| [ Index ] | PHP Cross Reference of MediaWiki-1.24.0 | 
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * PHP script to stream out an image thumbnail. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 * http://www.gnu.org/copyleft/gpl.html 19 * 20 * @file 21 * @ingroup Media 22 */ 23 24 define( 'MW_NO_OUTPUT_COMPRESSION', 1 ); 25 require __DIR__ . '/includes/WebStart.php'; 26 27 // Don't use fancy MIME detection, just check the file extension for jpg/gif/png 28 $wgTrivialMimeDetection = true; 29 30 if ( defined( 'THUMB_HANDLER' ) ) { 31 // Called from thumb_handler.php via 404; extract params from the URI... 32 wfThumbHandle404(); 33 } else { 34 // Called directly, use $_GET params 35 wfThumbHandleRequest(); 36 } 37 38 wfLogProfilingData(); 39 // Commit and close up! 40 $factory = wfGetLBFactory(); 41 $factory->commitMasterChanges(); 42 $factory->shutdown(); 43 44 //-------------------------------------------------------------------------- 45 46 /** 47 * Handle a thumbnail request via query parameters 48 * 49 * @return void 50 */ 51 function wfThumbHandleRequest() { 52 $params = get_magic_quotes_gpc() 53 ? array_map( 'stripslashes', $_GET ) 54 : $_GET; 55 56 wfStreamThumb( $params ); // stream the thumbnail 57 } 58 59 /** 60 * Handle a thumbnail request via thumbnail file URL 61 * 62 * @return void 63 */ 64 function wfThumbHandle404() { 65 global $wgArticlePath; 66 67 # Set action base paths so that WebRequest::getPathInfo() 68 # recognizes the "X" as the 'title' in ../thumb_handler.php/X urls. 69 # Note: If Custom per-extension repo paths are set, this may break. 70 $repo = RepoGroup::singleton()->getLocalRepo(); 71 $oldArticlePath = $wgArticlePath; 72 $wgArticlePath = $repo->getZoneUrl( 'thumb' ) . '/$1'; 73 74 $matches = WebRequest::getPathInfo(); 75 76 $wgArticlePath = $oldArticlePath; 77 78 if ( !isset( $matches['title'] ) ) { 79 wfThumbError( 404, 'Could not determine the name of the requested thumbnail.' ); 80 return; 81 } 82 83 $params = wfExtractThumbRequestInfo( $matches['title'] ); // basic wiki URL param extracting 84 if ( $params == null ) { 85 wfThumbError( 400, 'The specified thumbnail parameters are not recognized.' ); 86 return; 87 } 88 89 wfStreamThumb( $params ); // stream the thumbnail 90 } 91 92 /** 93 * Stream a thumbnail specified by parameters 94 * 95 * @param array $params List of thumbnailing parameters. In addition to parameters 96 * passed to the MediaHandler, this may also includes the keys: 97 * f (for filename), archived (if archived file), temp (if temp file), 98 * w (alias for width), p (alias for page), r (ignored; historical), 99 * rel404 (path for render on 404 to verify hash path correct), 100 * thumbName (thumbnail name to potentially extract more parameters from 101 * e.g. 'lossy-page1-120px-Foo.tiff' would add page, lossy and width 102 * to the parameters) 103 * @return void 104 */ 105 function wfStreamThumb( array $params ) { 106 global $wgVaryOnXFP; 107 108 $section = new ProfileSection( __METHOD__ ); 109 110 $headers = array(); // HTTP headers to send 111 112 $fileName = isset( $params['f'] ) ? $params['f'] : ''; 113 114 // Backwards compatibility parameters 115 if ( isset( $params['w'] ) ) { 116 $params['width'] = $params['w']; 117 unset( $params['w'] ); 118 } 119 if ( isset( $params['width'] ) && substr( $params['width'], -2 ) == 'px' ) { 120 // strip the px (pixel) suffix, if found 121 $params['width'] = substr( $params['width'], 0, -2 ); 122 } 123 if ( isset( $params['p'] ) ) { 124 $params['page'] = $params['p']; 125 } 126 127 // Is this a thumb of an archived file? 128 $isOld = ( isset( $params['archived'] ) && $params['archived'] ); 129 unset( $params['archived'] ); // handlers don't care 130 131 // Is this a thumb of a temp file? 132 $isTemp = ( isset( $params['temp'] ) && $params['temp'] ); 133 unset( $params['temp'] ); // handlers don't care 134 135 // Some basic input validation 136 $fileName = strtr( $fileName, '\\/', '__' ); 137 138 // Actually fetch the image. Method depends on whether it is archived or not. 139 if ( $isTemp ) { 140 $repo = RepoGroup::singleton()->getLocalRepo()->getTempRepo(); 141 $img = new UnregisteredLocalFile( null, $repo, 142 # Temp files are hashed based on the name without the timestamp. 143 # The thumbnails will be hashed based on the entire name however. 144 # @todo fix this convention to actually be reasonable. 145 $repo->getZonePath( 'public' ) . '/' . $repo->getTempHashPath( $fileName ) . $fileName 146 ); 147 } elseif ( $isOld ) { 148 // Format is <timestamp>!<name> 149 $bits = explode( '!', $fileName, 2 ); 150 if ( count( $bits ) != 2 ) { 151 wfThumbError( 404, wfMessage( 'badtitletext' )->text() ); 152 return; 153 } 154 $title = Title::makeTitleSafe( NS_FILE, $bits[1] ); 155 if ( !$title ) { 156 wfThumbError( 404, wfMessage( 'badtitletext' )->text() ); 157 return; 158 } 159 $img = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $fileName ); 160 } else { 161 $img = wfLocalFile( $fileName ); 162 } 163 164 // Check the source file title 165 if ( !$img ) { 166 wfThumbError( 404, wfMessage( 'badtitletext' )->text() ); 167 return; 168 } 169 170 // Check permissions if there are read restrictions 171 $varyHeader = array(); 172 if ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) ) { 173 if ( !$img->getTitle() || !$img->getTitle()->userCan( 'read' ) ) { 174 wfThumbError( 403, 'Access denied. You do not have permission to access ' . 175 'the source file.' ); 176 return; 177 } 178 $headers[] = 'Cache-Control: private'; 179 $varyHeader[] = 'Cookie'; 180 } 181 182 // Check if the file is hidden 183 if ( $img->isDeleted( File::DELETED_FILE ) ) { 184 wfThumbError( 404, "The source file '$fileName' does not exist." ); 185 return; 186 } 187 188 // Do rendering parameters extraction from thumbnail name. 189 if ( isset( $params['thumbName'] ) ) { 190 $params = wfExtractThumbParams( $img, $params ); 191 } 192 if ( $params == null ) { 193 wfThumbError( 400, 'The specified thumbnail parameters are not recognized.' ); 194 return; 195 } 196 197 // Check the source file storage path 198 if ( !$img->exists() ) { 199 $redirectedLocation = false; 200 if ( !$isTemp ) { 201 // Check for file redirect 202 // Since redirects are associated with pages, not versions of files, 203 // we look for the most current version to see if its a redirect. 204 $possRedirFile = RepoGroup::singleton()->getLocalRepo()->findFile( $img->getName() ); 205 if ( $possRedirFile && !is_null( $possRedirFile->getRedirected() ) ) { 206 $redirTarget = $possRedirFile->getName(); 207 $targetFile = wfLocalFile( Title::makeTitleSafe( NS_FILE, $redirTarget ) ); 208 if ( $targetFile->exists() ) { 209 $newThumbName = $targetFile->thumbName( $params ); 210 if ( $isOld ) { 211 $newThumbUrl = $targetFile->getArchiveThumbUrl( 212 $bits[0] . '!' . $targetFile->getName(), $newThumbName ); 213 } else { 214 $newThumbUrl = $targetFile->getThumbUrl( $newThumbName ); 215 } 216 $redirectedLocation = wfExpandUrl( $newThumbUrl, PROTO_CURRENT ); 217 } 218 } 219 } 220 221 if ( $redirectedLocation ) { 222 // File has been moved. Give redirect. 223 $response = RequestContext::getMain()->getRequest()->response(); 224 $response->header( "HTTP/1.1 302 " . HttpStatus::getMessage( 302 ) ); 225 $response->header( 'Location: ' . $redirectedLocation ); 226 $response->header( 'Expires: ' . 227 gmdate( 'D, d M Y H:i:s', time() + 12 * 3600 ) . ' GMT' ); 228 if ( $wgVaryOnXFP ) { 229 $varyHeader[] = 'X-Forwarded-Proto'; 230 } 231 if ( count( $varyHeader ) ) { 232 $response->header( 'Vary: ' . implode( ', ', $varyHeader ) ); 233 } 234 return; 235 } 236 237 // If its not a redirect that has a target as a local file, give 404. 238 wfThumbError( 404, "The source file '$fileName' does not exist." ); 239 return; 240 } elseif ( $img->getPath() === false ) { 241 wfThumbError( 500, "The source file '$fileName' is not locally accessible." ); 242 return; 243 } 244 245 // Check IMS against the source file 246 // This means that clients can keep a cached copy even after it has been deleted on the server 247 if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { 248 // Fix IE brokenness 249 $imsString = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] ); 250 // Calculate time 251 wfSuppressWarnings(); 252 $imsUnix = strtotime( $imsString ); 253 wfRestoreWarnings(); 254 if ( wfTimestamp( TS_UNIX, $img->getTimestamp() ) <= $imsUnix ) { 255 header( 'HTTP/1.1 304 Not Modified' ); 256 return; 257 } 258 } 259 260 $rel404 = isset( $params['rel404'] ) ? $params['rel404'] : null; 261 unset( $params['r'] ); // ignore 'r' because we unconditionally pass File::RENDER 262 unset( $params['f'] ); // We're done with 'f' parameter. 263 unset( $params['rel404'] ); // moved to $rel404 264 265 // Get the normalized thumbnail name from the parameters... 266 try { 267 $thumbName = $img->thumbName( $params ); 268 if ( !strlen( $thumbName ) ) { // invalid params? 269 wfThumbError( 400, 'The specified thumbnail parameters are not valid.' ); 270 return; 271 } 272 $thumbName2 = $img->thumbName( $params, File::THUMB_FULL_NAME ); // b/c; "long" style 273 } catch ( MWException $e ) { 274 wfThumbError( 500, $e->getHTML() ); 275 return; 276 } 277 278 // For 404 handled thumbnails, we only use the the base name of the URI 279 // for the thumb params and the parent directory for the source file name. 280 // Check that the zone relative path matches up so squid caches won't pick 281 // up thumbs that would not be purged on source file deletion (bug 34231). 282 if ( $rel404 !== null ) { // thumbnail was handled via 404 283 if ( rawurldecode( $rel404 ) === $img->getThumbRel( $thumbName ) ) { 284 // Request for the canonical thumbnail name 285 } elseif ( rawurldecode( $rel404 ) === $img->getThumbRel( $thumbName2 ) ) { 286 // Request for the "long" thumbnail name; redirect to canonical name 287 $response = RequestContext::getMain()->getRequest()->response(); 288 $response->header( "HTTP/1.1 301 " . HttpStatus::getMessage( 301 ) ); 289 $response->header( 'Location: ' . 290 wfExpandUrl( $img->getThumbUrl( $thumbName ), PROTO_CURRENT ) ); 291 $response->header( 'Expires: ' . 292 gmdate( 'D, d M Y H:i:s', time() + 7 * 86400 ) . ' GMT' ); 293 if ( $wgVaryOnXFP ) { 294 $varyHeader[] = 'X-Forwarded-Proto'; 295 } 296 if ( count( $varyHeader ) ) { 297 $response->header( 'Vary: ' . implode( ', ', $varyHeader ) ); 298 } 299 return; 300 } else { 301 wfThumbError( 404, "The given path of the specified thumbnail is incorrect; 302 expected '" . $img->getThumbRel( $thumbName ) . "' but got '" . 303 rawurldecode( $rel404 ) . "'." ); 304 return; 305 } 306 } 307 308 $dispositionType = isset( $params['download'] ) ? 'attachment' : 'inline'; 309 310 // Suggest a good name for users downloading this thumbnail 311 $headers[] = "Content-Disposition: {$img->getThumbDisposition( $thumbName, $dispositionType )}"; 312 313 if ( count( $varyHeader ) ) { 314 $headers[] = 'Vary: ' . implode( ', ', $varyHeader ); 315 } 316 317 // Stream the file if it exists already... 318 $thumbPath = $img->getThumbPath( $thumbName ); 319 if ( $img->getRepo()->fileExists( $thumbPath ) ) { 320 $img->getRepo()->streamFile( $thumbPath, $headers ); 321 return; 322 } 323 324 $user = RequestContext::getMain()->getUser(); 325 if ( !wfThumbIsStandard( $img, $params ) && $user->pingLimiter( 'renderfile-nonstandard' ) ) { 326 wfThumbError( 500, wfMessage( 'actionthrottledtext' ) ); 327 return; 328 } elseif ( $user->pingLimiter( 'renderfile' ) ) { 329 wfThumbError( 500, wfMessage( 'actionthrottledtext' ) ); 330 return; 331 } 332 333 // Actually generate a new thumbnail 334 list( $thumb, $errorMsg ) = wfGenerateThumbnail( $img, $params, $thumbName, $thumbPath ); 335 336 // Check for thumbnail generation errors... 337 $msg = wfMessage( 'thumbnail_error' ); 338 if ( !$thumb ) { 339 $errorMsg = $errorMsg ?: $msg->rawParams( 'File::transform() returned false' )->escaped(); 340 } elseif ( $thumb->isError() ) { 341 $errorMsg = $thumb->getHtmlMsg(); 342 } elseif ( !$thumb->hasFile() ) { 343 $errorMsg = $msg->rawParams( 'No path supplied in thumbnail object' )->escaped(); 344 } elseif ( $thumb->fileIsSource() ) { 345 $errorMsg = $msg-> 346 rawParams( 'Image was not scaled, is the requested width bigger than the source?' )->escaped(); 347 } 348 349 if ( $errorMsg !== false ) { 350 wfThumbError( 500, $errorMsg ); 351 } else { 352 // Stream the file if there were no errors 353 $thumb->streamFile( $headers ); 354 } 355 } 356 357 /** 358 * Actually try to generate a new thumbnail 359 * 360 * @param File $file 361 * @param array $params 362 * @param string $thumbName 363 * @param string $thumbPath 364 * @return array (MediaTransformOutput|bool, string|bool error message HTML) 365 */ 366 function wfGenerateThumbnail( File $file, array $params, $thumbName, $thumbPath ) { 367 global $wgMemc, $wgAttemptFailureEpoch; 368 369 $key = wfMemcKey( 'attempt-failures', $wgAttemptFailureEpoch, 370 $file->getRepo()->getName(), $file->getSha1(), md5( $thumbName ) ); 371 372 // Check if this file keeps failing to render 373 if ( $wgMemc->get( $key ) >= 4 ) { 374 return array( false, wfMessage( 'thumbnail_image-failure-limit', 4 ) ); 375 } 376 377 $done = false; 378 // Record failures on PHP fatals in addition to caching exceptions 379 register_shutdown_function( function () use ( &$done, $key ) { 380 if ( !$done ) { // transform() gave a fatal 381 global $wgMemc; 382 // Randomize TTL to reduce stampedes 383 $wgMemc->incrWithInit( $key, 3600 + mt_rand( 0, 300 ) ); 384 } 385 } ); 386 387 $thumb = false; 388 $errorHtml = false; 389 390 // guard thumbnail rendering with PoolCounter to avoid stampedes 391 // expensive files use a separate PoolCounter config so it is possible 392 // to set up a global limit on them 393 if ( $file->isExpensiveToThumbnail() ) { 394 $poolCounterType = 'FileRenderExpensive'; 395 } else { 396 $poolCounterType = 'FileRender'; 397 } 398 399 // Thumbnail isn't already there, so create the new thumbnail... 400 try { 401 $work = new PoolCounterWorkViaCallback( $poolCounterType, sha1( $file->getName() ), 402 array( 403 'doWork' => function () use ( $file, $params ) { 404 return $file->transform( $params, File::RENDER_NOW ); 405 }, 406 'getCachedWork' => function () use ( $file, $params, $thumbPath ) { 407 // If the worker that finished made this thumbnail then use it. 408 // Otherwise, it probably made a different thumbnail for this file. 409 return $file->getRepo()->fileExists( $thumbPath ) 410 ? $file->transform( $params, File::RENDER_NOW ) 411 : false; // retry once more in exclusive mode 412 }, 413 'fallback' => function () { 414 return wfMessage( 'generic-pool-error' )->parse(); 415 }, 416 'error' => function ( $status ) { 417 return $status->getHTML(); 418 } 419 ) 420 ); 421 $result = $work->execute(); 422 if ( $result instanceof MediaTransformOutput ) { 423 $thumb = $result; 424 } elseif ( is_string( $result ) ) { // error 425 $errorHtml = $result; 426 } 427 } catch ( Exception $e ) { 428 // Tried to select a page on a non-paged file? 429 } 430 431 $done = true; // no PHP fatal occured 432 433 if ( !$thumb || $thumb->isError() ) { 434 // Randomize TTL to reduce stampedes 435 $wgMemc->incrWithInit( $key, 3600 + mt_rand( 0, 300 ) ); 436 } 437 438 return array( $thumb, $errorHtml ); 439 } 440 441 /** 442 * Returns true if this thumbnail is one that MediaWiki generates 443 * links to on file description pages and possibly parser output. 444 * 445 * $params is considered non-standard if they involve a non-standard 446 * width or any non-default parameters aside from width and page number. 447 * The number of possible files with standard parameters is far less than 448 * that of all combinations; rate-limiting for them can thus be more generious. 449 * 450 * @param File $file 451 * @param array $params 452 * @return bool 453 */ 454 function wfThumbIsStandard( File $file, array $params ) { 455 global $wgThumbLimits, $wgImageLimits; 456 457 $handler = $file->getHandler(); 458 if ( !$handler || !isset( $params['width'] ) ) { 459 return false; 460 } 461 462 $basicParams = array(); 463 if ( isset( $params['page'] ) ) { 464 $basicParams['page'] = $params['page']; 465 } 466 467 // Check if the width matches one of $wgThumbLimits 468 if ( in_array( $params['width'], $wgThumbLimits ) ) { 469 $normalParams = $basicParams + array( 'width' => $params['width'] ); 470 // Append any default values to the map (e.g. "lossy", "lossless", ...) 471 $handler->normaliseParams( $file, $normalParams ); 472 } else { 473 // If not, then check if the width matchs one of $wgImageLimits 474 $match = false; 475 foreach ( $wgImageLimits as $pair ) { 476 $normalParams = $basicParams + array( 'width' => $pair[0], 'height' => $pair[1] ); 477 // Decide whether the thumbnail should be scaled on width or height. 478 // Also append any default values to the map (e.g. "lossy", "lossless", ...) 479 $handler->normaliseParams( $file, $normalParams ); 480 // Check if this standard thumbnail size maps to the given width 481 if ( $normalParams['width'] == $params['width'] ) { 482 $match = true; 483 break; 484 } 485 } 486 if ( !$match ) { 487 return false; // not standard for description pages 488 } 489 } 490 491 // Check that the given values for non-page, non-width, params are just defaults 492 foreach ( $params as $key => $value ) { 493 if ( !isset( $normalParams[$key] ) || $normalParams[$key] != $value ) { 494 return false; 495 } 496 } 497 498 return true; 499 } 500 501 /** 502 * Convert pathinfo type parameter, into normal request parameters 503 * 504 * So for example, if the request was redirected from 505 * /w/images/thumb/a/ab/Foo.png/120px-Foo.png. The $thumbRel parameter 506 * of this function would be set to "a/ab/Foo.png/120px-Foo.png". 507 * This method is responsible for turning that into an array 508 * with the folowing keys: 509 * * f => the filename (Foo.png) 510 * * rel404 => the whole thing (a/ab/Foo.png/120px-Foo.png) 511 * * archived => 1 (If the request is for an archived thumb) 512 * * temp => 1 (If the file is in the "temporary" zone) 513 * * thumbName => the thumbnail name, including parameters (120px-Foo.png) 514 * 515 * Transform specific parameters are set later via wfExtractThumbParams(). 516 * 517 * @param string $thumbRel Thumbnail path relative to the thumb zone 518 * @return array|null Associative params array or null 519 */ 520 function wfExtractThumbRequestInfo( $thumbRel ) { 521 $repo = RepoGroup::singleton()->getLocalRepo(); 522 523 $hashDirReg = $subdirReg = ''; 524 $hashLevels = $repo->getHashLevels(); 525 for ( $i = 0; $i < $hashLevels; $i++ ) { 526 $subdirReg .= '[0-9a-f]'; 527 $hashDirReg .= "$subdirReg/"; 528 } 529 530 // Check if this is a thumbnail of an original in the local file repo 531 if ( preg_match( "!^((archive/)?$hashDirReg([^/]*)/([^/]*))$!", $thumbRel, $m ) ) { 532 list( /*all*/, $rel, $archOrTemp, $filename, $thumbname ) = $m; 533 // Check if this is a thumbnail of an temp file in the local file repo 534 } elseif ( preg_match( "!^(temp/)($hashDirReg([^/]*)/([^/]*))$!", $thumbRel, $m ) ) { 535 list( /*all*/, $archOrTemp, $rel, $filename, $thumbname ) = $m; 536 } else { 537 return null; // not a valid looking thumbnail request 538 } 539 540 $params = array( 'f' => $filename, 'rel404' => $rel ); 541 if ( $archOrTemp === 'archive/' ) { 542 $params['archived'] = 1; 543 } elseif ( $archOrTemp === 'temp/' ) { 544 $params['temp'] = 1; 545 } 546 547 $params['thumbName'] = $thumbname; 548 return $params; 549 } 550 551 /** 552 * Convert a thumbnail name (122px-foo.png) to parameters, using 553 * file handler. 554 * 555 * @param File $file File object for file in question 556 * @param array $params Array of parameters so far 557 * @return array Parameters array with more parameters 558 */ 559 function wfExtractThumbParams( $file, $params ) { 560 if ( !isset( $params['thumbName'] ) ) { 561 throw new MWException( "No thumbnail name passed to wfExtractThumbParams" ); 562 } 563 564 $thumbname = $params['thumbName']; 565 unset( $params['thumbName'] ); 566 567 // Do the hook first for older extensions that rely on it. 568 if ( !wfRunHooks( 'ExtractThumbParameters', array( $thumbname, &$params ) ) ) { 569 // Check hooks if parameters can be extracted 570 // Hooks return false if they manage to *resolve* the parameters 571 // This hook should be considered deprecated 572 wfDeprecated( 'ExtractThumbParameters', '1.22' ); 573 return $params; // valid thumbnail URL (via extension or config) 574 } 575 576 // FIXME: Files in the temp zone don't set a MIME type, which means 577 // they don't have a handler. Which means we can't parse the param 578 // string. However, not a big issue as what good is a param string 579 // if you have no handler to make use of the param string and 580 // actually generate the thumbnail. 581 $handler = $file->getHandler(); 582 583 // Based on UploadStash::parseKey 584 $fileNamePos = strrpos( $thumbname, $params['f'] ); 585 if ( $fileNamePos === false ) { 586 // Maybe using a short filename? (see FileRepo::nameForThumb) 587 $fileNamePos = strrpos( $thumbname, 'thumbnail' ); 588 } 589 590 if ( $handler && $fileNamePos !== false ) { 591 $paramString = substr( $thumbname, 0, $fileNamePos - 1 ); 592 $extraParams = $handler->parseParamString( $paramString ); 593 if ( $extraParams !== false ) { 594 return $params + $extraParams; 595 } 596 } 597 598 // As a last ditch fallback, use the traditional common parameters 599 if ( preg_match( '!^(page(\d*)-)*(\d*)px-[^/]*$!', $thumbname, $matches ) ) { 600 list( /* all */, $pagefull, $pagenum, $size ) = $matches; 601 $params['width'] = $size; 602 if ( $pagenum ) { 603 $params['page'] = $pagenum; 604 } 605 return $params; // valid thumbnail URL 606 } 607 return null; 608 } 609 610 /** 611 * Output a thumbnail generation error message 612 * 613 * @param int $status 614 * @param string $msg 615 * @return void 616 */ 617 function wfThumbError( $status, $msg ) { 618 global $wgShowHostnames; 619 620 header( 'Cache-Control: no-cache' ); 621 header( 'Content-Type: text/html; charset=utf-8' ); 622 if ( $status == 404 ) { 623 header( 'HTTP/1.1 404 Not found' ); 624 } elseif ( $status == 403 ) { 625 header( 'HTTP/1.1 403 Forbidden' ); 626 header( 'Vary: Cookie' ); 627 } else { 628 header( 'HTTP/1.1 500 Internal server error' ); 629 } 630 if ( $wgShowHostnames ) { 631 header( 'X-MW-Thumbnail-Renderer: ' . wfHostname() ); 632 $url = htmlspecialchars( isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : '' ); 633 $hostname = htmlspecialchars( wfHostname() ); 634 $debug = "<!-- $url -->\n<!-- $hostname -->\n"; 635 } else { 636 $debug = ''; 637 } 638 echo <<<EOT 639 <html><head><title>Error generating thumbnail</title></head> 640 <body> 641 <h1>Error generating thumbnail</h1> 642 <p> 643 $msg 644 </p> 645 $debug 646 </body> 647 </html> 648 649 EOT; 650 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Fri Nov 28 14:03:12 2014 | Cross-referenced by PHPXref 0.7.1 |