| 42 | aurelien | 1 | <?php
 | 
        
           |  |  | 2 |   | 
        
           |  |  | 3 | /**
 | 
        
           |  |  | 4 |  * This is the PHP OpenID library by JanRain, Inc.
 | 
        
           |  |  | 5 |  *
 | 
        
           |  |  | 6 |  * This module contains core utility functionality used by the
 | 
        
           |  |  | 7 |  * library.  See Consumer.php and Server.php for the consumer and
 | 
        
           |  |  | 8 |  * server implementations.
 | 
        
           |  |  | 9 |  *
 | 
        
           |  |  | 10 |  * PHP versions 4 and 5
 | 
        
           |  |  | 11 |  *
 | 
        
           |  |  | 12 |  * LICENSE: See the COPYING file included in this distribution.
 | 
        
           |  |  | 13 |  *
 | 
        
           |  |  | 14 |  * @package OpenID
 | 
        
           |  |  | 15 |  * @author JanRain, Inc. <openid@janrain.com>
 | 
        
           |  |  | 16 |  * @copyright 2005 Janrain, Inc.
 | 
        
           |  |  | 17 |  * @license http://www.gnu.org/copyleft/lesser.html LGPL
 | 
        
           |  |  | 18 |  */
 | 
        
           |  |  | 19 |   | 
        
           |  |  | 20 | /**
 | 
        
           |  |  | 21 |  * Require the fetcher code.
 | 
        
           |  |  | 22 |  */
 | 
        
           |  |  | 23 | require_once "Services/Yadis/PlainHTTPFetcher.php";
 | 
        
           |  |  | 24 | require_once "Services/Yadis/ParanoidHTTPFetcher.php";
 | 
        
           |  |  | 25 | require_once "Auth/OpenID/BigMath.php";
 | 
        
           |  |  | 26 |   | 
        
           |  |  | 27 | /**
 | 
        
           |  |  | 28 |  * Status code returned by the server when the only option is to show
 | 
        
           |  |  | 29 |  * an error page, since we do not have enough information to redirect
 | 
        
           |  |  | 30 |  * back to the consumer. The associated value is an error message that
 | 
        
           |  |  | 31 |  * should be displayed on an HTML error page.
 | 
        
           |  |  | 32 |  *
 | 
        
           |  |  | 33 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 34 |  */
 | 
        
           |  |  | 35 | define('Auth_OpenID_LOCAL_ERROR', 'local_error');
 | 
        
           |  |  | 36 |   | 
        
           |  |  | 37 | /**
 | 
        
           |  |  | 38 |  * Status code returned when there is an error to return in key-value
 | 
        
           |  |  | 39 |  * form to the consumer. The caller should return a 400 Bad Request
 | 
        
           |  |  | 40 |  * response with content-type text/plain and the value as the body.
 | 
        
           |  |  | 41 |  *
 | 
        
           |  |  | 42 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 43 |  */
 | 
        
           |  |  | 44 | define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
 | 
        
           |  |  | 45 |   | 
        
           |  |  | 46 | /**
 | 
        
           |  |  | 47 |  * Status code returned when there is a key-value form OK response to
 | 
        
           |  |  | 48 |  * the consumer. The value associated with this code is the
 | 
        
           |  |  | 49 |  * response. The caller should return a 200 OK response with
 | 
        
           |  |  | 50 |  * content-type text/plain and the value as the body.
 | 
        
           |  |  | 51 |  *
 | 
        
           |  |  | 52 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 53 |  */
 | 
        
           |  |  | 54 | define('Auth_OpenID_REMOTE_OK', 'remote_ok');
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 | /**
 | 
        
           |  |  | 57 |  * Status code returned when there is a redirect back to the
 | 
        
           |  |  | 58 |  * consumer. The value is the URL to redirect back to. The caller
 | 
        
           |  |  | 59 |  * should return a 302 Found redirect with a Location: header
 | 
        
           |  |  | 60 |  * containing the URL.
 | 
        
           |  |  | 61 |  *
 | 
        
           |  |  | 62 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 63 |  */
 | 
        
           |  |  | 64 | define('Auth_OpenID_REDIRECT', 'redirect');
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 | /**
 | 
        
           |  |  | 67 |  * Status code returned when the caller needs to authenticate the
 | 
        
           |  |  | 68 |  * user. The associated value is a {@link Auth_OpenID_ServerRequest}
 | 
        
           |  |  | 69 |  * object that can be used to complete the authentication. If the user
 | 
        
           |  |  | 70 |  * has taken some authentication action, use the retry() method of the
 | 
        
           |  |  | 71 |  * {@link Auth_OpenID_ServerRequest} object to complete the request.
 | 
        
           |  |  | 72 |  *
 | 
        
           |  |  | 73 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 74 |  */
 | 
        
           |  |  | 75 | define('Auth_OpenID_DO_AUTH', 'do_auth');
 | 
        
           |  |  | 76 |   | 
        
           |  |  | 77 | /**
 | 
        
           |  |  | 78 |  * Status code returned when there were no OpenID arguments
 | 
        
           |  |  | 79 |  * passed. This code indicates that the caller should return a 200 OK
 | 
        
           |  |  | 80 |  * response and display an HTML page that says that this is an OpenID
 | 
        
           |  |  | 81 |  * server endpoint.
 | 
        
           |  |  | 82 |  *
 | 
        
           |  |  | 83 |  * @see Auth_OpenID_Server
 | 
        
           |  |  | 84 |  */
 | 
        
           |  |  | 85 | define('Auth_OpenID_DO_ABOUT', 'do_about');
 | 
        
           |  |  | 86 |   | 
        
           |  |  | 87 | /**
 | 
        
           |  |  | 88 |  * Defines for regexes and format checking.
 | 
        
           |  |  | 89 |  */
 | 
        
           |  |  | 90 | define('Auth_OpenID_letters',
 | 
        
           |  |  | 91 |        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
 | 
        
           |  |  | 92 |   | 
        
           |  |  | 93 | define('Auth_OpenID_digits',
 | 
        
           |  |  | 94 |        "0123456789");
 | 
        
           |  |  | 95 |   | 
        
           |  |  | 96 | define('Auth_OpenID_punct',
 | 
        
           |  |  | 97 |        "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
 | 
        
           |  |  | 98 |   | 
        
           |  |  | 99 | if (Auth_OpenID_getMathLib() === null) {
 | 
        
           |  |  | 100 |     define('Auth_OpenID_NO_MATH_SUPPORT', true);
 | 
        
           |  |  | 101 | }
 | 
        
           |  |  | 102 |   | 
        
           |  |  | 103 | /**
 | 
        
           |  |  | 104 |  * The OpenID utility function class.
 | 
        
           |  |  | 105 |  *
 | 
        
           |  |  | 106 |  * @package OpenID
 | 
        
           |  |  | 107 |  * @access private
 | 
        
           |  |  | 108 |  */
 | 
        
           |  |  | 109 | class Auth_OpenID {
 | 
        
           |  |  | 110 |   | 
        
           |  |  | 111 |     /**
 | 
        
           |  |  | 112 |      * These namespaces are automatically fixed in query arguments by
 | 
        
           |  |  | 113 |      * Auth_OpenID::fixArgs.
 | 
        
           |  |  | 114 |      */
 | 
        
           |  |  | 115 |     function getOpenIDNamespaces()
 | 
        
           |  |  | 116 |     {
 | 
        
           |  |  | 117 |         return array('openid',
 | 
        
           |  |  | 118 |                      'sreg');
 | 
        
           |  |  | 119 |     }
 | 
        
           |  |  | 120 |   | 
        
           |  |  | 121 |     /**
 | 
        
           |  |  | 122 |      * Rename query arguments back to 'openid.' from 'openid_'
 | 
        
           |  |  | 123 |      *
 | 
        
           |  |  | 124 |      * @access private
 | 
        
           |  |  | 125 |      * @param array $args An associative array of URL query arguments
 | 
        
           |  |  | 126 |      */
 | 
        
           |  |  | 127 |     function fixArgs($args)
 | 
        
           |  |  | 128 |     {
 | 
        
           |  |  | 129 |         foreach (array_keys($args) as $key) {
 | 
        
           |  |  | 130 |             $fixed = $key;
 | 
        
           |  |  | 131 |             if (preg_match('/^openid/', $key)) {
 | 
        
           |  |  | 132 |                 foreach (Auth_OpenID::getOpenIDNamespaces() as $ns) {
 | 
        
           |  |  | 133 |                     if (preg_match('/'.$ns.'_/', $key)) {
 | 
        
           |  |  | 134 |                         $fixed = preg_replace('/'.$ns.'_/', $ns.'.', $fixed);
 | 
        
           |  |  | 135 |                     }
 | 
        
           |  |  | 136 |                 }
 | 
        
           |  |  | 137 |   | 
        
           |  |  | 138 |                 if ($fixed != $key) {
 | 
        
           |  |  | 139 |                     $val = $args[$key];
 | 
        
           |  |  | 140 |                     unset($args[$key]);
 | 
        
           |  |  | 141 |                     $args[$fixed] = $val;
 | 
        
           |  |  | 142 |                 }
 | 
        
           |  |  | 143 |             }
 | 
        
           |  |  | 144 |         }
 | 
        
           |  |  | 145 |   | 
        
           |  |  | 146 |         return $args;
 | 
        
           |  |  | 147 |     }
 | 
        
           |  |  | 148 |   | 
        
           |  |  | 149 |     /**
 | 
        
           |  |  | 150 |      * Create dir_name as a directory if it does not exist. If it
 | 
        
           |  |  | 151 |      * exists, make sure that it is, in fact, a directory.  Returns
 | 
        
           |  |  | 152 |      * true if the operation succeeded; false if not.
 | 
        
           |  |  | 153 |      *
 | 
        
           |  |  | 154 |      * @access private
 | 
        
           |  |  | 155 |      */
 | 
        
           |  |  | 156 |     function ensureDir($dir_name)
 | 
        
           |  |  | 157 |     {
 | 
        
           |  |  | 158 |         if (is_dir($dir_name) || @mkdir($dir_name)) {
 | 
        
           |  |  | 159 |             return true;
 | 
        
           |  |  | 160 |         } else {
 | 
        
           |  |  | 161 |             if (Auth_OpenID::ensureDir(dirname($dir_name))) {
 | 
        
           |  |  | 162 |                 return is_dir($dir_name) || @mkdir($dir_name);
 | 
        
           |  |  | 163 |             } else {
 | 
        
           |  |  | 164 |                 return false;
 | 
        
           |  |  | 165 |             }
 | 
        
           |  |  | 166 |         }
 | 
        
           |  |  | 167 |     }
 | 
        
           |  |  | 168 |   | 
        
           |  |  | 169 |     /**
 | 
        
           |  |  | 170 |      * Convenience function for getting array values.
 | 
        
           |  |  | 171 |      *
 | 
        
           |  |  | 172 |      * @access private
 | 
        
           |  |  | 173 |      */
 | 
        
           |  |  | 174 |     function arrayGet($arr, $key, $fallback = null)
 | 
        
           |  |  | 175 |     {
 | 
        
           |  |  | 176 |         if (is_array($arr)) {
 | 
        
           |  |  | 177 |             if (array_key_exists($key, $arr)) {
 | 
        
           |  |  | 178 |                 return $arr[$key];
 | 
        
           |  |  | 179 |             } else {
 | 
        
           |  |  | 180 |                 return $fallback;
 | 
        
           |  |  | 181 |             }
 | 
        
           |  |  | 182 |         } else {
 | 
        
           |  |  | 183 |             trigger_error("Auth_OpenID::arrayGet expected " .
 | 
        
           |  |  | 184 |                           "array as first parameter", E_USER_WARNING);
 | 
        
           |  |  | 185 |             return false;
 | 
        
           |  |  | 186 |         }
 | 
        
           |  |  | 187 |     }
 | 
        
           |  |  | 188 |   | 
        
           |  |  | 189 |     /**
 | 
        
           |  |  | 190 |      * Implements the PHP 5 'http_build_query' functionality.
 | 
        
           |  |  | 191 |      *
 | 
        
           |  |  | 192 |      * @access private
 | 
        
           |  |  | 193 |      * @param array $data Either an array key/value pairs or an array
 | 
        
           |  |  | 194 |      * of arrays, each of which holding two values: a key and a value,
 | 
        
           |  |  | 195 |      * sequentially.
 | 
        
           |  |  | 196 |      * @return string $result The result of url-encoding the key/value
 | 
        
           |  |  | 197 |      * pairs from $data into a URL query string
 | 
        
           |  |  | 198 |      * (e.g. "username=bob&id=56").
 | 
        
           |  |  | 199 |      */
 | 
        
           |  |  | 200 |     function httpBuildQuery($data)
 | 
        
           |  |  | 201 |     {
 | 
        
           |  |  | 202 |         $pairs = array();
 | 
        
           |  |  | 203 |         foreach ($data as $key => $value) {
 | 
        
           |  |  | 204 |             if (is_array($value)) {
 | 
        
           |  |  | 205 |                 $pairs[] = urlencode($value[0])."=".urlencode($value[1]);
 | 
        
           |  |  | 206 |             } else {
 | 
        
           |  |  | 207 |                 $pairs[] = urlencode($key)."=".urlencode($value);
 | 
        
           |  |  | 208 |             }
 | 
        
           |  |  | 209 |         }
 | 
        
           |  |  | 210 |         return implode("&", $pairs);
 | 
        
           |  |  | 211 |     }
 | 
        
           |  |  | 212 |   | 
        
           |  |  | 213 |     /**
 | 
        
           |  |  | 214 |      * "Appends" query arguments onto a URL.  The URL may or may not
 | 
        
           |  |  | 215 |      * already have arguments (following a question mark).
 | 
        
           |  |  | 216 |      *
 | 
        
           |  |  | 217 |      * @param string $url A URL, which may or may not already have
 | 
        
           |  |  | 218 |      * arguments.
 | 
        
           |  |  | 219 |      * @param array $args Either an array key/value pairs or an array of
 | 
        
           |  |  | 220 |      * arrays, each of which holding two values: a key and a value,
 | 
        
           |  |  | 221 |      * sequentially.  If $args is an ordinary key/value array, the
 | 
        
           |  |  | 222 |      * parameters will be added to the URL in sorted alphabetical order;
 | 
        
           |  |  | 223 |      * if $args is an array of arrays, their order will be preserved.
 | 
        
           |  |  | 224 |      * @return string $url The original URL with the new parameters added.
 | 
        
           |  |  | 225 |      *
 | 
        
           |  |  | 226 |      */
 | 
        
           |  |  | 227 |     function appendArgs($url, $args)
 | 
        
           |  |  | 228 |     {
 | 
        
           |  |  | 229 |         if (count($args) == 0) {
 | 
        
           |  |  | 230 |             return $url;
 | 
        
           |  |  | 231 |         }
 | 
        
           |  |  | 232 |   | 
        
           |  |  | 233 |         // Non-empty array; if it is an array of arrays, use
 | 
        
           |  |  | 234 |         // multisort; otherwise use sort.
 | 
        
           |  |  | 235 |         if (array_key_exists(0, $args) &&
 | 
        
           |  |  | 236 |             is_array($args[0])) {
 | 
        
           |  |  | 237 |             // Do nothing here.
 | 
        
           |  |  | 238 |         } else {
 | 
        
           |  |  | 239 |             $keys = array_keys($args);
 | 
        
           |  |  | 240 |             sort($keys);
 | 
        
           |  |  | 241 |             $new_args = array();
 | 
        
           |  |  | 242 |             foreach ($keys as $key) {
 | 
        
           |  |  | 243 |                 $new_args[] = array($key, $args[$key]);
 | 
        
           |  |  | 244 |             }
 | 
        
           |  |  | 245 |             $args = $new_args;
 | 
        
           |  |  | 246 |         }
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 |         $sep = '?';
 | 
        
           |  |  | 249 |         if (strpos($url, '?') !== false) {
 | 
        
           |  |  | 250 |             $sep = '&';
 | 
        
           |  |  | 251 |         }
 | 
        
           |  |  | 252 |   | 
        
           |  |  | 253 |         return $url . $sep . Auth_OpenID::httpBuildQuery($args);
 | 
        
           |  |  | 254 |     }
 | 
        
           |  |  | 255 |   | 
        
           |  |  | 256 |     /**
 | 
        
           |  |  | 257 |      * Turn a string into an ASCII string.
 | 
        
           |  |  | 258 |      *
 | 
        
           |  |  | 259 |      * Replace non-ascii characters with a %-encoded, UTF-8
 | 
        
           |  |  | 260 |      * encoding. This function will fail if the input is a string and
 | 
        
           |  |  | 261 |      * there are non-7-bit-safe characters. It is assumed that the
 | 
        
           |  |  | 262 |      * caller will have already translated the input into a Unicode
 | 
        
           |  |  | 263 |      * character sequence, according to the encoding of the HTTP POST
 | 
        
           |  |  | 264 |      * or GET.
 | 
        
           |  |  | 265 |      *
 | 
        
           |  |  | 266 |      * Do not escape anything that is already 7-bit safe, so we do the
 | 
        
           |  |  | 267 |      * minimal transform on the identity URL
 | 
        
           |  |  | 268 |      *
 | 
        
           |  |  | 269 |      * @access private
 | 
        
           |  |  | 270 |      */
 | 
        
           |  |  | 271 |     function quoteMinimal($s)
 | 
        
           |  |  | 272 |     {
 | 
        
           |  |  | 273 |         $res = array();
 | 
        
           |  |  | 274 |         for ($i = 0; $i < strlen($s); $i++) {
 | 
        
           |  |  | 275 |             $c = $s[$i];
 | 
        
           |  |  | 276 |             if ($c >= "\x80") {
 | 
        
           |  |  | 277 |                 for ($j = 0; $j < count(utf8_encode($c)); $j++) {
 | 
        
           |  |  | 278 |                     array_push($res, sprintf("%02X", ord($c[$j])));
 | 
        
           |  |  | 279 |                 }
 | 
        
           |  |  | 280 |             } else {
 | 
        
           |  |  | 281 |                 array_push($res, $c);
 | 
        
           |  |  | 282 |             }
 | 
        
           |  |  | 283 |         }
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 |         return implode('', $res);
 | 
        
           |  |  | 286 |     }
 | 
        
           |  |  | 287 |   | 
        
           |  |  | 288 |     /**
 | 
        
           |  |  | 289 |      * Implements python's urlunparse, which is not available in PHP.
 | 
        
           |  |  | 290 |      * Given the specified components of a URL, this function rebuilds
 | 
        
           |  |  | 291 |      * and returns the URL.
 | 
        
           |  |  | 292 |      *
 | 
        
           |  |  | 293 |      * @access private
 | 
        
           |  |  | 294 |      * @param string $scheme The scheme (e.g. 'http').  Defaults to 'http'.
 | 
        
           |  |  | 295 |      * @param string $host The host.  Required.
 | 
        
           |  |  | 296 |      * @param string $port The port.
 | 
        
           |  |  | 297 |      * @param string $path The path.
 | 
        
           |  |  | 298 |      * @param string $query The query.
 | 
        
           |  |  | 299 |      * @param string $fragment The fragment.
 | 
        
           |  |  | 300 |      * @return string $url The URL resulting from assembling the
 | 
        
           |  |  | 301 |      * specified components.
 | 
        
           |  |  | 302 |      */
 | 
        
           |  |  | 303 |     function urlunparse($scheme, $host, $port = null, $path = '/',
 | 
        
           |  |  | 304 |                                     $query = '', $fragment = '')
 | 
        
           |  |  | 305 |     {
 | 
        
           |  |  | 306 |   | 
        
           |  |  | 307 |         if (!$scheme) {
 | 
        
           |  |  | 308 |             $scheme = 'http';
 | 
        
           |  |  | 309 |         }
 | 
        
           |  |  | 310 |   | 
        
           |  |  | 311 |         if (!$host) {
 | 
        
           |  |  | 312 |             return false;
 | 
        
           |  |  | 313 |         }
 | 
        
           |  |  | 314 |   | 
        
           |  |  | 315 |         if (!$path) {
 | 
        
           |  |  | 316 |             $path = '/';
 | 
        
           |  |  | 317 |         }
 | 
        
           |  |  | 318 |   | 
        
           |  |  | 319 |         $result = $scheme . "://" . $host;
 | 
        
           |  |  | 320 |   | 
        
           |  |  | 321 |         if ($port) {
 | 
        
           |  |  | 322 |             $result .= ":" . $port;
 | 
        
           |  |  | 323 |         }
 | 
        
           |  |  | 324 |   | 
        
           |  |  | 325 |         $result .= $path;
 | 
        
           |  |  | 326 |   | 
        
           |  |  | 327 |         if ($query) {
 | 
        
           |  |  | 328 |             $result .= "?" . $query;
 | 
        
           |  |  | 329 |         }
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 |         if ($fragment) {
 | 
        
           |  |  | 332 |             $result .= "#" . $fragment;
 | 
        
           |  |  | 333 |         }
 | 
        
           |  |  | 334 |   | 
        
           |  |  | 335 |         return $result;
 | 
        
           |  |  | 336 |     }
 | 
        
           |  |  | 337 |   | 
        
           |  |  | 338 |     /**
 | 
        
           |  |  | 339 |      * Given a URL, this "normalizes" it by adding a trailing slash
 | 
        
           |  |  | 340 |      * and / or a leading http:// scheme where necessary.  Returns
 | 
        
           |  |  | 341 |      * null if the original URL is malformed and cannot be normalized.
 | 
        
           |  |  | 342 |      *
 | 
        
           |  |  | 343 |      * @access private
 | 
        
           |  |  | 344 |      * @param string $url The URL to be normalized.
 | 
        
           |  |  | 345 |      * @return mixed $new_url The URL after normalization, or null if
 | 
        
           |  |  | 346 |      * $url was malformed.
 | 
        
           |  |  | 347 |      */
 | 
        
           |  |  | 348 |     function normalizeUrl($url)
 | 
        
           |  |  | 349 |     {
 | 
        
           |  |  | 350 |         if ($url === null) {
 | 
        
           |  |  | 351 |             return null;
 | 
        
           |  |  | 352 |         }
 | 
        
           |  |  | 353 |   | 
        
           |  |  | 354 |         assert(is_string($url));
 | 
        
           |  |  | 355 |   | 
        
           |  |  | 356 |         $old_url = $url;
 | 
        
           |  |  | 357 |         $url = trim($url);
 | 
        
           |  |  | 358 |   | 
        
           |  |  | 359 |         if (strpos($url, "://") === false) {
 | 
        
           |  |  | 360 |             $url = "http://" . $url;
 | 
        
           |  |  | 361 |         }
 | 
        
           |  |  | 362 |   | 
        
           |  |  | 363 |         $parsed = @parse_url($url);
 | 
        
           |  |  | 364 |   | 
        
           |  |  | 365 |         if ($parsed === false) {
 | 
        
           |  |  | 366 |             return null;
 | 
        
           |  |  | 367 |         }
 | 
        
           |  |  | 368 |   | 
        
           |  |  | 369 |         $defaults = array(
 | 
        
           |  |  | 370 |                           'scheme' => '',
 | 
        
           |  |  | 371 |                           'host' => '',
 | 
        
           |  |  | 372 |                           'path' => '',
 | 
        
           |  |  | 373 |                           'query' => '',
 | 
        
           |  |  | 374 |                           'fragment' => '',
 | 
        
           |  |  | 375 |                           'port' => ''
 | 
        
           |  |  | 376 |                           );
 | 
        
           |  |  | 377 |   | 
        
           |  |  | 378 |         $parsed = array_merge($defaults, $parsed);
 | 
        
           |  |  | 379 |   | 
        
           |  |  | 380 |         if (($parsed['scheme'] == '') ||
 | 
        
           |  |  | 381 |             ($parsed['host'] == '')) {
 | 
        
           |  |  | 382 |             if ($parsed['path'] == '' &&
 | 
        
           |  |  | 383 |                 $parsed['query'] == '' &&
 | 
        
           |  |  | 384 |                 $parsed['fragment'] == '') {
 | 
        
           |  |  | 385 |                 return null;
 | 
        
           |  |  | 386 |             }
 | 
        
           |  |  | 387 |   | 
        
           |  |  | 388 |             $url = 'http://' + $url;
 | 
        
           |  |  | 389 |             $parsed = parse_url($url);
 | 
        
           |  |  | 390 |   | 
        
           |  |  | 391 |             $parsed = array_merge($defaults, $parsed);
 | 
        
           |  |  | 392 |         }
 | 
        
           |  |  | 393 |   | 
        
           |  |  | 394 |         $tail = array_map(array('Auth_OpenID', 'quoteMinimal'),
 | 
        
           |  |  | 395 |                           array($parsed['path'],
 | 
        
           |  |  | 396 |                                 $parsed['query'],
 | 
        
           |  |  | 397 |                                 $parsed['fragment']));
 | 
        
           |  |  | 398 |         if ($tail[0] == '') {
 | 
        
           |  |  | 399 |             $tail[0] = '/';
 | 
        
           |  |  | 400 |         }
 | 
        
           |  |  | 401 |   | 
        
           |  |  | 402 |         $url = Auth_OpenID::urlunparse($parsed['scheme'], $parsed['host'],
 | 
        
           |  |  | 403 |                                        $parsed['port'], $tail[0], $tail[1],
 | 
        
           |  |  | 404 |                                        $tail[2]);
 | 
        
           |  |  | 405 |   | 
        
           |  |  | 406 |         assert(is_string($url));
 | 
        
           |  |  | 407 |   | 
        
           |  |  | 408 |         return $url;
 | 
        
           |  |  | 409 |     }
 | 
        
           |  |  | 410 | }
 | 
        
           |  |  | 411 |   | 
        
           |  |  | 412 | ?>
 |