PHP Conference Japan 2024

支援的協定與封裝器

PHP 內建許多用於各種 URL 式協定的封裝器,以便與檔案系統函式(例如 fopen()copy()file_exists()filesize())搭配使用。除了這些封裝器外,也可以使用 stream_wrapper_register() 函式註冊自訂封裝器。

注意 用於描述封裝器的 URL 語法僅支援 scheme://... 語法。scheme:/scheme: 語法不受支援。

目錄

新增筆記

使用者貢獻的筆記 31 筆筆記

24
fabacrans__ at __nospamhotmail__ dot __com
11 年前
您可以使用「php://input」來接收和解析「PUT」、「DELETE」等要求。

<?php
// 解析 "PUT" 要求的範例
parse_str(file_get_contents('php://input'), $_PUT);

// 結果
print_r($_PUT);
?>

(對於 Restful API 非常有用)
17
ben dot johansen at gmail dot com
18 年前
如何使用 php://input 取得原始 post 資料的範例

//讀取原始資料
$roughHTTPPOST = file_get_contents("php://input");
//將其解析為變數
parse_str($roughHTTPPOST);

如果您執行 readfile("php://input"),您將取得 post 資料的長度
13
aidan at php dot net
20 年前
常數

* STDIN
* STDOUT
* STDERR

在 PHP 4.3.0 中引入,與 fopen('php://stdx') 結果資源同義。
18
sander at medicore dot nl
17 年前
為了建立原始 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 來進行寫入。請注意,您完全繞過了網頁伺服器,因此某些變數將不可用。
13
ben dot johansen at gmail dot com
18 年前
在嘗試使用 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);
11
php at rapsys dot eu
12 年前
這是一個程式碼片段,用於在不啟用全域變數的情況下讀取壓縮的原始 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);
}
?>
10
sebastian dot krebs at kingcrunch dot de
13 年前
除非達到限制,否則資料流 php://temp/maxmemory:$limit 會將資料儲存在記憶體中。然後,它會將整個內容寫入暫存檔並釋放記憶體。我沒有找到任何方法可以至少將部分資料取回記憶體。
12
Hayley Watson
6 年前
即使它們的名稱相同,您也可以同時開啟多個 //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!]"。
?>
12
gjaman at gmail dot com
16 年前
您可以透過結合封裝器來解壓縮 (gzip) 輸入串流

例如:$x = file_get_contents("compress.zlib://php://input");

我使用此方法來解壓縮推送到我網頁伺服器的 gzip 串流
9
heitorsiller at uol dot com dot br
18 年前
對於讀取 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 訊息特別有用。
8
nargy at yahoo dot com
20 年前
當在附加模式下開啟 php://output 時會發生錯誤,正確的做法是
$fp=fopen("php://output","w");
fwrite($fp,"Hello, world !<BR>\n");
fclose($fp);
6
vibhavsinha91 at gmail dot com
10 年前
在寫入錯誤串流時,error_log() 函式是寫入 php://stderr 的簡寫。當透過如 Apache 之類的網頁伺服器執行時,此函式也允許寫入網頁伺服器記錄。
4
Anonymous
6 年前
請注意

file_get_contents 中使用的 file:// 協定會作為「任何無法識別的協定」的預設協定。因此

aldfjadlfadfladfl://whatever

將會與

file://whatever
7
Anonymous
7 年前
如果您想透過 php://input 過濾傳入的資料,請使用以下方法

file_get_contents("php://filter/read=string.strip_tags/resource=php://input");

我找不到任何文件說明如何執行此操作。我看到的所有範例都建議必須使用完整且實際的 URL(這對我不起作用)。

但這似乎有效。
6
Justin Megawarne
11 年前
如果我對實作程式碼的理解正確,每次您開啟 php://memory 串流時,都會配置新的儲存空間。也就是說,php://memory 不是共享的記憶體區塊。
7
sam at bigwig dot net
21 年前
[ 編輯註記:有一種方法可以知道。所有回應標頭(來自最終回應伺服器和中間重新導向器)都可以在 $http_response_header 或 stream_get_meta_data() 中找到,如上所述。 ]

