質問

PHP で非同期 HTTP 呼び出しを行う方法はありますか?反応は気にしない、ただ次のようなことをしたいだけです file_get_contents(), ただし、リクエストが完了するのを待ってからコードの残りの部分を実行します。これは、アプリケーション内である種の「イベント」を開始したり、長いプロセスをトリガーしたりする場合に非常に役立ちます。

何か案は?

役に立ちましたか?

解決

以前に受け入れた答えは機能しませんでした。まだ応答を待っています。ただし、これは機能します。 PHP で非同期 GET リクエストを行うにはどうすればよいですか?

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

他のヒント

非同期的に呼び出したいターゲットを制御する場合 (例:独自の「longtask.php」)、その側から接続を閉じることができ、両方のスクリプトが並行して実行されます。それはこのように動作します:

  1. Quick.php は cURL 経由で longtask.php を開きます (ここには魔法はありません)
  2. longtask.php は接続を閉じて続行します (魔法!)
  3. 接続が閉じられると、cURL は Quick.php に戻ります
  4. 両方のタスクが並行して続行されます

これを試してみましたが、うまくいきました。しかし、プロセス間の通信手段を作成しない限り、quick.php は、longtask.php がどのように動作しているかについて何も知りません。

他の作業を行う前に、longtask.php でこのコードを試してください。接続は閉じられますが、引き続き実行されます (出力は抑制されます)。

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

コードはからコピーされます PHPマニュアルのユーザー投稿メモ そして若干改善されました。

これにはphp5が必要で、docs.php.netから盗み、最後に編集しました。

クライアントサイトでエラーが発生したときの監視に使用しています。出力を保留せずにデータを送信します。

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

exec() を使用して、次のような HTTP リクエストを実行できるものを呼び出すことで、トリックを行うことができます。 wget, ただし、プログラムからのすべての出力をファイルや /dev/null などの場所に送信する必要があります。そうしないと、PHP プロセスはその出力を待機します。

プロセスを Apache スレッドから完全に分離したい場合は、次のようなことを試してください (これについてはわかりませんが、アイデアが理解できれば幸いです)。

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

これは良いビジネスではありません。実際の非同期イベントを実行するために実際のデータベース イベント キューをポーリングするハートビート スクリプトを呼び出す cron ジョブのようなものが必要になるでしょう。

