source: spip-zone/_plugins_/_stable_/simpletest/simpletest/url.php @ 24737

Last change on this file since 24737 was 24737, checked in by marcimat@…, 12 years ago

Plugin pour des tests unitaires avec SPIP utilisant les librairies SimpleTest? (version 1.0.1).

L'api de simpleTest est enrichie pour proposer des tests spécifiques utilisant les fonctions de SPIP. La documentation sur Contrib va suivre.

Une remarque importante : pour que les tests fonctionnent, il ne PEUT pas y avoir le lien symbolique sur les répertoires plugins ou de simpleTests

Le répertoire tests/ (qui contient les premiers tests unitaires dans un format qui n'est pas simpleTest) peut être ajouté à la racine du site, les tests SimpleTests? se lanceront dedans correctement si ce plugin est activé.

File size: 16.2 KB
Line 
1<?php
2/**
3 *  base include file for SimpleTest
4 *  @package    SimpleTest
5 *  @subpackage WebTester
6 *  @version    $Id: url.php 1723 2008-04-08 00:34:10Z lastcraft $
7 */
8
9/**#@+
10 *  include other SimpleTest class files
11 */
12require_once(dirname(__FILE__) . '/encoding.php');
13/**#@-*/
14
15/**
16 *    URL parser to replace parse_url() PHP function which
17 *    got broken in PHP 4.3.0. Adds some browser specific
18 *    functionality such as expandomatics.
19 *    Guesses a bit trying to separate the host from
20 *    the path and tries to keep a raw, possibly unparsable,
21 *    request string as long as possible.
22 *    @package SimpleTest
23 *    @subpackage WebTester
24 */
25class SimpleUrl {
26    var $_scheme;
27    var $_username;
28    var $_password;
29    var $_host;
30    var $_port;
31    var $_path;
32    var $_request;
33    var $_fragment;
34    var $_x;
35    var $_y;
36    var $_target;
37    var $_raw = false;
38   
39    /**
40     *    Constructor. Parses URL into sections.
41     *    @param string $url        Incoming URL.
42     *    @access public
43     */
44    function SimpleUrl($url = '') {
45        list($x, $y) = $this->_chompCoordinates($url);
46        $this->setCoordinates($x, $y);
47        $this->_scheme = $this->_chompScheme($url);
48        list($this->_username, $this->_password) = $this->_chompLogin($url);
49        $this->_host = $this->_chompHost($url);
50        $this->_port = false;
51        if (preg_match('/(.*?):(.*)/', $this->_host, $host_parts)) {
52            $this->_host = $host_parts[1];
53            $this->_port = (integer)$host_parts[2];
54        }
55        $this->_path = $this->_chompPath($url);
56        $this->_request = $this->_parseRequest($this->_chompRequest($url));
57        $this->_fragment = (strncmp($url, "#", 1) == 0 ? substr($url, 1) : false);
58        $this->_target = false;
59    }
60   
61    /**
62     *    Extracts the X, Y coordinate pair from an image map.
63     *    @param string $url   URL so far. The coordinates will be
64     *                         removed.
65     *    @return array        X, Y as a pair of integers.
66     *    @access private
67     */
68    function _chompCoordinates(&$url) {
69        if (preg_match('/(.*)\?(\d+),(\d+)$/', $url, $matches)) {
70            $url = $matches[1];
71            return array((integer)$matches[2], (integer)$matches[3]);
72        }
73        return array(false, false);
74    }
75   
76    /**
77     *    Extracts the scheme part of an incoming URL.
78     *    @param string $url   URL so far. The scheme will be
79     *                         removed.
80     *    @return string       Scheme part or false.
81     *    @access private
82     */
83    function _chompScheme(&$url) {
84        if (preg_match('/^([^\/:]*):(\/\/)(.*)/', $url, $matches)) {
85            $url = $matches[2] . $matches[3];
86            return $matches[1];
87        }
88        return false;
89    }
90   
91    /**
92     *    Extracts the username and password from the
93     *    incoming URL. The // prefix will be reattached
94     *    to the URL after the doublet is extracted.
95     *    @param string $url    URL so far. The username and
96     *                          password are removed.
97     *    @return array         Two item list of username and
98     *                          password. Will urldecode() them.
99     *    @access private
100     */
101    function _chompLogin(&$url) {
102        $prefix = '';
103        if (preg_match('/^(\/\/)(.*)/', $url, $matches)) {
104            $prefix = $matches[1];
105            $url = $matches[2];
106        }
107        if (preg_match('/^([^\/]*)@(.*)/', $url, $matches)) {
108            $url = $prefix . $matches[2];
109            $parts = split(":", $matches[1]);
110            return array(
111                    urldecode($parts[0]),
112                    isset($parts[1]) ? urldecode($parts[1]) : false);
113        }
114        $url = $prefix . $url;
115        return array(false, false);
116    }
117   
118    /**
119     *    Extracts the host part of an incoming URL.
120     *    Includes the port number part. Will extract
121     *    the host if it starts with // or it has
122     *    a top level domain or it has at least two
123     *    dots.
124     *    @param string $url    URL so far. The host will be
125     *                          removed.
126     *    @return string        Host part guess or false.
127     *    @access private
128     */
129    function _chompHost(&$url) {
130        if (preg_match('/^(\/\/)(.*?)(\/.*|\?.*|#.*|$)/', $url, $matches)) {
131            $url = $matches[3];
132            return $matches[2];
133        }
134        if (preg_match('/(.*?)(\.\.\/|\.\/|\/|\?|#|$)(.*)/', $url, $matches)) {
135            $tlds = SimpleUrl::getAllTopLevelDomains();
136            if (preg_match('/[a-z0-9\-]+\.(' . $tlds . ')/i', $matches[1])) {
137                $url = $matches[2] . $matches[3];
138                return $matches[1];
139            } elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i', $matches[1])) {
140                $url = $matches[2] . $matches[3];
141                return $matches[1];
142            }
143        }
144        return false;
145    }
146   
147    /**
148     *    Extracts the path information from the incoming
149     *    URL. Strips this path from the URL.
150     *    @param string $url     URL so far. The host will be
151     *                           removed.
152     *    @return string         Path part or '/'.
153     *    @access private
154     */
155    function _chompPath(&$url) {
156        if (preg_match('/(.*?)(\?|#|$)(.*)/', $url, $matches)) {
157            $url = $matches[2] . $matches[3];
158            return ($matches[1] ? $matches[1] : '');
159        }
160        return '';
161    }
162   
163    /**
164     *    Strips off the request data.
165     *    @param string $url  URL so far. The request will be
166     *                        removed.
167     *    @return string      Raw request part.
168     *    @access private
169     */
170    function _chompRequest(&$url) {
171        if (preg_match('/\?(.*?)(#|$)(.*)/', $url, $matches)) {
172            $url = $matches[2] . $matches[3];
173            return $matches[1];
174        }
175        return '';
176    }
177       
178    /**
179     *    Breaks the request down into an object.
180     *    @param string $raw           Raw request.
181     *    @return SimpleFormEncoding    Parsed data.
182     *    @access private
183     */
184    function _parseRequest($raw) {
185        $this->_raw = $raw;
186        $request = new SimpleGetEncoding();
187        foreach (split("&", $raw) as $pair) {
188            if (preg_match('/(.*?)=(.*)/', $pair, $matches)) {
189                $request->add($matches[1], urldecode($matches[2]));
190            } elseif ($pair) {
191                $request->add($pair, '');
192            }
193        }
194        return $request;
195    }
196   
197    /**
198     *    Accessor for protocol part.
199     *    @param string $default    Value to use if not present.
200     *    @return string            Scheme name, e.g "http".
201     *    @access public
202     */
203    function getScheme($default = false) {
204        return $this->_scheme ? $this->_scheme : $default;
205    }
206   
207    /**
208     *    Accessor for user name.
209     *    @return string    Username preceding host.
210     *    @access public
211     */
212    function getUsername() {
213        return $this->_username;
214    }
215   
216    /**
217     *    Accessor for password.
218     *    @return string    Password preceding host.
219     *    @access public
220     */
221    function getPassword() {
222        return $this->_password;
223    }
224   
225    /**
226     *    Accessor for hostname and port.
227     *    @param string $default    Value to use if not present.
228     *    @return string            Hostname only.
229     *    @access public
230     */
231    function getHost($default = false) {
232        return $this->_host ? $this->_host : $default;
233    }
234   
235    /**
236     *    Accessor for top level domain.
237     *    @return string       Last part of host.
238     *    @access public
239     */
240    function getTld() {
241        $path_parts = pathinfo($this->getHost());
242        return (isset($path_parts['extension']) ? $path_parts['extension'] : false);
243    }
244   
245    /**
246     *    Accessor for port number.
247     *    @return integer    TCP/IP port number.
248     *    @access public
249     */
250    function getPort() {
251        return $this->_port;
252    }       
253           
254    /**
255     *    Accessor for path.
256     *    @return string    Full path including leading slash if implied.
257     *    @access public
258     */
259    function getPath() {
260        if (! $this->_path && $this->_host) {
261            return '/';
262        }
263        return $this->_path;
264    }
265   
266    /**
267     *    Accessor for page if any. This may be a
268     *    directory name if ambiguious.
269     *    @return            Page name.
270     *    @access public
271     */
272    function getPage() {
273        if (! preg_match('/([^\/]*?)$/', $this->getPath(), $matches)) {
274            return false;
275        }
276        return $matches[1];
277    }
278   
279    /**
280     *    Gets the path to the page.
281     *    @return string       Path less the page.
282     *    @access public
283     */
284    function getBasePath() {
285        if (! preg_match('/(.*\/)[^\/]*?$/', $this->getPath(), $matches)) {
286            return false;
287        }
288        return $matches[1];
289    }
290   
291    /**
292     *    Accessor for fragment at end of URL after the "#".
293     *    @return string    Part after "#".
294     *    @access public
295     */
296    function getFragment() {
297        return $this->_fragment;
298    }
299   
300    /**
301     *    Sets image coordinates. Set to false to clear
302     *    them.
303     *    @param integer $x    Horizontal position.
304     *    @param integer $y    Vertical position.
305     *    @access public
306     */
307    function setCoordinates($x = false, $y = false) {
308        if (($x === false) || ($y === false)) {
309            $this->_x = $this->_y = false;
310            return;
311        }
312        $this->_x = (integer)$x;
313        $this->_y = (integer)$y;
314    }
315   
316    /**
317     *    Accessor for horizontal image coordinate.
318     *    @return integer        X value.
319     *    @access public
320     */
321    function getX() {
322        return $this->_x;
323    }
324       
325    /**
326     *    Accessor for vertical image coordinate.
327     *    @return integer        Y value.
328     *    @access public
329     */
330    function getY() {
331        return $this->_y;
332    }
333   
334    /**
335     *    Accessor for current request parameters
336     *    in URL string form. Will return teh original request
337     *    if at all possible even if it doesn't make much
338     *    sense.
339     *    @return string   Form is string "?a=1&b=2", etc.
340     *    @access public
341     */
342    function getEncodedRequest() {
343        if ($this->_raw) {
344            $encoded = $this->_raw;
345        } else {
346            $encoded = $this->_request->asUrlRequest();
347        }
348        if ($encoded) {
349            return '?' . preg_replace('/^\?/', '', $encoded);
350        }
351        return '';
352    }
353   
354    /**
355     *    Adds an additional parameter to the request.
356     *    @param string $key            Name of parameter.
357     *    @param string $value          Value as string.
358     *    @access public
359     */
360    function addRequestParameter($key, $value) {
361        $this->_raw = false;
362        $this->_request->add($key, $value);
363    }
364   
365    /**
366     *    Adds additional parameters to the request.
367     *    @param hash/SimpleFormEncoding $parameters   Additional
368     *                                                parameters.
369     *    @access public
370     */
371    function addRequestParameters($parameters) {
372        $this->_raw = false;
373        $this->_request->merge($parameters);
374    }
375   
376    /**
377     *    Clears down all parameters.
378     *    @access public
379     */
380    function clearRequest() {
381        $this->_raw = false;
382        $this->_request = &new SimpleGetEncoding();
383    }
384   
385    /**
386     *    Gets the frame target if present. Although
387     *    not strictly part of the URL specification it
388     *    acts as similarily to the browser.
389     *    @return boolean/string    Frame name or false if none.
390     *    @access public
391     */
392    function getTarget() {
393        return $this->_target;
394    }
395   
396    /**
397     *    Attaches a frame target.
398     *    @param string $frame        Name of frame.
399     *    @access public
400     */
401    function setTarget($frame) {
402        $this->_raw = false;
403        $this->_target = $frame;
404    }
405   
406    /**
407     *    Renders the URL back into a string.
408     *    @return string        URL in canonical form.
409     *    @access public
410     */
411    function asString() {
412        $path = $this->_path;
413        $scheme = $identity = $host = $encoded = $fragment = '';
414        if ($this->_username && $this->_password) {
415            $identity = $this->_username . ':' . $this->_password . '@';
416        }
417        if ($this->getHost()) {
418            $scheme = $this->getScheme() ? $this->getScheme() : 'http';
419            $scheme .= "://";
420            $host = $this->getHost();
421        }
422        if (substr($this->_path, 0, 1) == '/') {
423            $path = $this->normalisePath($this->_path);
424        }
425        $encoded = $this->getEncodedRequest();
426        $fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
427        $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
428        return "$scheme$identity$host$path$encoded$fragment$coords";
429    }
430   
431    /**
432     *    Replaces unknown sections to turn a relative
433     *    URL into an absolute one. The base URL can
434     *    be either a string or a SimpleUrl object.
435     *    @param string/SimpleUrl $base       Base URL.
436     *    @access public
437     */
438    function makeAbsolute($base) {
439        if (! is_object($base)) {
440            $base = new SimpleUrl($base);
441        }
442        if ($this->getHost()) {
443            $scheme = $this->getScheme();
444            $host = $this->getHost();
445            $port = $this->getPort() ? ':' . $this->getPort() : '';
446            $identity = $this->getIdentity() ? $this->getIdentity() . '@' : '';
447            if (! $identity) {
448                $identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
449            }
450        } else {
451            $scheme = $base->getScheme();
452            $host = $base->getHost();
453            $port = $base->getPort() ? ':' . $base->getPort() : '';
454            $identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
455        }
456        $path = $this->normalisePath($this->_extractAbsolutePath($base));
457        $encoded = $this->getEncodedRequest();
458        $fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
459        $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
460        return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords");
461    }
462   
463    /**
464     *    Replaces unknown sections of the path with base parts
465     *    to return a complete absolute one.
466     *    @param string/SimpleUrl $base       Base URL.
467     *    @param string                       Absolute path.
468     *    @access private
469     */
470    function _extractAbsolutePath($base) {
471        if ($this->getHost()) {
472            return $this->_path;
473        }
474        if (! $this->_isRelativePath($this->_path)) {
475            return $this->_path;
476        }
477        if ($this->_path) {
478            return $base->getBasePath() . $this->_path;
479        }
480        return $base->getPath();
481    }
482   
483    /**
484     *    Simple test to see if a path part is relative.
485     *    @param string $path        Path to test.
486     *    @return boolean            True if starts with a "/".
487     *    @access private
488     */
489    function _isRelativePath($path) {
490        return (substr($path, 0, 1) != '/');
491    }
492   
493    /**
494     *    Extracts the username and password for use in rendering
495     *    a URL.
496     *    @return string/boolean    Form of username:password or false.
497     *    @access public
498     */
499    function getIdentity() {
500        if ($this->_username && $this->_password) {
501            return $this->_username . ':' . $this->_password;
502        }
503        return false;
504    }
505   
506    /**
507     *    Replaces . and .. sections of the path.
508     *    @param string $path    Unoptimised path.
509     *    @return string         Path with dots removed if possible.
510     *    @access public
511     */
512    function normalisePath($path) {
513        $path = preg_replace('|/\./|', '/', $path);
514        return preg_replace('|/[^/]+/\.\./|', '/', $path);
515    }
516   
517    /**
518     *    A pipe seperated list of all TLDs that result in two part
519     *    domain names.
520     *    @return string        Pipe separated list.
521     *    @access public
522     *    @static
523     */
524    function getAllTopLevelDomains() {
525        return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum';
526    }
527}
528?>
Note: See TracBrowser for help on using the repository browser.