MediaWiki  REL1_23
AjaxResponse.php
Go to the documentation of this file.
00001 <?php
00030 class AjaxResponse {
00035     private $mCacheDuration;
00036 
00041     private $mContentType;
00042 
00047     private $mDisabled;
00048 
00053     private $mLastModified;
00054 
00059     private $mResponseCode;
00060 
00065     private $mVary;
00066 
00071     private $mText;
00072 
00076     function __construct( $text = null ) {
00077         $this->mCacheDuration = null;
00078         $this->mVary = null;
00079 
00080         $this->mDisabled = false;
00081         $this->mText = '';
00082         $this->mResponseCode = '200 OK';
00083         $this->mLastModified = false;
00084         $this->mContentType = 'application/x-wiki';
00085 
00086         if ( $text ) {
00087             $this->addText( $text );
00088         }
00089     }
00090 
00095     function setCacheDuration( $duration ) {
00096         $this->mCacheDuration = $duration;
00097     }
00098 
00103     function setVary( $vary ) {
00104         $this->mVary = $vary;
00105     }
00106 
00111     function setResponseCode( $code ) {
00112         $this->mResponseCode = $code;
00113     }
00114 
00119     function setContentType( $type ) {
00120         $this->mContentType = $type;
00121     }
00122 
00126     function disable() {
00127         $this->mDisabled = true;
00128     }
00129 
00134     function addText( $text ) {
00135         if ( ! $this->mDisabled && $text ) {
00136             $this->mText .= $text;
00137         }
00138     }
00139 
00143     function printText() {
00144         if ( ! $this->mDisabled ) {
00145             print $this->mText;
00146         }
00147     }
00148 
00152     function sendHeaders() {
00153         global $wgUseSquid, $wgUseESI;
00154 
00155         if ( $this->mResponseCode ) {
00156             $n = preg_replace( '/^ *(\d+)/', '\1', $this->mResponseCode );
00157             header( "Status: " . $this->mResponseCode, true, (int)$n );
00158         }
00159 
00160         header ( "Content-Type: " . $this->mContentType );
00161 
00162         if ( $this->mLastModified ) {
00163             header ( "Last-Modified: " . $this->mLastModified );
00164         } else {
00165             header ( "Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . " GMT" );
00166         }
00167 
00168         if ( $this->mCacheDuration ) {
00169             # If squid caches are configured, tell them to cache the response,
00170             # and tell the client to always check with the squid. Otherwise,
00171             # tell the client to use a cached copy, without a way to purge it.
00172 
00173             if ( $wgUseSquid ) {
00174                 # Expect explicit purge of the proxy cache, but require end user agents
00175                 # to revalidate against the proxy on each visit.
00176                 # Surrogate-Control controls our Squid, Cache-Control downstream caches
00177 
00178                 if ( $wgUseESI ) {
00179                     header( 'Surrogate-Control: max-age=' . $this->mCacheDuration . ', content="ESI/1.0"' );
00180                     header( 'Cache-Control: s-maxage=0, must-revalidate, max-age=0' );
00181                 } else {
00182                     header( 'Cache-Control: s-maxage=' . $this->mCacheDuration . ', must-revalidate, max-age=0' );
00183                 }
00184 
00185             } else {
00186                 # Let the client do the caching. Cache is not purged.
00187                 header ( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $this->mCacheDuration ) . " GMT" );
00188                 header ( "Cache-Control: s-maxage={$this->mCacheDuration}," .
00189                     "public,max-age={$this->mCacheDuration}" );
00190             }
00191 
00192         } else {
00193             # always expired, always modified
00194             header ( "Expires: Mon, 26 Jul 1997 05:00:00 GMT" );    // Date in the past
00195             header ( "Cache-Control: no-cache, must-revalidate" );  // HTTP/1.1
00196             header ( "Pragma: no-cache" );                          // HTTP/1.0
00197         }
00198 
00199         if ( $this->mVary ) {
00200             header ( "Vary: " . $this->mVary );
00201         }
00202     }
00203 
00212     function checkLastModified( $timestamp ) {
00213         global $wgCachePages, $wgCacheEpoch, $wgUser;
00214         $fname = 'AjaxResponse::checkLastModified';
00215 
00216         if ( !$timestamp || $timestamp == '19700101000000' ) {
00217             wfDebug( "$fname: CACHE DISABLED, NO TIMESTAMP\n", 'log' );
00218             return false;
00219         }
00220 
00221         if ( !$wgCachePages ) {
00222             wfDebug( "$fname: CACHE DISABLED\n", 'log' );
00223             return false;
00224         }
00225 
00226         $timestamp = wfTimestamp( TS_MW, $timestamp );
00227         $lastmod = wfTimestamp( TS_RFC2822, max( $timestamp, $wgUser->getTouched(), $wgCacheEpoch ) );
00228 
00229         if ( !empty( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) ) {
00230             # IE sends sizes after the date like this:
00231             # Wed, 20 Aug 2003 06:51:19 GMT; length=5202
00232             # this breaks strtotime().
00233             $modsince = preg_replace( '/;.*$/', '', $_SERVER["HTTP_IF_MODIFIED_SINCE"] );
00234             $modsinceTime = strtotime( $modsince );
00235             $ismodsince = wfTimestamp( TS_MW, $modsinceTime ? $modsinceTime : 1 );
00236             wfDebug( "$fname: -- client send If-Modified-Since: " . $modsince . "\n", 'log' );
00237             wfDebug( "$fname: --  we might send Last-Modified : $lastmod\n", 'log' );
00238 
00239             if ( ( $ismodsince >= $timestamp )
00240                 && $wgUser->validateCache( $ismodsince ) &&
00241                 $ismodsince >= $wgCacheEpoch
00242             ) {
00243                 ini_set( 'zlib.output_compression', 0 );
00244                 $this->setResponseCode( "304 Not Modified" );
00245                 $this->disable();
00246                 $this->mLastModified = $lastmod;
00247 
00248                 wfDebug( "$fname: CACHED client: $ismodsince ; user: {$wgUser->getTouched()} ; " .
00249                     "page: $timestamp ; site $wgCacheEpoch\n", 'log' );
00250 
00251                 return true;
00252             } else {
00253                 wfDebug( "$fname: READY  client: $ismodsince ; user: {$wgUser->getTouched()} ; " .
00254                     "page: $timestamp ; site $wgCacheEpoch\n", 'log' );
00255                 $this->mLastModified = $lastmod;
00256             }
00257         } else {
00258             wfDebug( "$fname: client did not send If-Modified-Since header\n", 'log' );
00259             $this->mLastModified = $lastmod;
00260         }
00261         return false;
00262     }
00263 
00269     function loadFromMemcached( $mckey, $touched ) {
00270         global $wgMemc;
00271 
00272         if ( !$touched ) {
00273             return false;
00274         }
00275 
00276         $mcvalue = $wgMemc->get( $mckey );
00277         if ( $mcvalue ) {
00278             # Check to see if the value has been invalidated
00279             if ( $touched <= $mcvalue['timestamp'] ) {
00280                 wfDebug( "Got $mckey from cache\n" );
00281                 $this->mText = $mcvalue['value'];
00282 
00283                 return true;
00284             } else {
00285                 wfDebug( "$mckey has expired\n" );
00286             }
00287         }
00288 
00289         return false;
00290     }
00291 
00297     function storeInMemcached( $mckey, $expiry = 86400 ) {
00298         global $wgMemc;
00299 
00300         $wgMemc->set( $mckey,
00301             array(
00302                 'timestamp' => wfTimestampNow(),
00303                 'value' => $this->mText
00304             ), $expiry
00305         );
00306 
00307         return true;
00308     }
00309 }