I’m trying to get POST content in php side (using PHP 8.3, Symfony 7.1)
Here is an example backend:
#[Route("test")]
public function testing(Request $request) {
$_POST = json_decode($request->getContent(), true);
if(isset($_POST["line"])) { // FIRST METHOD
// try when using JS query (see code below)
}
if($request->request->get("line") != null) { // SECOND METHOD
// true when using Symfony queries
}
return $this->json([]);
}
Two if
are never true at the same time.
- The first method is multiple times recommended in stackoverflow (like here, here or here), and worked for me since long time
- The second method is mentionned in Symfony documentation
- When using this JS code:
await fetch("/test", {
method: "POST",
body: JSON.stringify({
"line": "the line"
}),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
It works by using the first method $_POST
.
- When using this code with
PHPUnit
:
$client->request('POST', "/test", [
"line" => "the line"
], [], [ 'CONTENT_TYPE' => 'application/json', 'ACCEPT' => 'application/json' ]);
It the second method that works (by using request->get
).
Why is there a difference and what am I doing wrong?
3
Answers
When you use
$request->request->get("line")
Symfony is expectingapplication/x-www-form-urlencoded
as content type.So you need to handle your body as a json in your symfony controller:
Or in symfony >= 5.2
You could also modify your ajax request to be treated as
application/x-www-form-urlencoded
.You may also use of the new symfony 6 attribute to map your payload to a new dto in your method parameters (symfony >= 6.3).
In your JavaScript example, you send the POST data as a JSON body:
body: JSON.stringify()
'Content-Type': 'application/json'
It means the HTTP request body has been sent as a JSON string:
That’s why your 1st option works, but you can see that you need to decode the JSON before any other operation:
json_decode($request->getContent(), true)
. PHP is not built to handle POST data in JSON format by default.The 2nd example is the standard one. By default, POST data is sent with a
Content-Type
HTTP header with the valueapplication/x-www-form-urlencoded
. The request body looks like a query string (like GET data):In this case, the
$_POST
superglobal is already configured to contain aline
key, you don’t need to JSON decode anything. That’s why Symfony’sRequest
(as it uses the$_POST
superglobal in its web runtime) can get your data using$request->request->get()
.If you want your JS code and PHPUnit code to work, you should either:
x-www-form-urlencoded
request()
method properly)PS: don’t create/rewrite superglobals like
$_POST
, if not a bad practice, it’s at least very confusing. Never use such variables in Symfony anyways.What you are doing is wrong:
Nothing crazy needs to be done, it’s just the the approaches to send data, and each approach requires a different way to handle the data on the PHP side.
If you want to use the same approach for both scenarios, you could consider using a library like
symfony/http-foundation
to handle the JSON requests in a more standardized way.Here is the example on your code base to handle the request the PHPUnit test to send a raw JSON payload, similar to the JavaScript example, by using the
json
key in therequest
method.This would send a raw JSON payload; you could use the first method to handle it in your PHP code.