PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/wiki/extensions/OpenID/SpecialOpenIDServer.body.php

https://bitbucket.org/openfarmtechwiki/wiki-content
PHP | 755 lines | 536 code | 142 blank | 77 comment | 103 complexity | bf4a048e2e870746e376e8d4f27bcd9f MD5 | raw file
  1. <?php
  2. /**
  3. * SpecialOpenIDServer.body.php -- Server side of OpenID site
  4. * Copyright 2006,2007 Internet Brands (http://www.internetbrands.com/)
  5. * Copyright 2007,2008 Evan Prodromou <evan@prodromou.name>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. *
  21. * @author Evan Prodromou <evan@prodromou.name>
  22. * @addtogroup Extensions
  23. */
  24. if ( !defined( 'MEDIAWIKI' ) )
  25. exit( 1 );
  26. require_once( "Auth/OpenID/Server.php" );
  27. require_once( "Auth/OpenID/Consumer.php" );
  28. # Special page for the server side of OpenID
  29. # It has three major flavors:
  30. # * no parameter is for external requests to validate a user.
  31. # * 'Login' is we got a validation request but the
  32. # user wasn't logged in. We show them a form (see OpenIDServerLoginForm)
  33. # and they post the results, which go to OpenIDServerLogin
  34. # * 'Trust' is when the user has logged in, but they haven't
  35. # specified whether it's OK to let the requesting site trust them.
  36. # If they haven't, we show them a form (see OpenIDServerTrustForm)
  37. # and let them post results which go to OpenIDServerTrust.
  38. #
  39. # OpenID has its own modes; we only handle two of them ('check_setup' and
  40. # 'check_immediate') and let the OpenID libraries handle the rest.
  41. #
  42. # Output may be just a redirect, or a form if we need info.
  43. class SpecialOpenIDServer extends SpecialOpenID {
  44. function SpecialOpenIDServer() {
  45. SpecialPage::SpecialPage( "OpenIDServer", '', false );
  46. }
  47. function execute( $par ) {
  48. global $wgOut, $wgOpenIDClientOnly;
  49. wfLoadExtensionMessages( 'OpenID' );
  50. $this->setHeaders();
  51. # No server functionality if this site is only a client
  52. # Note: special page is un-registered if this flag is set,
  53. # so it'd be unusual to get here.
  54. if ( $wgOpenIDClientOnly ) {
  55. $wgOut->showErrorPage( 'openiderror', 'openidclientonlytext' );
  56. return;
  57. }
  58. wfSuppressWarnings();
  59. $server = $this->getServer();
  60. wfRestoreWarnings();
  61. switch ( $par ) {
  62. case 'Login':
  63. list( $request, $sreg ) = $this->FetchValues();
  64. $result = $this->serverLogin( $request );
  65. if ( $result ) {
  66. if ( is_string( $result ) ) {
  67. $this->LoginForm( $request, $result );
  68. return;
  69. } else {
  70. $this->Response( $server, $result );
  71. return;
  72. }
  73. }
  74. break;
  75. case 'Trust':
  76. list( $request, $sreg ) = $this->FetchValues();
  77. $result = $this->Trust( $request, $sreg );
  78. if ( $result ) {
  79. if ( is_string( $result ) ) {
  80. $this->TrustForm( $request, $sreg, $result );
  81. return;
  82. } else {
  83. $this->Response( $server, $result );
  84. return;
  85. }
  86. }
  87. break;
  88. default:
  89. if ( strlen( $par ) ) {
  90. wfDebug( "OpenID: aborting in user validation because the parameter was empty\n" );
  91. $wgOut->showErrorPage( 'openiderror', 'openiderrortext' );
  92. return;
  93. } else {
  94. $method = $_SERVER['REQUEST_METHOD'];
  95. $query = null;
  96. if ( $method == 'GET' ) {
  97. $query = $_GET;
  98. } else {
  99. $query = $_POST;
  100. }
  101. wfSuppressWarnings();
  102. $request = $server->decodeRequest();
  103. wfRestoreWarnings();
  104. $sreg = $this->SregFromQuery( $query );
  105. $response = null;
  106. break;
  107. }
  108. }
  109. if ( !isset( $request ) ) {
  110. wfDebug( "OpenID: aborting in user validation because the request was missing\n" );
  111. $wgOut->showErrorPage( 'openiderror', 'openiderrortext' );
  112. return;
  113. }
  114. global $wgUser;
  115. switch ( $request->mode ) {
  116. case "checkid_setup":
  117. $response = $this->Check( $server, $request, $sreg, false );
  118. break;
  119. case "checkid_immediate":
  120. $response = $this->Check( $server, $request, $sreg, true );
  121. break;
  122. default:
  123. # For all the other parts, just let the libs do it
  124. wfSuppressWarnings();
  125. $response =& $server->handleRequest( $request );
  126. wfRestoreWarnings();
  127. }
  128. # OpenIDServerCheck returns NULL if some output (like a form)
  129. # has been done
  130. if ( isset( $response ) ) {
  131. # We're done; clear values
  132. $this->ClearValues();
  133. $this->Response( $server, $response );
  134. }
  135. }
  136. # Returns the full URL of the special page; we need to pass it around
  137. # for some requests
  138. function Url() {
  139. $nt = Title::makeTitleSafe( NS_SPECIAL, 'OpenIDServer' );
  140. if ( isset( $nt ) ) {
  141. return $nt->getFullURL();
  142. } else {
  143. return null;
  144. }
  145. }
  146. # Returns an Auth_OpenID_Server from the libraries. Utility.
  147. function getServer() {
  148. global $wgOpenIDServerStorePath,
  149. $wgOpenIDServerStoreType;
  150. $store = $this->getOpenIDStore( $wgOpenIDServerStoreType,
  151. 'server',
  152. array( 'path' => $wgOpenIDServerStorePath ) );
  153. return new Auth_OpenID_Server( $store, $this->serverUrl() );
  154. }
  155. # Checks a validation request. $imm means don't run any UI.
  156. # Fairly meticulous and step-by step, and uses assertions
  157. # to point out assumptions at each step.
  158. #
  159. # FIXME: this should probably be broken up into multiple functions for
  160. # clarity.
  161. function Check( $server, $request, $sreg, $imm = true ) {
  162. global $wgUser, $wgOut;
  163. assert( isset( $wgUser ) && isset( $wgOut ) );
  164. assert( isset( $server ) );
  165. assert( isset( $request ) );
  166. assert( isset( $sreg ) );
  167. assert( isset( $imm ) && is_bool( $imm ) );
  168. # Is the passed identity URL a user page?
  169. $url = $request->identity;
  170. assert( isset( $url ) && strlen( $url ) > 0 );
  171. $name = $this->UrlToUserName( $url );
  172. if ( !isset( $name ) || strlen( $name ) == 0 ) {
  173. wfDebug( "OpenID: '$url' not a user page.\n" );
  174. return $request->answer( false, $this->serverUrl() );
  175. }
  176. assert( isset( $name ) && strlen( $name ) > 0 );
  177. # Is there a logged in user?
  178. if ( $wgUser->getId() == 0 ) {
  179. wfDebug( "OpenID: User not logged in.\n" );
  180. if ( $imm ) {
  181. return $request->answer( false, $this->serverUrl() );
  182. } else {
  183. # Bank these for later
  184. $this->SaveValues( $request, $sreg );
  185. $this->LoginForm( $request );
  186. return null;
  187. }
  188. }
  189. assert( $wgUser->getId() != 0 );
  190. # Is the user page for the logged-in user?
  191. $user = User::newFromName( $name );
  192. if ( !isset( $user ) ||
  193. $user->getId() != $wgUser->getId() ) {
  194. wfDebug( "OpenID: User from url not logged in user.\n" );
  195. return $request->answer( false, $this->serverUrl() );
  196. }
  197. assert( isset( $user ) && $user->getId() == $wgUser->getId() && $user->getId() != 0 );
  198. # Is the user an OpenID user?
  199. if ( $this->getUserUrl( $user ) ) {
  200. wfDebug( "OpenID: Not one of our users; logs in with OpenID.\n" );
  201. return $request->answer( false, $this->serverUrl() );
  202. }
  203. assert( is_array( $sreg ) );
  204. # Does the request require sreg fields that the user has not specified?
  205. if ( array_key_exists( 'required', $sreg ) ) {
  206. $notFound = false;
  207. foreach ( $sreg['required'] as $reqfield ) {
  208. if ( is_null( $this->GetUserField( $user, $reqfield ) ) ) {
  209. $notFound = true;
  210. break;
  211. }
  212. }
  213. if ( $notFound ) {
  214. wfDebug( "OpenID: Consumer demands info we don't have.\n" );
  215. return $request->answer( false, $this->serverUrl() );
  216. }
  217. }
  218. # Trust check
  219. $trust_root = $request->trust_root;
  220. assert( isset( $trust_root ) && is_string( $trust_root ) && strlen( $trust_root ) > 0 );
  221. $trust = $this->GetUserTrust( $user, $trust_root );
  222. # Is there a trust record?
  223. if ( is_null( $trust ) ) {
  224. wfDebug( "OpenID: No trust record.\n" );
  225. if ( $imm ) {
  226. return $request->answer( false, $this->serverUrl() );
  227. } else {
  228. # Bank these for later
  229. $this->SaveValues( $request, $sreg );
  230. $this->TrustForm( $request, $sreg );
  231. return null;
  232. }
  233. }
  234. assert( !is_null( $trust ) );
  235. # Is the trust record _not_ to allow trust?
  236. # NB: exactly equal
  237. if ( $trust === false ) {
  238. wfDebug( "OpenID: User specified not to allow trust.\n" );
  239. return $request->answer( false, $this->serverUrl() );
  240. }
  241. assert( isset( $trust ) && is_array( $trust ) );
  242. # Does the request require sreg fields that the user has
  243. # not allowed us to pass, or has not specified?
  244. if ( array_key_exists( 'required', $sreg ) ) {
  245. $notFound = false;
  246. foreach ( $sreg['required'] as $reqfield ) {
  247. if ( !in_array( $reqfield, $trust ) ||
  248. is_null( $this->GetUserField( $user, $reqfield ) ) ) {
  249. $notFound = true;
  250. break;
  251. }
  252. }
  253. if ( $notFound ) {
  254. wfDebug( "OpenID: Consumer demands info user doesn't want shared.\n" );
  255. return $request->answer( false, $this->serverUrl() );
  256. }
  257. }
  258. # assert(all required sreg fields are in $trust)
  259. # FIXME: run a hook here to check
  260. # SUCCESS
  261. $response_fields = array_intersect( array_unique( array_merge( $sreg['required'], $sreg['optional'] ) ),
  262. $trust );
  263. wfSuppressWarnings();
  264. $response = $request->answer( true );
  265. wfRestoreWarnings();
  266. assert( isset( $response ) );
  267. foreach ( $response_fields as $field ) {
  268. $value = $this->GetUserField( $user, $field );
  269. if ( !is_null( $value ) ) {
  270. $response->addField( 'sreg', $field, $value );
  271. }
  272. }
  273. return $response;
  274. }
  275. # Get the user's configured trust value for a particular trust root.
  276. # Returns one of three values:
  277. # * NULL -> no stored trust preferences
  278. # * false -> stored trust preference is not to trust
  279. # * array -> possibly empty array of allowed profile fields; trust is OK
  280. function GetUserTrust( $user, $trust_root ) {
  281. static $allFields = array( 'nickname', 'fullname', 'email', 'language' );
  282. global $wgOpenIDServerForceAllowTrust;
  283. foreach ( $wgOpenIDServerForceAllowTrust as $force ) {
  284. if ( preg_match( $force, $trust_root ) ) {
  285. return $allFields;
  286. }
  287. }
  288. $trust_array = $this->GetUserTrustArray( $user );
  289. if ( array_key_exists( $trust_root, $trust_array ) ) {
  290. return $trust_array[$trust_root];
  291. } else {
  292. return null; # Unspecified trust
  293. }
  294. }
  295. function SetUserTrust( &$user, $trust_root, $value ) {
  296. $trust_array = $this->GetUserTrustArray( $user );
  297. if ( is_null( $value ) ) {
  298. if ( array_key_exists( $trust_root, $trust_array ) ) {
  299. unset( $trust_array[$trust_root] );
  300. }
  301. } else {
  302. $trust_array[$trust_root] = $value;
  303. }
  304. $this->SetUserTrustArray( $user, $trust_array );
  305. }
  306. function GetUserTrustArray( $user ) {
  307. $trust_array = array();
  308. $trust_str = $user->getOption( 'openid_trust' );
  309. if ( strlen( $trust_str ) > 0 ) {
  310. $trust_records = explode( "\x1E", $trust_str );
  311. foreach ( $trust_records as $record ) {
  312. $fields = explode( "\x1F", $record );
  313. $trust_root = array_shift( $fields );
  314. if ( count( $fields ) == 1 && strcmp( $fields[0], 'no' ) == 0 ) {
  315. $trust_array[$trust_root] = false;
  316. } else {
  317. $fields = array_map( 'trim', $fields );
  318. $fields = array_filter( $fields, array( $this, 'ValidField' ) );
  319. $trust_array[$trust_root] = $fields;
  320. }
  321. }
  322. }
  323. return $trust_array;
  324. }
  325. function SetUserTrustArray( &$user, $arr ) {
  326. $trust_records = array();
  327. foreach ( $arr as $root => $value ) {
  328. if ( $value === false ) {
  329. $record = implode( "\x1F", array( $root, 'no' ) );
  330. } else if ( is_array( $value ) ) {
  331. if ( count( $value ) == 0 ) {
  332. $record = $root;
  333. } else {
  334. $value = array_map( 'trim', $value );
  335. $value = array_filter( $value, array( $this, 'ValidField' ) );
  336. $record = implode( "\x1F", array_merge( array( $root ), $value ) );
  337. }
  338. } else {
  339. continue;
  340. }
  341. $trust_records[] = $record;
  342. }
  343. $trust_str = implode( "\x1E", $trust_records );
  344. $user->setOption( 'openid_trust', $trust_str );
  345. }
  346. function ValidField( $name ) {
  347. # FIXME: eventually add timezone
  348. static $fields = array( 'nickname', 'email', 'fullname', 'language' );
  349. return in_array( $name, $fields );
  350. }
  351. function SregFromQuery( $query ) {
  352. $sreg = array( 'required' => array(), 'optional' => array(),
  353. 'policy_url' => null );
  354. if ( array_key_exists( 'openid.sreg.required', $query ) ) {
  355. $sreg['required'] = explode( ',', $query['openid.sreg.required'] );
  356. }
  357. if ( array_key_exists( 'openid.sreg.optional', $query ) ) {
  358. $sreg['optional'] = explode( ',', $query['openid.sreg.optional'] );
  359. }
  360. if ( array_key_exists( 'openid.sreg.policy_url', $query ) ) {
  361. $sreg['policy_url'] = $query['openid.sreg.policy_url'];
  362. }
  363. return $sreg;
  364. }
  365. function SetUserField( &$user, $field, $value ) {
  366. switch ( $field ) {
  367. case 'fullname':
  368. $user->setRealName( $value );
  369. return true;
  370. break;
  371. case 'email':
  372. # FIXME: deal with validation
  373. $user->setEmail( $value );
  374. return true;
  375. break;
  376. case 'language':
  377. $user->setOption( 'language', $value );
  378. return true;
  379. break;
  380. default:
  381. return false;
  382. }
  383. }
  384. function GetUserField( $user, $field ) {
  385. switch ( $field ) {
  386. case 'nickname':
  387. return $user->getName();
  388. break;
  389. case 'fullname':
  390. return $user->getRealName();
  391. break;
  392. case 'email':
  393. return $user->getEmail();
  394. break;
  395. case 'language':
  396. return $user->getOption( 'language' );
  397. break;
  398. default:
  399. return null;
  400. }
  401. }
  402. function Response( &$server, &$response ) {
  403. global $wgOut;
  404. assert( !is_null( $server ) );
  405. assert( !is_null( $response ) );
  406. $wgOut->disable();
  407. wfSuppressWarnings();
  408. $wr =& $server->encodeResponse( $response );
  409. wfRestoreWarnings();
  410. assert( !is_null( $wr ) );
  411. header( "Status: " . $wr->code );
  412. foreach ( $wr->headers as $k => $v ) {
  413. header( "$k: $v" );
  414. }
  415. print $wr->body;
  416. return;
  417. }
  418. function LoginForm( $request, $msg = null ) {
  419. global $wgOut, $wgUser;
  420. $url = $request->identity;
  421. $name = $this->UrlToUserName( $url );
  422. $trust_root = $request->trust_root;
  423. $instructions = wfMsg( 'openidserverlogininstructions', $url, $name, $trust_root );
  424. $username = wfMsg( 'yourname' );
  425. $password = wfMsg( 'yourpassword' );
  426. $ok = wfMsg( 'ok' );
  427. $cancel = wfMsg( 'cancel' );
  428. if ( !is_null( $msg ) ) {
  429. $wgOut->addHTML( "<p class='error'>{$msg}</p>" );
  430. }
  431. $sk = $wgUser->getSkin();
  432. $wgOut->addHTML( "<p>{$instructions}</p>" .
  433. '<form action="' . $sk->makeSpecialUrl( 'OpenIDServer/Login' ) . '" method="POST">' .
  434. '<table>' .
  435. "<tr><td><label for='username'>{$username}</label></td>" .
  436. ' <td><span id="username">' . htmlspecialchars( $name ) . '</span></td></tr>' .
  437. "<tr><td><label for='password'>{$password}</label></td>" .
  438. ' <td><input type="password" name="wpPassword" size="32" value="" /></td></tr>' .
  439. "<tr><td colspan='2'><input type='submit' name='wpOK' value='{$ok}' /> <input type='submit' name='wpCancel' value='{$cancel}' /></td></tr>" .
  440. '</table>' .
  441. '</form>' );
  442. }
  443. function SaveValues( $request, $sreg ) {
  444. global $wgSessionStarted, $wgUser;
  445. if ( !$wgSessionStarted ) {
  446. $wgUser->SetupSession();
  447. }
  448. $_SESSION['openid_server_request'] = $request;
  449. $_SESSION['openid_server_sreg'] = $sreg;
  450. return true;
  451. }
  452. function FetchValues() {
  453. return array( $_SESSION['openid_server_request'], $_SESSION['openid_server_sreg'] );
  454. }
  455. function ClearValues() {
  456. unset( $_SESSION['openid_server_request'] );
  457. unset( $_SESSION['openid_server_sreg'] );
  458. return true;
  459. }
  460. function serverLogin( $request ) {
  461. global $wgRequest, $wgUser;
  462. assert( isset( $request ) );
  463. assert( isset( $wgRequest ) );
  464. if ( $wgRequest->getCheck( 'wpCancel' ) ) {
  465. return $request->answer( false );
  466. }
  467. $password = $wgRequest->getText( 'wpPassword' );
  468. if ( !isset( $password ) || strlen( $password ) == 0 ) {
  469. return wfMsg( 'wrongpasswordempty' );
  470. }
  471. assert ( isset( $password ) && strlen( $password ) > 0 );
  472. $url = $request->identity;
  473. assert( isset( $url ) && is_string( $url ) && strlen( $url ) > 0 );
  474. $name = $this->UrlToUserName( $url );
  475. assert( isset( $name ) && is_string( $name ) && strlen( $name ) > 0 );
  476. $user = User::newFromName( $name );
  477. assert( isset( $user ) );
  478. if ( !$user->checkPassword( $password ) ) {
  479. return wfMsg( 'wrongpassword' );
  480. } else {
  481. $id = $user->getId();
  482. $wgUser = $user;
  483. $wgUser->SetupSession();
  484. $wgUser->SetCookies();
  485. wfRunHooks( 'UserLoginComplete', array( &$wgUser ) );
  486. return false;
  487. }
  488. }
  489. function TrustForm( $request, $sreg, $msg = null ) {
  490. global $wgOut, $wgUser;
  491. $url = $request->identity;
  492. $name = $this->UrlToUserName( $url );
  493. $trust_root = $request->trust_root;
  494. $instructions = wfMsg( 'openidtrustinstructions', $trust_root );
  495. $allow = wfMsg( 'openidallowtrust', $trust_root );
  496. if ( is_null( $sreg['policy_url'] ) ) {
  497. $policy = wfMsg( 'openidnopolicy' );
  498. } else {
  499. $policy = wfMsg( 'openidpolicy', $sreg['policy_url'] );
  500. }
  501. if ( isset( $msg ) ) {
  502. $wgOut->addHTML( "<p class='error'>{$msg}</p>" );
  503. }
  504. $ok = wfMsg( 'ok' );
  505. $cancel = wfMsg( 'cancel' );
  506. $sk = $wgUser->getSkin();
  507. $wgOut->addHTML( "<p>{$instructions}</p>" .
  508. '<form action="' . $sk->makeSpecialUrl( 'OpenIDServer/Trust' ) . '" method="POST">' .
  509. '<input name="wpAllowTrust" type="checkbox" value="on" checked="checked" id="wpAllowTrust">' .
  510. '<label for="wpAllowTrust">' . $allow . '</label><br />' );
  511. $fields = array_filter( array_unique( array_merge( $sreg['optional'], $sreg['required'] ) ),
  512. array( $this, 'ValidField' ) );
  513. if ( count( $fields ) > 0 ) {
  514. $wgOut->addHTML( '<table>' );
  515. foreach ( $fields as $field ) {
  516. $wgOut->addHTML( "<tr>" );
  517. $wgOut->addHTML( "<th><label for='wpAllow{$field}'>" );
  518. $wgOut->addHTML( wfMsg( "openid$field" ) );
  519. $wgOut->addHTML( "</label></th>" );
  520. $value = $this->GetUserField( $wgUser, $field );
  521. $wgOut->addHTML( "</td>" );
  522. $wgOut->addHTML( "<td> " . ( ( is_null( $value ) ) ? '' : $value ) . "</td>" );
  523. $wgOut->addHTML( "<td>" . ( ( in_array( $field, $sreg['required'] ) ) ? wfMsg( 'openidrequired' ) : wfMsg( 'openidoptional' ) ) . "</td>" );
  524. $wgOut->addHTML( "<td><input name='wpAllow{$field}' id='wpAllow{$field}' type='checkbox'" );
  525. if ( !is_null( $value ) ) {
  526. $wgOut->addHTML( " value='on' checked='checked' />" );
  527. } else {
  528. $wgOut->addHTML( " disabled='disabled' />" );
  529. }
  530. $wgOut->addHTML( "</tr>" );
  531. }
  532. $wgOut->addHTML( '</table>' );
  533. }
  534. $wgOut->addHTML( "<input type='submit' name='wpOK' value='{$ok}' /> <input type='submit' name='wpCancel' value='{$cancel}' /></form>" );
  535. return null;
  536. }
  537. function Trust( $request, $sreg ) {
  538. global $wgRequest, $wgUser;
  539. assert( isset( $request ) );
  540. assert( isset( $sreg ) );
  541. assert( isset( $wgRequest ) );
  542. if ( $wgRequest->getCheck( 'wpCancel' ) ) {
  543. return $request->answer( false );
  544. }
  545. $trust_root = $request->trust_root;
  546. assert( isset( $trust_root ) && strlen( $trust_root ) > 0 );
  547. # If they don't want us to allow trust, save that.
  548. if ( !$wgRequest->getCheck( 'wpAllowTrust' ) ) {
  549. $this->SetUserTrust( $wgUser, $trust_root, false );
  550. # Set'em and sav'em
  551. $wgUser->saveSettings();
  552. } else {
  553. $fields = array_filter( array_unique( array_merge( $sreg['optional'], $sreg['required'] ) ),
  554. array( $this, 'ValidField' ) );
  555. $allow = array();
  556. foreach ( $fields as $field ) {
  557. if ( $wgRequest->getCheck( 'wpAllow' . $field ) ) {
  558. $allow[] = $field;
  559. }
  560. }
  561. $this->SetUserTrust( $wgUser, $trust_root, $allow );
  562. # Set'em and sav'em
  563. $wgUser->saveSettings();
  564. }
  565. }
  566. # Converts an URL to a user name, if possible
  567. function UrlToUserName( $url ) {
  568. global $wgArticlePath, $wgServer;
  569. # URL must be a string
  570. if ( !isset( $url ) || !is_string( $url ) || strlen( $url ) == 0 ) {
  571. return null;
  572. }
  573. # it must start with our server, case doesn't matter
  574. if ( strpos( strtolower( $url ), strtolower( $wgServer ) ) !== 0 ) {
  575. return null;
  576. }
  577. $parts = parse_url( $url );
  578. $relative = $parts['path'];
  579. if ( !is_null( $parts['query'] ) && strlen( $parts['query'] ) > 0 ) {
  580. $relative .= '?' . $parts['query'];
  581. }
  582. # Use regexps to extract user name
  583. $pattern = str_replace( '$1', '(.*)', $wgArticlePath );
  584. $pattern = str_replace( '?', '\?', $pattern );
  585. # Can't have a pound-sign in the relative, since that's for fragments
  586. if ( !preg_match( "#$pattern#", $relative, $matches ) ) {
  587. return null;
  588. } else {
  589. $titletext = urldecode( $matches[1] );
  590. $nt = Title::newFromText( $titletext );
  591. if ( is_null( $nt ) || $nt->getNamespace() != NS_USER ) {
  592. return null;
  593. } else {
  594. return $nt->getText();
  595. }
  596. }
  597. }
  598. function serverUrl() {
  599. return $this->getTitle()->getFullUrl();
  600. }
  601. }