Completed
Push — 3.5 ( 1a9180...1bec8a )
by Daniel
24s
created

SimpleCookie::__construct()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 13
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 6
nop 5
dl 0
loc 13
rs 9.2
c 0
b 0
f 0
1
<?php
2
/**
3
 *  Base include file for SimpleTest
4
 *  @package    SimpleTest
5
 *  @subpackage WebTester
6
 *  @version    $Id: cookies.php 1723 2008-04-08 00:34:10Z lastcraft $
7
 */
8
9
/**#@+
10
 *  include other SimpleTest class files
11
 */
12
require_once(dirname(__FILE__) . '/url.php');
13
/**#@-*/
14
15
/**
16
 *    Cookie data holder. Cookie rules are full of pretty
17
 *    arbitary stuff. I have used...
18
 *    http://wp.netscape.com/newsref/std/cookie_spec.html
19
 *    http://www.cookiecentral.com/faq/
20
 *    @package SimpleTest
21
 *    @subpackage WebTester
22
 */
23
class SimpleCookie {
24
    var $_host;
25
    var $_name;
26
    var $_value;
27
    var $_path;
28
    var $_expiry;
29
    var $_is_secure;
30
    
31
    /**
32
     *    Constructor. Sets the stored values.
33
     *    @param string $name            Cookie key.
34
     *    @param string $value           Value of cookie.
35
     *    @param string $path            Cookie path if not host wide.
36
     *    @param string $expiry          Expiry date as string.
37
     *    @param boolean $is_secure      Currently ignored.
38
     */
39
    function SimpleCookie($name, $value = false, $path = false, $expiry = false, $is_secure = false) {
40
        $this->_host = false;
41
        $this->_name = $name;
42
        $this->_value = $value;
43
        $this->_path = ($path ? $this->_fixPath($path) : "/");
44
        $this->_expiry = false;
45
        if (is_string($expiry)) {
46
            $this->_expiry = strtotime($expiry);
47
        } elseif (is_integer($expiry)) {
48
            $this->_expiry = $expiry;
49
        }
50
        $this->_is_secure = $is_secure;
51
    }
52
    
53
    /**
54
     *    Sets the host. The cookie rules determine
55
     *    that the first two parts are taken for
56
     *    certain TLDs and three for others. If the
57
     *    new host does not match these rules then the
58
     *    call will fail.
59
     *    @param string $host       New hostname.
60
     *    @return boolean           True if hostname is valid.
61
     *    @access public
62
     */
63
    function setHost($host) {
64
        if ($host = $this->_truncateHost($host)) {
65
            $this->_host = $host;
66
            return true;
67
        }
68
        return false;
69
    }
70
    
71
    /**
72
     *    Accessor for the truncated host to which this
73
     *    cookie applies.
74
     *    @return string       Truncated hostname.
75
     *    @access public
76
     */
77
    function getHost() {
78
        return $this->_host;
79
    }
80
    
81
    /**
82
     *    Test for a cookie being valid for a host name.
83
     *    @param string $host    Host to test against.
84
     *    @return boolean        True if the cookie would be valid
85
     *                           here.
86
     */
87
    function isValidHost($host) {
88
        return ($this->_truncateHost($host) === $this->getHost());
89
    }
90
    
91
    /**
92
     *    Extracts just the domain part that determines a
93
     *    cookie's host validity.
94
     *    @param string $host    Host name to truncate.
95
     *    @return string        Domain or false on a bad host.
96
     *    @access private
97
     */
98
    function _truncateHost($host) {
99
        $tlds = SimpleUrl::getAllTopLevelDomains();
100
        if (preg_match('/[a-z\-]+\.(' . $tlds . ')$/i', $host, $matches)) {
101
            return $matches[0];
102
        } elseif (preg_match('/[a-z\-]+\.[a-z\-]+\.[a-z\-]+$/i', $host, $matches)) {
103
            return $matches[0];
104
        }
105
        return false;
106
    }
107
    
108
    /**
109
     *    Accessor for name.
110
     *    @return string       Cookie key.
111
     *    @access public
112
     */
113
    function getName() {
114
        return $this->_name;
115
    }
116
    
117
    /**
118
     *    Accessor for value. A deleted cookie will
119
     *    have an empty string for this.
120
     *    @return string       Cookie value.
121
     *    @access public
122
     */
123
    function getValue() {
124
        return $this->_value;
125
    }
126
    
127
    /**
128
     *    Accessor for path.
129
     *    @return string       Valid cookie path.
130
     *    @access public
131
     */
132
    function getPath() {
133
        return $this->_path;
134
    }
135
    
136
    /**
137
     *    Tests a path to see if the cookie applies
138
     *    there. The test path must be longer or
139
     *    equal to the cookie path.
140
     *    @param string $path       Path to test against.
141
     *    @return boolean           True if cookie valid here.
142
     *    @access public
143
     */
144
    function isValidPath($path) {
145
        return (strncmp(
146
                $this->_fixPath($path),
147
                $this->getPath(),
148
                strlen($this->getPath())) == 0);
149
    }
150
    
151
    /**
152
     *    Accessor for expiry.
153
     *    @return string       Expiry string.
154
     *    @access public
155
     */
156
    function getExpiry() {
157
        if (! $this->_expiry) {
158
            return false;
159
        }
160
        return gmdate("D, d M Y H:i:s", $this->_expiry) . " GMT";
161
    }
162
    
163
    /**
164
     *    Test to see if cookie is expired against
165
     *    the cookie format time or timestamp.
166
     *    Will give true for a session cookie.
167
     *    @param integer/string $now  Time to test against. Result
168
     *                                will be false if this time
169
     *                                is later than the cookie expiry.
170
     *                                Can be either a timestamp integer
171
     *                                or a cookie format date.
172
     *    @access public
173
     */
174
    function isExpired($now) {
175
        if (! $this->_expiry) {
176
            return true;
177
        }
178
        if (is_string($now)) {
179
            $now = strtotime($now);
180
        }
181
        return ($this->_expiry < $now);
182
    }
183
    
184
    /**
185
     *    Ages the cookie by the specified number of
186
     *    seconds.
187
     *    @param integer $interval   In seconds.
188
     *    @public
189
     */
190
    function agePrematurely($interval) {
191
        if ($this->_expiry) {
192
            $this->_expiry -= $interval;
193
        }
194
    }
195
    
196
    /**
197
     *    Accessor for the secure flag.
198
     *    @return boolean       True if cookie needs SSL.
199
     *    @access public
200
     */
201
    function isSecure() {
202
        return $this->_is_secure;
203
    }
204
    
205
    /**
206
     *    Adds a trailing and leading slash to the path
207
     *    if missing.
208
     *    @param string $path            Path to fix.
209
     *    @access private
210
     */
211
    function _fixPath($path) {
212
        if (substr($path, 0, 1) != '/') {
213
            $path = '/' . $path;
214
        }
215
        if (substr($path, -1, 1) != '/') {
216
            $path .= '/';
217
        }
218
        return $path;
219
    }
220
}
221
222
/**
223
 *    Repository for cookies. This stuff is a
224
 *    tiny bit browser dependent.
225
 *    @package SimpleTest
226
 *    @subpackage WebTester
227
 */
