PHP Conference Japan 2024

curl_setopt

(PHP 4 >= 4.0.2, PHP 5, PHP 7, PHP 8)

curl_setopt為 cURL 傳輸設定選項

描述

curl_setopt(CurlHandle $handle, int $option, mixed $value): bool

在給定的 cURL 會話控制代碼上設定選項。

參數

handle

curl_init() 返回的 cURL 控制代碼。

option

要設定的 CURLOPT_* 選項。

value

要在 option 上設定的值。請參閱 CURLOPT_* 常數的描述,以瞭解每個常數預期的值類型。

傳回值

成功時返回 true,失敗時返回 false

變更日誌

版本 描述
8.4.0 CURLOPT_DNS_USE_GLOBAL_CACHE 不再有任何作用,在執行緒安全的 PHP 建置版本上啟用它也不再觸發警告。
8.0.0 handle 現在預期一個 CurlHandle 實例;先前預期的是 資源
7.3.15, 7.4.3 引入 CURLOPT_HTTP09_ALLOWED
7.3.0 引入 CURLOPT_ABSTRACT_UNIX_SOCKETCURLOPT_KEEP_SENDING_ON_ERRORCURLOPT_PRE_PROXYCURLOPT_PROXY_CAINFOCURLOPT_PROXY_CAPATHCURLOPT_PROXY_CRLFILECURLOPT_PROXY_KEYPASSWDCURLOPT_PROXY_PINNEDPUBLICKEYCURLOPT_PROXY_SSLCERTCURLOPT_PROXY_SSLCERTTYPECURLOPT_PROXY_SSL_CIPHER_LISTCURLOPT_PROXY_SSLKEYCURLOPT_PROXY_SSLKEYTYPECURLOPT_PROXY_SSL_OPTIONSCURLOPT_PROXY_SSL_VERIFYHOSTCURLOPT_PROXY_SSL_VERIFYPEERCURLOPT_PROXY_SSLVERSIONCURLOPT_PROXY_TLSAUTH_PASSWORDCURLOPT_PROXY_TLSAUTH_TYPECURLOPT_PROXY_TLSAUTH_USERNAMECURLOPT_SOCKS5_AUTHCURLOPT_SUPPRESS_CONNECT_HEADERSCURLOPT_DISALLOW_USERNAME_IN_URLCURLOPT_DNS_SHUFFLE_ADDRESSESCURLOPT_HAPPY_EYEBALLS_TIMEOUT_MSCURLOPT_HAPROXYPROTOCOLCURLOPT_PROXY_TLS13_CIPHERSCURLOPT_SSH_COMPRESSIONCURLOPT_TIMEVALUE_LARGECURLOPT_TLS13_CIPHERS
7.0.7 引入 CURL_HTTP_VERSION_2CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGECURL_HTTP_VERSION_2TLSCURL_REDIR_POST_301CURL_REDIR_POST_302CURL_REDIR_POST_303CURL_REDIR_POST_ALLCURL_VERSION_KERBEROS5CURL_VERSION_PSLCURL_VERSION_UNIX_SOCKETSCURLAUTH_NEGOTIATECURLAUTH_NTLM_WBCURLFTP_CREATE_DIRCURLFTP_CREATE_DIR_NONECURLFTP_CREATE_DIR_RETRYCURLHEADER_SEPARATECURLHEADER_UNIFIEDCURLMOPT_CHUNK_LENGTH_PENALTY_SIZECURLMOPT_CONTENT_LENGTH_PENALTY_SIZECURLMOPT_MAX_HOST_CONNECTIONSCURLMOPT_MAX_PIPELINE_LENGTHCURLMOPT_MAX_TOTAL_CONNECTIONSCURLOPT_CONNECT_TOCURLOPT_DEFAULT_PROTOCOLCURLOPT_DNS_INTERFACECURLOPT_DNS_LOCAL_IP4CURLOPT_DNS_LOCAL_IP6CURLOPT_EXPECT_100_TIMEOUT_MSCURLOPT_HEADEROPTCURLOPT_LOGIN_OPTIONSCURLOPT_PATH_AS_ISCURLOPT_PINNEDPUBLICKEYCURLOPT_PIPEWAITCURLOPT_PROXY_SERVICE_NAMECURLOPT_PROXYHEADERCURLOPT_SASL_IRCURLOPT_SERVICE_NAMECURLOPT_SSL_ENABLE_ALPNCURLOPT_SSL_ENABLE_NPNCURLOPT_SSL_FALSESTARTCURLOPT_SSL_VERIFYSTATUSCURLOPT_STREAM_WEIGHTCURLOPT_TCP_FASTOPENCURLOPT_TFTP_NO_OPTIONSCURLOPT_UNIX_SOCKET_PATHCURLOPT_XOAUTH2_BEARERCURLPROTO_SMBCURLPROTO_SMBSCURLPROXY_HTTP_1_0CURLSSH_AUTH_AGENTCURLSSLOPT_NO_REVOKE

範例

範例 1:初始化新的 cURL 會話並擷取網頁

<?php
// 建立新的 cURL 資源
$ch = curl_init();

// 設定 URL 和其他適當選項
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
curl_setopt($ch, CURLOPT_HEADER, false);

// 抓取 URL 並將其傳遞給瀏覽器
curl_exec($ch);

// 關閉 cURL 資源並釋放系統資源
curl_close($ch);
?>

註釋

註釋:

將陣列傳遞給 CURLOPT_POSTFIELDS 會將資料編碼為 multipart/form-data,而傳遞 URL 編碼的字串會將資料編碼為 application/x-www-form-urlencoded

參見

新增註解

使用者貢獻的註解 64 條註解

rmckay at webaware dot com dot au
12 年前
請各位停止將 CURLOPT_SSL_VERIFYPEER 設定為 false 或 0。如果您的 PHP 安裝沒有最新的 CA 根憑證套件,請從 curl 網站下載並儲存在您的伺服器上

http://curl.haxx.se/docs/caextract.html

然後在您的 php.ini 檔案中設定路徑,例如在 Windows 上

curl.cainfo=c:\php\cacert.pem

關閉 CURLOPT_SSL_VERIFYPEER 允許中間人(MITM)攻擊,這是您不希望發生的!
joey
8 年前
重要的是,任何使用 cURL 和 PHP 的人都必須記住,並非所有 CURLOPT 和 CURLINFO 常數都有文件記錄。我總是建議直接閱讀 cURL 文件,因為它有時包含更好的資訊。cURL API 也傾向於很混亂,所以不要期望事情會在你通常會邏輯地尋找它們的地方。

當涉及到 cookie 時,curl 特別難以使用。因此,我將談談我在 PHP 5.6 和 curl 7.26 中發現的內容。

如果您想在不使用檔案的情況下管理記憶體中的 cookie,包括讀取、寫入和清除自訂 cookie,請繼續閱讀。

首先,要啟用與 cURL 控制代碼相關的僅限記憶體的 cookie,您應該使用

curl_setopt($curl, CURLOPT_COOKIEFILE, "");

cURL 喜歡在選項中使用魔術字串作為特殊命令。它沒有提供一個選項來啟用記憶體中的 cookie 引擎,而是使用魔術字串來做到這一點。儘管這裡的文件略有提及,但像我這樣的大多數人甚至不會讀到,因為 COOKIEFILE 與我們想要的完全相反。

要取得 curl 控制代碼的 cookie,您可以使用

curl_getinfo($curl, CURLINFO_COOKIELIST);

這將產生一個陣列,其中包含每個 cookie 的字串。它是以 tab 分隔的,不幸的是,如果您想做除了複製 cookie 之外的任何事情,您必須自己解析它。

要清除 cURL 控制代碼的記憶體中 cookie,您可以使用

