PHP cURL request body is undefined in node.js - php

I've tried all the examples on these SO posts:
How do I send a POST request with PHP?
PHP cURL Post request not working
Always my request.body is undefined yet in the request itself I see "_hasBody":true
The current code for my php post file:
function httpPost($url,$data){
$curl = curl_init($url);
curl_setopt($curl,CURLOPT_POST,true);
curl_setopt($curl,CURLOPT_POSTFIELDS,http_build_query($data));
curl_setopt($curl,CURLOPT_RETURNTRANSFER,true);
$response=curl_exec($curl);
curl_close($curl);
return $response;
}
$fields = array(
'name' => 'ben'
, 'foo' => 'bar'
);
echo httpPost("http://localhost:8002", $fields);
Then my node.js listening server code is:
var test=require('http').createServer(function(q,a){//question,answer
console.log(q.body);
console.log(JSON.stringify(q).indexOf('ben'));
a.end(JSON.stringify(q));
});
test.listen(8002,function(e,r){console.log("listening");});
As you can see, in the node.js server I search the request for my name but the console says
undefined//no body
-1//could not find your name in the request
then I hand over the request back to the response and print it to the page so I can see the whole data.
logically it would seem that I am doing the cURL part right as its copied code, so I would say I might be doing something wrong to access the vars
My question is how do I see the request body or where the vars?

To handle a POST request, you have to do the following:
var qs = require('querystring');
var http = require('http');
var test = http.createServer(function(req, res) {
//Handle POST Request
if (req.method == 'POST') {
var body = '';
req.on('data', function(data) {
body += data;
});
req.on('end', function() {
var POST = qs.parse(body);
console.log(body); // 'name=ben&foo=bar'
console.log(POST); // { name: 'ben', foo: 'bar' }
if(POST.name == 'ben')
console.log("I'm ben"); //Do whatever you want.
res.setHeader("Content-Type", "application/json;charset=utf-8");
res.statusCode = 200;
res.end(JSON.stringify(POST)); //your response
});
}
});
test.listen(8002, function(e, r) {
console.log("listening");
});
cURL response:
{"name":"ben","foo":"bar"}

Related

How to send a message to the client from the backend server use Workerman?

