常言道常在河邊走,哪能不濕鞋。作為天天寫php的老司機(jī),時(shí)不時(shí)就會(huì)被php的某個(gè)特性給坑一下。周末整理了三個(gè)自己或者身邊朋友碰到的最坑爹的case,分享給大家。
一、為啥接口偶爾會(huì)報(bào)簽名錯(cuò)誤呢?
做過接口開發(fā)的phper都知道,往往為了安全性,接口都會(huì)增加一個(gè)簽名字段,用來保證安全。但是,如果一個(gè)運(yùn)行良好的接口,就是有不那么高的概率報(bào)簽名錯(cuò)誤,到底是怎么回事呢?
這是我實(shí)際碰到的一個(gè)case,我們?cè)谡{(diào)用其它服務(wù)時(shí),有時(shí)會(huì)出現(xiàn)簽名錯(cuò)誤的錯(cuò)誤碼。這個(gè)事情很詭異。因?yàn)槲覀兊暮灻怯脗鬟f的參數(shù)加上秘鑰md5得到的,接收方也是一樣的方式來校驗(yàn)。我們算簽名是發(fā)送前的最后一步,算完簽名就扔給接收方了。如果簽名要是錯(cuò)了,那肯定就是算法錯(cuò)了??墒沁@種一會(huì)對(duì)一會(huì)錯(cuò)的,到底算個(gè)啥?
后來我們?cè)诎l(fā)送方和接收方都打了日志,好不容易又出現(xiàn)了這個(gè)case,趕緊拉出來分析。不看不知道,看了氣吐血??纯聪旅孢@個(gè)圖:


是的,你應(yīng)該猜到了。在我們發(fā)送方計(jì)算的時(shí)候,由于是使用字符串連接來做的加密串計(jì)算,所以會(huì)有x等于空字符串,y等于空字符串來參與計(jì)算簽名。而發(fā)給接收方的時(shí)候,經(jīng)過了一道http_build_query,接收方收到了一個(gè)為0的x,而且沒有收到y(tǒng)。簽名算出來自然不對(duì)了。
由于生成的參數(shù)值偶爾會(huì)有false或者null這種值,所以簽名會(huì)偶爾報(bào)錯(cuò)。我有理由相信,很多經(jīng)驗(yàn)豐富的老司機(jī),開到這里都會(huì)栽一下。如果不小心栽在某個(gè)重要接口上,真心是渾身有嘴都說不清。
二、奇怪了,不是有值嗎?怎么empty是true?
這個(gè)case是我朋友的,但是絲毫不影響我把它放在這篇分享坑爹case的文章里。首先看看下面的代碼及結(jié)果:


神奇吧?猜猜看,為啥?
好,可能你有個(gè)猜想,不過我們先看看class a的定義。

事實(shí)上,是因?yàn)閑mpty里面有個(gè)isset的判斷,自然class a沒有x這個(gè)屬性,所以empty就返回了true。在這個(gè)代碼里面,這個(gè)問題倒是很簡(jiǎn)單。可是實(shí)際開發(fā)中,很多框架或者自己的代碼都會(huì)使用__get,到時(shí)候判斷的時(shí)候,任你多少年的老司機(jī),稍微一不注意,車輪就進(jìn)來了。這種bug可是bool的顛倒,完全改變了后續(xù)的邏輯,想想就知道多恐怖。
三、咦?配置文件報(bào)錯(cuò)?
最后來個(gè)??永纤緳C(jī)的。老司機(jī)到了一定層次,會(huì)自己寫一些會(huì)手動(dòng)載入配置的代碼,比如下面這個(gè)db的示例。


很熟悉對(duì)不對(duì),粗看沒有問題對(duì)不對(duì)??墒悄惆l(fā)現(xiàn)這貨跑著跑著會(huì)報(bào)錯(cuò)。你去review也找不到問題點(diǎn)。var_dump加上exit吧,也沒啥問題。郁悶死了對(duì)不對(duì)。
這個(gè)示例代碼很短,而且明確的指出了可能出問題的地方,相信大家都找到了問題所在:第二次實(shí)例化DB的時(shí)候,載入的config是true,而不是數(shù)組。這是因?yàn)閞equire_once在第二次載入同一個(gè)文件的時(shí)候,就會(huì)直接返回true了。
對(duì)于這種第二次才犯病的bug,如果一開始不出現(xiàn),這個(gè)雷就潛伏了下來。而且這種代碼可能一般是很基礎(chǔ)的很底層的代碼,說不好某個(gè)時(shí)候你就寫了個(gè)正常的代碼,這雷就炸了,而且還炸在另一個(gè)毫無關(guān)聯(lián)的地方。
祝大家好好開車,爭(zhēng)做平平安安的好司機(jī)。