views:

9135

answers:

6

Is there a way to PHP make asynchronous http calls? I don't care about the response, I just want to do something like file_get_contents(), but not wait on the request to finish before executing the rest of my code. This would be super useful for setting off "events" of a sort in my application, or triggering long processes.

Any ideas?

+2  A: 

You can do trickery by using exec() to invoke something that can do HTTP requests, like wget, but you must direct all output from the program to somewhere, like a file or /dev/null, otherwise the PHP process will wait for that output.

If you want to separate the process from the apache thread entirely, try something like (I'm not sure about this, but I hope you get the idea):

exec('bash -c "wget -O (url goes here) > /dev/null 2>&1 &"');

It's not a nice business, and you'll probably want something like a cron job invoking a heartbeat script which polls an actual database event queue to do real asynchronous events.

Internet Friend
Similarly, I've also done the following: exec("curl $url > /dev/null
Matt Huggins
Question: is there a benefit of calling 'bash -c "wget"' rather than just 'wget'?
Matt Huggins
+10  A: 

this needs php5, i stole it out of docs.php.net and edited the end.

I use it for monitoring when an error happens on a clients site, it sends data off to me without holding up the output

function do_post_request($url, $data, $optional_headers = null,$getresponse = false) {
      $params = array('http' => array(
                   'method' => 'POST',
                   'content' => $data
                ));
      if ($optional_headers !== null) {
         $params['http']['header'] = $optional_headers;
      }
      $ctx = stream_context_create($params);
      $fp = @fopen($url, 'rb', false, $ctx);
      if (!$fp) {
        return false;
      }
      if ($getresponse){
        $response = stream_get_contents($fp);
        return $response
      }
    return true;
}
Bruce Aldridge
Awesome, i'll try that!
UltimateBrent
Is this the best solution for asynchronously running a .php file on the SAME site?
philfreo
how are you wanting to call it? via the web (ie this method) or run it locally (eg like an include()) either way this is easy. running exec('php /path/to/file.php
Bruce Aldridge
Please see the below accepted answer. The one above turned out to not work like I wanted.
UltimateBrent
+7  A: 

Wez Furlong demonstrated how to do it:

http://netevil.org/blog/2005/may/guru-multiplexing

he provided both PHP4- and PHP5-compatible implementations of it.

cruizer
Link times out for me, but thanks for trying!
UltimateBrent
+3  A: 

If you control the target that you want to call asynchronously (e.g. your own "longtask.php"), you can close the connection from that end, and both scripts will run in parallel. It works like this:

  1. quick.php opens longtask.php via cURL (no magic here)
  2. longtask.php closes the connection and continues (magic!)
  3. cURL returns to quick.php when the connection is closed
  4. Both tasks continue in parallel

I have tried this, and it works just fine. But quick.php won't know anything about how longtask.php is doing, unless you create some means of communication between the processes.

Try this code in longtask.php, before you do anything else. It will close the connection, but still continue to run (and suppress any output):

while(ob_get_level()) ob_end_clean();
header('Connection: close');
ignore_user_abort();
ob_start();
echo('Connection Closed');
$size = ob_get_length();
header("Content-Length: $size");
ob_end_flush();
flush();

The code is copied from the PHP manual's user contributed notes and somewhat improved.

Christian Davén
A: 
/**
 * Asynchronously execute/include a PHP file. Does not record the output of the file anywhere. 
 *
 * @param string $filename              file to execute, relative to calling script
 * @param string $options               (optional) arguments to pass to file via the command line
 */ 
function asyncInclude($filename, $options = '') {
    exec("/path/to/php -f {$filename} {$options} >> /dev/null &");
}
philfreo
+3  A: 

The answer I'd previously accepted didn't work. It still waited for responses. This does work though, taken from http://stackoverflow.com/questions/962915/how-do-i-make-an-asynchronous-get-request-in-php

function curl_post_async($url, $params)
{
    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);
}
UltimateBrent
If you look at the link you posted here, my answer includes a way to do GET requests as well.
catgofire