How do I make an asynchronous GET request in PHP?

2019-01-01 01:43发布

I wish to make a simple GET request to another script on a different server. How do I do this?

In one case, I just need to request an external script without the need for any output.

make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage

In the second case, I need to get the text output.

$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output

To be honest, I do not want to mess around with CURL as this isn't really the job of CURL. I also do not want to make use of http_get as I do not have the PECL extensions.

Would fsockopen work? If so, how do I do this without reading in the contents of the file? Is there no other way?

Thanks all

Update

I should of added, in the first case, I do not want to wait for the script to return anything. As I understand file_get_contents() will wait for the page to load fully etc?

22条回答
梦寄多情
2楼-- · 2019-01-01 02:24

Nobody seems to mention Guzzle, which is a PHP HTTP client that makes it easy to send HTTP requests. It can work with or without Curl. It can send both synchronous and asynchronous requests.

$client = new GuzzleHttp\Client();
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise->then(
    function (ResponseInterface $res) {
        echo $res->getStatusCode() . "\n";
    },
    function (RequestException $e) {
        echo $e->getMessage() . "\n";
        echo $e->getRequest()->getMethod();
    }
);
查看更多
明月照影归
3楼-- · 2019-01-01 02:24

For PHP5.5+, mpyw/co is the ultimate solution. It works as if it is tj/co in JavaScript.

Example

Assume that you want to download specified multiple GitHub users' avatars. The following steps are required for each user.

  1. Get content of http://github.com/mpyw (GET HTML)
  2. Find <img class="avatar" src="..."> and request it (GET IMAGE)

---: Waiting my response
...: Waiting other response in parallel flows

Many famous curl_multi based scripts already provide us the following flows.

        /-----------GET HTML\  /--GET IMAGE.........\
       /                     \/                      \ 
[Start] GET HTML..............----------------GET IMAGE [Finish]
       \                     /\                      /
        \-----GET HTML....../  \-----GET IMAGE....../

However, this is not efficient enough. Do you want to reduce worthless waiting times ...?

        /-----------GET HTML--GET IMAGE\
       /                                \            
[Start] GET HTML----------------GET IMAGE [Finish]
       \                                /
        \-----GET HTML-----GET IMAGE.../

Yes, it's very easy with mpyw/co. For more details, visit the repository page.

查看更多
只若初见
4楼-- · 2019-01-01 02:27

If you are using Linux environment then you can use the PHP's exec command to invoke the linux curl. Here is a sample code, which will make a Asynchronous HTTP post.

function _async_http_post($url, $json_string) {
  $run = "curl -X POST -H 'Content-Type: application/json'";
  $run.= " -d '" .$json_string. "' " . "'" . $url . "'";
  $run.= " > /dev/null 2>&1 &";
  exec($run, $output, $exit);
  return $exit == 0;
}

This code does not need any extra PHP libs and it can complete the http post in less than 10 milliseconds.

查看更多
若你有天会懂
5楼-- · 2019-01-01 02:29

Based on this thread I made this for my codeigniter project. It works just fine. You can have any function processed in the background.

A controller that accepts the async calls.

class Daemon extends CI_Controller
{
    // Remember to disable CI's csrf-checks for this controller

    function index( )
    {
        ignore_user_abort( 1 );
        try
        {
            if ( strcmp( $_SERVER['REMOTE_ADDR'], $_SERVER['SERVER_ADDR'] ) != 0 && !in_array( $_SERVER['REMOTE_ADDR'], $this->config->item( 'proxy_ips' ) ) )
            {
                log_message( "error", "Daemon called from untrusted IP-address: " . $_SERVER['REMOTE_ADDR'] );
                show_404( '/daemon' );
                return;
            }

            $this->load->library( 'encrypt' );
            $params = unserialize( urldecode( $this->encrypt->decode( $_POST['data'] ) ) );
            unset( $_POST );
            $model = array_shift( $params );
            $method = array_shift( $params );
            $this->load->model( $model );
            if ( call_user_func_array( array( $this->$model, $method ), $params ) === FALSE )
            {
                log_message( "error", "Daemon could not call: " . $model . "::" . $method . "()" );
            }
        }
        catch(Exception $e)
        {
            log_message( "error", "Daemon has error: " . $e->getMessage( ) . $e->getFile( ) . $e->getLine( ) );
        }
    }
}

And a library that does the async calls

class Daemon
{
    public function execute_background( /* model, method, params */ )
    {
        $ci = &get_instance( );
        // The callback URL (its ourselves)
        $parts = parse_url( $ci->config->item( 'base_url' ) . "/daemon" );
        if ( strcmp( $parts['scheme'], 'https' ) == 0 )
        {
            $port = 443;
            $host = "ssl://" . $parts['host'];
        }
        else 
        {
            $port = 80;
            $host = $parts['host'];
        }
        if ( ( $fp = fsockopen( $host, isset( $parts['port'] ) ? $parts['port'] : $port, $errno, $errstr, 30 ) ) === FALSE )
        {
            throw new Exception( "Internal server error: background process could not be started" );
        }
        $ci->load->library( 'encrypt' );
        $post_string = "data=" . urlencode( $ci->encrypt->encode( serialize( func_get_args( ) ) ) );
        $out = "POST " . $parts['path'] . " HTTP/1.1\r\n";
        $out .= "Host: " . $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";
        $out .= $post_string;
        fwrite( $fp, $out );
        fclose( $fp );
    }
}

This method can be called to process any model::method() in the 'background'. It uses variable arguments.

$this->load->library('daemon');
$this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );
查看更多
登录 后发表回答