Skip to content

Instantly share code, notes, and snippets.

@xeoncross
Created April 11, 2012 21:44
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save xeoncross/2362936 to your computer and use it in GitHub Desktop.
Save xeoncross/2362936 to your computer and use it in GitHub Desktop.
cURL asynchronous requests using curl_multi and callbacks
<?php
require('Requests.php');
// We want the requests to be mixed fast/slow so we can see if it's working
$slow = 'http://localhost/curl_multi/slow.php';
$fast = 'http://localhost/curl_multi/fast.php';
$urls = array();
for ($i = 0; $i < 10; $i++)
{
if($i % 2)
{
print "Slow\n";
$urls[] = $slow;
}
else
{
print "Fast\n";
$urls[] = $fast;
}
}
$callback = function($data, $info)
{
print "Callback: ";
print_r($data);
print_r($info);
};
$requests = new Requests();
$requests->process($urls, $callback);
<?php
usleep(mt_rand(10000, 200000));
print basename(__FILE__) . "\n";
<?php
/**
* Make asynchronous requests to different resources as fast as possible and process the results as they are ready.
*/
class Requests
{
public $handle;
public function __construct()
{
$this->handle = curl_multi_init();
}
public function process($urls, $callback)
{
foreach($urls as $url)
{
$ch = curl_init($url);
curl_setopt_array($ch, array(CURLOPT_RETURNTRANSFER => TRUE));
curl_multi_add_handle($this->handle, $ch);
}
do {
$mrc = curl_multi_exec($this->handle, $active);
if ($state = curl_multi_info_read($this->handle))
{
//print_r($state);
$info = curl_getinfo($state['handle']);
//print_r($info);
$callback(curl_multi_getcontent($state['handle']), $info);
curl_multi_remove_handle($this->handle, $state['handle']);
}
usleep(10000); // stop wasting CPU cycles and rest for a couple ms
} while ($mrc == CURLM_CALL_MULTI_PERFORM || $active);
}
public function __destruct()
{
curl_multi_close($this->handle);
}
}
<?php
// This limits the request rate to the size of the $rolling_window
// http://www.onlineaspect.com/2009/01/26/how-to-use-curl_multi-without-blocking/
function rolling_curl($urls, $callback, $custom_options = null)
{
// make sure the rolling window isn't greater than the # of urls
$rolling_window = 5;
$rolling_window = (sizeof($urls) < $rolling_window) ? sizeof($urls) : $rolling_window;
$master = curl_multi_init();
$curl_arr = array();
// add additional curl options here
$std_options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5
);
$options = ($custom_options) ? ($std_options + $custom_options) : $std_options;
// start the first batch of requests
for ($i = 0; $i < $rolling_window; $i++)
{
$ch = curl_init();
$options[CURLOPT_URL] = $urls[$i];
curl_setopt_array($ch,$options);
curl_multi_add_handle($master, $ch);
}
do {
while(($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM);
if($execrun != CURLM_OK)
break;
// a request was just completed -- find out which one
while($done = curl_multi_info_read($master))
{
$info = curl_getinfo($done['handle']);
$output = curl_multi_getcontent($done['handle']);
// request successful. process output using the callback function.
$callback($output, $info);
if(isset($urls[$i + 1]))
{
// start a new request (it's important to do this before removing the old one)
$ch = curl_init();
$options[CURLOPT_URL] = $urls[$i++]; // increment i
curl_setopt_array($ch,$options);
curl_multi_add_handle($master, $ch);
}
// remove the curl handle that just completed
curl_multi_remove_handle($master, $done['handle']);
}
usleep(10000); // stop wasting CPU cycles and rest for a couple ms
} while ($running);
curl_multi_close($master);
}
<?php
usleep(mt_rand(100000, 600000));
print basename(__FILE__) . "\n";
@Chuanyou124
Copy link

Hi Thanks for your code. I am pretty newbie in php, and have 2 questions:

  1. How can I pass POST data in the request?
  2. After I change your slow.php file's sleeping time, say change it to a constant value, then for the slow.php I can only get 1 print within the callback, which seems to me the callback is called only ONCE. However, if it is really asynchronous call, the response should be uniquely identified by some id right? and all 5 slow.php should call the callback once, is it a bug?
    Thanks again for your time,
    very appreciated.

@abiusx
Copy link

abiusx commented Dec 12, 2018

This is still blocking, just not blocking in the curl call (but in your loop instead).

@lewiscowleschipuk
Copy link

@abiusx have you yet learned that all async await eventually blocks? This is just kinda low-level way to get async / await prior to those features in PHP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment