您可以使用「php://input」來接收和解析「PUT」、「DELETE」等要求。
<?php
// 解析 "PUT" 要求的範例
parse_str(file_get_contents('php://input'), $_PUT);
// 結果
print_r($_PUT);
?>
(對於 Restful API 非常有用)
PHP 內建許多用於各種 URL 式協定的封裝器,以便與檔案系統函式(例如 fopen()、copy()、file_exists() 和 filesize())搭配使用。除了這些封裝器外,也可以使用 stream_wrapper_register() 函式註冊自訂封裝器。
注意: 用於描述封裝器的 URL 語法僅支援
scheme://...
語法。scheme:/
和scheme:
語法不受支援。
您可以使用「php://input」來接收和解析「PUT」、「DELETE」等要求。
<?php
// 解析 "PUT" 要求的範例
parse_str(file_get_contents('php://input'), $_PUT);
// 結果
print_r($_PUT);
?>
(對於 Restful API 非常有用)
如何使用 php://input 取得原始 post 資料的範例
//讀取原始資料
$roughHTTPPOST = file_get_contents("php://input");
//將其解析為變數
parse_str($roughHTTPPOST);
如果您執行 readfile("php://input"),您將取得 post 資料的長度
為了建立原始 tcp 接聽系統,我使用以下方式
xinetd 精靈與如下組態
service test
{
disable = no
type = UNLISTED
socket_type = stream
protocol = tcp
bind = 127.0.0.1
port = 12345
wait = no
user = apache
group = apache
instances = 10
server = /usr/local/bin/php
server_args = -n [您的 php 檔案在此]
only_from = 127.0.0.1 #必須愛護安全性#
log_type = FILE /var/log/phperrors.log
log_on_success += DURATION
}
現在使用 fgets(STDIN) 來讀取輸入。建立連線非常快,而且運作良好。可以使用 STDOUT 或只是 echo 來進行寫入。請注意,您完全繞過了網頁伺服器,因此某些變數將不可用。
在嘗試使用 PHP 和 Javascript 執行 AJAX 時,我遇到一個問題,從以下 javascript 傳送的 POST 引數無法透過使用 $_REQUEST 或 $_POST 的 PHP 5 讀取。我最終弄清楚如何使用 php://input 指示詞讀取原始資料。
Javascript 程式碼
=============
//建立要求執行個體
xhttp = new XMLHttpRequest();
// 設定事件處理常式
xhttp.onreadystatechange = serviceReturn;
// 準備呼叫,http method=POST,true=非同步呼叫
var Args = 'number='+NbrValue;
xhttp.open("POST", "http://<?php echo $_SERVER['SERVER_NAME'] ?>/webservices/ws_service.php", true);
// 傳送帶有引數的呼叫
xhttp.send(Args);
PHP 程式碼
//讀取原始資料
$roughHTTPPOST = file_get_contents("php://input");
//將其解析為變數
parse_str($roughHTTPPOST);
這是一個程式碼片段,用於在不啟用全域變數的情況下讀取壓縮的原始 post 資料。
我需要它來讀取 ocs agent 提交的 xml post 資料。資料以 Content-Type:application/x-compressed(zlib 壓縮資料)傳送。
這似乎與一個仍有問題的舊錯誤有關
https://bugs.php.net/bug.php?id=49411
重要的部分是預設視窗設定為 15 而不是 -15。
程式碼片段
<?php
$data = '';
$fh = fopen('php://input', 'rb');
stream_filter_append($fh, 'zlib.inflate', STREAM_FILTER_READ, array('window'=>15));
while(!feof($fh)) {
$data .= fread($fh, 8192);
}
?>
除非達到限制,否則資料流 php://temp/maxmemory:$limit 會將資料儲存在記憶體中。然後,它會將整個內容寫入暫存檔並釋放記憶體。我沒有找到任何方法可以至少將部分資料取回記憶體。
即使它們的名稱相同,您也可以同時開啟多個 //memory 或 //temp 串流;每次您使用 fopen() 開啟這類串流時,都會開啟一個獨立於其他串流的「新」串流。
這點可以從您在建立這類串流時,沒有在路徑中加入任何唯一識別碼來推斷,但並沒有明確說明。
<?php
$hello = fopen('php://memory', 'r+'); // $hello、$php、$world 都是不同的串流。
$php = fopen('php://memory', 'r+');
$world = fopen('php://memory', 'r+'); // 它們不是同一個串流被開啟三次。
fputs($hello, "Hello ");
fputs($php, "PHP ");
rewind($php);
fputs($world, "World!");
rewind($hello);
rewind($world);
echo '[', stream_get_contents($hello), '][', stream_get_contents($php), '][', stream_get_contents($world), ']';
// 如果它們是同一個串流,輸出結果會是 "[World!][World!][World!]"。
?>
您可以透過結合封裝器來解壓縮 (gzip) 輸入串流
例如:$x = file_get_contents("compress.zlib://php://input");
我使用此方法來解壓縮推送到我網頁伺服器的 gzip 串流
對於讀取 XML 串流,這將運作良好
<?php
$arq = file_get_contents('php://input');
?>
然後您可以像這樣解析 XML
<?php
$xml = xml_parser_create();
xml_parse_into_struct($xml, $arq, $vs);
xml_parser_free($xml);
$data = "";
foreach($vs as $v){
if($v['level'] == 3 && $v['type'] == 'complete')
$data .= "\n".$v['tag']." -> ".$v['value'];
}
echo $data;
?>
附註:這對於接收來自手機公司的行動發起 (MO) SMS 訊息特別有用。
當在附加模式下開啟 php://output 時會發生錯誤,正確的做法是
$fp=fopen("php://output","w");
fwrite($fp,"Hello, world !<BR>\n");
fclose($fp);
在寫入錯誤串流時,error_log() 函式是寫入 php://stderr 的簡寫。當透過如 Apache 之類的網頁伺服器執行時,此函式也允許寫入網頁伺服器記錄。
請注意
file_get_contents 中使用的 file:// 協定會作為「任何無法識別的協定」的預設協定。因此
aldfjadlfadfladfl://whatever
將會與
file://whatever
如果您想透過 php://input 過濾傳入的資料,請使用以下方法
file_get_contents("php://filter/read=string.strip_tags/resource=php://input");
我找不到任何文件說明如何執行此操作。我看到的所有範例都建議必須使用完整且實際的 URL(這對我不起作用)。
但這似乎有效。
如果我對實作程式碼的理解正確,每次您開啟 php://memory 串流時,都會配置新的儲存空間。也就是說,php://memory 不是共享的記憶體區塊。
[ 編輯註記:有一種方法可以知道。所有回應標頭(來自最終回應伺服器和中間重新導向器)都可以在 $http_response_header 或 stream_get_meta_data() 中找到,如上所述。 ]
如果您開啟一個 HTTP URL,並且伺服器發出 Location 樣式的重新導向,則會讀取重新導向的內容,但您無法得知這已發生。
因此,如果您隨後解析傳回的 HTML 並嘗試將相對 URL 合理化,您可能會出錯。
如果您正在尋找基於 Unix 的 smb 封裝器,則沒有內建的封裝器,但我使用 http://www.zevils.com/cgi-bin/viewcvs.cgi/libsmbclient-php/(結尾處有 tarball 連結) 相當順利。
不僅 STDIN、STDOUT 和 STDERR 僅允許用於 CLI 程式,它們也不允許用於從 STDIN 讀取的程式。如果您嘗試輸入一個簡單的測試程式,這可能會讓您感到困惑。
我發現使用 file_get_contents 和 php://input 非常方便且有效率。這是程式碼
$request = "";
$request = file_get_contents("php://input");
我不需要將 URL 檔案字串宣告為 "r"。它會自動處理以讀取模式開啟檔案。
然後我可以將此 $request 字串作為資料用於您的 XML 解析器。
請注意程式碼注入,各位 - 就像您從使用者取得的任何其他內容一樣,請先「消毒」。這點怎麼強調都不為過 - 如果我每次看到從表單輸入取得並直接使用的程式碼(我自己也是,我也曾愚蠢過)就有一美元,我可能早就擁有 PHP 了。雖然在 URL 封裝器中使用表單資料是自找麻煩,但您可以確保您的輸入是合理的,並且不太可能為世界上的 LulzSec 提供造成混亂的機會,從而大大減少麻煩。
後續
我發現如果我在 AJAX 呼叫中加入這行,值就會顯示在 $_POST 中
xhttp.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
處理大型檔案上傳的一個有用的方法是執行類似以下的操作
copy(("php://input"),$tmpfile);
因為這樣可以避免僅為了緩衝檔案內容而使用大量記憶體。
此操作的正確 MIME 類型應為 "application/octet-stream",但是如果您在 POST 中設定此類型或任何其他識別的 MIME 類型(而不是 "multipart/form-data"),則 $HTTP_RAW_POST_DATA 會被填入,並且記憶體仍然會被消耗。
將 MIME 類型設定為 "multipart/form-data" 會引發「PHP 警告:在未知的 multipart/form-data POST 資料中遺失邊界」的警告,但它似乎沒有問題地運作。
對於 php://filter,/resource=foo 部分必須放在最後。而 foo 完全不需要逸出。
php://filter/resource=foo/read=somefilter 會嘗試開啟檔案 'foo/read=somefilter',而 php://filter/read=somefilter/resource=foo 將開啟檔案 'foo' 並套用 somefilter 過濾器。
使用 php://temp/maxmemory 作為串流會計入指令碼的記憶體使用量;您並非透過使用這類串流來指定新的記憶體池。
但是,如文件中所述,此串流類型在超出指定的 maxmemory 限制後將開始寫入檔案。此檔案緩衝區不受記憶體限制的限制。
如果您希望您的指令碼具有合理的記憶體限制(例如 32MB),但仍能夠在串流中處理大量資料(例如 256MB),這非常方便。
這只有在使用像 fputs() 這樣的串流函數時才有效;如果你使用 $buffer .= 'string'; 或 $buffer = $buffer . 'string';,你會將串流資料讀回 PHP,這會觸發記憶體限制。
一個實例範例:
<?php
// 0.5MB 記憶體限制
ini_set('memory_limit', '0.5M');
// 2MB 串流限制
$buffer = fopen('php://temp/maxmemory:1048576', 'r+');
$x = 0;
// 嘗試寫入 1MB 到串流
while ($x < 1*1024*1024) {
fputs($buffer, 'a');
$x++;
}
echo "這永遠不會被顯示";
?>
然而,將 fopen 修改為使用 php://temp/maxmemory:1 (一個位元組,而不是一百萬位元組),它會立即開始寫入無限制的檔案串流,避免記憶體限制錯誤。
<?php
//在必要時啟用 $HTTP_RAW_POST_DATA
ini_set('always_populate_raw_post_data',-1);
$HTTP_RAW_POST_DATA = file_get_contents('php://input');
echo $HTTP_RAW_POST_DATA;
?>
在 PHP 5.4+ 中,如果將 enable_post_data_reading 設定為 Off,你可以透過 php://input 讀取 multipart 資料。
當然,如果你將它設定為關閉,則 $_POST 和 $_FILES 全域變數將完全不會被填充。現在完全由你來解析資料。
每個指向 php://memory 和 php://temp 的串流指標都有自己的記憶體分配,因此你可以開啟許多串流指標來儲存你個別的值。
<?php
$fp = fopen("php://temp", "r+");
$fp2 = fopen("php://temp", "r+");
fwrite($fp, "line1\n");
fwrite($fp2, "line4\n");
fwrite($fp, "line2\n");
fwrite($fp2, "line5\n");
fwrite($fp, "line3\n");
fwrite($fp2, "line6\n");
var_dump(memory_get_usage());
rewind($fp);
while(!feof($fp)) {
var_dump(fread($fp, 1024));
}
fclose($fp);
var_dump(memory_get_usage());
rewind($fp2);
while(!feof($fp2)) {
var_dump(fread($fp2, 1024));
}
fclose($fp2);
var_dump(memory_get_usage());
?>
關閉他們的串流處理也會釋放已分配的記憶體。
php://memory 串流類型為 MEMORY,而 php://temp 串流類型為 STDIO FILE*。