简单的签名技术

编    写:袁    亮
时    间:2015-01-27
说    明:基本的数字签名技术

一、为什么需要
1、网络传输的过程中,数据对别人来说是可见的,我们需要保证数据没有被篡改,以保证基本的安全
2、常见使用:
cookie信息
接口调用参数验证

二、如何实现
1、先验条件
1.1 数据生成、数据接收方都需要可控
1.2 两边统一一个相应的密钥,并保存
2、实现
2.1 生成方,在原始数据的后面,根据密钥以及原始数据(其中一部分也行,两边约定好即可),使用散列(MD5或者SHA-1)生成一个签名
2.2 接受放根据接受到的数据,将原始数据使用同样的办法,进行散列,查看与接受到的签名是否一致,如果不同,则非法
3、优点
3.1 实现简单,安全性较高
4、缺点
4.1 如果密钥泄露,更改较为麻烦,得两边同时修改

三、cookie签名demo
1、设置cookie
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$cstr = '1535917,yuanliang847,暗夜御林';//设置到cookie里的内容
$signstr = md5($cstr.MD_STR);
$cstr .= "|-|".$signstr;

setcookie("uinfo",$cstr,0,"/",'',false,true)

2、cookie解析
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$uinfo = checkLogin();

function checkLogin(){
if(!isset($_COOKIE['uinfo']) || !$_COOKIE['uinfo']){
return array();
}

$cstr = $_COOKIE['uinfo'];
$tmp = explode("|-|",$cstr);
if(md5($tmp[0].MD_STR) != $tmp[1]){//cookie非法
return array();
}

$data = explode(",",$tmp);
return array('user_id'=>$data[0],'username'=>$data[1],'nickname'=>$data[2]);
}

四、接口参数签名demo
1、client(必须是服务端的,不能是用户可见的过程,比如js)
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$uid = 1535917;
$username = 'yuanliang847';
$str = "uid={$uid}&username={$username}";//需要传输的原始数据
$http_str = $str."&signstr=".md5($str.MD_STR);//将签名与原始数据一起拼接传输

//...网络数据传输

2、server
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$uid = isset($_GET['uid'])?intval($_GET['uid']):0;
$username = isset($_GET['username'])?$_GET['username']:'';
$signstr = isset($_GET['signstr'])?$_GET['signstr']:'';

$str = "uid={$uid}&username={$username}";
if(md5($str.MD_STR) != $signstr){
die('参数错误');
}

//...正常业务逻辑处理

3、改进
以上需要对每一个客户端和服务端进行相应的编写,很麻烦
可以编写一个统一的签名函数,来进行相应的验证

五、接口层统一的函数
1、client
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$p = array(//需要传递的参数,可以是get或者post用
'user_id'    => 1535917,
'username'    => 'yuanliang847',
'nickname'    => '暗夜御林',
);
$p = addSign($p);
$url = "http://api.***.com/***.php?".http_build_query($p);

//...发送接口请求

/**
* 将需要传递的参数数组增加一个签名串
* @data 需要传递的参数数组
* #返回新的参数数组,并增加键值signstr作为签名
*/
function addSign($data){
$str = json_encode($data);
$data['signstr'] = md5($str.MD_STR);
return $data;
}

2、server
define("MD_STR","FDSAF$#@dsa!#@4134Eda");

$is_sign = checkSign($_POST);//看接口是post还是get,传入不同的数据
if(!$is_sign){
die('参数错误');
}

//... 正常业务逻辑处理

/**
* 验证签名串是否正确
* @data 需要验证的参数,包括原始数据以及签名串
* #返回true则正常,否则参数有问题
*/
function checkSign($data){
if(!isset($data['signstr']) || !$data['signstr']){//没有签名
return false;
}

$signstr = $data['signstr'];
unset($data['signstr']);
if(md5(json_encode($data).MD_STR) != $signstr){
return false;
}

return true;
}

育儿网邮寄地址插件

编    写:袁    亮
时    间:2015-01-20
说    明:育儿网邮寄地址插件使用说明

一、问题
1、收货的邮寄地址需要用户填写省市区
2、省市区等信息会变,需要统一管理
3、需要实现联动效果,不需要各个项目都做这一套

