Ir a la última revisión | Autoría | Comparar con el anterior | Ultima modificación | Ver Log |
<?phpnamespace GuzzleHttp\Cookie;use Psr\Http\Message\RequestInterface;use Psr\Http\Message\ResponseInterface;/*** Cookie jar that stores cookies as an array*/class CookieJar implements CookieJarInterface{/*** @var SetCookie[] Loaded cookie data*/private $cookies = [];/*** @var bool*/private $strictMode;/*** @param bool $strictMode Set to true to throw exceptions when invalid* cookies are added to the cookie jar.* @param array $cookieArray Array of SetCookie objects or a hash of* arrays that can be used with the SetCookie* constructor*/public function __construct(bool $strictMode = false, array $cookieArray = []){$this->strictMode = $strictMode;foreach ($cookieArray as $cookie) {if (!($cookie instanceof SetCookie)) {$cookie = new SetCookie($cookie);}$this->setCookie($cookie);}}/*** Create a new Cookie jar from an associative array and domain.** @param array $cookies Cookies to create the jar from* @param string $domain Domain to set the cookies to*/public static function fromArray(array $cookies, string $domain): self{$cookieJar = new self();foreach ($cookies as $name => $value) {$cookieJar->setCookie(new SetCookie(['Domain' => $domain,'Name' => $name,'Value' => $value,'Discard' => true]));}return $cookieJar;}/*** Evaluate if this cookie should be persisted to storage* that survives between requests.** @param SetCookie $cookie Being evaluated.* @param bool $allowSessionCookies If we should persist session cookies*/public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool{if ($cookie->getExpires() || $allowSessionCookies) {if (!$cookie->getDiscard()) {return true;}}return false;}/*** Finds and returns the cookie based on the name** @param string $name cookie name to search for** @return SetCookie|null cookie that was found or null if not found*/public function getCookieByName(string $name): ?SetCookie{foreach ($this->cookies as $cookie) {if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {return $cookie;}}return null;}/*** @inheritDoc*/public function toArray(): array{return \array_map(static function (SetCookie $cookie): array {return $cookie->toArray();}, $this->getIterator()->getArrayCopy());}/*** @inheritDoc*/public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void{if (!$domain) {$this->cookies = [];return;} elseif (!$path) {$this->cookies = \array_filter($this->cookies,static function (SetCookie $cookie) use ($domain): bool {return !$cookie->matchesDomain($domain);});} elseif (!$name) {$this->cookies = \array_filter($this->cookies,static function (SetCookie $cookie) use ($path, $domain): bool {return !($cookie->matchesPath($path) &&$cookie->matchesDomain($domain));});} else {$this->cookies = \array_filter($this->cookies,static function (SetCookie $cookie) use ($path, $domain, $name) {return !($cookie->getName() == $name &&$cookie->matchesPath($path) &&$cookie->matchesDomain($domain));});}}/*** @inheritDoc*/public function clearSessionCookies(): void{$this->cookies = \array_filter($this->cookies,static function (SetCookie $cookie): bool {return !$cookie->getDiscard() && $cookie->getExpires();});}/*** @inheritDoc*/public function setCookie(SetCookie $cookie): bool{// If the name string is empty (but not 0), ignore the set-cookie// string entirely.$name = $cookie->getName();if (!$name && $name !== '0') {return false;}// Only allow cookies with set and valid domain, name, value$result = $cookie->validate();if ($result !== true) {if ($this->strictMode) {throw new \RuntimeException('Invalid cookie: ' . $result);}$this->removeCookieIfEmpty($cookie);return false;}// Resolve conflicts with previously set cookiesforeach ($this->cookies as $i => $c) {// Two cookies are identical, when their path, and domain are// identical.if ($c->getPath() != $cookie->getPath() ||$c->getDomain() != $cookie->getDomain() ||$c->getName() != $cookie->getName()) {continue;}// The previously set cookie is a discard cookie and this one is// not so allow the new cookie to be setif (!$cookie->getDiscard() && $c->getDiscard()) {unset($this->cookies[$i]);continue;}// If the new cookie's expiration is further into the future, then// replace the old cookieif ($cookie->getExpires() > $c->getExpires()) {unset($this->cookies[$i]);continue;}// If the value has changed, we better change itif ($cookie->getValue() !== $c->getValue()) {unset($this->cookies[$i]);continue;}// The cookie exists, so no need to continuereturn false;}$this->cookies[] = $cookie;return true;}public function count(): int{return \count($this->cookies);}/*** @return \ArrayIterator<int, SetCookie>*/public function getIterator(): \ArrayIterator{return new \ArrayIterator(\array_values($this->cookies));}public function extractCookies(RequestInterface $request, ResponseInterface $response): void{if ($cookieHeader = $response->getHeader('Set-Cookie')) {foreach ($cookieHeader as $cookie) {$sc = SetCookie::fromString($cookie);if (!$sc->getDomain()) {$sc->setDomain($request->getUri()->getHost());}if (0 !== \strpos($sc->getPath(), '/')) {$sc->setPath($this->getCookiePathFromRequest($request));}if (!$sc->matchesDomain($request->getUri()->getHost())) {continue;}// Note: At this point `$sc->getDomain()` being a public suffix should// be rejected, but we don't want to pull in the full PSL dependency.$this->setCookie($sc);}}}/*** Computes cookie path following RFC 6265 section 5.1.4** @link https://tools.ietf.org/html/rfc6265#section-5.1.4*/private function getCookiePathFromRequest(RequestInterface $request): string{$uriPath = $request->getUri()->getPath();if ('' === $uriPath) {return '/';}if (0 !== \strpos($uriPath, '/')) {return '/';}if ('/' === $uriPath) {return '/';}$lastSlashPos = \strrpos($uriPath, '/');if (0 === $lastSlashPos || false === $lastSlashPos) {return '/';}return \substr($uriPath, 0, $lastSlashPos);}public function withCookieHeader(RequestInterface $request): RequestInterface{$values = [];$uri = $request->getUri();$scheme = $uri->getScheme();$host = $uri->getHost();$path = $uri->getPath() ?: '/';foreach ($this->cookies as $cookie) {if ($cookie->matchesPath($path) &&$cookie->matchesDomain($host) &&!$cookie->isExpired() &&(!$cookie->getSecure() || $scheme === 'https')) {$values[] = $cookie->getName() . '='. $cookie->getValue();}}return $values? $request->withHeader('Cookie', \implode('; ', $values)): $request;}/*** If a cookie already exists and the server asks to set it again with a* null value, the cookie must be deleted.*/private function removeCookieIfEmpty(SetCookie $cookie): void{$cookieValue = $cookie->getValue();if ($cookieValue === null || $cookieValue === '') {$this->clear($cookie->getDomain(),$cookie->getPath(),$cookie->getName());}}}