PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/openid_192/Auth/OpenID.php

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