Handle utf-8 format posted data - php

My c++ desktop application is posting data to my server with the charset=UTF-8 format (specified in my HTTP request headers). My php script analysing the posted data is not reading _POST correctly.
Does my script need to manually decode the posted data? I thought if the HTTP post request specified the charset that the script/php will automatically figure it out?
foreach($_POST as $key => $value)
{
$contents .= $key . ", " . $value . "\r\n";
}
// contents = n, J o h n D o e
// when it should = name, John Doe\r\nuserid, hithere\r\n

I thought if the HTTP post request specified the charset that the script/php will automatically figure it out?
No, character encoding is a lower layer. First of all, you need to let PHP know about the Content-Type of the data that you are sending it.
Check the manual on $_POST, it says:
An associative array of variables passed to the current script via the HTTP POST method when using application/x-www-form-urlencoded or multipart/form-data as the HTTP Content-Type in the request.
For HTTP file upload you would use the latter, for other "normal" form data (text fields, anything basically that sends string data) the first one.
And of course your script will have to send the data encoded according to the chosen Content-Type. Whatever HTTP library you are using should provide methods to handle that; I'd recommend a look in the docuentation if you're not sure.
That would be the way to do it, as far as emulating HTML forms goes. If that is not your goal, your other option would be to send the data encoded in any format you chose, like f.e. JSON (or maybe even not treated any special way at all), and then read the raw input using file_get_contents and the php://input stream wrapper.

Related

PSR-7: getParsedBody() vs getBody()