228
class SimpleCookieJar {
229
    var $_cookies;
230
    
231
    /**
232
     *    Constructor. Jar starts empty.
233
     *    @access public
234
     */
235
    function SimpleCookieJar() {
236
        $this->_cookies = array();
237
    }
238
    
239
    /**
240
     *    Removes expired and temporary cookies as if
241
     *    the browser was closed and re-opened.
242
     *    @param string/integer $now   Time to test expiry against.
243
     *    @access public
244
     */
245
    function restartSession($date = false) {
246
        $surviving_cookies = array();
247
        for ($i = 0; $i < count($this->_cookies); $i++) {
248
            if (! $this->_cookies[$i]->getValue()) {
249
                continue;
250
            }
251
            if (! $this->_cookies[$i]->getExpiry()) {
252
                continue;
253
            }
254
            if ($date && $this->_cookies[$i]->isExpired($date)) {
255
                continue;
256
            }
257
            $surviving_cookies[] = $this->_cookies[$i];
258
        }
259
        $this->_cookies = $surviving_cookies;
260
    }
261
    
262
    /**
263
     *    Ages all cookies in the cookie jar.
264
     *    @param integer $interval     The old session is moved
265
     *                                 into the past by this number
266
     *                                 of seconds. Cookies now over
267
     *                                 age will be removed.
268
     *    @access public
269
     */
270
    function agePrematurely($interval) {
271
        for ($i = 0; $i < count($this->_cookies); $i++) {
272
            $this->_cookies[$i]->agePrematurely($interval);
273
        }
274
    }
275
    
276
    /**
277
     *    Sets an additional cookie. If a cookie has
278
     *    the same name and path it is replaced.
279
     *    @param string $name       Cookie key.
280
     *    @param string $value      Value of cookie.
281
     *    @param string $host       Host upon which the cookie is valid.
282
     *    @param string $path       Cookie path if not host wide.
283
     *    @param string $expiry     Expiry date.
284
     *    @access public
285
     */
286
    function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
287
        $cookie = new SimpleCookie($name, $value, $path, $expiry);
288
        if ($host) {
289
            $cookie->setHost($host);
290
        }
291
        $this->_cookies[$this->_findFirstMatch($cookie)] = $cookie;
292
    }
