一、小數(符點數)不能直接比較是否相等
例如 if( 0.5+0.2==0.7 ) 的結果是 false。究其原因是因為,PHP是基於C語言的,而C語言由於其二進位符點數的表示方式,導致不能精確表示大多數符點數。事實上,幾乎所有的程式語言都沒能精確表示小數(符點數),這是一個普遍存在的現象,因為這個是 IEEE 754 的缺陷。想要解決這個問題,只能另立標準,似乎只有Mathematica解決了這個問題。
為什麼呢?因為這個比較是弱型,兩個比較時,PHP會先試著判別左右兩者是否為數字。而問題就在於什麼樣的字串是數字,是單純的數字字串嗎?遠遠不只如此,還包括 0x 開頭的十六進制,XXeX類型的科學記數法 等等,如 '12e0'=='0x0C' 得到的是true。而在數值類型與字串比較時,甚至一些數字開頭的非數值串,例如 12=='12這個串' 得到的值也會是 true。
所以這些情況下,可能會使本來並不相同的字串被判定為相等。而使用===比較則為包含類型的比較,不會有任何轉換,所以是可以準確比較字串是否相同的。
另外吐槽一下JAVA,==居然比較不了字串是否相等,因為字串是一個對象,==變成了判斷是否為同一個對象…
trim函數的基本用法是去除最外邊的空格、換行符之類的。因為其可選參數,許多人也會將其用於去除UTF8BOM頭、檔案副檔名等等,例如 ltrim($str, "xEFxBBxBF"); rtrim($str, "str .txt"); 。但很快,就會發現這些函數會多去除了一些東西,例如本來是想去除後綴的,結果 logtext.txt 會變成了 logte 而不是 logtext。為什麼呢?因為後面這個參數的意思不是一個完整字串,而是字元列表
,也就是說會一直檢查最左/最右是否符合此列表的其中一個。那怎麼樣才是真正我們想要的去掉最前面最後呢?網路上的說法是說用正規表示式,我封裝了對應的三個方法,以便使用。命名規則是比原來PHP的函數多了個s,表示string的意思。用法跟原來PHP的函數一樣。
ltrims(, = ( ("/^{}/", '', rtrims(, = ( ("/{}$/", '', trims(, = ( = ("/^{}/", '', ("/{}$/", '', trimBOM( ("/^\xEF\xBB\xBF/", '',
網路上流行一段取得客戶端IP位址的PHP函數如下:
这函数看起来并没有什么问题,很多开源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($someArr as $someL){ } 之类的用法时,要注意最后的一个 $someL 会一直保留到该函数/方法结束。而当使用引用的时候 foreach($someArr as &$someL){ }这是以引用来保存,也就是说后面若有使用同一个名字的变量名,将会把原数据改变(就像一个乱用的C指针)。为安全起见,建议每个foreach(尤其是引用的)结束之后都使用unset把这些变量清除掉。
foreach($someArr as &$someL){ //doSomething ...}unset($someL);
不少网站都是使用此函数作为通用的输入过滤函数,但是此函数默认情况是不过滤单引号的。这是非常非常地容易造成XSS漏洞。这样的做法和不过滤双引号没太大区别,只要前端写得稍微有点不规范(用了单引号)就会中招。下面这个示例改编自知乎梧桐雨的回答4110a9844baef9d25a82ccef3094ed14
' />
要求所有的时候都使用双引号不得使用单引号,这其实不太现实。所以,这个主要还是后端的责任,把单引号也要转义,我们用的时候一定要给这个函数加上参数 htmlspecialchars( $data, ENT_QUOTES);
很多人向Thinkphp框架提出过这个问题,因为其默认过滤方法就是无参数的htmlspecialchars,不过滤单引号,而其官方答复是“I函数的作用不能等同于防止SQL注入,可以自定义函数来过滤”……毛线啊,最基本的防护都不给力,这是给埋了多少隐患啊。在此强烈各位使用者重新定义默认过滤函数,我自己定义的是 htmlspecialchars(trim($data), ENT_QUOTES); ,有更好建议欢迎评论。同时非常希望TP官方更正此问题。
关于XSS,容我多说两句,请看下面这个例子。
<span style="color:#ff00ff;"><?</span><span style="color:#ff00ff;"><span style="color:#000000;"><span style="color:#ff00ff;">php</span> $name='alert(1)';</span> </span><span style="color:#ff00ff;">?></span><span style="color:#0000ff;"><</span><span style="color:#800000;">p </span><span style="color:#ff0000;">id</span><span style="color:#0000ff;">="XSS2"</span><span style="color:#0000ff;">></</span><span style="color:#800000;">p</span><span style="color:#0000ff;">></span><span style="color:#0000ff;"><</span><span style="color:#800000;">script </span><span style="color:#ff0000;">src</span><span style="color:#0000ff;">="//cdn.batsing.com/jquery.js"</span><span style="color:#0000ff;">></</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span><span style="color:#0000ff;"><</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span><span style="background-color:#f5f5f5;color:#000000;">$(</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">#XSS2</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">)[</span><span style="background-color:#f5f5f5;color:#000000;">0</span><span style="background-color:#f5f5f5;color:#000000;">].innerHTML </span><span style="background-color:#f5f5f5;color:#000000;">=</span> <span style="background-color:#f5f5f5;color:#000000;"><?=</span><span style="background-color:#f5f5f5;color:#000000;">$name</span><span style="background-color:#f5f5f5;color:#000000;">?></span><span style="background-color:#f5f5f5;color:#000000;">; $("#XSS2").html( <?=$name?> ); $(</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">#XSS2</span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">)[</span><span style="background-color:#f5f5f5;color:#000000;">0</span><span style="background-color:#f5f5f5;color:#000000;">].innerHTML </span><span style="background-color:#f5f5f5;color:#000000;">=</span> <span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;"><?=$name?></span><span style="background-color:#f5f5f5;color:#000000;">"</span><span style="background-color:#f5f5f5;color:#000000;">; $("#XSS2").html(" <?=$name?> ");</span><span style="color:#0000ff;"></</span><span style="color:#800000;">script</span><span style="color:#0000ff;">></span>
其中第1、2行 JS會造成 XSS 漏洞,第3、4行則不會。而 alert(1) 這樣一種字串,後端甚至沒有什麼比較好的方法可以過濾,唯一有效的方法可能是在資料的兩端加上引號。主要責任還是在於前端,對innerHTML 和jQuery的html() 的輸出使用時,一定要確保傳入的參數是字符串,否則其危險性不亞於亞eval 函數