/**
 * 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 &");
}

2018年現在、 ガズル は、HTTP リクエストの事実上の標準ライブラリとなり、いくつかの最新のフレームワークで使用されています。純粋な PHP で書かれており、カスタム拡張機能をインストールする必要はありません。

非同期 HTTP 呼び出しを非常にうまく実行できます。 それらをプールする たとえば、100 回の HTTP 呼び出しを行う必要があるが、一度に 5 回以上実行したくない場合などです。

同時リクエストの例

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

// You can access each result using the key provided to the unwrap
// function.
echo $results['image']['value']->getHeader('Content-Length')[0]
echo $results['png']['value']->getHeader('Content-Length')[0]

見る http://docs.guzzlephp.org/en/stable/quickstart.html#concurrent-requests

  1. を使用してリクエストの中止を偽装します CURL 低く設定する CURLOPT_TIMEOUT_MS

  2. セット ignore_user_abort(true) 接続が閉じられた後も処理を継続します。

この方法では、OS、ブラウザ、PHP のバージョンに依存しすぎるヘッダーやバッファーを介した接続処理を実装する必要がありません。

マスタープロセス

function async_curl($background_process=''){

    //-------------get curl contents----------------

    $ch = curl_init($background_process);
    curl_setopt_array($ch, array(
        CURLOPT_HEADER => 0,
        CURLOPT_RETURNTRANSFER =>true,
        CURLOPT_NOSIGNAL => 1, //to timeout immediately if the value is < 1000 ms
        CURLOPT_TIMEOUT_MS => 50, //The maximum number of mseconds to allow cURL functions to execute
        CURLOPT_VERBOSE => 1,
        CURLOPT_HEADER => 1
    ));
    $out = curl_exec($ch);

    //-------------parse curl contents----------------

    //$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    //$header = substr($out, 0, $header_size);
    //$body = substr($out, $header_size);

    curl_close($ch);

    return true;
}

async_curl('http://example.com/background_process_1.php');

バックグラウンドプロセス

ignore_user_abort(true);

//do something...

注意

1秒未満でカールをタイムアウトにしたい場合は、curlopt_timeout_msを使用できますが、「unix-likeシステム」にはバグ/「機能」があり、エラーが1000 ms未満の場合はlibcurlがすぐにタイムアウトします。カールエラー(28):タイムアウトになりました。」この動作の説明は次のとおりです。

[...]

解決策は、CURLOPT_NOSIGNAL を使用してシグナルを無効にすることです。

リソース

このライブラリは次のように使用できます。 https://github.com/stil/curl-easy

それは非常に簡単です:

<?php
$request = new cURL\Request('http://yahoo.com/');
$request->getOptions()->set(CURLOPT_RETURNTRANSFER, true);

// Specify function to be called when your request is complete
$request->addListener('complete', function (cURL\Event $event) {
    $response = $event->response;
    $httpCode = $response->getInfo(CURLINFO_HTTP_CODE);
    $html = $response->getContent();
    echo "\nDone.\n";
});

// Loop below will run as long as request is processed
$timeStart = microtime(true);
while ($request->socketPerform()) {
    printf("Running time: %dms    \r", (microtime(true) - $timeStart)*1000);
    // Here you can do anything else, while your request is in progress
}

以下に、上記の例のコンソール出力を示します。リクエストの実行時間を示すシンプルなライブクロックが表示されます。


animation

私のやり方を教えてあげましょう:)

サーバーにnodejsがインストールされている必要があります

(サーバーが 1000 件の https get リクエストを送信するのにかかる時間はわずか 2 秒です)

URL.php :

<?
$urls = array_fill(0, 100, 'http://google.com/blank.html');

function execinbackground($cmd) { 
    if (substr(php_uname(), 0, 7) == "Windows"){ 
        pclose(popen("start /B ". $cmd, "r"));  
    } 
    else { 
        exec($cmd . " > /dev/null &");   
    } 
} 
fwite(fopen("urls.txt","w"),implode("\n",$urls);
execinbackground("nodejs urlscript.js urls.txt");
// { do your work while get requests being executed.. }
?>

URLスクリプト.js >

var https = require('https');
var url = require('url');
var http = require('http');
var fs = require('fs');
var dosya = process.argv[2];
var logdosya = 'log.txt';
var count=0;
http.globalAgent.maxSockets = 300;
https.globalAgent.maxSockets = 300;

setTimeout(timeout,100000); // maximum execution time (in ms)

function trim(string) {
    return string.replace(/^\s*|\s*$/g, '')
}

fs.readFile(process.argv[2], 'utf8', function (err, data) {
    if (err) {
        throw err;
    }
    parcala(data);
});

function parcala(data) {
    var data = data.split("\n");
    count=''+data.length+'-'+data[1];
    data.forEach(function (d) {
        req(trim(d));
    });
    /*
    fs.unlink(dosya, function d() {
        console.log('<%s> file deleted', dosya);
    });
    */
}


function req(link) {
    var linkinfo = url.parse(link);
    if (linkinfo.protocol == 'https:') {
        var options = {
        host: linkinfo.host,
        port: 443,
        path: linkinfo.path,
        method: 'GET'
    };
https.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    } else {
    var options = {
        host: linkinfo.host,
        port: 80,
        path: linkinfo.path,
        method: 'GET'
    };        
http.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
    }
}


process.on('exit', onExit);

function onExit() {
    log();
}

function timeout()
{
console.log("i am too far gone");process.exit();
}

function log() 
{
    var fd = fs.openSync(logdosya, 'a+');
    fs.writeSync(fd, dosya + '-'+count+'\n');
    fs.closeSync(fd);
}

ノンブロッキング ソケットと PHP の pecl 拡張機能の 1 つを使用できます。

コードと pecl 拡張機能の間に抽象化レイヤーを提供するライブラリを使用できます。 https://github.com/reactphp/event-loop

以前のライブラリに基づいて、非同期 http-client を使用することもできます。 https://github.com/reactphp/http-client

ReactPHP の他のライブラリを参照してください。 http://reactphp.org

非同期モデルの場合は注意してください。YouTube でこのビデオを見ることをお勧めします。 http://www.youtube.com/watch?v=MWNcItWuKpI

スウールエクステンション。 https://github.com/matyhtf/swoolePHP 用の非同期および同時ネットワーキング フレームワーク。

$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);

$client->on("connect", function($cli) {
    $cli->send("hello world\n");
});

$client->on("receive", function($cli, $data){
    echo "Receive: $data\n";
});

$client->on("error", function($cli){
    echo "connect fail\n";
});

$client->on("close", function($cli){
    echo "close\n";
});

$client->connect('127.0.0.1', 9501, 0.5);
class async_file_get_contents extends Thread{
    public $ret;
    public $url;
    public $finished;
        public function __construct($url) {
        $this->finished=false;
        $this->url=$url;
    }
        public function run() {
        $this->ret=file_get_contents($this->url);
        $this->finished=true;
    }
}
$afgc=new async_file_get_contents("http://example.org/file.ext");

イベント延長

イベント 拡張子は非常に適切です。の港です リベベント 主にネットワーク向けのイベント駆動型 I/O 用に設計されたライブラリです。

多数のHTTPリクエストをスケジュールして非同期に実行できるサンプルHTTPクライアントを作成しました。

これは、以下に基づくサンプル HTTP クライアント クラスです。 イベント 拡大。

このクラスを使用すると、多数の HTTP リクエストをスケジュールし、非同期で実行できます。

http-client.php

<?php
class MyHttpClient {
  /// @var EventBase
  protected $base;
  /// @var array Instances of EventHttpConnection
  protected $connections = [];

  public function __construct() {
    $this->base = new EventBase();
  }

  /**
   * Dispatches all pending requests (events)
   *
   * @return void
   */
  public function run() {
    $this->base->dispatch();
  }

  public function __destruct() {
    // Destroy connection objects explicitly, don't wait for GC.
    // Otherwise, EventBase may be free'd earlier.
    $this->connections = null;
  }

  /**
   * @brief Adds a pending HTTP request
   *
   * @param string $address Hostname, or IP
   * @param int $port Port number
   * @param array $headers Extra HTTP headers
   * @param int $cmd A EventHttpRequest::CMD_* constant
   * @param string $resource HTTP request resource, e.g. '/page?a=b&c=d'
   *
   * @return EventHttpRequest|false
   */
  public function addRequest($address, $port, array $headers,
    $cmd = EventHttpRequest::CMD_GET, $resource = '/')
  {
    $conn = new EventHttpConnection($this->base, null, $address, $port);
    $conn->setTimeout(5);

    $req = new EventHttpRequest([$this, '_requestHandler'], $this->base);

    foreach ($headers as $k => $v) {
      $req->addHeader($k, $v, EventHttpRequest::OUTPUT_HEADER);
    }
    $req->addHeader('Host', $address, EventHttpRequest::OUTPUT_HEADER);
    $req->addHeader('Connection', 'close', EventHttpRequest::OUTPUT_HEADER);
    if ($conn->makeRequest($req, $cmd, $resource)) {
      $this->connections []= $conn;
      return $req;
    }

    return false;
  }


  /**
   * @brief Handles an HTTP request
   *
   * @param EventHttpRequest $req
   * @param mixed $unused
   *
   * @return void
   */
  public function _requestHandler($req, $unused) {
    if (is_null($req)) {
      echo "Timed out\n";
    } else {
      $response_code = $req->getResponseCode();

      if ($response_code == 0) {
        echo "Connection refused\n";
      } elseif ($response_code != 200) {
        echo "Unexpected response: $response_code\n";
      } else {
        echo "Success: $response_code\n";
        $buf = $req->getInputBuffer();
        echo "Body:\n";
        while ($s = $buf->readLine(EventBuffer::EOL_ANY)) {
          echo $s, PHP_EOL;
        }
      }
    }
  }
}


$address = "my-host.local";
$port = 80;
$headers = [ 'User-Agent' => 'My-User-Agent/1.0', ];

$client = new MyHttpClient();

// Add pending requests
for ($i = 0; $i < 10; $i++) {
  $client->addRequest($address, $port, $headers,
    EventHttpRequest::CMD_GET, '/test.php?a=' . $i);
}

// Dispatch pending requests
$client->run();

テスト.php

サーバー側のサンプルスクリプトです。