二、使用范例
1、代码(参考demo.html文件)
<form name="recvaddress_form">
<select name="province" onchange="ciarea.selcity(this.value,0);" style="width:80px;"></select> 省
<select name="city" style="width:120px;" onchange="ciarea.selarea(this.value,0);"></select> 市
<select name="area" style="width:120px;"></select> 区
</form>
<script type="text/javascript" src="http://shiyong.ci123.com/district/common.js"></script>
<script type="text/javascript">
window.onload = function(){
//ci_province=11;ci_city=1100;ci_area=41306; //编辑的时候,需要默中省市区的时候设置
ciarea.selprovince(ci_province,ci_city,ci_area);
}
</script>
2、需要注意的地方
2.1 form的name必须设置为recvaddress_form,js中有用到
2.2 三个select的name的名称是确定的这三个
2.3 两个onchange事件不能少
2.4 引用common.js
2.5 页面加载的时候,触发数据加载
2.6 编辑地址的时候,需要有默认选中的时候,则设置相应的三个js变量即可

三、参考页面
1、http://shiyong.ci123.com/user/address.php
2、http://user.ci123.com/account/EditUserInfo/detail

邮寄地址插件demo范例

<!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>
</head>

<body>
<form name="recvaddress_form">
<select name="province" onchange="ciarea.selcity(this.value,0);" style="width:80px;"></select> 省
<select name="city" style="width:120px;" onchange="ciarea.selarea(this.value,0);"></select> 市
<select name="area" style="width:120px;"></select> 区
</form>
<script type="text/javascript" src="http://shiyong.ci123.com/district/common.js"></script>
<script type="text/javascript">
window.onload = function(){
//ci_province=11;ci_city=1100;ci_area=41306; //编辑的时候,需要默中省市区的时候设置
ciarea.selprovince(ci_province,ci_city,ci_area);
}
</script>
</body>
</html>

http协议的简单总结

编    写:袁    亮
时    间:2014-6-26
说    明:http协议的简单总结

一、基本流程
1、在浏览器输入网址
2、浏览器根据网址,封装http请求头数据包
3、数据包根据地址查找到相应服务器
4、服务器根据头信息进行相应处理并返回返回头信息以及body内容
5、浏览器接收到返回数据,展示body部分内容,并根据头消息进行相应设置,比如cookie等
6、浏览器根据内容进行相应的排版现实,并且运行其中的js交互脚本
7、一次完整的交互完成

二、查找服务器过程
1、根据域名查找本地hosts文件,看是否有对应ip
2、发送到代理,代理去请求数据
3、如果没有,则发送请求到公网dns查询该域名对应的服务器地址
4、cdn加速访问
5、前端代理转发
6、http服务器接收请求,并交给php解析运行
7、服务器将返回的数据再传输回用户的浏览器

三、http常用状态码
200:正常返回
301:永久跳转
302:临时重定向
304:资源未修改,直接使用本地缓存
403:权限不够
404:找不到文件
500:服务器错误,一般是程序语法错误等
502:代理服务器未能接受到正确响应
504:响应超时

crontab书写的一些注意事项

编	写:袁	亮
时	间:2014-03-13
说	明:crontab书写的一些注意事项

一、使用说明:
crontab 是指定时linux服务器,自动的定时去执行一个脚本
一般用于定时去进行一些数据统计,缓存更新,消息提醒等等

二、使用流程:
1、脚本编写,并执行测试(/opt/ci123/php/bin/php *.php),看功能是否正常
	a、定时脚本最好不要在浏览器中执行,因为定时脚本一般执行时间较长,如果在浏览器下执行,有死循环或者太耗时间的语句,中途停止不了,很容易因为这个把数据库等弄挂,项目不能正常访问。而在linux下直接执行,如果卡或异常,可以直接ctrl+c中止。
	b、引入外部文件最好以全路径包含:通过define("FROOT",(dirname(__FILE__)))获取当前文件路径,再通过FROOT来拼接(易于迁移,防止多重include导致相对路径计算错误等)
	c、不允许浏览器访问,防止爬虫等异常访问,加在脚本的前面
		[code]
		if(isset($_SERVER['HTTP_HOST'])){//定时脚本不允许浏览器访问
 		       die();
		}
		[/code]
	d、必须有输出,包括:脚本开始时间、结束时间,各模块的结束时间,方便后期排查

