]> git.mxchange.org Git - friendica.git/blob - library/HTMLPurifier/URIFilter/MakeAbsolute.php
make 'PHP "register_argc_argv"' easier to translate, may require fix for po2php
[friendica.git] / 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     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