<?php
namespace Cas\Module;
use KIF\Exception\ParamsException;
use KIF\Core\Config;
use KIF\Data\ResultWrapper;
use KIF\Core\Request;
use KIF\Verify;
/**
 * 
 * 用户通行证
 * @author lishumingoo@gmail.com
 */
class Passport {
	
	/**
	 * 安全key
	 * @var string
	 */
	private $securityKey;
	
	private $login_cookie_name = 'TM_PASSPORT_MEMBER';
	
	/**
	 * 登陆类型之:未授权
	 * @var unknown
	 */
	const LOGIN_TYPE_NOT_AUTH = '1';
	
	/**
	 * 登陆类型之:已授权
	 * @var unknown
	 */
	const LOGIN_TYPE_HAS_AUTH = '2';
	
	
	public function __construct() {
		
		$PASSPORT_SIGN_KEY = Config::getInstance()->get('passport_sign_key');
		if (!$PASSPORT_SIGN_KEY) {
			throw new ParamsException('请指定securityKey');
		}
		$this->securityKey = $PASSPORT_SIGN_KEY;
	}
	
	/**
	 * 登陆
	 */
	public function login() {}
	
	/**
	 * 注册
	 * @param array $info
	 */
	public function register(array $info) {}
	
	/**
	 * 获取登录用户信息
	 * @return ResultWrapper 成功:存在登录cookie里的信息作为数组返回;失败:失败原因
	 */
	public function getLoginInfo() {
		if (!isset($_COOKIE[$this->login_cookie_name])) {
			return ResultWrapper::fail('没有登录cookie');
		}
        $loginCookie = $_COOKIE[$this->login_cookie_name];

        $loginInfo = array();
        parse_str($loginCookie, $loginInfo);

        $tmpResult = $this->verifySign($loginInfo);
        if (!$tmpResult->isSuccess()) {
        	return $tmpResult;
        }

        return ResultWrapper::success($loginInfo);
	}
	
	/**
	 * 写登录信息到cookie
	 * @param array $info
	 * @return ResultWrapper
	 */
	public function writeLoginCookie(array $info) {
		if (is_null($info['expire'])) {// 说明这是个当前会话期有效的登录用户
			$info['expire']      = time() + 4 * 60 * 60;//登录cookie签名的有效性,设为4小时
			$cookie_expire       = null;//让登录cookie在当前会话期有效
		} else {
			# 让登录cookie的存在期比 登录cookie签名有效性多1天。避免用户电脑时间与服务器时间不一致,导致签名在有效期,但cookie却已失效的情况。
// 			$cookie_expire       = $info['expire'] + 24 * 60 * 60;
			$cookie_expire       = $info['expire'];
		}

		if (is_null($info['timestamp'])) {//
			$info['timestamp'] = time();
		}

		# 版本号,为以后安全性升级做准备
		$info['version'] = '0.1';

        $tmpResult = $this->sign($info);
        if (!$tmpResult->isSuccess()) {//签名失败
        	return $tmpResult;
        }

        $info['sign'] = $tmpResult->getData();

        setcookie($this->login_cookie_name, http_build_query($info), $cookie_expire, '/', Request::rootDomain());

        return ResultWrapper::success();
	}
	
	/**
	 * 对 $info 做签名
	 *
	 * @param array $info 格式:array
	 * (
	 *     // 这些是必要字段
	 *     'uid'       => (int),//用户id
	 *     'uname'     => (string),//用户名
	 *     'expire'    => (int),//签名有效期,过了这个有效期,即使签名正确,也不认。
	 *     'register_type' => (int),//用户注册类型
	 * )
	 *
	 * @return ResultWrapper  成功:返回签名$sign;失败:返回失败原因
	 */
	public function sign(array $info) {
		if (!isset($info['uid']) || !Verify::int($info['uid'])) {
			return ResultWrapper::fail('无效的uid');
		}
	
		if (!isset($info['expire']) || !Verify::int($info['expire'])) {
			return ResultWrapper::fail('无效的expire');
		}
	
// 		if (!isset($info['nickname']) || !is_string($info['nickname']) || empty($info['nickname'])) {
// 			return ResultWrapper::fail('无效的uname');
// 		}
	
		ksort($info);
		$tmpStr = '';
		foreach ($info as $k => $v) {
			if ($v != '' && $k != 'sign') {
				$tmpStr .= "{$k}={$v}&";
			}
		}
		$tmpStr .= "securityKey={$this->securityKey}";
		$sign = strtolower(sha1($tmpStr));
	
		return ResultWrapper::success($sign);
	}
	
	/**
	 * 验证 $info 的有效性
	 * @param array $info
	 * @return ResultWrapper
	 */
	public function verifySign(array $info) {
		if (!isset($info['sign'])) {
			return ResultWrapper::fail('没有指定sign值,无法校验');
		}
	
		$tmpResult = $this->sign($info);
		if (!$tmpResult->isSuccess()) {
			return $tmpResult;
		}
	
		$sign = $tmpResult->getData();
		if ($sign != $info['sign']) {
			return ResultWrapper::fail("给定的sign:{$info['sign']} 与 计算后的sign:{$sign} 不等");
		}
	
		if ($info['expire'] < time()) {
			return ResultWrapper::fail('expire存储的签名有效期已过');
		}
	
		return ResultWrapper::success();
	}
	
}