Chris@0: getAttribute('rel')) !== 'alternate' Chris@12: || ! $link->getAttribute('type') || ! $link->getAttribute('href')) { Chris@0: continue; Chris@0: } Chris@12: if (! isset($this->rss) && $link->getAttribute('type') == 'application/rss+xml') { Chris@0: $this->rss = $this->absolutiseUri(trim($link->getAttribute('href')), $uri); Chris@12: } elseif (! isset($this->atom) && $link->getAttribute('type') == 'application/atom+xml') { Chris@0: $this->atom = $this->absolutiseUri(trim($link->getAttribute('href')), $uri); Chris@12: } elseif (! isset($this->rdf) && $link->getAttribute('type') == 'application/rdf+xml') { Chris@0: $this->rdf = $this->absolutiseUri(trim($link->getAttribute('href')), $uri); Chris@0: } Chris@0: $this[] = new static([ Chris@0: 'rel' => 'alternate', Chris@0: 'type' => $link->getAttribute('type'), Chris@0: 'href' => $this->absolutiseUri(trim($link->getAttribute('href')), $uri), Chris@12: 'title' => $link->getAttribute('title'), Chris@0: ]); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Attempt to turn a relative URI into an absolute URI Chris@12: * Chris@12: * @param string $link Chris@12: * @param string $uri OPTIONAL Chris@12: * @return string|null absolutised link or null if invalid Chris@0: */ Chris@0: protected function absolutiseUri($link, $uri = null) Chris@0: { Chris@0: $linkUri = Uri::factory($link); Chris@12: if ($linkUri->isAbsolute()) { Chris@12: // invalid absolute link can not be recovered Chris@12: return $linkUri->isValid() ? $link : null; Chris@12: } Chris@0: Chris@12: $scheme = 'http'; Chris@12: if ($uri !== null) { Chris@12: $uri = Uri::factory($uri); Chris@12: $scheme = $uri->getScheme() ?: $scheme; Chris@12: } Chris@0: Chris@12: if ($linkUri->getHost()) { Chris@12: $link = $this->resolveSchemeRelativeUri($link, $scheme); Chris@12: } elseif ($uri !== null) { Chris@12: $link = $this->resolveRelativeUri($link, $scheme, $uri->getHost(), $uri->getPath()); Chris@12: } Chris@0: Chris@12: if (! Uri::factory($link)->isValid()) { Chris@12: return null; Chris@0: } Chris@12: Chris@0: return $link; Chris@0: } Chris@0: Chris@0: /** Chris@12: * Resolves scheme relative link to absolute Chris@12: * Chris@12: * @param string $link Chris@12: * @param string $scheme Chris@12: * @return string Chris@12: */ Chris@12: private function resolveSchemeRelativeUri($link, $scheme) Chris@12: { Chris@12: $link = ltrim($link, '/'); Chris@12: return sprintf('%s://%s', $scheme, $link); Chris@12: } Chris@12: Chris@12: /** Chris@12: * Resolves relative link to absolute Chris@12: * Chris@12: * @param string $link Chris@12: * @param string $scheme Chris@12: * @param string $host Chris@12: * @param string $uriPath Chris@12: * @return string Chris@12: */ Chris@12: private function resolveRelativeUri($link, $scheme, $host, $uriPath) Chris@12: { Chris@12: if ($link[0] !== '/') { Chris@12: $link = $uriPath . '/' . $link; Chris@12: } Chris@12: return sprintf( Chris@12: '%s://%s/%s', Chris@12: $scheme, Chris@12: $host, Chris@12: $this->canonicalizePath($link) Chris@12: ); Chris@12: } Chris@12: Chris@12: /** Chris@0: * Canonicalize relative path Chris@17: * Chris@17: * @param string $path Chris@17: * @return string Chris@0: */ Chris@0: protected function canonicalizePath($path) Chris@0: { Chris@0: $parts = array_filter(explode('/', $path)); Chris@0: $absolutes = []; Chris@0: foreach ($parts as $part) { Chris@0: if ('.' == $part) { Chris@0: continue; Chris@0: } Chris@0: if ('..' == $part) { Chris@0: array_pop($absolutes); Chris@0: } else { Chris@0: $absolutes[] = $part; Chris@0: } Chris@0: } Chris@0: return implode('/', $absolutes); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Supports lazy loading of feeds using Reader::import() but Chris@0: * delegates any other operations to the parent class. Chris@0: * Chris@0: * @param string $offset Chris@0: * @return mixed Chris@0: */ Chris@0: public function offsetGet($offset) Chris@0: { Chris@12: if ($offset == 'feed' && ! $this->offsetExists('feed')) { Chris@12: if (! $this->offsetExists('href')) { Chris@0: return; Chris@0: } Chris@0: $feed = Reader::import($this->offsetGet('href')); Chris@0: $this->offsetSet('feed', $feed); Chris@0: return $feed; Chris@0: } Chris@0: return parent::offsetGet($offset); Chris@0: } Chris@0: }