<?php
echo 'GET: ', var_export($_GET, true), PHP_EOL;
echo 'User-Agent: ', $_SERVER['HTTP_USER_AGENT'] ?? '(none)', PHP_EOL;

使用法

php http-client.php

サンプル出力

Success: 200
Body:
GET: array (
  'a' => '1',
)
User-Agent: My-User-Agent/1.0
Success: 200
Body:
GET: array (
  'a' => '0',
)
User-Agent: My-User-Agent/1.0
Success: 200
Body:
GET: array (
  'a' => '3',
)
...

(トリミング済み)

このコードは、長期間の処理を想定して設計されていることに注意してください。 CLI SAPI.


カスタム プロトコルの場合は、低レベル API の使用を検討してください。 バッファイベント, バッファ. 。SSL/TLS 通信の場合は、イベントの API と組み合わせて低レベル API を使用することをお勧めします。 SSLコンテキスト. 。例:


Libevent の HTTP API はシンプルですが、バッファ イベントほど柔軟ではありません。たとえば、HTTP API は現在、カスタム HTTP メソッドをサポートしていません。ただし、低レベル API を使用すると、事実上あらゆるプロトコルを実装できます。

EV拡張機能

また、次を使用して別の HTTP クライアントのサンプルも作成しました。 エヴ 拡張子付き ソケットノンブロッキングモード. 。Ev は汎用イベント ループであるため、コードは Event に基づくサンプルよりも若干冗長になります。ネットワーク固有の機能は提供しませんが、 EvIo ウォッチャーは、特にソケット リソースにカプセル化されたファイル記述子をリッスンできます。

これは、以下に基づくサンプル HTTP クライアントです。 エヴ 拡大。

Ev 拡張機能は、シンプルかつ強力な汎用イベント ループを実装します。ネットワーク固有のウォッチャーは提供しませんが、 I/Oウォッチャー の非同期処理に使用できます ソケット.

次のコードは、HTTP リクエストを並列処理用にスケジュールする方法を示しています。

http-client.php

<?php
class MyHttpRequest {
  /// @var MyHttpClient
  private $http_client;
  /// @var string
  private $address;
  /// @var string HTTP resource such as /page?get=param
  private $resource;
  /// @var string HTTP method such as GET, POST etc.
  private $method;
  /// @var int
  private $service_port;
  /// @var resource Socket
  private $socket;
  /// @var double Connection timeout in seconds.
  private $timeout = 10.;
  /// @var int Chunk size in bytes for socket_recv()
  private $chunk_size = 20;
  /// @var EvTimer
  private $timeout_watcher;
  /// @var EvIo
  private $write_watcher;
  /// @var EvIo
  private $read_watcher;
  /// @var EvTimer
  private $conn_watcher;
  /// @var string buffer for incoming data
  private $buffer;
  /// @var array errors reported by sockets extension in non-blocking mode.
  private static $e_nonblocking = [
    11, // EAGAIN or EWOULDBLOCK
    115, // EINPROGRESS
  ];

  /**
   * @param MyHttpClient $client
   * @param string $host Hostname, e.g. google.co.uk
   * @param string $resource HTTP resource, e.g. /page?a=b&c=d
   * @param string $method HTTP method: GET, HEAD, POST, PUT etc.
   * @throws RuntimeException
   */
  public function __construct(MyHttpClient $client, $host, $resource, $method) {
    $this->http_client = $client;
    $this->host        = $host;
    $this->resource    = $resource;
    $this->method      = $method;

    // Get the port for the WWW service
    $this->service_port = getservbyname('www', 'tcp');

    // Get the IP address for the target host
    $this->address = gethostbyname($this->host);

    // Create a TCP/IP socket
    $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if (!$this->socket) {
      throw new RuntimeException("socket_create() failed: reason: " .
        socket_strerror(socket_last_error()));
    }

    // Set O_NONBLOCK flag
    socket_set_nonblock($this->socket);

    $this->conn_watcher = $this->http_client->getLoop()
      ->timer(0, 0., [$this, 'connect']);
  }

  public function __destruct() {
    $this->close();
  }

  private function freeWatcher(&$w) {
    if ($w) {
      $w->stop();
      $w = null;
    }
  }