Scenario 1 sending x-www-form-urlencoded data
POST /path HTTP/1.1
Content-Type: application/x-www-form-urlencoded
foo=bar
Running print_r($request->getParsedBody()); returns fine:
Array
(
[foo] => bar
)
Running print_r($request->getBody()->getContents()); returns a string foo=bar
Scenario 2 sending application/json data
POST /path HTTP/1.1
Content-Type: application/json
{
"foo": "bar"
}
Running print_r($request->getParsedBody()); returns an empty array. Array ( )
But, running print_r($request->getBody()->getContents()); returns fine:
{"foo":"bar"}
Is this expected behavior?
Meaning, if we're sending x-www-form-urlencoded data, we should use getParsedBody().
While getBody()->getContents() should be used if we're sending application/json?
Additional info:
Request object is created using:
$request = \Laminas\Diactoros\ServerRequestFactory::fromGlobals(
$_SERVER, $_GET, $_POST, $_COOKIE, $_FILES
);
Message body:
In a PSR-7 library, the message body is abstracted by the StreamInterface. Any implementation of this interface MUST wrap a PHP stream and, of course, should provide the proper functionality to perform the specific read/write/seek operations on it. PHP provides a list of I/O streams, from which php://input is suitable for the task in question.
php://input is a read-only stream that allows you to read raw data from the request body. php://input is not available with enctype="multipart/form-data".
In this context, when a request to the server is performed, the request body data (regardless of its data type) is automatically written to the php://input stream, in raw format (string). The information can later be read from it by calling StreamInterface::getContents, StreamInterface::__toString, or StreamInterface::read (which would probably make use of stream_get_contents(), or similar, in their implementation).
Note: The method StreamInterface::__toString is automatically called when the object representing the message body, e.g. the instance of the class implementing StreamInterface is cast to a string. For example, like this - see Type Casting in PHP:
$messageBodyObject = $request->getBody(); // implements StreamInterface
$contentOfMessageBody = (string) $messageBodyObject; // cast to string => StreamInterface::__toString is called
echo $contentOfMessageBody;
Parsed body:
In regard of the PSR-7, the parsed body is a "characteristic" of the applications where PHP is "used as a server-side application to fulfill HTTP requests" (in comparison with the applications where PHP is used as "an HTTP client") - see Summary of the PSR-7 Meta Document. So, the parsed body is a component of the ServerRequestInterface only.
The parsed body (read the comments of ServerRequestInterface::getParsedBody and ServerRequestInterface::withParsedBody) is thought as a representation in a "parsed" form (array, or object) of the raw data (a string) saved in the php://input stream as the result of performing a request. For example, the $_POST variable, which is an array, holds the parsed body of a POST request, under the conditions presented bellow.
Relevant use-cases:
If a POST request is performed and the header Content-Type is application/x-www-form-urlencoded (for example when submitting a normal HTML form), the content of the request body is automatically saved into both the php://input stream (serialized) and the $_POST variable (array). So, in the PSR-7 context, calling both StreamInterface::getContents (or StreamInterface::__toString, or StreamInterface::read) and ServerRequestInterface::getParsedBody will return "valid" values.
If a POST request is performed and the header Content-Type is multipart/form-data (for example when performing a file(s) upload), the content of the request body is NOT saved into the php://input stream at all, but only into the $_POST variable (array). So, in the PSR-7 context, only calling ServerRequestInterface::getParsedBody will return a "valid" value.
If a POST request is performed and the header Content-Type has other value than the two presented above (for example application/json, or text/plain; charset=utf-8), the content of the request body is saved only into the php://input stream. So, in the PSR-7 context, only calling StreamInterface::getContents (or StreamInterface::__toString, or StreamInterface::read) will return a "valid" value.
Resources:
PSR-7: HTTP message interfaces
PSR-7 Meta Document
How to get body of a POST in php?
PHP "php://input" vs $_POST
php://input - what does it do in fopen()? (the comment to the answer)
The answer by #dakis is correct, but I find it a bit ambiguous in answering the original question of why Scenario 2 failed.
From a PSR standpoint, the behaviour is correct (as #dakis said):
body returns a stream to the request body
parsedBody is a characteristic of the request and can contain a parsed representation of the body (but is not required to), as mentioned in the PHPDoc of ServerRequestInterface::getParsedBody:
Otherwise, this method may return any results of deserializing the request body content; ...
From a usefulness perspective, laminas-diactoros is lacking and, in my opinion, half-baked. This library doesn't seem to do a lot more than passing around data already parsed by PHP ($_GET/$_POST..). A better implementation would have handled the specific content-type for use with parsedBody and would have automatically thrown or handled bad POST data.

Can't read raw POST body data - how to do this in this example?

I'm setting an API for my server for another developer. I'm currently using Flash AIR to send POST data to my server, and simply extract the variables as in
$command = $_POST['command'].
However, he's not using Flash, and is sending data like so:
https://www.mysite.com POST /api/account.php?command=login HTTP/1.1
Content-Type: application/json
Connection: close
command=login
params {"pass":"12345678","token":"","appID":"theirApp","user":"johnnyb","ver":"2.0","Library_ID":"1"}
My server is returning him an error saying that the 'command' parameter is missing.
What do I need to do my end to extract the $_POST var 'command' from his above data?
I've tried file_get_contents('php://input') and http_get_request_body(), but although they don't error, they don't show anything.
Thanks for your help.
The request claims that it is sending JSON.
Content-Type: application/json
However, this:
command=login
params {"pass":"12345678","token":"","appID":"theirApp","user":"johnnyb","ver":"2.0","Library_ID":"1"}
… is not JSON.
If you get rid of everything before the { then it would be JSON and you should be able to read it with file_get_contents('php://input') (and could then pass it through a decoder.
I've tried file_get_contents('php://input') and http_get_request_body() … they don't show anything.
They should work.
When I print out file_get_contents('php://input') for the comms … I get command=login, yet...
I thought you said you didn't get anything
if(!isset($_POST['command']))
$_POST will only be populated for the two standard HTML form encoding methods. If you are using JSON then it won't be automatically parsed, you have to do it yourself (with valid JSON input (so the additional data would need to be encoded in the JSON text with the rest of the data)), file_get_contents('php://input') and decode_json).
"Content-Type should be www-form-urlencoded" from #Cole (correct answer)
More info here: http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
The command parameter needs to be part of the data, and the whole thing should be valid JSON. As is, command=login, it is not valid JSON.
Add it to the params object or make a containing object, like
{
command:'login',
params :{"pass":"12345678","token":"","appID":"theirApp","user":"johnnyb","ver":"2.0","Library_ID":"1"}
}

XHR request to PHP

Hi i am having problems with an XHR post request.
in javascript:
self.xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
self.xhr.setRequestHeader("Method", "POST " + url + " HTTP/1.1");
In firebug:
Parametersapplication/x-www-form-urlencoded
{"u":"andrepadez","m":"\n...
JSON
m
"sfdsfsdfdsfdsf"
u
"andrepadez"
Source
{"u":"andrepadez","m":"\nsfdsfsdfdsfdsf"}
In .NET, I post this to an .ASHX, and in the ProcessRequest i do:
StreamReader sr = new StreamReader(context.Request.InputStream, context.Request.ContentEncoding);
javaScriptSerializer.Deserialize<MyClass>(message);
and I have no problems.
I don't know how to get the data in PHP, either $_POST and $_REQUEST are empty arrays.
Any help please?
thanks
You've not set a field name for the data being sent. PHP requires data coming in via POST to be in a fieldname=value format. _POST is an array like any other, and every value stored in a PHP array must have a key (which is the form field name).
You can try retrieving the data by reading from php://input:
$post_data = file_get_contents('php://input');
But the simplest solution is to provide a fieldname in your XHR call.
You are setting the Content-Type to application/x-www-form-urlencoded, but you are setting the content to json. I'm guessing this is confusing your PHP webserver. Try setting your POST contents to what you tell the server it will be (application/x-www-form-urlencoded) or read the raw HTTP contents in php://input.
If you set the Content-Type to application/x-www-form-urlencoded then naturally PHP will want to parse the POST body. But as the data does not actually constitute form data, it is discarded as invalid.
You need to set the correct CT application/json (actually doesn't matter) so PHP will leave it alone. Then it becomes available as php://input or $HTTP_RAW_POST_DATA

URL encoding seems to get in the way of properly json encoding/decoding in my PHP program

I'm implementing a PHP script which receives an HTTP POST message with in the body a json string, tied to a 'report' parameter. So HTTP POST report=.
I'm testing this out with SimpleTest (PHP Unit Testing).
I build the json:
$array = array("type" => "start"); // DEBUG
$report = json_encode($array);
I send the POST:
$this->post(LOCAL_URL, array("report"=>$json));
(calls a method in the WebTestCase class from SimpleTest).
SimpleTest says it sends this:
POST /Receiver/web/report.php HTTP/1.0
Host: localhost:8888
Connection: close
Content-Length: 37
Content-Type: application/x-www-form-urlencoded
report=%7B%22type%22%3A%22start%22%7D
I receive as such:
$report = $_POST['report'];
$logger->debug("Content of the report parameter: $report");
$json = json_decode($report);
The debug statement above gives me:
Content of the report parameter: {\"type\":\"start\"}
And when I decode, it gives the error
Syntax error, malformed JSON
The 'application/x-www-form-urlencoded' content-type is automatically selected by SimpleTest. When I set it to 'application/json', my PHP script doesn't see any parameters and as such, can't find the 'report' variable.
I suppose something is going wrong with the url encoding, but I'm lost here as to how I should get the json accross.
Also, what is the usual practice here? Does one use the key/value approach even if you just send an entire json body? Or can I just dump the json string in the body of the HTTP POST and read it out somehow? (I had no success in actually reading it out without a variable to point to).
Anyway, I hope the problem is somewhat clearly stated.
Thanks a bunch in advance.
Dieter
It sounds like you have magic quotes enabled (which is a big no-no). I would suggest you disable this, otherwise, run all your input through stripslashes().
However, it is better practice to reference the POST data as a key/value pair, otherwise you will have to read the php://input stream.
For the quick fix, try:
$report = stripslashes($_POST['report']);
Better, disable magic quotes GPC. G=Get, P=Post, C=Cookie.
In your case Post. Post values get automatically ("magic") quoted with a single slash.
Read here how to disable magic quotes.

Determine REST POST/PUT request format

I'm developing a REST CodeIgniter Controller and need to POST and PUT to a URL in multiple formats.
The main formats I can think of would be:
XML
JSON
HTML Form data
There will be a response format defined in the URI e.g. /format/xml or /format/csv.
I don't want to have to define the request format in the URI as well.
I was wondering if anyone has any suggestions on finding out the request format so my script can complete the request.
I'm thinking it may be possible to get this data from the request headers "content-type"?
"content-type: text/xml" = XML
"content-type: application/json" = JSON
"content-type: text/plain" = HTLM Form data **i think!*
Would this method be robust or are there better approaches out there?
Thanks.
The content-type is the correct way to get the information you want.
Just make sure to throw an exception with some feedback and the correct http error code if the client calls it on the wrong format or do not pass the content-type header (you could also assume one content-type as default)
Also, you don't really have to use format/format_of_the_response . A better way would be to use the header Accept on the same way you use the header content-type
That method is robust as long as you know the your REST client will follow your content-type rule. If you control the client then this is fine. If you don't control the client then how acceptable is failure of the call when an unusual (or no) content-type is passed in?
Oh and for reference HTML form data has a content type of 'application/x-www-form-urlencoded'
I know this has been answered, but Phil Sturgeon wrote a REST Client and REST Server Library for codeigniter, might help you out a little bit.
http://github.com/philsturgeon/codeigniter-restclient

Categories