Please help me figure out the Workerman library I'm using for websockets.
server.php:
use Workerman\Worker;
require_once '/usr/local/workerman/vendor/autoload.php';
$ws_worker = new Worker('websocket://1.1.1.1:2346');
$ws_worker->onWorkerStart = function($ws_worker)
{
$http_worker = new Worker('http://127.0.0.1:2023');
$http_worker->onMessage = function($http_connection, $request) use ($ws_worker) {
//this code does not work:
foreach($ws_worker->connections as $connection) {
$connection->send($request);
}
};
$http_worker->listen();
};
// this code works correctly:
$ws_worker->onMessage = function ($con, $data) use ($ws_worker) {
foreach($ws_worker->connections as $connection) {
$connection->send($data);
}
};
Worker::runAll();
client.html:
<input type="number" id="input" onchange="ws.send(value); value='';" autofocus="autofocus">
<br><br>
<div id="div" rows="2"></div>
<script>
ws = new WebSocket("ws://1.1.1.1:2346");
const div = document.getElementById('div');
const input = document.getElementById('input');
ws.onopen = function() {
alert("connection success");
console.log(ws);
};
ws.onmessage = function(e) {
div.innerText += e.data + "\n";
console.log(e.data + "\n");
};
</script>
The data sent from input in client.html is successfully displayed in DIV on the client.html page.
My problem is sending data from backend PHP script. For this I use the following code:
$url = 'http://127.0.0.1:2023';
$data = '12345'; // or '{"data": "12345"}'
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_POSTFIELDS => $data,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => array("Content-Type: application/json")
]);
$curl_result = curl_exec($ch);
curl_close($ch);
var_export($curl_result); // return true
I expect that '12345' should appear in the DIV on the client.html page, but this does not happen. I believe that the event '$http_worker->onMessage' does not work.
What am I doing wrong?
It appears that the issue is that you're sending data to the HTTP worker using a POST request, but you're trying to read that data in the onMessage event of the HTTP worker. The onMessage event is triggered when the HTTP worker receives an HTTP request with a GET method, not POST.
To fix this, you can modify your client.html to use a POST request to send data to the backend PHP script, and then have the PHP script send the data to the WebSocket server. Here's an example:
client.html:
<form id="form">
<input type="text" id="input" name="input">
<input type="submit" value="Send">
</form>
<div id="div"></div>
<script>
const form = document.getElementById('form');
const input = document.getElementById('input');
const div = document.getElementById('div');
const ws = new WebSocket("ws://1.1.1.1:2346");
ws.onmessage = function(e) {
div.innerText += e.data + "\n";
};
form.addEventListener('submit', function(e) {
e.preventDefault();
const data = new FormData(form);
fetch('/send.php', { method: 'POST', body: data });
input.value = '';
});
</script>
In this example, when the form is submitted, it sends a POST request to /send.php with the data from the input field. The input field is then cleared. You can replace the existing input field in your client.html with this code.
Then, in your backend PHP script, you can receive the data and send it to the WebSocket server using the following code:
send.php:
<?php
$data = $_POST['input'];
$context = stream_context_create();
$socket = stream_socket_client('tcp://1.1.1.1:2346', $errno, $errstr, 5, STREAM_CLIENT_CONNECT, $context);
if ($socket) {
fwrite($socket, json_encode($data));
fclose($socket);
}
In this code, we create a socket connection to the WebSocket server using stream_socket_client(), and then write the data to the socket using fwrite(). Note that we're using json_encode() to encode the data as a JSON string, because the WebSocket server is expecting JSON-encoded data.
With these changes, when you submit the form in client.html, the data should be sent to the WebSocket server and appear in the DIV element.

How to set $_POST values in Node JS child process

