PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/common/libraries/plugin/htmlpurifier/library/HTMLPurifier/URI.php

https://bitbucket.org/renaatdemuynck/chamilo
PHP | 240 lines | 142 code | 21 blank | 77 comment | 28 complexity | 0484b58e045ec01b9c96dcf8c5930176 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT, GPL-2.0
  1. <?php
  2. /**
  3. * HTML Purifier's internal representation of a URI.
  4. * @note
  5. * Internal data-structures are completely escaped. If the data needs
  6. * to be used in a non-URI context (which is very unlikely), be sure
  7. * to decode it first. The URI may not necessarily be well-formed until
  8. * validate() is called.
  9. */
  10. class HTMLPurifier_URI
  11. {
  12. public $scheme, $userinfo, $host, $port, $path, $query, $fragment;
  13. /**
  14. * @note Automatically normalizes scheme and port
  15. */
  16. public function __construct($scheme, $userinfo, $host, $port, $path, $query, $fragment)
  17. {
  18. $this->scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme);
  19. $this->userinfo = $userinfo;
  20. $this->host = $host;
  21. $this->port = is_null($port) ? $port : (int) $port;
  22. $this->path = $path;
  23. $this->query = $query;
  24. $this->fragment = $fragment;
  25. }
  26. /**
  27. * Retrieves a scheme object corresponding to the URI's scheme/default
  28. * @param $config Instance of HTMLPurifier_Config
  29. * @param $context Instance of HTMLPurifier_Context
  30. * @return Scheme object appropriate for validating this URI
  31. */
  32. public function getSchemeObj($config, $context)
  33. {
  34. $registry = HTMLPurifier_URISchemeRegistry :: instance();
  35. if ($this->scheme !== null)
  36. {
  37. $scheme_obj = $registry->getScheme($this->scheme, $config, $context);
  38. if (! $scheme_obj)
  39. return false; // invalid scheme, clean it out
  40. }
  41. else
  42. {
  43. // no scheme: retrieve the default one
  44. $def = $config->getDefinition('URI');
  45. $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context);
  46. if (! $scheme_obj)
  47. {
  48. // something funky happened to the default scheme object
  49. trigger_error('Default scheme object "' . $def->defaultScheme . '" was not readable', E_USER_WARNING);
  50. return false;
  51. }
  52. }
  53. return $scheme_obj;
  54. }
  55. /**
  56. * Generic validation method applicable for all schemes. May modify
  57. * this URI in order to get it into a compliant form.
  58. * @param $config Instance of HTMLPurifier_Config
  59. * @param $context Instance of HTMLPurifier_Context
  60. * @return True if validation/filtering succeeds, false if failure
  61. */
  62. public function validate($config, $context)
  63. {
  64. // ABNF definitions from RFC 3986
  65. $chars_sub_delims = '!$&\'()*+,;=';
  66. $chars_gen_delims = ':/?#[]@';
  67. $chars_pchar = $chars_sub_delims . ':@';
  68. // validate host
  69. if (! is_null($this->host))
  70. {
  71. $host_def = new HTMLPurifier_AttrDef_URI_Host();
  72. $this->host = $host_def->validate($this->host, $config, $context);
  73. if ($this->host === false)
  74. $this->host = null;
  75. }
  76. // validate scheme
  77. // NOTE: It's not appropriate to check whether or not this
  78. // scheme is in our registry, since a URIFilter may convert a
  79. // URI that we don't allow into one we do. So instead, we just
  80. // check if the scheme can be dropped because there is no host
  81. // and it is our default scheme.
  82. if (! is_null($this->scheme) && is_null($this->host) || $this->host === '')
  83. {
  84. // support for relative paths is pretty abysmal when the
  85. // scheme is present, so axe it when possible
  86. $def = $config->getDefinition('URI');
  87. if ($def->defaultScheme === $this->scheme)
  88. {
  89. $this->scheme = null;
  90. }
  91. }
  92. // validate username
  93. if (! is_null($this->userinfo))
  94. {
  95. $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':');
  96. $this->userinfo = $encoder->encode($this->userinfo);
  97. }
  98. // validate port
  99. if (! is_null($this->port))
  100. {
  101. if ($this->port < 1 || $this->port > 65535)
  102. $this->port = null;
  103. }
  104. // validate path
  105. $path_parts = array();
  106. $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/');
  107. if (! is_null($this->host))
  108. { // this catches $this->host === ''
  109. // path-abempty (hier and relative)
  110. // http://www.example.com/my/path
  111. // //www.example.com/my/path (looks odd, but works, and
  112. // recognized by most browsers)
  113. // (this set is valid or invalid on a scheme by scheme
  114. // basis, so we'll deal with it later)
  115. // file:///my/path
  116. // ///my/path
  117. $this->path = $segments_encoder->encode($this->path);
  118. }
  119. elseif ($this->path !== '')
  120. {
  121. if ($this->path[0] === '/')
  122. {
  123. // path-absolute (hier and relative)
  124. // http:/my/path
  125. // /my/path
  126. if (strlen($this->path) >= 2 && $this->path[1] === '/')
  127. {
  128. // This could happen if both the host gets stripped
  129. // out
  130. // http://my/path
  131. // //my/path
  132. $this->path = '';
  133. }
  134. else
  135. {
  136. $this->path = $segments_encoder->encode($this->path);
  137. }
  138. }
  139. elseif (! is_null($this->scheme))
  140. {
  141. // path-rootless (hier)
  142. // http:my/path
  143. // Short circuit evaluation means we don't need to check nz
  144. $this->path = $segments_encoder->encode($this->path);
  145. }
  146. else
  147. {
  148. // path-noscheme (relative)
  149. // my/path
  150. // (once again, not checking nz)
  151. $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@');
  152. $c = strpos($this->path, '/');
  153. if ($c !== false)
  154. {
  155. $this->path = $segment_nc_encoder->encode(substr($this->path, 0, $c)) . $segments_encoder->encode(substr($this->path, $c));
  156. }
  157. else
  158. {
  159. $this->path = $segment_nc_encoder->encode($this->path);
  160. }
  161. }
  162. }
  163. else
  164. {
  165. // path-empty (hier and relative)
  166. $this->path = ''; // just to be safe
  167. }
  168. // qf = query and fragment
  169. $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?');
  170. if (! is_null($this->query))
  171. {
  172. $this->query = $qf_encoder->encode($this->query);
  173. }
  174. if (! is_null($this->fragment))
  175. {
  176. $this->fragment = $qf_encoder->encode($this->fragment);
  177. }
  178. return true;
  179. }
  180. /**
  181. * Convert URI back to string
  182. * @return String URI appropriate for output
  183. */
  184. public function toString()
  185. {
  186. // reconstruct authority
  187. $authority = null;
  188. // there is a rendering difference between a null authority
  189. // (http:foo-bar) and an empty string authority
  190. // (http:///foo-bar).
  191. if (! is_null($this->host))
  192. {
  193. $authority = '';
  194. if (! is_null($this->userinfo))
  195. $authority .= $this->userinfo . '@';
  196. $authority .= $this->host;
  197. if (! is_null($this->port))
  198. $authority .= ':' . $this->port;
  199. }
  200. // Reconstruct the result
  201. // One might wonder about parsing quirks from browsers after
  202. // this reconstruction. Unfortunately, parsing behavior depends
  203. // on what *scheme* was employed (file:///foo is handled *very*
  204. // differently than http:///foo), so unfortunately we have to
  205. // defer to the schemes to do the right thing.
  206. $result = '';
  207. if (! is_null($this->scheme))
  208. $result .= $this->scheme . ':';
  209. if (! is_null($authority))
  210. $result .= '//' . $authority;
  211. $result .= $this->path;
  212. if (! is_null($this->query))
  213. $result .= '?' . $this->query;
  214. if (! is_null($this->fragment))
  215. $result .= '#' . $this->fragment;
  216. return $result;
  217. }
  218. }
  219. // vim: et sw=4 sts=4