curl_setopt($curl, CURLOPT_COOKIELIST, "ALL");

這是一個魔術字串。cURL 文件中還有其他魔術字串。如果沒有使用魔術字串,此欄位應採用與 cookielist 常數的 getinfo 中相同的字串格式的 cookie。這可以用於刪除單獨的 cookie,雖然它不是最優雅的 API。

對於複製 cookie,我建議使用 curl_share_init。

您也可以像這樣將 cookie 從一個控制代碼複製到另一個控制代碼

foreach(curl_getinfo($curl_a, CURLINFO_COOKIELIST) as $cookie_line)
curl_setopt($curl, CURLOPT_COOKIELIST, $cookie_line);

一種不優雅的刪除 cookie 的方法是跳過您不想要的 cookie。

我只建議將 COOKIELIST 與魔術字串一起使用,因為 cookie 格式不安全或穩定。您可以將 tab 注入到至少路徑和名稱中,使其無法可靠地解析。如果您必須解析它,那麼為了保持其安全性,我建議禁止內容中超過 6 個 tab,這對大多數人來說可能不是很大的損失。

我建議至少進行以下驗證

/^([^\t]+\t){5}[^\t]+$/D

以下是格式

#define SEP "\t" /* Tab 分隔欄位 */

char *my_cookie =
"example.com" /* 主機名稱 */
SEP "FALSE" /* 包含子網域 */
SEP "/" /* 路徑 */
SEP "FALSE" /* 安全 */
SEP "0" /* 以 epoch 時間格式表示的到期時間。0 == 會話 */
SEP "foo" /* 名稱 */
SEP "bar"; /* 值 */
ashw1 - at - no spam - post - dot - cz
17 年前
如果您想知道為什麼 cookie 在 Windows 下無法運作,我已經在 Google 上搜尋了一些答案,結果如下:在 WIN 下,您需要輸入 cookie 檔案的絕對路徑。

這段程式碼可以解決這個問題

<?php

if ($cookies != '')
{
if (
substr(PHP_OS, 0, 3) == 'WIN')
{
$cookies = str_replace('\\','/', getcwd().'/'.$cookies);}
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookies);
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookies);
}

?>
Steve Kamerman
13 年前
如果您希望 cURL 在不到一秒的時間內逾時,您可以使用 CURLOPT_TIMEOUT_MS,雖然在「類 Unix 系統」上存在一個錯誤/「功能」,如果該值 < 1000 毫秒,會導致 libcurl 立即逾時並顯示錯誤「cURL Error (28): Timeout was reached」。此行為的解釋是

「如果 libcurl 是建置為使用標準系統名稱解析器,則傳輸的該部分仍然會使用整秒解析來進行逾時,允許的最小逾時時間為一秒。」

這對 PHP 開發人員的意義是「您可以使用此函數而無需先測試它,因為您無法判斷 libcurl 是否正在使用標準系統名稱解析器(但您可以相當肯定它正在使用)」

問題在於,在 (Li|U)nix 上,當 libcurl 使用標準名稱解析器時,名稱解析期間會引發 SIGALRM,libcurl 會將其視為逾時警報。

解決方案是使用 CURLOPT_NOSIGNAL 停用訊號。以下是一個範例腳本,該腳本會請求自身導致 10 秒延遲,以便您可以測試逾時

<?php
if (!isset($_GET['foo'])) {
// 客戶端
$ch = curl_init('https://127.0.0.1/test/test_timeout.php?foo=bar');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 200);
$data = curl_exec($ch);
$curl_errno = curl_errno($ch);
$curl_error = curl_error($ch);
curl_close($ch);

if (
$curl_errno > 0) {
echo
"cURL Error ($curl_errno): $curl_error\n";
} else {
echo
"Data received: $data\n";
}
} else {
// 伺服器
sleep(10);
echo
"Done.";
}
?>
qwertz182
4 年前
由於「範例 #2 上傳檔案」表示自 PHP 5.5.0 起已棄用,但沒有告訴您如何正確執行,
以下是一個使用 CURLFile 類別的非常簡單的範例

<?php
$request
= [
'firstName' => 'John',
'lastName' => 'Doe',
'file' => new CURLFile('example.txt', 'text/plain') // 或使用 curl_file_create()
];

$curlOptions = [
CURLOPT_URL => 'http://example.com/upload.php',
CURLOPT_POST => true,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POSTFIELDS => $request,
];

$ch = curl_init();
curl_setopt_array($ch, $curlOptions);

$response = curl_exec($ch);
?>

這就像發布一個具有 input[type=file] 欄位的 html 表單。
在 Windows 上的結果可能如下所示

<?php
// $_POST
Array
(
[
firstName] => John
[lastName] => Doe
)

// $_FILES
Array
(
[
file] => Array
(
[
name] => example.txt
[type] => text/plain
[tmp_name] => C:\wamp64\tmp\php3016.tmp
[error] => 0
[size] => 14
)

)
?>

由於請求是一個陣列(而不是字串),curl 會自動將資料編碼為 "multipart/form-data"。
請注意,如果您將無效的檔案路徑傳遞給 CURLFile,設定 CURLOPT_POSTFIELDS 選項將會失敗。
因此,如果您使用 curl_setopt_array 一次設定多個選項,根據手冊,「如果一個選項無法成功設定,將會立即傳回 FALSE,並忽略選項陣列中任何後續的選項。」。
因此,您應該確保檔案存在,或使用 curl_setopt() 設定 CURLOPT_POSTFIELDS 並檢查是否傳回 false,然後採取相應的行動。
Philippe dot Jausions at 11abacus dot com
18 年前
關於回呼方法的澄清

- CURLOPT_HEADERFUNCTION 用於處理*在回應中*收到的標頭行,
- CURLOPT_WRITEFUNCTION 用於處理*從回應中*接收的資料,
- CURLOPT_READFUNCTION 用於處理*在請求中*傳遞的資料。

回呼「字串」可以是任何可呼叫的函式,包括 array(&$obj, 'someMethodName') 格式。

-Philippe
JScott jscott401 at gmail dot com
14 年前
關於 curlopt_writefunction 的一些額外注意事項。我一開始為此掙扎了很久,因為它真的沒有被很好地記錄下來。

當您編寫一個回呼函式並將其與 curlopt_writefunction 一起使用時,它將會被呼叫*多次*。您的函式每次都*必須*傳回寫入其中的資料量。它對此非常挑剔。以下是我程式碼中的一個片段,可能會對您有所幫助

<?php
curl_setopt
($this->curl_handle, CURLOPT_WRITEFUNCTION, array($this, "receiveResponse"));

// 後續在類別中我編寫了 receiveResponse 方法

private function receiveResponse($curlHandle,$xmldata)
{
$this->responseString = $xmldata;
$this->responseXML .= $this->responseString;
$this->length = strlen($xmldata);
$this->size += $this->length;
return
$this->length;

}
?>

現在我為一個類別做了這個。如果您沒有使用 OOP,那麼您顯然需要修改此程式碼以供您自己使用。

CURL 會*多次*呼叫您的腳本,因為資料不會總是全部一次傳送。我們這裡談論的是網際網路,因此它會被分成許多封包。您需要將您的資料全部串連在一起,直到全部寫入。我幾乎要抓狂了,因為我會從伺服器收到破碎的 XML 區塊,而且長度隨機。我終於弄清楚了發生了什麼事。希望這對您有所幫助
cmatiasvillanueva at gmail dot com
7 年前
文件中沒有提到的是,如果您想要設定一個本機連接埠或本機連接埠範圍來建立連線,可以透過加入 CURLOPT_LOCALPORT 和 CURLOPT_LOCALPORTRANGE 選項來實現。

