Love Fuel?    Donate

FuelPHP Forums

Ask your question about FuelPHP in the appropriate forum, or help others by answering their questions.
Handling lots of PUT requests with urlencoded data
  • Is there a way to urldecode data that is submitted through a PUT request and maintain it's availability though the \Input class?

    I have an API that extends Controller_Rest. I developed and tested it using the POSTman REST client for Google Chrome. When we hooked up the API to the iOS App that we're developing, we immediately started getting validation errors from PUT requests. I did some logging and found:

    The var_dump(\Input::put()); from a POSTman PUT request looks like this:

    array(4) {
      ["name"]=>
      string(10) "Ben Harold"
      ["id"]=>
      string(1) "1"
      ["phone"]=>
      string(14) "(317) 286-8548"
      ["alt_phone"]=>
      string(0) ""
      ["address"]=>
      string(15) "123 Fake St"
    }

    Meanwhile, the var_dump(\Input::put()); from an iOS PUT request looks like this:

    array(5) {
      ["name"]=>
      string(12) "Ben%20Harold"
      ["id"]=>
      string(1) "1"
      ["phone"]=>
      string(16) "(317)%20286-8548"
      ["alt_phone"]=>
      string(0) ""
      ["address"]=>
      string(15) "123%20Fake%20St"
    }

    At first I assumed that POSTman was sending the "Content-Type: application/x-www-form-urlencoded" header and that the iOS client wasn't. I checked, and that's not the case. The iOS client sends a slightly more verbose "Content-Type: application/x-www-form-urlencoded charset=utf8" header.

    In virtually all of my controllers I'm using \Input::put('whatever'); to get the necessary data. I'd rather not go back and wrap every single \Input::put() call with urldecode(); Can I modify the PUT data (urldecode it) while still being able to access it using the \Input class?


  • HarroHarro
    Accepted Answer
    Input doesn't check the content type at the moment.

    I have no option to test this at the moment, if you change the hydrate() method in the Input class to this, does it fix it?
        protected static function hydrate()
        {
            static::$input = array_merge($_GET, $_POST);

            if (\Input::method() == 'PUT' or \Input::method() == 'DELETE')
            {
                static::$php_input === null and static::$php_input = file_get_contents('php://input');
                if (strpos(static::headers('CONTENT_TYPE'), 'www-form-urlencoded') > 0)
                {
                    static::$php_input = urldecode(static::$php_input);
                }
                parse_str(static::$php_input, static::$put_delete);
                static::$input = array_merge(static::$input, static::$put_delete);
            }
        }
  • Thanks Harro. The concept worked, although there is no \Input::headers() method. I created one, although I don't like it very much. Notice that I changed 'CONTENT_TYPE' in your code to 'Content-Type':

    protected static function headers($header)
    {
       $headers = apache_request_headers();
       $header = strtolower($header);

       $keys = array_map('strtolower', array_keys($headers));

       if ($key = array_search($header, $keys))
       {
           $headers = array_values($headers);
           return $headers[$key];
       }
       return '';
    }

    From what I understand nginx runs in FastCGI mode, and the getallheaders() and apache_request_headers() don't work in FastCGI mode before PHP 5.4. For this reason, this hack is pretty ugly and incompatible with a *lot* of setups :(
  • HarroHarro
    Accepted Answer
    I always work on 1.7/develop, and that has the headers() method. It has a workaround for fastcgi and nginx.

    If the concept works I'll commit it to 1.7/develop.
  • Yes, the concept works! Thanks so much! That's a much more elegant solution than adding urldecode() to a few hundred lines of code.
  • Also added support for plain id strings, so you can now use Session::key(), in GET, POST and the HTTP header, no more need to do crazy array serialization stuff...

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion