Advertisement
Guest User

Untitled

a guest
Sep 22nd, 2016
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 20.04 KB | None | 0 0
  1. <?php
  2.  
  3. function dump($v) {
  4.   echo('<pre>' . var_export($v, true) . '</pre>');
  5. }
  6.  
  7.  
  8. // header("http/1.0              404                \t\t\tNot Found\t");
  9. header("Content-Type:\t \t  text/plain;charset=windows-1251 =пизда%00;charset   \t\t\t\t= \"utf-8\" foo, bar");
  10. header('cache-control: no-cache');
  11. header('Cache-control: no-store'); // cache-control: no-store
  12. echo("Тест\n");
  13.  
  14. preg_match('~;\s*charset\s*=\s*(?:"([^"]+)"|([^\s;]+))~i', "text/html;  charset\t=   utf-8\t\"q;", $matches);
  15. // var_dump($matches);
  16. // echo('charset: ' . (count($matches) ? (isset($matches[2]) ? $matches[2] : $matches[1]) : ''));
  17. // echo('\\\t\'\0 ');
  18.  
  19.  
  20. preg_match_all('/[\x00-\xff]/', 'тест', $m);
  21. // var_dump($m);
  22.  
  23. $headers = "HTTP/1.1 200\r\n" .
  24.            "Content-Type:" .
  25.            "\r\n\ttext/html;" .
  26.            "\r\n\t charset=utf-8";
  27.  
  28. // echo("Headers:\n");
  29. // echo(preg_replace('/\r\n[ \t]+/', ' ', $headers));
  30. // Bad chars: \x00-\x08\x0b\x0c\x0e-\x1f\x7f
  31.  
  32. error_reporting(E_ALL);
  33. // set_time_limit(5);
  34. echo(str_repeat('-', 80) . PHP_EOL);
  35.  
  36. // list($a, $b) = explode(':', '');
  37.  
  38. // die;
  39.  
  40. if (!function_exists('http_build_url')) {
  41.   function http_build_url($parts) {
  42.     if (!is_array($parts)) {
  43.       return false;
  44.     }
  45.  
  46.     return (isset($parts['scheme']) ? $parts['scheme'] . '://' : '') .
  47.       (isset($parts['user']) ?
  48.         $parts['user'] .
  49.         (isset($parts['pass']) ? ':' . $parts['pass'] : '') . '@'
  50.         : '') .
  51.       (isset($parts['host']) ? $parts['host']: '') .
  52.       (isset($parts['port']) ? ':' . $parts['port']: '') .
  53.       (isset($parts['path']) ?
  54.         (substr($parts['path'], 0, 1) != '/' ? '/' : '') . $parts['path']
  55.         : '') .
  56.       (isset($parts['query']) ? '?' . $parts['query']: '') .
  57.       (isset($parts['fragment']) ? '#' . $parts['fragment']: '');
  58.   }
  59. }
  60.  
  61.  
  62. echo(http_build_url([
  63.   'user' => 'username',
  64.   'host' => 'example.com',
  65.   'path' => 'path/to/handler',
  66.   'query' => 'query',
  67.   'fragment' => 'hash'
  68. ]) . PHP_EOL);
  69.  
  70. echo(http_build_url([
  71.   'scheme' => 'https',
  72.   'user' => 'username',
  73.   'pass' => 'password',
  74.   'host' => 'example.com',
  75.   'path' => 'path/to/handler',
  76.   'query' => 'query',
  77.   'fragment' => 'hash'
  78. ]) . PHP_EOL);
  79.  
  80. $u = 'google.com:8080/path/to/handler?#';
  81. echo('Исходный URL: ' . $u . PHP_EOL);
  82. $p = parse_url($u);
  83. echo("Результат парсинга: ");
  84. print_r($p);
  85. echo('Результат http_build_url(): ' . http_build_url($p) . PHP_EOL);
  86.  
  87.  
  88. class HTTPConnection {
  89.   const CONNECTION_TIMEOUT = 10;
  90.   const HOSTNAME = 'localhost';
  91.   const READ_SIZE = 4096;
  92.   const TIMEOUT = 10;
  93.   const TRANSPORT = 'tcp';
  94.   const PORT = 80;
  95.  
  96.   protected $connectionTimeout;
  97.   protected $persistent;
  98.   protected $port;
  99.   protected $socket;
  100.   protected $timeout;
  101.   protected $hostname;
  102.  
  103.   public function __construct($hostname = null, $port = null, $connection_timeout = null, $timeout = null,
  104.       $persistent = false) {
  105.     $this->hostname = is_null($hostname) ? static::HOSTNAME : $hostname;
  106.     $this->port = is_null($port) ? static::PORT : $port;
  107.     $this->connectionTimeout = is_null($connection_timeout) ? static::CONNECTION_TIMEOUT : $connection_timeout;
  108.     $this->timeout = is_null($timeout) ? static::TIMEOUT : $timeout;
  109.     $this->persistent = $persistent;
  110.     $this->open();
  111.   }
  112.  
  113.   public function getHostname() {
  114.     return $this->hostname;
  115.   }
  116.  
  117.   public function getPort() {
  118.     return $this->port;
  119.   }
  120.  
  121.   public function getConnectionTimeout() {
  122.     return $this->connectionTimeout;
  123.   }
  124.  
  125.   public function getTimeout() {
  126.     return $this->timeout;
  127.   }
  128.  
  129.   public function request($path = '/', $method = 'GET', $headers = array(),
  130.       $data = '') {
  131.     $message = "$method $path HTTP/1.1\r\n";
  132.     $message .= 'Host: ' . $this->hostname . ($this->port != static::PORT ? ':' . $this->port : '') . "\r\n";
  133.  
  134.     foreach ($headers as $name => $value) {
  135.       $message .= "$name: $value\r\n";
  136.     }
  137.  
  138.     $message .= "\r\n";
  139.     $message .= $data;
  140.     // echo("Request:\n");
  141.     // echo($message . "\n");
  142.     $this->write($message);
  143.   }
  144.  
  145.   public function write($data) {
  146.     return fwrite($this->socket, $data);
  147.   }
  148.  
  149.   public function read($size = null) {
  150.     $data = fread($this->socket, is_null($size) ? static::READ_SIZE : $size);
  151.     $this->throwIfTimedOut();
  152.     return $data;
  153.   }
  154.  
  155.   public function readLine($size = null) {
  156.     $data = fgets($this->socket, is_null($size) ? static::READ_SIZE : $size);
  157.     $this->throwIfTimedOut();
  158.     return $data;
  159.   }
  160.  
  161.   public function eof() {
  162.     return feof($this->socket);
  163.   }
  164.  
  165.   public function getStreamMetaData() {
  166.     return stream_get_meta_data($this->socket);
  167.   }
  168.  
  169.   public function close() {
  170.     fclose($this->socket);
  171.   }
  172.  
  173.   protected function open() {
  174.     $funcion = ($this->persistent ? 'p' : '') . 'fsockopen';
  175.     $address = static::TRANSPORT . '://' . $this->hostname;
  176.     // echo($address . "\n");
  177.     $this->socket = @call_user_func($funcion, $address, $this->port, $errno, $errstr, $this->connectionTimeout);
  178.  
  179.     if (!$this->socket) {
  180.       // Функции типа socket_last_error отключены по-умолчанию
  181.       throw new SocketError("Socket error $errno: $errstr");    
  182.     }
  183.  
  184.     // http://forum.sources.ru/index.php?showtopic=88374
  185.     // stream_set_blocking($this->socket, true);
  186.     // timeout на чтение/запись в сокет
  187.     stream_set_timeout($this->socket, $this->timeout);
  188.   }
  189.  
  190.   protected function throwIfTimedOut() {
  191.     $info = $this->getStreamMetaData();
  192.  
  193.     if ($info['timed_out']) {
  194.       throw new SocketError('Socket timed out');
  195.     }
  196.   }
  197. }
  198.  
  199.  
  200. class HTTPSConnection extends HTTPConnection {
  201.   const PORT = 443;
  202.   const TRANSPORT = 'ssl';
  203. }
  204.  
  205.  
  206. class SocketError extends Exception {}
  207.  
  208.  
  209. class Header {
  210.   protected $name;
  211.   protected $value;
  212.  
  213.   public function __construct($name, $value) {
  214.     $this->setName($name);
  215.     $this->setValue($value);
  216.   }
  217.  
  218.   public function setName($name) {
  219.     $this->name = $name;
  220.   }
  221.  
  222.   public function setValue($value) {
  223.     $this->value = $value;
  224.   }
  225.  
  226.   public function getName() {
  227.     return $this->name;
  228.   }
  229.  
  230.   public function getValue() {
  231.     return $this->value;
  232.   }
  233.  
  234.   public function __toString() {
  235.     return sprintf('%s: %s', $this->name,  $this->value);
  236.   }
  237. }
  238.  
  239.  
  240. /**
  241.   * Класс для работы с http-заголовками.
  242.   *
  243.   * Имена полей регистронезависимы. Значения полей можно получить, обращаясь к
  244.   * объекту как к массиву. К объекту применимы вызовы функций count, isset и
  245.   * unset, а так же возможен по нему обход с помощью цикла foreach.
  246.   */
  247. class Headers implements ArrayAccess, Countable, IteratorAggregate {
  248.   protected $headers = array();
  249.  
  250.   public function __construct($headers = array()) {
  251.     $this->update($headers);
  252.   }
  253.  
  254.   /**
  255.     * Добавляет новый заголовок.
  256.     */
  257.   public function add($name, $value) {
  258.     $this->headers[strtolower($name)] = new Header($name, $value);
  259.   }
  260.  
  261.   /**
  262.     * Добавляет новый заголовок либо заменяет значение существующего, при этом
  263.     * оригинальное имя сохраняется.
  264.     */
  265.   public function set($name, $value) {
  266.     $lower_name = strtolower($name);
  267.  
  268.     if (isset($this->headers[$lower_name])) {
  269.       $this->headers[$lower_name]->setValue($value);
  270.     } else {
  271.       $this->headers[$lower_name] = new Header($name, $value);
  272.     }
  273.  
  274.     // возвращаем установленное значение
  275.     return $value;
  276.   }
  277.  
  278.   public function update($data) {
  279.     foreach ($data as $name => $value) {
  280.       $this->set($name, $value);
  281.     }
  282.   }
  283.  
  284.   public function get($name, $default = null) {
  285.     $name = strtolower($name);
  286.     return isset($this->headers[$name]) ? $this->headers[$name]->getValue() : $default;
  287.   }
  288.  
  289.   /**
  290.     * Возвращает оригинальное имя заголовка.
  291.     */
  292.   public function getOriginalName($name) {
  293.     $name = strtolower($name);
  294.  
  295.     if (isset($this->headers[$name])) {
  296.       return $this->headers[$name]->getName();
  297.     }
  298.   }
  299.  
  300.   public function has($name) {
  301.     return isset($this->headers[strtolower($name)]);
  302.   }
  303.  
  304.   public function remove($name) {
  305.     unset($this->headers[strtolower($name)]);
  306.   }
  307.  
  308.   public function toArray() {
  309.     $headers = array();
  310.  
  311.     foreach ($this->headers as $header) {
  312.       $headers[$header->getName()] = $header->getValue();
  313.     }
  314.  
  315.     return $headers;
  316.   }
  317.  
  318.   public function __toString() {
  319.     $out = '';
  320.    
  321.     foreach ($this->headers as $header) {
  322.       $out .= $header->__toString() . "\r\n";
  323.     }
  324.  
  325.     return $out;
  326.   }
  327.  
  328.   public function __clone() {
  329.     foreach ($this->headers as &$h) {
  330.       $h = clone $h;
  331.     }
  332.   }
  333.  
  334.   public static function parse($str) {
  335.     // new self будет создавать экземпляр класса, где был объявлен метод
  336.     $headers = new static;
  337.  
  338.     if (strlen($str)) {
  339.       // Значения заголовков могут располагаться на нескольких строках, если
  340.       // перед значением следуют CRLF и хотя бы один пробел или таб (LWS):
  341.       //
  342.       // Header: value,
  343.       //         value2
  344.       //
  345.       // RFC советует заменять LWS на одиночный пробел:
  346.       //
  347.       // Header: value, value2
  348.       //
  349.       $str = preg_replace('/\r\n[ \t]+/', ' ', $str);
  350.       // всегда возвращает хотя бы один элемент
  351.       $lines = explode("\r\n", $str);
  352.       $limit = count($lines);
  353.  
  354.       // Пустая строка в конце массива
  355.       if (!strlen($lines[$limit - 1])) {
  356.         --$limit;
  357.       }
  358.  
  359.       for ($i = 0; $i < $limit; ++$i) {
  360.         $parts = explode(':', $lines[$i], 2);
  361.  
  362.         if (count($parts) < 2) {
  363.           throw new HeaderParseError('Header without colon');
  364.         }
  365.  
  366.         list($name, $value) = $parts;
  367.         $value = trim($value);
  368.        
  369.         if (isset($headers[$name])) {
  370.           // по rfc заголовки с одинаковыми либо различающимися лишь регистром
  371.           // именами могут быть объеденены в один. Их значения должны быть
  372.           // добавлены к значениям первого заголовка и разделены запятыми.
  373.           //
  374.           // Пример:
  375.           //
  376.           // Cache-Control: no-cache
  377.           // cache-control: no-store
  378.           //
  379.           // После нормализации:
  380.           //
  381.           // Cache-Control: no-cache, no-store
  382.           $headers[$name] .= ', ' . $value;
  383.         } else {
  384.           $headers[$name] = $value;
  385.         }
  386.       }
  387.     }
  388.  
  389.     return $headers;
  390.   }
  391.  
  392.   public function offsetSet($offset, $value) {
  393.     return $this->set($offset, $value);
  394.   }
  395.  
  396.   public function offsetExists($offset) {
  397.     return $this->has($offset);
  398.   }
  399.  
  400.   public function offsetUnset($offset) {
  401.     $this->remove($offset);
  402.   }
  403.  
  404.   public function offsetGet($offset) {
  405.     return $this->get($offset);
  406.   }
  407.  
  408.   public function count() {
  409.     return count($this->headers);
  410.   }
  411.  
  412.   public function getIterator() {
  413.     return new ArrayIterator($this->toArray());
  414.   }
  415. }
  416.  
  417.  
  418. class HeaderParseError extends Exception {}
  419.  
  420.  
  421. // за основу взят этот код:
  422. // https://github.com/square/okhttp/blob/master/okhttp/src/main/java/okhttp3/MediaType.java
  423. // там неправильная регулярка для токенов
  424. // http://rfc2.ru/2068.rfc/6#p2.2
  425. class MediaType {
  426.   const TOKEN = '([!#$%&\'*+-.^`|~\w]+)';
  427.   // quoted-string  = ( <"> *(qdtext) <"> )
  428.   // qdtext         = <любой TEXT не включающий <">>
  429.   const QUOTED_STRING = '"([^"]*)"';
  430.  
  431.   protected $mediaType;
  432.   protected $type;
  433.   protected $subtype;
  434.   protected $parameters;
  435.  
  436.   public function __construct($str) {
  437.     $this->mediaType = $str;
  438.     $this->parse();
  439.   }
  440.  
  441.   public function __toString() {
  442.     return $this->mediaType;
  443.   }
  444.  
  445.   public function getMediaType() {
  446.     return $this->mediaType;
  447.   }
  448.  
  449.   public function getType() {
  450.     return $this->type;
  451.   }
  452.  
  453.   public function getSubtype() {
  454.     return $this->subtype;
  455.   }
  456.  
  457.   public function getFullType() {
  458.     return $this->type . '/' . $this->subtype;
  459.   }
  460.  
  461.   public function getParameter($name, $default = null) {
  462.     $name = strtolower($name);
  463.    
  464.     if (isset($this->parameters[$name])) {
  465.       return $this->parameters[$name];
  466.     }
  467.  
  468.     return $default;
  469.   }
  470.  
  471.   public function getParameters() {
  472.     return $this->parameters;
  473.   }
  474.  
  475.   protected function parse() {
  476.     // media-type     = type "/" subtype *( ";" parameter )
  477.     // type           = token
  478.     // subtype        = token
  479.     $media_type_re = '/^\s*' . static::TOKEN . '\/' . static::TOKEN . '\s*(?=;|$)/';
  480.     // echo($media_type_re . PHP_EOL);
  481.     // parameter      = attribute "=" value
  482.     // attribute      = token
  483.     // value          = token | quoted-string
  484.     $parameter_re = '/^;\s*' . static::TOKEN . '\s*=\s*(?:' . static::TOKEN . '|' . static::QUOTED_STRING . ')\s*/';
  485.     // echo($parameter_re . PHP_EOL);
  486.  
  487.     if (!preg_match($media_type_re, $this->mediaType, $matches)) {
  488.       throw new MediaTypeError('Invalid media type');
  489.     }
  490.  
  491.     $this->type = strtolower($matches[1]);
  492.     $this->subtype = strtolower($matches[2]);
  493.     $offset = strlen($matches[0]);
  494.     $str = $this->mediaType;
  495.  
  496.     while ($offset < strlen($str)) {
  497.       $str = substr($str, $offset);
  498.  
  499.       if (!preg_match($parameter_re, $str, $matches)) {
  500.         throw new MediaTypeError('Invalid parameter');
  501.       }
  502.  
  503.       // print_r($matches);
  504.       $offset = strlen($matches[0]);
  505.       $name = strtolower($matches[1]);
  506.       $value = isset($matches[3]) ? $this->unquote($matches[3]) : $matches[2];
  507.       $this->parameters[$name] = $value;
  508.     }
  509.   }
  510.  
  511.   protected function unquote($v) {
  512.     // TODO: сделать замену escape-последовательностей
  513.     return $v;
  514.   }
  515. }
  516.  
  517.  
  518. class MediaTypeError extends Exception {}
  519.  
  520.  
  521. print_r(new MediaType('  TeXt/HtMl ; charset =  "UTF-8" ; foo=bar '));
  522.  
  523.  
  524. $headers = new Headers(
  525.   array(
  526.     'User-Agent' => 'Mozilla/5.0',
  527.     'Accept-Encoding' => 'gzip, deflate',
  528.     'Accept' => '*/*',
  529.   )
  530. );
  531.  
  532. //
  533. // $url = 'https://httpbin.org/gzip';
  534. // $url = 'https://httpbin.org/deflate'
  535. $url = 'https://www.httpwatch.com/httpgallery/chunked/chunkedimage.aspx';
  536.  
  537. $method = 'GET';
  538. $data = '';
  539. // scheme, user, pass, host, port, path, query, fragment
  540. $parsed_url = parse_url($url);
  541. print_r($parsed_url);
  542.  
  543. if ($parsed_url === false || !isset($parsed_url['scheme'])
  544.     || !isset($parsed_url['host'])) {
  545.   throw new Exception('Bad URL');
  546. }
  547.  
  548. $scheme = $parsed_url['scheme'];
  549.  
  550. if (!preg_match('/^https?$/i', $scheme)) {
  551.   throw new Exception("Unsupported scheme: $scheme");
  552. }
  553.  
  554. $hostname = $parsed_url['host'];
  555. $port = isset($parsed_url['port']) ? $parsed_url['port'] : null;
  556. // классы все равно регистронезависимы
  557. $class = $scheme . 'connection';
  558. $connection = new $class($hostname, $port);
  559. $request_uri = isset($parsed_url['path']) ? $parsed_url['path'] : '/';
  560.  
  561. if (isset($parsed_url['query'])) {
  562.   $request_uri .= '?' . $parsed_url['query'];
  563. }
  564.  
  565. $headers = clone $headers;
  566. // $headers['Connection'] = 'close';
  567.  
  568. // if (isset($parsed_url['user'])) {
  569. //   $username = $parsed_url['user'];
  570. //   $password = isset($parsed_url['pass']) ? $parsed_url['pass'] : '';
  571. //   $headers['Authorization'] = 'Basic ' .
  572. //     base64_encode($username . ':' . $password);
  573. // }
  574.  
  575. $content_length = strlen($data);
  576.  
  577. if ($content_length) {
  578.   $headers['Content-Length'] = $content_length;
  579. }
  580.  
  581. echo("Request headers:\n");
  582. print_r($headers->toArray());
  583. $connection->request($request_uri, $method, $headers, $data);
  584. $status_line = $connection->readLine();
  585. // HTTP-version is case-sensitive.
  586. $re = '/^HTTP\/(\d\.\d) ([1-5]\d\d) (.*)/';
  587.  
  588. if (!preg_match($re, $status_line, $matches)) {
  589.   throw new Exception('Invalid status line');
  590. }
  591.  
  592. list( , $http_version, $status_code, $reason_phrase) = $matches;
  593.  
  594. $header = '';
  595.  
  596. while (!$connection->eof()) {
  597.   $line = $connection->readLine();
  598.  
  599.   if ($line == "\r\n") {
  600.     break;
  601.   }
  602.  
  603.   $header .= $line;
  604. }
  605.  
  606. $headers = Headers::parse($header);
  607. echo("Response headers:\n");
  608. print_r($headers->toArray());
  609. // unset($headers['content-length']);
  610. // $headers['content-length'] = -1;
  611.  
  612. $content = '';
  613.  
  614. function decode($data, $encoding) {
  615.   if ($encoding == 'gzip') {
  616.     // http://php.net/manual/ru/function.gzinflate.php#77336
  617.     // Про флаги тут:
  618.     // http://www.forensicswiki.org/wiki/Gzip
  619.     if (substr($data, 0, 3) == "\x1f\x8b\x08") {
  620.       $offset = 10;
  621.       $flag = ord(substr($data, 3, 1));
  622.  
  623.       if ($flag) {
  624.         if ($flag & 2) {
  625.           $offset += 2;
  626.         }
  627.  
  628.         if ($flag & 4) {
  629.           list($xlen) = unpack('v',substr($data, $offset, 2));
  630.           $offset += 2 + $xlen;
  631.         }
  632.        
  633.         if ($flag & 8) {
  634.           $offset = strpos($data, "\0", $offset) + 1;
  635.         }
  636.  
  637.         if ($flag & 16) {
  638.           $offset = strpos($data, "\0", $offset) + 1;
  639.         }
  640.       }
  641.  
  642.       return @gzinflate(substr($data, $offset, -8));
  643.     }
  644.   } else if ($encoding == 'deflate') {
  645.     // https://github.com/zendframework/zend-http/blob/master/src/Response.php
  646.     $h = unpack('n', substr($data, 0, 2));
  647.  
  648.     if ($h[1] % 31 == 0) {
  649.         return @gzuncompress($data);
  650.     }
  651.  
  652.     return @gzinflate($data);
  653.   }
  654.  
  655.   return false;
  656. }  
  657.  
  658.  
  659. // Если установлен Transfer-Encoding Content-Length игнорируется.
  660.  
  661. // If a Content-Length header field (section 14.13) is present, its decimal
  662. // value in OCTETs represents both the entity-length and the transfer-length.
  663. // The Content-Length header field MUST NOT be sent if these two lengths are
  664. // different (i.e., if a Transfer-Encoding header field is present). If a
  665. // message is received with both a Transfer-Encoding header field and a
  666. // Content-Length header field, the latter MUST be ignored.
  667. if (isset($headers['transfer-encoding'])) {
  668.   $encoding = strtolower($headers['transfer-encoding']);
  669.  
  670.   if ($encoding != 'chunked') {
  671.     throw new Exception("Unsupported transfer-encoding: $encoding");
  672.   }
  673.  
  674.   while (!$connection->eof()) {
  675.     $chunk = $connection->readLine();
  676.  
  677.     if (!preg_match('/^[a-fA-F0-9]+(?=;|\r\n)/', $chunk, $matches)) {
  678.       throw new Exception('Invalid chunk');
  679.     }
  680.  
  681.     $size = hexdec($matches[0]);
  682.  
  683.     if (!$size) {
  684.       $connection->readLine();
  685.       break;
  686.     }
  687.  
  688.     $content .= $connection->read($size);
  689.     $connection->readLine();
  690.   }
  691. } else {
  692.   if (isset($headers['content-length'])) {
  693.     if (!preg_match('/^(0|[1-9]\d*)$/', $headers['content-length'])) {
  694.       throw new Exception('Invalid content-length');
  695.     }
  696.  
  697.     // читаем количество байт указанных в заголовке
  698.     $length = intval($headers['content-length']);
  699.  
  700.     if ($length) {
  701.       $content = $connection->read($length);
  702.     }
  703.   } else {
  704.     // Если заголовок Content-Length не установлен, клиент должен читать из
  705.     // сокета, пока не будет разорвано соединение
  706.     while (!$connection->eof()) {
  707.       $content .= $connection->read();
  708.     }
  709.   }
  710.  
  711.   if (isset($headers['content-encoding'])) {
  712.     $encoding = strtolower($headers['content-encoding']);
  713.     $decoded = decode($content, $encoding);
  714.  
  715.     if ($decoded === false) {
  716.       throw new Exception("Unable to decode content with content-encoding: $encoding");
  717.     }
  718.  
  719.     $content = $decoded;
  720.   }
  721. }
  722.  
  723. print_r($connection->getStreamMetaData());
  724.  
  725. $connection->close();
  726.  
  727. file_put_contents('chunked.jpeg', $content);
  728.  
  729. // echo($content);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement