I am working on a PHP web service that returns data in JSON form. I am at a point where I am now testing the web service with a jQuery/javascript file. It seems to be making the calls and receiving data correctly but the return values from the server seem to have too many double quotes.
PHP:
public static function getToken($username, $password)
{
$token = AuthenticationController::authenticate($username, $password);
if ($token)
{
$user = AuthenticationController::getUserFromToken($token);
if (UserController::userIsVerified($user->id))
{
$t = array('token' => $token);
return json_encode($t);
}
return json_encode(array('error' => 'This account has not been verified. Check email and click the provided link to verify the account.'));
}
return json_encode(array('error' => 'Authentication failed.'));
}
JS:
req.done(function(msg)
{
if (msg.error)
{
error = true;
message = msg.error;
}
else if (msg.message)
{
message = msg.message;
}
else if (msg.token)
{
token = msg.token;
}
else
{
error = true;
message = "An unknown error has occured.";
}
});
For one, the msg object is not coming back as a JSON object but instead it comes in as a string, so I have to do a $.parseJSON(msg) on it. What you see below, the token variable ends up writing out to be "mylongtoken" (quotes included). And if you look at that variable in firebug, it is like this: ""mylongtoken"". Is this just default behavior and I need to strip the quotes out?
First, to enable jquery to parse your response as json, you must return an appropriate content type. application/json seems appropriate.
For added security, you can add X-Content-Type-Options: nosniff to prevent browsers that get tricked into reading your JSON as a normal page to try any content sniffing which might enable HTML parsing and XSS:
Second, If you get two sets of quotes, then something you coded does add them. json_encode() does not:
echo json_encode(array('token' => 'tokenstring'); will output {"token":"tokenstring"} - no surrounding quotes. Any quotes inside any strings will be escaped using a backslash.
Related
On Concrete5-8.1.0 I have created a custom block with Ajax functionality based largely on the concrete5 docs - Implementing Ajax in Block View Templates. However, unlike the example I do not want to reload the block view, I want to pass specific messages based on the input. I tried a simple echo '{"msg":"ok"}'; and return '{"msg":"ok"}); as a test, but requests to the function yielded an empty response.
I found How To Send JSON Responses with Concrete5.7 and used Option 2 (for greater control of error codes) resulting in the following test code:
public function action_submit($token = false, $bID = false) {
if ($this->bID != $bID) {
return false;
}
if (Core::make('token')->validate('get_paper', $token)) {
//save to database
//removed for brevity
//send email
if ($this->emailto != '') {
//removed for brevity
}
if ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest') {
return new Response(
json_encode(array('msg' => 'ok')),
200,
['Content-Type' => 'application/json']
);
} else {
Redirect::page($page)->send();
}
}
else {
return false;
}
exit;
}
The database save and email function as expected, but the response is still empty. In Chrome Dev Tools, I see the correct Content-Type (as a test, I tried text/html and saw that change in dev tools), but no content. Interestingly, if I change the status from 200 to 500 I not only see the status change reflected in dev tools, I also see the {"msg":"ok"} content that I'm expecting, but changing the status back to 200 and the content is again empty.
It seems I'm missing something simple... I have verified that all caching is turned off within C5 (site is still in development), I have also verified the jQuery request includes cache:false, but the solution escapes me.
I am creating a form login with ExtJS, and sending JSON data to do authentification within Zend Framework. The problem is, no matter what username and password I fill, login always succeed. Here's the related code :
Submit Function for Ext JS Form, where we send JSON data contained username and password.
var doLogin = function () {
if (formPanel.getForm().isValid()) {
formPanel.getForm().submit({
method: 'POST',
url: '/zend/public/auth/valid',
waitMsg: 'Processing Request',
success: function (form, action) {
document.location = '/zend/public/guestbook';
},
failure: function (form, action) {
if (action.failureType = 'server') {
obj = Ext.util.JSON.decode(action.response.responseText);
Ext.Msg.alert('Login Failed', obj.errors.reason);
} else {
Ext.Msg.alert('Warning!', 'Authentification server is uneachable : ' + action.response.responseText);
}
formPanel.getForm().reset
}
})
}
}
The Controller, we have ValidAction function to receive and send JSON data, and process to do the authentification.
public function validAction()
{
if(!isset($this->session->isLogin)){
$username = mysql_escape_string($_POST['username']);
$password = mysql_escape_string($_POST['password']);
$formdata = array('username'=>$username, 'password'=>$password);
if ($this->_process($formdata)) {
$this->session->setExpirationSeconds(3600);
$msg = '{success:true, result:{message:\'Welcome, '.$username.'!\'}}';
} else {
$msg = '{success:false, errors:{reason:\'Login failed, try again.\'}}';
}
}
protected function _process($values) {
// Get our authentication adapter and check credentials
$adapter = $this->_getAuthAdapter();
$adapter->setIdentity($values['username']);
$adapter->setCredential($values['password']);
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
$user = $adapter->getResultRowObject();
$auth->getStorage()->write($user);
return true;
}
return false;
}
The problem lies in validAction, and weirdly I do var_dump to $this->process($formdata) and returns false, yet it always go to if function, message Success. Any ideas? Appreciated fellas.
UPDATE :
The var_dump :
Uncaught Error: You're trying to decode an invalid JSON String:
array(2) {
["username"]=>
string(2) "ad"
["password"]=>
string(4) "pass"
}
bool(false)
string(59) "{success:false, errors:{reason:'Login failed, try again.'}}"
Backend problem
You are outputting invalid JSON.
PHP provides json_encode to save you having to manually create json:
$response=array();
$response['success']=false;
$response['result']=array();
$response['message']='Welcome '.$username;
$msg = json_encode($response);
If you really don't want to use this you should add double quotes to your keys, and change to double quotes for your string properties too:
$msg = '{"success":true, "result":{"message":"Welcome, '.$username.'!"}}';
Front end problem
You are using success and failure methods, but I can't see anything in your back end code to send status headers.
The failure method will only get called when a response returns with a non 200 status code. So you may need to either add this to your back end code, and/or also decode the response inside your success method to make sure that you have sent success:true as part of your json before redirecting.
To send the header in PHP 5.4 or newer:
http_response_code(401);
in 5.3 or older you have to use header method instead - but if you are running this version you should upgrade immediately so I wont include an example.
Somewhat strange situation here
$location = 'Location: http://localhost/pages';
//header($location); exit; works
$response->header($location)->send(); exit; //doesn't work
and the $response object's class
public headers = [];
public function header($string, $replace = true, $code = 200)
{
$this->headers[] = [
'string' => $string,
'replace' => $replace,
'code' => $code
];
return $this;
}
public function send()
{
foreach ($this->headers as $header) {
header($header['string'], $header['replace'], $header['code']);
}
}
The code works fine when using vanilla header but it doesn't when using the methods. Am I missing something here?
You are returning the Location header to the browser with a 200 status code.
For a redirection to actually occur, a 3xx response code should be sent instead (usually, a 302). A 200 response code simply means "OK, content follows". For a redirection to actually take place, a 3xx response code must be given.
Your code is ultimately calling
header('Location: http://localhost/pages', true, 200);
which isn't going to result in the browser redirecting you to the desired location.
PHP itself special-cases calls to header('Location: ...') and unless otherwise specified, uses a 302 instead of leaving the response code unchanged. You may want to adjust your code to do the same to keep the same behavior as PHP.
Also, important to note that, while every HTTP response only has one response code, header() allows you to set the response code each time you call it.
Thus, if you use your code like this:
$response
->header("Location: http://localhost/pages", true, 302)
->header("SomeOtherheader: value")
->send()
;
the 302 you intended to send will get replaced with the 200 that gets set in the next call to header().
Instead, what you should do is either separate the concept of setting the status code from actually setting the header content, e.g.:
$response
->header("Location: http://localhost/pages"))
->header("SomeOtherheader: value")
->responseCode(302)
->send()
;
or instead do what header() does and treat an unspecified response code as meaning, don't change the what's already been set:
public function header($string, $replace = true, $code = false) { ... }
false (or 0) passed on to PHP's header() will indicate that.
Have a sendmail.php page that i'm calling via ajax on a WordPress site.
This is the basics of how it looks:
if ($_POST) {
foreach($_POST as $field => $val) {
if ($val == '') {
$jsonReturn = ['success' => false, 'message' => 'Validation errors whilst processing your form, please go back and check.'];
echo json_encode($jsonReturn);
die();
}
}
if ($noErrors) { // set elsewhere, but works okay
/*
Send an email
*/
if ($mail->send()){
$jsonReturn = ['success' => true, 'message' => "Thank you, message sent."];
echo json_encode($jsonReturn);
}
}
} else {
header("Location: /");
die();
}
If the 'validation' fails at the top of the page, I get a 200 page back containing the JSON return of success false.
However, if I pass validation and send the email thens end the json return it 404's the page.
I tested also by putting:
$jsonReturn = ['success' => true, 'message' => "Thank you, message sent."];
echo json_encode($jsonReturn);
Directly under the first foreach and it also 404's. So im guessing there is something wrong with that?
Any help.
Sorted, the input field has a name of "name".
Changing that worked, speaking to a colleague it appears that WordPress has a certain set of field names reserved for its queries. In this case it was seeing the field name and sending the request off to another page which doesn't exist.
Im sure a person with more knowledge at WP can explain better, but for now if anyone comes across this issue just make sure to check the input names.
I'm beginning to learn how to properly use REST API's following a popular tutorial here
When trying to create a simple POST api I keep running into a 400 error and I haven't found any answers online as of yet.
API is as follows:
$app->post('/test', function() use ($app) {
// check for required params
verifyRequiredParams(array('email'));
echo "Success";
});
Which attempts to verify the 'email' parameter with this block of code, unchanged from the tutorial:
function verifyRequiredParams($required_fields) {
$error = false;
$error_fields = "";
$request_params = array();
$request_params = $_REQUEST;
// Handling PUT request params
if ($_SERVER['REQUEST_METHOD'] == 'PUT') {
$app = \Slim\Slim::getInstance();
parse_str($app->request()->getBody(), $request_params);
}
foreach ($required_fields as $field) {
if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
$error = true;
$error_fields .= $field . ', ';
}
}
if ($error) {
// Required field(s) are missing or empty
// echo error json and stop the app
$response = array();
$app = \Slim\Slim::getInstance();
$response["error"] = true;
$response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
echoRespnse(400, $response);
$app->stop();
}
}
The code always fails with a 400 error code because it seems that the $_REQUEST function is returning an empty array. Any idea's what could be going wrong? I'm developing on an ubuntu server running apache.
The Slim API framework is set up correctly as I can call a very simple call through Google's Advanced Rest Client which echos a response correctly. And I am definitely passing the correct parameters into the api.
UPDATE: I've also tried running the $_REQUEST and $_GET functions directly from the api and it just returns an empty string like this:
Array
(
)
I wonder if there's some sort of apache config file that's blocking data to these functions or something?
Possible Problem:
Have you double checked that your selected Content-Type in the request headers is right?
I suspect the client is perceiving a malformed markup language being sent from the server side.
Possible Solution:
Change Content-Type: application/x-www-form-urlencoded to application/JSON or vice versa.
For the tutorial to receive
$name = $app->request->post('name');
the POST parameters have to be in Payload data
name=yourname&password=pass&email=me#mail.com
application/x-www-form-urlencoded
If you provide the parameters after the URL but not in the payload data, that is for a GET request. In such a case the tutorial partly works (it sees the parameters to verify required parameters are present) but it is looking for the parameters "anywhere" when it should only be looking in the payload parameters for POST.