understanding php curl_multi_exec
You can explore two article that describes this example.
PHP and curl_multi_exec
First, here's the high level. There are two outer loops. The first one is responsible for clearing out the curl buffer right now. The second one is responsible for waiting for more information, and then getting that information. This is an example of what is called blocking I/O. We block execution of the rest of the program until the network I/O is done. While this isn't the most preferable way in general to handle network I/O, it's really our only choice in single-threaded, synchronous PHP.
Doing curl_multi_exec the right way
First the
$mrc
variable and from the manual we learn that the response is a cURL code defined in the cURL Predefined Constants. In essence it is a regular response and as with any other PHP functioncurl_multi_exec
is no different and only returns a response once it is finished. Which means there should be only ONE response. In a perfect world this single response is 0 (zero) or equal to the predefined constantCURLM_OK
.
PHP curl_multi_exec output to array
Solved it by changing the ${'ch_'.$i}
to an array $ch[$i]
then looping through the array using curl_multi_getcontent
as follows:
foreach ($ch as $a)
{
$result = curl_multi_getcontent($a);
parse_str($result, $arr);
print_r($arr);
echo "--------------------------------------------------\n";
}
This then lets me the data in the array $arr
. For example, $arr['EMAIL'];
See as well: Curl Multi and Return Transfer and understanding php curl_multi_exec.
Make curl_multi 'sleep' or wait before sending next request
function asyncCurl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
}
$timeout = 3; // in seconds
$urls = array(...);
foreach($urls as $url){
asyncCurl($url);
sleep($timeout);
}
If you need to get the response, it can still be done by creating a "background process" type of thing on your server. This will require 2 scripts instead of one.
background.php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
$a = curl_exec($ch);
curl_close($ch);
return $a;
}
$response = curl($_GET['url']);
// code here to handle the response
doRequest.php (or whatever, this is the one you will call in your browser)
function asyncCurl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "mydomain.com/background.php?url=".urlencode($url));
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
curl_exec($ch);
curl_close($ch);
}
$timeout = 3; // in seconds
$urls = array(...);
foreach($urls as $url){
asyncCurl($url);
sleep($timeout);
}
The idea here is that PHP is single threaded, but there is no reason you can't have more than one PHP process running at the same time. The only downside is that you have to make the requests on one script and handle the response on another.
Option 3: display the output as soon as it becomes available.
This method is exactly the same as the one above, except that it uses javascript to create a new php process. You didn't have javascript tagged, but this is the only way to accomplish both
- asynchronous requests w/ a timeout
and
display the response as soon as it's available
doRequest.php
<?php
$urls = array(); // fill with your urls
$timeout = 3; // in seconds
if (isset($_GET['url'])) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_GET['url']);
$a = curl_exec($ch);
curl_close($ch);
echo $a;
exit;
}
?><html>
<body>
<div id='results'></div>
<script>
var urls = <?php echo json_encode($urls); ?>;
var currentIndex = 0;
function doRequest(url) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (xhttp.readyState == 4 && xhttp.status == 200) {
document.getElementById("results").insertAdjacentHTML("beforeend", "<hr>" + xhttp.responseText);
}
};
xhttp.open("GET", "doRequest.php?url=" + encodeURIComponent(url), true);
xhttp.send();
}
var index=0;
function startLoop(){
var url = urls[index];
doRequest(url);
setTimeout(function(){
index++;
if('undefined' != urls[index]) startLoop();
}, <?php echo $timeout*1000; ?>);
}
startLoop();
</script>
</body>
What's happening is you server is creating a new request for each url and then using normal curl to get the response, but instead of using curl to create the new process, we use ajax which is async by nature and has the ability to create multiple PHP processes and wait for the response.
Godspeed!
How many times does curl_multi_exec have to be called?
curl_multi_exec() reads and writes data to the socket. It stops when it cannot write or read.
So the number of needed calls depends on the amount of data to be transfered and the speed of the network. curl_multi_select() waits till a socket becomes readable or writable.
You should use the curl_multi_select() and have all hosts inside one multi-handle.
Check curl_getinfo() or curl_multi_info_read() if you need to know the duration of the individual requests.
PHP curl_multi_exec runs once
You're not setting up the curl
options correctly:
Currently, you're setting options on $ch
which is your array, you need to be setting the options specifically on the current curl handler, which in your loop is $ch[$id]
:
//Initialize and set options
curl_setopt($ch[$id], CURLOPT_URL, $url);
curl_setopt($ch[$id], CURLOPT_HEADER, 0);
curl_setopt($ch[$id], CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch[$id], CURLOPT_POST, 1);
curl_setopt($ch[$id], CURLOPT_POSTFIELDS, $request);
Related Topics
How to Send Notification to Android from PHP
Getting List Ips from Cidr Notation in PHP
How to Detect Non-Ascii Characters in a String
MySQL Query In() Clause Slow on Indexed Column
Select Last 20 Order by Ascending - PHP/Mysql
Is There an Equivalent in C++ of PHP's Explode() Function
How to Make a Catch-All Route in Laravel
PHP Directory List from Remote Server
Mysql_Insert_Id Alternative for Postgresql
PHP MySQL_Real_Escape_String() -> Stripslashes() Leaving Multiple Slashes
Magento - Load Only Configurable Products
Convert to Date Format Dd/Mm/Yyyy
MySQL Join Multiple Rows as Columns
How to Match Accented Characters with PHP Preg
Why Does PHP Not Complain When I Treat a Null Value as an Array Like This