例如
$conn=curl_init ('example.com');
curl_setopt($conn, CURLOPT_LOCALPORT, 35000);
curl_setopt($conn, CURLOPT_LOCALPORTRANGE, 200);

CURLOPT_LOCALPORT:此選項設定用於連線的 Socket 的本機連接埠號碼。

CURLOPT_LOCALPORTRANGE:range 引數是 libcurl 嘗試尋找可用的本機連接埠號碼的次數。它會從給定的 CURLOPT_LOCALPORT 開始,每次重試都會將數字加一。將此選項設定為 1 或更低會使 libcurl 只嘗試一次精確的連接埠號碼。

介面也可以使用 CURLOPT_INTERFACE 進行設定

例如

curl_setopt($conn, CURLOPT_INTERFACE, "eth1");
sgamon at yahoo dot com
16 年前
如果您正在執行 POST,且內容長度大於或等於 1,025,則 curl 會利用 http 1.1 的一個功能:100 (繼續) 狀態。

請參閱 http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3

* 它會加入一個標頭,「Expect: 100-continue」。
* 然後它會傳送請求頭,等待 100 回應代碼,然後傳送內容

但並非所有網路伺服器都支援此功能。根據伺服器而異,會傳回各種錯誤。如果您遇到這種情況,請使用以下命令抑制「Expect」標頭

<?php
curl_setopt
($ch, CURLOPT_HTTPHEADER, array('Expect:'));
?>

請參閱 http://www.gnegg.ch/2007/02/the-return-of-except-100-continue/
mw+php dot net at lw-systems dot de
12 年前
CURLOPT_POSTFIELDS 選項的使用描述應強調,使用 HTTP/1.1 和 cURL 進行 POST 時,會隱含使用「Expect: 100-continue」標頭。某些網路伺服器將無法理解 POST 資料分塊傳輸的處理。

若要停用此行為,必須使用以下程式碼停用「Expect:」標頭:

curl_setopt($ch, CURLOPT_HTTPHEADER,array("Expect:"));
Ed Cradock
14 年前
PUT 請求非常簡單,只需確保指定 content-length 標頭,並將 post 欄位設定為字串。

範例

<?php
function doPut($url, $fields)
{
$fields = (is_array($fields)) ? http_build_query($fields) : $fields;

if(
$ch = curl_init($url))
{
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Length: ' . strlen($fields)));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_exec($ch);

$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

return (int)
$status;
}
else
{
return
false;
}
}

if(
doPut('http://example.com/api/a/b/c', array('foo' => 'bar')) == 200)
// 做一些事情
else
// 做其他事情。
?>

您可以使用以下程式碼在另一端抓取請求資料

<?php
if($_SERVER['REQUEST_METHOD'] == 'PUT')
{
parse_str(file_get_contents('php://input'), $requestData);

// 陣列 ( [foo] => bar )
print_r($requestData);

// 使用資料做一些事情...
}
?>

DELETE 可以以完全相同的方式完成。
Victor Jerlin
15 年前
似乎此頁面上沒有提及某些選項,但在 http://curl.haxx.se/libcurl/c/curl_easy_setopt.html 上列出的選項實際上是支援的。

我很高興看到我甚至可以從 PHP 使用 CURLOPT_FTP_CREATE_MISSING_DIRS。
dweingart at pobox dot com
21 年前
如果您希望 Curl 跟隨重新導向,並且您還希望 Curl 回應在此過程中設定的任何 Cookie,請使用此程式碼

<?php curl_setopt($ch, CURLOPT_COOKIEJAR, '-'); ?>

「-」表示標準輸出

-dw
yann dot corno at free dot fr
22 年前
關於 CURLOPT_HTTPHEADER 選項,我花了一些時間才弄清楚所謂的「陣列」的格式。事實上,它是一個字串列表。如果 Curl 已經定義了一個標頭項目,您的標頭將會取代它。以下是一個範例,用於變更 POST 中的 Content Type

<?php curl_setopt ($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml")); ?>

Yann
luca dot manzo at bbsitalia dot com
18 年前
如果您在 curl 中處理 Cookie 時遇到問題

- curl 會在單一 curl 會話中透明地管理 Cookie
- 選項
<?php curl_setopt($ch, CURLOPT_COOKIEJAR, "/tmp/cookieFileName"); ?>

讓 curl 將 cookie 儲存在 curl 會期結束時的檔案中

- 選項
<?php curl_setopt($ch, CURLOPT_COOKIEFILE, "/tmp/cookieFileName"); ?>

讓 curl 使用指定的檔案作為要發送到伺服器的 cookie 來源。

因此,為了正確處理不同 curl 會期之間的 cookie,您必須執行類似以下的操作

<?php
$ch
= curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_COOKIEJAR, COOKIE_FILE_PATH);
curl_setopt ($ch, CURLOPT_COOKIEFILE, COOKIE_FILE_PATH);

curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
$result = curl_exec ($ch);
curl_close($ch);
return
$result;
?>

如果您使用 PEAR_SOAP 函式庫在 https 上建立 Web 服務用戶端,並且遠端伺服器需要建立會期 cookie,則這點尤其必要。事實上,每個 SOAP 訊息都是使用不同的 curl 會期發送的!!

我希望這能幫助到某些人
Luca
Chris at PureFormSolutions dot com
15 年前
我發現多次設定 CURLOPT_HTTPHEADER 會清除您先前使用 CURLOPT_HTTPHEADER 設定的任何標頭。

請考慮以下情況
<?php
# ...

curl_setopt($cURL,CURLOPT_HTTPHEADER,array (
"Content-Type: text/xml; charset=utf-8",
"Expect: 100-continue"
));

# ... 做一些其他的事情 ...

curl_setopt($cURL,CURLOPT_HTTPHEADER,array (
"Accept: application/json"
));

# ...
?>

我設定的 Content-Type 和 Expect 都不會在傳出的標頭中,但是 Accept 會在。
joelhy
8 年前
請注意 CURLINFO_HEADER_OUT 和 CURLOPT_VERBOSE 選項不能一起使用
「當 CURLINFO_HEADER_OUT 設定為 TRUE 時,CURLOPT_VERBOSE 無法運作。」(來自 https://bugs.php.net/bug.php?id=65348)。
我花了一兩個小時才弄清楚這一點。
badman
11 年前
許多主機商使用 PHP safe_mode 或/和 open_basedir,因此您無法使用 CURLOPT_FOLLOWLOCATION。如果您嘗試,您會看到類似這樣的訊息
當啟用 safe_mode 或在 [您的腳本名稱 & 路徑] 的 XXX 行設定 open_basedir 時,無法啟用 CURLOPT_FOLLOWLOCATION

首先,我嘗試使用此頁面上的 zsalab 函式 (http://us2.php.net/manual/en/function.curl-setopt.php#102121),但是由於某些原因,它無法正常運作。因此,我寫了自己的函式。

它可以代替 curl_exec 使用。如果伺服器的 HTTP 回應代碼是 30x,則函式將轉發請求,直到回應與 30x 不同為止(例如,200 Ok)。您也可以使用 POST。

function curlExec(/* Array */$curlOptions='', /* Array */$curlHeaders='', /* Array */$postFields='')
{
$newUrl = '';
$maxRedirection = 10;
do
{
if ($maxRedirection<1) die('錯誤:已達到重定向的限制');

$ch = curl_init();
if (!empty($curlOptions)) curl_setopt_array($ch, $curlOptions);
if (!empty($curlHeaders)) curl_setopt($ch, CURLOPT_HTTPHEADER, $curlHeaders);
if (!empty($postFields))
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
}

if (!empty($newUrl)) curl_setopt($ch, CURLOPT_URL, $newUrl); // 需要重定向

$curlResult = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ($code == 301 || $code == 302 || $code == 303 || $code == 307)
{
preg_match('/Location:(.*?)\n/', $curlResult, $matches);
$newUrl = trim(array_pop($matches));
curl_close($ch);

$maxRedirection--;
continue;
}
else // 沒有更多重定向
{
$code = 0;
curl_close($ch);
}
}
while($code);
return $curlResult;
}
joeterranova at gmail dot com
14 年前
看來在設定 CURLOPT_RETURNTRANSFER 之前設定 CURLOPT_FILE 無法運作,大概是因為 CURLOPT_FILE 依賴於已設定 CURLOPT_RETURNTRANSFER。

所以這樣做

<?php
curl_setopt
($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FILE, $fp);
?>

而不是這樣

<?php
curl_setopt
($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
?>
jade dot skaggs at gmail dot com
16 年前
經過一番掙扎後,我終於讓需要 HTTP 驗證的 SOAP 請求正常運作。以下是一些程式碼,希望對其他人有所幫助。

<?php

$credentials
= "username:password";

// 讀取要傳送到 Web 服務的 XML
$request_file
= "./SampleRequest.xml";
$fh = fopen($request_file, 'r');
$xml_data = fread($fh, filesize($request_file));
fclose($fh);

$url = "http://www.example.com/services/calculation";
$page = "/services/calculation";
$headers = array(
"POST ".$page." HTTP/1.0",
"Content-type: text/xml;charset=\"utf-8\"",
"Accept: text/xml",
"Cache-Control: no-cache",
"Pragma: no-cache",
"SOAPAction: \"run\"",
"Content-length: ".strlen($xml_data),
"Authorization: Basic " . base64_encode($credentials)
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_USERAGENT, $defined_vars['HTTP_USER_AGENT']);

// 將 XML 應用於 curl 呼叫
curl_setopt
($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_data);

$data = curl_exec($ch);

if (
curl_errno($ch)) {
print
"Error: " . curl_error($ch);
} else {
// 顯示結果
var_dump
($data);
curl_close($ch);
}

?>
jancister at gmail dot com
9 年前
請注意,如果您想使用 CURLOPT_PROGRESSFUNCTION 選項來處理進度,您需要考慮您使用的 PHP 版本。自 5.5.0 版本起,傳遞給回呼函數的參數數量/順序引入了不相容的變更,並且 cURL 資源現在會作為第一個參數傳遞。

5.5.0 版本之前
<?php
// ...
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
curl_setopt($resource, CURLOPT_NOPROGRESS, false);
// ...
function progressCallback($download_size = 0, $downloaded = 0, $upload_size = 0, $uploaded = 0)
{
// 處理進度
}
?>

從 5.5.0 版本起
<?php
// ...
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
curl_setopt($resource, CURLOPT_NOPROGRESS, false);
// ...
function progressCallback($resource, $download_size = 0, $downloaded = 0, $upload_size = 0, $uploaded = 0)
{
// 處理進度
}
?>

然而,如果您的程式碼需要與 5.5.0 之前和之後的 PHP 版本相容,請考慮新增版本檢查
<?php
// ...
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, 'progressCallback');
curl_setopt($resource, CURLOPT_NOPROGRESS, false);
// ...
function progressCallback($resource, $download_size = 0, $downloaded = 0, $upload_size = 0, $uploaded = 0)
{
/**
* 在 5.5.0 版本中新增了 $resource 參數,破壞了向後相容性;
* 如果我們使用的是低於 5.5.0 的 PHP 版本,我們需要位移參數
* @see https://php.dev.org.tw/manual/en/function.curl-setopt.php#refsect1-function.curl-setopt-changelog
*/
if (version_compare(PHP_VERSION, '5.5.0') < 0) {
$uploaded = $upload_size;
$upload_size = $downloaded;
$downloaded = $download_size;
$download_size = $resource;
}

// 處理進度
}
?>
eric dot van dot eldik at peercode dot nl
6 年前
當您使用 PUT 請求時收到此錯誤:「SSL read: error:00000000:lib(0):func(0):reason(0), errno 104」)

可能是因為
<?php
curl_setopt
($ch, CURLOPT_PUT, TRUE);
?>

請改為嘗試
<?php
curl_setopt
($ch, CURLOPT_CUSTOMREQUEST, "PUT");
?>
skyogre __at__ yandex __dot__ ru
18 年前
在 PHP 4+ 中,使用 curl 傳輸 $_POST 資料確實存在問題。
我改進了 Alejandro Moreno 的編碼函數,使其能夠正確處理多維陣列。

<?php
function data_encode($data, $keyprefix = "", $keypostfix = "") {
assert( is_array($data) );
$vars=null;
foreach(
$data as $key=>$value) {
if(
is_array($value)) $vars .= data_encode($value, $keyprefix.$key.$keypostfix.urlencode("["), urlencode("]"));
else
$vars .= $keyprefix.$key.$keypostfix."=".urlencode($value)."&";
}
return
$vars;
}

curl_setopt($ch, CURLOPT_POSTFIELDS, substr(data_encode($_POST), 0, -1) );

?>
fnjordy at gmail dot com
16 年前
請注意,當 CURLOPT_RETURNTRANSFER 與 CURLOPT_WRITEFUNCTION 一起使用時,實際上具有三個設定:預設值、true 和 false。

預設值 - 將會如預期呼叫回呼。
true - 內容將會回傳,但不會呼叫回呼函數。
false - 內容將會輸出,且不會呼叫回呼函數。

請注意,CURLOPT_HEADERFUNCTION 回呼永遠都會被呼叫。
juozaspo at gmail dot com
12 年前
我建立了一個範例,可以取得傳遞給腳本的 URL 上的檔案,並將其輸出到瀏覽器。

<?php
//取得檔案(例如圖片)並將其輸出到瀏覽器
$ch = curl_init(); //開啟 curl 處理程序
curl_setopt($ch, CURLOPT_URL, $_GET['url']); //設定 URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //不直接輸出,使用變數
curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); //進行二進位傳輸
curl_setopt($ch, CURLOPT_FAILONERROR, 1); //若發生錯誤則停止
$file=curl_exec($ch); //將內容儲存在變數中
if(!curl_errno($ch))
{
//發送標頭並輸出
header ("Content-type: ".curl_getinfo($ch, CURLINFO_CONTENT_TYPE)."");
header ("Content-Length: ".curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD)."");
echo
$file;
} else echo
'Curl 錯誤:' . curl_error($ch);
curl_close($ch); //關閉 curl 處理程序
?>

附註:請確保程式碼前後沒有換行符號,否則腳本可能無法運作。
Joey Hewitt
12 年前
請注意,如果您將憑證鏈放入 PEM 檔案中,則憑證需要排序,使每個憑證都緊跟著其發行者(即,根憑證在最後)。

來源: http://publib.boulder.ibm.com/tividd/td/ITIM/SC32-1493-00/en_US/HTML/im451_config09.htm
anderseta at gmail dot com
14 年前
如果您想找到您正在串流的檔案大小並將其用作標頭,以下是如何操作:

<?php

function write_function($curl_resource, $string)
{
if(
curl_getinfo($curl_resource, CURLINFO_SIZE_DOWNLOAD) <= 2000)
{
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Description: File Transfer');
header("Content-Transfer-Encoding: binary");
header("Content-Type: ".curl_getinfo($curl_resource, CURLINFO_CONTENT_TYPE)."");
header("Content-Length: ".curl_getinfo($curl_resource, CURLINFO_CONTENT_LENGTH_DOWNLOAD)."");
}

print
$string;

return
mb_strlen($string, '8bit');
}

?>

1440 是 curl 呼叫寫入函式的預設位元組數(BUFFERSIZE 不會影響此值,我實際上認為您無法變更此值),因此這表示標頭只會設定一次。

