detect.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. <?php
  2. $path_extra = dirname(dirname(__FILE__));
  3. $path = ini_get('include_path');
  4. $path = $path_extra . PATH_SEPARATOR . $path;
  5. ini_set('include_path', $path);
  6. define('IS_WINDOWS', strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
  7. class PlainText {
  8. function start($title)
  9. {
  10. return '';
  11. }
  12. function tt($text)
  13. {
  14. return $text;
  15. }
  16. function link($href, $text=null)
  17. {
  18. if ($text) {
  19. return $text . ' <' . $href . '>';
  20. } else {
  21. return $href;
  22. }
  23. }
  24. function b($text)
  25. {
  26. return '*' . $text . '*';
  27. }
  28. function contentType()
  29. {
  30. return 'text/plain';
  31. }
  32. function p($text)
  33. {
  34. return wordwrap($text) . "\n\n";
  35. }
  36. function pre($text)
  37. {
  38. $out = '';
  39. $lines = array_map('trim', explode("\n", $text));
  40. foreach ($lines as $line) {
  41. $out .= ' ' . $line . "\n";
  42. }
  43. $out .= "\n";
  44. return $out;
  45. }
  46. function ol($items)
  47. {
  48. $out = '';
  49. $c = 1;
  50. foreach ($items as $item) {
  51. $item = wordwrap($item, 72);
  52. $lines = array_map('trim', explode("\n", $item));
  53. $out .= $c . '. ' . $lines[0] . "\n";
  54. unset($lines[0]);
  55. foreach ($lines as $line) {
  56. $out .= ' ' . $line . "\n";
  57. }
  58. $out .= "\n";
  59. $c += 1;
  60. }
  61. return $out;
  62. }
  63. function h2($text)
  64. {
  65. return $this->h($text, 2);
  66. }
  67. function h1($text)
  68. {
  69. return $this->h($text, 1);
  70. }
  71. function h($text, $n)
  72. {
  73. $chars = '#=+-.';
  74. $c = $chars[$n - 1];
  75. return "\n" . $text . "\n" . str_repeat($c, strlen($text)) . "\n\n";
  76. }
  77. function end()
  78. {
  79. return '';
  80. }
  81. }
  82. class HTML {
  83. function start($title)
  84. {
  85. return '<html><head><title>' . $title . '</title>' .
  86. $this->stylesheet().
  87. '</head><body>' . "\n";
  88. }
  89. function stylesheet()
  90. {
  91. return "<style type='text/css'>\n".
  92. "p {\n".
  93. " width: 50em;\n".
  94. "}\n".
  95. '</style>';
  96. }
  97. function tt($text)
  98. {
  99. return '<code>' . $text . '</code>';
  100. }
  101. function contentType()
  102. {
  103. return 'text/html';
  104. }
  105. function b($text)
  106. {
  107. return '<strong>' . $text . '</strong>';
  108. }
  109. function p($text)
  110. {
  111. return '<p>' . wordwrap($text) . "</p>\n";
  112. }
  113. function pre($text)
  114. {
  115. return '<pre>' . $text . "</pre>\n";
  116. }
  117. function ol($items)
  118. {
  119. $out = '<ol>';
  120. foreach ($items as $item) {
  121. $out .= '<li>' . wordwrap($item) . "</li>\n";
  122. }
  123. $out .= "</ol>\n";
  124. return $out;
  125. }
  126. function h($text, $n)
  127. {
  128. return "<h$n>$text</h$n>\n";
  129. }
  130. function h2($text)
  131. {
  132. return $this->h($text, 2);
  133. }
  134. function h1($text)
  135. {
  136. return $this->h($text, 1);
  137. }
  138. function link($href, $text=null)
  139. {
  140. return '<a href="' . $href . '">' . ($text ? $text : $href) . '</a>';
  141. }
  142. function end()
  143. {
  144. return "</body>\n</html>\n";
  145. }
  146. }
  147. if (isset($_SERVER['REQUEST_METHOD'])) {
  148. $r = new HTML();
  149. } else {
  150. $r = new PlainText();
  151. }
  152. function detect_math($r, &$out)
  153. {
  154. $out .= $r->h2('Math support');
  155. $ext = Auth_OpenID_detectMathLibrary(Auth_OpenID_math_extensions());
  156. if (!isset($ext['extension']) || !isset($ext['class'])) {
  157. $out .= $r->p(
  158. 'Your PHP installation does not include big integer math ' .
  159. 'support. This support is required if you wish to run a ' .
  160. 'secure OpenID server without using SSL.');
  161. $out .= $r->p('To use this library, you have a few options:');
  162. $gmp_lnk = $r->link('http://www.php.net/manual/en/ref.gmp.php', 'GMP');
  163. $bc_lnk = $r->link('http://www.php.net/manual/en/ref.bc.php', 'bcmath');
  164. $out .= $r->ol(array(
  165. 'Install the ' . $gmp_lnk . ' PHP extension',
  166. 'Install the ' . $bc_lnk . ' PHP extension',
  167. 'If your site is low-security, call ' .
  168. 'Auth_OpenID_setNoMathSupport(), defined in Auth/OpenID/BigMath.php. ',
  169. 'The library will function, but ' .
  170. 'the security of your OpenID server will depend on the ' .
  171. 'security of the network links involved. If you are only ' .
  172. 'using consumer support, you should still be able to operate ' .
  173. 'securely when the users are communicating with a ' .
  174. 'well-implemented server.'));
  175. return false;
  176. } else {
  177. switch ($ext['extension']) {
  178. case 'bcmath':
  179. $out .= $r->p('Your PHP installation has bcmath support. This is ' .
  180. 'adequate for small-scale use, but can be CPU-intensive. ' .
  181. 'You may want to look into installing the GMP extension.');
  182. $lnk = $r->link('http://www.php.net/manual/en/ref.gmp.php');
  183. $out .= $r->p('See ' . $lnk .' for more information ' .
  184. 'about the GMP extension.');
  185. break;
  186. case 'gmp':
  187. $out .= $r->p('Your PHP installation has gmp support. Good.');
  188. break;
  189. default:
  190. $class = $ext['class'];
  191. $lib = new $class();
  192. $one = $lib->init(1);
  193. $two = $lib->add($one, $one);
  194. $t = $lib->toString($two);
  195. $out .= $r->p('Uh-oh. I do not know about the ' .
  196. $ext['extension'] . ' extension!');
  197. if ($t != '2') {
  198. $out .= $r->p('It looks like it is broken. 1 + 1 = ' .
  199. var_export($t, false));
  200. return false;
  201. } else {
  202. $out .= $r->p('But it seems to be able to add one and one.');
  203. }
  204. }
  205. return true; // Math library is OK
  206. }
  207. }
  208. function detect_random($r, &$out)
  209. {
  210. $out .= $r->h2('Cryptographic-quality randomness source');
  211. if (Auth_OpenID_RAND_SOURCE === null) {
  212. $out .= $r->p('Using (insecure) pseudorandom number source, because ' .
  213. 'Auth_OpenID_RAND_SOURCE has been defined as null.');
  214. return false;
  215. }
  216. $msg = 'The library will try to access ' . Auth_OpenID_RAND_SOURCE
  217. . ' as a source of random data. ';
  218. $numbytes = 6;
  219. $f = @fopen(Auth_OpenID_RAND_SOURCE, 'r');
  220. if ($f !== false) {
  221. $data = fread($f, $numbytes);
  222. $stat = fstat($f);
  223. $size = $stat['size'];
  224. fclose($f);
  225. } else {
  226. $data = null;
  227. $size = true;
  228. }
  229. if ($f !== false) {
  230. $dataok = (Auth_OpenID::bytes($data) == $numbytes);
  231. $ok = $dataok && !$size;
  232. $msg .= 'It seems to exist ';
  233. if ($dataok) {
  234. $msg .= 'and be readable. Here is some hex data: ' .
  235. bin2hex($data) . '.';
  236. } else {
  237. $msg .= 'but reading data failed.';
  238. }
  239. if ($size) {
  240. $msg .= ' This is a ' . $size . ' byte file. Unless you know ' .
  241. 'what you are doing, it is likely that you are making a ' .
  242. 'mistake by using a regular file as a randomness source.';
  243. }
  244. } else {
  245. $msg .= Auth_OpenID_RAND_SOURCE .
  246. ' could not be opened. This could be because of restrictions on' .
  247. ' your PHP environment or that randomness source may not exist' .
  248. ' on this platform.';
  249. if (IS_WINDOWS) {
  250. $msg .= ' You seem to be running Windows. This library does not' .
  251. ' have access to a good source of randomness on Windows.';
  252. }
  253. $ok = false;
  254. }
  255. $out .= $r->p($msg);
  256. if (!$ok) {
  257. $out .= $r->p(
  258. 'To set a source of randomness, define Auth_OpenID_RAND_SOURCE ' .
  259. 'to the path to the randomness source. If your platform does ' .
  260. 'not provide a secure randomness source, the library can' .
  261. 'operate in pseudorandom mode, but it is then vulnerable to ' .
  262. 'theoretical attacks. If you wish to operate in pseudorandom ' .
  263. 'mode, define Auth_OpenID_RAND_SOURCE to null.');
  264. $out .= $r->p('You are running on:');
  265. $out .= $r->pre(php_uname());
  266. $out .= $r->p('There does not seem to be an available source ' .
  267. 'of randomness. On a Unix-like platform ' .
  268. '(including MacOS X), try /dev/random and ' .
  269. '/dev/urandom.');
  270. }
  271. return $ok;
  272. }
  273. function detect_stores($r, &$out)
  274. {
  275. $out .= $r->h2('Data storage');
  276. $found = array();
  277. foreach (array('sqlite', 'mysql', 'pgsql') as $dbext) {
  278. if (extension_loaded($dbext) || @dl($dbext . '.' . PHP_SHLIB_SUFFIX)) {
  279. $found[] = $dbext;
  280. }
  281. }
  282. if (count($found) == 0) {
  283. $text = 'No SQL database support was found in this PHP ' .
  284. 'installation. See the PHP manual if you need to ' .
  285. 'use an SQL database.';
  286. } else {
  287. $text = 'Support was found for ';
  288. if (count($found) == 1) {
  289. $text .= $found[0] . '.';
  290. } else {
  291. $last = array_pop($found);
  292. $text .= implode(', ', $found) . ' and ' . $last . '.';
  293. }
  294. $text = $r->b($text);
  295. }
  296. $text .= ' The library supports the MySQL, PostgreSQL, and SQLite ' .
  297. 'database engines, as well as filesystem-based storage. In ' .
  298. 'addition, PEAR DB is required to use databases.';
  299. $out .= $r->p($text);
  300. if (function_exists('posix_getpwuid') &&
  301. function_exists('posix_geteuid')) {
  302. $processUser = posix_getpwuid(posix_geteuid());
  303. $web_user = $r->b($r->tt($processUser['name']));
  304. } else {
  305. $web_user = 'the PHP process';
  306. }
  307. if (in_array('sqlite', $found)) {
  308. $out .= $r->p('If you are using SQLite, your database must be ' .
  309. 'writable by ' . $web_user . ' and not available over' .
  310. ' the web.');
  311. }
  312. $basedir_str = ini_get('open_basedir');
  313. if (gettype($basedir_str) == 'string') {
  314. $url = 'http://www.php.net/manual/en/features.safe-mode.php' .
  315. '#ini.open-basedir';
  316. $lnk = $r->link($url, 'open_basedir');
  317. $out .= $r->p('If you are using a filesystem-based store or SQLite, ' .
  318. 'be aware that ' . $lnk . ' is in effect. This means ' .
  319. 'that your data will have to be stored in one of the ' .
  320. 'following locations:');
  321. $out .= $r->pre(var_export($basedir_str, true));
  322. } else {
  323. $out .= $r->p('The ' . $r->b($r->tt('open_basedir')) . ' configuration restriction ' .
  324. 'is not in effect.');
  325. }
  326. $out .= $r->p('If you are using the filesystem store, your ' .
  327. 'data directory must be readable and writable by ' .
  328. $web_user . ' and not availabe over the Web.');
  329. return true;
  330. }
  331. function detect_xml($r, &$out)
  332. {
  333. global $__Auth_Yadis_xml_extensions;
  334. $out .= $r->h2('XML Support');
  335. // Try to get an XML extension.
  336. $ext = Auth_Yadis_getXMLParser();
  337. if ($ext !== null) {
  338. $out .= $r->p('XML parsing support is present using the '.
  339. $r->b(get_class($ext)).' interface.');
  340. return true;
  341. } else {
  342. $out .= $r->p('XML parsing support is absent; please install one '.
  343. 'of the following PHP extensions:');
  344. foreach ($__Auth_Yadis_xml_extensions as $name => $cls) {
  345. $out .= "<li>" . $r->b($name) . "</li>";
  346. }
  347. return false;
  348. }
  349. }
  350. function detect_fetcher($r, &$out)
  351. {
  352. $out .= $r->h2('HTTP Fetching');
  353. $result = @include 'Auth/Yadis/Yadis.php';
  354. if (!$result) {
  355. $out .= $r->p('Yadis code unavailable; could not test fetcher support.');
  356. return false;
  357. }
  358. if (Auth_Yadis_Yadis::curlPresent()) {
  359. $out .= $r->p('This PHP installation has support for libcurl. Good.');
  360. } else {
  361. $out .= $r->p('This PHP installation does not have support for ' .
  362. 'libcurl. CURL is not required but is recommended. '.
  363. 'The OpenID library will use an fsockopen()-based fetcher.');
  364. $lnk = $r->link('http://us3.php.net/manual/en/ref.curl.php');
  365. $out .= $r->p('See ' . $lnk . ' about enabling the libcurl support ' .
  366. 'for PHP.');
  367. }
  368. $ok = true;
  369. $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
  370. $fetch_url = 'http://www.openidenabled.com/resources/php-fetch-test';
  371. $expected_url = $fetch_url . '.txt';
  372. $result = $fetcher->get($fetch_url);
  373. if (isset($result)) {
  374. $parts = array('An HTTP request was completed.');
  375. // list ($code, $url, $data) = $result;
  376. if ($result->status != '200' && $result->status != '206') {
  377. $ok = false;
  378. $parts[] = $r->b(
  379. sprintf(
  380. 'Got %s instead of the expected HTTP status ' .
  381. 'code (200 or 206).', $result->status));
  382. }
  383. $url = $result->final_url;
  384. if ($url != $expected_url) {
  385. $ok = false;
  386. if ($url == $fetch_url) {
  387. $msg = 'The redirected URL was not returned.';
  388. } else {
  389. $msg = 'An unexpected URL was returned: <' . $url . '>.';
  390. }
  391. $parts[] = $r->b($msg);
  392. }
  393. $data = $result->body;
  394. if ($data != 'Hello World!') {
  395. $ok = false;
  396. $parts[] = $r->b('Unexpected data was returned.');
  397. }
  398. $out .= $r->p(implode(' ', $parts));
  399. } else {
  400. $ok = false;
  401. $out .= $r->p('Fetching URL ' . $lnk . ' failed!');
  402. }
  403. if ($fetcher->supportsSSL()) {
  404. $out .= $r->p('Your PHP installation appears to support SSL, so it ' .
  405. 'will be able to process HTTPS identity URLs and server URLs.');
  406. } else {
  407. $out .= $r->p('Your PHP installation does not support SSL, so it ' .
  408. 'will NOT be able to process HTTPS identity URLs and server URLs.');
  409. }
  410. return $ok;
  411. }
  412. header('Content-Type: ' . $r->contentType() . '; charset=us-ascii');
  413. $title = 'OpenID Library Support Report';
  414. $out = $r->start($title) .
  415. $r->h1($title) .
  416. $r->p('This script checks your PHP installation to determine if you ' .
  417. 'are set up to use the JanRain PHP OpenID library.');
  418. $body = '';
  419. $_include = include 'Auth/OpenID.php';
  420. if (!$_include) {
  421. $path = ini_get('include_path');
  422. $body .= $r->p(
  423. 'Cannot find the OpenID library. It must be in your PHP include ' .
  424. 'path. Your PHP include path is currently:');
  425. $body .= $r->pre($path);
  426. } else {
  427. $status = array();
  428. $status[] = detect_math($r, $body);
  429. $status[] = detect_random($r, $body);
  430. $status[] = detect_stores($r, $body);
  431. $status[] = detect_fetcher($r, $body);
  432. $status[] = detect_xml($r, $body);
  433. $result = true;
  434. foreach ($status as $v) {
  435. if (!$v) {
  436. $result = false;
  437. break;
  438. }
  439. }
  440. if ($result) {
  441. $out .= $r->h2('Setup Complete!');
  442. $out .= $r->p('Your system should be ready to run the OpenID library.');
  443. } else {
  444. $out .= $r->h2('Setup Incomplete');
  445. $out .= $r->p('Your system needs a few changes before it will be ready to run the OpenID library.');
  446. }
  447. }
  448. $out .= $body . $r->end();
  449. print $out;
  450. ?>