I have a RESTful Zend action which should send me back a json encoded object, but in the response whatever I set in the body gets duplicated.
My code looks like this :
public function blablaAction() {
$this->_helper->viewRenderer->setNoRender();
$response = $this->getResponse();
[...]
$response->setBody('aaaaaaaa' . json_encode($output) . 'aaaaaaaa');
$response->sendResponse();
}
And if I look at the response body, I can see:
aaaaaaaaXXXXXXXXXXXXXXaaaaaaaaaaaaaaaaXXXXXXXXXXXXXXaaaaaaaa
(XXXXXXXXXXXXXX being the json encoded data).
Why?
PS: I added the aaaaaaa just to make sure the problem didn't come from the json encoding. I'll just have $response->setBody(json_encode($output)); when it finally works as expected.
I just found a workaround from this question: Zend response application/json utf-8
It works as expected if, instead of using $response along with setBody, I use $this->_helper->json->sendJson($output);.
This is only a workaround and would like to understand what's the problem with setBody, so I won't accept this "answer"...
Related
I have been writing an API using Symfony as the backend, a plugin written by a third party is sending certain data to an endpoint, the endpoint is then to return a json encoded response, however following the instructions as set out in the current symfony documaentation(https://symfony.com/doc/current/components/http_foundation.html) the return value is displayed twice and the response is not well formed and outputs like string
The original method that I wrote had calls to a database to validate a token, store a bookmark and display the result of the backend process, however when getting down to brass tacks and removing everything but the response building; it is obvious that this is where the problem lies. The method uses this snippet, though for clarity I have not included the database processing and used the posted values as the return array, the result is the same if it is the post or processed data, the output displays twice.
$token = $request->request->get('token');
$bookmark = $request->request->get('bookmark');
$data = ['token' => $token, 'bookmark' => $bookmark];
$response = new Response();
$response->headers->set('Access-Control-Allow-Origin', '*');
$response->setContent(json_encode($data));
$response->send();
return $response;
What I was expecting was a single json response but what is returned is a double string of the json output
e.g. if I posted these values to the above snippet:
token: ksjdbvqpi8e7rqp7evbprb
bookmark: http://www.google.com
the return result is
{"token":"ksjdbvqpi8e7rqp7evbprb", "bookmark":"http:\/\/www.google.com"}{"token":"ksjdbvqpi8e7rqp7evbprb", "bookmark":"http:\/\/www.google.com"}
when what I was expecting was just
{"token":"ksjdbvqpi8e7rqp7evbprb", "bookmark":"http:\/\/www.google.com"}
I have no idea at the moment why it is displaying twice, any help is as always appreciated.
Thanks
$response->send(); is the line that should be removed.
As you already return object of class Response symfony will take care to output this response to browser, you don't need to do it manually with send().
Background
I wrote a small test to make sure I could pull the data from a POST request made from my mobile application. It works fine,
$rawJsonObj = file_get_contents('php://input');
$json = json_decode( $rawJsonObj, true );
$decodedData = base64_decode($json['data']);
file_put_contents('student-data/'.$json['username'].'.txt', $decodedData);
Then in my Slim Framework app I try the same logic and the actual data that I use to create the file with is null. But I can still access the username and password that are sent in the request.
$app->post('/api/v1/endpoint', function ($request, $response, $args) {
$rawJsonObj = $request->getParams();
$json = json_decode( $rawJsonObj, true );
$decodedData = base64_decode($json['data']);
file_put_contents('test.txt', $decodedData);
return $response;
}
The username and password are showing in the request and I can see them when I write the data in the request to a file.
$data = $request->getParams();
file_put_contents('2.txt', $data);
Data that is wrote to file,
","username":"myuname","password":"myPword"}
But the base64encoded string is missing,
Example
In Swift I am creating the dict like this, then POST it as json,
let dict: [String: Any] = [
"username": named,
"password": password,
"data": data.base64EncodedString()
]
if let json = try? JSONSerialization.data(withJSONObject: dict, options: []) {
request.httpBody = json
}
Question
How do I access the actual "data": data.base64EncodedString() from the request body in Slim Framework 3?
I assume this has to do with the way $rawJsonObj = file_get_contents('php://input'); actually handles the data compared to Slim?
Request::getParams() is a custom method by Slim (not part of PSR-7) that collects all input data; in other words, it's a rough equivalent of PHP's $_REQUEST superglobal. Internally, it grabs the request body with Request::getParsedBody() (this one, part of PSR-7). Here's where major differences with $_REQUEST or $_POST arise:
If the request Content-Type is either
application/x-www-form-urlencoded or multipart/form-data, and the
request method is POST, this method MUST return the contents of
$_POST.
Otherwise, this method may return any results of deserializing the
request body content; as parsing returns structured content, the
potential types MUST be arrays or objects only. A null value
indicates the absence of body content.
While $_POST only decodes standard form encodings (thus in your test code you need to fetch and parse data manually) getParsedBody() tries to decode other encodings but, just like $_POST, it needs a proper Content-Type to do so. If you send one from your mobile app:
Content-Type: application/json
... it'll work as expected because Slim has a builtin JSON decoder.
If you can't send an encoding declaration, you need to decode stuff manually. In this case, the PSR-7 way to fetch the raw request body is Message::getBody(), that returns a stream (more specifically, a Stream object that that implements StreamInterface).
My question is related to Slack's Slash commands.
I am trying to echo response back to invoking channel.
e.g I have integerated a test command like
/test hello
and I want response as:
Hello
Wold
but I am currently getting it as (in my slack channel):
{"text":"hello\nworld"}
This is my PHP code:
$payload = '{"text":"hello\nworld"}';
echo $payload;
Note I don't want to just echo like this:
echo "hello\nworld";
Thanks in advance :)
Maybe useful in giving answer:-
Sample wrong response actual:
Slack slash command API url:
https://api.slack.com/slash-commands
If you had carefully read the docs (which you linked), you would have noticed that it says:
NOTE: If you are responding with JSON instead of plain text, the content-type header of the response must match the disposition of your content, application/json.
It looks like you're just outputting JSON without sending the correct Content-Type header, so Slack thinks it's plain text and displays your JSON as plain text.
Also, consider using json_encode instead of manually writing JSON.
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"}
}
In the book of laravel I read, and also my co-worker who has experience with laravel said that generating JSON I should in laravel way.
Why do I need to do this:
Route::get('markdown/response', function()
{
$data = array('iron', 'man', 'rocks');
return Response::json($data);
});
As I read it sends also content-type header when using this.
When I was using codeigniter I used to do simply this:
echo json_endode($data);
and never ever ever had any problems. Even if it is not set content type. Actually I dont know maybe php sets it automatically, but since I did not have problems, I did not care.
And when using 'new' technology I really want to know why it is better than good old one.
With respect, by not providing a content-type header, you were doing it "wrong" when coding in CodeIgniter.
Most clients (browsers, ajax requests, especially jQuery) can still can guess how to handle the response correctly and so probably "just worked" for you. You were likely always implicitly returning a Content-Type: text/html with your response, which is a default header in CodeIgniter.
You should always return a proper content type with your HTTP responses so the consuming client knows how to treat this content. Note that this is a mechanism of HTTP as defined in specification, not specific to any framework or even a language.
Response::json()
The above code is just a convenience function, where Laravel will automatically set the application/json header for you, as well as convert an array of data into JSON format. The only effective difference from your CodeIgniter code is the setting of the header, as you've pointed out.
It's worth noting that the Response object extends Symfony's response object, which is very "powerful" - in other words, it's a very good implementation of the HTTP protocol.
The response object returned from Response::json (and other Response static methods) are highly modifiable.
$response = Response::json($data);
$response->header('Content-Type', 'application/json');
return $response;
You can check for more available methods in the Laravel and Symfony code API.
http://laravel.com/api/class-Illuminate.Http.Response.html
http://api.symfony.com/2.1/Symfony/Component/HttpFoundation/Response.html
Just because it worked doesn't mean it wasn't wrong. JSON isn't HTML, so text/html is an inaccurate Content-Type for it.
Sending the correct header means libraries like jQuery understand what sort of data they're getting back, and thus are able to handle it on their own without guidance. Browsers may also do things like pretty-printing the JSON data or making it otherwise easier to read.
Depends what you are trying to do with the route. if you only want to return json data you can just return json_encode($data) and that will work, To actually return a json response for use with something like an ajax request you need the headers set properly or the accepting route just thinks its getting a string. Response::json is for setting the response which sets the headers appropriately.