3 # Valid web server entry point
4 define( 'THUMB_HANDLER', true );
6 # Load thumb-handler configuration. Avoids WebStart.php for performance.
7 if ( !file_exists( dirname( __FILE__
) . "/thumb.config.php" ) ) {
8 die( "thumb_handler.php is not enabled for this wiki.\n" );
10 require( dirname( __FILE__
) . "/thumb.config.php" );
12 # Execute thumb.php if not handled via cURL
13 if ( wfHandleThumb404Main() === 'wfThumbMain' ) {
14 require( dirname( __FILE__
) . '/thumb.php' );
17 function wfHandleThumb404Main() {
18 global $thgThumbCallbacks, $thgThumbCurlConfig;
20 # lighttpd puts the original request in REQUEST_URI, while
21 # sjs sets that to the 404 handler, and puts the original
22 # request in REDIRECT_URL.
23 if ( isset( $_SERVER['REDIRECT_URL'] ) ) {
24 # The URL is un-encoded, so put it back how it was.
25 $uri = str_replace( "%2F", "/", urlencode( $_SERVER['REDIRECT_URL'] ) );
27 $uri = $_SERVER['REQUEST_URI'];
30 # Extract thumb.php params from the URI...
31 if ( isset( $thgThumbCallbacks['extractParams'] )
32 && is_callable( $thgThumbCallbacks['extractParams'] ) ) // overridden by configuration?
34 $params = call_user_func_array( $thgThumbCallbacks['extractParams'], array( $uri ) );
36 $params = wfExtractThumbParams( $uri ); // basic wiki URL param extracting
39 # Show 404 error if this is not a valid thumb request...
40 if ( !is_array( $params ) ) {
41 header( 'X-Debug: no regex match' ); // useful for debugging
42 if ( isset( $thgThumbCallbacks['error404'] )
43 && is_callable( $thgThumbCallbacks['error404'] ) ) // overridden by configuration?
45 call_user_func( $thgThumbCallbacks['error404'] );
47 wfDisplay404Error(); // standard 404 message
52 # Obtain and stream the thumbnail or setup for wfThumbMain() call...
53 if ( $thgThumbCurlConfig['enabled'] ) {
54 wfStreamThumbViaCurl( $params, $uri );
57 $_REQUEST = $params; // pass params to thumb.php
63 * Extract the required params for thumb.php from the thumbnail request URI.
64 * At least 'width' and 'f' should be set if the result is an array.
66 * @param $uri String Thumbnail request URI
67 * @return Array|null associative params array or null
69 function wfExtractThumbParams( $uri ) {
70 global $thgThumbUrlMatch;
72 $thumbRegex = '!^(?:' . preg_quote( $thgThumbUrlMatch['server'] ) . ')?/' .
73 preg_quote( $thgThumbUrlMatch['dirFragment'] ) . '(/archive|/temp|)/' .
74 $thgThumbUrlMatch['hashFragment'] . '([^/]*)/(page(\d*)-)*(\d*)px-[^/]*$!';
76 if ( preg_match( $thumbRegex, $uri, $matches ) ) {
77 list( $all, $archOrTemp, $filename, $pagefull, $pagenum, $size ) = $matches;
78 $params = array( 'f' => $filename, 'width' => $size );
80 $params['page'] = $pagenum;
82 if ( $archOrTemp == '/archive' ) {
83 $params['archived'] = 1;
84 } elseif ( $archOrTemp == '/temp' ) {
88 $params = null; // not a valid thumbnail URL
95 * cURL to thumb.php and stream back the resulting file or give an error message.
97 * @param $params Array Parameters to thumb.php
98 * @param $uri String Thumbnail request URI
101 function wfStreamThumbViaCurl( array $params, $uri ) {
102 global $thgThumbCallbacks, $thgThumbCurlConfig;
104 # Check any backend caches for the thumbnail...
105 if ( isset( $thgThumbCallbacks['checkCache'] )
106 && is_callable( $thgThumbCallbacks['checkCache'] ) )
108 if ( call_user_func_array( $thgThumbCallbacks['checkCache'], array( $uri, $params ) ) ) {
109 return; // file streamed from backend thumb cache
113 if ( !extension_loaded( 'curl' ) ) {
114 die( "cURL is not enabled for PHP on this wiki.\n" ); // sanity
117 # Build up the request URL to use with CURL...
118 $reqURL = $thgThumbCurlConfig['url'] . '?';
120 foreach ( $params as $name => $value ) {
126 $reqURL .= "$name=$value"; // Note: value is already urlencoded
129 # Set relevant HTTP headers...
131 $headers[] = "X-Original-URI: " . str_replace( "\n", '', $uri );
132 if ( isset( $thgThumbCallbacks['curlHeaders'] )
133 && is_callable( $thgThumbCallbacks['curlHeaders'] ) )
135 # Add on any custom headers (like XFF)
136 call_user_func_array( $thgThumbCallbacks['curlHeaders'], array( &$headers ) );
139 # Pass through some other headers...
140 $passThrough = array( 'If-Modified-Since', 'Referer', 'User-Agent' );
141 foreach ( $passThrough as $headerName ) {
142 $serverVarName = 'HTTP_' . str_replace( '-', '_', strtoupper( $headerName ) );
143 if ( !empty( $_SERVER[$serverVarName] ) ) {
144 $headers[] = $headerName . ': ' .
145 str_replace( "\n", '', $_SERVER[$serverVarName] );
149 $ch = curl_init( $reqURL );
150 if ( $thgThumbCurlConfig['proxy'] ) {
151 curl_setopt( $ch, CURLOPT_PROXY
, $thgThumbCurlConfig['proxy'] );
154 curl_setopt( $ch, CURLOPT_HTTPHEADER
, $headers );
155 curl_setopt( $ch, CURLOPT_RETURNTRANSFER
, true );
156 curl_setopt( $ch, CURLOPT_TIMEOUT
, $thgThumbCurlConfig['timeout'] );
158 # Actually make the request
159 $text = curl_exec( $ch );
161 # Send it on to the client...
162 $errno = curl_errno( $ch );
163 $contentType = curl_getinfo( $ch, CURLINFO_CONTENT_TYPE
);
164 $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE
);
166 header( 'HTTP/1.1 500 Internal server error' );
167 header( 'Cache-Control: no-cache' );
168 $contentType = 'text/html';
169 $text = wfCurlErrorText( $ch );
170 } elseif ( $httpCode == 304 ) { // OK
171 header( 'HTTP/1.1 304 Not modified' );
174 } elseif ( strval( $text ) == '' ) {
175 header( 'HTTP/1.1 500 Internal server error' );
176 header( 'Cache-Control: no-cache' );
177 $contentType = 'text/html';
178 $text = wfCurlEmptyText( $ch );
179 } elseif ( $httpCode == 404 ) {
180 header( 'HTTP/1.1 404 Not found' );
181 header( 'Cache-Control: s-maxage=300, must-revalidate, max-age=0' );
182 } elseif ( $httpCode != 200 ||
substr( $contentType, 0, 9 ) == 'text/html' ) {
183 # Error message, suppress cache
184 header( 'HTTP/1.1 500 Internal server error' );
185 header( 'Cache-Control: no-cache' );
187 # OK thumbnail; save to any backend caches...
188 if ( isset( $thgThumbCallbacks['fillCache'] )
189 && is_callable( $thgThumbCallbacks['fillCache'] ) )
191 call_user_func_array( $thgThumbCallbacks['fillCache'], array( $uri, $text ) );
195 if ( !$contentType ) {
196 header( 'Content-Type:' );
198 header( "Content-Type: $contentType" );
201 print $text; // thumb data or error text
207 * Get error message HTML for when the cURL response is an error.
209 * @param $ch cURL handle
212 function wfCurlErrorText( $ch ) {
213 $error = htmlspecialchars( curl_error( $ch ) );
216 <head><title>Thumbnail error</title></head>
217 <body>Error retrieving thumbnail from scaling server: $error</body>
223 * Get error message HTML for when the cURL response is empty.
225 * @param $ch cURL handle
228 function wfCurlEmptyText( $ch ) {
231 <head><title>Thumbnail error</title></head>
232 <body>Error retrieving thumbnail from scaling server: empty response</body>
238 * Print out a generic 404 error message.
242 function wfDisplay404Error() {
243 header( 'HTTP/1.1 404 Not Found' );
244 header( 'Content-Type: text/html;charset=utf-8' );
246 $prot = isset( $_SERVER['HTTPS'] ) ?
"https://" : "http://";
247 $serv = strlen( $_SERVER['HTTP_HOST'] ) ?
$_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'];
248 $loc = $_SERVER["REQUEST_URI"];
250 $encUrl = htmlspecialchars( $prot . $serv . $loc );
252 // Looks like a typical apache2 error
253 $standard_404 = <<<ENDTEXT
254 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
256 <title>404 Not Found</title>
259 <p>The requested URL $encUrl was not found on this server.</p>