Wordpress 4.6
[autoinstalls/wordpress.git] / wp-includes / class-wp-http-cookie.php
1 <?php
2 /**
3  * HTTP API: WP_Http_Cookie class
4  *
5  * @package WordPress
6  * @subpackage HTTP
7  * @since 4.4.0
8  */
9
10 /**
11  * Core class used to encapsulate a single cookie object for internal use.
12  *
13  * Returned cookies are represented using this class, and when cookies are set, if they are not
14  * already a WP_Http_Cookie() object, then they are turned into one.
15  *
16  * @todo The WordPress convention is to use underscores instead of camelCase for function and method
17  * names. Need to switch to use underscores instead for the methods.
18  *
19  * @since 2.8.0
20  */
21 class WP_Http_Cookie {
22
23         /**
24          * Cookie name.
25          *
26          * @since 2.8.0
27          * @var string
28          */
29         public $name;
30
31         /**
32          * Cookie value.
33          *
34          * @since 2.8.0
35          * @var string
36          */
37         public $value;
38
39         /**
40          * When the cookie expires.
41          *
42          * @since 2.8.0
43          * @var string
44          */
45         public $expires;
46
47         /**
48          * Cookie URL path.
49          *
50          * @since 2.8.0
51          * @var string
52          */
53         public $path;
54
55         /**
56          * Cookie Domain.
57          *
58          * @since 2.8.0
59          * @var string
60          */
61         public $domain;
62
63         /**
64          * Sets up this cookie object.
65          *
66          * The parameter $data should be either an associative array containing the indices names below
67          * or a header string detailing it.
68          *
69          * @since 2.8.0
70          * @access public
71          *
72          * @param string|array $data {
73          *     Raw cookie data as header string or data array.
74          *
75          *     @type string     $name    Cookie name.
76          *     @type mixed      $value   Value. Should NOT already be urlencoded.
77          *     @type string|int $expires Optional. Unix timestamp or formatted date. Default null.
78          *     @type string     $path    Optional. Path. Default '/'.
79          *     @type string     $domain  Optional. Domain. Default host of parsed $requested_url.
80          *     @type int        $port    Optional. Port. Default null.
81          * }
82          * @param string       $requested_url The URL which the cookie was set on, used for default $domain
83          *                                    and $port values.
84          */
85         public function __construct( $data, $requested_url = '' ) {
86                 if ( $requested_url )
87                         $arrURL = @parse_url( $requested_url );
88                 if ( isset( $arrURL['host'] ) )
89                         $this->domain = $arrURL['host'];
90                 $this->path = isset( $arrURL['path'] ) ? $arrURL['path'] : '/';
91                 if (  '/' != substr( $this->path, -1 ) )
92                         $this->path = dirname( $this->path ) . '/';
93
94                 if ( is_string( $data ) ) {
95                         // Assume it's a header string direct from a previous request.
96                         $pairs = explode( ';', $data );
97
98                         // Special handling for first pair; name=value. Also be careful of "=" in value.
99                         $name  = trim( substr( $pairs[0], 0, strpos( $pairs[0], '=' ) ) );
100                         $value = substr( $pairs[0], strpos( $pairs[0], '=' ) + 1 );
101                         $this->name  = $name;
102                         $this->value = urldecode( $value );
103
104                         // Removes name=value from items.
105                         array_shift( $pairs );
106
107                         // Set everything else as a property.
108                         foreach ( $pairs as $pair ) {
109                                 $pair = rtrim($pair);
110
111                                 // Handle the cookie ending in ; which results in a empty final pair.
112                                 if ( empty($pair) )
113                                         continue;
114
115                                 list( $key, $val ) = strpos( $pair, '=' ) ? explode( '=', $pair ) : array( $pair, '' );
116                                 $key = strtolower( trim( $key ) );
117                                 if ( 'expires' == $key )
118                                         $val = strtotime( $val );
119                                 $this->$key = $val;
120                         }
121                 } else {
122                         if ( !isset( $data['name'] ) )
123                                 return;
124
125                         // Set properties based directly on parameters.
126                         foreach ( array( 'name', 'value', 'path', 'domain', 'port' ) as $field ) {
127                                 if ( isset( $data[ $field ] ) )
128                                         $this->$field = $data[ $field ];
129                         }
130
131                         if ( isset( $data['expires'] ) )
132                                 $this->expires = is_int( $data['expires'] ) ? $data['expires'] : strtotime( $data['expires'] );
133                         else
134                                 $this->expires = null;
135                 }
136         }
137
138         /**
139          * Confirms that it's OK to send this cookie to the URL checked against.
140          *
141          * Decision is based on RFC 2109/2965, so look there for details on validity.
142          *
143          * @access public
144          * @since 2.8.0
145          *
146          * @param string $url URL you intend to send this cookie to
147          * @return bool true if allowed, false otherwise.
148          */
149         public function test( $url ) {
150                 if ( is_null( $this->name ) )
151                         return false;
152
153                 // Expires - if expired then nothing else matters.
154                 if ( isset( $this->expires ) && time() > $this->expires )
155                         return false;
156
157                 // Get details on the URL we're thinking about sending to.
158                 $url = parse_url( $url );
159                 $url['port'] = isset( $url['port'] ) ? $url['port'] : ( 'https' == $url['scheme'] ? 443 : 80 );
160                 $url['path'] = isset( $url['path'] ) ? $url['path'] : '/';
161
162                 // Values to use for comparison against the URL.
163                 $path   = isset( $this->path )   ? $this->path   : '/';
164                 $port   = isset( $this->port )   ? $this->port   : null;
165                 $domain = isset( $this->domain ) ? strtolower( $this->domain ) : strtolower( $url['host'] );
166                 if ( false === stripos( $domain, '.' ) )
167                         $domain .= '.local';
168
169                 // Host - very basic check that the request URL ends with the domain restriction (minus leading dot).
170                 $domain = substr( $domain, 0, 1 ) == '.' ? substr( $domain, 1 ) : $domain;
171                 if ( substr( $url['host'], -strlen( $domain ) ) != $domain )
172                         return false;
173
174                 // Port - supports "port-lists" in the format: "80,8000,8080".
175                 if ( !empty( $port ) && !in_array( $url['port'], explode( ',', $port) ) )
176                         return false;
177
178                 // Path - request path must start with path restriction.
179                 if ( substr( $url['path'], 0, strlen( $path ) ) != $path )
180                         return false;
181
182                 return true;
183         }
184
185         /**
186          * Convert cookie name and value back to header string.
187          *
188          * @access public
189          * @since 2.8.0
190          *
191          * @return string Header encoded cookie name and value.
192          */
193         public function getHeaderValue() {
194                 if ( ! isset( $this->name ) || ! isset( $this->value ) )
195                         return '';
196
197                 /**
198                  * Filters the header-encoded cookie value.
199                  *
200                  * @since 3.4.0
201                  *
202                  * @param string $value The cookie value.
203                  * @param string $name  The cookie name.
204                  */
205                 return $this->name . '=' . apply_filters( 'wp_http_cookie_value', $this->value, $this->name );
206         }
207
208         /**
209          * Retrieve cookie header for usage in the rest of the WordPress HTTP API.
210          *
211          * @access public
212          * @since 2.8.0
213          *
214          * @return string
215          */
216         public function getFullHeader() {
217                 return 'Cookie: ' . $this->getHeaderValue();
218         }
219
220         /**
221          * Retrieves cookie attributes.
222          *
223          * @since 4.6.0
224          * @access public
225          *
226          * @return array {
227          *    List of attributes.
228          *
229          *    @type string $expires When the cookie expires.
230          *    @type string $path    Cookie URL path.
231          *    @type string $domain  Cookie domain.
232          * }
233          */
234         public function get_attributes() {
235                 return array(
236                         'expires' => $this->expires,
237                         'path'    => $this->path,
238                         'domain'  => $this->domain,
239                 );
240         }
241 }