前言,在作某個渠道的過程當中,發現一個驗籤錯誤的問題。可是,當時驗簽在兩個地方表現不一致,同一套處理方法,想到了這是由於兩個地方請求方式是不一樣的一個get方法另一個天然是post方法。固然,出問題確定就是get。php
GET請求方式,因爲是將參數放在URL中,因此在進行傳遞的時候可能會受到瀏覽器端的一些策略問題,對參數進行urlencode處理。因此,當你在服務端拿到參數的時候可能並非原始的數據。所以,在經過GET方式請求拿到數據,若是不作任何處理的話去驗籤可能會存在問題。這邊的可能就是當base64處理以後不含+這個特殊的字符,+在GET方式以後不作任何處理拿到的就是一個空白字符串。程序員
POST請求方式,是將參數放在request body中,在進行http傳遞的過程當中不會存在因爲瀏覽器的一些策略問題對參數進行任何的處理。所以,經過POST請求進行參數驗籤的時候不會存在問題,可以很順利的進行驗籤。可是,咱們沒有辦法去要求渠道商將get請求變成post請求,所以咱們只能本身想辦法。算法
urlencode:瀏覽器
(PHP 4, PHP 5, PHP 7) urlencode — 編碼 URL 字符串 string urlencode ( string $str ) 此函數便於將字符串編碼並將其用於 URL 的請求部分,同時它還便於將變量傳遞給下一頁。 return 返回字符串,此字符串中除了 -_. 以外的全部非字母數字字符都將被替換成百分號(%)後跟兩位十六進制數,空格則編碼爲加號(+)。此編碼與 WWW 表單 POST 數據的編碼方式是同樣的,同時與 application/x-www-form-urlencoded 的媒體類型編碼方式同樣
urldecode:app
(PHP 4, PHP 5, PHP 7) urldecode — 解碼已編碼的 URL 字符串 string urldecode ( string $str ) 解碼給出的已編碼字符串中的任何 %##。 加號('+')被解碼成一個空格字符。 返回解碼後的字符串。
好像咱們看到了曙光,對+這個會變成空格的字符串的"完美處理方式"。那就是,對簽名字符串進行urlencode進行加密處理。而後,興高采烈的去驗證,fxxk,false。仍是不經過,而後甩本身一個耳光。base64加密以後會出現=這個補位字符串,很蛋疼。因而我就想了一個臨時處理方式。函數
urlencode(substr($str,0,strlen($sign)-2)).substr($sign,strlen($sign)-2)
當時,考慮到base64最多出現兩個==,因此在最後兩個不進行urlencode處理。這個基本上可以處理,可是可能存在一個問題,那就是在最後兩位出現+也是不行的,果真這個方案不能說服本身,推翻。而且在這個過程還發現一個問題就是,傳過來的簽名字符串還有可能會已經通過urlencode處理。這個仍是一個小問題,先進行urldecode處理,由於decode不會引發誤會。post
當時,小夥伴提出一個解決辦法,那就是直接替換+號不就能夠了嗎?的確,這是一個辦法。可是我認爲這個辦法很挫,若是之後加密算法改變了或者增長了其餘特殊字符呢,好比@#¥%……&**( 等這些,咱們不可能都去匹配替換什麼的。因此,我贊成臨時方案處理,可是我繼續想。編碼
rawurlencode:加密
(PHP 4, PHP 5, PHP 7) rawurlencode — 按照 RFC 3986 對 URL 進行編碼 string rawurlencode ( string $str ) 根據 » RFC 3986 編碼指定的字符。
rawurldecode:url
(PHP 4, PHP 5, PHP 7) rawurldecode — 對已編碼的 URL 字符串進行解碼 string rawurldecode ( string $str ) 返回字符串,此字符串中百分號(%)後跟兩位十六進制數的序列都將被替換成原義字符。
新的曙光出現了,理解rawurldecode,替換成原義字符。因此,解決方案呼之欲出了。
rawurldecode(urlencode(urldecode($sign))));
初看上去以爲還臃腫或者爲何要這麼繞來繞去處理呢?其實你還真得這麼處理,至於爲何,請看上上面的吹牛逼。
做爲程序員,咱們必需要有兩手準備,一手臨時方案,可以快速修復如今問題。在生產環境恢復正常,可是從長遠來看必需要可以一個穩定可靠的方案。方案來源於你不斷的嘗試和php.net。