2017-03-24 39 views
10

我從http傳遞給https,因此我必須將StreamContext添加到幾個read_fileget_file_contents調用中。何時StreamContext可重用?何時不應該重複使用?

我需要

$stream_context = stream_context_create([ 
    /* some lenghty options array */ 
]); 
read_file('https://'.$host.$uri, false, $stream_context); 

現在我的問題,以取代

read_file('http://'.$host.$uri); 

:是一個$ stream_context可重複使用的是這樣的:

$stream_context = stream_context_create([ 
    /* some lenghty options array */ 
]); 
read_file('https://'.$host.$uri, false, $stream_context); 
get_file_contents($another_url, false, $stream_context); 
read_file($even_another, false, $stream_context); 

或者我需要重新創建一個新的每個網址有StreamContext

以不同方式提出問題:流上下文只是參數和選項的描述符,還是在使用它時綁定到資源?

編輯:從評論看來,人們可以經常使用StreamContext,但並非總是如此。作爲答案,這並不令人滿意。

什麼時候可以或應該重用,何時不能重用?有人可以對StreamContext的內部工作有所瞭解。 documentation看起來相當稀疏。

+0

你可以試試看。我希望它是可重用的,因爲它是一種從未讀取但未寫入的資源。 – apokryfos

+1

我會說它的目的是可重複使用;但它似乎可能會有意想不到的結果(如果我沒有正確使用,我認爲)在這裏評論:http://php.net/manual/en/function.stream-context-create.php#117361 – ilpaijin

+0

@ilpaijin這一點很有趣。 –

回答

1

流上下文是可重複使用和它們總是可以重複使用,不經常。

來自@ilpaijin的評論指出「不可預知的行爲評論」很簡單,是對作者留下評論的誤解。

當您爲HTTP包裝器指定上下文時,無論您的目標模式如何,都將包裝器指定爲HTTP,這意味着不存在HTTPS包裝器這樣的事情。

如果試圖做到以下幾點:

"https" => [ 
// options will not be applied to HTTPS stream as there is no such wrapper (https) 
] 

正確的方法:

"http" => [ 
// options will apply to http:// and https:// streams. 
] 

當應/可以重新使用?

這真的取決於你,並且達到你正試圖實施的邏輯。

不要忘記,您已爲所有native PHP wrappers設置了默認上下文。

您發佈的例子中,您將相同的上下文流傳遞給3個不同的調用s是不必要的,只需使用stream_context_set_default併爲源自代碼的請求設置默認上下文。

有你設置的默認值,但對於一個特定的請求,你希望有不同的上下文某些情況下,這將是創建另一個數據流,並通過它的一個好主意。

是否流上下文包含狀態,例如cookies或tls初始協商是從一個呼叫傳遞到另一個呼叫?

流上下文不包含狀態,但是您可以使用附加代碼實現這種模擬。任何狀態,讓它成爲cookie或TLS握手,都只是請求標題。您需要從傳入的請求中讀取該信息並將其設置在流中,然後將該流傳遞給其他請求,從而嘲笑父請求的「狀態」。這是說 - 不要這樣做,只需使用CURL

一方面,溪流的真正力量正在創造自己的/定製的stream。使用CURL可以更輕鬆(更好地)實現標題操作和狀態控制。

+0

這是最好地闡述這個問題的問題。關於http://php.net/manual/en/function.stream-context-create.php#117361的批評,我認爲它忽略了一點:確實,「https」不是包裝名稱,「tls '和'ssl'(同義詞)是。 –

+0

我作爲輔助問題留下的是:流上下文是否包含狀態,例如cookie或tls初始協商是否從一個調用傳遞到另一個? –

+0

嗨洛倫茲,謝謝你的賞賜。我通過添加子問題和提示來編輯答案。 ;) – rock3t

1

看來你可以。我用xdebug_debug_zval跑一些簡單的測試,看看是否PHP在內部保留它(我用PHP 7.1.3 Xdebug的內部開發服務器上)

$context = stream_context_create(['https' => ['method' => 'GET']]); 
xdebug_debug_zval('context'); 
$stream = file_get_contents('https://secure.php.net/manual/en/function.file-get-contents.php', false, $context); 
xdebug_debug_zval('context'); 
$stream = fopen('https://secure.php.net/', 'r', false, $context); 
xdebug_debug_zval('context'); 

我什麼時候回來是

背景:

(引用計數= 1,is_ref = 0)的資源(2,流上下文)

上下文:

(引用計數= 1,is_ref = 0)的資源(2,流上下文)

上下文:

(引用計數= 2,is_ref = 0)的資源(2,流上下文)

有趣的是,第二次調用增加了refcount,這意味着它在內部通過引用傳遞。即使未設置$stream也沒有刪除它或阻止我再次調用它。

編輯

由於議題改性...

上下文創建resource數據類型。因爲它包含一個PHP數據實例,所以它通過引用隱含地通過,這意味着PHP直接傳遞內部數據而不是簡單地複製它。沒有原生的方式來銷燬上下文。

+0

感謝您的回答。雖然它嚴格回答了'是一個StreamContext可重用'的問題,但這不是我所期望的。事實上,有些情況下它不可重用,比如涉及到SSL連接(請參閱評論)。我想更好地理解什麼是概念上真正的StreamContext。如何把握它,而不是僅僅使用它。 –

+0

也許你應該分享'read_file'的代碼。我無法複製流上下文無法重用的情況。 PHP函數通過引用*傳遞它,所以它不應該被破壞 – Machavity

1

它顯然用作連接對象(相同邏輯像數據庫連接),並且可以以類似的方式被重用:

<?php 
$default_opts = array(
    'http'=>array(
    'method'=>"GET", 
    'header'=>"Accept-language: en\r\n" . 
       "Cookie: foo=bar", 
    'proxy'=>"tcp://10.54.1.39:8000" 
) 
); 


$alternate_opts = array(
    'http'=>array(
    'method'=>"POST", 
    'header'=>"Content-type: application/x-www-form-urlencoded\r\n" . 
       "Content-length: " . strlen("baz=bomb"), 
    'content'=>"baz=bomb" 
) 
); 

$default = stream_context_get_default($default_opts); 
$alternate = stream_context_create($alternate_opts); 

/* Sends a regular GET request to proxy server at 10.54.1.39 
* For www.example.com using context options specified in $default_opts 
*/ 
readfile('http://www.example.com'); 

/* Sends a POST request directly to www.example.com 
* Using context options specified in $alternate_opts 
*/ 
readfile('http://www.example.com', false, $alternate); 

?> 
+1

請注意,問題是使用'read_file'而不是'readfile'。這不是一個微不足道的差異 – Machavity

+0

是的確......其實我不知道什麼是read_file。我想說的是,上下文可能是自定義和默認的。並且默認情景可以在幕後多次使用。此外,上下文不需要關閉或回收。這意味着它們不會在請求之間收集任何狀態。 – DenisSt

-1

我同意上面的答案,stream_context_create()將通過獲取連接的選項參數來創建並返回資源句柄。這可以重新用於不同的資源,因爲它是一個句柄。無所謂,在哪裏使用,但需要在請求內處理。

相關問題