I hosted my Slim app on AWS Lambda. For my PHP app to work, I followed this tutorial
My app runs fine until I try to submit a form with a POST method. My PHP cannot get the values from the form. When I dumped $_POST and file_get_contents('php://input'), both returned a null.
In the tutorial, Chris (the author) stated that this code spawns the child process and sets a bunch of environment variables which PHP CGI populates into the $_SERVER super global.
var php = spawn('./php-cgi', ['function.php'], {
env: Object.assign({
REDIRECT_STATUS: 200,
REQUEST_METHOD: requestMethod,
SCRIPT_FILENAME: 'function.php',
SCRIPT_NAME: '/function.php',
PATH_INFO: '/',
SERVER_NAME: serverName,
SERVER_PROTOCOL: 'HTTP/1.1',
REQUEST_URI: requestUri
}, headers)
});
I am not familiar with child processes, so I would like to ask if there is a way that I can also populate the $_POST superglobal? Because I think the POST data lives in the event object/variable in my handler function, meaning (I think) my NodeJS wrapper could access the POST data, but it didn't pass it to the PHP CGI?
exports.handler = function(event, context)
here is the full code of my NodeJS wrapper:
var spawn = require('child_process').spawn;
var parseHeaders, parseResponse, parseStatusLine;
parseResponse = function(responseString) {
var headerLines, line, lines, parsedStatusLine, response;
response = {};
lines = responseString.split('\r\n');
parsedStatusLine = parseStatusLine(lines.shift());
response['protocolVersion'] = parsedStatusLine['protocol'];
response['statusCode'] = parsedStatusLine['statusCode'];
response['statusMessage'] = parsedStatusLine['statusMessage'];
headerLines = [];
while (lines.length > 0) {
line = lines.shift();
if (line === "") {
break;
}
headerLines.push(line);
}
response['headers'] = parseHeaders(headerLines);
response['body'] = lines.join('\r\n');
return response;
};
parseHeaders = function(headerLines) {
var headers, key, line, parts, _i, _len;
headers = {};
for (_i = 0, _len = headerLines.length; _i < _len; _i++) {
line = headerLines[_i];
parts = line.split(":");
key = parts.shift();
headers[key] = parts.join(":").trim();
}
return headers;
};
parseStatusLine = function(statusLine) {
var parsed, parts;
parts = statusLine.match(/^(.+) ([0-9]{3}) (.*)$/);
parsed = {};
if (parts !== null) {
parsed['protocol'] = parts[1];
parsed['statusCode'] = parts[2];
parsed['statusMessage'] = parts[3];
}
return parsed;
};
exports.index = function(event, context) {
// Sets some sane defaults here so that this function doesn't fail when it's not handling a HTTP request from
// API Gateway.
var requestMethod = event.httpMethod || 'GET';
var serverName = event.headers ? event.headers.Host : '';
var requestUri = event.path || '';
var headers = {};
// Convert all headers passed by API Gateway into the correct format for PHP CGI. This means converting a header
// such as "X-Test" into "HTTP_X-TEST".
if (event.headers) {
Object.keys(event.headers).map(function (key) {
headers['HTTP_' + key.toUpperCase()] = event.headers[key];
});
}
// Spawn the PHP CGI process with a bunch of environment variables that describe the request.
var php = spawn('./php-cgi', ['slim/public/index.php'], {
env: Object.assign({
REDIRECT_STATUS: 200,
REQUEST_METHOD: requestMethod,
SCRIPT_FILENAME: 'slim/public/index.php',
SCRIPT_NAME: '/index.php',
PATH_INFO: '/',
SERVER_NAME: serverName,
SERVER_PROTOCOL: 'HTTP/1.1',
REQUEST_URI: requestUri
}, headers)
});
// Listen for output on stdout, this is the HTTP response.
var response = '';
php.stdout.on('data', function(data) {
response += data.toString('utf-8');
});
// When the process exists, we should have a complete HTTP response to send back to API Gateway.
php.on('close', function(code) {
// Parses a raw HTTP response into an object that we can manipulate into the required format.
var parsedResponse = parseResponse(response);
// Signals the end of the Lambda function, and passes the provided object back to API Gateway.
context.succeed({
statusCode: parsedResponse.statusCode || 200,
headers: parsedResponse.headers,
body: parsedResponse.body
});
});
};
In some cases it's necessary to set CONTENT_LENGTH and/or CONTENT_TYPE in the environment in order for php-cgi to process $_POST properly. For example (where postBody is a string like "field1=value1&field2=value2"):
var env = {
'SCRIPT_FILENAME': script_path,
'REQUEST_METHOD': 'POST',
'REDIRECT_STATUS': 1,
'CONTENT_TYPE': 'application/x-www-form-urlencoded',
'CONTENT_LENGTH': postBody.length
}
//if the URL has anything after "?", it should appear in $_GET even when the method is "POST"
if(queryString) env['QUERY_STRING'] = queryString;
The post body needs to be input into the stdin of the child.
Here is an async example:
var spawn = require('child_process').spawn;
var phpProcess = spawn (php_cgi_path, [script_path], {'env': env})
phpProcess.stdin.write( postBody );
var outputBuffer = [];
phpProcess.stdout.on('data', function(data) {
outputBuffer.push (data.toString());
})
phpProcess.stdout.on('end', function( ) {
var phpOutput = outputBuffer.join('') ;
// process php output
});
It's also possible to give the input data in a synchronous way, for example:
var spawnSync = require('child_process').spawnSync;
var phpProcessSync = spawnSync (php_cgi_path, [script_path], {'env': env, 'input': postBody})
var phpOutput = phpProcessSync.stdout.toString()
// process php output
Again the post data is input separately from "env".
It's also possible to modify the script so that it populates $_FILES as well.
For example, one can use Uint8Array (instead of string) to store post body, then set 'CONTENT_TYPE' to request.headers['content-type'] (Then we would have for example "Content-Type:multipart/form-data; boundary=----WebKitFormBoundarynGa8p8HMIQ8kWQLA")then use phpProcess.stdin.write( Buffer.from(postBody) );
It will have "tmp_name" etc in the $_FILES variable.