write_function 必須傳回字串的確切位元組數,因此您可以使用 mb_strlen 傳回值。
Dustin Hawkins
18 年前
進一步擴展 CURLOPT_CAPATH 和 CURLOPT_CAINFO 的使用...

在我的情況下,我希望防止 curl 連接到任何 HTTPS 伺服器,除了我自己的伺服器使用自我簽署憑證。為此,您需要安裝 openssl 並存取 HTTPS 伺服器憑證(預設在 apache 上為 server.crt)。

然後,您可以使用類似以下的命令將您的 apache 憑證轉換為 curl 可以接受的憑證。

$ openssl x509 -in server.crt -out outcert.pem -text

然後將 CURLOPT_CAINFO 設定為 outcert.pem 的完整路徑,並開啟 CURLOPT_SSL_VERIFYPEER。

如果您想使用 CURLOPT_CAPATH 選項,您應該為您建立的所有有效憑證建立一個目錄,然後使用 openssl 隨附的 c_rehash 腳本來「準備」該目錄。

如果您不使用 c_rehash 公用程式,curl 將會忽略您設定的目錄中的任何檔案。
saidk at phirebranding dot com
16 年前
將 PHP 的 $_SESSION 傳遞到您的 cURL 呼叫中

<?php
session_start
();
$strCookie = 'PHPSESSID=' . $_COOKIE['PHPSESSID'] . '; path=/';
session_write_close();

$curl_handle = curl_init('在此輸入外部 URL');
curl_setopt( $curl_handle, CURLOPT_COOKIE, $strCookie );
curl_exec($curl_handle);
curl_close($curl_handle);
?>

這對我來說效果很好。我從同一台伺服器呼叫頁面,並且需要保留 $_SESSION 變數。這會將它們傳遞過去。如果您想測試,請使用 print_r($_SESSION);。

請享用!
Martin K.
10 年前
如果您只想啟用 cookie 處理,而不需要為單獨的會話儲存 cookie,只需將 CURLOPT_COOKIEFILE 設定為空字串即可。我曾被建議使用 php://memory,但它似乎沒有相同的效果。

雖然這在文件中已說明,但我認為值得重申,因為它給我帶來了很多麻煩。
Ojas Ojasvi
17 年前
<?php
/*
* 作者:Ojas Ojasvi
* 發布日期:2007 年 9 月 25 日
* 說明:一個 disguise_curl() 函式的範例,示範如何使用偽造的使用者代理和偽造的標頭,從網站抓取內容,同時保持完全的偽裝。
*/

$url = 'https://php.dev.org.tw';

// 使用偽造的標頭和偽造的使用者代理來偽裝 curl。
function disguise_curl($url)
{
$curl = curl_init();

// 設定標頭 - 我使用了 Firefox 2.0.0.6 版的相同標頭
// 下面拆成多行是因為 php.net 說該行太長。 :/
$header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
$header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
$header[] = "Cache-Control: max-age=0";
$header[] = "Connection: keep-alive";
$header[] = "Keep-Alive: 300";
$header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
$header[] = "Accept-Language: en-us,en;q=0.5";
$header[] = "Pragma: "; // 瀏覽器會將此留空。

curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_USERAGENT, 'Googlebot/2.1 (+http://www.google.com/bot.html)');
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_REFERER, 'http://www.google.com');
curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
curl_setopt($curl, CURLOPT_AUTOREFERER, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);

$html = curl_exec($curl); // 執行 curl 命令
curl_close($curl); // 關閉連線

return $html; // 最後,回傳 $html
}

// 使用函式並顯示網站的文字
$text = disguise_curl($url);
echo
$text;
?>

Ojas Ojasvi
Aaron Wells
10 年前
如果您使用 cURL 來獲取使用者提供的 URL(例如,在基於 Web 的 RSS 聚合器中),請注意伺服器端請求偽造 (SSRF) 的風險。這是一種攻擊,使用者會利用 cURL 請求是從 Web 伺服器本身發送的事實,來訪問他們無法從網路外部訪問的網路位置。

例如,他們可以輸入 "https://127.0.0.1" URL,並透過 "localhost" 訪問 Web 伺服器上的內容。或者, "ftp://127.0.0.1"。cURL 支援許多協定!

如果您正在使用 CURLOPT_FOLLOWLOCATION,惡意的 URL 可能會在原始請求的重新導向中。cURL 也會將重新導向標頭追蹤到其他協定!(303 See Other;Location: ftp://127.0.0.1)。

因此,如果您正在使用 cURL 和使用者提供的 URL,至少要使用 CURLOPT_PROTOCOLS(也會設定 CURLOPT_REDIR_PROTOCOLS),並且要停用 CURLOPT_FOLLOWLOCATION 或使用 "SafeCurl" 函式庫來安全地追蹤重新導向。
mr at coder dot tv
18 年前
有時您無法使用 CURLOPT_COOKIEJAR 和 CURLOPT_COOKIEFILE,因為伺服器的 PHP 設定(他們說您可以使用這些選項從伺服器抓取任何檔案)。以下是解決方案
1) 不要使用 CURLOPT_FOLLOWLOCATION
2) 使用 curl_setopt($ch, CURLOPT_HEADER, 1)
3) 從標頭抓取 cookies,如下所示
preg_match_all('|Set-Cookie: (.*);|U', $content, $results);
$cookies = implode(';', $results[1]);
4) 使用 curl_setopt($ch, CURLOPT_COOKIE, $cookies); 設定它們

祝您好運,Yevgen
PHP at RHaworth dot net
13 年前
當 CURLOPT_FOLLOWLOCATION 和 CURLOPT_HEADER 都為 true 且發生重新導向時,curl_exec() 回傳的標頭將包含重新導向鏈中的所有標頭,依據它們被遇到的順序。
S\
13 年前
當使用 CURLOPT_POSTFIELDS 並以陣列作為參數時,您必須高度注意使用者輸入。未驗證的使用者輸入將導致嚴重的安全性問題。

<?php

/**
* test.php:
*/
$ch = curl_init('http://example.com');

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'foo' => $_GET['bar']
));

curl_exec($ch);

?>

請求 "test.php?bar=@/home/user/test.png" 將會把 "test.png" 送到 example.com。
請確保您從使用者輸入中移除開頭的 "@"。
clint at fewbar dot com
14 年前
如果您在 curl 控制代碼上啟用了條件式 GET,然後對於後續的請求,您沒有為 CURLOPT_TIMEVALUE 設定良好的值,您可以使用以下方式停用 If-Modified-Since 檢查

<?php

$ch
= curl_init();
curl_setopt($ch, CURLOPT_URL, $foo);
curl_setopt($ch, CURLOPT_TIMEVALUE, filemtime($foo_path));
curl_setopt($ch, CURLOPT_TIMECONDITION, CURLOPT_TIMECOND_IFMODIFIEDSINCE);
curl_exec($ch);
// 重複使用相同的 curl 控制代碼
curl_setopt($ch, CURLOPT_URL, $bar);
curl_setopt($ch, CURLOPT_TIMEVALUE, null); // 不知道修改時間
curl_setopt($ch, CURLOPT_TIMECONDITION, 0); // 將其設定為 0,關閉它
curl_exec($ch);

?>
ohcc at 163 dot com
7 年前
這是如何在 PHP 中使用 cURL 上傳現有檔案到 FTP 伺服器的方法。

您應該記住,CURLOPT_URL 應該包含檔案的基本名稱,以儲存在 FTP 伺服器上。例如,如果您將 hello.txt 上傳到 ftp://www.wuxiancheng.cn/text/,CURLOPT_URL 應該是 ftp://www.wuxiancheng.cn/text/hello.txt,而不是 ftp://www.wuxiancheng.cn/text/,否則當您呼叫 curl_error() 時,您會收到類似「上傳到沒有檔案名稱的 URL!」的錯誤訊息;

