React PHP get POST data - php

I'm trying to run a simple Web app over a ReactPHP Web server, but I can't figure out where to get POST data coming from an HTML form. The server is defined as:
include 'vendor/autoload.php';
register_shutdown_function(function() {
echo implode(PHP_EOL, error_get_last()), PHP_EOL;
});
$loop = React\EventLoop\Factory::create();
$socket = new React\Socket\Server($loop);
$http = new React\Http\Server($socket);
$http->on('request', function(React\Http\Request $request, React\Http\Response $response) {
print_r($request);
$response->writeHead(200, array('Content-type' => 'text/html'));
$response->end('<form method="POST"><input type="text" name="text"><input type="submit" name="submit" value="Submit"></form>');
});
$socket->listen(9000);
$loop->run();
When I post some string using the HTML form, the $request object, when printed on the console, looks like:
React\Http\Request Object
(
[readable:React\Http\Request:private] => 1
[method:React\Http\Request:private] => POST
[path:React\Http\Request:private] => /
[query:React\Http\Request:private] => Array
(
)
[httpVersion:React\Http\Request:private] => 1.1
[headers:React\Http\Request:private] => Array
(
[User-Agent] => Opera/9.80 (X11; Linux i686) Presto/2.12.388 Version/12.16
[Host] => localhost:9000
[Accept] => text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
[Accept-Language] => it,en;q=0.9
[Accept-Encoding] => gzip, deflate
[Referer] => http://localhost:9000/
[Connection] => Keep-Alive
[Content-Length] => 24
[Content-Type] => application/x-www-form-urlencoded
)
[listeners:protected] => Array
(
)
)
Here I can't find my data anywhere. I thought it should be located in the query property, but it's empty.
When I make GET requests, instead, data passed in the querystring can be found inside the query property of the $request object.
So, where can I find data passed with POST requests?

I repeat the last edit to my question here, so this question can be marked as answered.
Nevermind, found an answer here. Basically, it seems that React PHP does not support an easy way to read POST data yet. What we can do, though, is to read data as soon as it comes, watching the event data of the $request object:
$request->on('data', function($data) {
// Here $data contains our POST data.
// The $request needs to be manually ended, though.
});

Related

Making POST application/json request with file_get_contents

I made a code in PHP. The code works correctly when I run the command:
$payload = file_get_contents ('request.json');
However, I need to create dynamic content for the parameters passed by request.json
I made a routine that generates a string with exactly the same content as in the request.json file. However, when I pass this content to the $payload my function does not work.
$options = array (
'http' => array (
'header' => "Content-type: application / json",
'method' => 'POST',
'content' => $reqjson,
)
);
$context = stream_context_create ($options);
$result = file_get_contents ($url, false, $context);
Why is that? Isn't the type returned by the "file_get_contents" function a common string? How to fix it?
First, each line of header must end with "\r\n". Please append that to the "Content-Type" line. Second, if the function file_get_contents() returns false, it mean the request somehow failed. You should examine $http_response_header for more information:
$options = array(
'http' => array(
'header' => "Content-type: application/json\r\n",
'method' => 'POST',
'content' => $reqjson,
),
);
$context = stream_context_create($options);
if (($result = file_get_contents($url, false, $context)) === false) {
var_dump($http_response_header);
}
If the response header ($http_response_header) starts with HTTP/1.0 400 Bad Request, it means that the server somehow think your request is malformatted. Then,
If you have access to the requested server, try to find relevant log file(s) for more information.
If you have documentations to the requested server / service, please check carefully the accepted request format.
Often request format errors can be:
"appliation/json" is not an accepted request format; or
The content of $reqjson is malformat (e.g. it is supposed to be JSON text, not PHP array).
If you're using 3rd party service and still cannot figure out why it doesn't give you the expected result, seek help from the service provider.
Thanks, Koala Yeung.
As I said, the problem is that I tried to assemble in a string exactly the same content that is inside the request.json file. However, when I use the file_get_contents function to get the contents of the json file, it works. When it is directly in the string variable, the error occurs:
array (8) {[0] => string (24) "HTTP / 1.0 400 Bad Request" [1] => string (79) "x-cloud-trace-context: db4d34cce75495db89a04731bb718b49 / 1272894976542815412; o = 0" [2 ] => string (12) "vary: origin" [3] => string (45) "content-type: application / json; charset = utf-8" [4] => string (23) "cache-control: no-cache "[5] => string (19)" content-length: 229 "[6] => string (35)" Date: Tue, 08 Dec 2020 21:01:45 GMT "[7] => string (15) "Via: 1.1 google"}
bool (false)
I believe it is something related to this type of error:
"The content of $ reqjson is malformat (e.g. it is supposed to be JSON text, not PHP array)."
But the string is identical.

