]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
lost cookie-jar file
authorEvan Prodromou <evan@status.net>
Wed, 22 Jun 2011 21:21:15 +0000 (17:21 -0400)
committerEvan Prodromou <evan@status.net>
Wed, 22 Jun 2011 21:21:15 +0000 (17:21 -0400)
extlib/HTTP/Request2/CookieJar.php [new file with mode: 0644]

diff --git a/extlib/HTTP/Request2/CookieJar.php b/extlib/HTTP/Request2/CookieJar.php
new file mode 100644 (file)
index 0000000..af7534f
--- /dev/null
@@ -0,0 +1,499 @@
+<?php\r
+/**\r
+ * Stores cookies and passes them between HTTP requests\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * LICENSE:\r
+ *\r
+ * Copyright (c) 2008-2011, Alexey Borzov <avb@php.net>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ *\r
+ *    * Redistributions of source code must retain the above copyright\r
+ *      notice, this list of conditions and the following disclaimer.\r
+ *    * Redistributions in binary form must reproduce the above copyright\r
+ *      notice, this list of conditions and the following disclaimer in the\r
+ *      documentation and/or other materials provided with the distribution.\r
+ *    * The names of the authors may not be used to endorse or promote products\r
+ *      derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\r
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ * @category   HTTP\r
+ * @package    HTTP_Request2\r
+ * @author     Alexey Borzov <avb@php.net>\r
+ * @license    http://opensource.org/licenses/bsd-license.php New BSD License\r
+ * @version    SVN: $Id: CookieJar.php 308629 2011-02-24 17:34:24Z avb $\r
+ * @link       http://pear.php.net/package/HTTP_Request2\r
+ */\r
+\r
+/** Class representing a HTTP request message */\r
+require_once 'HTTP/Request2.php';\r
+\r
+/**\r
+ * Stores cookies and passes them between HTTP requests\r
+ *\r
+ * @category   HTTP\r
+ * @package    HTTP_Request2\r
+ * @author     Alexey Borzov <avb@php.net>\r
+ * @version    Release: @package_version@\r
+ */\r
+class HTTP_Request2_CookieJar implements Serializable\r
+{\r
+   /**\r
+    * Array of stored cookies\r
+    *\r
+    * The array is indexed by domain, path and cookie name\r
+    *   .example.com\r
+    *     /\r
+    *       some_cookie => cookie data\r
+    *     /subdir\r
+    *       other_cookie => cookie data\r
+    *   .example.org\r
+    *     ...\r
+    *\r
+    * @var array\r
+    */\r
+    protected $cookies = array();\r
+\r
+   /**\r
+    * Whether session cookies should be serialized when serializing the jar\r
+    * @var bool\r
+    */\r
+    protected $serializeSession = false;\r
+\r
+   /**\r
+    * Whether Public Suffix List should be used for domain matching\r
+    * @var bool\r
+    */\r
+    protected $useList = true;\r
+\r
+   /**\r
+    * Array with Public Suffix List data\r
+    * @var  array\r
+    * @link http://publicsuffix.org/\r
+    */\r
+    protected static $psl = array();\r
+\r
+   /**\r
+    * Class constructor, sets various options\r
+    *\r
+    * @param bool Controls serializing session cookies, see {@link serializeSessionCookies()}\r
+    * @param bool Controls using Public Suffix List, see {@link usePublicSuffixList()}\r
+    */\r
+    public function __construct($serializeSessionCookies = false, $usePublicSuffixList = true)\r
+    {\r
+        $this->serializeSessionCookies($serializeSessionCookies);\r
+        $this->usePublicSuffixList($usePublicSuffixList);\r
+    }\r
+\r
+   /**\r
+    * Returns current time formatted in ISO-8601 at UTC timezone\r
+    *\r
+    * @return string\r
+    */\r
+    protected function now()\r
+    {\r
+        $dt = new DateTime();\r
+        $dt->setTimezone(new DateTimeZone('UTC'));\r
+        return $dt->format(DateTime::ISO8601);\r
+    }\r
+\r
+   /**\r
+    * Checks cookie array for correctness, possibly updating its 'domain', 'path' and 'expires' fields\r
+    *\r
+    * The checks are as follows:\r
+    *   - cookie array should contain 'name' and 'value' fields;\r
+    *   - name and value should not contain disallowed symbols;\r
+    *   - 'expires' should be either empty parseable by DateTime;\r
+    *   - 'domain' and 'path' should be either not empty or an URL where\r
+    *     cookie was set should be provided.\r
+    *   - if $setter is provided, then document at that URL should be allowed\r
+    *     to set a cookie for that 'domain'. If $setter is not provided,\r
+    *     then no domain checks will be made.\r
+    *\r
+    * 'expires' field will be converted to ISO8601 format from COOKIE format,\r
+    * 'domain' and 'path' will be set from setter URL if empty.\r
+    *\r
+    * @param    array    cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}\r
+    * @param    Net_URL2 URL of the document that sent Set-Cookie header\r
+    * @return   array    Updated cookie array\r
+    * @throws   HTTP_Request2_LogicException\r
+    * @throws   HTTP_Request2_MessageException\r
+    */\r
+    protected function checkAndUpdateFields(array $cookie, Net_URL2 $setter = null)\r
+    {\r
+        if ($missing = array_diff(array('name', 'value'), array_keys($cookie))) {\r
+            throw new HTTP_Request2_LogicException(\r
+                "Cookie array should contain 'name' and 'value' fields",\r
+                HTTP_Request2_Exception::MISSING_VALUE\r
+            );\r
+        }\r
+        if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['name'])) {\r
+            throw new HTTP_Request2_LogicException(\r
+                "Invalid cookie name: '{$cookie['name']}'",\r
+                HTTP_Request2_Exception::INVALID_ARGUMENT\r
+            );\r
+        }\r
+        if (preg_match(HTTP_Request2::REGEXP_INVALID_COOKIE, $cookie['value'])) {\r
+            throw new HTTP_Request2_LogicException(\r
+                "Invalid cookie value: '{$cookie['value']}'",\r
+                HTTP_Request2_Exception::INVALID_ARGUMENT\r
+            );\r
+        }\r
+        $cookie += array('domain' => '', 'path' => '', 'expires' => null, 'secure' => false);\r
+\r
+        // Need ISO-8601 date @ UTC timezone\r
+        if (!empty($cookie['expires'])\r
+            && !preg_match('/^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\+0000$/', $cookie['expires'])\r
+        ) {\r
+            try {\r
+                $dt = new DateTime($cookie['expires']);\r
+                $dt->setTimezone(new DateTimeZone('UTC'));\r
+                $cookie['expires'] = $dt->format(DateTime::ISO8601);\r
+            } catch (Exception $e) {\r
+                throw new HTTP_Request2_LogicException($e->getMessage());\r
+            }\r
+        }\r
+\r
+        if (empty($cookie['domain']) || empty($cookie['path'])) {\r
+            if (!$setter) {\r
+                throw new HTTP_Request2_LogicException(\r
+                    'Cookie misses domain and/or path component, cookie setter URL needed',\r
+                    HTTP_Request2_Exception::MISSING_VALUE\r
+                );\r
+            }\r
+            if (empty($cookie['domain'])) {\r
+                if ($host = $setter->getHost()) {\r
+                    $cookie['domain'] = $host;\r
+                } else {\r
+                    throw new HTTP_Request2_LogicException(\r
+                        'Setter URL does not contain host part, can\'t set cookie domain',\r
+                        HTTP_Request2_Exception::MISSING_VALUE\r
+                    );\r
+                }\r
+            }\r
+            if (empty($cookie['path'])) {\r
+                $path = $setter->getPath();\r
+                $cookie['path'] = empty($path)? '/': substr($path, 0, strrpos($path, '/') + 1);\r
+            }\r
+        }\r
+\r
+        if ($setter && !$this->domainMatch($setter->getHost(), $cookie['domain'])) {\r
+            throw new HTTP_Request2_MessageException(\r
+                "Domain " . $setter->getHost() . " cannot set cookies for "\r
+                . $cookie['domain']\r
+            );\r
+        }\r
+\r
+        return $cookie;\r
+    }\r
+\r
+   /**\r
+    * Stores a cookie in the jar\r
+    *\r
+    * @param    array    cookie data, as returned by {@link HTTP_Request2_Response::getCookies()}\r
+    * @param    Net_URL2 URL of the document that sent Set-Cookie header\r
+    * @throws   HTTP_Request2_Exception\r
+    */\r
+    public function store(array $cookie, Net_URL2 $setter = null)\r
+    {\r
+        $cookie = $this->checkAndUpdateFields($cookie, $setter);\r
+\r
+        if (strlen($cookie['value'])\r
+            && (is_null($cookie['expires']) || $cookie['expires'] > $this->now())\r
+        ) {\r
+            if (!isset($this->cookies[$cookie['domain']])) {\r
+                $this->cookies[$cookie['domain']] = array();\r
+            }\r
+            if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {\r
+                $this->cookies[$cookie['domain']][$cookie['path']] = array();\r
+            }\r
+            $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;\r
+\r
+        } elseif (isset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']])) {\r
+            unset($this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']]);\r
+        }\r
+    }\r
+\r
+   /**\r
+    * Adds cookies set in HTTP response to the jar\r
+    *\r
+    * @param HTTP_Request2_Response response\r
+    * @param Net_URL2               original request URL, needed for setting\r
+    *                               default domain/path\r
+    */\r
+    public function addCookiesFromResponse(HTTP_Request2_Response $response, Net_URL2 $setter)\r
+    {\r
+        foreach ($response->getCookies() as $cookie) {\r
+            $this->store($cookie, $setter);\r
+        }\r
+    }\r
+\r
+   /**\r
+    * Returns all cookies matching a given request URL\r
+    *\r
+    * The following checks are made:\r
+    *   - cookie domain should match request host\r
+    *   - cookie path should be a prefix for request path\r
+    *   - 'secure' cookies will only be sent for HTTPS requests\r
+    *\r
+    * @param  Net_URL2\r
+    * @param  bool      Whether to return cookies as string for "Cookie: " header\r
+    * @return array\r
+    */\r
+    public function getMatching(Net_URL2 $url, $asString = false)\r
+    {\r
+        $host   = $url->getHost();\r
+        $path   = $url->getPath();\r
+        $secure = 0 == strcasecmp($url->getScheme(), 'https');\r
+\r
+        $matched = $ret = array();\r
+        foreach (array_keys($this->cookies) as $domain) {\r
+            if ($this->domainMatch($host, $domain)) {\r
+                foreach (array_keys($this->cookies[$domain]) as $cPath) {\r
+                    if (0 === strpos($path, $cPath)) {\r
+                        foreach ($this->cookies[$domain][$cPath] as $name => $cookie) {\r
+                            if (!$cookie['secure'] || $secure) {\r
+                                $matched[$name][strlen($cookie['path'])] = $cookie;\r
+                            }\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+        foreach ($matched as $cookies) {\r
+            krsort($cookies);\r
+            $ret = array_merge($ret, $cookies);\r
+        }\r
+        if (!$asString) {\r
+            return $ret;\r
+        } else {\r
+            $str = '';\r
+            foreach ($ret as $c) {\r
+                $str .= (empty($str)? '': '; ') . $c['name'] . '=' . $c['value'];\r
+            }\r
+            return $str;\r
+        }\r
+    }\r
+\r
+   /**\r
+    * Returns all cookies stored in a jar\r
+    *\r
+    * @return array\r
+    */\r
+    public function getAll()\r
+    {\r
+        $cookies = array();\r
+        foreach (array_keys($this->cookies) as $domain) {\r
+            foreach (array_keys($this->cookies[$domain]) as $path) {\r
+                foreach ($this->cookies[$domain][$path] as $name => $cookie) {\r
+                    $cookies[] = $cookie;\r
+                }\r
+            }\r
+        }\r
+        return $cookies;\r
+    }\r
+\r
+   /**\r
+    * Sets whether session cookies should be serialized when serializing the jar\r
+    *\r
+    * @param    boolean\r
+    */\r
+    public function serializeSessionCookies($serialize)\r
+    {\r
+        $this->serializeSession = (bool)$serialize;\r
+    }\r
+\r
+   /**\r
+    * Sets whether Public Suffix List should be used for restricting cookie-setting\r
+    *\r
+    * Without PSL {@link domainMatch()} will only prevent setting cookies for\r
+    * top-level domains like '.com' or '.org'. However, it will not prevent\r
+    * setting a cookie for '.co.uk' even though only third-level registrations\r
+    * are possible in .uk domain.\r
+    *\r
+    * With the List it is possible to find the highest level at which a domain\r
+    * may be registered for a particular top-level domain and consequently\r
+    * prevent cookies set for '.co.uk' or '.msk.ru'. The same list is used by\r
+    * Firefox, Chrome and Opera browsers to restrict cookie setting.\r
+    *\r
+    * Note that PSL is licensed differently to HTTP_Request2 package (refer to\r
+    * the license information in public-suffix-list.php), so you can disable\r
+    * its use if this is an issue for you.\r
+    *\r
+    * @param    boolean\r
+    * @link     http://publicsuffix.org/learn/\r
+    */\r
+    public function usePublicSuffixList($useList)\r
+    {\r
+        $this->useList = (bool)$useList;\r
+    }\r
+\r
+   /**\r
+    * Returns string representation of object\r
+    *\r
+    * @return string\r
+    * @see    Serializable::serialize()\r
+    */\r
+    public function serialize()\r
+    {\r
+        $cookies = $this->getAll();\r
+        if (!$this->serializeSession) {\r
+            for ($i = count($cookies) - 1; $i >= 0; $i--) {\r
+                if (empty($cookies[$i]['expires'])) {\r
+                    unset($cookies[$i]);\r
+                }\r
+            }\r
+        }\r
+        return serialize(array(\r
+            'cookies'          => $cookies,\r
+            'serializeSession' => $this->serializeSession,\r
+            'useList'          => $this->useList\r
+        ));\r
+    }\r
+\r
+   /**\r
+    * Constructs the object from serialized string\r
+    *\r
+    * @param string  string representation\r
+    * @see   Serializable::unserialize()\r
+    */\r
+    public function unserialize($serialized)\r
+    {\r
+        $data = unserialize($serialized);\r
+        $now  = $this->now();\r
+        $this->serializeSessionCookies($data['serializeSession']);\r
+        $this->usePublicSuffixList($data['useList']);\r
+        foreach ($data['cookies'] as $cookie) {\r
+            if (!empty($cookie['expires']) && $cookie['expires'] <= $now) {\r
+                continue;\r
+            }\r
+            if (!isset($this->cookies[$cookie['domain']])) {\r
+                $this->cookies[$cookie['domain']] = array();\r
+            }\r
+            if (!isset($this->cookies[$cookie['domain']][$cookie['path']])) {\r
+                $this->cookies[$cookie['domain']][$cookie['path']] = array();\r
+            }\r
+            $this->cookies[$cookie['domain']][$cookie['path']][$cookie['name']] = $cookie;\r
+        }\r
+    }\r
+\r
+   /**\r
+    * Checks whether a cookie domain matches a request host.\r
+    *\r
+    * The method is used by {@link store()} to check for whether a document\r
+    * at given URL can set a cookie with a given domain attribute and by\r
+    * {@link getMatching()} to find cookies matching the request URL.\r
+    *\r
+    * @param    string  request host\r
+    * @param    string  cookie domain\r
+    * @return   bool    match success\r
+    */\r
+    public function domainMatch($requestHost, $cookieDomain)\r
+    {\r
+        if ($requestHost == $cookieDomain) {\r
+            return true;\r
+        }\r
+        // IP address, we require exact match\r
+        if (preg_match('/^(?:\d{1,3}\.){3}\d{1,3}$/', $requestHost)) {\r
+            return false;\r
+        }\r
+        if ('.' != $cookieDomain[0]) {\r
+            $cookieDomain = '.' . $cookieDomain;\r
+        }\r
+        // prevents setting cookies for '.com' and similar domains\r
+        if (!$this->useList && substr_count($cookieDomain, '.') < 2\r
+            || $this->useList && !self::getRegisteredDomain($cookieDomain)\r
+        ) {\r
+            return false;\r
+        }\r
+        return substr('.' . $requestHost, -strlen($cookieDomain)) == $cookieDomain;\r
+    }\r
+\r
+   /**\r
+    * Removes subdomains to get the registered domain (the first after top-level)\r
+    *\r
+    * The method will check Public Suffix List to find out where top-level\r
+    * domain ends and registered domain starts. It will remove domain parts\r
+    * to the left of registered one.\r
+    *\r
+    * @param  string        domain name\r
+    * @return string|bool   registered domain, will return false if $domain is\r
+    *                       either invalid or a TLD itself\r
+    */\r
+    public static function getRegisteredDomain($domain)\r
+    {\r
+        $domainParts = explode('.', ltrim($domain, '.'));\r
+\r
+        // load the list if needed\r
+        if (empty(self::$psl)) {\r
+            $path = '@data_dir@' . DIRECTORY_SEPARATOR . 'HTTP_Request2';\r
+            if (0 === strpos($path, '@' . 'data_dir@')) {\r
+                $path = realpath(dirname(__FILE__) . DIRECTORY_SEPARATOR . '..'\r
+                                 . DIRECTORY_SEPARATOR . 'data');\r
+            }\r
+            self::$psl = include_once $path . DIRECTORY_SEPARATOR . 'public-suffix-list.php';\r
+        }\r
+\r
+        if (!($result = self::checkDomainsList($domainParts, self::$psl))) {\r
+            // known TLD, invalid domain name\r
+            return false;\r
+        }\r
+\r
+        // unknown TLD\r
+        if (!strpos($result, '.')) {\r
+            // fallback to checking that domain "has at least two dots"\r
+            if (2 > ($count = count($domainParts))) {\r
+                return false;\r
+            }\r
+            return $domainParts[$count - 2] . '.' . $domainParts[$count - 1];\r
+        }\r
+        return $result;\r
+    }\r
+\r
+   /**\r
+    * Recursive helper method for {@link getRegisteredDomain()}\r
+    *\r
+    * @param  array         remaining domain parts\r
+    * @param  mixed         node in {@link HTTP_Request2_CookieJar::$psl} to check\r
+    * @return string|null   concatenated domain parts, null in case of error\r
+    */\r
+    protected static function checkDomainsList(array $domainParts, $listNode)\r
+    {\r
+        $sub    = array_pop($domainParts);\r
+        $result = null;\r
+\r
+        if (!is_array($listNode) || is_null($sub)\r
+            || array_key_exists('!' . $sub, $listNode)\r
+         ) {\r
+            return $sub;\r
+\r
+        } elseif (array_key_exists($sub, $listNode)) {\r
+            $result = self::checkDomainsList($domainParts, $listNode[$sub]);\r
+\r
+        } elseif (array_key_exists('*', $listNode)) {\r
+            $result = self::checkDomainsList($domainParts, $listNode['*']);\r
+\r
+        } else {\r
+            return $sub;\r
+        }\r
+\r
+        return (strlen($result) > 0) ? ($result . '.' . $sub) : null;\r
+    }\r
+}\r
+?>
\ No newline at end of file