]>
Commit | Line | Data |
---|---|---|
f45a286b AD |
1 | <?php |
2 | ||
3 | // does not support network paths | |
4 | ||
5 | class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter | |
6 | { | |
7 | public $name = 'MakeAbsolute'; | |
8 | protected $base; | |
9 | protected $basePathStack = array(); | |
10 | public function prepare($config) { | |
11 | $def = $config->getDefinition('URI'); | |
12 | $this->base = $def->base; | |
13 | if (is_null($this->base)) { | |
14 | trigger_error('URI.MakeAbsolute is being ignored due to lack of value for URI.Base configuration', E_USER_WARNING); | |
15 | return false; | |
16 | } | |
17 | $this->base->fragment = null; // fragment is invalid for base URI | |
18 | $stack = explode('/', $this->base->path); | |
19 | array_pop($stack); // discard last segment | |
20 | $stack = $this->_collapseStack($stack); // do pre-parsing | |
21 | $this->basePathStack = $stack; | |
22 | return true; | |
23 | } | |
24 | public function filter(&$uri, $config, $context) { | |
25 | if (is_null($this->base)) return true; // abort early | |
26 | if ( | |
27 | $uri->path === '' && is_null($uri->scheme) && | |
28 | is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment) | |
29 | ) { | |
30 | // reference to current document | |
31 | $uri = clone $this->base; | |
32 | return true; | |
33 | } | |
34 | if (!is_null($uri->scheme)) { | |
35 | // absolute URI already: don't change | |
36 | if (!is_null($uri->host)) return true; | |
37 | $scheme_obj = $uri->getSchemeObj($config, $context); | |
38 | if (!$scheme_obj) { | |
39 | // scheme not recognized | |
40 | return false; | |
41 | } | |
42 | if (!$scheme_obj->hierarchical) { | |
43 | // non-hierarchal URI with explicit scheme, don't change | |
44 | return true; | |
45 | } | |
46 | // special case: had a scheme but always is hierarchical and had no authority | |
47 | } | |
48 | if (!is_null($uri->host)) { | |
49 | // network path, don't bother | |
50 | return true; | |
51 | } | |
52 | if ($uri->path === '') { | |
53 | $uri->path = $this->base->path; | |
54 | } elseif ($uri->path[0] !== '/') { | |
55 | // relative path, needs more complicated processing | |
56 | $stack = explode('/', $uri->path); | |
57 | $new_stack = array_merge($this->basePathStack, $stack); | |
58 | if ($new_stack[0] !== '' && !is_null($this->base->host)) { | |
59 | array_unshift($new_stack, ''); | |
60 | } | |
61 | $new_stack = $this->_collapseStack($new_stack); | |
62 | $uri->path = implode('/', $new_stack); | |
63 | } else { | |
64 | // absolute path, but still we should collapse | |
65 | $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); | |
66 | } | |
67 | // re-combine | |
68 | $uri->scheme = $this->base->scheme; | |
69 | if (is_null($uri->userinfo)) $uri->userinfo = $this->base->userinfo; | |
70 | if (is_null($uri->host)) $uri->host = $this->base->host; | |
71 | if (is_null($uri->port)) $uri->port = $this->base->port; | |
72 | return true; | |
73 | } | |
74 | ||
75 | /** | |
76 | * Resolve dots and double-dots in a path stack | |
77 | */ | |
78 | private function _collapseStack($stack) { | |
79 | $result = array(); | |
80 | $is_folder = false; | |
81 | for ($i = 0; isset($stack[$i]); $i++) { | |
82 | $is_folder = false; | |
83 | // absorb an internally duplicated slash | |
84 | if ($stack[$i] == '' && $i && isset($stack[$i+1])) continue; | |
85 | if ($stack[$i] == '..') { | |
86 | if (!empty($result)) { | |
87 | $segment = array_pop($result); | |
88 | if ($segment === '' && empty($result)) { | |
89 | // error case: attempted to back out too far: | |
90 | // restore the leading slash | |
91 | $result[] = ''; | |
92 | } elseif ($segment === '..') { | |
93 | $result[] = '..'; // cannot remove .. with .. | |
94 | } | |
95 | } else { | |
96 | // relative path, preserve the double-dots | |
97 | $result[] = '..'; | |
98 | } | |
99 | $is_folder = true; | |
100 | continue; | |
101 | } | |
102 | if ($stack[$i] == '.') { | |
103 | // silently absorb | |
104 | $is_folder = true; | |
105 | continue; | |
106 | } | |
107 | $result[] = $stack[$i]; | |
108 | } | |
109 | if ($is_folder) $result[] = ''; | |
110 | return $result; | |
111 | } | |
112 | } | |
113 | ||
114 | // vim: et sw=4 sts=4 |