<?php
$ch
= curl_init();
$filepath = 'D:\Web\www\wuxiancheng.cn\hello.txt';
$basename = pathInfo($filepath, PATHINFO_BASENAME);
$filesize = fileSize($filepath);
curl_setopt_array(
$ch,
array(
CURLOPT_URL => 'ftp://www.wuxiancheng.cn/text/' . $basename,
CURLOPT_USERPWD => 'USERNAME:PASSWORD',
CURLOPT_PROTOCOLS => CURLPROTO_FTP,
CURLOPT_UPLOAD => true,
CURLOPT_INFILE => $filepath,
CURLOPT_INFILESIZE => $filesize,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
)
);
curl_exec($ch);
$message = curl_errno($ch) === CURLE_OK ? 'success' : 'failure';
echo
$message;
?>
Pawel Antczak
14 年前
哈囉。
在處理「當 safe_mode 或 open_basedir 設定時,CURLOPT_FOLLOWLOCATION 無法啟用」的問題時
我正在尋找解決方案。
我在這個頁面找到一些方法,但沒有一個夠好,所以我自己做了一個。
<?php
function curl_redirect_exec($ch, &$redirects, $curlopt_header = false) {
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (
$http_code == 301 || $http_code == 302) {
list(
$header) = explode("\r\n\r\n", $data, 2);
$matches = array();
preg_match('/(Location:|URI:)(.*?)\n/', $header, $matches);
$url = trim(array_pop($matches));
$url_parsed = parse_url($url);
if (isset(
$url_parsed)) {
curl_setopt($ch, CURLOPT_URL, $url);
$redirects++;
return
curl_redirect_exec($ch, $redirects);
}
}
if (
$curlopt_header)
return
$data;
else {
list(,
$body) = explode("\r\n\r\n", $data, 2);
return
$body;
}
}
?>

現有函式的主要問題是缺乏關於已完成多少次重新導向的資訊。
這個會計算它。
第一個參數如常。
第二個參數應該是一個已經初始化的整數,它會依照完成的重新導向次數遞增。
如果你需要,可以設定 CURLOPT_HEADER。
regan dot corey at gmail dot com
12 年前
我花了好幾天嘗試將多維表單欄位陣列(包括檔案上傳)以 POST 方式傳送到遠端伺服器來更新產品。以下是一些突破,終於讓腳本如預期般執行。

首先,HTML 表單使用如下的輸入名稱
<input type="text" name="product[name]" />
<input type="text" name="product[cost]" />
<input type="file" name="product[thumbnail]" />
與另外兩個不屬於產品陣列的表單輸入結合
<input type="text" name="method" value="put" />
<input type="text" name="mode" />

我使用了幾個 cURL 選項,但只有兩個(除了 URL)是重要的
curl_setopt($handle, CURLOPT_POST, true);
curl_setopt($handle, CURLOPT_POSTFIELDS, $postfields);
到目前為止都很標準。
注意:不需要設定標頭,當您將陣列傳遞到 CURLOPT_POSTFIELDS 時,cURL 會自動設定標頭(例如 content-type: multipart/form-data; content-length...)。
注意:即使這應該是透過 HTTP POST 表單發出的 PUT 命令,也不需要透過 cURL 原生傳遞任何特殊的 PUT 選項。例如像這樣的選項
curl_setopt($handle, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT', 'Content-Length: ' . strlen($fields)));
或是
curl_setopt($handle, CURLOPT_PUT, true);
或是
curl_setopt($handle, CURLOPT_CUSTOMREQUEST, "PUT);
這些都不是讓程式碼正常運作所需要的。

我想要透過 cURL 傳遞的欄位被整理成一個如下的陣列
$postfields = array("method" => $_POST["method"],
"mode" => $_POST["mode"],
"product" => array("name" => $_POST["product"],
"cost" => $_POST["product"]["cost"],
"thumbnail" => "@{$_FILES["thumbnail"]["tmp_name"]};type={$_FILES["thumbnail"]["type"]}")
);

-請注意,@ 出現在暫存檔案名稱之前,這樣會建立連結,讓 PHP 上傳/傳輸實際的檔案,而不是僅傳送檔案名稱(如果沒有包含 @ 就會發生這種情況)。
-請注意,我強制設定了要上傳的檔案的 MIME 類型。我之前遇到問題,圖片檔案類型預設為 octet-stream,而不是 image/png 或 image/jpeg 或其他選定圖片的類型。

然後我嘗試將 $postfields 直接傳遞到 curl_setopt($this->handle, CURLOPT_POSTFIELDS, $postfields); 但它不起作用。
我嘗試使用 http_build_query($postfields); 但那也沒有正常運作。
在這兩種情況下,檔案都不會被視為實際檔案,並且表單資料也沒有被正確傳送。問題在於 HTTP 傳輸陣列的方法。雖然 PHP 和其他語言可以找出如何處理透過表單傳遞的陣列,但 HTTP 並沒有那麼複雜。我必須像這樣重寫 $postfields 陣列
$postfields = array("method" => $_POST["method"],
"mode" => $_POST["mode"],
"product[name]" => $_POST["product"],
"product[cost]" => $_POST["product"]["cost"],
"product[thumbnail]" => "@{$_FILES["thumbnail"]["tmp_name"]}");
curl_setopt($handle, CURLOPT_POSTFIELDS, $postfields);

這樣,在沒有使用 http_build_query 的情況下,就解決了我所有的問題。現在接收端主機可以正確輸出 $_POST 和 $_FILES 變數。
zsalab
13 年前
如果啟用了 safe_mode 或 open_basedir,則使用 curl 處理重新導向。該函數透明地工作,在標頭和 returntransfer 選項方面沒有問題。您可以使用可選的第二個參數來處理最大重新導向次數(如果超出最大重新導向次數,該函數會將變數設定為零)。
第二個參數值
- maxredirect 為 null 或未設定:最多重新導向五次,之後會引發 PHP 警告
- maxredirect 大於零:不引發錯誤,但參數變數會設定為零
- maxredirect 小於或等於零:不追蹤重新導向

<?php
function curl_exec_follow(/*resource*/ $ch, /*int*/ &$maxredirect = null) {
$mr = $maxredirect === null ? 5 : intval($maxredirect);
if (
ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $mr > 0);
curl_setopt($ch, CURLOPT_MAXREDIRS, $mr);
} else {
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
if (
$mr > 0) {
$newurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);

$rch = curl_copy_handle($ch);
curl_setopt($rch, CURLOPT_HEADER, true);
curl_setopt($rch, CURLOPT_NOBODY, true);
curl_setopt($rch, CURLOPT_FORBID_REUSE, false);
curl_setopt($rch, CURLOPT_RETURNTRANSFER, true);
do {
curl_setopt($rch, CURLOPT_URL, $newurl);
$header = curl_exec($rch);
if (
curl_errno($rch)) {
$code = 0;
} else {
$code = curl_getinfo($rch, CURLINFO_HTTP_CODE);
if (
$code == 301 || $code == 302) {
preg_match('/Location:(.*?)\n/', $header, $matches);
$newurl = trim(array_pop($matches));
} else {
$code = 0;
}
}
} while (
$code && --$mr);
curl_close($rch);
if (!
$mr) {
if (
$maxredirect === null) {
trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING);
} else {
$maxredirect = 0;
}
return
false;
}
curl_setopt($ch, CURLOPT_URL, $newurl);
}
}
return
curl_exec($ch);
}
?>
Adam Monsen
12 年前
如果你想要將 Content-Type 標頭設定為 "multipart/form-data" (例如,當 CURLOPT_POSTFIELDS 是一個陣列時),則必須將 CURLOPT_POST 保持未設定。 如果你將 CURLOPT_POSTFIELDS 設定為陣列,並將 CURLOPT_POST 設定為 TRUE,則 Content-Length 將會是 -1,而且大多數正常的伺服器將會拒絕該請求。 如果你將 CURLOPT_POSTFIELDS 設定為陣列,並將 CURLOPT_POST 設定為 FALSE,cURL 將會傳送一個 GET 請求。
c00lways at gmail dot com
16 年前
如果你想要傳送 XML 請求到伺服器 (例如,建立一個 SOAP 代理),
你必須設定

