1<?php 2 3/** 4 * URI normalization routines. 5 * 6 * @package OpenID 7 * @author JanRain, Inc. <openid@janrain.com> 8 * @copyright 2005-2008 Janrain, Inc. 9 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 10 */ 11 12require_once 'Auth/Yadis/Misc.php'; 13 14// from appendix B of rfc 3986 (http://www.ietf.org/rfc/rfc3986.txt) 15function Auth_OpenID_getURIPattern() 16{ 17 return '&^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?&'; 18} 19 20function Auth_OpenID_getAuthorityPattern() 21{ 22 return '/^([^@]*@)?([^:]*)(:.*)?/'; 23} 24 25function Auth_OpenID_getEncodedPattern() 26{ 27 return '/%([0-9A-Fa-f]{2})/'; 28} 29 30# gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" 31# 32# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" 33# / "*" / "+" / "," / ";" / "=" 34# 35# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" 36function Auth_OpenID_getURLIllegalCharRE() 37{ 38 return "/([^-A-Za-z0-9:\/\?#\[\]@\!\$&'\(\)\*\+,;=\._~\%])/"; 39} 40 41function Auth_OpenID_getUnreserved() 42{ 43 $_unreserved = array(); 44 for ($i = 0; $i < 256; $i++) { 45 $_unreserved[$i] = false; 46 } 47 48 for ($i = ord('A'); $i <= ord('Z'); $i++) { 49 $_unreserved[$i] = true; 50 } 51 52 for ($i = ord('0'); $i <= ord('9'); $i++) { 53 $_unreserved[$i] = true; 54 } 55 56 for ($i = ord('a'); $i <= ord('z'); $i++) { 57 $_unreserved[$i] = true; 58 } 59 60 $_unreserved[ord('-')] = true; 61 $_unreserved[ord('.')] = true; 62 $_unreserved[ord('_')] = true; 63 $_unreserved[ord('~')] = true; 64 65 return $_unreserved; 66} 67 68function Auth_OpenID_getEscapeRE() 69{ 70 $parts = array(); 71 foreach (array_merge(Auth_Yadis_getUCSChars(), 72 Auth_Yadis_getIPrivateChars()) as $pair) { 73 list($m, $n) = $pair; 74 $parts[] = sprintf("%s-%s", chr($m), chr($n)); 75 } 76 77 return sprintf('[%s]', implode('', $parts)); 78} 79 80function Auth_OpenID_pct_encoded_replace_unreserved($mo) 81{ 82 $_unreserved = Auth_OpenID_getUnreserved(); 83 84 $i = intval($mo[1], 16); 85 if ($_unreserved[$i]) { 86 return chr($i); 87 } else { 88 return strtoupper($mo[0]); 89 } 90 91 return $mo[0]; 92} 93 94function Auth_OpenID_pct_encoded_replace($mo) 95{ 96 return chr(intval($mo[1], 16)); 97} 98 99function Auth_OpenID_remove_dot_segments($path) 100{ 101 $result_segments = array(); 102 103 while ($path) { 104 if (Auth_Yadis_startswith($path, '../')) { 105 $path = substr($path, 3); 106 } else if (Auth_Yadis_startswith($path, './')) { 107 $path = substr($path, 2); 108 } else if (Auth_Yadis_startswith($path, '/./')) { 109 $path = substr($path, 2); 110 } else if ($path == '/.') { 111 $path = '/'; 112 } else if (Auth_Yadis_startswith($path, '/../')) { 113 $path = substr($path, 3); 114 if ($result_segments) { 115 array_pop($result_segments); 116 } 117 } else if ($path == '/..') { 118 $path = '/'; 119 if ($result_segments) { 120 array_pop($result_segments); 121 } 122 } else if (($path == '..') || 123 ($path == '.')) { 124 $path = ''; 125 } else { 126 $i = 0; 127 if ($path[0] == '/') { 128 $i = 1; 129 } 130 $i = strpos($path, '/', $i); 131 if ($i === false) { 132 $i = strlen($path); 133 } 134 $result_segments[] = substr($path, 0, $i); 135 $path = substr($path, $i); 136 } 137 } 138 139 return implode('', $result_segments); 140} 141 142function Auth_OpenID_urinorm($uri) 143{ 144 $uri_matches = array(); 145 preg_match(Auth_OpenID_getURIPattern(), $uri, $uri_matches); 146 147 if (count($uri_matches) < 9) { 148 for ($i = count($uri_matches); $i <= 9; $i++) { 149 $uri_matches[] = ''; 150 } 151 } 152 153 $illegal_matches = array(); 154 preg_match(Auth_OpenID_getURLIllegalCharRE(), 155 $uri, $illegal_matches); 156 if ($illegal_matches) { 157 return null; 158 } 159 160 $scheme = $uri_matches[2]; 161 if ($scheme) { 162 $scheme = strtolower($scheme); 163 } 164 165 $scheme = $uri_matches[2]; 166 if ($scheme === '') { 167 // No scheme specified 168 return null; 169 } 170 171 $scheme = strtolower($scheme); 172 if (!in_array($scheme, array('http', 'https'))) { 173 // Not an absolute HTTP or HTTPS URI 174 return null; 175 } 176 177 $authority = $uri_matches[4]; 178 if ($authority === '') { 179 // Not an absolute URI 180 return null; 181 } 182 183 $authority_matches = array(); 184 preg_match(Auth_OpenID_getAuthorityPattern(), 185 $authority, $authority_matches); 186 if (count($authority_matches) === 0) { 187 // URI does not have a valid authority 188 return null; 189 } 190 191 if (count($authority_matches) < 4) { 192 for ($i = count($authority_matches); $i <= 4; $i++) { 193 $authority_matches[] = ''; 194 } 195 } 196 197 list($_whole, $userinfo, $host, $port) = $authority_matches; 198 199 if ($userinfo === null) { 200 $userinfo = ''; 201 } 202 203 if (strpos($host, '%') !== -1) { 204 $host = strtolower($host); 205 $host = preg_replace_callback( 206 Auth_OpenID_getEncodedPattern(), 207 'Auth_OpenID_pct_encoded_replace', $host); 208 // NO IDNA. 209 // $host = unicode($host, 'utf-8').encode('idna'); 210 } else { 211 $host = strtolower($host); 212 } 213 214 if ($port) { 215 if (($port == ':') || 216 ($scheme == 'http' && $port == ':80') || 217 ($scheme == 'https' && $port == ':443')) { 218 $port = ''; 219 } 220 } else { 221 $port = ''; 222 } 223 224 $authority = $userinfo . $host . $port; 225 226 $path = $uri_matches[5]; 227 $path = preg_replace_callback( 228 Auth_OpenID_getEncodedPattern(), 229 'Auth_OpenID_pct_encoded_replace_unreserved', $path); 230 231 $path = Auth_OpenID_remove_dot_segments($path); 232 if (!$path) { 233 $path = '/'; 234 } 235 236 $query = $uri_matches[6]; 237 if ($query === null) { 238 $query = ''; 239 } 240 241 $fragment = $uri_matches[8]; 242 if ($fragment === null) { 243 $fragment = ''; 244 } 245 246 return $scheme . '://' . $authority . $path . $query . $fragment; 247} 248 249 250