3 # Valid web server entry point
4 define( 'THUMB_HANDLER', true );
6 # Load thumb-handler configuration. We don't want to use
7 # WebStart.php or the like as it would kill performance.
8 $configPath = dirname( __FILE__
) . "/thumb.config.php";
9 if ( !file_exists( $configPath ) ) {
10 die( "Thumb-handler.php is not enabled for this wiki.\n" );
11 } elseif ( !extension_loaded( 'curl' ) ) {
12 die( "cURL is not enabled for PHP on this wiki.\n" ); // sanity
14 require( $configPath );
16 wfHandleThumb404Main();
18 function wfHandleThumb404Main() {
19 global $thgThumbCallbacks, $thgThumb404File;
21 # lighttpd puts the original request in REQUEST_URI, while
22 # sjs sets that to the 404 handler, and puts the original
23 # request in REDIRECT_URL.
24 if ( isset( $_SERVER['REDIRECT_URL'] ) ) {
25 # The URL is un-encoded, so put it back how it was.
26 $uri = str_replace( "%2F", "/", urlencode( $_SERVER['REDIRECT_URL'] ) );
28 $uri = $_SERVER['REQUEST_URI'];
31 # Extract thumb.php params from the URI...
32 if ( isset( $thgThumbCallbacks['extractParams'] )
33 && is_callable( $thgThumbCallbacks['extractParams'] ) ) // overridden by configuration?
35 $params = call_user_func_array( $thgThumbCallbacks['extractParams'], array( $uri ) );
37 $params = wfExtractThumbParams( $uri ); // basic wiki URL param extracting
40 # Show 404 error if this is not a valid thumb request...
41 if ( !is_array( $params ) ) {
42 header( 'X-Debug: no regex match' ); // useful for debugging
43 if ( $thgThumb404File ) { // overridden by configuration?
44 require( $thgThumb404File );
46 wfDisplay404Error(); // standard 404 message
51 # Check any backend caches for the thumbnail...
52 if ( isset( $thgThumbCallbacks['checkCache'] )
53 && is_callable( $thgThumbCallbacks['checkCache'] ) )
55 if ( call_user_func_array( $thgThumbCallbacks['checkCache'], array( $uri, $params ) ) ) {
56 return; // file streamed from backend thumb cache
60 wfStreamThumbViaCurl( $params, $uri );
64 * Extract the required params for thumb.php from the thumbnail request URI.
65 * At least 'width' and 'f' should be set if the result is an array.
67 * @param $uri String Thumbnail request URI
68 * @return Array|null associative params array or null
70 function wfExtractThumbParams( $uri ) {
71 global $thgThumbServer, $thgThumbFragment, $thgThumbHashFragment;
73 $thumbRegex = '!^(?:' . preg_quote( $thgThumbServer ) . ')?/' .
74 preg_quote( $thgThumbFragment ) . '(/archive|/temp|)/' .
75 $thgThumbHashFragment . '([^/]*)/(page(\d*)-)*(\d*)px-[^/]*$!';
77 if ( preg_match( $thumbRegex, $uri, $matches ) ) {
78 list( $all, $archOrTemp, $filename, $pagefull, $pagenum, $size ) = $matches;
79 $params = array( 'f' => $filename, 'width' => $size );
81 $params['page'] = $pagenum;
83 if ( $archOrTemp == '/archive' ) {
84 $params['archived'] = 1;
85 } elseif ( $archOrTemp == '/temp' ) {
89 $params = null; // not a valid thumbnail URL
96 * cURL to thumb.php and stream back the resulting file or give an error message.
98 * @param $params Array Parameters to thumb.php
99 * @param $uri String Thumbnail request URI
102 function wfStreamThumbViaCurl( array $params, $uri ) {
103 global $thgThumbCallbacks, $thgThumbScriptPath, $thgThumbCurlProxy, $thgThumbCurlTimeout;
105 # Build up the request URL to use with CURL...
106 $reqURL = "{$thgThumbScriptPath}?";
108 foreach ( $params as $name => $value ) {
114 $reqURL .= "$name=$value"; // Note: value is already urlencoded
117 # Set relevant HTTP headers...
119 $headers[] = "X-Original-URI: " . str_replace( "\n", '', $uri );
120 if ( isset( $thgThumbCallbacks['curlHeaders'] )
121 && is_callable( $thgThumbCallbacks['curlHeaders'] ) )
123 # Add on any custom headers (like XFF)
124 call_user_func_array( $thgThumbCallbacks['curlHeaders'], array( &$headers ) );
127 # Pass through some other headers...
128 $passThrough = array( 'If-Modified-Since', 'Referer', 'User-Agent' );
129 foreach ( $passThrough as $headerName ) {
130 $serverVarName = 'HTTP_' . str_replace( '-', '_', strtoupper( $headerName ) );
131 if ( !empty( $_SERVER[$serverVarName] ) ) {
132 $headers[] = $headerName . ': ' .
133 str_replace( "\n", '', $_SERVER[$serverVarName] );
137 $ch = curl_init( $reqURL );
138 if ( $thgThumbCurlProxy ) {
139 curl_setopt( $ch, CURLOPT_PROXY
, $thgThumbCurlProxy );
142 curl_setopt( $ch, CURLOPT_HTTPHEADER
, $headers );
143 curl_setopt( $ch, CURLOPT_RETURNTRANSFER
, true );
144 curl_setopt( $ch, CURLOPT_TIMEOUT
, $thgThumbCurlTimeout );
146 # Actually make the request
147 $text = curl_exec( $ch );
149 # Send it on to the client...
150 $errno = curl_errno( $ch );
151 $contentType = curl_getinfo( $ch, CURLINFO_CONTENT_TYPE
);
152 $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE
);
154 header( 'HTTP/1.1 500 Internal server error' );
155 header( 'Cache-Control: no-cache' );
156 $contentType = 'text/html';
157 $text = wfCurlErrorText( $ch );
158 } elseif ( $httpCode == 304 ) { // OK
159 header( 'HTTP/1.1 304 Not modified' );
162 } elseif ( strval( $text ) == '' ) {
163 header( 'HTTP/1.1 500 Internal server error' );
164 header( 'Cache-Control: no-cache' );
165 $contentType = 'text/html';
166 $text = wfCurlEmptyText( $ch );
167 } elseif ( $httpCode == 404 ) {
168 header( 'HTTP/1.1 404 Not found' );
169 header( 'Cache-Control: s-maxage=300, must-revalidate, max-age=0' );
170 } elseif ( $httpCode != 200 ||
substr( $contentType, 0, 9 ) == 'text/html' ) {
171 # Error message, suppress cache
172 header( 'HTTP/1.1 500 Internal server error' );
173 header( 'Cache-Control: no-cache' );
175 # OK thumbnail; save to any backend caches...
176 if ( isset( $thgThumbCallbacks['fillCache'] )
177 && is_callable( $thgThumbCallbacks['fillCache'] ) )
179 call_user_func_array( $thgThumbCallbacks['fillCache'], array( $uri, $text ) );
183 if ( !$contentType ) {
184 header( 'Content-Type:' );
186 header( "Content-Type: $contentType" );
189 print $text; // thumb data or error text
195 * Get error message HTML for when the cURL response is an error.
197 * @param $ch cURL handle
200 function wfCurlErrorText( $ch ) {
201 $error = htmlspecialchars( curl_error( $ch ) );
204 <head><title>Thumbnail error</title></head>
205 <body>Error retrieving thumbnail from scaling server: $error</body>
211 * Get error message HTML for when the cURL response is empty.
213 * @param $ch cURL handle
216 function wfCurlEmptyText( $ch ) {
219 <head><title>Thumbnail error</title></head>
220 <body>Error retrieving thumbnail from scaling server: empty response</body>
226 * Print out a generic 404 error message.
230 function wfDisplay404Error() {
231 header( 'HTTP/1.1 404 Not Found' );
232 header( 'Content-Type: text/html;charset=utf-8' );
234 $prot = isset( $_SERVER['HTTPS'] ) ?
"https://" : "http://";
235 $serv = strlen( $_SERVER['HTTP_HOST'] ) ?
$_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
236 $loc = $_SERVER["REQUEST_URI"];
238 $encUrl = htmlspecialchars( $prot . $serv . $loc );
240 // Looks like a typical apache2 error
241 $standard_404 = <<<ENDTEXT
242 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
244 <title>404 Not Found</title>
247 <p>The requested URL $encUrl was not found on this server.</p>