2、加入crontab
	a、crontab -e 进行crontab文件编辑,-e参数不可少,否则会导致将crontab内容清楚,切记
	b、添加一条记录,例如:
		第一行	以#开头的是注释,谁写的,什么时间,做什么用的
		第二行,前5个,分别代表分、时、日、月、周(具体数字代表固定时间;1-5,代表区间;1,4,7代表指定几个时间;*/5代表每5个单位时间执行一次;*代表任意时间;);
			source /etc/profile.d/ice-3.2.1.sh;这个是有ice扩展的时候才加;
			后面是调试时候的执行代码;
			>>/tmp/bbs_static_hour_log 是指将输出以追加的方式记录到/tmp/bbs_static_hour_log这个文件中,命名需规范
			2>&1; 代表不管是正常输出,还是错误提示都记录到日志,照抄即可

		[code]
		#袁亮-2013-12-03,统计bbs每天24小时发帖、回帖等数据
		37 2 * * * ( source /etc/profile.d/ice-3.2.1.sh; /opt/ci123/php/bin/php 		/opt/ci123/www/html/bbs/sadmin/cront/makeStatic.php >>/tmp/bbs_static_hour_log  2>&1;)
		[/code]
	
	

php数组的相关知识

编    写:袁    亮
时    间:2015-01-20
说    明:php数组的相关知识

一、相关概念
1、把有限个变量用同一个名字标识,然后使用不同的名称标识,标识称为下标。本身是一个集合
2、php数组有三种
索引数组 - 带有数字索引的数组
关联数组 - 带有指定键的数组
多维数组 - 包含一个或多个数组的数组

二、常用功能
1、数组创建
$data = array(//索引数组
'user_id'    => 1535917,
'username'    => 'yuanliang847',
'nickname'    => '暗夜御林',
);

$data = array('yuanliang','暗夜御林');//如果数组很小,不需要跟上面似的,写成多行;索引数组

$data['username'] = 'yuanliang847';

$data[] = '暗夜御林';//索引数组,下标值自动加1

第一种方式key后面使用Tab键缩进保持代码对齐,不要打一堆空格,值的前面是一个空格
最后一个值的“,”可以省略,但建议不要省,方便其他人加一个下标的时候,忘了补从而出错
多维数组只是把其中的值value变成一个数组即可
2、循环遍历
foreach($data as $k=>$v){
echo $v."<hr />";
}
php数组使用最多的方式,没有之一
for循环只能对索引数组循环,而foreach可以对任意数组进行循环遍历
$k 是相应的数组下标,$v是对应的值
3、数组计算
$num = count($data);
多维数组也只记第一维的个数

三、数组打印调试
1、var_dump()
var_dump($data);
die();

这是php调试中最常使用的调试打印方法,任意类型的变量都可以打印
2、echo
echo $data['username'];
程序嵌套部分,都是使用的echo把php变量输出成对应的html
3、var_export()
var_export($data);
与var_dump类似,但是这个打印出来的内容,复制出来,可以直接复制给php变量使用,有些时候非常有用
$d = var_export($data,1);//把转化的数据变成字符串,经常会用来生成php文件

四、其他比较有用的功能
1、排序
sort ksort
排序的不同方式,有一堆sort结尾的函数,需要的时候,具体看函数列表
2、数组去重
array_unique
先将值作为字符串排序,然后对每个值只保留第一个遇到的键名,接着忽略所有后面的键名
一般只对一维数组排,多维数组排没有任何意义
3、多个数组合并
array_merge
如果键名有重复,该键的键值为最后一个键名对应的值(后面的覆盖前面的)。如果数组是数字索引的,则键名会以连续方式重新索引
4、查看给定的值在数组中是否存在
in_array($str,$arr)
一般我们只用在索引数组里
5、随机获取一个或者多个元素
array_rand
6、把数组中的值赋给一些变量
$data = array(1535917,'yuanliang847','暗夜御林');
list($user_id,$username,$nickname) = $data;
省去了多次赋值
7、与字符串的互相转换
字符串转索引数组:
explode(separator,string,limit)
数组转字符串:(不要使用join别名,高版本会报错,ps:没记错的话是5.3之后)
implode(separator,array)

翻墙的相关知识

编    写:袁    亮
时    间:2015-06-25
说    明:翻墙的相关知识

