Send JSON data to PHP using XMLHttpRequest w/o jQuery - php

I am trying to send JSON data from a form using the XMLHttpRequest object. I can send the data using the following function. There are no errors displayed in FireBug and the JSON-data in the request is displayed well formed by FireBug.
However, I send the data to echo.php, what simply returns the content:
<?php
print_r($_POST);
print_r($_GET);
foreach (getallheaders() as $name => $value) {
echo "$name: $value\n";
}
echo file_get_contents('php://input');
?>
The POST-array is always empty, but I can see the JSON string returned by file_get_contents. How does that happen? What am I doing wrong?
output of echo.php
Array
(
)
Array
(
)
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:10.0.2) Gecko/20100101 Firefox/10.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: eo,de-de;q=0.8,de;q=0.6,en-us;q=0.4,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Referer: http://localhost/form.html
Content-Length: 88
Cookie: {{..to much data..}}
Pragma: no-cache
Cache-Control: no-cache
{"type":"my_type","comment":"commented"}
the sending function:
function submit(){
var data={};
data.type=document.form.type.value;
data.comment=document.form.comment.value;
//get right XMLHttpRequest object for current browsrer
var x=ajaxFunction();
var string = JSON.stringify(data);
x.open('POST','echo.php',true);
x.setRequestHeader('Content-type','application/json; charset=utf-8');
x.setRequestHeader("Content-length", string.length);
x.setRequestHeader("Connection", "close");
x.onreadystatechange = function(){
if (x.readyState != 4) return;
if (x.status != 200 && x.status != 304) {
alert('HTTP error ' + req.status);
return;
}
data.resp = JSON.parse(x.responseText);
if(data.resp.status=='success'){
alert('That worked!');
}else{
alert('That didn\'t work!');
}
}
x.send(string);
return false; //prevent native form submit
}