$http angularjs php response

Quite new to angularjs, but already done some research.
I'm making the following $http post request:
$scope.onClick2 = function () {
var myRequest = {};
myRequest = {};
myRequest.ServiceType = "SearchExams";
myRequest.SessionId = 'SessionlessRequest';
myRequest.Compression = 'no';
myRequest.Parameters = {};
myRequest.Parameters.Status = ['30', '40'];
myRequest = JSON.stringify(myRequest);
var request = $http({
method: 'POST',
url: 'http://localhost/request.php',
data: 'data=' + myRequest,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
})
};
My request.php handles the request and sends back an json response.
Howerver I see in the response tab of chrome and in fiddler that the original request is also in the response. See below:
Array
(
[data] => {"ServiceType":"SearchExams","SessionId":"SessionlessRequest","Compression":"no","Parameters":{"Status":["30","40"]}}
)
{"Error":false,"ErrorMessage":null,"Data":[{"ExamID":1,"A.......
I would expect only the last line ({"Error":false,"ErrorMessage":null,"Data":[{"ExamID":1,"A...... to be returned....looking at what my request.php send back it should.
Am I missing something?
Thanks,
Sorry for waisting anybodies time on this.
There was an error in my php code indeed.

From node.js request JSON file to PHP

From node.js I would like to get JSON data from a PHP file. I thought about using the request package, but I am not sure about what to write in the PHP file in order to send the JSON back to node:
Node:
var request = require('request');
request
.get('http://IP/File.php')
.on('response', function(response) {
data = JSON.parse(data from the php file);
});
PHP:
$data = array('message' => 'HeLLO');
$json = json_encode($data);
when executing this, send $json to node
you need to print a response from your .PHP file:
$data = array('message' => 'HeLLO');
$json = json_encode($data);
print_r($json);
javascript:
var request = require('request');
request('http://IP/File.php', function (error, response, body) {
if (!error && response.statusCode == 200) {
data = JSON.parse(body)[0];
}
})

jquery ajax request seems to hang after a few requests

I have several objects on my page that I iterate through and make an ajax request to request the status either on or off. They are lights controlled by homeseer automation software.
Using firebug I can see all the being made and the responses coming back. when I press a light, I check the status of all lights, in case the status for the lights has changed. After about the third click, I can see all the requests being made but no response coming back.
Jquery passes the url to a PHP script which makes the call and returns the data to jquery this gets around cross domain security.
I can open up another tab and copy the url post statement into the address and the page displays the response.
Am I not closing something when I have finished with my request/ why after the third click are requests made but no response back???
here is my code
function X10Check(){
//This Ajax checks the current on/off status of the passed X10 code
$('div.lightchk').each(function(i, obj) {
$x10Device = $(this).data("x10");
var element = $(this);
var data = "url=http://192.168.0.34:81/tenHsServer/tenHsServer.aspx?t=ab&f=DeviceStatus&d=" + $x10Device ;
$.ajax({
url:"urlencode.php",
data: data,
type: "POST",
success: function(data)
{
myd = $('<span />').html(data).find("#Result").text();
var Nmyd = myd.charAt(3);
if (Nmyd ==':')Nmyd = myd.charAt(4);
if (Nmyd == '2'){element.removeClass('off').addClass('on')}else{element.removeClass('on').addClass('off')};
},
error: function (request, status, error)
{
// alert(request.responseText);
}
});
});
};
it makes a php call here is the php call using the php script allows me to get around cross domain security issues.
<?php
//set POST variables
$url = $_POST['url'];
unset($_POST['url']);
$fields_string = "";
//url-ify the data for the POST
foreach($_POST as $key=>$value) {
$fields_string .= $key.'='.urlencode($value).'&';
}
rtrim($fields_string,"&");
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
$url .= '&';
$url .= $fields_string;
curl_setopt($ch,CURLOPT_URL,$url);
//execute post
$string = curl_exec($ch);
curl_exec($ch);
curl_close($ch);
?>

Categories