c507bbff8e220dc10981ed889ec35ee943ee866f
[yaffs-website] / vendor / ezyang / htmlpurifier / library / HTMLPurifier / URIFilter / MakeAbsolute.php
1 <?php
2
3 // does not support network paths
4
5 class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter
6 {
7     /**
8      * @type string
9      */
10     public $name = 'MakeAbsolute';
11
12     /**
13      * @type
14      */
15     protected $base;
16
17     /**
18      * @type array
19      */
20     protected $basePathStack = array();
21
22     /**
23      * @param HTMLPurifier_Config $config
24      * @return bool
25      */
26     public function prepare($config)
27     {
28         $def = $config->getDefinition('URI');
29         $this->base = $def->base;
30         if (is_null($this->base)) {
31             trigger_error(
32                 'URI.MakeAbsolute is being ignored due to lack of ' .
33                 'value for URI.Base configuration',
34                 E_USER_WARNING
35             );
36             return false;
37         }
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;
43         return true;
44     }
45
46     /**
47      * @param HTMLPurifier_URI $uri
48      * @param HTMLPurifier_Config $config
49      * @param HTMLPurifier_Context $context
50      * @return bool
51      */
52     public function filter(&$uri, $config, $context)
53     {
54         if (is_null($this->base)) {
55             return true;
56         } // abort early
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;
61             return true;
62         }
63         if (!is_null($uri->scheme)) {
64             // absolute URI already: don't change
65             if (!is_null($uri->host)) {
66                 return true;
67             }
68             $scheme_obj = $uri->getSchemeObj($config, $context);
69             if (!$scheme_obj) {
70                 // scheme not recognized
71                 return false;
72             }
73             if (!$scheme_obj->hierarchical) {
74                 // non-hierarchal URI with explicit scheme, don't change
75                 return true;
76             }
77             // special case: had a scheme but always is hierarchical and had no authority
78         }
79         if (!is_null($uri->host)) {
80             // network path, don't bother
81             return true;
82         }
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, '');
91             }
92             $new_stack = $this->_collapseStack($new_stack);
93             $uri->path = implode('/', $new_stack);
94         } else {
95             // absolute path, but still we should collapse
96             $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path)));
97         }
98         // re-combine
99         $uri->scheme = $this->base->scheme;
100         if (is_null($uri->userinfo)) {
101             $uri->userinfo = $this->base->userinfo;
102         }
103         if (is_null($uri->host)) {
104             $uri->host = $this->base->host;
105         }
106         if (is_null($uri->port)) {
107             $uri->port = $this->base->port;
108         }
109         return true;
110     }
111
112     /**
113      * Resolve dots and double-dots in a path stack
114      * @param array $stack
115      * @return array
116      */
117     private function _collapseStack($stack)
118     {
119         $result = array();
120         $is_folder = false;
121         for ($i = 0; isset($stack[$i]); $i++) {
122             $is_folder = false;
123             // absorb an internally duplicated slash
124             if ($stack[$i] == '' && $i && isset($stack[$i + 1])) {
125                 continue;
126             }
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
133                         $result[] = '';
134                     } elseif ($segment === '..') {
135                         $result[] = '..'; // cannot remove .. with ..
136                     }
137                 } else {
138                     // relative path, preserve the double-dots
139                     $result[] = '..';
140                 }
141                 $is_folder = true;
142                 continue;
143             }
144             if ($stack[$i] == '.') {
145                 // silently absorb
146                 $is_folder = true;
147                 continue;
148             }
149             $result[] = $stack[$i];
150         }
151         if ($is_folder) {
152             $result[] = '';
153         }
154         return $result;
155     }
156 }
157
158 // vim: et sw=4 sts=4