3 // does not support network paths
5 class HTMLPurifier_URIFilter_MakeAbsolute
extends HTMLPurifier_URIFilter
10 public $name = 'MakeAbsolute';
20 protected $basePathStack = array();
23 * @param HTMLPurifier_Config $config
26 public function prepare($config)
28 $def = $config->getDefinition('URI');
29 $this->base
= $def->base
;
30 if (is_null($this->base
)) {
32 'URI.MakeAbsolute is being ignored due to lack of ' .
33 'value for URI.Base configuration',
38 $this->base
->fragment
= null; // fragment is invalid for base URI
39 $stack = explode('/', $this->base
->path
);
40 array_pop($stack); // discard last segment
41 $stack = $this->_collapseStack($stack); // do pre-parsing
42 $this->basePathStack
= $stack;
47 * @param HTMLPurifier_URI $uri
48 * @param HTMLPurifier_Config $config
49 * @param HTMLPurifier_Context $context
52 public function filter(&$uri, $config, $context)
54 if (is_null($this->base
)) {
57 if ($uri->path
=== '' && is_null($uri->scheme
) &&
58 is_null($uri->host
) && is_null($uri->query
) && is_null($uri->fragment
)) {
59 // reference to current document
60 $uri = clone $this->base
;
63 if (!is_null($uri->scheme
)) {
64 // absolute URI already: don't change
65 if (!is_null($uri->host
)) {
68 $scheme_obj = $uri->getSchemeObj($config, $context);
70 // scheme not recognized
73 if (!$scheme_obj->hierarchical
) {
74 // non-hierarchal URI with explicit scheme, don't change
77 // special case: had a scheme but always is hierarchical and had no authority
79 if (!is_null($uri->host
)) {
80 // network path, don't bother
83 if ($uri->path
=== '') {
84 $uri->path
= $this->base
->path
;
85 } elseif ($uri->path
[0] !== '/') {
86 // relative path, needs more complicated processing
87 $stack = explode('/', $uri->path
);
88 $new_stack = array_merge($this->basePathStack
, $stack);
89 if ($new_stack[0] !== '' && !is_null($this->base
->host
)) {
90 array_unshift($new_stack, '');
92 $new_stack = $this->_collapseStack($new_stack);
93 $uri->path
= implode('/', $new_stack);
95 // absolute path, but still we should collapse
96 $uri->path
= implode('/', $this->_collapseStack(explode('/', $uri->path
)));
99 $uri->scheme
= $this->base
->scheme
;
100 if (is_null($uri->userinfo
)) {
101 $uri->userinfo
= $this->base
->userinfo
;
103 if (is_null($uri->host
)) {
104 $uri->host
= $this->base
->host
;
106 if (is_null($uri->port
)) {
107 $uri->port
= $this->base
->port
;
113 * Resolve dots and double-dots in a path stack
114 * @param array $stack
117 private function _collapseStack($stack)
121 for ($i = 0; isset($stack[$i]); $i++
) {
123 // absorb an internally duplicated slash
124 if ($stack[$i] == '' && $i && isset($stack[$i +
1])) {
127 if ($stack[$i] == '..') {
128 if (!empty($result)) {
129 $segment = array_pop($result);
130 if ($segment === '' && empty($result)) {
131 // error case: attempted to back out too far:
132 // restore the leading slash
134 } elseif ($segment === '..') {
135 $result[] = '..'; // cannot remove .. with ..
138 // relative path, preserve the double-dots
144 if ($stack[$i] == '.') {
149 $result[] = $stack[$i];
158 // vim: et sw=4 sts=4