Differences Between: [Versions 310 and 311] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [Versions 39 and 311]
1 <?php 2 /** 3 * SimplePie 4 * 5 * A PHP-Based RSS and Atom Feed Framework. 6 * Takes the hard work out of managing a complete RSS/Atom solution. 7 * 8 * Copyright (c) 2004-2016, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without modification, are 12 * permitted provided that the following conditions are met: 13 * 14 * * Redistributions of source code must retain the above copyright notice, this list of 15 * conditions and the following disclaimer. 16 * 17 * * Redistributions in binary form must reproduce the above copyright notice, this list 18 * of conditions and the following disclaimer in the documentation and/or other materials 19 * provided with the distribution. 20 * 21 * * Neither the name of the SimplePie Team nor the names of its contributors may be used 22 * to endorse or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 26 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 28 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 * POSSIBILITY OF SUCH DAMAGE. 34 * 35 * @package SimplePie 36 * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue 37 * @author Ryan Parman 38 * @author Sam Sneddon 39 * @author Ryan McCue 40 * @link http://simplepie.org/ SimplePie 41 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 42 */ 43 44 45 /** 46 * Content-type sniffing 47 * 48 * Based on the rules in http://tools.ietf.org/html/draft-abarth-mime-sniff-06 49 * 50 * This is used since we can't always trust Content-Type headers, and is based 51 * upon the HTML5 parsing rules. 52 * 53 * 54 * This class can be overloaded with {@see SimplePie::set_content_type_sniffer_class()} 55 * 56 * @package SimplePie 57 * @subpackage HTTP 58 */ 59 class SimplePie_Content_Type_Sniffer 60 { 61 /** 62 * File object 63 * 64 * @var SimplePie_File 65 */ 66 var $file; 67 68 /** 69 * Create an instance of the class with the input file 70 * 71 * @param SimplePie_Content_Type_Sniffer $file Input file 72 */ 73 public function __construct($file) 74 { 75 $this->file = $file; 76 } 77 78 /** 79 * Get the Content-Type of the specified file 80 * 81 * @return string Actual Content-Type 82 */ 83 public function get_type() 84 { 85 if (isset($this->file->headers['content-type'])) 86 { 87 if (!isset($this->file->headers['content-encoding']) 88 && ($this->file->headers['content-type'] === 'text/plain' 89 || $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1' 90 || $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1' 91 || $this->file->headers['content-type'] === 'text/plain; charset=UTF-8')) 92 { 93 return $this->text_or_binary(); 94 } 95 96 if (($pos = strpos($this->file->headers['content-type'], ';')) !== false) 97 { 98 $official = substr($this->file->headers['content-type'], 0, $pos); 99 } 100 else 101 { 102 $official = $this->file->headers['content-type']; 103 } 104 $official = trim(strtolower($official)); 105 106 if ($official === 'unknown/unknown' 107 || $official === 'application/unknown') 108 { 109 return $this->unknown(); 110 } 111 elseif (substr($official, -4) === '+xml' 112 || $official === 'text/xml' 113 || $official === 'application/xml') 114 { 115 return $official; 116 } 117 elseif (substr($official, 0, 6) === 'image/') 118 { 119 if ($return = $this->image()) 120 { 121 return $return; 122 } 123 124 return $official; 125 } 126 elseif ($official === 'text/html') 127 { 128 return $this->feed_or_html(); 129 } 130 131 return $official; 132 } 133 134 return $this->unknown(); 135 } 136 137 /** 138 * Sniff text or binary 139 * 140 * @return string Actual Content-Type 141 */ 142 public function text_or_binary() 143 { 144 if (substr($this->file->body, 0, 2) === "\xFE\xFF" 145 || substr($this->file->body, 0, 2) === "\xFF\xFE" 146 || substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF" 147 || substr($this->file->body, 0, 3) === "\xEF\xBB\xBF") 148 { 149 return 'text/plain'; 150 } 151 elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body)) 152 { 153 return 'application/octet-stream'; 154 } 155 156 return 'text/plain'; 157 } 158 159 /** 160 * Sniff unknown 161 * 162 * @return string Actual Content-Type 163 */ 164 public function unknown() 165 { 166 $ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20"); 167 if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html' 168 || strtolower(substr($this->file->body, $ws, 5)) === '<html' 169 || strtolower(substr($this->file->body, $ws, 7)) === '<script') 170 { 171 return 'text/html'; 172 } 173 elseif (substr($this->file->body, 0, 5) === '%PDF-') 174 { 175 return 'application/pdf'; 176 } 177 elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-') 178 { 179 return 'application/postscript'; 180 } 181 elseif (substr($this->file->body, 0, 6) === 'GIF87a' 182 || substr($this->file->body, 0, 6) === 'GIF89a') 183 { 184 return 'image/gif'; 185 } 186 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 187 { 188 return 'image/png'; 189 } 190 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 191 { 192 return 'image/jpeg'; 193 } 194 elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 195 { 196 return 'image/bmp'; 197 } 198 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 199 { 200 return 'image/vnd.microsoft.icon'; 201 } 202 203 return $this->text_or_binary(); 204 } 205 206 /** 207 * Sniff images 208 * 209 * @return string Actual Content-Type 210 */ 211 public function image() 212 { 213 if (substr($this->file->body, 0, 6) === 'GIF87a' 214 || substr($this->file->body, 0, 6) === 'GIF89a') 215 { 216 return 'image/gif'; 217 } 218 elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") 219 { 220 return 'image/png'; 221 } 222 elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF") 223 { 224 return 'image/jpeg'; 225 } 226 elseif (substr($this->file->body, 0, 2) === "\x42\x4D") 227 { 228 return 'image/bmp'; 229 } 230 elseif (substr($this->file->body, 0, 4) === "\x00\x00\x01\x00") 231 { 232 return 'image/vnd.microsoft.icon'; 233 } 234 235 return false; 236 } 237 238 /** 239 * Sniff HTML 240 * 241 * @return string Actual Content-Type 242 */ 243 public function feed_or_html() 244 { 245 $len = strlen($this->file->body); 246 $pos = strspn($this->file->body, "\x09\x0A\x0D\x20\xEF\xBB\xBF"); 247 248 while ($pos < $len) 249 { 250 switch ($this->file->body[$pos]) 251 { 252 case "\x09": 253 case "\x0A": 254 case "\x0D": 255 case "\x20": 256 $pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos); 257 continue 2; 258 259 case '<': 260 $pos++; 261 break; 262 263 default: 264 return 'text/html'; 265 } 266 267 if (substr($this->file->body, $pos, 3) === '!--') 268 { 269 $pos += 3; 270 if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false) 271 { 272 $pos += 3; 273 } 274 else 275 { 276 return 'text/html'; 277 } 278 } 279 elseif (substr($this->file->body, $pos, 1) === '!') 280 { 281 if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false) 282 { 283 $pos++; 284 } 285 else 286 { 287 return 'text/html'; 288 } 289 } 290 elseif (substr($this->file->body, $pos, 1) === '?') 291 { 292 if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false) 293 { 294 $pos += 2; 295 } 296 else 297 { 298 return 'text/html'; 299 } 300 } 301 elseif (substr($this->file->body, $pos, 3) === 'rss' 302 || substr($this->file->body, $pos, 7) === 'rdf:RDF') 303 { 304 return 'application/rss+xml'; 305 } 306 elseif (substr($this->file->body, $pos, 4) === 'feed') 307 { 308 return 'application/atom+xml'; 309 } 310 else 311 { 312 return 'text/html'; 313 } 314 } 315 316 return 'text/html'; 317 } 318 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body