  /**
   * Deallocates all resources of the request
   */
  private function close() {
    if ($this->socket) {
      socket_close($this->socket);
      $this->socket = null;
    }

    $this->freeWatcher($this->timeout_watcher);
    $this->freeWatcher($this->read_watcher);
    $this->freeWatcher($this->write_watcher);
    $this->freeWatcher($this->conn_watcher);
  }

  /**
   * Initializes a connection on socket
   * @return bool
   */
  public function connect() {
    $loop = $this->http_client->getLoop();

    $this->timeout_watcher = $loop->timer($this->timeout, 0., [$this, '_onTimeout']);
    $this->write_watcher = $loop->io($this->socket, Ev::WRITE, [$this, '_onWritable']);

    return socket_connect($this->socket, $this->address, $this->service_port);
  }

  /**
   * Callback for timeout (EvTimer) watcher
   */
  public function _onTimeout(EvTimer $w) {
    $w->stop();
    $this->close();
  }

  /**
   * Callback which is called when the socket becomes wriable
   */
  public function _onWritable(EvIo $w) {
    $this->timeout_watcher->stop();
    $w->stop();

    $in = implode("\r\n", [
      "{$this->method} {$this->resource} HTTP/1.1",
      "Host: {$this->host}",
      'Connection: Close',
    ]) . "\r\n\r\n";

    if (!socket_write($this->socket, $in, strlen($in))) {
      trigger_error("Failed writing $in to socket", E_USER_ERROR);
      return;
    }

    $loop = $this->http_client->getLoop();
    $this->read_watcher = $loop->io($this->socket,
      Ev::READ, [$this, '_onReadable']);

    // Continue running the loop
    $loop->run();
  }

  /**
   * Callback which is called when the socket becomes readable
   */
  public function _onReadable(EvIo $w) {
    // recv() 20 bytes in non-blocking mode
    $ret = socket_recv($this->socket, $out, 20, MSG_DONTWAIT);

    if ($ret) {
      // Still have data to read. Append the read chunk to the buffer.
      $this->buffer .= $out;
    } elseif ($ret === 0) {
      // All is read
      printf("\n<<<<\n%s\n>>>>", rtrim($this->buffer));
      fflush(STDOUT);
      $w->stop();
      $this->close();
      return;
    }

    // Caught EINPROGRESS, EAGAIN, or EWOULDBLOCK
    if (in_array(socket_last_error(), static::$e_nonblocking)) {
      return;
    }

    $w->stop();
    $this->close();
  }
}

/////////////////////////////////////
class MyHttpClient {
  /// @var array Instances of MyHttpRequest
  private $requests = [];
  /// @var EvLoop
  private $loop;

  public function __construct() {
    // Each HTTP client runs its own event loop
    $this->loop = new EvLoop();
  }

  public function __destruct() {
    $this->loop->stop();
  }

  /**
   * @return EvLoop
   */
  public function getLoop() {
    return $this->loop;
  }

  /**
   * Adds a pending request
   */
  public function addRequest(MyHttpRequest $r) {
    $this->requests []= $r;
  }

  /**
   * Dispatches all pending requests
   */
  public function run() {
    $this->loop->run();
  }
}


/////////////////////////////////////
// Usage
$client = new MyHttpClient();
foreach (range(1, 10) as $i) {
  $client->addRequest(new MyHttpRequest($client, 'my-host.local', '/test.php?a=' . $i, 'GET'));
}
$client->run();

テスト

仮定する http://my-host.local/test.php スクリプトはダンプを出力しています $_GET:

<?php
echo 'GET: ', var_export($_GET, true), PHP_EOL;

次に、の出力 php http-client.php コマンドは次のようになります。

<<<<
HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Fri, 02 Dec 2016 12:39:54 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/7.0.13-pl0-gentoo

1d
GET: array (
  'a' => '3',
)

0
>>>>
<<<<
HTTP/1.1 200 OK
Server: nginx/1.10.1
Date: Fri, 02 Dec 2016 12:39:54 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: close
X-Powered-By: PHP/7.0.13-pl0-gentoo

1d
GET: array (
  'a' => '2',
)

0
>>>>
...

(トリミング)

PHP 5 では、 ソケット 拡張機能は次の警告をログに記録する可能性があります EINPROGRESS, EAGAIN, 、 そして EWOULDBLOCK errno 価値観。次のコマンドを使用してログをオフにすることができます

error_reporting(E_ERROR);

