How to execute a PHP script in background? - php

I have a little question:
public function backend()
{
$form = $_POST;
// execute this code in another thread (don't wait to finish)
SearchOnGoogle($form);
// redirect instantly (and function "SearchOnGoogle" works in background);
return redirect('/');
}
How can I do this thing? I tried a lot of things, and the function redirect is executed when SearchOnGoogle finishies execution.

If you want to do this within PHP then you can use curl_multi-exec(). This does does not execute "in the background" - but most of the time a client is retrieving content over HTTP, it is simply waiting for data to pass across the network. The curl_multi_select() function deals with checking the task(s) to see if if the local machine needs to do anything or if any data has arrived from the remote system.
The documentation for curl_multi_exec() in the PHP manual is (IMHO) not on a par with the writeups for other functions. There is a deeper dive here, briefly....
$ch1 = curl_init();
$ch2 = curl_init();
// set URL and other appropriate options
curl_setopt($ch1, CURLOPT_URL, "http://example.com/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
$requests=array($ch1, $ch2);
//create the multiple cURL handle
$mh = curl_multi_init();
//add the two handles
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
$active=count($requests);
$started=microtime(true);
for ($x=0; $x<=4 && $active; $x++) {
curl_multi_exec($mh, $active);
// we wait for a bit to allow stuff TCP handshakes to complete and so forth...
curl_mutli_select($mh, 0.02)
}
do_something_useful();
do {
// wait for everything to finish...
curl_multi_exec($mh, $active);
if ($active) {
curl_mutli_select($mh, 0.05);
use_some_spare_cpu_cuycles_here();
}
// until all the results are in or a timeout occurs
} while ($active > 0 && (MAX_RUNTIME<microtime(true)=$started);

Related

Why is curl_multi_exec taking much longer than the slowest url executed?

I'm attempting some sort of multitasking using curl. The task the curls do is to look for a string in several 4-megabyte files. When I delegated one curl call for each file, that was already some gain over one PHP scanning them all. It took from 3 to 4 seconds to scan all files. Then I decided to create TWO curls for each file scan, each curl call scanning a half of the file. I felt I didn't get the increase in speed I expected, so I tried now 4 curls for each file because I wanted to check the overhead/efficacy ratio. Some profiling showed me that:
$running = null;
do {
curl_multi_exec($mh, $running);
} while($running > 0);
Takes around 4 seconds to complete 28 curls. Now, the longest time a curl took was 0.4. Why had the difference? I thought I was blocking it somehow, but the added values of the 28 executions (measured independently inside the PHP's that were called) would easily jump 10 s, so the 'multitasking' was there.
To make things clearer, this is what I am using:
function multiRequest($data, $options = array(),$color) {
// array of curl handles
$curly = array();
// data to be returned
$result = array();
// multi handle
$mh = curl_multi_init();
// loop through $data and create curl handles
// then add them to the multi-handle
foreach ($data as $id => $d) {
$curly[$id] = curl_init();
$url = (is_array($d) && !empty($d['url'])) ? $d['url'] : $d;
curl_setopt($curly[$id], CURLOPT_URL, $url);
//curl_setopt($curly[$id], CURLOPT_TIMEOUT,1); <-- this would make my computer a zombie, seemingly worrying about NOTHING but the curls
curl_setopt($curly[$id], CURLOPT_FRESH_CONNECT, true); //<-- I added this line cuz I heard its good
curl_setopt($curly[$id], CURLOPT_HEADER, 0);
curl_setopt($curly[$id], CURLOPT_RETURNTRANSFER, 1);
// post?
if (is_array($d)) {
if (!empty($d['post'])) {
curl_setopt($curly[$id], CURLOPT_POST, 1);
curl_setopt($curly[$id], CURLOPT_POSTFIELDS, $d['post']);
}
}
// extra options?
if (!empty($options)) {
curl_setopt_array($curly[$id], $options);
}
curl_multi_add_handle($mh, $curly[$id]);
}
// execute the handles
$running = null;
do {
curl_multi_exec($mh, $running); //<--- grrrr
} while($running > 0);
// get content and remove handles
foreach($curly as $id => $c) {
$result[$id] = curl_multi_getcontent($c);
curl_multi_remove_handle($mh, $c);
}
// all done
curl_multi_close($mh);
}
(I've read there is a method I can add a callback function that gets triggered seemingly on progress, and that would enable me some manipulation of the "get contents and remove handles" part, but is it possible to bypass the waiting at the curl_multi_exec loop while have the curl files execute? Or we have to keep calling the curl_multi_exec for the execution to proceed? I'm thinking: 1 has curl call for PHPs/2 curl doesn't wait and returns and for us it is dead, but it run desired PHPs/3 PHPs write data to files at their own pace while main program scans for these files, curl theoretically still dealing with its overhead while we already returned to client...)
Thanks in advance.

PHP hold request until finish

I have an API written in PHP that sends 10 requests with CURL.
The problem is that when I send a HTTP request to the API, I get the response right away, although the server hasn't finished working( getting the response for all of the 10 requests).
I can't use ignore_user_abort() because I need to know exactly the time that the API finished.
How can I notify the connection "hey, wait for the script to finish working"?
Important note: if I use sleep() the connection holds.
Here's my code: gist
This is just a example to show how ob_start works.
echo "hello";
ob_start(); // output buffering starts here
echo "hello1";
//all curl requests
if(all curl requests completed)
{
ob_end_flush() ;
}
With no code to refer, I can only show implementation of ob_start. You have to change this code according to your requirement.
$handlers = [];
$mh = curl_multi_init();
ob_start(); // output buffering starts here
foreach($query->fetchAll() as $domain){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://'.$domain['name']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $DEFAULT_REQUEST_TIMEOUT);
curl_setopt($ch, CURLOPT_TIMEOUT, $DEFAULT_REQUEST_TIMEOUT);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 2);
curl_multi_add_handle($mh, $ch);
$handlers[] = ['ch'=>$ch, 'domain_id'=>$domain['domain_id']];
echo $domain['name'];
}
// Execute the handles
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
// Wait for activity on any curl-connection
if (curl_multi_select($mh) == -1) {
usleep(1);
}
// Continue to exec until curl is ready to
// give us more data
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
}
// Extract the content
$values = [];
foreach($handlers as $key => $handle){
// Check for errors
echo $key.'. result: ';
$curlError = curl_error($handle['ch']);
if($curlError == ""){
$res = curl_multi_getcontent($handle['ch']);
echo 'done';
}
else {
echo "Curl error on handle $key: $curlError".' <br />';
}
// Remove and close the handle
curl_multi_remove_handle($mh, $handle['ch']);
curl_close($handle['ch']);
}
// Clean up the curl_multi handle
curl_multi_close($mh);
ob_end_flush() ; // output flushed here
Source - http://php.net/manual/en/function.ob-start.php
I use this code for my website
ob_start("unique_identifier");
// your header script
// your page script
// your footer script
ob_end_flush("unique_identifier");
ob_end_clean("unique_identifier");
I use "unique_identifier" because inside my script also exists another
ob_start()

When is it best to check asynchronous cURL requests for completion?

Multiple cURL requests are better to be made in an asynchronous manner, that is without each of the requests waiting till all the previous requests have received responses. Another optimization in many cases would be starting to process a received response without waiting for other responses. However, the docs and official examples are not clear when it is both possible and as early as possible to check for completed requests (which is typically done using curl_multi_info_read function).
So when is the earliest point to check for completed requests? Or what is the optimal set of such points?
This is the example from the curl_multi_exec's page (comments in upper case are mine):
<?php
// create both cURL resources
$ch1 = curl_init();
$ch2 = curl_init();
// set URL and other appropriate options
curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
//create the multiple cURL handle
$mh = curl_multi_init();
//add the two handles
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
$active = null;
//execute the handles
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// SHOULD REQUESTS BE CHECKED FOR COMPLETION HERE?
while ($active && $mrc == CURLM_OK) {
if (curl_multi_select($mh) != -1) {
// SHOULD REQUESTS BE CHECKED FOR COMPLETION HERE?
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
// SHOULD REQUESTS BE CHECKED FOR COMPLETION HERE?
}
// SHOULD REQUESTS BE CHECKED FOR COMPLETION HERE?
}
// SHOULD REQUESTS BE CHECKED FOR COMPLETION HERE?
//close the handles
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_close($mh);
?>
First, to simplify your life the CURLM_CALL_MULTI_PERFORM return code isn't used in modern libcurls (not used in 7.20.0 or later).
Then, as long as 'active' is larger than zero there are at least one active transfer in progress so you can wait with checking curl_multi_info_read() if you want.
Or you can call curl_multi_info_read() immediately after every call to curl_multi_exec(), that's up to you!

Loading remote items together or separately?

I'm looking to optimize my application. It uses the Twitter and the Facebook API and loads large files to be displayed on the users screen. Right now, I am running the script linearly, calling one file that includes both API calls using AJAX and loading all of the information onto the screen. Would it be faster for me to separate the two API calls into two different files and then load each one separately with AJAX? This way, if one response was taking longer then the other, the faster one would still be displayed.
Thank you.
If it matters, I'm using PHP and CURL for API calls.
Certainly it would be better if the AJAX calls don't depend each other. You can also do this at the PHP side using curl_multi_init that executes HTTP calls in paralell.
Sample from the PHP manual:
<?php
// create both cURL resources
$ch1 = curl_init();
$ch2 = curl_init();
// set URL and other appropriate options
curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
//create the multiple cURL handle
$mh = curl_multi_init();
//add the two handles
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
$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);
?>

how to make non blocking call in php

I am using a php script to upload lot of files. I am using the CURL command . The remote server accepts only POST requests. But when I execute the below script it processes the first request and waits until the first file is uploaded. Is there a way to make it non blocking and run simultaneous 2 curl upload requests .Find the code sample below.
<?php
$arr= array(somefile1.txt,somefile2.txt);
for ( $i=0;$i<2;$i++) {
$cmd = "curl -F name=aaa -F type=yyy FileName=#/xxxxx/xxxx/$arr[$i] http://someurl.com";
print "Executing file ";
shell_exec("nohup $cmd 2> /dev/null & echo $!" );
print "======= done ================";
}
?>
I believe you may want curl_multi_init. Here is an outbound example; it will have to be adapted for your inbound problem. This seems cleaner than you forking multiple threads yourself.
<?php
// create both cURL resources
$ch1 = curl_init();
$ch2 = curl_init();
// set URL and other appropriate options
curl_setopt($ch1, CURLOPT_URL, "http://lxr.php.net/");
curl_setopt($ch1, CURLOPT_HEADER, 0);
curl_setopt($ch2, CURLOPT_URL, "http://www.php.net/");
curl_setopt($ch2, CURLOPT_HEADER, 0);
//create the multiple cURL handle
$mh = curl_multi_init();
//add the two handles
curl_multi_add_handle($mh,$ch1);
curl_multi_add_handle($mh,$ch2);
$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);
?>
There is a good article about "multithreading", take a look at it here: Multithreading in PHP with CURL
You can try use PHP Simple Curl Wrapper - https://github.com/Graceas/php-simple-curl-wrapper. This library allows the processing of multiple request's asynchronously.
You can find full answer here: php asynchronous cURL request
No you cannot run simultaneously two curl statements.
Curl is made for working like this. A Curl statement will make the later statements
wait until it finishes its operation.

Categories