0

I was reading through the "Faking the method with _method" section on the following URL: http://symfony.com/doc/current/cookbook/routing/method_parameters.html

After some experimentation, I realized that the documentation is either unclear or inaccurate. One can only override the HTTP method with the _method parameter if the browser uses POST (and not GET) to make the request.

Symfony\Component\HttpFoundation\Request

public function getMethod()
    {
        if (null === $this->method) {
            $this->method = strtoupper($this->server->get('REQUEST_METHOD', 'GET'));

            if ('POST' === $this->method) {
                if ($method = $this->headers->get('X-HTTP-METHOD-OVERRIDE')) {
                    $this->method = strtoupper($method);
                } elseif (self::$httpMethodParameterOverride) {
                    $this->method = strtoupper($this->request->get('_method', $this->query->get('_method', 'POST')));
                }
            }
        }

        return $this->method;
    }

In our application, we'd like to override the HTTP method for GET requests, because we're using JSONP. In our case, this is not a security issue as requests are signed using a CSRF token.

I found a solution for this in the "Overriding the Request" section here:

http://symfony.com/doc/current/components/http_foundation/introduction.html

This would involve making a sub-class of Symfony\Component\HttpFoundation\Request, over-riding the getMethod() method, and setting it using Request::setFactory().

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return SpecialRequest::create(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

My question is:

The only place I can see to do this is in app.php / app_dev.php / app_test.php. E.g.:

require_once __DIR__.'/../app/AppKernel.php';

$kernel = new AppKernel($env, $is_debug);
$kernel->loadClassCache();

// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
//Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);

Would this be the right place to do this?

I looked at kernel events, such as kernel.request, but at this point it seems too late for the event to be useful:

"1) The kernel.request Event Typical Purposes: To add more information to the Request, initialize parts of the system, or return a Response if possible (e.g. a security layer that denies access)."

http://symfony.com/doc/current/components/http_kernel/introduction.html

Any advice would be appreciated. Thank you.

2
  • This question should apply to Symfony 2.3 and above. Commented Nov 14, 2014 at 18:02
  • Starting in 2.4 you can adjust the factory used to create a Request object. symfony.com/doc/current/components/http_foundation/…. Otherwise I think you are on the right track. But do carefully consider exactly what you are trying to accomplish. The _method was to overcome browser limitations. Misusing it as you you propose will completely screw up all kinds of http caching issues. I suspect you will end up regretting going down this path. Commented Nov 14, 2014 at 21:21

3 Answers 3

1

To override the HTTP methods in symfony, it's not that hard, first add the parameter method to your routing :

blog_update:
    path:     /blog/{slug}
    defaults: { _controller: AcmeDemoBundle:Blog:update }
    methods:   [PUT]

Next, depending on which version of symfony you are using, enable Http Method Parameter Override, here's how you can do so : (from symfony doc)

The _method functionality shown here is disabled by default in Symfony 2.2 and enabled by default in Symfony 2.3. To control it in Symfony 2.2, you must call Request::enableHttpMethodParameterOverride before you handle the request (e.g. in your front controller). In Symfony 2.3, use the http_method_override option.

now if you are using symfony's FormBuilder, it should add a hidden input with the name "_method", or you can add it yourself if you are not using the symfony's form builder.

here's the full doc : http://symfony.com/doc/current/cookbook/routing/method_parameters.html

Sign up to request clarification or add additional context in comments.

3 Comments

Hi teeyo, I tried both of these things. This solution only works if the browser makes a POST request to the server (see first code excerpt above). I would need a solution that works with GET requests as well. To clarify, a POST request can be transformed using _method to any other method, but a GET request cannot.
I'm afraid there's no way to do this, because symfony says that this works only with post, it's like if the method is GET they don't boder checking if you want to override the method.
@JaySheth here you go, from the symfony documentation : static public enableHttpMethodParameterOverride() Enables support for the _method request parameter to determine the intended HTTP method. Be warned that enabling this feature might lead to CSRF issues in your code. Check that you are using CSRF tokens when required. The HTTP method can only be overridden when the real HTTP method is POST.
0

To enable the Override of the HTTP method in symfony you should define the http_method_override in the config.yml

framework:
    http_method_override: true

kernel.http_method_override

Comments

0

Overriding Request object

For those who are interested in overriding the Request base class.

There is actually a mistake in the doc, I will send a PR for this.


The following (see your example) is not correct:

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return SpecialRequest::create(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

The following is correct:

use Symfony\Component\HttpFoundation\Request;

Request::setFactory(function (
    array $query = array(),
    array $request = array(),
    array $attributes = array(),
    array $cookies = array(),
    array $files = array(),
    array $server = array(),
    $content = null
) {
    return new SpecialRequest(
        $query,
        $request,
        $attributes,
        $cookies,
        $files,
        $server,
        $content
    );
});

$request = Request::createFromGlobals();

Can you spot the difference?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.