wp/wp-includes/SimplePie/src/File.php
changeset 22 8c2e4d02f4ef
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * SimplePie
       
     5  *
       
     6  * A PHP-Based RSS and Atom Feed Framework.
       
     7  * Takes the hard work out of managing a complete RSS/Atom solution.
       
     8  *
       
     9  * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors
       
    10  * All rights reserved.
       
    11  *
       
    12  * Redistribution and use in source and binary forms, with or without modification, are
       
    13  * permitted provided that the following conditions are met:
       
    14  *
       
    15  * 	* Redistributions of source code must retain the above copyright notice, this list of
       
    16  * 	  conditions and the following disclaimer.
       
    17  *
       
    18  * 	* Redistributions in binary form must reproduce the above copyright notice, this list
       
    19  * 	  of conditions and the following disclaimer in the documentation and/or other materials
       
    20  * 	  provided with the distribution.
       
    21  *
       
    22  * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
       
    23  * 	  to endorse or promote products derived from this software without specific prior
       
    24  * 	  written permission.
       
    25  *
       
    26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
       
    27  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
       
    28  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
       
    29  * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
       
    31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
       
    32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       
    33  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
       
    34  * POSSIBILITY OF SUCH DAMAGE.
       
    35  *
       
    36  * @package SimplePie
       
    37  * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue
       
    38  * @author Ryan Parman
       
    39  * @author Sam Sneddon
       
    40  * @author Ryan McCue
       
    41  * @link http://simplepie.org/ SimplePie
       
    42  * @license http://www.opensource.org/licenses/bsd-license.php BSD License
       
    43  */
       
    44 
       
    45 namespace SimplePie;
       
    46 
       
    47 /**
       
    48  * Used for fetching remote files and reading local files
       
    49  *
       
    50  * Supports HTTP 1.0 via cURL or fsockopen, with spotty HTTP 1.1 support
       
    51  *
       
    52  * This class can be overloaded with {@see \SimplePie\SimplePie::set_file_class()}
       
    53  *
       
    54  * @package SimplePie
       
    55  * @subpackage HTTP
       
    56  * @todo Move to properly supporting RFC2616 (HTTP/1.1)
       
    57  */
       
    58 class File
       
    59 {
       
    60     public $url;
       
    61     public $useragent;
       
    62     public $success = true;
       
    63     public $headers = [];
       
    64     public $body;
       
    65     public $status_code = 0;
       
    66     public $redirects = 0;
       
    67     public $error;
       
    68     public $method = \SimplePie\SimplePie::FILE_SOURCE_NONE;
       
    69     public $permanent_url;
       
    70 
       
    71     public function __construct($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false, $curl_options = [])
       
    72     {
       
    73         if (class_exists('idna_convert')) {
       
    74             $idn = new \idna_convert();
       
    75             $parsed = \SimplePie\Misc::parse_url($url);
       
    76             $url = \SimplePie\Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], null);
       
    77         }
       
    78         $this->url = $url;
       
    79         $this->permanent_url = $url;
       
    80         $this->useragent = $useragent;
       
    81         if (preg_match('/^http(s)?:\/\//i', $url)) {
       
    82             if ($useragent === null) {
       
    83                 $useragent = ini_get('user_agent');
       
    84                 $this->useragent = $useragent;
       
    85             }
       
    86             if (!is_array($headers)) {
       
    87                 $headers = [];
       
    88             }
       
    89             if (!$force_fsockopen && function_exists('curl_exec')) {
       
    90                 $this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_CURL;
       
    91                 $fp = curl_init();
       
    92                 $headers2 = [];
       
    93                 foreach ($headers as $key => $value) {
       
    94                     $headers2[] = "$key: $value";
       
    95                 }
       
    96                 if (version_compare(\SimplePie\Misc::get_curl_version(), '7.10.5', '>=')) {
       
    97                     curl_setopt($fp, CURLOPT_ENCODING, '');
       
    98                 }
       
    99                 curl_setopt($fp, CURLOPT_URL, $url);
       
   100                 curl_setopt($fp, CURLOPT_HEADER, 1);
       
   101                 curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
       
   102                 curl_setopt($fp, CURLOPT_FAILONERROR, 1);
       
   103                 curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
       
   104                 curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
       
   105                 curl_setopt($fp, CURLOPT_REFERER, \SimplePie\Misc::url_remove_credentials($url));
       
   106                 curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
       
   107                 curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
       
   108                 foreach ($curl_options as $curl_param => $curl_value) {
       
   109                     curl_setopt($fp, $curl_param, $curl_value);
       
   110                 }
       
   111 
       
   112                 $this->headers = curl_exec($fp);
       
   113                 if (curl_errno($fp) === 23 || curl_errno($fp) === 61) {
       
   114                     curl_setopt($fp, CURLOPT_ENCODING, 'none');
       
   115                     $this->headers = curl_exec($fp);
       
   116                 }
       
   117                 $this->status_code = curl_getinfo($fp, CURLINFO_HTTP_CODE);
       
   118                 if (curl_errno($fp)) {
       
   119                     $this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
       
   120                     $this->success = false;
       
   121                 } else {
       
   122                     // Use the updated url provided by curl_getinfo after any redirects.
       
   123                     if ($info = curl_getinfo($fp)) {
       
   124                         $this->url = $info['url'];
       
   125                     }
       
   126                     curl_close($fp);
       
   127                     $this->headers = \SimplePie\HTTP\Parser::prepareHeaders($this->headers, $info['redirect_count'] + 1);
       
   128                     $parser = new \SimplePie\HTTP\Parser($this->headers);
       
   129                     if ($parser->parse()) {
       
   130                         $this->headers = $parser->headers;
       
   131                         $this->body = trim($parser->body);
       
   132                         $this->status_code = $parser->status_code;
       
   133                         if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) {
       
   134                             $this->redirects++;
       
   135                             $location = \SimplePie\Misc::absolutize_url($this->headers['location'], $url);
       
   136                             $previousStatusCode = $this->status_code;
       
   137                             $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen, $curl_options);
       
   138                             $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
       
   139                             return;
       
   140                         }
       
   141                     }
       
   142                 }
       
   143             } else {
       
   144                 $this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_FSOCKOPEN;
       
   145                 $url_parts = parse_url($url);
       
   146                 $socket_host = $url_parts['host'];
       
   147                 if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) === 'https') {
       
   148                     $socket_host = "ssl://$url_parts[host]";
       
   149                     $url_parts['port'] = 443;
       
   150                 }
       
   151                 if (!isset($url_parts['port'])) {
       
   152                     $url_parts['port'] = 80;
       
   153                 }
       
   154                 $fp = @fsockopen($socket_host, $url_parts['port'], $errno, $errstr, $timeout);
       
   155                 if (!$fp) {
       
   156                     $this->error = 'fsockopen error: ' . $errstr;
       
   157                     $this->success = false;
       
   158                 } else {
       
   159                     stream_set_timeout($fp, $timeout);
       
   160                     if (isset($url_parts['path'])) {
       
   161                         if (isset($url_parts['query'])) {
       
   162                             $get = "$url_parts[path]?$url_parts[query]";
       
   163                         } else {
       
   164                             $get = $url_parts['path'];
       
   165                         }
       
   166                     } else {
       
   167                         $get = '/';
       
   168                     }
       
   169                     $out = "GET $get HTTP/1.1\r\n";
       
   170                     $out .= "Host: $url_parts[host]\r\n";
       
   171                     $out .= "User-Agent: $useragent\r\n";
       
   172                     if (extension_loaded('zlib')) {
       
   173                         $out .= "Accept-Encoding: x-gzip,gzip,deflate\r\n";
       
   174                     }
       
   175 
       
   176                     if (isset($url_parts['user']) && isset($url_parts['pass'])) {
       
   177                         $out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
       
   178                     }
       
   179                     foreach ($headers as $key => $value) {
       
   180                         $out .= "$key: $value\r\n";
       
   181                     }
       
   182                     $out .= "Connection: Close\r\n\r\n";
       
   183                     fwrite($fp, $out);
       
   184 
       
   185                     $info = stream_get_meta_data($fp);
       
   186 
       
   187                     $this->headers = '';
       
   188                     while (!$info['eof'] && !$info['timed_out']) {
       
   189                         $this->headers .= fread($fp, 1160);
       
   190                         $info = stream_get_meta_data($fp);
       
   191                     }
       
   192                     if (!$info['timed_out']) {
       
   193                         $parser = new \SimplePie\HTTP\Parser($this->headers);
       
   194                         if ($parser->parse()) {
       
   195                             $this->headers = $parser->headers;
       
   196                             $this->body = $parser->body;
       
   197                             $this->status_code = $parser->status_code;
       
   198                             if ((in_array($this->status_code, [300, 301, 302, 303, 307]) || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects) {
       
   199                                 $this->redirects++;
       
   200                                 $location = \SimplePie\Misc::absolutize_url($this->headers['location'], $url);
       
   201                                 $previousStatusCode = $this->status_code;
       
   202                                 $this->__construct($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen, $curl_options);
       
   203                                 $this->permanent_url = ($previousStatusCode == 301) ? $location : $url;
       
   204                                 return;
       
   205                             }
       
   206                             if (isset($this->headers['content-encoding'])) {
       
   207                                 // Hey, we act dumb elsewhere, so let's do that here too
       
   208                                 switch (strtolower(trim($this->headers['content-encoding'], "\x09\x0A\x0D\x20"))) {
       
   209                                     case 'gzip':
       
   210                                     case 'x-gzip':
       
   211                                         $decoder = new \SimplePie\Gzdecode($this->body);
       
   212                                         if (!$decoder->parse()) {
       
   213                                             $this->error = 'Unable to decode HTTP "gzip" stream';
       
   214                                             $this->success = false;
       
   215                                         } else {
       
   216                                             $this->body = trim($decoder->data);
       
   217                                         }
       
   218                                         break;
       
   219 
       
   220                                     case 'deflate':
       
   221                                         if (($decompressed = gzinflate($this->body)) !== false) {
       
   222                                             $this->body = $decompressed;
       
   223                                         } elseif (($decompressed = gzuncompress($this->body)) !== false) {
       
   224                                             $this->body = $decompressed;
       
   225                                         } elseif (function_exists('gzdecode') && ($decompressed = gzdecode($this->body)) !== false) {
       
   226                                             $this->body = $decompressed;
       
   227                                         } else {
       
   228                                             $this->error = 'Unable to decode HTTP "deflate" stream';
       
   229                                             $this->success = false;
       
   230                                         }
       
   231                                         break;
       
   232 
       
   233                                     default:
       
   234                                         $this->error = 'Unknown content coding';
       
   235                                         $this->success = false;
       
   236                                 }
       
   237                             }
       
   238                         }
       
   239                     } else {
       
   240                         $this->error = 'fsocket timed out';
       
   241                         $this->success = false;
       
   242                     }
       
   243                     fclose($fp);
       
   244                 }
       
   245             }
       
   246         } else {
       
   247             $this->method = \SimplePie\SimplePie::FILE_SOURCE_LOCAL | \SimplePie\SimplePie::FILE_SOURCE_FILE_GET_CONTENTS;
       
   248             if (empty($url) || !($this->body = trim(file_get_contents($url)))) {
       
   249                 $this->error = 'file_get_contents could not read the file';
       
   250                 $this->success = false;
       
   251             }
       
   252         }
       
   253     }
       
   254 }
       
   255 
       
   256 class_alias('SimplePie\File', 'SimplePie_File');