Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async curl request in PHP

I'm executing two curl post requests in PHP. Here's how they look like:

//Onfleet API credentials  $username = 'xxxxx';  $api_onfleet = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';     $url_onfleet = "https://onfleet.com/api/v2/tasks";  curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);     $request =  $url.'api/mail.send.json';      // Generate curl request     $session = curl_init($request);     // Tell curl to use HTTP POST     curl_setopt ($session, CURLOPT_POST, true);     // Tell curl that this is the body of the POST     curl_setopt ($session, CURLOPT_POSTFIELDS, $params);     // Tell curl not to return headers, but do return the response     curl_setopt($session, CURLOPT_HEADER, false);     curl_setopt($session, CURLOPT_RETURNTRANSFER, true);      // obtain response     $response = curl_exec($session);     curl_close($session);        // Post the Pickup task to Onfleet     $ch = curl_init();     curl_setopt($ch, CURLOPT_URL, $url_onfleet);     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);     curl_setopt($ch, CURLOPT_USERPWD, $api_onfleet);     curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);     curl_setopt($ch, CURLOPT_ENCODING, "");       curl_setopt($ch, CURLOPT_POST, true);     curl_setopt($ch, CURLOPT_POSTFIELDS, '{"destination":{"address":{"unparsed":"'.$pickup_address.'"},"notes":"'.$comments.'"},"recipients":[{"name":"'.$name.'","phone":"+61'.$phone.'","notes":"Number of riders: '.$riders.'"}],"completeBefore":'.$timestamp.',"pickupTask":"yes","autoAssign":{"mode":"distance"}}');      $result_pickup = curl_exec($ch);     curl_close($ch);      // Post the Dropoff task to Onfleet     $curl = curl_init();     curl_setopt($curl, CURLOPT_URL, $url_onfleet);     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);     curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);     curl_setopt($curl, CURLOPT_USERPWD, $api_onfleet);     curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);     curl_setopt($curl, CURLOPT_ENCODING, "");       curl_setopt($curl, CURLOPT_POST, true);     curl_setopt($curl, CURLOPT_POSTFIELDS, '{"destination":{"address":{"unparsed":"'.$dropoff_address.'"},"notes":"'.$comments.'"},"recipients":[{"name":"'.$name.'","phone":"+61'.$phone.'","notes":"Number of riders: '.$riders.'"}],"autoAssign":{"mode":"distance"}}');      $result_dropoff = curl_exec($curl);     curl_close($curl); 

They are working, but sometimes, the second curl post request is not executed.

I'd like to execute this two requests at the same time.

How can I do that? Please note that they take different options in the postfields.

Thanks for your help!

like image 767
Hyacinthe Avatar asked Mar 23 '16 06:03

Hyacinthe


People also ask

Is curl asynchronous in PHP?

Short answer is no it isn't asynchronous. Longer answer is "Not unless you wrote the backend yourself to do so." If you're using XHR, each request is going to have a different worker thread on the backend which means no request should block any other, barring hitting process and memory limits.

How do you run asynchronous curls?

So, basically you need to create a class which extends the Thread class and everything you want to run asynchronously (rather parallely), would be put in the function run() of the class.

Can PHP be asynchronous?

Yes. Because asynchronous processing enables the management and completion of more than one task at a time, you can dramatically boost PHP performance by using it instead of synchronous PHP.

What is Curl_multi_exec?

Description ¶ curl_multi_exec(CurlMultiHandle $multi_handle , int &$still_running ): int. Processes each of the handles in the stack. This method can be called whether or not a handle needs to read or write data.


1 Answers

So what you want to do is asynchronous execution of the cUrl Requests.

So you would need a asynchronous/parallel processing library for php.


Async cURL

The other way is to use the built in asynchronous cURL functions.

So, when using curl_multi_*, your code would look something like:

$username = 'xxxxx';  $api_onfleet = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';     $url_onfleet = "https://onfleet.com/api/v2/tasks";  curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);     $request =  $url.'api/mail.send.json';      // Generate curl request     $session = curl_init($request);     // Tell curl to use HTTP POST     curl_setopt ($session, CURLOPT_POST, true);     // Tell curl that this is the body of the POST     curl_setopt ($session, CURLOPT_POSTFIELDS, $params);     // Tell curl not to return headers, but do return the response     curl_setopt($session, CURLOPT_HEADER, false);     curl_setopt($session, CURLOPT_RETURNTRANSFER, true);        // Post the Pickup task to Onfleet     $ch = curl_init();     curl_setopt($ch, CURLOPT_URL, $url_onfleet);     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);     curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);     curl_setopt($ch, CURLOPT_USERPWD, $api_onfleet);     curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);     curl_setopt($ch, CURLOPT_ENCODING, "");       curl_setopt($ch, CURLOPT_POST, true);     curl_setopt($ch, CURLOPT_POSTFIELDS, '{"destination":{"address":{"unparsed":"'.$pickup_address.'"},"notes":"'.$comments.'"},"recipients":[{"name":"'.$name.'","phone":"+61'.$phone.'","notes":"Number of riders: '.$riders.'"}],"completeBefore":'.$timestamp.',"pickupTask":"yes","autoAssign":{"mode":"distance"}}'); $mh = curl_multi_init(); curl_multi_add_handle($mh,$session); curl_multi_add_handle($mh,$ch);  $active = null; //execute the handles do {     $mrc = curl_multi_exec($mh, $active); } while ($mrc == CURLM_CALL_MULTI_PERFORM);  while ($active && $mrc == CURLM_OK) {     if (curl_multi_select($mh) != -1) {         do {             $mrc = curl_multi_exec($mh, $active);         } while ($mrc == CURLM_CALL_MULTI_PERFORM);     } } //close the handles curl_multi_remove_handle($mh, $ch1); curl_multi_remove_handle($mh, $ch2); curl_multi_close($mh); 

Suggested Reading:

  1. curl_multi_init()
  2. curl_multi_exec()
  3. curl_multi_add_handle()
  4. curl_multi_remove_handle()

pThreads

One of the prominent threading libraries for php is pthreads

You would need to first get the dll/so file and save it in the php/ext dir, and enable that extension in php.ini.

After That, this code would do your job:

class Request1 extends Thread {     $username = 'xxxxx';      $api_onfleet = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';         $url_onfleet = "https://onfleet.com/api/v2/tasks";     public function run() {         curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);         $request =  $this->url.'api/mail.send.json';              // Generate curl request         $session = curl_init($request);         // Tell curl to use HTTP POST         curl_setopt ($session, CURLOPT_POST, true);        // Tell curl that this is the body of the POST        curl_setopt ($session, CURLOPT_POSTFIELDS, $params);        // Tell curl not to return headers, but do return the response        curl_setopt($session, CURLOPT_HEADER, false);        curl_setopt($session, CURLOPT_RETURNTRANSFER, true);          // obtain response         $response = curl_exec($session);         curl_close($session);     } }   class Request2 extends Thread {     $username = 'xxxxx';      $api_onfleet = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';         $url_onfleet = "https://onfleet.com/api/v2/tasks";     public function run() {       $ch = curl_init();       curl_setopt($ch, CURLOPT_URL, $url_onfleet);       curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);       curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);       curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);       curl_setopt($ch, CURLOPT_USERPWD, $this->api_onfleet);       curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);       curl_setopt($ch, CURLOPT_ENCODING, "");         curl_setopt($ch, CURLOPT_POST, true);       curl_setopt($ch, CURLOPT_POSTFIELDS, '{"destination":{"address":{"unparsed":"'.$pickup_address.'"},"notes":"'.$comments.'"},"recipients":[{"name":"'.$name.'","phone":"+61'.$phone.'","notes":"Number of riders: '.$riders.'"}],"completeBefore":'.$timestamp.',"pickupTask":"yes","autoAssign":{"mode":"distance"}}');        $result_pickup = curl_exec($ch);       curl_close($ch);        // Post the Dropoff task to Onfleet       $curl = curl_init();       curl_setopt($curl, CURLOPT_URL, $this->url_onfleet);       curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);       curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);       curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);       curl_setopt($curl, CURLOPT_USERPWD, $this->api_onfleet);       curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);       curl_setopt($curl, CURLOPT_ENCODING, "");         curl_setopt($curl, CURLOPT_POST, true);       curl_setopt($curl, CURLOPT_POSTFIELDS, '{"destination":{"address":{"unparsed":"'.$dropoff_address.'"},"notes":"'.$comments.'"},"recipients":[{"name":"'.$name.'","phone":"+61'.$phone.'","notes":"Number of riders: '.$riders.'"}],"autoAssign":{"mode":"distance"}}');        $result_dropoff = curl_exec($curl);       curl_close($curl);     } }  $req1 = new Request1(); $req1->start(); $req2 = new Request2(); $req2->start(); 

So, basically you need to create a class which extends the Thread class and everything you want to run asynchronously (rather parallely), would be put in the function run() of the class.

When you want to start the thread just instantiate the class in a variable, and call the start method of the object, like $threadsObject->start() and everything in the run() would be executed on another thread.

Reference:

  1. class::Thread
  2. Thread::start

That's it.

like image 76
Ikari Avatar answered Sep 20 '22 01:09

Ikari