PHP Fire and Forget Запрос POST

Я пытаюсь создать метод пожара и забыть в PHP, чтобы я мог POST передавать данные на веб-сервер и не ждать ответа. Я читал, что это может быть достигнуто с помощью CURL, как в следующем коде:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_exec($ch);
curl_close($ch);

Однако я не думаю, что это работает, как я ожидаю. Например, если у URL-адреса, который я отправляю запрос, есть ошибка, он вызывает ошибку script. Если бы это был огонь и забыть, я бы ожидал, что этого не произойдет.

Может ли кто-нибудь сказать мне, что я делаю что-то неправильно или предлагаю альтернативное предложение. Я использую Windows локально и Linux для разработчиков, промежуточных и производственных сред.

UPDATE

Я нашел альтернативное решение здесь: http://blog.markturansky.com/archives/205

Я очистил его в коде ниже:

function curl_post_async($url, $params = array())
{
    // create POST string   
    $post_params = array();
    foreach ($params as $key => &$val) 
    {
        $post_params[] = $key . '=' . urlencode($val);
    }
    $post_string = implode('&', $post_params);

    // get URL segments
    $parts = parse_url($url);

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

    // create output string
    $output  = "POST " . $parts['path'] . " HTTP/1.1\r\n";
    $output .= "Host: " . $parts['host'] . "\r\n";
    $output .= "Content-Type: application/x-www-form-urlencoded\r\n";
    $output .= "Content-Length: " . strlen($post_string) . "\r\n";
    $output .= "Connection: Close\r\n\r\n";
    $output .= isset($post_string) ? $post_string : '';

    // send output to $url handle
    fwrite($fp, $output);
    fclose($fp);
}

Кажется, что это работает лучше для меня.

Это допустимое решение?

Ответ 1

Да, использование сокетов - это путь, если вам не нужен ответ с URL-адреса, который вы вызываете. Это связано с тем, что соединение сокета может быть прекращено сразу после отправки запроса без ожидания, и это именно то, что вам нужно - Fire and Forget.

Две заметки:

  • Это больше не запрос cURL, поэтому стоит переименовать функцию.:)
  • Конечно, стоит проверить, мог ли сокет быть открыт, чтобы предотвратить script позже жалобы, если сбой:

    $fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
    
    if ( ! $fp)
    {
       return FALSE;
    }
    

Стоит ли ссылаться на исходный источник fsocket() script, который вы сейчас используете:
http://w-shadow.com/blog/2007/10/16/how-to-run-a-php-script-in-the-background/

Ответ 2

Я бы предложил использовать Guzzle для этого: http://docs.guzzlephp.org/en/latest/quickstart.html#concurrent-requests

use GuzzleHttp\Client;
use GuzzleHttp\Promise;

$client = new Client(['base_uri' => 'http://httpbin.org/']);

// Initiate each request but do not block
$promises = [
    'image' => $client->getAsync('/image'),
    'png'   => $client->getAsync('/image/png'),
    'jpeg'  => $client->getAsync('/image/jpeg'),
    'webp'  => $client->getAsync('/image/webp')
];

// Wait on all of the requests to complete. Throws a ConnectException
// if any of the requests fail
$results = Promise\unwrap($promises);

// Wait for the requests to complete, even if some of them fail
$results = Promise\settle($promises)->wait();