source: trunk/server/www/vendors/simpletest/cookies.php @ 6

Last change on this file since 6 was 6, checked in by sander, 11 years ago

Added SimpleTest? test framework

File size: 11.5 KB
Line 
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 */
12require_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 */
23class 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 */
228class 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?>
Note: See TracBrowser for help on using the repository browser.