<?php
/*
* @package LabCMS
* @copyright (c) 2006 Alexander Levin aka Loki (loki_angel@mail.ru)
* @support http://labcms.ru
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/

if (@!is_readable('/dev/urandom')) {
	// Если не поддерживается random, сбрасываем переменную в null
	define('Auth_OpenID_RAND_SOURCE', null);
}

class OpenId
{
	public $required=array();
	public $optional=array();
	public $returnTo=null;
	
	public function SendOpenId($openid)
	{
		$consumer = $this->getConsumer();
		// Начало процесса OpenID авторизации
		$auth_request = $consumer->begin(trim($openid));
		// No auth request means we can't begin OpenID.
		if (!$auth_request) {
			$this->error("Некорректный OpenID.");
			return false;
		}
		
		if (!empty($this->required) || !empty($this->optional)) {
			require_once LAB_PATH_KERNEL.'/classes/Auth/OpenID/SReg.php';
			if (Auth_OpenID_supportsSReg($auth_request->endpoint)) {
				$sreg_req = Auth_OpenID_SRegRequest::build(
					$this->required, $this->optional
				);
				$auth_request->addExtension($sreg_req);
			} else {
				require_once LAB_PATH_KERNEL.'/classes/Auth/OpenID/AX.php';
				if ($auth_request->endpoint->usesExtension(Auth_OpenID_AX_NS_URI)) {
					$ax=$this->getOpenIDAXmake($this->required, $this->optional);
					// Add AX fetch request to authentication request
					$auth_request->addExtension($ax);
				}
			}
		}

		if (!$this->returnTo) $this->returnTo=$this->getReturnTo();
		// Редирект пользователя на OpenID server для авторизации.
		// Для OpenID 1, делаем редирект.  Для OpenID 2, используем форму для  отправки POST
		if ($auth_request->shouldSendRedirect()) {
			$redirect_url = $auth_request->redirectURL(
				$this->getTrustRoot(), $this->returnTo
			);
			// Если redirect URL не может быть сформирован, выведем сообщение об ошибках.
			if (Auth_OpenID::isFailure($redirect_url)) {
				$this->error("Не могу перенаправить на сервер: ");
				$this->error($redirect_url->message, true);
				return false;
			} else {
				// Делаем редирект.
				refresh('', $redirect_url);
			}
		} else {
			// Создаем форму для JS-редиректа
			$form_id = 'openid_message';
			$form_html = $auth_request->formMarkup(
				$this->getTrustRoot(), $this->returnTo,
				false, array('id' => $form_id)
			);
			// Сделаем форму невидимой
			$s = " style=\"display:none\" ";
			$form_html = str_replace("<form", "<form $s", $form_html);

			// Отправляем форму
			if (Auth_OpenID::isFailure($form_html)) {
				$this->error(
					"Не могу перенаправить на сервер: ".$form_html->message
				);
				return false;
			} else {
				$page_contents = array(
				"<html><body 
				onload='document.getElementById(\"".$form_id."\").submit()'>",  
				$form_html,"</body></html>");
				print implode("\n", $page_contents);
				
			}
		}
		exit;
	}
	
	function getConsumer()
	{
		// Создание клиентского объекта
		$store =  new Auth_OpenID_FileStore(LAB_PATH_DATA.'/cache/openid');
		return new Auth_OpenID_Consumer($store);
	}

	function getScheme()
	{
		$scheme = 'http';
		if (isset($_SERVER['HTTPS']) and $_SERVER['HTTPS'] == 'on') {
			$scheme .= 's';
		}
		return $scheme;
	}

	function getReturnTo()
	{
		
		$u=parse_url($_SERVER['REQUEST_URI']);
		$s = $this->getScheme()."://".$_SERVER['HTTP_HOST'].$u['path'];
		if (!empty($u['query'])) {
			$u['query']=explode('&', $u['query']);
			foreach ($u['query'] as $key=>$var) {
				if (substr($var, 0, 7)=='openid.') unset($u['query'][$key]);
			}
			if ($u['query']) $u['query']='?'.implode('&', $u['query']);
			$s.=$u['query'];
		}
		return $s;
	}

	function getTrustRoot()
	{
		$s = $this->getScheme()."://".$_SERVER['HTTP_HOST'];
		return $s;
	}
	
	public function CheckAuthByOpenId()
	{
		$consumer = $this->getConsumer();

		$response = $consumer->complete($this->getReturnTo());
		if ($response->status == Auth_OpenID_SUCCESS) {
			if (!empty($_GET['openid_ns_sreg'])) {
				require_once LAB_PATH_KERNEL.'/classes/Auth/OpenID/SReg.php';
				$sreg_resp=Auth_OpenID_SRegResponse::fromSuccessResponse($response);
				$sreg_resp->data['openid'] = $response->getDisplayIdentifier();
				return $sreg_resp->data;
			} elseif (!empty($_GET['openid_ext1_mode'])) {
				$data=$this->getOpenIDAXResponse($response);
				$data['openid'] = $response->getDisplayIdentifier();
				return $data;
			} else
				return $response->getDisplayIdentifier();
		}
		if ($response->status == Auth_OpenID_CANCEL) {
			$this->error("Проверка отменена.");
		} elseif ($response->status == Auth_OpenID_FAILURE) {
			$this->error("Аутентификация не удалась: ");
			$this->error($response->message, true);
		}
		return false;
	}

	private function error($mess, $html=false)
	{
		//if (LabCMS::is_object()) {
			if ($html) LabCMS::i()->error(_m($mess), true);
			else LabCMS::i()->error($mess);
		//} else die($mess);
	}
	
	protected function getAliases()
	{
		return array(	'fullname' => 'http://axschema.org/namePerson',
			  'email' => 'http://axschema.org/contact/email',
			  'country' => 'http://axschema.org/contact/country/home',
			 // 'nickname' => 'http://axschema.org/namePerson/friendly',
			 // так сделано пока гугл не образумится
			  'nickname' => 'http://axschema.org/namePerson/first',
			  'language' => 'http://axschema.org/pref/language',
			  'dob' => 'http://axschema.org/birthDate',
			  'gender' => 'http://axschema.org/person/gender',
			  'postcode' => 'http://axschema.org/contact/postalCode/home',
			  'timezone' => 'http://axschema.org/pref/timezone');
		
	}

	protected function getOpenIDAXmake($required=false, $optional=false)
	{
		$aliases=$this->getAliases();
		$ax = new Auth_OpenID_AX_FetchRequest;

		if ($required) {
			foreach ($required as $item) {
				// Usage: make($type_uri, $count=1, $required=false, $alias=null)
				$ax->add(
					Auth_OpenID_AX_AttrInfo::make(
						$aliases[$item],
						1,
						true,
						$item
					)
				);
			}
			
		}

		if ($optional) {
			foreach ($optional as $item) {
				$ax->add(
					Auth_OpenID_AX_AttrInfo::make(
						$aliases[$item],
						1,
						false,
						$item
					)
				);
			}
		}
		return $ax;
	}
	
	protected function getOpenIDAXResponse($response)
	{
		require_once LAB_PATH_KERNEL.'/classes/Auth/OpenID/AX.php';
		$aliases=$this->getAliases();
		$ax = new Auth_OpenID_AX_FetchResponse();
		$obj = $ax->fromSuccessResponse($response);
		$items=array_keys($obj->data);
		if ($items) {
			foreach ($items as $item) {
				if (in_array($item, $aliases)) {
					$data[array_search($item, $aliases)]=$obj->data[$item][0];
				}
			}
		}
		return $data;
	}
}