Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\BrowserKit; Chris@0: Chris@0: /** Chris@0: * CookieJar. Chris@0: * Chris@0: * @author Fabien Potencier Chris@0: */ Chris@0: class CookieJar Chris@0: { Chris@17: protected $cookieJar = []; Chris@0: Chris@0: public function set(Cookie $cookie) Chris@0: { Chris@0: $this->cookieJar[$cookie->getDomain()][$cookie->getPath()][$cookie->getName()] = $cookie; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets a cookie by name. Chris@0: * Chris@0: * You should never use an empty domain, but if you do so, Chris@0: * this method returns the first cookie for the given name/path Chris@0: * (this behavior ensures a BC behavior with previous versions of Chris@0: * Symfony). Chris@0: * Chris@0: * @param string $name The cookie name Chris@0: * @param string $path The cookie path Chris@0: * @param string $domain The cookie domain Chris@0: * Chris@0: * @return Cookie|null A Cookie instance or null if the cookie does not exist Chris@0: */ Chris@0: public function get($name, $path = '/', $domain = null) Chris@0: { Chris@0: $this->flushExpiredCookies(); Chris@0: Chris@13: foreach ($this->cookieJar as $cookieDomain => $pathCookies) { Chris@13: if ($cookieDomain && $domain) { Chris@13: $cookieDomain = '.'.ltrim($cookieDomain, '.'); Chris@13: if ($cookieDomain !== substr('.'.$domain, -\strlen($cookieDomain))) { Chris@13: continue; Chris@0: } Chris@0: } Chris@0: Chris@13: foreach ($pathCookies as $cookiePath => $namedCookies) { Chris@13: if (0 !== strpos($path, $cookiePath)) { Chris@13: continue; Chris@13: } Chris@13: if (isset($namedCookies[$name])) { Chris@13: return $namedCookies[$name]; Chris@13: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes a cookie by name. Chris@0: * Chris@0: * You should never use an empty domain, but if you do so, Chris@0: * all cookies for the given name/path expire (this behavior Chris@0: * ensures a BC behavior with previous versions of Symfony). Chris@0: * Chris@0: * @param string $name The cookie name Chris@0: * @param string $path The cookie path Chris@0: * @param string $domain The cookie domain Chris@0: */ Chris@0: public function expire($name, $path = '/', $domain = null) Chris@0: { Chris@0: if (null === $path) { Chris@0: $path = '/'; Chris@0: } Chris@0: Chris@0: if (empty($domain)) { Chris@0: // an empty domain means any domain Chris@0: // this should never happen but it allows for a better BC Chris@0: $domains = array_keys($this->cookieJar); Chris@0: } else { Chris@17: $domains = [$domain]; Chris@0: } Chris@0: Chris@0: foreach ($domains as $domain) { Chris@0: unset($this->cookieJar[$domain][$path][$name]); Chris@0: Chris@0: if (empty($this->cookieJar[$domain][$path])) { Chris@0: unset($this->cookieJar[$domain][$path]); Chris@0: Chris@0: if (empty($this->cookieJar[$domain])) { Chris@0: unset($this->cookieJar[$domain]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes all the cookies from the jar. Chris@0: */ Chris@0: public function clear() Chris@0: { Chris@17: $this->cookieJar = []; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Updates the cookie jar from a response Set-Cookie headers. Chris@0: * Chris@0: * @param array $setCookies Set-Cookie headers from an HTTP response Chris@0: * @param string $uri The base URL Chris@0: */ Chris@0: public function updateFromSetCookie(array $setCookies, $uri = null) Chris@0: { Chris@17: $cookies = []; Chris@0: Chris@0: foreach ($setCookies as $cookie) { Chris@0: foreach (explode(',', $cookie) as $i => $part) { Chris@0: if (0 === $i || preg_match('/^(?P\s*[0-9A-Za-z!#\$%\&\'\*\+\-\.^_`\|~]+)=/', $part)) { Chris@0: $cookies[] = ltrim($part); Chris@0: } else { Chris@17: $cookies[\count($cookies) - 1] .= ','.$part; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: foreach ($cookies as $cookie) { Chris@0: try { Chris@0: $this->set(Cookie::fromString($cookie, $uri)); Chris@0: } catch (\InvalidArgumentException $e) { Chris@0: // invalid cookies are just ignored Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Updates the cookie jar from a Response object. Chris@0: * Chris@0: * @param Response $response A Response object Chris@0: * @param string $uri The base URL Chris@0: */ Chris@0: public function updateFromResponse(Response $response, $uri = null) Chris@0: { Chris@0: $this->updateFromSetCookie($response->getHeader('Set-Cookie', false), $uri); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns not yet expired cookies. Chris@0: * Chris@0: * @return Cookie[] An array of cookies Chris@0: */ Chris@0: public function all() Chris@0: { Chris@0: $this->flushExpiredCookies(); Chris@0: Chris@17: $flattenedCookies = []; Chris@0: foreach ($this->cookieJar as $path) { Chris@0: foreach ($path as $cookies) { Chris@0: foreach ($cookies as $cookie) { Chris@0: $flattenedCookies[] = $cookie; Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $flattenedCookies; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns not yet expired cookie values for the given URI. Chris@0: * Chris@0: * @param string $uri A URI Chris@0: * @param bool $returnsRawValue Returns raw value or urldecoded value Chris@0: * Chris@0: * @return array An array of cookie values Chris@0: */ Chris@0: public function allValues($uri, $returnsRawValue = false) Chris@0: { Chris@0: $this->flushExpiredCookies(); Chris@0: Chris@17: $parts = array_replace(['path' => '/'], parse_url($uri)); Chris@17: $cookies = []; Chris@0: foreach ($this->cookieJar as $domain => $pathCookies) { Chris@0: if ($domain) { Chris@0: $domain = '.'.ltrim($domain, '.'); Chris@17: if ($domain != substr('.'.$parts['host'], -\strlen($domain))) { Chris@0: continue; Chris@0: } Chris@0: } Chris@0: Chris@0: foreach ($pathCookies as $path => $namedCookies) { Chris@17: if ($path != substr($parts['path'], 0, \strlen($path))) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: foreach ($namedCookies as $cookie) { Chris@0: if ($cookie->isSecure() && 'https' != $parts['scheme']) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $cookies[$cookie->getName()] = $returnsRawValue ? $cookie->getRawValue() : $cookie->getValue(); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: return $cookies; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Returns not yet expired raw cookie values for the given URI. Chris@0: * Chris@0: * @param string $uri A URI Chris@0: * Chris@0: * @return array An array of cookie values Chris@0: */ Chris@0: public function allRawValues($uri) Chris@0: { Chris@0: return $this->allValues($uri, true); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Removes all expired cookies. Chris@0: */ Chris@0: public function flushExpiredCookies() Chris@0: { Chris@0: foreach ($this->cookieJar as $domain => $pathCookies) { Chris@0: foreach ($pathCookies as $path => $namedCookies) { Chris@0: foreach ($namedCookies as $name => $cookie) { Chris@0: if ($cookie->isExpired()) { Chris@0: unset($this->cookieJar[$domain][$path][$name]); Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: } Chris@0: }