test.php檔案的代碼如下:
情況1:
變數a的值是可控的,由參數input決定,
所以,當從瀏覽器訪問:http://127.0.0.1/test.php?input=start_%0a_end
的時候
查看網頁原始碼,結果如下:
//省略……//省略……
我們可以發現,情況1中,出現了換行,而情況2保持原樣。
為什麼會出現這種情況呢?
誰能幫忙詳細講解下其中的原理嗎?
說下我對此問題的看法:
當用戶端訪問網址(http://127.0.0.1/test.php?input=start_%0a_end)的時候,由於是php檔案,所以服務端會交個Apache伺服器解析執行,並把結果返回給服務端,服務端再將結果通過http響應返回給用戶端(瀏覽器),瀏覽器再將頁面渲染出來,呈現給使用者。
使用者--->瀏覽器--->伺服器--->apache
那麼,
換行到底是:
1.出現在Apache的解析執行的階段
2.還是瀏覽器將最終結果呈現給使用者這一階段
如果是出現在Apache的解析執行階段,那麼應該也會出現換行,但實際上並沒有
而如果換行是出現在:瀏覽器的渲染階段,那麼
應該也會出現換行才是,但實際上也沒有
回複內容:
test.php檔案的代碼如下:
情況1:
變數a的值是可控的,由參數input決定,
所以,當從瀏覽器訪問:http://127.0.0.1/test.php?input=start_%0a_end
的時候
查看網頁原始碼,結果如下:
//省略……//省略……
我們可以發現,情況1中,出現了換行,而情況2保持原樣。
為什麼會出現這種情況呢?
誰能幫忙詳細講解下其中的原理嗎?
說下我對此問題的看法:
當用戶端訪問網址(http://127.0.0.1/test.php?input=start_%0a_end)的時候,由於是php檔案,所以服務端會交個Apache伺服器解析執行,並把結果返回給服務端,服務端再將結果通過http響應返回給用戶端(瀏覽器),瀏覽器再將頁面渲染出來,呈現給使用者。
使用者--->瀏覽器--->伺服器--->apache
那麼,
換行到底是:
1.出現在Apache的解析執行的階段
2.還是瀏覽器將最終結果呈現給使用者這一階段
如果是出現在Apache的解析執行階段,那麼應該也會出現換行,但實際上並沒有
而如果換行是出現在:瀏覽器的渲染階段,那麼
應該也會出現換行才是,但實際上也沒有
接 @安堅實 的答案,query string由於地址欄顯示、日誌記錄、或者轉義等各方面的需要,必須將部分字元進行翻譯(比如無法顯示的字元、有特殊含義的控制字元等)
所以你在百度搜尋一個&符號的時候 訪問到的連結 實際是 http://www.baidu.com/s?wd=%26
因為這個字元與query string中的參數串連符衝突了,需要進行轉義
這個過程就是一個編碼的過程,這樣的編碼演算法最常見的就是 URLEncode 和 Base64Encode
而此處使用的是 URLEncode,這個是在 RFC 3986 中定義的
服務端收到了這個請求時,先原樣記錄在日誌中,然後將參數變成應用程式裡的字串 交給web應用處理
這個時候就需要進行一個解碼過程,否則得到的資料就與預期不一致了
接上面那個例子,我想搜尋的是 字串& 而不是 字串%26,因此需要解碼變回 &
再解釋LZ的例子,瀏覽器中訪問http://127.0.0.1/test.php?input=start_%0a_end時,
其實input這個參數的實際值 並不是 start_%0a_end 這個字串,只是因為地址欄無法顯示分行符號,將分行符號進行了轉義, 他的實際值就是start_[換行]_end,頁面輸出時,將他還原成了[換行]
如果你想要指定 input參數的實際值為 start_%0a_end, 需要將% 做一次轉義,變為 %25
嘗試訪問一下 http://127.0.0.1/test.php?input=start_%250a_end
解析過程其實是這樣的:
使用者 --> 瀏覽器 --> 伺服器 --> apache --> PHP解譯器
首先,start_%0a_end 被傳遞給PHP解譯器時,%0a 並沒有被轉換成換行。
var_dump($_SERVER['QUERY_STRING']); # string(19) "input=start_%0a_end"
但是,當它被寫入到 $_GET 全域數組裡時,就變成換行了
var_dump($_GET['input']); #string(11) "start_#_end"
因此,應該是PHP解譯器在把 query string 的值寫入 $_GET 裡時,進行了某些處理
至於為什麼進行這樣的處理,以及如何解決... 這個超出我的知識範圍了...
其實這裡只涉及到一個知識點,URIEncode,
URI內的字元在傳輸時會進行轉義,當處理常式收到資料時會進行反轉義;
%0a 的轉義過程大致如下(JS,PHP的過程 @安堅實 已解釋了部分):
// encodeencodeURIComponent('\n') // %0AencodeURIComponent('\n').toLowerCase() === '%0a' // true// decodedecodeURIComponent('%0a').charCodeAt(0) // 10'\n'.charCodeAt(0) // 10
關於 JS URI 編碼部分可見:
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html