MediaWiki  REL1_20
Cookie.php
Go to the documentation of this file.
00001 <?php
00024 class Cookie {
00025         protected $name;
00026         protected $value;
00027         protected $expires;
00028         protected $path;
00029         protected $domain;
00030         protected $isSessionKey = true;
00031         // TO IMPLEMENT  protected $secure
00032         // TO IMPLEMENT? protected $maxAge (add onto expires)
00033         // TO IMPLEMENT? protected $version
00034         // TO IMPLEMENT? protected $comment
00035 
00036         function __construct( $name, $value, $attr ) {
00037                 $this->name = $name;
00038                 $this->set( $value, $attr );
00039         }
00040 
00052         public function set( $value, $attr ) {
00053                 $this->value = $value;
00054 
00055                 if ( isset( $attr['expires'] ) ) {
00056                         $this->isSessionKey = false;
00057                         $this->expires = strtotime( $attr['expires'] );
00058                 }
00059 
00060                 if ( isset( $attr['path'] ) ) {
00061                         $this->path = $attr['path'];
00062                 } else {
00063                         $this->path = '/';
00064                 }
00065 
00066                 if ( isset( $attr['domain'] ) ) {
00067                         if ( self::validateCookieDomain( $attr['domain'] ) ) {
00068                                 $this->domain = $attr['domain'];
00069                         }
00070                 } else {
00071                         throw new MWException( 'You must specify a domain.' );
00072                 }
00073         }
00074 
00090         public static function validateCookieDomain( $domain, $originDomain = null ) {
00091                 // Don't allow a trailing dot
00092                 if ( substr( $domain, -1 ) == '.' ) {
00093                         return false;
00094                 }
00095 
00096                 $dc = explode( ".", $domain );
00097 
00098                 // Only allow full, valid IP addresses
00099                 if ( preg_match( '/^[0-9.]+$/', $domain ) ) {
00100                         if ( count( $dc ) != 4 ) {
00101                                 return false;
00102                         }
00103 
00104                         if ( ip2long( $domain ) === false ) {
00105                                 return false;
00106                         }
00107 
00108                         if ( $originDomain == null || $originDomain == $domain ) {
00109                                 return true;
00110                         }
00111 
00112                 }
00113 
00114                 // Don't allow cookies for "co.uk" or "gov.uk", etc, but allow "supermarket.uk"
00115                 if ( strrpos( $domain, "." ) - strlen( $domain )  == -3 ) {
00116                         if ( ( count( $dc ) == 2 && strlen( $dc[0] ) <= 2 )
00117                                 || ( count( $dc ) == 3 && strlen( $dc[0] ) == "" && strlen( $dc[1] ) <= 2 ) ) {
00118                                 return false;
00119                         }
00120                         if ( ( count( $dc ) == 2 || ( count( $dc ) == 3 && $dc[0] == '' ) )
00121                                 && preg_match( '/(com|net|org|gov|edu)\...$/', $domain ) ) {
00122                                 return false;
00123                         }
00124                 }
00125 
00126                 if ( $originDomain != null ) {
00127                         if ( substr( $domain, 0, 1 ) != '.' && $domain != $originDomain ) {
00128                                 return false;
00129                         }
00130 
00131                         if ( substr( $domain, 0, 1 ) == '.'
00132                                 && substr_compare( $originDomain, $domain, -strlen( $domain ),
00133                                                                    strlen( $domain ), true ) != 0 ) {
00134                                 return false;
00135                         }
00136                 }
00137 
00138                 return true;
00139         }
00140 
00148         public function serializeToHttpRequest( $path, $domain ) {
00149                 $ret = '';
00150 
00151                 if ( $this->canServeDomain( $domain )
00152                                 && $this->canServePath( $path )
00153                                 && $this->isUnExpired() ) {
00154                         $ret = $this->name . '=' . $this->value;
00155                 }
00156 
00157                 return $ret;
00158         }
00159 
00164         protected function canServeDomain( $domain ) {
00165                 if ( $domain == $this->domain
00166                         || ( strlen( $domain ) > strlen( $this->domain )
00167                                  && substr( $this->domain, 0, 1 ) == '.'
00168                                  && substr_compare( $domain, $this->domain, -strlen( $this->domain ),
00169                                                                         strlen( $this->domain ), true ) == 0 ) ) {
00170                         return true;
00171                 }
00172 
00173                 return false;
00174         }
00175 
00180         protected function canServePath( $path ) {
00181                 return ( $this->path && substr_compare( $this->path, $path, 0, strlen( $this->path ) ) == 0 );
00182         }
00183 
00187         protected function isUnExpired() {
00188                 return $this->isSessionKey || $this->expires > time();
00189         }
00190 }
00191 
00192 class CookieJar {
00193         private $cookie = array();
00194 
00199         public function setCookie ( $name, $value, $attr ) {
00200                 /* cookies: case insensitive, so this should work.
00201                  * We'll still send the cookies back in the same case we got them, though.
00202                  */
00203                 $index = strtoupper( $name );
00204 
00205                 if ( isset( $this->cookie[$index] ) ) {
00206                         $this->cookie[$index]->set( $value, $attr );
00207                 } else {
00208                         $this->cookie[$index] = new Cookie( $name, $value, $attr );
00209                 }
00210         }
00211 
00216         public function serializeToHttpRequest( $path, $domain ) {
00217                 $cookies = array();
00218 
00219                 foreach ( $this->cookie as $c ) {
00220                         $serialized = $c->serializeToHttpRequest( $path, $domain );
00221 
00222                         if ( $serialized ) {
00223                                 $cookies[] = $serialized;
00224                         }
00225                 }
00226 
00227                 return implode( '; ', $cookies );
00228         }
00229 
00237         public function parseCookieResponseHeader ( $cookie, $domain ) {
00238                 $len = strlen( 'Set-Cookie:' );
00239 
00240                 if ( substr_compare( 'Set-Cookie:', $cookie, 0, $len, true ) === 0 ) {
00241                         $cookie = substr( $cookie, $len );
00242                 }
00243 
00244                 $bit = array_map( 'trim', explode( ';', $cookie ) );
00245 
00246                 if ( count( $bit ) >= 1 ) {
00247                         list( $name, $value ) = explode( '=', array_shift( $bit ), 2 );
00248                         $attr = array();
00249 
00250                         foreach ( $bit as $piece ) {
00251                                 $parts = explode( '=', $piece );
00252                                 if ( count( $parts ) > 1 ) {
00253                                         $attr[strtolower( $parts[0] )] = $parts[1];
00254                                 } else {
00255                                         $attr[strtolower( $parts[0] )] = true;
00256                                 }
00257                         }
00258 
00259                         if ( !isset( $attr['domain'] ) ) {
00260                                 $attr['domain'] = $domain;
00261                         } elseif ( !Cookie::validateCookieDomain( $attr['domain'], $domain ) ) {
00262                                 return null;
00263                         }
00264 
00265                         $this->setCookie( $name, $value, $attr );
00266                 }
00267         }
00268 }