293
    
294
    /**
295
     *    Finds a matching cookie to write over or the
296
     *    first empty slot if none.
297
     *    @param SimpleCookie $cookie    Cookie to write into jar.
298
     *    @return integer                Available slot.
299
     *    @access private
300
     */
301
    function _findFirstMatch($cookie) {
302
        for ($i = 0; $i < count($this->_cookies); $i++) {
303
            $is_match = $this->_isMatch(
304
                    $cookie,
305
                    $this->_cookies[$i]->getHost(),
306
                    $this->_cookies[$i]->getPath(),
307
                    $this->_cookies[$i]->getName());
308
            if ($is_match) {
309
                return $i;
310
            }
311
        }
312
        return count($this->_cookies);
313
    }
314
    
315
    /**
316
     *    Reads the most specific cookie value from the
317
     *    browser cookies. Looks for the longest path that
318
     *    matches.
319
     *    @param string $host        Host to search.
320
     *    @param string $path        Applicable path.
321
     *    @param string $name        Name of cookie to read.
322
     *    @return string             False if not present, else the
323
     *                               value as a string.
324
     *    @access public
325
     */
326
    function getCookieValue($host, $path, $name) {
327
        $longest_path = '';
328
        foreach ($this->_cookies as $cookie) {
329
            if ($this->_isMatch($cookie, $host, $path, $name)) {
330
                if (strlen($cookie->getPath()) > strlen($longest_path)) {
331
                    $value = $cookie->getValue();
332
                    $longest_path = $cookie->getPath();
333
                }
334
            }
335
        }
336
        return (isset($value) ? $value : false);
337
    }
338
    
339
    /**
340
     *    Tests cookie for matching against search
341
     *    criteria.
342
     *    @param SimpleTest $cookie    Cookie to test.
343
     *    @param string $host          Host must match.
344
     *    @param string $path          Cookie path must be shorter than
345
     *                                 this path.
346
     *    @param string $name          Name must match.
347
     *    @return boolean              True if matched.
348
     *    @access private
349
     */
350
    function _isMatch($cookie, $host, $path, $name) {
351
        if ($cookie->getName() != $name) {
352
            return false;
353
        }
354
        if ($host && $cookie->getHost() && ! $cookie->isValidHost($host)) {
355
            return false;
356
        }
357
        if (! $cookie->isValidPath($path)) {
358
            return false;
359
        }
360
        return true;
361
    }
362
    
363
    /**
364
     *    Uses a URL to sift relevant cookies by host and
365
     *    path. Results are list of strings of form "name=value".
366
     *    @param SimpleUrl $url       Url to select by.
367
     *    @return array               Valid name and value pairs.
368
     *    @access public
369
     */
370
    function selectAsPairs($url) {
371
        $pairs = array();
372
        foreach ($this->_cookies as $cookie) {
373
            if ($this->_isMatch($cookie, $url->getHost(), $url->getPath(), $cookie->getName())) {
374
                $pairs[] = $cookie->getName() . '=' . $cookie->getValue();
375
            }
376
        }
377
        return $pairs;
378
    }
379
}
380
?>
381