<?php
curl_setopt
($ch, CURLOPT_HTTPHEADER, Array("Content-Type: text/xml"));
?>

請務必注意快取問題
以下的程式碼將會防止快取...

<?php
curl_setopt
($ch, CURLOPT_FORBID_REUSE, 1);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, 1);
?>

希望這對您有幫助 ;)
fred at themancan dot com
16 年前
要找出給定的 HTTP POST 請求使用的編碼很容易 -- 將一個陣列傳遞給 CURLOPT_POSTFIELDS 會產生 multipart/form-data

<?php
curl_setopt
(CURLOPT_POSTFIELDS, array('field1' => 'value'));
?>

傳遞 URL 編碼字串將會產生 application/x-www-form-urlencoded

<?php
curl_setopt
(CURLOPT_POSTFIELDS, array('field1=value&field2=value2'));
?>

我在與倉儲系統和電子郵件系統整合時遇到這個問題;兩者都不接受 multipart/form-data,但都樂於接受 application/x-www-form-urlencoded。
scy-phpmanual at scytale dot name
14 年前
為了重設 CURLOPT_HTTPHEADER,將它設定為 array()。 cURL C API 說你應該將它設定為 NULL,但是在 PHP 包裝器中這不起作用。
rob
15 年前
文件中沒有提到的是,你必須將 CURLOPT_COOKIEJAR 設定為一個檔案,CURL 控制代碼才能真正使用 Cookie,如果未設定,則不會解析 Cookie。
markandrewslade at gmail dot com
7 年前
與文件相反,CURLOPT_STDERR 應該設定為你要寫入的檔案的控制代碼,而不是檔案的位置。
ron at ttvavanti dot nl
20 年前
如果你指定了 CAINFO,請注意該檔案必須是 PEM 格式! (如果不是,它將無法運作)。
使用 Openssl,你可以使用
openssl x509 -in <cert> -inform d -outform PEM -out cert.pem
從二進制憑證 (如果你從某處下載了 CA,你會得到這個憑證) 建立 PEM 格式的憑證。
eion at bigfoot dot com
18 年前
如果你嘗試使用 CURLOPT_FOLLOWLOCATION 並收到此警告
警告:curl_setopt() [function.curl-setopt]:當處於 safe_mode 或設定了 open_basedir 時,無法啟用 CURLOPT_FOLLOWLOCATION ...

那麼你會想要閱讀 https://php.dev.org.tw/ChangeLog-4.php,其中指出「當啟用 open_basedir 或 safe_mode 時,在 curl 中禁用 CURLOPT_FOLLOWLOCATION」,自 PHP 4.4.4/5.1.5 開始。這是因為 curl 不是 PHP 的一部分,並且不知道 open_basedir 或 safe_mode 的值,因此你可以透過重定向 (使用 header('Location: ...')) 到 "file://" URL,這會讓 curl 樂意地檢索,從而損害你以安全模式運作的網路伺服器。

在 PHP 或 curl (如果有的話) 中更改 curl 擴充功能以處理 "Location:" 標頭之前,以下是我正在使用的 curl_exec 函數的遠非完美的重新製作。

由於沒有等效的 curl_getopt 函數,你必須調整該函數以使其適用於你的特定用途。 就目前情況而言,它會傳回回應的主體而不是標頭。它也不處理帶有使用者名稱和密碼的重定向 URL。

<?php
function curl_redir_exec($ch)
{
static
$curl_loops = 0;
static
$curl_max_loops = 20;
if (
$curl_loops++ >= $curl_max_loops)
{
$curl_loops = 0;
return
FALSE;
}
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
list(
$header, $data) = explode("\n\n", $data, 2);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if (
$http_code == 301 || $http_code == 302)
{
$matches = array();
preg_match('/Location:(.*?)\n/', $header, $matches);
$url = @parse_url(trim(array_pop($matches)));
if (!
$url)
{
//couldn't process the url to redirect to
$curl_loops = 0;
return
$data;
}
$last_url = parse_url(curl_getinfo($ch, CURLINFO_EFFECTIVE_URL));
if (!
$url['scheme'])
$url['scheme'] = $last_url['scheme'];
if (!
$url['host'])
$url['host'] = $last_url['host'];
if (!
$url['path'])
$url['path'] = $last_url['path'];
$new_url = $url['scheme'] . '://' . $url['host'] . $url['path'] . ($url['query']?'?'.$url['query']:'');
curl_setopt($ch, CURLOPT_URL, $new_url);
debug('Redirecting to', $new_url);
return
curl_redir_exec($ch);
} else {
$curl_loops=0;
return
$data;
}
}
?>
anonymous
12 年前
這可能不明顯,但如果您指定了 CURLOPT_POSTFIELDS 卻沒有指定 CURLOPT_POST,它仍然會發送 POST 請求,而不是 GET 請求(您可能會認為 GET 是預設的)。
所以這一行:

curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

等同於:

curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

即使您像這樣設定選項(按此順序):

curl_setopt($ch, CURLOPT_POST, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);

它仍然會發送 POST 請求,因為 CURLOPT_POSTFIELDS 後設定。
所以,如果您想要發送 GET 請求,請確保您沒有在任何地方指定 CURLOPT_POSTFIELDS。
michaeledwards.com
19 年前
如果您在重定向時,將 CURLOPT_URL 與 CURLOPT_HEADERS 中的 'Host:' 標頭混合使用,可能會發生問題,因為 cURL 會將您在 'Host:' 標頭中明確聲明的主機,與重定向響應的 Location: 標頭中的主機合併。

簡而言之,不要這樣做:

<?php
$host
= "www.example.com";
$url = "http://$host/";

$headers = array("Host: $host");

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

請改為這樣做:

$host = "www.example.com";
$url = "http://$host/";

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $url);
?>
php at miggy dot org
18 年前
請注意,如果您想要使用代理並將其用作「快取」,您必須執行以下操作:

<?php curl_setopt($ch, CURLOPT_HTTPHEADER, array("Pragma: ")); ?>

否則,預設情況下,Curl 會在請求中放入 "Pragma: no-cache" 標頭,從而強制所有請求都錯失快取。
joel at mojamail dot com
6 年前
在冗長的文檔中,很容易忽略 CURLOPT_POSTFIELDS 會將 Content-Type 設定為 "multipart/form-data" (而不是通常的 "application/x-www-form-urlencoded"),只有在您提供陣列(而不是查詢字串)時才會這樣!

某些伺服器會因為 Content-Type 錯誤而返回奇怪的錯誤(例如 "SSL read: error:00000000:lib(0):func(0):reason(0), errno 104"),您可能會浪費很多時間來試圖找出原因!
Salil Kothadia
16 年前
在 PHP5 中,對於 "CURLOPT_POSTFIELDS" 選項,我們可以使用:

<?php
$ch
= curl_init($URI);
$Post = http_build_query($PostData);
curl_setopt($ch, CURLOPT_POSTFIELDS, $Post);
$Output = curl_exec($ch);
curl_close($ch);
?>
qeremy [atta] gmail [dotta] com
12 年前
如果您嘗試在伺服器上更新某些內容,並且需要通過 PUT 來處理此更新操作;

<?php
curl_setopt
($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_PUT, 1);
?>

