Как сделать асинхронный запрос GET в PHP? - PullRequest
93 голосов
/ 08 июня 2009

Я хочу сделать простой запрос GET к другому сценарию на другом сервере. Как мне это сделать?

В одном случае мне просто нужно запросить внешний скрипт без необходимости какого-либо вывода.

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

Во втором случае мне нужно получить вывод текста.

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

Если честно, я не хочу возиться с CURL, так как на самом деле это не работа CURL. Я также не хочу использовать http_get, так как у меня нет расширений PECL.

Будет ли работать fsockopen? Если да, то как мне это сделать, не читая содержимое файла? Разве нет другого пути?

Спасибо всем

Обновление

Я должен добавить, в первом случае я не хочу ждать, пока скрипт ничего не вернет. Как я понимаю file_get_contents () будет ждать полной загрузки страницы и т. Д.

Ответы [ 22 ]

2 голосов
/ 03 февраля 2011

Лучше использовать очереди сообщений вместо рекомендованных методов. Я уверен, что это будет лучшим решением, хотя оно требует немного больше работы, чем просто отправка запроса.

1 голос
/ 08 июня 2009

Попробуйте:

//Your Code here
$pid = pcntl_fork();
if ($pid == -1) {
     die('could not fork');
}
else if ($pid)
{
echo("Bye")  
}
else
{
     //Do Post Processing
}

Это НЕ будет работать как модуль apache, вам нужно использовать CGI.

1 голос
/ 06 января 2013

Вот адаптация принятого ответа для выполнения простого запроса GET.

Стоит отметить, что если сервер выполняет перезапись URL, это не сработает Вам нужно будет использовать более полнофункциональный http-клиент.

  /**
   * Performs an async get request (doesn't wait for response)
   * Note: One limitation of this approach is it will not work if server does any URL rewriting
   */
  function async_get($url)
  {
      $parts=parse_url($url);

      $fp = fsockopen($parts['host'],
          isset($parts['port'])?$parts['port']:80,
          $errno, $errstr, 30);

      $out = "GET ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Connection: Close\r\n\r\n";
      fwrite($fp, $out);
      fclose($fp);
  }
1 голос
/ 19 июня 2018

Никто, кажется, не упоминает Guzzle , который является PHP-клиентом HTTP, который облегчает отправку HTTP-запросов. Может работать с или без Curl. Может отправлять как синхронные, так и асинхронные запросы.

$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();
    }
);
1 голос
/ 08 июня 2009

Я нашел эту интересную ссылку для асинхронной обработки (получить запрос).

askapache

Кроме того, вы можете выполнять асинхронную обработку, используя очередь сообщений, например, beanstalkd.

1 голос
/ 26 мая 2014

Несколько исправлений в сценариях, опубликованных выше. Следующее работает для меня

function curl_request_async($url, $params, $type='GET')
    {
        $post_params = array();
        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);
        echo print_r($parts, TRUE);
        $fp = fsockopen($parts['host'],
            (isset($parts['scheme']) && $parts['scheme'] == 'https')? 443 : 80,
            $errno, $errstr, 30);

        $out = "$type ".$parts['path'] . (isset($parts['query']) ? '?'.$parts['query'] : '') ." 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";
        // Data goes in the request body for a POST request
        if ('POST' == $type && isset($post_string)) $out.= $post_string;
        fwrite($fp, $out);
        fclose($fp);
    }
0 голосов
/ 26 января 2013

Основываясь на этой теме, я сделал это для своего проекта codeigniter. Работает просто отлично. Вы можете обработать любую функцию в фоновом режиме.

Контроллер, принимающий асинхронные вызовы.

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( ) );
        }
    }
}

И библиотека, которая выполняет асинхронные вызовы

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 );
    }
}

Этот метод может быть вызван для обработки любой модели :: method () в фоновом режиме. Он использует переменные аргументы.

$this->load->library('daemon');
$this->daemon->execute_background( 'model', 'method', $arg1, $arg2, ... );
0 голосов
/ 21 июля 2016

Для PHP5.5 +, mpyw / co является окончательным решением. Он работает так, как если бы он был TJ / Co в JavaScript.

Пример

Предположим, что вы хотите загрузить указанные аватары нескольких пользователей GitHub. Для каждого пользователя требуются следующие шаги.

  1. Получить содержимое http://github.com/mpyw (GET HTML)
  2. Найдите <img class="avatar" src="..."> и запросите его (ПОЛУЧИТЕ ИЗОБРАЖЕНИЕ)

---: жду моего ответа
...: Ожидание другого ответа в параллельных потоках

Многие известные скрипты на основе curl_multi уже предоставляют нам следующие потоки.

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

Однако это недостаточно эффективно. Вы хотите сократить бесполезное время ожидания ...?

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

Да, с mpyw / co это очень просто. Для получения более подробной информации посетите страницу хранилища.

0 голосов
/ 16 февраля 2012

Попробуйте этот код ....

$chu = curl_init();

curl_setopt($chu, CURLOPT_URL, 'http://www.myapp.com/test.php?someprm=xyz');

curl_setopt($chu, CURLOPT_FRESH_CONNECT, true);
curl_setopt($chu, CURLOPT_TIMEOUT, 1);

curl_exec($chu);
curl_close($chu);

Пожалуйста, не забудьте включить расширение CURL php.

0 голосов
/ 12 июля 2013

Это прекрасно работает для меня, к сожалению, вы не можете получить ответ на ваш запрос:

<?php
header("http://mahwebsite.net/myapp.php?var=dsafs");
?>

Работает очень быстро, нет необходимости в необработанных TCP-сокетах:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...