| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | /** |
|---|
| 4 | * PHP script to stream out an image thumbnail. |
|---|
| 5 | * |
|---|
| 6 | * @file |
|---|
| 7 | * @ingroup Media |
|---|
| 8 | */ |
|---|
| 9 | define( 'MW_NO_OUTPUT_COMPRESSION', 1 ); |
|---|
| 10 | require_once( './includes/WebStart.php' ); |
|---|
| 11 | |
|---|
| 12 | $wgTrivialMimeDetection = true; //don't use fancy mime detection, just check the file extension for jpg/gif/png. |
|---|
| 13 | |
|---|
| 14 | require_once( "$IP/includes/StreamFile.php" ); |
|---|
| 15 | |
|---|
| 16 | wfThumbMain(); |
|---|
| 17 | wfLogProfilingData(); |
|---|
| 18 | |
|---|
| 19 | //-------------------------------------------------------------------------- |
|---|
| 20 | |
|---|
| 21 | function wfThumbMain() { |
|---|
| 22 | wfProfileIn( __METHOD__ ); |
|---|
| 23 | |
|---|
| 24 | $headers = array(); |
|---|
| 25 | |
|---|
| 26 | // Get input parameters |
|---|
| 27 | if ( get_magic_quotes_gpc() ) { |
|---|
| 28 | $params = array_map( 'stripslashes', $_REQUEST ); |
|---|
| 29 | } else { |
|---|
| 30 | $params = $_REQUEST; |
|---|
| 31 | } |
|---|
| 32 | |
|---|
| 33 | $fileName = isset( $params['f'] ) ? $params['f'] : ''; |
|---|
| 34 | unset( $params['f'] ); |
|---|
| 35 | |
|---|
| 36 | // Backwards compatibility parameters |
|---|
| 37 | if ( isset( $params['w'] ) ) { |
|---|
| 38 | $params['width'] = $params['w']; |
|---|
| 39 | unset( $params['w'] ); |
|---|
| 40 | } |
|---|
| 41 | if ( isset( $params['p'] ) ) { |
|---|
| 42 | $params['page'] = $params['p']; |
|---|
| 43 | } |
|---|
| 44 | unset( $params['r'] ); |
|---|
| 45 | |
|---|
| 46 | // Is this a thumb of an archived file? |
|---|
| 47 | $isOld = (isset( $params['archived'] ) && $params['archived']); |
|---|
| 48 | unset( $params['archived'] ); |
|---|
| 49 | |
|---|
| 50 | // Some basic input validation |
|---|
| 51 | $fileName = strtr( $fileName, '\\/', '__' ); |
|---|
| 52 | |
|---|
| 53 | // Actually fetch the image. Method depends on whether it is archived or not. |
|---|
| 54 | if( $isOld ) { |
|---|
| 55 | // Format is <timestamp>!<name> |
|---|
| 56 | $bits = explode( '!', $fileName, 2 ); |
|---|
| 57 | if( !isset($bits[1]) ) { |
|---|
| 58 | wfThumbError( 404, wfMsg( 'badtitletext' ) ); |
|---|
| 59 | return; |
|---|
| 60 | } |
|---|
| 61 | $title = Title::makeTitleSafe( NS_FILE, $bits[1] ); |
|---|
| 62 | if( is_null($title) ) { |
|---|
| 63 | wfThumbError( 404, wfMsg( 'badtitletext' ) ); |
|---|
| 64 | return; |
|---|
| 65 | } |
|---|
| 66 | $img = RepoGroup::singleton()->getLocalRepo()->newFromArchiveName( $title, $fileName ); |
|---|
| 67 | } else { |
|---|
| 68 | $img = wfLocalFile( $fileName ); |
|---|
| 69 | } |
|---|
| 70 | |
|---|
| 71 | // Check permissions if there are read restrictions |
|---|
| 72 | if ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) ) { |
|---|
| 73 | if ( !$img->getTitle()->userCanRead() ) { |
|---|
| 74 | wfThumbError( 403, 'Access denied. You do not have permission to access ' . |
|---|
| 75 | 'the source file.' ); |
|---|
| 76 | return; |
|---|
| 77 | } |
|---|
| 78 | $headers[] = 'Cache-Control: private'; |
|---|
| 79 | $headers[] = 'Vary: Cookie'; |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | if ( !$img ) { |
|---|
| 83 | wfThumbError( 404, wfMsg( 'badtitletext' ) ); |
|---|
| 84 | return; |
|---|
| 85 | } |
|---|
| 86 | if ( !$img->exists() ) { |
|---|
| 87 | wfThumbError( 404, 'The source file for the specified thumbnail does not exist.' ); |
|---|
| 88 | return; |
|---|
| 89 | } |
|---|
| 90 | $sourcePath = $img->getPath(); |
|---|
| 91 | if ( $sourcePath === false ) { |
|---|
| 92 | wfThumbError( 500, 'The source file is not locally accessible.' ); |
|---|
| 93 | return; |
|---|
| 94 | } |
|---|
| 95 | |
|---|
| 96 | // Check IMS against the source file |
|---|
| 97 | // This means that clients can keep a cached copy even after it has been deleted on the server |
|---|
| 98 | if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) { |
|---|
| 99 | // Fix IE brokenness |
|---|
| 100 | $imsString = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] ); |
|---|
| 101 | // Calculate time |
|---|
| 102 | wfSuppressWarnings(); |
|---|
| 103 | $imsUnix = strtotime( $imsString ); |
|---|
| 104 | wfRestoreWarnings(); |
|---|
| 105 | $stat = @stat( $sourcePath ); |
|---|
| 106 | if ( $stat['mtime'] <= $imsUnix ) { |
|---|
| 107 | header( 'HTTP/1.1 304 Not Modified' ); |
|---|
| 108 | return; |
|---|
| 109 | } |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | // Stream the file if it exists already |
|---|
| 113 | try { |
|---|
| 114 | if ( false != ( $thumbName = $img->thumbName( $params ) ) ) { |
|---|
| 115 | $thumbPath = $img->getThumbPath( $thumbName ); |
|---|
| 116 | |
|---|
| 117 | if ( is_file( $thumbPath ) ) { |
|---|
| 118 | wfStreamFile( $thumbPath, $headers ); |
|---|
| 119 | return; |
|---|
| 120 | } |
|---|
| 121 | } |
|---|
| 122 | } catch ( MWException $e ) { |
|---|
| 123 | wfThumbError( 500, $e->getHTML() ); |
|---|
| 124 | return; |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | try { |
|---|
| 128 | $thumb = $img->transform( $params, File::RENDER_NOW ); |
|---|
| 129 | } catch( Exception $ex ) { |
|---|
| 130 | // Tried to select a page on a non-paged file? |
|---|
| 131 | $thumb = false; |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | $errorMsg = false; |
|---|
| 135 | if ( !$thumb ) { |
|---|
| 136 | $errorMsg = wfMsgHtml( 'thumbnail_error', 'File::transform() returned false' ); |
|---|
| 137 | } elseif ( $thumb->isError() ) { |
|---|
| 138 | $errorMsg = $thumb->getHtmlMsg(); |
|---|
| 139 | } elseif ( !$thumb->getPath() ) { |
|---|
| 140 | $errorMsg = wfMsgHtml( 'thumbnail_error', 'No path supplied in thumbnail object' ); |
|---|
| 141 | } elseif ( $thumb->getPath() == $img->getPath() ) { |
|---|
| 142 | $errorMsg = wfMsgHtml( 'thumbnail_error', 'Image was not scaled, ' . |
|---|
| 143 | 'is the requested width bigger than the source?' ); |
|---|
| 144 | } else { |
|---|
| 145 | wfStreamFile( $thumb->getPath(), $headers ); |
|---|
| 146 | } |
|---|
| 147 | if ( $errorMsg !== false ) { |
|---|
| 148 | wfThumbError( 500, $errorMsg ); |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | wfProfileOut( __METHOD__ ); |
|---|
| 152 | } |
|---|
| 153 | |
|---|
| 154 | function wfThumbError( $status, $msg ) { |
|---|
| 155 | global $wgShowHostnames; |
|---|
| 156 | header( 'Cache-Control: no-cache' ); |
|---|
| 157 | header( 'Content-Type: text/html; charset=utf-8' ); |
|---|
| 158 | if ( $status == 404 ) { |
|---|
| 159 | header( 'HTTP/1.1 404 Not found' ); |
|---|
| 160 | } elseif ( $status == 403 ) { |
|---|
| 161 | header( 'HTTP/1.1 403 Forbidden' ); |
|---|
| 162 | header( 'Vary: Cookie' ); |
|---|
| 163 | } else { |
|---|
| 164 | header( 'HTTP/1.1 500 Internal server error' ); |
|---|
| 165 | } |
|---|
| 166 | if( $wgShowHostnames ) { |
|---|
| 167 | $url = htmlspecialchars( @$_SERVER['REQUEST_URI'] ); |
|---|
| 168 | $hostname = htmlspecialchars( wfHostname() ); |
|---|
| 169 | $debug = "<!-- $url -->\n<!-- $hostname -->\n"; |
|---|
| 170 | } else { |
|---|
| 171 | $debug = ""; |
|---|
| 172 | } |
|---|
| 173 | echo <<<EOT |
|---|
| 174 | <html><head><title>Error generating thumbnail</title></head> |
|---|
| 175 | <body> |
|---|
| 176 | <h1>Error generating thumbnail</h1> |
|---|
| 177 | <p> |
|---|
| 178 | $msg |
|---|
| 179 | </p> |
|---|
| 180 | $debug |
|---|
| 181 | </body> |
|---|
| 182 | </html> |
|---|
| 183 | |
|---|
| 184 | EOT; |
|---|
| 185 | } |
|---|
| 186 | |
|---|