cas 登录各种虐

原理:

http://steven-wiki.readthedocs.org/en/latest/security/sso/

麻烦一:

出现一个比较奇葩的逻辑。是有一套系统已经成形了。cas 登录是后补充的.

需要由原页面登录页面进行提交。

麻烦二:

cas是其它合作公司处理,竞争公司,你懂的。。

 

解决方式:

1.直接post 提交

1.1 各种逻辑处理问题相对麻烦,特别是对于已经成形的

1.2页面各种跳转不好看

2.ajax 进行提交(前提目标公司要合作。。。。要合作。。。)

2.1目标服务器需要有权限,设置头

参考:http://haibin.info/?p=532

2.2需要考虑兼容问题(ie8+,chrome 这些ok,ie7以下的请无视看3)

参考:http://haibin.info/?p=973

2.3页面不用跳转,可在原逻辑的支持下实现,修改少。

3.隐藏post 表单 js 提交到 隐藏的iframe (通过target 指定对应的提交地址)

3.1 修改相对较少,没有兼容性问题。因为post提交,只要是浏览器都支持.

3.2不过本身就是通过跳来跳去实现的,只是包装到iframe中,再通过外部函数调用。如果原页面逻辑复杂,推荐这种处理方式

4.jsonp登录,类似ajax(前提目标公司要合作。。。。要合作。。。)

4.1参考http://www.cnblogs.com/jifeng/p/3511219.html(页面图大。。。谨慎 ~.~ )

http://www.cnblogs.com/jifeng/p/3511219.html

5. cas/service 手动写入cookie.(需要有服务器的操作权限或配置)

5.1 最简单的实现方式,影响最小,通过模拟登录获取最终CASTCG ,通过客户端GET 直接设置到cookie

6. 模拟登录,登录成功之后 iframe 进行隐藏post提交,即是登录两次。相对修改较少

7.这边的最终解决方案,搞一个同域名下的服务器.让目标公司配合cookie 设置成顶级域名下

setcookie ( 'name', 'value' ,null,'/','.xxxxxx.com');

 

注意事项:

登录检查

1.http://casservice/cas/login?servce=跳转的目标地址

1.1访问以上地址,会返回对应的ticket ,ticket 只能抓取一次数据

1.2 这种跳转是直接控制top.location ,无法进行iframe 检查

2.http://casservice/cas/remoteLogin?service=跳转的目标地址&loginUrl=跳转的目标地址

2.1登录地址也可以用来进行登录检查判断

2.2只跳转当前location ,可以当前iframe进行跳转

ticket获取用户信息

1 ticket 只能抓取一次数据

2 http://caservice/cas/serviceValidate?service=获取ticket的地址&ticket=返回的ticket

3.补充xml转array代码

		// 过滤标签头
		$result = preg_replace ( '/<cas:/i', '<', $xml );
		// 过滤结束标签头
		$result = preg_replace ( '/</cas:/i', '</', $result );
		$res = @simplexml_load_string ( $result, NULL, LIBXML_NOCDATA );
		if (! $res) {
			return false;
		}
		$res = json_decode ( json_encode ( $res ), true );
		if (isset ( $res ['authenticationSuccess'] )) {
			/**
			 * Array
			 * (
			 * _[authenticationSuccess] => Array
			 * _(
			 * __[user] => xxxxx
			 * __[attributes] => Array
			 * __(
			 * ____[login_flag] => xxx
			 * ____[employeeId] => xxx
			 * ____[asHelp] => xxxx
			 * __)
			 * _)
			 * )
			 */
			//$res ['authenticationSuccess'];
			return true;
		}

 

修复Yii ar 在win环境下 oci_pconnect 访问慢问题

同样的代码,在linux 环境下的 apache访问速度就正常,一样是链接外部数据库。

在开发环境中win(php5.2)链接测试机linux数据库访问里,速度会慢。还是用oci_pconnect的情况下.

折腾过php的不同版本 5.4 ts nts 这些版本。速度依旧烂。

