PHP的一些天坑
什么叫天坑。天呐,原来这么坑,不知则已,细思极恐。
一、小数(符点数)不能直接比较是否相等
比如 if( 8-6.4==1.6 ) 的结果是 false。究其原因是因为,PHP是基于C语言的,而C语言由于其二进制符点数的表示方式,导致不能精确表示大多数符点数。实际上,几乎所有的编程语言都没能精确表示小数(符点数),这是一个普遍存在的现象,因为这个是 IEEE 754 的缺陷。想要解决此问题,只能另立标准,似乎只有Mathematica解决了此问题。
PHP 中可以使用BC数学函数系列中的 bccomp()函数 比较小数是否相等。
二、字符串是否相同建议用 === 而非 ==
为什么呢?因为这个比较是弱类型,两个比较时,PHP会先尝试判别左右两者是否为数字。而问题就在于什么样的字符串是数字,是单纯的数字串吗?远远不只于此,还包括 0x 开头的十六进制,XXeX类型的科学记数法 等等,如 '12e0'=='0x0C' 得到的是true。而在数值类型与字符串比较时,甚至一些数字开头的非数值串,比如 12=='12这个串' 得到的值也会是 true。
所以这些情况下,可能会使本来并不相同的字符串被判定为相等。而使用===比较则为包含类型的比较,不会有任何转换,所以是可以准确比较字符串是否相同的。
另外吐槽一下JAVA,==居然比较不了字符串是否相等,因为字符串是一个对象,==变成了判断是否为同一个对象……
三、trim系列函数的过多去除
trim函数的基本用法是去除最外边的空格、换行符之类的。因为其可选参数,很多人也会将其用于去除UTF8BOM头、文件扩展名等等,比如 ltrim($str, "\xEF\xBB\xBF"); rtrim($str, ".txt"); 。但是很快,就会发现这些函数会多去除了一些东西,比如本来是想去除后缀的,结果 logtext.txt 会变成了 logte 而不是 logtext。为什么呢?因为后面这个参数的意思不是一个完整字符串,而是字符列表,也就是说会一直检查最左/最右是否符合此列表的其中一个。
那怎么样才是真正我们想要的去掉最前最后呢?网上的说法是说用正则表达式,我封装了对应的三个方法,以便使用。命名规则是比原来PHP的函数多了个s,表示string的意思。用法跟原来PHP的函数一样。
/**
* 另一种 trim ,不会过多去除
* $charlist正则元字符会自动转义
* */
function ltrims($str, $charlist){
$charlist = preg_quote($charlist, '/');
return preg_replace("/^$charlist/", '', $str);
} function rtrims($str, $charlist){
$charlist = preg_quote($charlist, '/');
return preg_replace("/{$charlist}$/", '', $str);
} function trims($str, $charlist){
$charlist = preg_quote($charlist, '/');
$str = preg_replace("/^{$charlist}/", '', $str);;
return preg_replace("/{$charlist}$/", '', $str);
} function trimBOM($str){
return preg_replace("/^\xEF\xBB\xBF/", '', $str);
}
四、网上说的获取客户端IP地址的各种方法
网上流行一段获取客户端IP地址的PHP函数如下:
function getIP() {
if (getenv('HTTP_CLIENT_IP')) {
$ip = getenv('HTTP_CLIENT_IP');
}elseif (getenv('HTTP_X_FORWARDED_FOR')) {
$ip = getenv('HTTP_X_FORWARDED_FOR');
}elseif (getenv('HTTP_X_FORWARDED')) {
$ip = getenv('HTTP_X_FORWARDED');
}elseif (getenv('HTTP_FORWARDED_FOR')) {
$ip = getenv('HTTP_FORWARDED_FOR');}
}elseif (getenv('HTTP_FORWARDED')) {
$ip = getenv('HTTP_FORWARDED');
}else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
这函数看起来并没有什么问题,很多开源CMS之类的也在用。然而事实上,问题大着呢!首先第一步,是要了解这些 getenv 读取的东西到底是什么玩意,又是从哪来的。简单来说这些其实是HTTP header,有些代理服务器会把源请求地址放到header里,所以我们服务器可以知道访问用户的原始IP地址。但是,并不是所有代理服务器都会这么做,也并不是只有代理服务器会这么做。
而实际上,这些HTTP header是可以随便改动的,比如curl就可以自己设置各种HTTP header。如果用此函数得到的结果,进行IP限制等操作的话是很轻易绕过的。更可怕的是,如果后续程序没有对此函数取得的IP地址进行格式校验过滤的话,就很微妙地为SQL注入打开了一扇窗户。所以比较保险的方式是只读取非HTTP header的 $_SERVER['REMOTE_ADDR']
PHP5.4及以上可以使用以下函数判断是否符合IP地址格式 filter_var($ip, FILTER_VALIDATE_IP) ,老版本需自行写正则。
五、foreach的保留现象
使用 foreach($someArr as $someL){ } 之类的用法时,要注意最后的一个 $someL 会一直保留到该函数/方法结束。而当使用引用的时候 foreach($someArr as &$someL){ }这是以引用来保存,也就是说后面若有使用同一个名字的变量名,将会把原数据改变(就像一个乱用的C指针)。为安全起见,建议每个foreach(尤其是引用的)结束之后都使用unset把这些变量清除掉。
foreach($someArr as &$someL){
//doSomething ...
}unset($someL);
六、htmlspecialchars 函数默认不转义单引号
不少网站都是使用此函数作为通用的输入过滤函数,但是此函数默认情况是不过滤单引号的。这是非常非常地容易造成XSS漏洞。这样的做法和不过滤双引号没太大区别,只要前端写得稍微有点不规范(用了单引号)就会中招。下面这个示例改编自知乎梧桐雨的回答
<!Doctype html>
<meta charset="utf-8"/>
<?php
$name = $_POST["xxs"];
$name = htmlspecialchars($name);
?>
<form action="" method="post">
提交的注入<input type="text" name="xxs" value="ins' onclick='alert(1)" >
<input type="submit" value="提交" />
</form> 提交后这个按钮会被注入点击弹警告
<input type='button' value='<?=$name?>' />

