Verzeichnisstruktur phpBB-3.2.0


Veröffentlicht
06.01.2017

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

CurlMultiHandler.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 7.46 KiB


 001  <?php
 002  namespace GuzzleHttp\Ring\Client;
 003   
 004  use GuzzleHttp\Ring\Future\FutureArray;
 005  use React\Promise\Deferred;
 006   
 007  /**
 008   * Returns an asynchronous response using curl_multi_* functions.
 009   *
 010   * This handler supports future responses and the "delay" request client
 011   * option that can be used to delay before sending a request.
 012   *
 013   * When using the CurlMultiHandler, custom curl options can be specified as an
 014   * associative array of curl option constants mapping to values in the
 015   * **curl** key of the "client" key of the request.
 016   *
 017   * @property resource $_mh Internal use only. Lazy loaded multi-handle.
 018   */
 019  class CurlMultiHandler
 020  {
 021      /** @var callable */
 022      private $factory;
 023      private $selectTimeout;
 024      private $active;
 025      private $handles = [];
 026      private $delays = [];
 027      private $maxHandles;
 028   
 029      /**
 030       * This handler accepts the following options:
 031       *
 032       * - mh: An optional curl_multi resource
 033       * - handle_factory: An optional callable used to generate curl handle
 034       *   resources. the callable accepts a request hash and returns an array
 035       *   of the handle, headers file resource, and the body resource.
 036       * - select_timeout: Optional timeout (in seconds) to block before timing
 037       *   out while selecting curl handles. Defaults to 1 second.
 038       * - max_handles: Optional integer representing the maximum number of
 039       *   open requests. When this number is reached, the queued futures are
 040       *   flushed.
 041       *
 042       * @param array $options
 043       */
 044      public function __construct(array $options = [])
 045      {
 046          if (isset($options['mh'])) {
 047              $this->_mh = $options['mh'];
 048          }
 049          $this->factory = isset($options['handle_factory'])
 050              ? $options['handle_factory'] : new CurlFactory();
 051          $this->selectTimeout = isset($options['select_timeout'])
 052              ? $options['select_timeout'] : 1;
 053          $this->maxHandles = isset($options['max_handles'])
 054              ? $options['max_handles'] : 100;
 055      }
 056   
 057      public function __get($name)
 058      {
 059          if ($name === '_mh') {
 060              return $this->_mh = curl_multi_init();
 061          }
 062   
 063          throw new \BadMethodCallException();
 064      }
 065   
 066      public function __destruct()
 067      {
 068          // Finish any open connections before terminating the script.
 069          if ($this->handles) {
 070              $this->execute();
 071          }
 072   
 073          if (isset($this->_mh)) {
 074              curl_multi_close($this->_mh);
 075              unset($this->_mh);
 076          }
 077      }
 078   
 079      public function __invoke(array $request)
 080      {
 081          $factory = $this->factory;
 082          $result = $factory($request);
 083          $entry = [
 084              'request'  => $request,
 085              'response' => [],
 086              'handle'   => $result[0],
 087              'headers'  => &$result[1],
 088              'body'     => $result[2],
 089              'deferred' => new Deferred(),
 090          ];
 091   
 092          $id = (int) $result[0];
 093   
 094          $future = new FutureArray(
 095              $entry['deferred']->promise(),
 096              [$this, 'execute'],
 097              function () use ($id) {
 098                  return $this->cancel($id);
 099              }
 100          );
 101   
 102          $this->addRequest($entry);
 103   
 104          // Transfer outstanding requests if there are too many open handles.
 105          if (count($this->handles) >= $this->maxHandles) {
 106              $this->execute();
 107          }
 108   
 109          return $future;
 110      }
 111   
 112      /**
 113       * Runs until all outstanding connections have completed.
 114       */
 115      public function execute()
 116      {
 117          do {
 118   
 119              if ($this->active &&
 120                  curl_multi_select($this->_mh, $this->selectTimeout) === -1
 121              ) {
 122                  // Perform a usleep if a select returns -1.
 123                  // See: https://bugs.php.net/bug.php?id=61141
 124                  usleep(250);
 125              }
 126   
 127              // Add any delayed futures if needed.
 128              if ($this->delays) {
 129                  $this->addDelays();
 130              }
 131   
 132              do {
 133                  $mrc = curl_multi_exec($this->_mh, $this->active);
 134              } while ($mrc === CURLM_CALL_MULTI_PERFORM);
 135   
 136              $this->processMessages();
 137   
 138              // If there are delays but no transfers, then sleep for a bit.
 139              if (!$this->active && $this->delays) {
 140                  usleep(500);
 141              }
 142   
 143          } while ($this->active || $this->handles);
 144      }
 145   
 146      private function addRequest(array &$entry)
 147      {
 148          $id = (int) $entry['handle'];
 149          $this->handles[$id] = $entry;
 150   
 151          // If the request is a delay, then add the reques to the curl multi
 152          // pool only after the specified delay.
 153          if (isset($entry['request']['client']['delay'])) {
 154              $this->delays[$id] = microtime(true) + ($entry['request']['client']['delay'] / 1000);
 155          } elseif (empty($entry['request']['future'])) {
 156              curl_multi_add_handle($this->_mh, $entry['handle']);
 157          } else {
 158              curl_multi_add_handle($this->_mh, $entry['handle']);
 159              // "lazy" futures are only sent once the pool has many requests.
 160              if ($entry['request']['future'] !== 'lazy') {
 161                  do {
 162                      $mrc = curl_multi_exec($this->_mh, $this->active);
 163                  } while ($mrc === CURLM_CALL_MULTI_PERFORM);
 164                  $this->processMessages();
 165              }
 166          }
 167      }
 168   
 169      private function removeProcessed($id)
 170      {
 171          if (isset($this->handles[$id])) {
 172              curl_multi_remove_handle(
 173                  $this->_mh,
 174                  $this->handles[$id]['handle']
 175              );
 176              curl_close($this->handles[$id]['handle']);
 177              unset($this->handles[$id], $this->delays[$id]);
 178          }
 179      }
 180   
 181      /**
 182       * Cancels a handle from sending and removes references to it.
 183       *
 184       * @param int $id Handle ID to cancel and remove.
 185       *
 186       * @return bool True on success, false on failure.
 187       */
 188      private function cancel($id)
 189      {
 190          // Cannot cancel if it has been processed.
 191          if (!isset($this->handles[$id])) {
 192              return false;
 193          }
 194   
 195          $handle = $this->handles[$id]['handle'];
 196          unset($this->delays[$id], $this->handles[$id]);
 197          curl_multi_remove_handle($this->_mh, $handle);
 198          curl_close($handle);
 199   
 200          return true;
 201      }
 202   
 203      private function addDelays()
 204      {
 205          $currentTime = microtime(true);
 206   
 207          foreach ($this->delays as $id => $delay) {
 208              if ($currentTime >= $delay) {
 209                  unset($this->delays[$id]);
 210                  curl_multi_add_handle(
 211                      $this->_mh,
 212                      $this->handles[$id]['handle']
 213                  );
 214              }
 215          }
 216      }
 217   
 218      private function processMessages()
 219      {
 220          while ($done = curl_multi_info_read($this->_mh)) {
 221              $id = (int) $done['handle'];
 222   
 223              if (!isset($this->handles[$id])) {
 224                  // Probably was cancelled.
 225                  continue;
 226              }
 227   
 228              $entry = $this->handles[$id];
 229              $entry['response']['transfer_stats'] = curl_getinfo($done['handle']);
 230   
 231              if ($done['result'] !== CURLM_OK) {
 232                  $entry['response']['curl']['errno'] = $done['result'];
 233                  if (function_exists('curl_strerror')) {
 234                      $entry['response']['curl']['error'] = curl_strerror($done['result']);
 235                  }
 236              }
 237   
 238              $result = CurlFactory::createResponse(
 239                  $this,
 240                  $entry['request'],
 241                  $entry['response'],
 242                  $entry['headers'],
 243                  $entry['body']
 244              );
 245   
 246              $this->removeProcessed($id);
 247              $entry['deferred']->resolve($result);
 248          }
 249      }
 250  }
 251