diff options
author | Nicolas LÅ“uillet <nicolas.loeuillet@gmail.com> | 2013-08-25 20:10:23 +0200 |
---|---|---|
committer | Nicolas LÅ“uillet <nicolas.loeuillet@gmail.com> | 2013-08-25 20:10:23 +0200 |
commit | ec3972361d95f6f5956df77f7a76105b5ae6af72 (patch) | |
tree | 316396d15290941f20b633fbe4f44d4427af4291 /inc/3rdparty/humble-http-agent/CookieJar.php | |
parent | fccd59e2e303cdbb45293365bf92921b831bf140 (diff) | |
download | wallabag-ec3972361d95f6f5956df77f7a76105b5ae6af72.tar.gz wallabag-ec3972361d95f6f5956df77f7a76105b5ae6af72.tar.zst wallabag-ec3972361d95f6f5956df77f7a76105b5ae6af72.zip |
poche now uses Full Text RSS to fetch content
Diffstat (limited to 'inc/3rdparty/humble-http-agent/CookieJar.php')
-rw-r--r-- | inc/3rdparty/humble-http-agent/CookieJar.php | 404 |
1 files changed, 404 insertions, 0 deletions
diff --git a/inc/3rdparty/humble-http-agent/CookieJar.php b/inc/3rdparty/humble-http-agent/CookieJar.php new file mode 100644 index 00000000..d91b711e --- /dev/null +++ b/inc/3rdparty/humble-http-agent/CookieJar.php | |||
@@ -0,0 +1,404 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * Cookie Jar | ||
4 | * | ||
5 | * PHP class for handling cookies, as defined by the Netscape spec: | ||
6 | * <http://curl.haxx.se/rfc/cookie_spec.html> | ||
7 | * | ||
8 | * This class should be used to handle cookies (storing cookies from HTTP response messages, and | ||
9 | * sending out cookies in HTTP request messages). This has been adapted for FiveFilters.org | ||
10 | * from the original version used in HTTP Navigator. See http://www.keyvan.net/code/http-navigator/ | ||
11 | * | ||
12 | * This class is mainly based on Cookies.pm <http://search.cpan.org/author/GAAS/libwww-perl-5.65/ | ||
13 | * lib/HTTP/Cookies.pm> from the libwww-perl collection <http://www.linpro.no/lwp/>. | ||
14 | * Unlike Cookies.pm, this class only supports the Netscape cookie spec, not RFC 2965. | ||
15 | * | ||
16 | * @version 0.5 | ||
17 | * @date 2011-03-15 | ||
18 | * @see http://php.net/HttpRequestPool | ||
19 | * @author Keyvan Minoukadeh | ||
20 | * @copyright 2011 Keyvan Minoukadeh | ||
21 | * @license http://www.gnu.org/licenses/agpl-3.0.html AGPL v3 | ||
22 | */ | ||
23 | |||
24 | class CookieJar | ||
25 | { | ||
26 | /** | ||
27 | * Cookies - array containing all cookies. | ||
28 | * | ||
29 | * <pre> | ||
30 | * Cookies are stored like this: | ||
31 | * [domain][path][name] = array | ||
32 | * where array is: | ||
33 | * 0 => value, 1 => secure, 2 => expires | ||
34 | * </pre> | ||
35 | * @var array | ||
36 | * @access private | ||
37 | */ | ||
38 | public $cookies = array(); | ||
39 | public $debug = false; | ||
40 | |||
41 | /** | ||
42 | * Constructor | ||
43 | */ | ||
44 | function __construct() { | ||
45 | } | ||
46 | |||
47 | protected function debug($msg, $file=null, $line=null) { | ||
48 | if ($this->debug) { | ||
49 | $mem = round(memory_get_usage()/1024, 2); | ||
50 | $memPeak = round(memory_get_peak_usage()/1024, 2); | ||
51 | echo '* ',$msg; | ||
52 | if (isset($file, $line)) echo " ($file line $line)"; | ||
53 | echo ' - mem used: ',$mem," (peak: $memPeak)\n"; | ||
54 | ob_flush(); | ||
55 | flush(); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Get matching cookies | ||
61 | * | ||
62 | * Only use this method if you cannot use add_cookie_header(), for example, if you want to use | ||
63 | * this cookie jar class without using the request class. | ||
64 | * | ||
65 | * @param array $param associative array containing 'domain', 'path', 'secure' keys | ||
66 | * @return string | ||
67 | * @see add_cookie_header() | ||
68 | */ | ||
69 | public function getMatchingCookies($url) | ||
70 | { | ||
71 | if (($parts = @parse_url($url)) && isset($parts['scheme'], $parts['host'], $parts['path'])) { | ||
72 | $param['domain'] = $parts['host']; | ||
73 | $param['path'] = $parts['path']; | ||
74 | $param['secure'] = (strtolower($parts['scheme']) == 'https'); | ||
75 | unset($parts); | ||
76 | } else { | ||
77 | return false; | ||
78 | } | ||
79 | // RFC 2965 notes: | ||
80 | // If multiple cookies satisfy the criteria above, they are ordered in | ||
81 | // the Cookie header such that those with more specific Path attributes | ||
82 | // precede those with less specific. Ordering with respect to other | ||
83 | // attributes (e.g., Domain) is unspecified. | ||
84 | $domain = $param['domain']; | ||
85 | if (strpos($domain, '.') === false) $domain .= '.local'; | ||
86 | $request_path = $param['path']; | ||
87 | if ($request_path == '') $request_path = '/'; | ||
88 | $request_secure = $param['secure']; | ||
89 | $now = time(); | ||
90 | $matched_cookies = array(); | ||
91 | // domain - find matching domains | ||
92 | $this->debug('Finding matching domains for '.$domain, __FILE__, __LINE__); | ||
93 | while (strpos($domain, '.') !== false) { | ||
94 | if (isset($this->cookies[$domain])) { | ||
95 | $this->debug(' domain match found: '.$domain); | ||
96 | $cookies =& $this->cookies[$domain]; | ||
97 | } else { | ||
98 | $domain = $this->_reduce_domain($domain); | ||
99 | continue; | ||
100 | } | ||
101 | // paths - find matching paths starting from most specific | ||
102 | $this->debug(' - Finding matching paths for '.$request_path); | ||
103 | $paths = array_keys($cookies); | ||
104 | usort($paths, array($this, '_cmp_length')); | ||
105 | foreach ($paths as $path) { | ||
106 | // continue to next cookie if request path does not path-match cookie path | ||
107 | if (!$this->_path_match($request_path, $path)) continue; | ||
108 | // loop through cookie names | ||
109 | $this->debug(' path match found: '.$path); | ||
110 | foreach ($cookies[$path] as $name => $values) { | ||
111 | // if this cookie is secure but request isn't, continue to next cookie | ||
112 | if ($values[1] && !$request_secure) continue; | ||
113 | // if cookie is not a session cookie and has expired, continue to next cookie | ||
114 | if (is_int($values[2]) && ($values[2] < $now)) continue; | ||
115 | // cookie matches request | ||
116 | $this->debug(' cookie match: '.$name.'='.$values[0]); | ||
117 | $matched_cookies[] = $name.'='.$values[0]; | ||
118 | } | ||
119 | } | ||
120 | $domain = $this->_reduce_domain($domain); | ||
121 | } | ||
122 | // return cookies | ||
123 | return implode('; ', $matched_cookies); | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * Parse Set-Cookie values. | ||
128 | * | ||
129 | * Only use this method if you cannot use extract_cookies(), for example, if you want to use | ||
130 | * this cookie jar class without using the response class. | ||
131 | * | ||
132 | * @param array $set_cookies array holding 1 or more "Set-Cookie" header values | ||
133 | * @param array $param associative array containing 'host', 'path' keys | ||
134 | * @return void | ||
135 | * @see extract_cookies() | ||
136 | */ | ||
137 | public function storeCookies($url, $set_cookies) | ||
138 | { | ||
139 | if (count($set_cookies) == 0) return; | ||
140 | $param = @parse_url($url); | ||
141 | if (!is_array($param) || !isset($param['host'])) return; | ||
142 | $request_host = $param['host']; | ||
143 | if (strpos($request_host, '.') === false) $request_host .= '.local'; | ||
144 | $request_path = @$param['path']; | ||
145 | if ($request_path == '') $request_path = '/'; | ||
146 | // | ||
147 | // loop through set-cookie headers | ||
148 | // | ||
149 | foreach ($set_cookies as $set_cookie) { | ||
150 | $this->debug('Parsing: '.$set_cookie); | ||
151 | // temporary cookie store (before adding to jar) | ||
152 | $tmp_cookie = array(); | ||
153 | $param = explode(';', $set_cookie); | ||
154 | // loop through params | ||
155 | for ($x=0; $x<count($param); $x++) { | ||
156 | $key_val = explode('=', $param[$x], 2); | ||
157 | if (count($key_val) != 2) { | ||
158 | // if the first param isn't a name=value pair, continue to the next set-cookie | ||
159 | // header | ||
160 | if ($x == 0) continue 2; | ||
161 | // check for secure flag | ||
162 | if (strtolower(trim($key_val[0])) == 'secure') $tmp_cookie['secure'] = true; | ||
163 | // continue to next param | ||
164 | continue; | ||
165 | } | ||
166 | list($key, $val) = array_map('trim', $key_val); | ||
167 | // first name=value pair is the cookie name and value | ||
168 | // the name and value are stored under 'name' and 'value' to avoid conflicts | ||
169 | // with later parameters. | ||
170 | if ($x == 0) { | ||
171 | $tmp_cookie = array('name'=>$key, 'value'=>$val); | ||
172 | continue; | ||
173 | } | ||
174 | $key = strtolower($key); | ||
175 | if (in_array($key, array('expires', 'path', 'domain', 'secure'))) { | ||
176 | $tmp_cookie[$key] = $val; | ||
177 | } | ||
178 | } | ||
179 | // | ||
180 | // set cookie | ||
181 | // | ||
182 | // check domain | ||
183 | if (isset($tmp_cookie['domain']) && ($tmp_cookie['domain'] != $request_host) && | ||
184 | ($tmp_cookie['domain'] != ".$request_host")) { | ||
185 | $domain = $tmp_cookie['domain']; | ||
186 | if ((strpos($domain, '.') === false) && ($domain != 'local')) { | ||
187 | $this->debug(' - domain "'.$domain.'" has no dot and is not a local domain'); | ||
188 | continue; | ||
189 | } | ||
190 | if (preg_match('/\.[0-9]+$/', $domain)) { | ||
191 | $this->debug(' - domain "'.$domain.'" appears to be an ip address'); | ||
192 | continue; | ||
193 | } | ||
194 | if (substr($domain, 0, 1) != '.') $domain = ".$domain"; | ||
195 | if (!$this->_domain_match($request_host, $domain)) { | ||
196 | $this->debug(' - request host "'.$request_host.'" does not domain-match "'.$domain.'"'); | ||
197 | continue; | ||
198 | } | ||
199 | } else { | ||
200 | // if domain is not specified in the set-cookie header, domain will default to | ||
201 | // the request host | ||
202 | $domain = $request_host; | ||
203 | } | ||
204 | // check path | ||
205 | if (isset($tmp_cookie['path']) && ($tmp_cookie['path'] != '')) { | ||
206 | $path = urldecode($tmp_cookie['path']); | ||
207 | if (!$this->_path_match($request_path, $path)) { | ||
208 | $this->debug(' - request path "'.$request_path.'" does not path-match "'.$path.'"'); | ||
209 | continue; | ||
210 | } | ||
211 | } else { | ||
212 | $path = $request_path; | ||
213 | $path = substr($path, 0, strrpos($path, '/')); | ||
214 | if ($path == '') $path = '/'; | ||
215 | } | ||
216 | // check if secure | ||
217 | $secure = (isset($tmp_cookie['secure'])) ? true : false; | ||
218 | // check expiry | ||
219 | if (isset($tmp_cookie['expires'])) { | ||
220 | if (($expires = strtotime($tmp_cookie['expires'])) < 0) { | ||
221 | $expires = null; | ||
222 | } | ||
223 | } else { | ||
224 | $expires = null; | ||
225 | } | ||
226 | // set cookie | ||
227 | $this->set_cookie($domain, $path, $tmp_cookie['name'], $tmp_cookie['value'], $secure, $expires); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | // return array of set-cookie values extracted from HTTP response headers (string $h) | ||
232 | public function extractCookies($h) { | ||
233 | $x = 0; | ||
234 | $lines = 0; | ||
235 | $headers = array(); | ||
236 | $last_match = false; | ||
237 | $h = explode("\n", $h); | ||
238 | foreach ($h as $line) { | ||
239 | $line = rtrim($line); | ||
240 | $lines++; | ||
241 | |||
242 | $trimmed_line = trim($line); | ||
243 | if (isset($line_last)) { | ||
244 | // check if we have \r\n\r\n (indicating the end of headers) | ||
245 | // some servers will not use CRLF (\r\n), so we make CR (\r) optional. | ||
246 | // if (preg_match('/\015?\012\015?\012/', $line_last.$line)) { | ||
247 | // break; | ||
248 | // } | ||
249 | // As an alternative, we can check if the current trimmed line is empty | ||
250 | if ($trimmed_line == '') { | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | // check for continuation line... | ||
255 | // RFC 2616 Section 2.2 "Basic Rules": | ||
256 | // HTTP/1.1 header field values can be folded onto multiple lines if the | ||
257 | // continuation line begins with a space or horizontal tab. All linear | ||
258 | // white space, including folding, has the same semantics as SP. A | ||
259 | // recipient MAY replace any linear white space with a single SP before | ||
260 | // interpreting the field value or forwarding the message downstream. | ||
261 | if ($last_match && preg_match('/^\s+(.*)/', $line, $match)) { | ||
262 | // append to previous header value | ||
263 | $headers[$x-1] .= ' '.rtrim($match[1]); | ||
264 | continue; | ||
265 | } | ||
266 | } | ||
267 | $line_last = $line; | ||
268 | |||
269 | // split header name and value | ||
270 | if (preg_match('/^Set-Cookie\s*:\s*(.*)/i', $line, $match)) { | ||
271 | $headers[$x++] = rtrim($match[1]); | ||
272 | $last_match = true; | ||
273 | } else { | ||
274 | $last_match = false; | ||
275 | } | ||
276 | } | ||
277 | return $headers; | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * Set Cookie | ||
282 | * @param string $domain | ||
283 | * @param string $path | ||
284 | * @param string $name cookie name | ||
285 | * @param string $value cookie value | ||
286 | * @param bool $secure | ||
287 | * @param int $expires expiry time (null if session cookie, <= 0 will delete cookie) | ||
288 | * @return void | ||
289 | */ | ||
290 | function set_cookie($domain, $path, $name, $value, $secure=false, $expires=null) | ||
291 | { | ||
292 | if ($domain == '') return; | ||
293 | if ($path == '') return; | ||
294 | if ($name == '') return; | ||
295 | // check if cookie needs to go | ||
296 | if (isset($expires) && ($expires <= 0)) { | ||
297 | if (isset($this->cookies[$domain][$path][$name])) unset($this->cookies[$domain][$path][$name]); | ||
298 | return; | ||
299 | } | ||
300 | if ($value == '') return; | ||
301 | $this->cookies[$domain][$path][$name] = array($value, $secure, $expires); | ||
302 | return; | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * Clear cookies - [domain [,path [,name]]] - call method with no arguments to clear all cookies. | ||
307 | * @param string $domain | ||
308 | * @param string $path | ||
309 | * @param string $name | ||
310 | * @return void | ||
311 | */ | ||
312 | function clear($domain=null, $path=null, $name=null) | ||
313 | { | ||
314 | if (!isset($domain)) { | ||
315 | $this->cookies = array(); | ||
316 | } elseif (!isset($path)) { | ||
317 | if (isset($this->cookies[$domain])) unset($this->cookies[$domain]); | ||
318 | } elseif (!isset($name)) { | ||
319 | if (isset($this->cookies[$domain][$path])) unset($this->cookies[$domain][$path]); | ||
320 | } elseif (isset($name)) { | ||
321 | if (isset($this->cookies[$domain][$path][$name])) unset($this->cookies[$domain][$path][$name]); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | /** | ||
326 | * Compare string length - used for sorting | ||
327 | * @access private | ||
328 | * @return int | ||
329 | */ | ||
330 | function _cmp_length($a, $b) | ||
331 | { | ||
332 | $la = strlen($a); $lb = strlen($b); | ||
333 | if ($la == $lb) return 0; | ||
334 | return ($la > $lb) ? -1 : 1; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * Reduce domain | ||
339 | * @param string $domain | ||
340 | * @return string | ||
341 | * @access private | ||
342 | */ | ||
343 | function _reduce_domain($domain) | ||
344 | { | ||
345 | if ($domain == '') return ''; | ||
346 | if (substr($domain, 0, 1) == '.') return substr($domain, 1); | ||
347 | return substr($domain, strpos($domain, '.')); | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * Path match - check if path1 path-matches path2 | ||
352 | * | ||
353 | * From RFC 2965: | ||
354 | * <i>For two strings that represent paths, P1 and P2, P1 path-matches P2 | ||
355 | * if P2 is a prefix of P1 (including the case where P1 and P2 string- | ||
356 | * compare equal). Thus, the string /tec/waldo path-matches /tec.</i> | ||
357 | * @param string $path1 | ||
358 | * @param string $path2 | ||
359 | * @return bool | ||
360 | * @access private | ||
361 | */ | ||
362 | function _path_match($path1, $path2) | ||
363 | { | ||
364 | return (substr($path1, 0, strlen($path2)) == $path2); | ||
365 | } | ||
366 | |||
367 | /** | ||
368 | * Domain match - check if domain1 domain-matches domain2 | ||
369 | * | ||
370 | * A few extracts from RFC 2965: | ||
371 | * - A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com | ||
372 | * would be rejected, because H is y.x and contains a dot. | ||
373 | * | ||
374 | * - A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com | ||
375 | * would be accepted. | ||
376 | * | ||
377 | * - A Set-Cookie2 with Domain=.com or Domain=.com., will always be | ||
378 | * rejected, because there is no embedded dot. | ||
379 | * | ||
380 | * - A Set-Cookie2 from request-host example for Domain=.local will | ||
381 | * be accepted, because the effective host name for the request- | ||
382 | * host is example.local, and example.local domain-matches .local. | ||
383 | * | ||
384 | * I'm ignoring the first point for now (must check to see how other browsers handle | ||
385 | * this rule for Set-Cookie headers) | ||
386 | * | ||
387 | * @param string $domain1 | ||
388 | * @param string $domain2 | ||
389 | * @return bool | ||
390 | * @access private | ||
391 | */ | ||
392 | function _domain_match($domain1, $domain2) | ||
393 | { | ||
394 | $domain1 = strtolower($domain1); | ||
395 | $domain2 = strtolower($domain2); | ||
396 | while (strpos($domain1, '.') !== false) { | ||
397 | if ($domain1 == $domain2) return true; | ||
398 | $domain1 = $this->_reduce_domain($domain1); | ||
399 | continue; | ||
400 | } | ||
401 | return false; | ||
402 | } | ||
403 | } | ||
404 | ?> \ No newline at end of file | ||