php代码规范以及项目开发规范

袁亮,2014-08-26,php代码规范以及项目开发规范,mysql规范

一、命名
1、文件夹、文件名
1.1 只允许小写字母,数字,下划线组成,不允许出现其他字符
1.2 以统一的功能模块名加操作类型命名
1.3 比如:user_add.php,sub/user_add_sub.php
1.4 add_user.php sub/add_user_sub.php 这种写法是不友好的,不要这么写
2、类名
2.1 只允许英文字母,数字组成
2.2 驼峰规则,每个单词的首字母大写
2.3 比如:class BlogPosts{}
3、函数名
3.1 只允许英文字母,数字组成
3.2 驼峰规则,同类名,第一个单词首字母小写
3.3 比如:function postAdd();
3.4 命名以模块名+动作类型命名,比如postDetailGet();而不是getPostDetail,并且将同一个模块的函数尽量放一起
4、变量名
4.1 只允许小写字母,数字,下划线组成
4.2 单词之间以_连接,除循环中之后,不允许出现单字母变量
4.3 善于临时变量,有些变量使用1-2次之后,马上就没用的,可以使用$tmp来命名,减少想变量名的苦恼
4.4 所以的sql语句,都用$sql命名,并且最好是定义完就使用,后面不会再次用到
4.5 常用变量名:
$page:分页页码
$limit:每页显示多少条
$ip:用户ip地址
$dated:当前时间
$ms:mysqls操作类实例
$pager:存放分页的html代码
$data:当前页面主要的数据
$user_id:用户id
$username:用户名
$nickname:用户昵称
5、全局变量
5.1 命名规范同变量,但加前缀g_标示这是一个全局变量
5.2 比如:global $g_username; $g_username = 'yuanliang847';
6、常量名
6.1 只允许大写字母,下划线,数字组成
6.2 比如 define("USER_PASS_MDSTR",'D123#!@ax?DSAD');
#7、session名称

二、php最后结束符
1、不要使用短标签<??>
2、每行后面必须加;号结束
3、纯php文件,最后不要加?>结束符,防止因为最后的空行等输出导致bug

三、单引号、双引号
1、纯字符串的时候,使用单引号
2、字符串中有变量的时候,使用双引号,并且变量必须以{}包含起来,比如$show = "你好{$nickname}!";
3、数组中,非数组下标,一定要加单引号,比如$data['username'] = 'yuanliang847';
4、sql语句中的变量值,以单引号包含起来,比如$sql = "select * from `users` where `username`='{$username}' limit 1";

四、括号使用
1、所有大括号的开始部分都跟在关键字的后面,没有例外,比如:
function getRow($sql){

}
foreach($data as $k=>$v){

}
class Mysqls{

}
2、小括号跟关键词相连,不需要额外的空格
if(1 == $a){

}else if(2 == $b){

}else{

}
3、函数参数左右不需要额外空格
function test($a,$b = 1){

}

五、空格、缩进、大数组缩进
1、所有缩进,均以tab进行缩进,不要使用多个空格
2、空格使用情况:
2.1 $username = 'yuanliang';变量赋值,前后加空格
2.2 比较操作符、算术操作符、逻辑操作符,前后加空格
+= , >= , <= , ==
+ , - , * , %
&& , ||
2.3 一元运算符,不需要空格
++ , -- , ! , &
2.4 对象运算符,不需要空格
$this->test();
parent::test();
3、大数组缩进方式,前面通过tab缩进到 同一层次,=>后面的是一个空格,数组只有1-2个值的时候,不需要写成这样
$data = array(
'user_id'    => 1535917,
'username'    => 'yuanliang847',
'nickname'    => '暗夜御林',
'head'        => 'http://i.ci123.com/153/1535917.png',//这种最后一定要加逗号,否则容易出错
);
$uinfo = array('username'=>'yuanliang847','nickname'=>'暗夜御林');

