PHP OpenID consumer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

discoverer.inc.php 4.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?PHP
  2. /* Poidsy 0.4 - http://chris.smith.name/projects/poidsy
  3. * Copyright (c) 2008 Chris Smith
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. */
  23. class Discoverer {
  24. private $server = null;
  25. private $delegate = '';
  26. private $identity = '';
  27. private $version = 1;
  28. public function __construct($uri) {
  29. if ($uri !== null) {
  30. $this->discover($this->identity = $this->normalise($uri));
  31. }
  32. }
  33. public function getServer() {
  34. return $this->server;
  35. }
  36. public function getDelegate() {
  37. return $this->delegate;
  38. }
  39. public function getIdentity() {
  40. return $this->identity;
  41. }
  42. public function getVersion() {
  43. return $this->version;
  44. }
  45. public static function normalise($uri) {
  46. // Strip xri:// prefix
  47. if (substr($uri, 0, 6) == 'xri://') {
  48. $uri = substr($uri, 6);
  49. }
  50. // If the first char is a global context symbol, treat it as XRI
  51. if (in_array($uri[0], array('=', '@', '+', '$', '!'))) {
  52. // TODO: Implement
  53. throw new Exception('This implementation does not currently support XRI');
  54. }
  55. // Add http:// if needed
  56. if (strpos($uri, '://') === false) {
  57. $uri = 'http://' . $uri;
  58. }
  59. $bits = @parse_url($uri);
  60. $result = $bits['scheme'] . '://';
  61. if (defined('OPENID_ALLOWUSER') && isset($bits['user'])) {
  62. $result .= $bits['user'];
  63. if (isset($bits['pass'])) {
  64. $result .= ':' . $bits['pass'];
  65. }
  66. $result .= '@';
  67. }
  68. $result .= preg_replace('/\.$/', '', $bits['host']);
  69. if (isset($bits['port']) && !empty($bits['port']) &&
  70. (($bits['scheme'] == 'http' && $bits['port'] != '80') ||
  71. ($bits['scheme'] == 'https' && $bits['port'] != '443') ||
  72. ($bits['scheme'] != 'http' && $bits['scheme'] != 'https'))) {
  73. $result .= ':' . $bits['port'];
  74. }
  75. if (isset($bits['path'])) {
  76. do {
  77. $bits['path'] = preg_replace('#/([^/]*)/\.\./#', '/', str_replace('/./', '/', $old = $bits['path']));
  78. } while ($old != $bits['path']);
  79. $result .= $bits['path'];
  80. } else {
  81. $result .= '/';
  82. }
  83. if (defined('OPENID_ALLOWQUERY') && isset($bits['query'])) {
  84. $result .= '?' . $bits['query'];
  85. }
  86. return $result;
  87. }
  88. private function discover($uri) {
  89. // TODO: Yaris discovery
  90. $this->delegate = $uri;
  91. $this->server = null;
  92. $this->htmlDiscover($uri);
  93. }
  94. private function htmlDiscover($uri) {
  95. $fh = @fopen($uri, 'r');
  96. if (!$fh) {
  97. return;
  98. }
  99. $details = stream_get_meta_data($fh);
  100. foreach ($details['wrapper_data'] as $line) {
  101. if (preg_match('/^Location: (.*?)$/i', $line, $m)) {
  102. if (strpos($m[1], '://') !== false) {
  103. // Fully qualified URL
  104. $this->identity = $m[1];
  105. } else if ($m[1][0] == '/') {
  106. // Absolute URL
  107. $this->identity = preg_replace('#^(.*?://.*?)/.*$#', '\1', $this->identity) . $m[1];
  108. } else {
  109. // Relative URL
  110. $this->identity = preg_replace('#^(.*?://.*/).*?$#', '\1', $this->identity) . $m[1];
  111. }
  112. }
  113. $this->identity = self::normalise($this->identity);
  114. }
  115. $data = '';
  116. while (!feof($fh) && strpos($data, '</head>') === false) {
  117. $data .= fgets($fh);
  118. }
  119. fclose($fh);
  120. $this->parseHtml($data);
  121. }
  122. public function parseHtml($data) {
  123. preg_match_all('#<link\s*(.*?)\s*/?>#is', $data, $matches);
  124. $links = array();
  125. foreach ($matches[1] as $link) {
  126. $rel = $href = null;
  127. if (preg_match('#rel\s*=\s*(?:([^"\'>\s]*)|"([^">]*)"|\'([^\'>]*)\')(?:\s|$)#is', $link, $m)) {
  128. array_shift($m);
  129. $rel = implode('', $m);
  130. }
  131. if (preg_match('#href\s*=\s*(?:([^"\'>\s]*)|"([^">]*)"|\'([^\'>]*)\')(?:\s|$)#is', $link, $m)) {
  132. array_shift($m);
  133. $href = implode('', $m);
  134. }
  135. $links[$rel] = html_entity_decode($href);
  136. }
  137. if (isset($links['openid2.provider'])) {
  138. $this->version = 2;
  139. $this->server = $links['openid2.provider'];
  140. if (isset($links['openid2.local_id'])) {
  141. $this->delegate = $links['openid2.local_id'];
  142. }
  143. } else if (isset($links['openid.server'])) {
  144. $this->version = 1;
  145. $this->server = $links['openid.server'];
  146. if (isset($links['openid.delegate'])) {
  147. $this->delegate = $links['openid.delegate'];
  148. }
  149. }
  150. }
  151. }
  152. ?>