File indexing completed on 2025-02-02 05:43:44
0001 <?php 0002 0003 // does not support network paths 0004 0005 class HTMLPurifier_URIFilter_MakeAbsolute extends HTMLPurifier_URIFilter 0006 { 0007 /** 0008 * @type string 0009 */ 0010 public $name = 'MakeAbsolute'; 0011 0012 /** 0013 * @type 0014 */ 0015 protected $base; 0016 0017 /** 0018 * @type array 0019 */ 0020 protected $basePathStack = array(); 0021 0022 /** 0023 * @param HTMLPurifier_Config $config 0024 * @return bool 0025 */ 0026 public function prepare($config) 0027 { 0028 $def = $config->getDefinition('URI'); 0029 $this->base = $def->base; 0030 if (is_null($this->base)) { 0031 trigger_error( 0032 'URI.MakeAbsolute is being ignored due to lack of ' . 0033 'value for URI.Base configuration', 0034 E_USER_WARNING 0035 ); 0036 return false; 0037 } 0038 $this->base->fragment = null; // fragment is invalid for base URI 0039 $stack = explode('/', $this->base->path); 0040 array_pop($stack); // discard last segment 0041 $stack = $this->_collapseStack($stack); // do pre-parsing 0042 $this->basePathStack = $stack; 0043 return true; 0044 } 0045 0046 /** 0047 * @param HTMLPurifier_URI $uri 0048 * @param HTMLPurifier_Config $config 0049 * @param HTMLPurifier_Context $context 0050 * @return bool 0051 */ 0052 public function filter(&$uri, $config, $context) 0053 { 0054 if (is_null($this->base)) { 0055 return true; 0056 } // abort early 0057 if ($uri->path === '' && is_null($uri->scheme) && 0058 is_null($uri->host) && is_null($uri->query) && is_null($uri->fragment)) { 0059 // reference to current document 0060 $uri = clone $this->base; 0061 return true; 0062 } 0063 if (!is_null($uri->scheme)) { 0064 // absolute URI already: don't change 0065 if (!is_null($uri->host)) { 0066 return true; 0067 } 0068 $scheme_obj = $uri->getSchemeObj($config, $context); 0069 if (!$scheme_obj) { 0070 // scheme not recognized 0071 return false; 0072 } 0073 if (!$scheme_obj->hierarchical) { 0074 // non-hierarchal URI with explicit scheme, don't change 0075 return true; 0076 } 0077 // special case: had a scheme but always is hierarchical and had no authority 0078 } 0079 if (!is_null($uri->host)) { 0080 // network path, don't bother 0081 return true; 0082 } 0083 if ($uri->path === '') { 0084 $uri->path = $this->base->path; 0085 } elseif ($uri->path[0] !== '/') { 0086 // relative path, needs more complicated processing 0087 $stack = explode('/', $uri->path); 0088 $new_stack = array_merge($this->basePathStack, $stack); 0089 if ($new_stack[0] !== '' && !is_null($this->base->host)) { 0090 array_unshift($new_stack, ''); 0091 } 0092 $new_stack = $this->_collapseStack($new_stack); 0093 $uri->path = implode('/', $new_stack); 0094 } else { 0095 // absolute path, but still we should collapse 0096 $uri->path = implode('/', $this->_collapseStack(explode('/', $uri->path))); 0097 } 0098 // re-combine 0099 $uri->scheme = $this->base->scheme; 0100 if (is_null($uri->userinfo)) { 0101 $uri->userinfo = $this->base->userinfo; 0102 } 0103 if (is_null($uri->host)) { 0104 $uri->host = $this->base->host; 0105 } 0106 if (is_null($uri->port)) { 0107 $uri->port = $this->base->port; 0108 } 0109 return true; 0110 } 0111 0112 /** 0113 * Resolve dots and double-dots in a path stack 0114 * @param array $stack 0115 * @return array 0116 */ 0117 private function _collapseStack($stack) 0118 { 0119 $result = array(); 0120 $is_folder = false; 0121 for ($i = 0; isset($stack[$i]); $i++) { 0122 $is_folder = false; 0123 // absorb an internally duplicated slash 0124 if ($stack[$i] == '' && $i && isset($stack[$i + 1])) { 0125 continue; 0126 } 0127 if ($stack[$i] == '..') { 0128 if (!empty($result)) { 0129 $segment = array_pop($result); 0130 if ($segment === '' && empty($result)) { 0131 // error case: attempted to back out too far: 0132 // restore the leading slash 0133 $result[] = ''; 0134 } elseif ($segment === '..') { 0135 $result[] = '..'; // cannot remove .. with .. 0136 } 0137 } else { 0138 // relative path, preserve the double-dots 0139 $result[] = '..'; 0140 } 0141 $is_folder = true; 0142 continue; 0143 } 0144 if ($stack[$i] == '.') { 0145 // silently absorb 0146 $is_folder = true; 0147 continue; 0148 } 0149 $result[] = $stack[$i]; 0150 } 0151 if ($is_folder) { 0152 $result[] = ''; 0153 } 0154 return $result; 0155 } 0156 } 0157 0158 // vim: et sw=4 sts=4