一、为什么需要翻墙?
1、天朝有个东西叫GFW(中国长城防火墙),会将一些不希望网民看到的东西封禁,导致我们上不了一些网站
DNS解析:DNS解析服务器不受国内控制,采用的域名劫持的办法使得我们上不了相应域名,也封锁了海外相当多的DNS服务器
连接阶段:请求与被封禁名单匹配,重置连接
URL关键词:在路由器上,对链接的关键词进行匹配,封禁
页面扫描:对国际出口,扫描页面内容,发现关键词,则在一定时间段内,不能连接到该网站,骨干网省级接入处也有
ps:国内网站基本上会通过行政干预,整改或者关闭,主要针对的是国外不能控制的网站
2、查找技术资料、问题的时候,百度经常搞不定
3、很多较新的技术,国内没有相关资料,需要翻墙

二、如何实现翻墙
1、加host
只适用于访问固定某个网站,比如给google加相应的host,像下载adt等的时候就会这么干
大部分时候无效,因为那些固定ip经常被封,
了解即可,正常翻墙不会这么干
2、代理
正常上网的话,需要路由器,dns解析等等,这个时候,防火墙会进行各种干扰导致上不了
使用代理,其实就是找到一个可以不经过防火墙的服务器(国外,国内肯定被墙),去帮你访问这些网站,并把这些网站的返回数据返回给我们,因为代理服务器没有被封,所以我们可以正常的连接到这台服务器上,而这台服务器又可以正常的上那些网站,所以通过它,我们就可以愉快的上各种网站了
代理不对请求内容进行加密,知识通过代理服务器进行了请求转发
这个一般都是在浏览器中设置相应的代理,只有设置了相应代理的浏览器才能翻墙
3、拨vpn
VPN:虚拟专用网络,架设一台VPN服务器,客户端上网的时候,通过加密的方式将数据传输到VPN服务器上,VPN服务器进行解密
从而进行通信,一般是用来作为企业内网使用
通过VPN上网的话,是在操作系统层面修改了连接方式,不管是什么浏览器,QQ还是其他客户端,都是走的VPN
连接vpn之后,本机将作为vpn网络的内网进行相应访问,vpn服务器作为统一的对外出入口
只要vpn服务器本身没有被墙,则访问任何网站都是可以的
vps:虚拟专用服务器,虚拟机

三、常用翻墙软件
1、免费,自动搜索代理服务器
自由门:经常需要更换代理,要求不高用用还可以
无界:一般,不大稳定,跟自由门差不多
webfreer浏览器:没用过
2、免费,固定代理
goagent:需要先翻墙才能申请google账号,也会时不时的被封
3、免费VPN
百度搜索,需要经常更换
http://qqbox.org/vpn/freevpn 这边有很多推荐的,可以自己试下
4、付款VPN
Shadowsocks:在用,99一年,还不错
红杏:没用过

php与apache的各种报错情况整理

编    写:盛星衡
时    间:2014-09-24
功    能:对php与apache的各种报错情况整理

php运行的报错,错误日志涉及下面几个参数的设置:
display_errors//on:页面显示错误提示,off页面屏蔽错误提示
log_errors,//on记录错误日志,off不记录错误日志
error_reporting,//设定报错级别

开发环境下一般把display_errors设置为on,error_reporting设置为8191,也就是E_ALL,宽松点可以设置为7,也可以写成error_reporting(E_ERROR | E_WARNING | E_PARSE);
一般开发模式会开warning提示,可以帮助开发人员找到一些边界处理的失误;

线上项目设置为display_errors设置为off,error_reporting设置为5,log_errors设置为on,并且apache设置log文件地址。

常见问题:
1、开发模式下设置了开启报错,但是就是没有错误提示?
这种问题一般是因为php.ini中把错误提示关闭了,程序中虽然开启了错误提示,但是语法错误,程序中设置不起效,导致没有错误提示。

2、php配置文件中把报错关闭了,没有权限对php配置文件进行修改,然后写了很长一段代码,语法错误,怎么看到错误提示?
这种情况在线上项目的调试会遇到,可以另写一个php文件,在文件中把报错开启,然后include语法错误的文件,就可以看到错误提示了。
常见的应用就是在apache上做rewrite,项目下的所有访问都统一到一个入口文件中,报错在入口文件当中配置,开启,关闭报错都比较方便。
在inc/gloal.php进行配置,然后引用,在文件本身语法错误的情况下,配置失效。

