سؤال

هل هناك طريقة في PHP لإجراء مكالمات HTTP غير متزامنة؟لا يهمني الرد، أريد فقط أن أفعل شيئًا مثل file_get_contents(), ، ولكن لا تنتظر انتهاء الطلب قبل تنفيذ بقية الكود الخاص بي.سيكون هذا مفيدًا جدًا لبدء "أحداث" من نوع ما في تطبيقي، أو تشغيل عمليات طويلة.

أيه أفكار؟

هل كانت مفيدة؟

المحلول

الإجابة التي قبلتها سابقًا لم تنجح.وما زالت تنتظر الردود.هذا لا يعمل بالرغم من ذلك، مأخوذ من كيف أقوم بتقديم طلب GET غير متزامن في PHP؟

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 longtask.php عبر cURL (لا يوجد سحر هنا)
  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) لمواصلة المعالجة بعد إغلاق الاتصال.

باستخدام هذه الطريقة، لا حاجة إلى تنفيذ معالجة الاتصال عبر الرؤوس والمخزن المؤقت الذي يعتمد أيضًا على نظام التشغيل والمتصفح وإصدار 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...

ملحوظة:

إذا كنت تريد أن تهتم Curl في أقل من ثانية واحدة ، فيمكنك استخدام Curlopt_timeout_ms ، على الرغم من وجود خطأ/"ميزة" على "أنظمة تشبه Unix" التي تسبب Libcurl إلى المهلة على الفور إذا كانت القيمة <1000 مللي ثانية مع الخطأ " خطأ حليقة (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

اسمحوا لي أن تظهر لك طريقي :)

يحتاج إلى تثبيت العقدة على الخادم

(يرسل الخادم الخاص بي 1000 https، ويستغرق الحصول على الطلب ثانيتين فقط)

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.. }
?>

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

يمكنك استخدام مآخذ التوصيل غير المحظورة وأحد امتدادات pecl لـ PHP:

يمكنك استخدام المكتبة التي تمنحك طبقة تجريد بين الكود الخاص بك وامتداد pecl: https://github.com/reactphp/event-loop

يمكنك أيضًا استخدام عميل http غير المتزامن، استنادًا إلى المكتبة السابقة: https://github.com/reactphp/http-client

شاهد مكتبات ReactPHP الأخرى: http://reactphp.org

كن حذرًا مع النموذج غير المتزامن.أنصح بمشاهدة هذا الفيديو على اليوتيوب: http://www.youtube.com/watch?v=MWNcItWuKpI

امتداد السوول. https://github.com/matyhtf/swooleإطار عمل الشبكات غير المتزامن والمتزامن لـ PHP.

$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");

ملحق الحدث

حدث التمديد مناسب جداًوهو ميناء ليبفينت مكتبة مصممة للإدخال/الإخراج المبني على الأحداث، خاصة للتواصل.

لقد كتبت عينة من عميل 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();

test.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',
)
...

(قلص.)

لاحظ أن الكود مصمم للمعالجة طويلة المدى في ملف كلي سابي.


بالنسبة للبروتوكولات المخصصة، فكر في استخدام واجهة برمجة التطبيقات ذات المستوى المنخفض، أي. الأحداث العازلة, مخازن.بالنسبة لاتصالات SSL/TLS، أوصي بواجهة برمجة التطبيقات (API) ذات المستوى المنخفض بالتزامن مع Event's سياق SSL.أمثلة:


على الرغم من أن واجهة برمجة تطبيقات HTTP الخاصة بـ Libevent بسيطة، إلا أنها ليست مرنة مثل أحداث المخزن المؤقت.على سبيل المثال، لا تدعم HTTP API حاليًا أساليب HTTP المخصصة.ولكن من الممكن تنفيذ أي بروتوكول تقريبًا باستخدام واجهة برمجة التطبيقات ذات المستوى المنخفض.

ملحق إيف

لقد كتبت أيضًا عينة من عميل HTTP آخر باستخدام إيف تمديد مع مآخذ في وضع عدم الحظر.التعليمات البرمجية أكثر تفصيلاً قليلاً من النموذج المستند إلى الحدث، لأن Ev عبارة عن حلقة حدث للأغراض العامة.لا يوفر وظائف خاصة بالشبكة، ولكنه يوفر وظائف خاصة بها EvIo المراقب قادر على الاستماع إلى واصف الملف المغلف في مورد المقبس، على وجه الخصوص.

هذا نموذج عميل HTTP يعتمد على إيف امتداد.

ينفذ ملحق Ev حلقة أحداث بسيطة لكنها قوية للأغراض العامة.لا يوفر مراقبين خاصين بالشبكة، ولكنه مراقب الإدخال/الإخراج يمكن استخدامها للمعالجة غير المتزامنة مآخذ.

يوضح التعليمة البرمجية التالية كيف يمكن جدولة طلبات 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));

هذه هي وظيفة PHP الخاصة بي عندما أقوم بالنشر إلى عنوان URL محدد لأي صفحة....عينة:*** استخدام وظيفتي...

    <?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 require shuchkin/react-http-client

الحصول على HTTP غير المتزامن

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

قم بتشغيل php في وضع CLI

$ php get.php

حسنًا ، يمكن تعيين المهلة بالمللي ثانية ، انظر "Curlopt_ConnectTimeOut_MS" في http://www.php.net/manual/en/function.curl-setopt

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top