PHP does not process JSON requests automatically like it does with form-encoded or multipart requests. If you want to use JSON to send requests to PHP, you're basically doing it correctly with file_get_contents(). If you want to merge those variables into your global $_POST object you can, though I would not recommend doing this as it might be confusing to other developers.
// it's safe to overwrite the $_POST if the content-type is application/json
// because the $_POST var will be empty
$headers = getallheaders();
if ($headers["Content-Type"] == "application/json")
$_POST = json_decode(file_get_contents("php://input"), true) ?: [];
Quick note: you should not be sending a charset with your Content-Type for application/json. This should only be sent with text/* Content-Types.

You forgot to name your variables in the send function.
The good way to use it is
x.send('name1='+string+'&name2=value2');
Given that, I think you will have to change the content-length header. I don't think it is usefull to send it.
One another thing you can do is try with GET method.
You can also try to change your content-type header by that one :
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded")

Related

POST Empty Regardless of Request [duplicate]

This question already has answers here:
Receive JSON POST with PHP
(12 answers)
Closed 1 year ago.
I am using jQuery to submit the following request:
$.ajax({
url: encodeURI('/server/api/user/update.php/'),
method: 'POST',
contentType: 'application/json',
headers: {
'Authorization': 'Bearer ' + utility.getJsonWebToken()
},
data: JSON.stringify(e.model),
dataType: 'json'
})
And I have the following PHP code that verifies that the request is valid and contains the necessary body:
// check for bad method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
$returnedJson['error'] = 'The supplied request method is not supported for the requested resource. This resource expects a POST request.';
echo json_encode($returnedJson);
return;
}
// check for bad request
$errors = array();
$user = new UserModel();
foreach (UserModel::$RequiredColumnNames as $property) {
$success = ControllerUtility::isValueInRequest($_POST, $property);
if (!$success) {
array_push($errors, $property);
continue;
}
$user->$property = $_POST[$property];
}
if (count($errors) > 0) {
http_response_code(400);
$returnedJson['error'] = 'Malformed request syntax. The following properties are missing from the request: ' . join(', ', $errors);
echo json_encode($returnedJson);
return;
}
Every time I submit the request, I get 400 error with the 'Malformed request syntax. The following properties are missing from the request: ...' error message.
I echoed the $_POST and $_REQUEST but in both instances and empty array is returned.
I verified that the request headers is a POST:
POST /server/api/user/update.php/ HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:86.0) Gecko/20100101 Firefox/86.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Authorization: Bearer -removed-
X-Requested-With: XMLHttpRequest
Content-Length: 180
Origin: http://localhost
Connection: keep-alive
Referer: -removed-
Sec-GPC: 1
And the fields are included in my request JSON:
{
"CreatedBy": null,
"CreatedOn": "2021-02-28 13:53:54",
"DeletedOn": null,
"Email": "-removed-",
"ModifiedBy": "1",
"ModifiedOn": "2021-02-28 16:35:51",
"UserId": "1",
"Username": "Adminn"
}
I have even removed the content-type header from my PHP without success. I've also tried just passing e.model instead of calling stringify in the AJAX request. At this point I'm at a loss as to what I'm doing wrong.
// echo the json string from php://input.
file_get_contents('php://input');

Slim response-headers returning text/html instead of application/json

I am fairly new to Slim and so far have had no trouble -- everything has worked as expected, until this issue. I've searched and searched, but I must not be looking in the right place.
I'm using AngularJS with Slim and NotORM. So far I've got user authentication working and I'm working on a simple status update form that saves to a database table - 'post'. The form itself is simple and contains only a textarea element with ng-model set to 'message.text'. When submitted, doPost(message) is called in the controller:
$scope.doPost = function(message) {
Data.post('message', {
message: message
}).then(function(results) {
Data.toast(results);
loadRemoteData();
}, function(error) {
console.log('message failed to send: ' + error);
});
$scope.message = {
content: ''
}
}
My code in the Data service (Data.post('message')) is:
var obj = {};
obj.post = function (q, object) {
return $http.post(serviceBase + q, object)
.then(function(results) {
return results.data;
},
function(error) {
console.log('failed -->' + results.data + '<--');
});
};
return obj;
And then the PHP:
$app->post('/message', function() use ($app, $db) {
$response = array();
$r = json_decode($app->request->getBody());
$userid = $_SESSION['uid'];
$displayname = $_SESSION['displayname'];
verifyRequiredParams(array('text'), $r->message);
$message = $db->post();
$data = array(
'userid' => $uid,
'displayname' => $displayname,
'text' => $r->message->text
);
$result = $message->insert($data);
if($result != NULL) {
$response['status'] = 'success';
$response['message'] = 'Post successful';
$response['id'] = $result['id'];
echoResponse(200, $response);
} else {
$response["status"] = "error";
$response["message"] = "Failed to create message. Please try again";
echoResponse(200, $response);
}
});
And in echoResponse():
function echoResponse($status_code, $response) {
$app = \Slim\Slim::getInstance();
// Http response code
$app->status($status_code);
// setting response content type to json
$app->contentType('application/json');
echo json_encode($response);
}
And that's pretty much it to the code. There are no errors, but the message.text does not post to the database and the response returned is empty. I created another form on the page containing an input field of type text and it works fine, using duplicated methods. I have tried everything I could think of and what stands out to me is the Response-Header's Content-Type is somehow text/html instead of application/json (the test form shows json). The table I'm trying to post to looks like this:
CREATE TABLE IF NOT EXISTS `post` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) NOT NULL,
`displayname` varchar(50) CHARACTER SET utf8,
`text` text CHARACTER SET utf8,
`date` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=9 ;
Any help would be appreciated. Thanks.
Here are the headers:
Response Headers
Access-Control-Allow-Head... origin, x-requested-with, content-type
Access-Control-Allow-Meth... PUT, GET, POST, DELETE, OPTIONS
Access-Control-Allow-Orig... *
Connection Keep-Alive
Content-Length 0
Content-Type text/html
Date Fri, 09 Jan 2015 11:52:12 GMT
Keep-Alive timeout=5, max=92
Server Apache/2.2.26 (Unix) DAV/2 PHP/5.4.30 mod_ssl/2.2.26 OpenSSL/0.9.8za
X-Powered-By PHP/5.4.30
Request Headers
Accept application/json, text/plain, */*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Content-Length 32
Content-Type application/json;charset=utf-8
Cookie PHPSESSID=g9ooedu5kk513pk5f5djug42c4
Host localhost
Referer localhost
User-Agent Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:34.0) Gecko/20100101 Firefox/34.0
You can set the Slim app global content by using this method :
$app->contentType('application/json');
You need to grab the $response because it's a protected object...
$response = $app->response();
$response->header('Content-Type', 'application/json');
$app->render(
file_get_contents($app->config('templates') . $template), $myPageVars
);
I choose to actually work out the JSON within a template rather than dumping the PHP data directly out. Allows later altering your data feeds without screwing with the data source.
No accepted answer, so for the record from the documentation (Slim 3):
$newResponse = $oldResponse->withHeader('Content-type', 'application/json');
# $result is the whatever you want to output
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-type', 'application/json');