测试机内部apache访问时,速度不慢。觉得是出在win上。

这块无解。尝试分析各sql访问上的速度问题.

log 补充 trace 打印出sql访问日志,单条进行数据分析

				'log' => array (
						'class' => 'CLogRouter',
						'routes' => array (
								array (
										'class' => 'CFileLogRoute',
										'levels' => 'trace, error, warning'
								)
						) 
				),

 

发现ar 在获取结构时,一次要花费约1s左右。

其它访问速度正常。

ar开启缓存。第一次访问时较慢,后续访问均明显变快,和原来mysql环境下差不多。

'db' => array (
              'class'=>'ext.oci8Pdo.OciDbConnection',
				'connectionString' => 'oci:dbname=//xxx/xx;charset=UTF8;',
				// 开启表结构缓存(schema caching)提高性能
				'schemaCachingDuration'=>3600,
		),

 

php array cover to xml

参考

http://stackoverflow.com/questions/1397036/how-to-convert-array-to-simplexml

<?php
class FileTools {
	/**
	 * 内部函数
	 *
	 * @param array $arr        	
	 * @param SimpleXMLElement $xml        	
	 * @return SimpleXMLElement
	 */
	static function _array_to_xml(array $arr, SimpleXMLElement $xml) {
		foreach ( $arr as $k => $v ) {
			$attrArr = array ();
			$kArray = explode ( ' ', $k );
			$tag = array_shift ( $kArray );

			if (count ( $kArray ) > 0) {
				foreach ( $kArray as $attrValue ) {
					$attrArr [] = explode ( '=', $attrValue );
				}
			}

			if (is_array ( $v )) {
				if (is_numeric ( $k )) {
					self::_array_to_xml ( $v, $xml );
				} else {
					$child = $xml->addChild ( $tag );
					if (isset ( $attrArr )) {
						foreach ( $attrArr as $attrArrV ) {
							$child->addAttribute ( $attrArrV [0], $attrArrV [1] );
						}
					}
					self::_array_to_xml ( $v, $child );
				}
			} else {
				$child = $xml->addChild ( $tag, $v );
				if (isset ( $attrArr )) {
					foreach ( $attrArr as $attrArrV ) {
						$child->addAttribute ( $attrArrV [0], $attrArrV [1] );
					}
				}
			}
		}
		return $xml;
	}
	/**
	 *
	 * @param array $array
	 *        	需要转化的数组
	 * @param string $root
	 *        	根标签
	 * @param boolean $formatoutput
	 *        	是否需要格式化输出
	 * @param boolean $preserveWhiteSpace
	 *        	是否过滤标签之间的空白
	 * @throws Exception
	 * @return mixed Ambigous mixed>
	 */
	static function array_to_xml($array = array(), $root, $formatoutput = false, $preserveWhiteSpace = false) {
		if (empty ( $root )) {
			throw new Exception ( '根标签不能为空' );
		}
		if (! preg_match ( '/^<w+/?>$/', $root )) {
			throw new Exception ( '标签格式异常' );
		}
		$xml = self::_array_to_xml ( $array, new SimpleXMLElement ( $root ) )->asXML ();
		if ($formatoutput || $preserveWhiteSpace) {
			if (! class_exists ( "DOMDocument" ))
				return $xml;
			$dom = new DOMDocument ();
			$dom->preserveWhiteSpace = $preserveWhiteSpace;
			$dom->loadXML ( $xml );
			$dom->formatOutput = $formatoutput;
			$xml = $dom->saveXml ();
		}
		return $xml;
	}
}

 

dompdf html cover to pdf

http://www.digitaljunkies.ca/dompdf/

常见问题:

1.页面和生成后的pdf各种不对应

需要通过table进行布局。原文件示例代码也是以表格布局为主,否则会引发各种变形。

如果涉及布局太复杂的页面,需要慢慢调试。如果有别的解决方案,请分享

尺寸不是以像素为参考,如pdf 840的页面尺寸,会实际铺满一个1300+的屏幕。所以需要进行特殊设置,不要在页面中尝试精确定位。

 

