MediaWiki  REL1_19
Cookie.php
Go to the documentation of this file.
00001 <?php
00006 class Cookie {
00007         protected $name;
00008         protected $value;
00009         protected $expires;
00010         protected $path;
00011         protected $domain;
00012         protected $isSessionKey = true;
00013         // TO IMPLEMENT  protected $secure
00014         // TO IMPLEMENT? protected $maxAge (add onto expires)
00015         // TO IMPLEMENT? protected $version
00016         // TO IMPLEMENT? protected $comment
00017 
00018         function __construct( $name, $value, $attr ) {
00019                 $this->name = $name;
00020                 $this->set( $value, $attr );
00021         }
00022 
00034         public function set( $value, $attr ) {
00035                 $this->value = $value;
00036 
00037                 if ( isset( $attr['expires'] ) ) {
00038                         $this->isSessionKey = false;
00039                         $this->expires = strtotime( $attr['expires'] );
00040                 }
00041 
00042                 if ( isset( $attr['path'] ) ) {
00043                         $this->path = $attr['path'];
00044                 } else {
00045                         $this->path = '/';
00046                 }
00047 
00048                 if ( isset( $attr['domain'] ) ) {
00049                         if ( self::validateCookieDomain( $attr['domain'] ) ) {
00050                                 $this->domain = $attr['domain'];
00051                         }
00052                 } else {
00053                         throw new MWException( 'You must specify a domain.' );
00054                 }
00055         }
00056 
00072         public static function validateCookieDomain( $domain, $originDomain = null ) {
00073                 // Don't allow a trailing dot
00074                 if ( substr( $domain, -1 ) == '.' ) {
00075                         return false;
00076                 }
00077 
00078                 $dc = explode( ".", $domain );
00079 
00080                 // Only allow full, valid IP addresses
00081                 if ( preg_match( '/^[0-9.]+$/', $domain ) ) {
00082                         if ( count( $dc ) != 4 ) {
00083                                 return false;
00084                         }
00085 
00086                         if ( ip2long( $domain ) === false ) {
00087                                 return false;
00088                         }
00089 
00090                         if ( $originDomain == null || $originDomain == $domain ) {
00091                                 return true;
00092                         }
00093 
00094                 }
00095 
00096                 // Don't allow cookies for "co.uk" or "gov.uk", etc, but allow "supermarket.uk"
00097                 if ( strrpos( $domain, "." ) - strlen( $domain )  == -3 ) {
00098                         if ( ( count( $dc ) == 2 && strlen( $dc[0] ) <= 2 )
00099                                 || ( count( $dc ) == 3 && strlen( $dc[0] ) == "" && strlen( $dc[1] ) <= 2 ) ) {
00100                                 return false;
00101                         }
00102                         if ( ( count( $dc ) == 2 || ( count( $dc ) == 3 && $dc[0] == '' ) )
00103                                 && preg_match( '/(com|net|org|gov|edu)\...$/', $domain ) ) {
00104                                 return false;
00105                         }
00106                 }
00107 
00108                 if ( $originDomain != null ) {
00109                         if ( substr( $domain, 0, 1 ) != '.' && $domain != $originDomain ) {
00110                                 return false;
00111                         }
00112 
00113                         if ( substr( $domain, 0, 1 ) == '.'
00114                                 && substr_compare( $originDomain, $domain, -strlen( $domain ),
00115                                                                    strlen( $domain ), true ) != 0 ) {
00116                                 return false;
00117                         }
00118                 }
00119 
00120                 return true;
00121         }
00122 
00130         public function serializeToHttpRequest( $path, $domain ) {
00131                 $ret = '';
00132 
00133                 if ( $this->canServeDomain( $domain )
00134                                 && $this->canServePath( $path )
00135                                 && $this->isUnExpired() ) {
00136                         $ret = $this->name . '=' . $this->value;
00137                 }
00138 
00139                 return $ret;
00140         }
00141 
00146         protected function canServeDomain( $domain ) {
00147                 if ( $domain == $this->domain
00148                         || ( strlen( $domain ) > strlen( $this->domain )
00149                                  && substr( $this->domain, 0, 1 ) == '.'
00150                                  && substr_compare( $domain, $this->domain, -strlen( $this->domain ),
00151                                                                         strlen( $this->domain ), true ) == 0 ) ) {
00152                         return true;
00153                 }
00154 
00155                 return false;
00156         }
00157 
00162         protected function canServePath( $path ) {
00163                 return ( $this->path && substr_compare( $this->path, $path, 0, strlen( $this->path ) ) == 0 );
00164         }
00165 
00169         protected function isUnExpired() {
00170                 return $this->isSessionKey || $this->expires > time();
00171         }
00172 }
00173 
00174 class CookieJar {
00175         private $cookie = array();
00176 
00181         public function setCookie ( $name, $value, $attr ) {
00182                 /* cookies: case insensitive, so this should work.
00183                  * We'll still send the cookies back in the same case we got them, though.
00184                  */
00185                 $index = strtoupper( $name );
00186 
00187                 if ( isset( $this->cookie[$index] ) ) {
00188                         $this->cookie[$index]->set( $value, $attr );
00189                 } else {
00190                         $this->cookie[$index] = new Cookie( $name, $value, $attr );
00191                 }
00192         }
00193 
00197         public function serializeToHttpRequest( $path, $domain ) {
00198                 $cookies = array();
00199 
00200                 foreach ( $this->cookie as $c ) {
00201                         $serialized = $c->serializeToHttpRequest( $path, $domain );
00202 
00203                         if ( $serialized ) {
00204                                 $cookies[] = $serialized;
00205                         }
00206                 }
00207 
00208                 return implode( '; ', $cookies );
00209         }
00210 
00217         public function parseCookieResponseHeader ( $cookie, $domain ) {
00218                 $len = strlen( 'Set-Cookie:' );
00219 
00220                 if ( substr_compare( 'Set-Cookie:', $cookie, 0, $len, true ) === 0 ) {
00221                         $cookie = substr( $cookie, $len );
00222                 }
00223 
00224                 $bit = array_map( 'trim', explode( ';', $cookie ) );
00225 
00226                 if ( count( $bit ) >= 1 ) {
00227                         list( $name, $value ) = explode( '=', array_shift( $bit ), 2 );
00228                         $attr = array();
00229 
00230                         foreach ( $bit as $piece ) {
00231                                 $parts = explode( '=', $piece );
00232                                 if ( count( $parts ) > 1 ) {
00233                                         $attr[strtolower( $parts[0] )] = $parts[1];
00234                                 } else {
00235                                         $attr[strtolower( $parts[0] )] = true;
00236                                 }
00237                         }
00238 
00239                         if ( !isset( $attr['domain'] ) ) {
00240                                 $attr['domain'] = $domain;
00241                         } elseif ( !Cookie::validateCookieDomain( $attr['domain'], $domain ) ) {
00242                                 return null;
00243                         }
00244 
00245                         $this->setCookie( $name, $value, $attr );
00246                 }
00247         }
00248 }