四、安全
1、需要过滤的外部数据:$_GET,$_POST,$_COOKIE,$_SESSION(session因为有可能存储了用户输入的内容,从而导致危险)
2、如果接收的是整形数据,一律以intval强制转为整形
2.1 比如 $user_id = isset($_GET['user_id'])?intval($_GET['user_id']):0;
3、如果是字符型,则需要调用防止sql注入的函数,进行过滤,该函数,在通用的function.php中就有
3.1 比如 $username = isset($_POST['username'])?stripSql($_POST['username']):'';
3.2 stripSql第二个参数,默认会调用stripTags,防止xss攻击,如果内容允许html等,则给定第二个参数
3.3 如果大串用户输入的内容,是会显示在页面的,比如文字内容等,可以使用htmlspecialchars将html实体化
4、接受外部参数的地方要在页面头部,或者函数开始位置全部获取所有可能接受的外部参数,该段代码之后,不允许再直接使用外部数据
5、如果是旧项目,需要改的地方太多,可以引入360的过滤文件,对所有外部危险输入进行过滤,并记录
该文件慎用,特别是在重要项目中,容易导致误判

五、功能块

六、注释

其他:
1、不要使用复杂的异或等逻辑判断(考验运算优先级的)
2、三元表达式只用做最简单的不赋值,不要做复杂的代码
3、不要让代码读起来有歧义,尽量简洁明了
4、不要写非常“巧妙”的代码,而是要让很二的人一眼就能读懂
5、不要使用or and,使用&&和||代替,优先级不同
6、少用while循环,太容易造成死循环
7、switch case 每个环节必须有break,否则会出错
8、理解清楚return continue break的意思,不要乱用
9、包含文件,一律使用include_once
10、嵌套层次最多4层,消除嵌套方法
11、循环中不要计算数量,有些计算能放在循环外面就不要放在循环里计算
11、大括号不可省略
12、使用construct 和 destruct,不要用与类同名的函数初始化 __get __set __autoload禁用
13、只用die,不要使用exit
14、不要使用嵌套式的赋值
if($a = ($c = getName())

做事优先级

dear tech4:

一、多件事情,怎么确定优先级
1、5分钟内就能搞定的事情,优先搞定,不要拖着
2、其他事情,按事情的重要程度来安排处理
3、更上级安排的事情,优先处理,比如员工群里,程总发现的问题或者南哥直接安排的事情
4、安全漏洞以及服务器出问题,需要迁移,请务必当成最重要的事情去做

二、同一件事情的处理优先级
1、第一优先级,东西是可用的
2、第二优先级,东西是好用的,包括代码的健壮、高效、易维护等
3、最后,才是自己是搞的很清楚的
因此,做事情前,必须要先去看看别人是怎么做的,不要想着什么都从头开始做,包括我们自己网站的内部资源,其他比较好的网站是怎么做的,百度或者google找到别人的demo,然后开始去处理。
给我看东西之前,都需要做好准备,我会问你“其他人是怎么做的?”,最好是能主动给我一个满意的答案

周报要求

13:14 2014-3-13,袁亮,周报要求

时间:每周日中午12点前
标题:【2014-02-24至2014-02-28】周报-袁亮
内容:
	一、本周做了什么?
		ps:主要工作记录下来即可,不要细化到改个链接什么的
	二、最有成就感或者最不爽的事?
		ps:学到了一个比较牛逼的东西,或者做了一个有意思的东西,或者做了一件自己觉得不想干的事等等
	三、有什么不足或者需要改进的?
	ps:自己的个人疑惑,或者自己哪方面还需要加强?团队中哪方面不合理的?个人或者团队内部的都可以

	其他:
	1、周报内容写在邮件正文里,可以提供附件作为备份参考,但不允许出现只有附件,没有正文的
	2、邮件的排版,参考看下其他人的邮件是怎么写的,不要写的乱七八糟,包括换行,缩进等,归纳总结
		如果自己都不能写的有条有理,那这个总结效果必然很一般
	3、周报发送给自己的直属领导,抄送我

简单的签名技术

编    写:袁    亮
时    间: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)