1 : <?php
2 :
3 : /**
4 : * HTML Purifier's internal representation of a URI.
5 : * @note
6 : * Internal data-structures are completely escaped. If the data needs
7 : * to be used in a non-URI context (which is very unlikely), be sure
8 : * to decode it first. The URI may not necessarily be well-formed until
9 : * validate() is called.
10 : */
11 : class HTMLPurifier_URI
12 1 : {
13 :
14 : public $scheme, $userinfo, $host, $port, $path, $query, $fragment;
15 :
16 : /**
17 : * @note Automatically normalizes scheme and port
18 : */
19 : public function __construct($scheme, $userinfo, $host, $port, $path, $query, $fragment) {
20 2 : $this->scheme = is_null($scheme) || ctype_lower($scheme) ? $scheme : strtolower($scheme);
21 2 : $this->userinfo = $userinfo;
22 2 : $this->host = $host;
23 2 : $this->port = is_null($port) ? $port : (int) $port;
24 2 : $this->path = $path;
25 2 : $this->query = $query;
26 2 : $this->fragment = $fragment;
27 2 : }
28 :
29 : /**
30 : * Retrieves a scheme object corresponding to the URI's scheme/default
31 : * @param $config Instance of HTMLPurifier_Config
32 : * @param $context Instance of HTMLPurifier_Context
33 : * @return Scheme object appropriate for validating this URI
34 : */
35 : public function getSchemeObj($config, $context) {
36 2 : $registry = HTMLPurifier_URISchemeRegistry::instance();
37 2 : if ($this->scheme !== null) {
38 2 : $scheme_obj = $registry->getScheme($this->scheme, $config, $context);
39 2 : if (!$scheme_obj) return false; // invalid scheme, clean it out
40 2 : } else {
41 : // no scheme: retrieve the default one
42 2 : $def = $config->getDefinition('URI');
43 2 : $scheme_obj = $registry->getScheme($def->defaultScheme, $config, $context);
44 2 : if (!$scheme_obj) {
45 : // something funky happened to the default scheme object
46 0 : trigger_error(
47 0 : 'Default scheme object "' . $def->defaultScheme . '" was not readable',
48 : E_USER_WARNING
49 0 : );
50 0 : return false;
51 : }
52 : }
53 2 : return $scheme_obj;
54 : }
55 :
56 : /**
57 : * Generic validation method applicable for all schemes. May modify
58 : * this URI in order to get it into a compliant form.
59 : * @param $config Instance of HTMLPurifier_Config
60 : * @param $context Instance of HTMLPurifier_Context
61 : * @return True if validation/filtering succeeds, false if failure
62 : */
63 : public function validate($config, $context) {
64 :
65 : // ABNF definitions from RFC 3986
66 2 : $chars_sub_delims = '!$&\'()*+,;=';
67 2 : $chars_gen_delims = ':/?#[]@';
68 2 : $chars_pchar = $chars_sub_delims . ':@';
69 :
70 : // validate scheme (MUST BE FIRST!)
71 2 : if (!is_null($this->scheme) && is_null($this->host)) {
72 1 : $def = $config->getDefinition('URI');
73 1 : if ($def->defaultScheme === $this->scheme) {
74 0 : $this->scheme = null;
75 0 : }
76 1 : }
77 :
78 : // validate host
79 2 : if (!is_null($this->host)) {
80 2 : $host_def = new HTMLPurifier_AttrDef_URI_Host();
81 2 : $this->host = $host_def->validate($this->host, $config, $context);
82 2 : if ($this->host === false) $this->host = null;
83 2 : }
84 :
85 : // validate username
86 2 : if (!is_null($this->userinfo)) {
87 0 : $encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . ':');
88 0 : $this->userinfo = $encoder->encode($this->userinfo);
89 0 : }
90 :
91 : // validate port
92 2 : if (!is_null($this->port)) {
93 0 : if ($this->port < 1 || $this->port > 65535) $this->port = null;
94 0 : }
95 :
96 : // validate path
97 2 : $path_parts = array();
98 2 : $segments_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/');
99 2 : if (!is_null($this->host)) {
100 : // path-abempty (hier and relative)
101 2 : $this->path = $segments_encoder->encode($this->path);
102 2 : } elseif ($this->path !== '' && $this->path[0] === '/') {
103 : // path-absolute (hier and relative)
104 0 : if (strlen($this->path) >= 2 && $this->path[1] === '/') {
105 : // This shouldn't ever happen!
106 0 : $this->path = '';
107 0 : } else {
108 0 : $this->path = $segments_encoder->encode($this->path);
109 : }
110 2 : } elseif (!is_null($this->scheme) && $this->path !== '') {
111 : // path-rootless (hier)
112 : // Short circuit evaluation means we don't need to check nz
113 1 : $this->path = $segments_encoder->encode($this->path);
114 2 : } elseif (is_null($this->scheme) && $this->path !== '') {
115 : // path-noscheme (relative)
116 : // (once again, not checking nz)
117 2 : $segment_nc_encoder = new HTMLPurifier_PercentEncoder($chars_sub_delims . '@');
118 2 : $c = strpos($this->path, '/');
119 2 : if ($c !== false) {
120 0 : $this->path =
121 2 : $segment_nc_encoder->encode(substr($this->path, 0, $c)) .
122 2 : $segments_encoder->encode(substr($this->path, $c));
123 2 : } else {
124 0 : $this->path = $segment_nc_encoder->encode($this->path);
125 : }
126 2 : } else {
127 : // path-empty (hier and relative)
128 1 : $this->path = ''; // just to be safe
129 : }
130 :
131 : // qf = query and fragment
132 2 : $qf_encoder = new HTMLPurifier_PercentEncoder($chars_pchar . '/?');
133 :
134 2 : if (!is_null($this->query)) {
135 2 : $this->query = $qf_encoder->encode($this->query);
136 2 : }
137 :
138 2 : if (!is_null($this->fragment)) {
139 2 : $this->fragment = $qf_encoder->encode($this->fragment);
140 2 : }
141 :
142 2 : return true;
143 :
144 : }
145 :
146 : /**
147 : * Convert URI back to string
148 : * @return String URI appropriate for output
149 : */
150 : public function toString() {
151 : // reconstruct authority
152 2 : $authority = null;
153 2 : if (!is_null($this->host)) {
154 2 : $authority = '';
155 2 : if(!is_null($this->userinfo)) $authority .= $this->userinfo . '@';
156 2 : $authority .= $this->host;
157 2 : if(!is_null($this->port)) $authority .= ':' . $this->port;
158 2 : }
159 :
160 : // reconstruct the result
161 2 : $result = '';
162 2 : if (!is_null($this->scheme)) $result .= $this->scheme . ':';
163 2 : if (!is_null($authority)) $result .= '//' . $authority;
164 2 : $result .= $this->path;
165 2 : if (!is_null($this->query)) $result .= '?' . $this->query;
166 2 : if (!is_null($this->fragment)) $result .= '#' . $this->fragment;
167 :
168 2 : return $result;
169 : }
170 :
171 : }
172 :
|