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