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

StreamHandler.php

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


 001  <?php
 002  namespace GuzzleHttp\Ring\Client;
 003   
 004  use GuzzleHttp\Ring\Core;
 005  use GuzzleHttp\Ring\Exception\ConnectException;
 006  use GuzzleHttp\Ring\Exception\RingException;
 007  use GuzzleHttp\Ring\Future\CompletedFutureArray;
 008  use GuzzleHttp\Stream\InflateStream;
 009  use GuzzleHttp\Stream\StreamInterface;
 010  use GuzzleHttp\Stream\Stream;
 011  use GuzzleHttp\Stream\Utils;
 012   
 013  /**
 014   * RingPHP client handler that uses PHP's HTTP stream wrapper.
 015   */
 016  class StreamHandler
 017  {
 018      private $options;
 019      private $lastHeaders;
 020   
 021      public function __construct(array $options = [])
 022      {
 023          $this->options = $options;
 024      }
 025   
 026      public function __invoke(array $request)
 027      {
 028          $url = Core::url($request);
 029          Core::doSleep($request);
 030   
 031          try {
 032              // Does not support the expect header.
 033              $request = Core::removeHeader($request, 'Expect');
 034              $stream = $this->createStream($url, $request);
 035              return $this->createResponse($request, $url, $stream);
 036          } catch (RingException $e) {
 037              return $this->createErrorResponse($url, $e);
 038          }
 039      }
 040   
 041      private function createResponse(array $request, $url, $stream)
 042      {
 043          $hdrs = $this->lastHeaders;
 044          $this->lastHeaders = null;
 045          $parts = explode(' ', array_shift($hdrs), 3);
 046          $response = [
 047              'version'        => substr($parts[0], 5),
 048              'status'         => $parts[1],
 049              'reason'         => isset($parts[2]) ? $parts[2] : null,
 050              'headers'        => Core::headersFromLines($hdrs),
 051              'effective_url'  => $url,
 052          ];
 053   
 054          $stream = $this->checkDecode($request, $response, $stream);
 055   
 056          // If not streaming, then drain the response into a stream.
 057          if (empty($request['client']['stream'])) {
 058              $dest = isset($request['client']['save_to'])
 059                  ? $request['client']['save_to']
 060                  : fopen('php://temp', 'r+');
 061              $stream = $this->drain($stream, $dest);
 062          }
 063   
 064          $response['body'] = $stream;
 065   
 066          return new CompletedFutureArray($response);
 067      }
 068   
 069      private function checkDecode(array $request, array $response, $stream)
 070      {
 071          // Automatically decode responses when instructed.
 072          if (!empty($request['client']['decode_content'])) {
 073              switch (Core::firstHeader($response, 'Content-Encoding', true)) {
 074                  case 'gzip':
 075                  case 'deflate':
 076                      $stream = new InflateStream(Stream::factory($stream));
 077                      break;
 078              }
 079          }
 080   
 081          return $stream;
 082      }
 083   
 084      /**
 085       * Drains the stream into the "save_to" client option.
 086       *
 087       * @param resource                        $stream
 088       * @param string|resource|StreamInterface $dest
 089       *
 090       * @return Stream
 091       * @throws \RuntimeException when the save_to option is invalid.
 092       */
 093      private function drain($stream, $dest)
 094      {
 095          if (is_resource($stream)) {
 096              if (!is_resource($dest)) {
 097                  $stream = Stream::factory($stream);
 098              } else {
 099                  stream_copy_to_stream($stream, $dest);
 100                  fclose($stream);
 101                  rewind($dest);
 102                  return $dest;
 103              }
 104          }
 105   
 106          // Stream the response into the destination stream
 107          $dest = is_string($dest)
 108              ? new Stream(Utils::open($dest, 'r+'))
 109              : Stream::factory($dest);
 110   
 111          Utils::copyToStream($stream, $dest);
 112          $dest->seek(0);
 113          $stream->close();
 114   
 115          return $dest;
 116      }
 117   
 118      /**
 119       * Creates an error response for the given stream.
 120       *
 121       * @param string        $url
 122       * @param RingException $e
 123       *
 124       * @return array
 125       */
 126      private function createErrorResponse($url, RingException $e)
 127      {
 128          // Determine if the error was a networking error.
 129          $message = $e->getMessage();
 130   
 131          // This list can probably get more comprehensive.
 132          if (strpos($message, 'getaddrinfo') // DNS lookup failed
 133              || strpos($message, 'Connection refused')
 134          ) {
 135              $e = new ConnectException($e->getMessage(), 0, $e);
 136          }
 137   
 138          return new CompletedFutureArray([
 139              'status'        => null,
 140              'body'          => null,
 141              'headers'       => [],
 142              'effective_url' => $url,
 143              'error'         => $e
 144          ]);
 145      }
 146   
 147      /**
 148       * Create a resource and check to ensure it was created successfully
 149       *
 150       * @param callable $callback Callable that returns stream resource
 151       *
 152       * @return resource
 153       * @throws \RuntimeException on error
 154       */
 155      private function createResource(callable $callback)
 156      {
 157          $errors = null;
 158          set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
 159              $errors[] = [
 160                  'message' => $msg,
 161                  'file'    => $file,
 162                  'line'    => $line
 163              ];
 164              return true;
 165          });
 166   
 167          $resource = $callback();
 168          restore_error_handler();
 169   
 170          if (!$resource) {
 171              $message = 'Error creating resource: ';
 172              foreach ($errors as $err) {
 173                  foreach ($err as $key => $value) {
 174                      $message .= "[$key] $value" . PHP_EOL;
 175                  }
 176              }
 177              throw new RingException(trim($message));
 178          }
 179   
 180          return $resource;
 181      }
 182   
 183      private function createStream($url, array $request)
 184      {
 185          static $methods;
 186          if (!$methods) {
 187              $methods = array_flip(get_class_methods(__CLASS__));
 188          }
 189   
 190          // HTTP/1.1 streams using the PHP stream wrapper require a
 191          // Connection: close header
 192          if ((!isset($request['version']) || $request['version'] == '1.1')
 193              && !Core::hasHeader($request, 'Connection')
 194          ) {
 195              $request['headers']['Connection'] = ['close'];
 196          }
 197   
 198          // Ensure SSL is verified by default
 199          if (!isset($request['client']['verify'])) {
 200              $request['client']['verify'] = true;
 201          }
 202   
 203          $params = [];
 204          $options = $this->getDefaultOptions($request);
 205   
 206          if (isset($request['client'])) {
 207              foreach ($request['client'] as $key => $value) {
 208                  $method = "add_{$key}";
 209                  if (isset($methods[$method])) {
 210                      $this->{$method}($request, $options, $value, $params);
 211                  }
 212              }
 213          }
 214   
 215          return $this->createStreamResource(
 216              $url,
 217              $request,
 218              $options,
 219              $this->createContext($request, $options, $params)
 220          );
 221      }
 222   
 223      private function getDefaultOptions(array $request)
 224      {
 225          $headers = "";
 226          foreach ($request['headers'] as $name => $value) {
 227              foreach ((array) $value as $val) {
 228                  $headers .= "$name: $val\r\n";
 229              }
 230          }
 231   
 232          $context = [
 233              'http' => [
 234                  'method'           => $request['http_method'],
 235                  'header'           => $headers,
 236                  'protocol_version' => isset($request['version']) ? $request['version'] : 1.1,
 237                  'ignore_errors'    => true,
 238                  'follow_location'  => 0,
 239              ],
 240          ];
 241   
 242          $body = Core::body($request);
 243          if (isset($body)) {
 244              $context['http']['content'] = $body;
 245              // Prevent the HTTP handler from adding a Content-Type header.
 246              if (!Core::hasHeader($request, 'Content-Type')) {
 247                  $context['http']['header'] .= "Content-Type:\r\n";
 248              }
 249          }
 250   
 251          $context['http']['header'] = rtrim($context['http']['header']);
 252   
 253          return $context;
 254      }
 255   
 256      private function add_proxy(array $request, &$options, $value, &$params)
 257      {
 258          if (!is_array($value)) {
 259              $options['http']['proxy'] = $value;
 260          } else {
 261              $scheme = isset($request['scheme']) ? $request['scheme'] : 'http';
 262              if (isset($value[$scheme])) {
 263                  $options['http']['proxy'] = $value[$scheme];
 264              }
 265          }
 266      }
 267   
 268      private function add_timeout(array $request, &$options, $value, &$params)
 269      {
 270          $options['http']['timeout'] = $value;
 271      }
 272   
 273      private function add_verify(array $request, &$options, $value, &$params)
 274      {
 275          if ($value === true) {
 276              // PHP 5.6 or greater will find the system cert by default. When
 277              // < 5.6, use the Guzzle bundled cacert.
 278              if (PHP_VERSION_ID < 50600) {
 279                  $options['ssl']['cafile'] = ClientUtils::getDefaultCaBundle();
 280              }
 281          } elseif (is_string($value)) {
 282              $options['ssl']['cafile'] = $value;
 283              if (!file_exists($value)) {
 284                  throw new RingException("SSL CA bundle not found: $value");
 285              }
 286          } elseif ($value === false) {
 287              $options['ssl']['verify_peer'] = false;
 288              $options['ssl']['allow_self_signed'] = true;
 289              return;
 290          } else {
 291              throw new RingException('Invalid verify request option');
 292          }
 293   
 294          $options['ssl']['verify_peer'] = true;
 295          $options['ssl']['allow_self_signed'] = false;
 296      }
 297   
 298      private function add_cert(array $request, &$options, $value, &$params)
 299      {
 300          if (is_array($value)) {
 301              $options['ssl']['passphrase'] = $value[1];
 302              $value = $value[0];
 303          }
 304   
 305          if (!file_exists($value)) {
 306              throw new RingException("SSL certificate not found: {$value}");
 307          }
 308   
 309          $options['ssl']['local_cert'] = $value;
 310      }
 311   
 312      private function add_progress(array $request, &$options, $value, &$params)
 313      {
 314          $fn = function ($code, $_1, $_2, $_3, $transferred, $total) use ($value) {
 315              if ($code == STREAM_NOTIFY_PROGRESS) {
 316                  $value($total, $transferred, null, null);
 317              }
 318          };
 319   
 320          // Wrap the existing function if needed.
 321          $params['notification'] = isset($params['notification'])
 322              ? Core::callArray([$params['notification'], $fn])
 323              : $fn;
 324      }
 325   
 326      private function add_debug(array $request, &$options, $value, &$params)
 327      {
 328          if ($value === false) {
 329              return;
 330          }
 331   
 332          static $map = [
 333              STREAM_NOTIFY_CONNECT       => 'CONNECT',
 334              STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
 335              STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',
 336              STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',
 337              STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',
 338              STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',
 339              STREAM_NOTIFY_PROGRESS      => 'PROGRESS',
 340              STREAM_NOTIFY_FAILURE       => 'FAILURE',
 341              STREAM_NOTIFY_COMPLETED     => 'COMPLETED',
 342              STREAM_NOTIFY_RESOLVE       => 'RESOLVE',
 343          ];
 344   
 345          static $args = ['severity', 'message', 'message_code',
 346              'bytes_transferred', 'bytes_max'];
 347   
 348          $value = Core::getDebugResource($value);
 349          $ident = $request['http_method'] . ' ' . Core::url($request);
 350          $fn = function () use ($ident, $value, $map, $args) {
 351              $passed = func_get_args();
 352              $code = array_shift($passed);
 353              fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
 354              foreach (array_filter($passed) as $i => $v) {
 355                  fwrite($value, $args[$i] . ': "' . $v . '" ');
 356              }
 357              fwrite($value, "\n");
 358          };
 359   
 360          // Wrap the existing function if needed.
 361          $params['notification'] = isset($params['notification'])
 362              ? Core::callArray([$params['notification'], $fn])
 363              : $fn;
 364      }
 365   
 366      private function applyCustomOptions(array $request, array &$options)
 367      {
 368          if (!isset($request['client']['stream_context'])) {
 369              return;
 370          }
 371   
 372          if (!is_array($request['client']['stream_context'])) {
 373              throw new RingException('stream_context must be an array');
 374          }
 375   
 376          $options = array_replace_recursive(
 377              $options,
 378              $request['client']['stream_context']
 379          );
 380      }
 381   
 382      private function createContext(array $request, array $options, array $params)
 383      {
 384          $this->applyCustomOptions($request, $options);
 385          return $this->createResource(
 386              function () use ($request, $options, $params) {
 387                  return stream_context_create($options, $params);
 388              },
 389              $request,
 390              $options
 391          );
 392      }
 393   
 394      private function createStreamResource(
 395          $url,
 396          array $request,
 397          array $options,
 398          $context
 399      ) {
 400          return $this->createResource(
 401              function () use ($url, $context) {
 402                  if (false === strpos($url, 'http')) {
 403                      trigger_error("URL is invalid: {$url}", E_USER_WARNING);
 404                      return null;
 405                  }
 406                  $resource = fopen($url, 'r', null, $context);
 407                  $this->lastHeaders = $http_response_header;
 408                  return $resource;
 409              },
 410              $request,
 411              $options
 412          );
 413      }
 414  }
 415