- How Do I use curl_post_async() to Run PHP Script in the Background?
- How Do I use curl_post_async() to Run PHP Script in the Background?
- Как делать асинхронные HTTP-запросы в PHP?
- Библиотека Guzzle 6
- Асинхронные HTTP-запросы с использованием Promise
- Параллелизм в Promise
- Многопоточные запросы с cURL
- Pete Warden’s blog
- Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
- How to post an asynchronous HTTP request in PHP
How Do I use curl_post_async() to Run PHP Script in the Background?
Building Request Manually Add HTTP Request sampler and configure it as follows: Server Name: Port Number: Method: Path: Check for POST Switch to «Files Upload» tab Click «Add» and provide full path to logo.jpg file, as Parameter Name and as MIME Type Add HTTP Header Manager and provide your headers names and values there References: curl man page JMeter Proxy Step by Step How to Save ‘Loads’ of Time Using JMeter’s Template Feature Solution 2: For JMeter 5.1 or higher. Solution 1: Option 1: Record the request In JMeter: File -> Templates -> Recording -> Create Workbench -> HTTP(S) Test Script Recorder -> Start In console: Option 2:
How Do I use curl_post_async() to Run PHP Script in the Background?
I expected the followingcode would create a file, test.txt, in the same directory of the loading script when the page is accessed. But it doesn’t. Nothing happens. Could somebody tell what is wrong with this code? Does it work fine in your environment?
curl_post_async(selfurl(), array('cache' => true)); echo 'writing a log in the background.
'; return; function curl_post_async($url, $params) < //http://stackoverflow.com/questions/124462/asynchronous-php-calls foreach ($params as $key =>&$val) < if (is_array($val)) $val = implode(',', $val); $post_params[] = $key.'='.urlencode($val); >$post_string = implode('&', $post_params); $parts=parse_url($url); $fp = fsockopen($parts['host'], isset($parts['port'])?$parts['port']:80, $errno, $errstr, 30); $out = "POST ".$parts['path']." HTTP/1.1\r\n"; $out.= "Host: ".$parts['host']."\r\n"; $out.= "Content-Type: application/x-www-form-urlencoded\r\n"; $out.= "Content-Length: ".strlen($post_string)."\r\n"; $out.= "Connection: Close\r\n\r\n"; if (isset($post_string)) $out.= $post_string; fwrite($fp, $out); fclose($fp); > function selfurl() < // http://www.weberdev.com/get_example.php3?ExampleID=4291 $s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : ""; $protocol = strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s; $port = ($_SERVER["SERVER_PORT"] == "80") ? "" : (":".$_SERVER["SERVER_PORT"]); return $protocol."://".$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI']; >function strleft($s1, $s2) < return substr($s1, 0, strpos($s1, $s2)); >?>
Problem
The error in your script is in the following
if (isset($_POST['cache']) && $_POST['cache'] === true) < $file = dirname(__FILE__) . '/test.txt'; $current = time() . ": John Smith\r\n"; file_put_contents($file, $current,FILE_APPEND); return; >
$_POST[‘cache’] === true would try to validated of cache with same type as boolean but $_POST[‘cache’] would actually output 1 when posted over http using current method
Solution
if (isset($_POST['cache'])) < if ($_POST['cache'] == true) < $file = dirname(__FILE__) . '/test.txt'; $current = time() . ": John Smith\r\n"; file_put_contents($file, $current, FILE_APPEND); >return ; >
Как делать асинхронные HTTP-запросы в PHP?
Асинхронный HTTP-запрос помогают нам обрабатывать HTTP-запросы с использованием неблокирующего ввода или вывода в разных потоках. Некоторые называют это возможностями COMET . Основное использование асинхронных HTTP-запросов — это когда клиент запрашивает у сервера поздний ответ. Типичным примером является клиент чата AJAX , в котором мы отправляем или извлекаем данные как с клиента, так и с сервера. Эти сценарии блокируют клиента на длительное время в сокете сервера в ожидании нового сообщения.
PHP обслуживает запросы синхронно. Это означает, что каждая строка кода выполняется синхронно сценария. После получения результата из одной строки он выполняет следующую строку или ожидает результата, прежде чем перейти к выполнению следующей строки кода. Есть случаи, когда мы должны делать запросы к URL-адресам, а они не полагаются друг на друга. В этом сценарии мы не хотим ждать результата одного запроса для выполнения других запросов. Поэтому мы делаем асинхронные запросы.
Библиотека Guzzle 6
Guzzle — это HTTP-клиент на PHP, который помогает отправлять HTTP-запросы. Эти методы могут использоваться для отправки асинхронных HTTP-запросов.
- RequestAsync,
- SendAsync,
- GetAsync,
- HeadAsync,
- PutAsync,
- PostAsync,
- DeleteAsync,
- patchAsync
Скачайте пакет guzzle . Его можно установить через composer .
php composer.phar require guzzlehttp/guzzle:~6.0
composer require guzzlehttp/guzzle:~6.0
Включите файл autoload.php в часть кода сценария, чтобы он загружал все классы и методы.
getAsync('http://localhost') ->then(function ($response) < echo '10'; >), $client->getAsync('http://www.google.com') ->then(function ($response) < echo '20'; >), $client->getAsync('http://localhost') ->then(function ($response) < echo '30'; >), $client->getAsync('http://localhost') ->then(function ($response) < echo '40'; >), $client->getAsync('http://localhost') ->then(function ($response) < echo '50'; >), $client->getAsync('http://localhost') ->then(function ($response) < echo '60'; >), $client->getAsync('http://localhost') ->then(function ($response) < echo '70'; >), ]; $results = GuzzleHttp\Promise\unwrap($promises); // Please wait for a while to complete // the requests(some of them may fail) $results = GuzzleHttp\Promise\settle( $promises)->wait(); print "finish/over." . PHP_EOL; ?>
В приведенный выше код включается файл autoload.php , а затем создается клиентский объект GuzzleHttp, который сохраняется в переменной client , и для каждого запроса Http используется метод getAsync() с URL-адресом.
Запрос, получивший первый ответ, выведет номер. Порядок запроса не имеет значения.
Асинхронные HTTP-запросы с использованием Promise
При использовании Promise результат асинхронной операции представляет собой Promise (специальный объект, который содержит своё состояние). Асинхронные запросы используются для неблокирующих операций HTTP. Когда асинхронные HTTP-запросы отправляют Promise, то возвращается состояние.
Выполним запрос с помощью HTTPlug:
$request = $messageFactory->createRequest( 'GET', 'http://php-http.org'); $Promise = $client->sendAsyncRequest ($request); echo 'Неблокирующий!';
«Promise», который возвращается из вышеупомянутого, реализует http\Promise\Promise .
$promise->wait() будет ожидать получения ответа
try < $response = $promise->wait(); > catch (\Exception $exception) < echo $exception->getMessage(); >
Вместо ожидания мы можем выполнять шаги асинхронно. Для этого нужно вызвать метод then с двумя аргументами.
- Функция обратного вызова, которая будет выполнена, если запрос окажется успешным.
- Функция обратного вызова, которая будет выполнена, если запрос приведет к ошибке.
// Success Callback function (ResponseInterface $response) < echo 'New response!'; // Write status code to the log file file_put_contents('responses.log', $response->getStatusCode() . "\n", FILE_APPEND); return $response; >, // Failure Callback function (\Exception $exception)
Параллелизм в Promise
Параллелизм означает одновременное выполнение нескольких вычислений. Обрабатка большого количества запросов одновременно может улучшить производительность. Для параллелизма мы должны использовать класс EveryPromise и генератор yield и, наконец, добавить wait() в конец программы.
getAsync( 'https://api.demo.com/v1/users?username=' . $user); > >)(); $eachPromise = new EachPromise($promises, [ // Number of concurrency 'concurrency' => 4, 'fulfilled' => function (Response $response) < if ($response->getStatusCode() == 200) < $user = json_decode( $response->getBody(), true); // processing response of the user > >, 'rejected' => function ($reason) < // handle promise rejected >]); $eachPromise->promise()->wait(); ?>
Многопоточные запросы с cURL
PHP как правило, может обрабатывать несколько запросов. Сначала мы запускаем первый и обрабатываем ответ, затем второй и третий и так далее. Но этот процесс медленный и требует много времени. Но предлагает функции curl_multi_ * для обработки любых asnyc-запросов.
$running = null; $mh = curl_multi_init(); $ch1 = curl_init(); curl_setopt($ch1, CURLOPT_URL, ‘https://endpoint.com’); // Other curl options… curl_multi_add_handle($mh, $ch1); $ch2 = curl_init(); curl_setopt($ch2, CURLOPT_URL, ‘https://endpoint.com’); // Other curl options… curl_multi_add_handle($mh, $ch2); do < curl_multi_exec($mh, $running); curl_multi_select($mh); >while ($running > 0); $r1 = curl_multi_getcontent($ch1); $r2 = curl_multi_getcontent($ch2); curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh);
Ответы собираются в переменных «r1» и «r2». С помощью этих функций cURL мы можем запускать запросы параллельно, чтобы сэкономить время и быстрее обрабатывать ответы.
Pete Warden’s blog
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
How to post an asynchronous HTTP request in PHP
The way users make things happen with web applications is by fetching from a URL, passing in some parameters, eg http://somewhere.com/somescript.php?action=dosomething. For an architecture like Facebook, this is also how API calls are made. I was pretty surprised to find that PHP has a hard time doing something this simple asynchronously.
The key problem is that most HTTP libraries are designed around two-way communication. You send off a request and then wait for a response. In this case I don’t want a reply, I just want the request to trigger some action on the other end, which might eventually involve that server calling me back with a similar fetch with some result, or it might just update an internal database. I want my PHP script to fire off that request and then continue executing, but the cURL functionality that’s built in always waits for the response before carrying on.
At first, I just needed to make an occasional call like this, and I found a hacky solution that set the timeout on the cURL fetch to 1 second. This meant the request was fired off, but then almost immediately timed-out. The problem is that almost immediately wasn’t fast enough once you start calling this frequently, that 1 second every time builds up, and you can’t set the timeout to 0. Here’s that code:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, ‘curl’);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$result = curl_exec($ch);
curl_close($ch);
>
I needed something that didn’t have that one-second penalty every time. PHP doesn’t support threads out of the box, so I looked at using its flavor of fork, pcnt_fork(). It was looking promising until I realized that it’s disabled by default in Apache, with some reason since there’s a lot of process baggage to copy when it’s running in that environment. I then toyed with the idea of using exec to spawn a cURL command-line instance to carry out the command, but that just seemed ugly, fragile and too heavy-weight. I looked at PHP’s HTTP streams too, but they are also synchronous.
I was getting frustrated because HTTP is a simple protocol at heart, and it shouldn’t be this hard to do what I need.
At last, White Shadow came to the rescue. His post talks about a few different ways of doing what I need, but importantly he has one based on raw sockets, and closing the connection immediately after writing the post data. This is exactly what I needed, it fires off the request and then returns almost immediately. I was able to get a lot better performance using this technique.
$fp = fsockopen($parts[‘host’],
isset($parts[‘port’])?$parts[‘port’]:80,
$errno, $errstr, 30);
pete_assert(($fp!=0), «Couldn’t open a socket to «.$url.» («.$errstr.»)»);
$out = «POST «.$parts[‘path’].» HTTP/1.1\r\n»;
$out.= «Host: «.$parts[‘host’].»\r\n»;
$out.= «Content-Type: application/x-www-form-urlencoded\r\n»;
$out.= «Content-Length: «.strlen($post_string).»\r\n»;
$out.= «Connection: Close\r\n\r\n»;
if (isset($post_string)) $out.= $post_string;