Manipulating JSON data with PHP

Scenario: Playing an online game, have an javascript file that allows me to port data to a PHP on a server using POST/json. I have to enter the path of my server into my client PC for this to work. I am getting a confirmation that connection is fine.
The PHP only recognises source from the website I am playing on, and I can see data transferring to the site in my developer console. The data being POSTed is in the following format:
I can see the data coming in an array looking at the console:
Request URL: //xxxxxx.xxxx/aix/server_api.php Request Method:POST Status Code:200 OK Request Headersview source Accept:application/json, text/javascript, */*; q=0.01 Accept-Charset:ISO-8859-1,utf-8;q=0.7,*;q=0.3 Accept-Encoding:gzip,deflate,sdch Accept-Language:en-GB,en-US;q=0.8,en;q=0.6 Connection:keep-alive Content-Length:65236 Content-Type:application/x-www-form-urlencoded; charset=UTF-8 Host:sd.fast-page.org Origin:http://xx.yyy.com Referer:http://xxx.yyy.com/232/index.aspx User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.22 (KHTML, like Gecko) Ubuntu Chromium/25.0.1364.160 Chrome/25.0.1364.160 Safari/537.22 Form Dataview sourceview URL encoded alliance[id]:118 alliance[name]:DS alliance[members]:12 alliance[score]:982078 data_type:city data[0][id]:12517457 data[0][owner_id]:1538 data[0][owner]:MM1 data[0][coords]:'081:191 data[0][name]:C31 4Chief data[0][score]:11020 data[0][city_type]:castle data[0][location]:land data[1][id]:12517458 data[1][owner_id]:1538 data[1][owner]:MM1 data[1][coords]:'082:191 data[1][name]:C31 5Redrum data[1][score]:10596 data[1][city_type]:castle data[1][location]:water data[2][id]:12386381 data[2][owner_id]:1538 data[2][owner]:MM1 data[2][coords]:'077:189 data[2][name]:C31 1Home data[2][score]:10460 data[2][city_type]:castle data[2][location]:land data[3][id]:12320847 data[3][owner_id]:1538 data[3][owner]:MM1 data[3][coords]:'079:188 data[3][name]:C31 6North data[3][score]:10182 data[3][city_type]:castle data[3][location]:land data[4][id]:12386382 data[4][owner_id]:1538 data[4][owner]:MM1 data[4][coords]:'078:189 data[4][name]:C31 3Back data[4][score]:10108 data[4][city_type]:castle data[4][location]:land data[5][id]:12517453 data[5][owner_id]:1538 data[5][owner]:MM1 data[5][coords]:'077:191 data[5][name]:C31 2Second data[5][score]:9968 data[5][city_type]:castle data[5][location]:land data[6][id]:12714060 data[6][owner_id]:1538 data[6][owner]:MM1 data[6][coords]:'076:194 data[6][name]:C31 MacoHub data[6][score]:9692 data[6][city_type]:castle data[6][location]:land data[7][id]:12517460 data[7][owner_id]:1538 data[7][owner]:MM1 data[7][coords]:'084:191 data[7][name]:C31 Tango data[7][score]:9163 data[7][city_type]:castle data[7][location]:land data[8][id]:12582993 data[8][owner_id]:1538 data[8][owner]:MM1 data[8][coords]:'081:192 data[8][name]:C31 Spring data[8][score]:8864 data[8][city_type]:castle data[8][location]:land data[9][id]:12517454 data[9][owner_id]:1538 data[9][owner]:MM1 data[9][coords]:'078:191 data[9][name]:C31 Pally data[9][score]:8816 data[9][city_type]:castle data[9][location]:land data[10][id]:12779603 data[10][owner_id]:1538
[and so on and so forth.....have masked the rest but this is the format
Response Headersview source Access-Control-Allow-Headers:Content-Type Access-Control-Allow-Methods:POST, GET, OPTIONS Access-Control-Allow-Origin: //xxx.yyy Access-Control-Max-Age:1000 Cache-Control:no-store, must-revalidate, max-age=0, proxy-revalidate, no-transform Connection:keep-alive Content-Encoding:gzip Content-Length:70 Content-Type:application/json Date:Fri, 29 Mar 2013 18:08:14 GMT Expires:Fri, 29 Mar 2013 18:08:14 GMT Pragma:no-cache Server:Apache Vary:Accept-Encoding X-Powered-By:PHP/5.5.0alpha5
Now what I see above is the output to the console on my PC when I trigger the client app.
The PHP is as follows:
$m = false;
if(preg_match('/http\:\/\/game url/',$_SERVER['HTTP_ORIGIN'],$m))
{ $m = $m[1]; }
if(empty($m)) { die('Invalid Origin.'); }
if(!empty($_POST['data_type']))
{
$sender = $_POST['sender'];
$alliance = $_POST['alliance'];
$request = $_POST['data_type'];
$data = $_POST['data'];
// Response to Alliance Info Exporter
$json = array(
'message' => 'recieved.',
'data' => array(),
'error' => false
);
// handle data types
switch($request)
{
case 'connection_test': $json['message'] = 'Welcome to our server. Your are connected!'; break;
case 'member' : /* Code for member request */ break;
case 'city' : /* Code for city request */ break;
case 'support' : /* Code for support request */ break;
default : $json['message'] = 'Nothing Done.'; break;
}
// set headers for API
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-type: application/json');
// Respond
die(json_encode($json));
}
die('No Access.');
I have two or three problems here
I can't seem to manipulate the data that the PHP is getting at all
Whenever I try to add any arguments to the case statement just to even see if I can parse the data somehow then the api stops responding to my client
For example, at the city switch I just tried to output the data to a file just to confirm it was coming through because my browser console gives me a POST success code (http 200)
This is the code I used:
$f = fopen("city.txt", "w");
fwrite($f, $_POST);
fclose($f);
I tried it in the main part of my PHP, tried it at the city case switch (that is the type of query I am executing first), and I tried with other defined types like $data, etc. Nothing writes.
What am I doing wrong?
Secondly my endstate is to post this to a SQL server, how would I do that?

Php ajax call for same php script response null

I am developing a single page script i.e. category.php for category management.
This script have an input button to invoke AJAX call.
<input type="button" id="btn" />
Jquery code to bind click event and call ajax. I want json response.
$(document).ready(function(e) {
$('#btn').click(function(e) {
id=1;
jQuery.ajax({
type: 'post',
url: 'category.php',
success: function(data) {
if(data.rstatus==1){
alert(data.text);
}else
alert(data);
},
data:{'id':id}
});
});
});
A php code to entertain AJAX call.
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) &&
strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$jsonResponse=array('rstatus'=>1,'id'=>$_POST['id']);
header("Content-type: application/json");
json_encode($jsonResponse);
die();
}
Problem:
This ajax call is unable to produce correct response in call back function, and cause error in firebug console.
TypeError: data is null
In FIREBUG Headers are as follow:
Response Headers
> Cache-Control no-cache, must-revalidate Connection Keep-Alive
> Content-Length 0 Content-Type application/json Date Tue, 26 Mar 2013
> 12:45:52 GMT Expires Mon, 26 Jul 1997 05:00:00 GMT
> Keep-Alive timeout=5, max=98 Last-Modified Tue, 26 Mar 2013
> 12:45:52GMT Pragma no-cache Server Apache/2.4.3 (Win32) OpenSSL/1.0.1c
> PHP/5.4.7 X-Powered-By PHP/5.4.7
Request Headers
> > Accept */* Accept-Encoding gzip, deflate
> > Accept-Language en-US,en;q=0.5 Content-Length 4
> > Content-Type application/x-www-form-urlencoded; charset=UTF-8
> > Cookie __gads=ID=39701a3d85dce702:T=1350383638:S=ALNI_MY_rHGVQ-qNxH4UGmbY_G-IuVcDkA;
> > __utma=141011373.593047819.1350426838.1364292528.1364295112.314;PHPSESSID=1s73cho6ildjt80jtudt8nq0f5 Host abc.com Referer http://www.abc.com/category.php
> > User-Agent Mozilla/5.0 (Windows NT 5.1; rv:19.0) Gecko/20100101
> > Firefox/19.0 X-Requested-With XMLHttpRequest
It's look like your response content is empty. You forgot an echo.
if(!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$jsonResponse=array('rstatus'=>1,'id'=>$_POST['id']);
header("Content-type: application/json");
echo json_encode($jsonResponse);
die();
}
If you want to response a json, you must put it in the response content. In Php, you just have to use echo to put something in the response content.
This doesn't work simply because $_SERVER doesn't contain that information. All request headers aren't really stored there. Have a look at getallheaders (http://php.net/manual/en/function.getallheaders.php)
Edit: Oh, also you need to echo the response. $_SERVER may contain the information you need in this case, but it is not reliable and portable. I'd still advise you to use getallheaders
don't use HTTP_X_REQUESTED_WITH - barely works in jQuery
try to send additional var, like
data:{'id':id, 'request':'xmlhttprequest'}

HTTP response contains text I don't understand

I have a PHP script that receives a file and returns a response.
The PHP script returns the response like this:
echo "<response><status>success</status><message>file received: test.txt</message></response>";
When I make the POST request from PuTTY, the response I receive is this:
6b
<response><status>success</status><message>file received: test.txt</message></response>
Depending on the response, the 6b could be something else as well? Is this the length of the response in hex, or something else?
The PHP script. Currently, I'm working on simply being able to POST a file and receive and parse the response, hence the PHP file is barebones.
<?php
if (array_key_exists('file',$_FILES) && $_FILES['file']['size'] != 0)
{
$status = 'success';
$message = "File received: " . $_FILES['file']['name'];
}
else
{
$status = 'failed';
$message = "No file received.";
}
$reply = "<response>"
."<status>" . $status . "</status>"
."<message>" . $message . "</message>"
."</response>";
echo $reply;
?>
I am establishing a RAW connection over port 80 on putty, and making the POST request like this:
POST /file_post.php HTTP/1.1
Host: example.com
Connection: Keep-Alive
Content-Length: 212
UserAgent: Mozilla/5.0
Content-Type: multipart/form-data; boundary=---------------------8ce9826eb81af6a
-----------------------8ce9826eb81af6a
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: application/octet-stream
TestData
-----------------------8ce9826eb81af6a--
Reponse received
This is Chunked Transfer Encoding http://en.wikipedia.org/wiki/Chunked_transfer_encoding
You can send request in http 1.0 instead of 1.1 to avoid this or you can decode it easily (check this out http://en.wikipedia.org/wiki/Chunked_transfer_encoding#Example ) really easy to decode ,
Or use php-curl, it will automatically decode the response for you.

Categories