3、线上项目明明设置为把错误记录到日志中,php配置文件中设置了关闭页面报错,为什么还是把错误提示显示在页面上了?
在设置记录日志的情况下,apache配置中没有设置log文件或者没有权限操作log文件时,错误日志会直接显示在页面上。

4、如果php.ini中设置了不显示warning报错,apache重启之后,还是没用,可能是因为apache中设置了phpvalue error_reporting导致
参考文档:
http://php.net/manual/zh/errorfunc.configuration.php
http://www.jb51.net/article/31499.htm
http://www.w3school.com.cn/php/func_error_reporting.asp

ajax的简单使用和常见问题


编	写:袁	亮
时	间:2015-01-16
说	明:ajax的简单使用和常见问题

一、介绍
	1、异步js和xml
	2、在不刷新整个网页的情况下,异步的请求服务器改变部分页面数据

二、简单使用范例
	1、一般我们直接使用jquery封装好的方法直接调用,原生的实现,可以参考w3c教程
	2、范例
		function addPost(f){
			var title = f.title.value;
			var uid = 1535917;

			if(title.length<2){
				alert('标题最少2个字');
				f.title.focus();
				return false;
			}

			//$.get("sub/post_add_sub.php?rid="+Math.random(),{title:title,user_id:uid},function(data){
			$.post("sub/post_add_sub.php?rid="+Math.random(),{title:title,user_id:uid},function(data,state){
				console.log("b");
				if(data == '1'){
					//成功后的处理,显示
				}else{//失败后的提示处理等
					alert(data);
				}
			});

			console.log("a");
			return false;//不能少
		}

	3、简单说明
		1、get和post方法使用方法一样
		2、第一个参数代表的是你访问的网址是什么,后面加了一个参数rid,是因为浏览器会对js的请求进行缓存
			我们使用ajax的请求,不希望被缓存,所以加了一个随机数
		2、第二个参数{title:title,user_id:uid}
			title是传给post_add_sub.php页面的参数名,第二个title是js的变量,传递值
			user_id:uid同理
		3、第三个参数,这是一个回调函数
			data是post_add_sub.php的返回值,string类型的(类似于post请求到那边,页面输出的源代码)
			state:表示的是这次请求的状态,是否成功等,简化使用的时候我们没有判断该参数
			function(data,state){

			}
		4、设置了两个console.log,一半来说a会比b先写进去
			ajax请求是一个异步的,发出这个请求,不管有没有成功,继续执行下面的代码,console.log("a");
			异步的请求执行完之后,才会执行到回调函数中console.log("b");
			因此一般的网络请求,都会是a先触发,后触发的b

三、适用场景
	1、异步提交数据
		填写了一个表单,写了一堆东西,结果提交过去之后,因为某些错误,返回重写,导致之前的努力全部白费
		这个时候非常需要异步提交,增强用户体验
	2、局部刷新页面数据
		页面只有一小部分数据需要刷新,有改动的情况
		比如说:投完票,我需要实时的查看现在的票数
		比如说,删除了一行数据
		或者一个很大的页面,其中一小块的数据需要进行分页等等
	3、性能
		一个页面如果有非常多的数据量,如果一次全部取出来,加载的话,会非常卡,而且有很多无效的查询和请求
		这个时候,可以有个简单的优化办法,按需加载
		比如页面滚动的时候,加载相应数据、图片等

四、缺点
	1、实现会比之前的稍微复杂些
	2、后加载的内容对搜索引擎不友好,搜索引擎抓取不到
		也有办法解决,就是会很麻烦
	3、复制链接给其他用户或者自己收藏的时候,下次打开发现跟预期的不一样
		可以通过锚点解决这个问题,可以百度看下相关资料

五、调试方法
	1、可以通过firebug,或者chrome的F12查看相应的network状态
		http请求的具体知识,请查看相应文档
	2、先使用get请求的方法访问,调试
		在新窗口中打开该请求,刷新页面调试即可,与正常网页一样
	3、使用抓包工具Fiddler2抓取请求包分析

六、常见问题
	1、编码
		只认utf-8编码,sub那边的返回数据必须设置编码格式
	2、跨域
		js不允许post跨域,浏览器同源安全策略
		get跨域,跨域通过jsonp方法解决(jquery的getJson方法)
		也可以采用本域中转页面,然后发起一个服务端到服务端的请求,从而绕过跨域限制
	3、缓存
		ajax请求,正常情况下是会被浏览器缓存中的,所以请加随机数防止