2.页面尺寸大小

配置文件中有个page_size参数

something like ‘letter’, ‘A4’, ‘legal’, etc. Thee default is ‘letter’,还有其它各种尺寸可以设置,直接源码搜letter即可看到配置文件.

3.页面如果为一个表格,当夹在中间页面时,要报frames的溢出异常。需要将表格调整到当前页。或者直接压到下一页

4.特殊字符无法正常显示,原因不明。google.code上有提供demo实例中有。但是官网本身demo已隐藏相关特殊字符实例。如 欧元符号 €.这边有个项目比较特殊,通过替换成图片进行解决。

php 序列生成工具

<?php
/**
 * 
 * 现在简单实现,可以处理成,根据对应的表,生成对应的序列进行生成,主要同步自增id
 *
 */
class OracleTools {
	/**
	 * 通过序列获取最新的id
	 * 如果制定表,如果表不存在,则创建新表。并以原表的id+1000的数据添加.
	 * 可以单独指定需要序列的表名和id
	 */
	public static function getNewId($seqname = "common", $id = "id", $tablename = "", $maxvalue = 0, $startbyzero = false) {
		$sseqname = $seqname;
		if (empty ( $tablename ))
			$tablename = $seqname;
		$seqname = "O2O_SEQ_{$seqname}";

		$exists = sql_fetch ( "SELECT
	count(1)  existsrow
FROM
	all_sequences
WHERE
	sequence_name = '$seqname'
AND sequence_owner = '" . Yii::app ()->db->username . "'", 'existsrow' );
		if (! $exists) {
			$lastid = 1;
			if (! $startbyzero) {
				$lastid = sql_fetch ( "SELECT {$id} FROM {$tablename} WHERE  ROWNUM =1 ORDER BY {$id} DESC ", $id );
				$lastid += 1000;
			}
			if (! $maxvalue) {
				$maxvalue = '9999999999999999';
			}
			sql_execute ( "CREATE SEQUENCE {$seqname} start WITH {$lastid} increment BY 1 MAXVALUE {$maxvalue} minvalue 1 cycle" );
		}
		$id = sql_fetch ( "SELECT {$seqname}.nextVal newid FROM dual", 'newid' );
		return $id;
	}
	public static function dropSeq($seqname = "common") {
		$seqname = "O2O_SEQ_{$seqname}";
		sql_execute ( "DROP SEQUENCE {$seqname} " );
	}
}

 

chinapay 兼容 php5.2-5.5

http://www.zhaoyuanma.com/

<?php
define ( "DES_KEY", "SCUBEPGW" );
define ( "HASH_PAD", "0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a05000414" );
bcscale ( 0 );
$private_key = array ();
// 兼容 php5.4+
if (! function_exists ( 'hex2bin' )) {
	function hex2bin($hexdata) {
		$bindata = '';
		if (strlen ( $hexdata ) % 2 == 1) {
			$hexdata = '0' . $hexdata;
		}
		for($i = 0; $i < strlen ( $hexdata ); $i += 2) {
			$bindata .= chr ( hexdec ( substr ( $hexdata, $i, 2 ) ) );
		}
		return $bindata;
	}
}
function padstr($src, $len = 256, $chr = '0', $d = 'L') {
	$ret = trim ( $src );
	$padlen = $len - strlen ( $ret );
	if ($padlen > 0) {
		$pad = str_repeat ( $chr, $padlen );
		if (strtoupper ( $d ) == 'L') {
			$ret = $pad . $ret;
		} else {
			$ret = $ret . $pad;
		}
	}
	return $ret;
}
function bin2int($bindata) {
	$hexdata = bin2hex ( $bindata );
	return bchexdec ( $hexdata );
}
function bchexdec($hexdata) {
	$ret = '0';
	$len = strlen ( $hexdata );
	for($i = 0; $i < $len; $i ++) {
		$hex = substr ( $hexdata, $i, 1 );
		$dec = hexdec ( $hex );
		$exp = $len - $i - 1;
		$pow = bcpow ( '16', $exp );
		$tmp = bcmul ( $dec, $pow );
		$ret = bcadd ( $ret, $tmp );
	}
	return $ret;
}
function bcdechex($decdata) {
	$s = $decdata;
	$ret = '';
	while ( $s != '0' ) {
		$m = bcmod ( $s, '16' );
		$s = bcdiv ( $s, '16' );
		$hex = dechex ( $m );
		$ret = $hex . $ret;
	}
	return $ret;
}
function sha1_128($string) {
	$hash = sha1 ( $string );
	$sha_bin = hex2bin ( $hash );
	$sha_pad = hex2bin ( HASH_PAD );
	return $sha_pad . $sha_bin;
}
function mybcpowmod($num, $pow, $mod) {
	if (function_exists ( 'bcpowmod' )) {
		return bcpowmod ( $num, $pow, $mod );
	}
	return emubcpowmod ( $num, $pow, $mod );
}
function emubcpowmod($num, $pow, $mod) {
	$result = '1';
	do {
		if (! bccomp ( bcmod ( $pow, '2' ), '1' )) {
			$result = bcmod ( bcmul ( $result, $num ), $mod );
		}
		$num = bcmod ( bcpow ( $num, '2' ), $mod );
		$pow = bcdiv ( $pow, '2' );
	} while ( bccomp ( $pow, '0' ) );
	return $result;
}
function rsa_encrypt($private_key, $input) {
	$p = bin2int ( $private_key ["prime1"] );
	$q = bin2int ( $private_key ["prime2"] );
	$u = bin2int ( $private_key ["coefficient"] );
	$dP = bin2int ( $private_key ["prime_exponent1"] );
	$dQ = bin2int ( $private_key ["prime_exponent2"] );
	$c = bin2int ( $input );
	$cp = bcmod ( $c, $p );
	$cq = bcmod ( $c, $q );
	$a = mybcpowmod ( $cp, $dP, $p );
	$b = mybcpowmod ( $cq, $dQ, $q );
	if (bccomp ( $a, $b ) >= 0) {
		$result = bcsub ( $a, $b );
	} else {
		$result = bcsub ( $b, $a );
		$result = bcsub ( $p, $result );
	}
	$result = bcmod ( $result, $p );
	$result = bcmul ( $result, $u );
	$result = bcmod ( $result, $p );
	$result = bcmul ( $result, $q );
	$result = bcadd ( $result, $b );
	$ret = bcdechex ( $result );
	$ret = strtoupper ( padstr ( $ret ) );
	return (strlen ( $ret ) == 256) ? $ret : false;
}
function rsa_decrypt($input) {
	global $private_key;
	$check = bchexdec ( $input );
	$modulus = bin2int ( $private_key ["modulus"] );
	$exponent = bchexdec ( "010001" );
	$result = bcpowmod ( $check, $exponent, $modulus );
	$rb = bcdechex ( $result );
	return strtoupper ( padstr ( $rb ) );
}
function buildKey($key) {
	global $private_key;
	if (count ( $private_key ) > 0) {
		foreach ( $private_key as $name => $value ) {
			unset ( $private_key [$name] );
		}
	}
	$ret = false;
	$key_file = parse_ini_file ( $key );
	if (! $key_file) {
		return $ret;
	}
	$hex = "";
	if (array_key_exists ( "MERID", $key_file )) {
		$ret = $key_file ["MERID"];
		$private_key ["MERID"] = $ret;
		$hex = substr ( $key_file ["prikeyS"], 80 );
	} else if (array_key_exists ( "PGID", $key_file )) {
		$ret = $key_file ["PGID"];
		$private_key ["PGID"] = $ret;
		$hex = substr ( $key_file ["pubkeyS"], 48 );
	} else {
		return $ret;
	}
	$bin = hex2bin ( $hex );
	$private_key ["modulus"] = substr ( $bin, 0, 128 );
	$cipher = MCRYPT_DES;
	$iv = str_repeat ( "x00", 8 );
	$prime1 = substr ( $bin, 384, 64 );
	// 兼容 php5.5+
	// $enc = mcrypt_cbc ( $cipher, DES_KEY, $prime1, MCRYPT_DECRYPT, $iv );
	$enc = mcrypt_decrypt ( $cipher, DES_KEY, $prime1, 'cbc', $iv );
	$private_key ["prime1"] = $enc;
	$prime2 = substr ( $bin, 448, 64 );

	// $enc = mcrypt_cbc ( $cipher, DES_KEY, $prime2, MCRYPT_DECRYPT, $iv );
	$enc = mcrypt_decrypt ( $cipher, DES_KEY, $prime2, 'cbc', $iv );
	$private_key ["prime2"] = $enc;
	$prime_exponent1 = substr ( $bin, 512, 64 );
	// $enc = mcrypt_cbc ( $cipher, DES_KEY, $prime_exponent1, MCRYPT_DECRYPT,
	// $iv );
	$enc = mcrypt_decrypt ( $cipher, DES_KEY, $prime_exponent1, 'cbc', $iv );
	$private_key ["prime_exponent1"] = $enc;
	$prime_exponent2 = substr ( $bin, 576, 64 );
	// $enc = mcrypt_cbc ( $cipher, DES_KEY, $prime_exponent2, MCRYPT_DECRYPT,
	// $iv );
	$enc = mcrypt_decrypt ( $cipher, DES_KEY, $prime_exponent2, 'cbc', $iv );
	$private_key ["prime_exponent2"] = $enc;
	$coefficient = substr ( $bin, 640, 64 );
	// $enc = mcrypt_cbc ( $cipher, DES_KEY, $coefficient, MCRYPT_DECRYPT, $iv
	// );
	$enc = mcrypt_decrypt ( $cipher, DES_KEY, $coefficient, 'cbc', $iv );
	$private_key ["coefficient"] = $enc;
	return $ret;
}
function sign($msg) {
	global $private_key;
	if (! array_key_exists ( "MERID", $private_key )) {
		return false;
	}
	$hb = sha1_128 ( $msg );
	return rsa_encrypt ( $private_key, $hb );
}
function signOrder($merid, $ordno, $amount, $curyid, $transdate, $transtype) {
	if (strlen ( $merid ) != 15)
		return false;
	if (strlen ( $ordno ) != 16)
		return false;
	if (strlen ( $amount ) != 12)
		return false;
	if (strlen ( $curyid ) != 3)
		return false;
	if (strlen ( $transdate ) != 8)
		return false;
	if (strlen ( $transtype ) != 4)
		return false;
	$plain = $merid . $ordno . $amount . $curyid . $transdate . $transtype;
	return sign ( $plain );
}
function verify($plain, $check) {
	global $private_key;
	if (! array_key_exists ( "PGID", $private_key )) {
		return false;
	}
	if (strlen ( $check ) != 256) {
		return false;
	}
	$hb = sha1_128 ( $plain );
	$hbhex = strtoupper ( bin2hex ( $hb ) );
	$rbhex = rsa_decrypt ( $check );
	return $hbhex == $rbhex ? true : false;
}
function verifyTransResponse($merid, $ordno, $amount, $curyid, $transdate, $transtype, $ordstatus, $check) {
	if (strlen ( $merid ) != 15)
		return false;
	if (strlen ( $ordno ) != 16)
		return false;
	if (strlen ( $amount ) != 12)
		return false;
	if (strlen ( $curyid ) != 3)
		return false;
	if (strlen ( $transdate ) != 8)
		return false;
	if (strlen ( $transtype ) != 4)
		return false;
	if (strlen ( $ordstatus ) != 4)
		return false;
	if (strlen ( $check ) != 256)
		return false;
	$plain = $merid . $ordno . $amount . $curyid . $transdate . $transtype . $ordstatus;
	return verify ( $plain, $check );
}

 

银联接入

手册
http://console.chinapay.com/NetPayClient/new/NetPayClient_Manual.pdf
无力吐槽啊,居然得用ie来生成私钥,操作界面居然还有兼容问题。
http://console.chinapay.com/newgms/
参考
http://www.phpally.com/tag/unionpay/

使用手册看登录界面右方接入指南,可使用网关,直接查询即可。

目前比较纠结一个问题是,银联的orderid需要满足16位,且包含密钥的中间部分,金额需要从分位算起。
因为原系统已定,所以直接将这边的订单id保存到备注字段中。
将orderid做为第三方id保存。

参数说明:
String MerId 商户号,长度为 15 个字节的数字串,由 ChinaPay 或清算银行分配。
String OrdId 订单号,长度为 16 个字节的数字串,由商户系统生成,失败的订单号允
许重复支付。
String TransAmt 交易金额,长度为 12 个字节的数字串,例如:数字串”000000001234″
表示 12.34 元。
String CuryId 货币代码, 长度为 3 个字节的数字串,目前只支持人民币,取值为”156″ 。
String TransDate 交易日期,长度为 8 个字节的数字串,表示格式为:YYYYMMDD。
String TransType 交易类型,长度为 4 个字节的数字串,取值范围为:”0001″和”0002″,其中”0001″表示消费交易,”0002″表示退货交易。

表 3 ChinaPay 交易状态代码表
状态码 状态信息
1001 消费交易成功
1003 退款提交成功
1005 退款撤销成功
其他
其他均为交易失败,具体信息请登录 ChinaPay 交易控台查询,或查询各银行出
错信息文档。

json dump 支持打印缺损json格式

/**
 * 将utf-8编码串转成原字符串
 * @param string $str utf-8编码
 * @return string 原字符串
 */
function unicode2utf8($str) {
	if (! $str)
		return $str;
	$decode = json_decode ( $str [0] );
	if ($decode)
		return $decode;
	$str = '["' . $str [0] . '"]';
	$decode = json_decode ( $str );
	if (count ( $decode ) == 1) {
		return $decode [0];
	}
	return $str;
}
/**
 * 将json串格式化成串输出,对于有缺损的json串同样可以进行格式化
 * 例:
 * 
 * {
 * "枯asdf":{
 * "adsf":[
 * "hffe顶替标有"
 * ],
 * "0":"asdf"
 * },
 * "0":"hahakao"
 * }
 *
 * @param string $json        	
 * @return void 
 */
function dumpjson($json) {
	$isnojson = json_decode ( $json, true );
	$json = preg_replace_callback ( "/(\uw{4})/", "unicode2utf8", $json );
	$json = preg_replace ( "/\//", '/', $json );
	$data = indent ( $json );
	return "<pre>{$data}</pre>";
}
function indent($json) {
	$result = '';
	$pos = 0;
	$strLen = mb_strlen ( $json, "utf-8" );
	$indentStr = '	';
	$newLine = "n";
	$prevChar = '';
	$outOfQuotes = true;
	for($i = 0; $i <= $strLen; $i ++) {
		// Grab the next character in the string.
		$char = mb_substr ( $json, $i, 1, "utf-8" );
		// Are we inside a quoted string?
		if ($char == '"' && $prevChar != '') {
			$outOfQuotes = ! $outOfQuotes;
			// If this character is the end of an element,
			// output a new line and indent the next line.
		} else if (($char == '}' || $char == ']') && $outOfQuotes) {
			$result .= $newLine;
			$pos --;
			for($j = 0; $j < $pos; $j ++) {
				$result .= $indentStr;
			}
		}
		// Add the character to the result string.
		$result .= $char;
		// If the last character was the beginning of an element,
		// output a new line and indent the next line.
		if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) {
			$result .= $newLine;
			if ($char == '{' || $char == '[') {
				$pos ++;
			}
			for($j = 0; $j < $pos; $j ++) {
				$result .= $indentStr;
			}
		}
		$prevChar = $char;
	}
	$result = preg_replace ( '/\\/', '', $result );
	$result = preg_replace ( '/\"/', '"', $result );
	return $result;
}