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