沒有以下內容是「無用的」:

<?php
curl_setopt
($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT'));
?>

範例:

更新資料庫中以 "id 1" 識別的書籍資料;

--cURL 部分--
<?php
$data
= http_build_query($_POST);
// 或
$data = http_build_query(array(
'name' => 'PHP in Action',
'price' => 10.9
));

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://api.localhost/rest/books/1");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT"); // 不再需要
// 或
// curl_setopt($ch, CURLOPT_PUT, 1); // 不再需要
curl_setopt($ch, CURLOPT_HTTPHEADER, array('X-HTTP-Method-Override: PUT'));
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$ce = curl_exec($ch);
curl_close($ch);
print_r($ce);
?>

--API 類別--
<?php
public function putAction() {
echo
"putAction() -> id: ". $this->_getParam('id') ."\n";
print_r($_POST);
// 使用 POST 資料做一些事情
...
?>

--輸出--
putAction() -> id: 15
Array
(
[name] => PHP in Action
[price] => 10.9
)

---關鍵字---
rest, restfull api, restfull put, curl put, curl customrequest put
gskluzacek at gmail dot com
13 年前
請注意...除非您明確設定使用者代理 (user agent),否則您的請求中不會發送使用者代理,因為它不像其他選項一樣沒有預設值。

正如其他人所說,不發送使用者代理可能會導致您無法獲得預期的結果,例如,0 位元組長度的內容、不同的內容等。
Andrew
15 年前
我注意到,如果您想在 curl_exec() 之後取得目前的 cookie 檔案,您需要關閉目前的 curl 處理 (就像手冊上說的那樣),但如果您希望在任何 curl_exec 之後 (沒有 curl_close) 將 cookie 轉儲到檔案,您可以

<?php
#正常呼叫
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_COOKIEFILE, "cookiefile");
curl_setopt($ch, CURLOPT_COOKIEJAR, "cookiefile");
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_URL, 'http://www.example.com/');
$result1 = curl_exec($ch);

#然後建立一個臨時副本
$ch_temp=curl_copy_handle(ch);
curl_close($ch);
$ch=$ch_temp;
?>

只有這樣,如果您關閉 $ch_temp,cookie 才不會被轉儲。
shiplu at programmer dot net
11 年前
CURLOPT_POST 應該在 CURLOPT_POSTFIELDS 之前設定。否則您可能會遇到 411 Length Required 錯誤。

以下程式碼會在 nginx/1.1.15 上產生「411 Length Required」。
<?php
curl_setopt
($ch, CURLOPT_POSTFIELDS, $postfields);
curl_setopt ($ch, CURLOPT_POST, 1);
?>

但這個有效。

<?php
curl_setopt
($ch, CURLOPT_POST, 1);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $postfields);
?>
ac at an dot y-co dot de
16 年前
如果您想連線到需要您使用憑證識別自己的伺服器,請使用以下程式碼。您的憑證和伺服器憑證由一個授權機構簽署,該授權機構的憑證位於 ca.ctr 中。

<?php
curl_setopt
($ch, CURLOPT_VERBOSE, '1');
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, '2');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, '1');
curl_setopt($ch, CURLOPT_CAINFO, getcwd().'/cert/ca.crt');
curl_setopt($ch, CURLOPT_SSLCERT, getcwd().'/cert/mycert.pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'password');
?>

如果您的原始憑證是 .pfx 格式,您必須使用以下命令將其轉換為 .pem
# openssl pkcs12 -in mycert.pfx -out mycert.key
# openssl rsa -in mycert.key -out mycert.pem
# openssl x509 -in mycert.key >> mycert.pem
Madcat
11 年前
如果您在 CURLOPT_POSTFIELDS 中混合使用以 @ (at 符號) 開頭的字串和檔案,您就會遇到問題 (例如發佈帶有附件媒體的推文),因為 curl 會嘗試將任何以 @ 開頭的內容解讀為檔案。

<?php

$postfields
= array(
'upload_file' => '@file_to_upload.png',
'upload_text' => '@text_to_upload'
);

$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, 'http://example.com/upload-test');
curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
curl_exec($curl);
curl_close($curl);

?>

為了規避這個問題,請像這樣在文字字串前面加上 NULL 字元

<?php
$postfields
= array(
'upload_file' => '@file_to_upload.png',
'upload_text' => sprintf("\0%s", '@text_to_upload')
);
?>

原始來源:http://bit.ly/AntMle
Sylvain R
15 年前
當您使用 CURLOPT_FILE 直接下載到檔案中時,您必須在 curl_close() 之後關閉檔案處理常式,否則檔案將不完整,並且在 php 程式執行結束之前您將無法使用它。

<?php

$fh
= fopen('/tmp/foo', 'w');
$ch = curl_init('http://example.com/foo');
curl_setopt($ch, CURLOPT_FILE, $fh);
curl_exec($ch);
curl_close($ch);

# 在這個時間點,你的檔案還不完整且已損毀

fclose($fh);

# 現在你可以使用你的檔案了;

read_file('/tmp/foo');

?>
julien veneziano
14 年前
如果你需要在 DELETE 請求中發送資料,請使用

<?php
$request_body
= 'some data';
$ch = curl_init('http://www.example.com');
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_body);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
$response = curl_exec($ch);
var_dump($response);
?>
adrian at foeder dot de
12 年前
如果你想在 GET 請求中附加請求主體資料,這會變得有點棘手,因為它會隱式地將請求更改為 POST,就像下面許多註解正確說明的那樣。
所以,為了類比命令列的

curl -XGET 'http://example.org?foo=bar' -d '<baz>some additional data</baz>'

在 PHP 中你會這樣做,除了你其他必要的東西之外,

<?php
curl_setopt
($curlHandle, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curlHandle, CURLOPT_POSTFIELDS, '<baz>some additional data</baz>');
?>

在我的實驗中,其他每個「類似」的方式,例如 CURLOPT_HTTPGET,都沒有發送額外的資料或變成 POST 請求。
Niki Romagnoli
1 年前
使用 CURLOPT_POST 和 CURLOPT_POSTFIELDS 時,設定順序*很重要*。
將 CURL_POST 設定為 true 會清除先前使用陣列的任何 CURLOPT_POSTFIELDS。結果是請求為帶有空主體的 POST。

CURLOPT_POSTFIELDS 會為您將 CURLOPT_POST 設定為 true,無需重複。
如果您真的需要同時設定兩者,那麼可以
- 在 CURLOPT_POSTFIELDS *之前*設定 CURLOPT_POST
- 或者不要使用陣列並將 CURLOPT_POSTFIELDS 轉換為 URL 編碼的字串,這樣就不會受到影響 (即。<?php curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($yourArray)); ?> )
alexchexes at gmail dot com
1 年前
如果您希望 cURL 成功將 Cookie 寫入使用 CURLOPT_COOKIEJAR 指定的檔案,請確保 cURL 具有修改該檔案的必要權限(如果該檔案已存在)。

我花了幾乎一整天的時間試圖理解為什麼 cURL 沒有將 Cookie 儲存到現有檔案中,即使我可以使用 file_put_contents() 輕鬆修改完全相同的檔案。此外,cURL 本身可以建立相同的檔案並儲存 Cookie,但前提是該檔案之前不存在。

最終,問題與檔案所有權有關。我在 WSL2 中工作,在一個符號連結的 Windows 目錄中。[automount] wsl.conf 中的「metadata」未設定,導致從 PHP 建立的每個檔案都具有預設所有者,該所有者與執行 PHP 的使用者不同。

一旦我配置了 wsl.conf,然後將整個目錄的所有權變更為與執行 PHP 的使用者匹配,Cookie 就可以成功寫入任何檔案,而不會出現任何問題。
To Top