要求所有的时候都使用双引号不得使用单引号,这其实不太现实。所以,这个主要还是后端的责任,把单引号也要转义,我们用的时候一定要给这个函数加上参数 htmlspecialchars( $data, ENT_QUOTES);
很多人向Thinkphp框架提出过这个问题,因为其默认过滤方法就是无参数的htmlspecialchars,不过滤单引号,而其官方答复是“I函数的作用不能等同于防止SQL注入,可以自定义函数来过滤”……毛线啊,最基本的防护都不给力,这是给埋了多少隐患啊。在此强烈各位使用者重新定义默认过滤函数,我自己定义的是 htmlspecialchars(trim($data), ENT_QUOTES); ,有更好建议欢迎评论。同时非常希望TP官方更正此问题。
关于XSS,容我多说两句,请看下面这个例子。
<?php $name='alert(1)'; ?>
<p id="XSS2"></p>
<script src="//cdn.batsing.com/jquery.js"></script>
<script>
$("#XSS2")[0].innerHTML = <?=$name?>;
$("#XSS2").html( <?=$name?> );
$("#XSS2")[0].innerHTML = "<?=$name?>";
$("#XSS2").html(" <?=$name?> ");
</script>
其中第1、2行 JS会造成 XSS 漏洞,第3、4行则不会。而 alert(1) 这样一种字符串,后端甚至没有什么比较好的方法可以过滤,唯一有效的方法可能是在数据的两端加上引号。主要责任还是在于前端,对 innerHTML 和 jQuery的html() 的输出使用时,一定要确保传入的参数是字符串,否则其危险性不亚于 eval 函数
PHP的一些天坑的更多相关文章
- Zepto的天坑汇总
前言 最近在做移动端开发,用的是zepto,发现他跟jquery比起来称之为天坑不足为过,但是由于项目本身原因,以及移动端速度要求的情况下,也只能继续用下去. 所以在这里做一下汇总 对img标签空sr ...
- 【天坑】ASP.net WebAPI跨域调用问题
最近在做一个项目,前端是VUE,后端是WebAPI,业务也就是一些实体的增删改查.在项目开始的时候我就预计到有跨域的问题,所以也找了一下资料,在Web.Config里面加上了配置信息: <htt ...
- 微信小程序天坑--图片汉字命名
图片用汉字命名的,在开发者工具中是显示的,但是,在真机的微信中,是不会显示的. 大写的尴尬,微信小程序开发者工具对于做微信的UI来说,就是一个天坑,在电脑上漂漂亮亮的,到手机上各种意想不到的情况.
- 天坑之路:用js给选中文字添加样式
前言 本例基于react,但是实际上就是用原生js做的.兼容性做到了IE9,但是按照这个思路做是可以做到IE8甚至更低的. 需求与最初的思路 当我拿到这个需求的时候以为很简单,就是可以给页面上的文章做 ...
- mvc.net路由中带特殊字符如【.*/\】等时遇到的天坑
用mvc.net的路由做网站伪静态时出现的天坑,自己一直没测试出来,竟然要靠客户被坑了后才知道 解决办法 参考https://stackoverflow.com/questions/16581184/ ...
- Unicode浅析——调用科大讯飞语音合成接口(日语)所遇到的天坑
如题,最近做的项目需要调用科大讯飞的语音合成接口,将日文合成日语.然后坑爹的是跟我对接的那一方直接扔过来一份接口文档,里面并未提及日语合成所需要的参数.中文.英文合成倒是没问题,就这个日语合成的音频始 ...
- shell script test指令的测试功能 &和&&,|和|| 区别 变量名赋值=号前后的空格问题(天坑)
小程序告一段落,达到阶段性目标.下一步继续Linux的学习....脑子不够用啊...真费... 书中介绍..检测系统某些文件或者相关属性时,用test指令.. 例如.测试某个文档目录是否存在可以 t ...
- ABP vNext 自动注入,暗藏天坑如斯
导言 我们在使用ABP vNext框架时,都知道该框架为我们实现了自动依赖注入(实现自动注入需要在项目里面创建Module类,并且将Module类上的DependsOn到相应的启动Module类或调用 ...
- 避开WebForm天坑,拥抱ASP.Net MVC吧
有鹏友在如鹏网的QQ群中提了一个问题: 请问,在ASP.Net中如何隐藏一个MenuItem,我想根据不同的权限,对功能菜单进行隐藏,用style不行. 如果要仅仅解答这个问题,很好解答,答案很简单: ...
随机推荐
- openstack controller ha测试环境搭建记录(一)——操作系统准备
为了初步了解openstack controller ha的工作原理,搭建测试环境进行学习. 在学习该方面知识时,当前采用的操作系统版本是centos 7.1 x64.首先在ESXi中建立2台用于测试 ...
- iOS学习笔记1--在xcode6以上的版本中不使用storyboard以及部分控件使用
首先建立一个iOS新工程,删除工程自动建立的main.storyboard以及xib文件,并且在info.plist上删除这两个选项 然后在项目配置中将maninterface设置为空,将launch ...
- list集合怎么转化成一个javaBean对象,及常见的使用方法(全)
一.List集合的用法 1.list集合添加实体并输出 for (int i = 0; i < list.size(); i++) { javabean obj= (javabean)list. ...
- MySql Host is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts' 解决方法 -摘自网络
错误:Host is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts' 原因: 同一个i ...
- Spring学习---JPA配置和使用
理论的东西如果不实践,永远不会变成自己的东西.本文将介绍用maven管理,用Hibernate作为JPA供应商,使用MYSQL数据库,配置和使用JPA. 以下代码已经上传至GITHUB. ...
- mysql show命令
MySQL中有很多的基本命令,show命令也是其中之一,在很多使用者中对show命令的使用还容易产生混淆,本文汇集了show命令的众多用法. 1. show tables或show tables fr ...
- Elasticsearch基础教程
Reference: http://blog.csdn.net/cnweike/article/details/33736429 基础概念 Elasticsearch有几个核心概念.从一开始理解这些概 ...
- C#键盘事件处理(来源网上)
C#键盘事件处理 如果你希望用户按F1弹出chm帮助,代码如下: private void FrmMain_Load(object sender, EventArgs e) { this.KeyPre ...
- highcharts设置Y轴范围及根据Y轴范围设置不同颜色
yAxis : { title : { text : '数据' }, plotLines : [ { value : 0, width : 1, color : '#808080' } ], min: ...
- HBuilder mui引导页制作
http://www.bcty365.com/content-146-2582-1.html