MediaWiki  REL1_22
OutputHandler.php
Go to the documentation of this file.
00001 <?php
00030 function wfOutputHandler( $s ) {
00031     global $wgDisableOutputCompression, $wgValidateAllHtml;
00032     $s = wfMangleFlashPolicy( $s );
00033     if ( $wgValidateAllHtml ) {
00034         $headers = headers_list();
00035         $isHTML = false;
00036         foreach ( $headers as $header ) {
00037             $parts = explode( ':', $header, 2 );
00038             if ( count( $parts ) !== 2 ) {
00039                 continue;
00040             }
00041             $name = strtolower( trim( $parts[0] ) );
00042             $value = trim( $parts[1] );
00043             if ( $name == 'content-type' && ( strpos( $value, 'text/html' ) === 0
00044                 || strpos( $value, 'application/xhtml+xml' ) === 0 )
00045             ) {
00046                 $isHTML = true;
00047                 break;
00048             }
00049         }
00050         if ( $isHTML ) {
00051             $s = wfHtmlValidationHandler( $s );
00052         }
00053     }
00054     if ( !$wgDisableOutputCompression && !ini_get( 'zlib.output_compression' ) ) {
00055         if ( !defined( 'MW_NO_OUTPUT_COMPRESSION' ) ) {
00056             $s = wfGzipHandler( $s );
00057         }
00058         if ( !ini_get( 'output_handler' ) ) {
00059             wfDoContentLength( strlen( $s ) );
00060         }
00061     }
00062     return $s;
00063 }
00064 
00073 function wfRequestExtension() {
00075     if ( isset( $_SERVER['REQUEST_URI'] ) ) {
00076         // Strip the query string...
00077         list( $path ) = explode( '?', $_SERVER['REQUEST_URI'], 2 );
00078     } elseif ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
00079         // Probably IIS. QUERY_STRING appears separately.
00080         $path = $_SERVER['SCRIPT_NAME'];
00081     } else {
00082         // Can't get the path from the server? :(
00083         return '';
00084     }
00085 
00086     $period = strrpos( $path, '.' );
00087     if ( $period !== false ) {
00088         return strtolower( substr( $path, $period ) );
00089     }
00090     return '';
00091 }
00092 
00101 function wfGzipHandler( $s ) {
00102     if ( !function_exists( 'gzencode' ) ) {
00103         wfDebug( __FUNCTION__ . "() skipping compression (gzencode unavailable)\n" );
00104         return $s;
00105     }
00106     if ( headers_sent() ) {
00107         wfDebug( __FUNCTION__ . "() skipping compression (headers already sent)\n" );
00108         return $s;
00109     }
00110 
00111     $ext = wfRequestExtension();
00112     if ( $ext == '.gz' || $ext == '.tgz' ) {
00113         // Don't do gzip compression if the URL path ends in .gz or .tgz
00114         // This confuses Safari and triggers a download of the page,
00115         // even though it's pretty clearly labeled as viewable HTML.
00116         // Bad Safari! Bad!
00117         return $s;
00118     }
00119 
00120     if ( wfClientAcceptsGzip() ) {
00121         wfDebug( __FUNCTION__ . "() is compressing output\n" );
00122         header( 'Content-Encoding: gzip' );
00123         $s = gzencode( $s, 6 );
00124     }
00125 
00126     // Set vary header if it hasn't been set already
00127     $headers = headers_list();
00128     $foundVary = false;
00129     foreach ( $headers as $header ) {
00130         if ( substr( $header, 0, 5 ) == 'Vary:' ) {
00131             $foundVary = true;
00132             break;
00133         }
00134     }
00135     if ( !$foundVary ) {
00136         header( 'Vary: Accept-Encoding' );
00137         global $wgUseXVO;
00138         if ( $wgUseXVO ) {
00139             header( 'X-Vary-Options: Accept-Encoding;list-contains=gzip' );
00140         }
00141     }
00142     return $s;
00143 }
00144 
00152 function wfMangleFlashPolicy( $s ) {
00153     # Avoid weird excessive memory usage in PCRE on big articles
00154     if ( preg_match( '/<\s*cross-domain-policy\s*>/i', $s ) ) {
00155         return preg_replace( '/<\s*cross-domain-policy\s*>/i', '<NOT-cross-domain-policy>', $s );
00156     } else {
00157         return $s;
00158     }
00159 }
00160 
00166 function wfDoContentLength( $length ) {
00167     if ( !headers_sent() && isset( $_SERVER['SERVER_PROTOCOL'] ) && $_SERVER['SERVER_PROTOCOL'] == 'HTTP/1.0' ) {
00168         header( "Content-Length: $length" );
00169     }
00170 }
00171 
00179 function wfHtmlValidationHandler( $s ) {
00180 
00181     $errors = '';
00182     if ( MWTidy::checkErrors( $s, $errors ) ) {
00183         return $s;
00184     }
00185 
00186     header( 'Cache-Control: no-cache' );
00187 
00188     $out = Html::element( 'h1', null, 'HTML validation error' );
00189     $out .= Html::openElement( 'ul' );
00190 
00191     $error = strtok( $errors, "\n" );
00192     $badLines = array();
00193     while ( $error !== false ) {
00194         if ( preg_match( '/^line (\d+)/', $error, $m ) ) {
00195             $lineNum = intval( $m[1] );
00196             $badLines[$lineNum] = true;
00197             $out .= Html::rawElement( 'li', null,
00198                 Html::element( 'a', array( 'href' => "#line-{$lineNum}" ), $error ) ) . "\n";
00199         }
00200         $error = strtok( "\n" );
00201     }
00202 
00203     $out .= Html::closeElement( 'ul' );
00204     $out .= Html::element( 'pre', null, $errors );
00205     $out .= Html::openElement( 'ol' ) . "\n";
00206     $line = strtok( $s, "\n" );
00207     $i = 1;
00208     while ( $line !== false ) {
00209         $attrs = array();
00210         if ( isset( $badLines[$i] ) ) {
00211             $attrs['class'] = 'highlight';
00212             $attrs['id'] = "line-$i";
00213         }
00214         $out .= Html::element( 'li', $attrs, $line ) . "\n";
00215         $line = strtok( "\n" );
00216         $i++;
00217     }
00218     $out .= Html::closeElement( 'ol' );
00219 
00220     $style = <<<CSS
00221 .highlight { background-color: #ffc }
00222 li { white-space: pre }
00223 CSS;
00224 
00225     $out = Html::htmlHeader( array( 'lang' => 'en', 'dir' => 'ltr' ) ) .
00226         Html::rawElement( 'head', null,
00227             Html::element( 'title', null, 'HTML validation error' ) .
00228             Html::inlineStyle( $style ) ) .
00229         Html::rawElement( 'body', null, $out ) .
00230         Html::closeElement( 'html' );
00231 
00232     return $out;
00233 }