PHP “php://input” vs $_POST

前端 未结 6 1923
离开以前
离开以前 2020-11-21 23:55

I have been directed to use the method php://input instead of $_POST when interacting with Ajax requests from JQuery. What I do not understand is t

6条回答
  •  你的背包
    2020-11-22 00:29

    First, a basic truth about PHP.

    PHP was not designed to explicitly give you a pure REST (GET, POST, PUT, PATCH, DELETE) like interface for handling HTTP requests.

    However, the $_POST, $_GET, and $_FILES superglobals, and the function filter_input_array() are very useful for the average person's / layman's needs.

    The number one hidden advantage of $_POST (and $_GET) is that your input data is urldecoded automatically by PHP. You never even think about having to do it, especially for query string parameters within a standard GET request.

    However, then you learn more ...

    That being said, as you advance in your programming knowledge and want to use JavaScript's XmlHttpRequest object (jQuery for some), you come to see the limitation of this scheme.

    $_POST limits you to the use of two media types in the HTTP Content-Type header:

    1. application/x-www-form-urlencoded, and
    2. multipart/form-data

    Thus, if you want to send data values to PHP on the server, and have it show up in the $_POST superglobal, then you must urlencode it on the client-side and send said data as key/value pairs--an inconvenient step for novices (especially when trying to figure out if different parts of the URL require different forms of urlencoding: normal, raw, etc..).

    For all you jQuery users, the $.ajax() method is converting your JSON to URL encoded key/value pairs before transmitting them to the server. You can override this behavior by setting processData: false. Just read the $.ajax() documentation, and don't forget to send the correct media type in the Content-Type header.

    URL encoding? What the heck!!!???

    Typically, if you are doing a normal, synchronous (when the entire page redraws) HTTP requests with an HTML form, the user-agent (web browser) will urlencode your form data for you. If you want to do an asynchronous HTTP requests using the XmlHttpRequest object, then you must fashion a urlencoded string and send it, if you want that data to show up in the $_POST superglobal.

    How in touch are you with JavaScript? :-)

    Converting from a JavaScript array or object to a urlencoded string bothers many developers (even with new APIs like Form Data). They would much rather just be able to send JSON, and it would be more efficient for the client code to do so.

    Remember (wink, wink), the average web developer does not learn to use the XmlHttpRequest object directly, global functions, string functions, array functions, and regular expressions like you and I ;-). Urlencoding for them is a nightmare. ;-)

    PHP, what gives?

    PHP's lack of intuitive XML and JSON handling turns many people off. You would think it would be part of PHP by now (sigh).

    So many media types (MIME types in the past)

    XML, JSON, and YAML all have media types that can be put into an HTTP Content-Type header.

    • application/xml
    • applicaiton/json
    • application/yaml (although IANA has no official designation listed)

    Look how many media-types (formerly, MIME types) are defined by IANA.

    Look how many HTTP headers there are.

    php://input or bust

    Using the php://input stream allows you to circumvent the baby-sitting / hand holding level of abstraction that PHP has forced on the world. :-) With great power comes great responsibility!

    Now, before you deal with data values streamed through php://input, you should / must do a few things.

    1. Determine if the correct HTTP method has been indicated (GET, POST, PUT, PATCH, DELETE, ...)
    2. Determine if the HTTP Content-Type header has been transmitted.
    3. Determine if the value for the Content-Type is the desired media type.
    4. Determine if the data sent is well formed XML / JSON / YMAL / etc.
    5. If necessary, convert the data to a PHP datatype: array or object.
    6. If any of these basic checks or conversions fails, throw an exception!

    What about the character encoding?

    AH, HA! Yes, you might want the data stream being sent into your application to be UTF-8 encoded, but how can you know if it is or not?

    Two critical problems.

    1. You do not know how much data is coming through php://input.
    2. You do not know for certain the current encoding of the data stream.

    Are you going to attempt to handle stream data without knowing how much is there first? That is a terrible idea. You cannot rely exclusively on the HTTP Content-Length header for guidance on the size of streamed input because it can be spoofed.

    You are going to need a:

    1. Stream size detection algorithm.
    2. Application defined stream size limits (Apache / Nginx / PHP limits may be too broad).

    Are you going to attempt to convert stream data to UTF-8 without knowing the current encoding of the stream? How? The iconv stream filter (iconv stream filter example) seems to want a starting and ending encoding, like this.

    'convert.iconv.ISO-8859-1/UTF-8'
    

    Thus, if you are conscientious, you will need:

    1. Stream encoding detection algorithm.
    2. Dynamic / runtime stream filter definition algorithm (because you cannot know the starting encoding a priori).

    (Update: 'convert.iconv.UTF-8/UTF-8' will force everything to UTF-8, but you still have to account for characters that the iconv library might not know how to translate. In other words, you have to some how define what action to take when a character cannot be translated: 1) Insert a dummy character, 2) Fail / throw and exception).

    You cannot rely exclusively on the HTTP Content-Encoding header, as this might indicate something like compression as in the following. This is not what you want to make a decision off of in regards to iconv.

    Content-Encoding: gzip
    

    Therefore, the general steps might be ...

    Part I: HTTP Request Related

    1. Determine if the correct HTTP method has been indicated (GET, POST, PUT, PATCH, DELETE, ...)
    2. Determine if the HTTP Content-Type header has been transmitted.
    3. Determine if the value for the Content-Type is the desired media type.

    Part II: Stream Data Related

    1. Determine the size of the input stream (optional, but recommended).
    2. Determine the encoding of the input stream.
    3. If necessary, convert the input stream to the desired character encoding (UTF-8).
    4. If necessary, reverse any application level compression or encryption, and then repeat steps 4, 5, and 6.

    Part III: Data Type Related

    1. Determine if the data sent is well formed XML / JSON / YMAL / etc.

    (Remember, the data can still be a URL encoded string which you must then parse and URL decode).

    1. If necessary, convert the data to a PHP datatype: array or object.

    Part IV: Data Value Related

    1. Filter input data.

    2. Validate input data.

    Now do you see?

    The $_POST superglobal, along with php.ini settings for limits on input, are simpler for the layman. However, dealing with character encoding is much more intuitive and efficient when using streams because there is no need to loop through superglobals (or arrays, generally) to check input values for the proper encoding.

提交回复
热议问题