<?php
/**
 * 登录回调文件，用于适应OAuth 2.0只允许1个callback地址的各种情况
 * 并且将OAuth 2.0的state内容还原回oauthCallBack URL中
 * @author yaoying <yaoying@staff.sina.com.cn>
 * @version $Id: oauth2_callback.php 18381 2012-07-26 03:46:54Z yaoying $
 */
//=========================配置区域开始=========================
error_reporting(0);
$cfg = array();
//跳转限制
$cfg['redirect_limit'] = array();
//允许自身目录下的跳转
$cfg['redirect_limit'][] = ($_SERVER['HTTPS'] == 'on' ? 'https' : 'http').'://'.$_SERVER['HTTP_HOST'].substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/') );
//=========================配置区域结束=========================

if(!isset($_GET['code']) || empty($_GET['code'])){
	tpl_msg('回调code获取失败，请关闭窗口重试。', null, 'error');
}

//兼容OAuth 1.0，将Oauth 2.0的code编码到oauth_verifier中
$_GET['oauth_verifier'] = $_GET['code'];
unset($_GET['oauthCallBack']);

//回调state内容进入$_GET
$__state = array();
$oauthCallBack = '';
if(isset($_GET['state']) && !empty($_GET['state'])){
	parse_str(urldecode($_GET['state']), $__state);
	if(isset($__state['oauthCallBack'])){
		$oauthCallBack = $__state['oauthCallBack'];
	}
	if(is_array($__state)){
		unset($__state['oauthCallBack']);
		$_GET += $__state;
	}
}
unset($_GET['state']);

if(empty($oauthCallBack)){
	tpl_msg('回调地址oauthCallBack获取失败，请关闭窗口重试。', null, 'error');
}

//跳转限制
$redirect_check = false;
$oauthCallBack_parsed = parse_url($oauthCallBack);
if(empty($oauthCallBack_parsed['host'])){
	tpl_msg('回调地址oauthCallBack解释域名失败，请关闭窗口重试。', null, 'error');
}

foreach($cfg['redirect_limit'] as $red){
	$red_parsed = parse_url($red);
	if($red_parsed['host'] === $oauthCallBack_parsed['host'] && strpos($oauthCallBack, $red) === 0){
		$redirect_check = true;
		break;
	}
}
if(false === $redirect_check){
	tpl_msg('回调地址oauthCallBack来源校验失败，请关闭窗口重试。', null, 'error');
}

//组合跳转地址
$param = http_build_query($_GET);
if(strpos($oauthCallBack, '?') === false){
	$oauthCallBack = $oauthCallBack. '?'. $param;
}else{
	$oauthCallBack = $oauthCallBack. '&'. $param;
}

if(strlen($oauthCallBack) > 2048){
	tpl_msg('回调地址oauthCallBack太长，请关闭窗口重试。', null, 'error');
}elseif(!is_url($oauthCallBack)){
	tpl_msg('回调地址oauthCallBack不是一个有效的URL，请关闭窗口重试。', null, 'error');
}

//编码安全：保护oauth_verifier不被referer记录，故不采取tpl_msg跳转，而是header跳转
header("Location: ".$oauthCallBack);
exit();


function tpl_msg($msg = '', $url = null, $type = 'tips', $param = array()){
	
	$msg = htmlspecialchars($msg);
	if('error' == $type){
		$title = '错误提示';
	}else{
		$title = '提示';
	}
	
	$tpl = <<<EOF
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{$title}</title>
</head>
<body style="text-align:center; font-family:Arial,Helvetica,sans-serif; padding-top:50px">
<h2>{$msg}</h2>
EOF;

	if(!empty($url)){
		$link = "<a href=\"{$url}\">如果无法跳转请点击这里</a>";
	$tpl .= <<<EOF
<h3>{$link}</h3>
<script>
window.location = '{$url}';
</script>
EOF;
	}
	
	
	$tpl .= <<<EOF
</body>
</html>
EOF;
	
	echo $tpl;
	exit();
	
}

/**
 * 确定是不是一个有效的url
 * @param string $url
 * @return bool
 * @version $Id: oauth2_callback.php 18381 2012-07-26 03:46:54Z yaoying $
 */
function is_url($url)
{
	$re = preg_match('/^(http:\/\/|https:\/\/)[a-zA-Z0-9.]+(\/)?[-a-zA-Z0-9@:%_\\+.~#?$()&\/\=]*$/', $url);
	return (bool)$re;
}