d602d6f3316bfb46d3b994382f86fe93c93d458e
[yaffs-website] / vendor / symfony / dom-crawler / AbstractUriElement.php
1 <?php
2
3 /*
4  * This file is part of the Symfony package.
5  *
6  * (c) Fabien Potencier <fabien@symfony.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 namespace Symfony\Component\DomCrawler;
13
14 /**
15  * Any HTML element that can link to an URI.
16  *
17  * @author Fabien Potencier <fabien@symfony.com>
18  */
19 abstract class AbstractUriElement
20 {
21     /**
22      * @var \DOMElement
23      */
24     protected $node;
25
26     /**
27      * @var string The method to use for the element
28      */
29     protected $method;
30
31     /**
32      * @var string The URI of the page where the element is embedded (or the base href)
33      */
34     protected $currentUri;
35
36     /**
37      * @param \DOMElement $node       A \DOMElement instance
38      * @param string      $currentUri The URI of the page where the link is embedded (or the base href)
39      * @param string      $method     The method to use for the link (get by default)
40      *
41      * @throws \InvalidArgumentException if the node is not a link
42      */
43     public function __construct(\DOMElement $node, $currentUri, $method = 'GET')
44     {
45         if (!in_array(strtolower(substr($currentUri, 0, 4)), array('http', 'file'))) {
46             throw new \InvalidArgumentException(sprintf('Current URI must be an absolute URL ("%s").', $currentUri));
47         }
48
49         $this->setNode($node);
50         $this->method = $method ? strtoupper($method) : null;
51         $this->currentUri = $currentUri;
52     }
53
54     /**
55      * Gets the node associated with this link.
56      *
57      * @return \DOMElement A \DOMElement instance
58      */
59     public function getNode()
60     {
61         return $this->node;
62     }
63
64     /**
65      * Gets the method associated with this link.
66      *
67      * @return string The method
68      */
69     public function getMethod()
70     {
71         return $this->method;
72     }
73
74     /**
75      * Gets the URI associated with this link.
76      *
77      * @return string The URI
78      */
79     public function getUri()
80     {
81         $uri = trim($this->getRawUri());
82
83         // absolute URL?
84         if (null !== parse_url($uri, PHP_URL_SCHEME)) {
85             return $uri;
86         }
87
88         // empty URI
89         if (!$uri) {
90             return $this->currentUri;
91         }
92
93         // an anchor
94         if ('#' === $uri[0]) {
95             return $this->cleanupAnchor($this->currentUri).$uri;
96         }
97
98         $baseUri = $this->cleanupUri($this->currentUri);
99
100         if ('?' === $uri[0]) {
101             return $baseUri.$uri;
102         }
103
104         // absolute URL with relative schema
105         if (0 === strpos($uri, '//')) {
106             return preg_replace('#^([^/]*)//.*$#', '$1', $baseUri).$uri;
107         }
108
109         $baseUri = preg_replace('#^(.*?//[^/]*)(?:\/.*)?$#', '$1', $baseUri);
110
111         // absolute path
112         if ('/' === $uri[0]) {
113             return $baseUri.$uri;
114         }
115
116         // relative path
117         $path = parse_url(substr($this->currentUri, strlen($baseUri)), PHP_URL_PATH);
118         $path = $this->canonicalizePath(substr($path, 0, strrpos($path, '/')).'/'.$uri);
119
120         return $baseUri.('' === $path || '/' !== $path[0] ? '/' : '').$path;
121     }
122
123     /**
124      * Returns raw URI data.
125      *
126      * @return string
127      */
128     abstract protected function getRawUri();
129
130     /**
131      * Returns the canonicalized URI path (see RFC 3986, section 5.2.4).
132      *
133      * @param string $path URI path
134      *
135      * @return string
136      */
137     protected function canonicalizePath($path)
138     {
139         if ('' === $path || '/' === $path) {
140             return $path;
141         }
142
143         if ('.' === substr($path, -1)) {
144             $path .= '/';
145         }
146
147         $output = array();
148
149         foreach (explode('/', $path) as $segment) {
150             if ('..' === $segment) {
151                 array_pop($output);
152             } elseif ('.' !== $segment) {
153                 $output[] = $segment;
154             }
155         }
156
157         return implode('/', $output);
158     }
159
160     /**
161      * Sets current \DOMElement instance.
162      *
163      * @param \DOMElement $node A \DOMElement instance
164      *
165      * @throws \LogicException If given node is not an anchor
166      */
167     abstract protected function setNode(\DOMElement $node);
168
169     /**
170      * Removes the query string and the anchor from the given uri.
171      *
172      * @param string $uri The uri to clean
173      *
174      * @return string
175      */
176     private function cleanupUri($uri)
177     {
178         return $this->cleanupQuery($this->cleanupAnchor($uri));
179     }
180
181     /**
182      * Remove the query string from the uri.
183      *
184      * @param string $uri
185      *
186      * @return string
187      */
188     private function cleanupQuery($uri)
189     {
190         if (false !== $pos = strpos($uri, '?')) {
191             return substr($uri, 0, $pos);
192         }
193
194         return $uri;
195     }
196
197     /**
198      * Remove the anchor from the uri.
199      *
200      * @param string $uri
201      *
202      * @return string
203      */
204     private function cleanupAnchor($uri)
205     {
206         if (false !== $pos = strpos($uri, '#')) {
207             return substr($uri, 0, $pos);
208         }
209
210         return $uri;
211     }
212 }