如果您開啟一個 HTTP URL,並且伺服器發出 Location 樣式的重新導向,則會讀取重新導向的內容,但您無法得知這已發生。

因此,如果您隨後解析傳回的 HTML 並嘗試將相對 URL 合理化,您可能會出錯。
5
chris at free-source dot com
19 年前
如果您正在尋找基於 Unix 的 smb 封裝器,則沒有內建的封裝器,但我使用 http://www.zevils.com/cgi-bin/viewcvs.cgi/libsmbclient-php/(結尾處有 tarball 連結) 相當順利。
5
jerry at gii dot co dot jp
17 年前
不僅 STDIN、STDOUT 和 STDERR 僅允許用於 CLI 程式,它們也不允許用於從 STDIN 讀取的程式。如果您嘗試輸入一個簡單的測試程式,這可能會讓您感到困惑。
5
lupti at yahoo dot com
21 年前
我發現使用 file_get_contents 和 php://input 非常方便且有效率。這是程式碼

$request = "";
$request = file_get_contents("php://input");

我不需要將 URL 檔案字串宣告為 "r"。它會自動處理以讀取模式開啟檔案。

然後我可以將此 $request 字串作為資料用於您的 XML 解析器。
5
aaron dot mason+php at thats-too-much dot info
12 年前
請注意程式碼注入,各位 - 就像您從使用者取得的任何其他內容一樣,請先「消毒」。這點怎麼強調都不為過 - 如果我每次看到從表單輸入取得並直接使用的程式碼(我自己也是,我也曾愚蠢過)就有一美元,我可能早就擁有 PHP 了。雖然在 URL 封裝器中使用表單資料是自找麻煩,但您可以確保您的輸入是合理的,並且不太可能為世界上的 LulzSec 提供造成混亂的機會,從而大大減少麻煩。
5
leonid at shagabutdinov dot com
13 年前
對於 Windows 的 https,請啟用此擴充功能

extension=php_openssl.dll
4
nyvsld at gmail dot com
19 年前
php://stdin 支援 fseek() 和 fstat() 函式呼叫,
而 php://input 不支援。
4
ben dot johansen at gmail dot com
18 年前
後續

我發現如果我在 AJAX 呼叫中加入這行,值就會顯示在 $_POST 中

xhttp.setRequestHeader('Content-Type',
'application/x-www-form-urlencoded');
1
kazdotkanso at geeemail dot com
4 年前
php://fd/ 封裝器僅在 cli 工具中受支援。
3
oliver at codeinline dot com
10 年前
處理大型檔案上傳的一個有用的方法是執行類似以下的操作

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 資料中遺失邊界」的警告,但它似乎沒有問題地運作。
3
Anonymous
12 年前
對於 php://filter,/resource=foo 部分必須放在最後。而 foo 完全不需要逸出。
php://filter/resource=foo/read=somefilter 會嘗試開啟檔案 'foo/read=somefilter',而 php://filter/read=somefilter/resource=foo 將開啟檔案 'foo' 並套用 somefilter 過濾器。
3
dave at 4mation dot com dot au
11 年前
使用 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 (一個位元組,而不是一百萬位元組),它會立即開始寫入無限制的檔案串流,避免記憶體限制錯誤。
1
匿名
8 年前
請注意,STDIN 和類似的定義僅在 CLI 中有效。
1
ohcc at 163 dot com
9 年前
<?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;
?>
1
匿名
11 年前
在 PHP 5.4+ 中,如果將 enable_post_data_reading 設定為 Off,你可以透過 php://input 讀取 multipart 資料。

當然,如果你將它設定為關閉,則 $_POST 和 $_FILES 全域變數將完全不會被填充。現在完全由你來解析資料。
-2
nguyenanthuan at gmail dot com
10 年前
每個指向 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*。
To Top