MediaWiki
REL1_20
|
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 }