Vimeo API not responding to "If-Modified-Since" header

According to Vimeo API documentation:
The If-Modified-Since header enables you to return only those API resources that have been modified since a particular date and time.
The header looks like this:
If-Modified-Since: {ddd}, {D} {MMM} {YYYY} {HH}:{mm}:{ss} {Z}
NOTE: If your formatting codes are rusty, Tue, 20 Jun 2023 14:42:36 GMT is an example.
If none of the resources have been modified since this date, the API returns an empty response body and the HTTP status 304 Not Modified.
I'm using the Official PHP library for the Vimeo API.
According to GitHub issue #130, the PHP library's request() method accepts an array of headers. And this commit shows how the $headers array is passed and parsed:
public function request($url, $params = array(), $method = 'GET',
$json_body = true, array $headers = array())
// Set the headers
foreach ($headers as $key => $value) {
$curl_opts[CURLOPT_HTTPHEADER][] = sprintf('%s: %s', $key, $value);
}
But when I pass the future date shown in the example, I still receive a full list of videos rather than the "empty response body and the HTTP status 304 Not Modified" specified in the documentation.
What am I doing wrong?
$fields = array(
'created_time',
'modified_time'
);
$params = array(
'page' => $page,
'filter' => 'embeddable',
'filter_embeddable' => true,
'fields' => implode(',',$fields)
);
$headers = array(
'If-Modified-Since' => 'Tue, 20 Jun 2023 14:42:36 GMT'
);
$json_body = true;
$method = 'GET';
$response = $vimeo->request('/me/videos', $params, $method, $json_body, $headers);
Result:
Array
(
[0] => Array
(
[created_time] => 2018-06-05T19:27:18+00:00
[modified_time] => 2018-06-29T19:12:21+00:00
)
[1] => Array
(
[created_time] => 2016-06-02T03:01:40+00:00
[modified_time] => 2019-04-30T06:15:29+00:00
)
[2] => Array
(
[created_time] => 2016-05-29T05:31:46+00:00
[modified_time] => 2019-04-25T07:46:53+00:00
)
....
Edit
Based on this answer (not about Vimeo), it seems that the API might return the entire set of videos if even one of them was modified after the "If-Modified-Since" date.
If anything has changed in the entire response, then it will send the entire response to you.
But I'd still expect the result to be empty if the date is in the future. Am I misunderstanding?
Edit
Tom suggested that the Vimeo API ignores "If-Modified-Since" headers that are set in the future. I tried setting mine in the recent past, but I'm still getting results that were modified before that date:
$vimeo = new \Vimeo\Vimeo(false,false,$access_token);
$fields = array(
'modified_time'
);
$params = array(
'page' => 1,
'fields' => implode(',',$fields)
);
$method = 'GET';
$json_body = true;
$headers = array(
'If-Modified-Since' => 'Fri, 24 May 2019 14:42:36 GMT'
);
$response = $vimeo->request('/me/videos', $params, $method, $json_body, $headers);
echo"<pre>".print_r($response,true)."</pre>";
The result includes:
[21] => Array
(
[modified_time] => 2019-05-16T17:22:58+00:00
)
[22] => Array
(
[modified_time] => 2019-05-12T08:07:30+00:00
)
Edit
I was wrong. As mentioned above, I believe the entire response is returned if any item in the response has been modified since the "If-Modified-Since" timestamp. That made it look like the header wasn't working. But I set the timestamp as close as possible to the current time and I did get a "304 Not Modified" response, as Tom reported in his answer below. Others (content producers) also have access to the Vimeo account I'm testing against and I wasn't aware how recently they had modified content.
It's not documented by Vimeo, but I found out by experiment that:
When If-Modified-Since lies in the future, it is ignored.
Otherwise, the header works as expected. But take care of your timezones and possible clock-skew of a few seconds.
Vimeo's modification time is shown in the API response, in my case:
"modified_time": "2019-05-22T09:52:45+00:00",
If-Modified-Since: Wed, 22 May 2019 09:56:25 GMT returns a 304 Not Modified for my situation.
I've submitted a support request to Vimeo to clarify or change this behaviour.

Vimeo: how to use php official client to add a domain whitelist for a video?

I am using official Vimeo PHP client.
I can upload a video, and set privacy.embed to whitelist.
Then doc tells me:
To add a domain to the whitelist, send a PUT request to /videos/{video_id}/privacy/domains/{domain}.
I tried
$privacy_uri = $uri . "/privacy/domains/testdomain.tld";
$domain_add_response = $client->request($privacy_uri);
where
- $uri is the /vimeo/<video_id>
- $client is born from new Vimeo(CLIENT_ID, CLIENT_SECRET, VIMEO_TOKEN);
Problem
Printing the $domain_add_response I get a 405 error, probably because of Allow (see the following response dump)
Array
(
[body] =>
[status] => 405
[headers] => Array
(
[Server] => nginx
[Content-Type] => application/json
[Allow] => PUT,DELETE,OPTIONS
[X-Vimeo-DC] => ge
[Accept-Ranges] => bytes
[Via] => 1.1 varnish
[Content-Length] => 0
[Date] => Mon, 15 Apr 2019 08:30:47 GMT
[Connection] => keep-alive
[X-Served-By] => cache-bwi5125-BWI, cache-mxp19820-MXP
[X-Cache] => MISS, MISS
[X-Cache-Hits] => 0, 0
[X-Timer] => S1555317047.232635,VS0,VE148
[Vary] => Accept-Encoding
)
)
I imagine I must set the PUT method in my request, but ... how ?
Solution found looking at api source code: https://github.com/vimeo/vimeo.php/blob/master/src/Vimeo/Vimeo.php#L88
where the signature of request is
public function request($url, $params = array(), $method = 'GET', $json_body = true, array $headers = array()): array
I understand that I can fix the problem, simply passing an empty $params array and specifing PUT as request $method
I changed this line
$domain_add_response = $client->request($privacy_uri);
Into this form
$domain_add_response = $client->request($privacy_uri, [], 'PUT');
And it works as expected

Async Upload Using Curl in PHP - curl_multi_exec()

I'm trying to figure out for days how would it be possible if at all, to upload multiple files parallel using PHP.
given I have a class called Request with 2 methods register() and executeAll():
class Request
{
protected $curlHandlers = [];
protected $curlMultiHandle = null;
public function register($url , $file = [])
{
if (empty($file)) {
return;
}
// Register the curl multihandle only once.
if (is_null($this->curlMultiHandle)) {
$this->curlMultiHandle = curl_multi_init();
}
$curlHandler = curl_init($url);
$options = [
CURLOPT_ENCODING => 'gzip',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => $file,
CURLOPT_USERAGENT => 'Curl',
CURLOPT_HTTPHEADER => [
'Content-Type' => 'multipart/form-data; boundry=-------------'.uniqid()
]
];
curl_setopt_array($curlHandler, $options);
$this->curlHandlers[] = $curlHandler;
curl_multi_add_handle($this->curlMultiHandle, $curlHandler);
}
public function executeAll()
{
$responses = [];
$running = null;
do {
curl_multi_exec($this->curlMultiHandle, $running);
} while ($running > 0);
foreach ($this->curlHandlers as $id => $handle) {
$responses[$id] = curl_multi_getcontent($handle);
curl_multi_remove_handle($this->curlMultiHandle, $handle);
}
curl_multi_close($this->curlMultiHandle);
return $responses;
}
}
$request = new Request;
// For this example I will keep it simple uploading only one file.
// that was posted using a regular HTML form multipart
$resource = $_FILES['file'];
$request->register('http://localhost/upload.php', $resource);
$responses = $request->executeAll(); // outputs an empty subset of array(1) { 0 => array(0) { } }
Problem:
Can't figure out why on upload.php (the script which is my endpoint url on the register method) $_FILES is always an empty array:
upload.php:
<?php
var_dump($_FILES); // outputs an empty array(0) { }
Things I've already tried:
prefixing the data with #, like so:
$options = [
CURLOPT_ENCODING => 'gzip',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => ['file' => '#'.$file['tmp_name']],
CURLOPT_USERAGENT => 'Curl',
CURLOPT_HTTPHEADER => [
'Content-Type' => 'multipart/form-data; boundry=-------------'.uniqid()
]
];
That unfortunately did not work.
What am I doing wrong ?
how could I get the file resource stored in $_FILES global on the posted script (upload.php) ?
Further Debug Information:
on upload.php print_r the headers I get as response the following:
array(1) {
[0]=>
string(260) "Array
(
[Host] => localhost
[User-Agent] => Curl
[Accept] => */*
[Accept-Encoding] => gzip
[Content-Length] => 1106
[Content-Type] => multipart/form-data; boundary=------------------------966fdfac935d2bba
[Expect] => 100-continue
)
"
}
print_r($_POST) on upload.php gives the following response back:
array(1) {
[0]=>
string(290) "Array
(
[name] => example-1.jpg
[encrypted_name] => Nk9pN21IWExiT2VlNnpHU3JRRkZKZz09.jpg
[type] => image/jpeg
[extension] => jpg
[tmp_name] => C:\xampp\tmp\php77D7.tmp
[error] => 0
[size] => 62473
[encryption] => 1
[success] =>
[errorMessage] =>
)
"
}
I appreciate any answer.
Thanks,
Eden
Can't figure out why on upload.php (the script which is my endpoint url on the register method) $_FILES is always an empty array - your first problem is that you override libcurl's boundary string with your own, but you have curl generate the multipart/form-data body automatically, meaning curl generates another random boundary string, different from your own, in the actual request body, meaning the server won't be able to parse the files. remove the custom boundary string from the headers (curl will insert its own if you don't overwrite it). your second problem is that you're using $_FILES wrong, you need to extract the upload name if you wish to give it to curl, and you need to convert the filenames to CURLFile objects to have curl upload them for you. another problem is that your script will for no good reason use 100% cpu while executing the multi handle, you should add a curl_multi_select to prevent choking an entire cpu core. for how to handle $_FILES, see http://php.net/manual/en/features.file-upload.post-method.php
, for how to use CURLFile, see http://php.net/manual/en/curlfile.construct.php and for how to use curl_multi_select, see http://php.net/manual/en/function.curl-multi-select.php

Wordpress Instagram Plugin

I'm working with a wordpress plugin called Instagrabber: pluggin page. The plugin had been working perfectly for several months up until about a week ago when it started failing authentication while updating the image stream. At first, I thought the token expired, but after creating a few new testing accounts, the problem persisted.
I've isolated the problem to a couple lines of code in the main instagrabber-api.class.php file, pertaining to authenticating and retrieving the content:
$response = wp_remote_post( $request_uri, array(
'timeout'=> 10,
'method' => 'POST',
'body' => $data
)
);
$decoded_response = json_decode($response['body']);
This throws an 500 internal server error, and authentication fails. I've successfully authenticated using instagram's localhost setting, and connected with their API console, but when I make the request from our host, it fails.
This may not cover everything, so I'm happy to provide additional information, if needed.
** Edited **
Here are the values for $data and $response:
$data = Array (
'client_id' => $InstagramClientID,
'client_secret' => InstagramClientSecret,
'grant_type' => 'authorization_code',
'redirect_uri' => $InstagramRedirectURI,
'code' => $auth_code
)
If I print $data, everything appears fine, with all values pulling correctly.
$response is an array using wp_remote_post default return values, which can be found here for reference. The following is what we get returned:
Array (
[headers] =>
Array (
[cache-control] => no-cache
[content-type] => text/html
[date] => Mon, 07 Apr 2014 13:15:33 GMT
[server] => nginx
[content-length] => 87
[connection] => Close )
[body] =>
This seems to be where the 500 server error stems from. My thought is because of the Connection = Close, and empty body content.

Categories