規範の「残り」について

私はただ次のようなことをしたいだけです file_get_contents(), ただし、リクエストが完了するのを待ってからコードの残りの部分を実行します。

ネットワークリクエストと並行して実行されることになっているコードは、 イベントタイマー, 、またはエヴの アイドルウォッチャー, 、 例えば。上記のサンプルを見ると簡単に理解できます。それ以外の場合は、別の例を追加します:)

これは実際の例です。実行してその後 storage.txt を開いて、魔法のような結果を確認してください。

<?php
    function curlGet($target){
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $target);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $result = curl_exec ($ch);
        curl_close ($ch);
        return $result;
    }

    // Its the next 3 lines that do the magic
    ignore_user_abort(true);
    header("Connection: close"); header("Content-Length: 0");
    echo str_repeat("s", 100000); flush();

    $i = $_GET['i'];
    if(!is_numeric($i)) $i = 1;
    if($i > 4) exit;
    if($i == 1) file_put_contents('storage.txt', '');

    file_put_contents('storage.txt', file_get_contents('storage.txt') . time() . "\n");

    sleep(5);
    curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));
    curlGet($_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'] . '?i=' . ($i + 1));

これは、任意のページの特定の URL に POST を実行するときの私自身の PHP 関数です。サンプル:*** 私の関数の使用法...

    <?php
        parse_str("email=myemail@ehehehahaha.com&subject=this is just a test");
        $_POST['email']=$email;
        $_POST['subject']=$subject;
        echo HTTP_POST("http://example.com/mail.php",$_POST);***

    exit;
    ?>
    <?php
    /*********HTTP POST using FSOCKOPEN **************/
    // by ArbZ

function HTTP_Post($URL,$data, $referrer="") {

    // parsing the given URL
    $URL_Info=parse_url($URL);

    // Building referrer
    if($referrer=="") // if not given use this script as referrer
        $referrer=$_SERVER["SCRIPT_URI"];

    // making string from $data
    foreach($data as $key=>$value)
        $values[]="$key=".urlencode($value);
        $data_string=implode("&",$values);

    // Find out which port is needed - if not given use standard (=80)
    if(!isset($URL_Info["port"]))
        $URL_Info["port"]=80;

    // building POST-request: HTTP_HEADERs
    $request.="POST ".$URL_Info["path"]." HTTP/1.1\n";
    $request.="Host: ".$URL_Info["host"]."\n";
    $request.="Referer: $referer\n";
    $request.="Content-type: application/x-www-form-urlencoded\n";
    $request.="Content-length: ".strlen($data_string)."\n";
    $request.="Connection: close\n";
    $request.="\n";
    $request.=$data_string."\n";

    $fp = fsockopen($URL_Info["host"],$URL_Info["port"]);
    fputs($fp, $request);
    while(!feof($fp)) {
        $result .= fgets($fp, 128);
    }
    fclose($fp); //$eco = nl2br();


    function getTextBetweenTags($string, $tagname) {
        $pattern = "/<$tagname ?.*>(.*)<\/$tagname>/";
        preg_match($pattern, $string, $matches);
        return $matches[1];
    }
    //STORE THE FETCHED CONTENTS to a VARIABLE, because its way better and fast...
    $str = $result;
    $txt = getTextBetweenTags($str, "span"); $eco = $txt;  $result = explode("&",$result);
    return $result[1];
    <span style=background-color:LightYellow;color:blue>".trim($_GET['em'])."</span>
    </pre> "; 
}
</pre>

ReactPHP 非同期 http クライアント
https://github.com/shuchkin/react-http-client

Composer 経由でインストールする

$ composer require shuchkin/react-http-client

非同期HTTP GET

// get.php
$loop = \React\EventLoop\Factory::create();

$http = new \Shuchkin\ReactHTTP\Client( $loop );

$http->get( 'https://tools.ietf.org/rfc/rfc2068.txt' )->then(
    function( $content ) {
        echo $content;
    },
    function ( \Exception $ex ) {
        echo 'HTTP error '.$ex->getCode().' '.$ex->getMessage();
    }
);

$loop->run();

CLIモードでphpを実行する

$ php get.php

さて、タイムアウトはミリ秒単位で設定できます。 http://www.php.net/manual/en/function.curl-setopt

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top