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 实例;以前,期望一个 resource
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 条注释

222
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) 攻击,这是您不希望看到的!
50
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 的字符串。它是制表符分隔的,如果您想执行除复制 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 的方法是跳过您不需要的那个。

我仅建议将 COOKIELIST 与魔术字符串一起使用,因为 cookie 格式不安全或不稳定。您至少可以将制表符注入到路径和名称中,因此无法可靠地解析。如果您必须解析它,为了确保其安全,我建议禁止内容中超过 6 个制表符,这对大多数人来说可能不是什么大损失。

对于绝对最低限度的验证,我建议

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

以下是格式

#define SEP "\t" /* 制表符分隔字段 */

char *my_cookie =
"example.com" /* 主机名 */
SEP "FALSE" /* 包含子域 */
SEP "/" /* 路径 */
SEP "FALSE" /* 安全 */
SEP "0" /* 以纪元时间格式表示的过期时间。0 == 会话 */
SEP "foo" /* 名称 */
SEP "bar"; /* 值 */
13
ashw1 - at - no spam - post - dot - cz
17 年前
如果您想知道为什么 cookie 在 Windows 下不起作用,我已经搜索了一些答案,结果如下:在 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);
}

?>
32
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\n";
}
} else {
// 服务器
sleep(10);
echo
"完成。";
}
?>
3
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 并相应地采取行动。
30
Philippe dot Jausions at 11abacus dot com
18 年前
回调方法的说明

- CURLOPT_HEADERFUNCTION 用于处理在*响应中*接收到的标头行,
- CURLOPT_WRITEFUNCTION 用于处理从*响应中*接收到的数据,
- CURLOPT_READFUNCTION 用于处理在*请求中*传递的数据。

回调“字符串”可以是任何可调用的函数,包括 array(&$obj, 'someMethodName') 格式。

-Philippe
14
JScott jscott401 at gmail dot com
14 年前
关于 curlopt_writefunction 的一些补充说明。我一开始对此很费解,因为它真的没有很好地记录。

当您编写一个回调函数并将其与 curlopt_writefunction 一起使用时,它将被多次调用。您的函数必须在每次调用时返回写入它的数据量。它对此非常挑剔。以下是我代码中可能对您有所帮助的片段

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

// 稍后在类中我编写了我的 receive Response 方法

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

}
?>

现在我为一个类做了这个。如果您没有进行面向对象编程,那么您显然需要根据自己的需要修改它。

CURL 多次调用您的脚本,因为数据并不总是立即发送。我们在这里谈论的是互联网,所以它被分成数据包。您需要获取您的数据并将其全部连接在一起,直到全部写入。我当时快要抓狂了,因为我会从服务器获取 XML 的片段,而且长度是随机的。我终于弄清楚发生了什么事。希望这有帮助
3
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:这将设置用于连接的套接字的本地端口号。

CURLOPT_LOCALPORTRANGE:范围参数是 libcurl 为找到可用的本地端口号而进行的尝试次数。它从给定的 CURLOPT_LOCALPORT 开始,每次重试都将数字加 1。将此选项设置为 1 或以下将使 libcurl 仅对确切的端口号尝试一次。

接口也可以使用 CURLOPT_INTERFACE 进行配置

例如

curl_setopt($conn, CURLOPT_INTERFACE, "eth1");
27
sgamon at yahoo dot com
16 年前
如果您正在执行 POST 操作,并且内容长度为 1,025 或更大,则 curl 会利用 http 1.1 的一项功能:100 (Continue) 状态。

参见 http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3

* 它添加一个标头,“Expect: 100-continue”。
* 然后它发送请求头,等待 100 响应代码,然后发送内容

但是并非所有 Web 服务器都支持此功能。根据服务器的不同,会返回各种错误。如果发生这种情况,请使用以下命令抑制“Expect”标头

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

参见 http://www.gnegg.ch/2007/02/the-return-of-except-100-continue/
6
mw+php dot net at lw-systems dot de
12 年前
CURLOPT_POSTFIELDS 选项的使用说明应该强调,使用 HTTP/1.1 与 cURL 进行 POST 操作意味着使用“Expect: 100-continue”标头。某些 Web 服务器将无法理解分块传输 POST 数据的处理方式。

要禁用此行为,必须使用以下方法禁用“Expect:”标头

curl_setopt($ch, CURLOPT_HTTPHEADER,array("Expect:"));
37
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 的操作方式完全相同。
6
Victor Jerlin
15 年前
似乎此页面上未提及某些选项,但在 http://curl.haxx.se/libcurl/c/curl_easy_setopt.html 上列出的选项实际上受支持。

我很高兴地发现,我实际上可以使用 CURLOPT_FTP_CREATE_MISSING_DIRS,即使是在 PHP 中。
14
dweingart at pobox dot com
21 年前
如果您希望 Curl 遵循重定向,并且还希望 Curl 回显在此过程中设置的任何 Cookie,请使用以下代码

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

'-' 表示标准输出

-dw
15
yann dot corno at free dot fr
22 年前
关于 CURLOPT_HTTPHEADER 选项,我花了一些时间才弄清楚如何格式化所谓的“数组”。实际上,它是一个字符串列表。如果 Curl 已经定义了某个标头项,则您的标头将替换它。以下是在 POST 中更改内容类型的示例

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

Yann
16
luca dot manzo at bbsitalia dot com
18 年前
如果您在处理 curl 的 Cookie 时遇到问题

- curl 在单个 curl 会话中透明地管理 Cookie
- 选项
<?php curl_setopt($ch, CURLOPT_COOKIEJAR, "/tmp/cookieFileName"); ?>

使 curl 在 curl 会话结束时将 Cookie 存储到文件中

- 选项
<?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
17
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 在其中。
14
joelhy
8 年前
请注意,CURLINFO_HEADER_OUT 和 CURLOPT_VERBOSE 选项不能一起使用
“当 CURLINFO_HEADER_OUT 设置为 TRUE 时,CURLOPT_VERBOSE 无法工作。”(来自 https://bugs.php.net/bug.php?id=65348)。
我花了一两个小时才弄清楚这一点。
14
badman
11 年前
许多主机使用 PHP safe_mode 或/和 open_basedir,因此您无法使用 CURLOPT_FOLLOWLOCATION。如果您尝试使用,则会看到如下消息
在 [您的脚本名称和路径] 的第 XXX 行中,启用 safe_mode 或设置 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(/* 数组 */$curlOptions='', /* 数组 */$curlHeaders='', /* 数组 */$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;
}
23
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);
?>
32
jade dot skaggs at gmail dot com
16 年前
经过一番努力,我成功地使需要 HTTP 身份验证的 SOAP 请求正常工作。以下是一些希望对其他人有用的源代码。

<?php

$credentials
= "用户名:密码";

// 读取发送到 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
"错误: " . curl_error($ch);
} else {
// 显示结果
var_dump($data);
curl_close($ch);
}

?>
8
[email protected]
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)
{
/**
* $resource 参数在 5.5.0 版本中添加,破坏了向后兼容性;
* 如果我们使用的是低于 5.5.0 版本的 PHP,我们需要调整参数
* @see https://php.net/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;
}

// 处理进度
}
?>
3
[email protected]
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");
?>
5
[email protected]
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) );

?>
9
[email protected]
16 年前
请注意,当 CURLOPT_RETURNTRANSFER 与 CURLOPT_WRITEFUNCTION 一起使用时,实际上有三种设置:默认、true 和 false。

默认 - 回调函数将按预期调用。
true - 内容将被返回,但回调函数不会被调用。
false - 内容将被输出,回调函数不会被调用。

请注意,CURLOPT_HEADERFUNCTION 回调函数始终会被调用。
3
[email protected]

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 处理程序
?>

附注:确保代码前后没有换行符,否则脚本可能无法正常工作。
3
Joey Hewitt
12 年前
请注意,如果您将证书链放在 PEM 文件中,则证书需要按顺序排列,以便每个证书后跟其颁发者(即根证书最后)。

来源: http://publib.boulder.ibm.com/tividd/td/ITIM/SC32-1493-00/en_US/HTML/im451_config09.htm
8
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 调用 write 函数的默认字节数(BUFFERSIZE 不影响此值,我实际上认为您无法更改此值),这意味着标头将仅设置一次。

write_function 必须返回字符串的确切字节数,因此您可以使用 mb_strlen 返回一个值。
7
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 将忽略您设置的目录中的任何文件。
14
saidk at phirebranding dot com
16 年前
将 PHP 的 $_SESSION 传递到您的 cURL 调用中

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

$curl_handle = curl_init('enter_external_url_here');
curl_setopt( $curl_handle, CURLOPT_COOKIE, $strCookie );
curl_exec($curl_handle);
curl_close($curl_handle);
?>

这对我很有效。我正在调用同一服务器上的页面,并且需要保留 $_SESSION 变量。这将它们传递过去。如果您想测试,只需 print_r($_SESSION);

享受!
5
Martin K.
10 年前
如果您只想启用 cookie 处理并且不需要为单独的会话保存 cookie,只需将 CURLOPT_COOKIEFILE 设置为空字符串即可。我被建议使用 php://memory,但这似乎没有相同的效果。

尽管这在文档中有所说明,但我认为值得重申,因为它给我带来了很多麻烦。
12
Ojas Ojasvi
17 年前
<?php
/*
* 作者:Ojas Ojasvi
* 发布日期:2007年9月25日
* 描述:一个 disguise_curl() 函数的示例,用于通过使用伪造的用户代理和伪造的请求头来抓取网站内容,同时保持完全伪装。
*/

$url = 'https://php.net';

// 使用伪造的请求头和伪造的用户代理伪装 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
7
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”库安全地跟随重定向。
11
mr at coder dot tv
18 年前
有时您无法使用 CURLOPT_COOKIEJAR 和 CURLOPT_COOKIEFILE,因为服务器 php 设置(他们说您可以使用这些选项从服务器获取任何文件)。以下是解决方法
1) 不要使用 CURLOPT_FOLLOWLOCATION
2) 使用 curl_setopt($ch, CURLOPT_HEADER, 1)
3) 从标头 cookie 中获取,如下所示
preg_match_all('|Set-Cookie: (.*);|U', $content, $results);
$cookies = implode(';', $results[1]);
4) 使用 curl_setopt($ch, CURLOPT_COOKIE, $cookies); 设置它们

祝您好运,Yevgen
10
PHP at RHaworth dot net
13 年前
当 CURLOPT_FOLLOWLOCATION 和 CURLOPT_HEADER 都为 true 且发生重定向时,curl_exec() 返回的标头将包含重定向链中所有标头,其顺序为遇到的顺序。
8
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。
确保您从用户输入中删除了前导“@”。
3
clint at fewbar dot com
14 年前
如果您在 curl 句柄上启用了条件获取,然后对于后续请求,您没有 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); // 不知道 mtime
curl_setopt($ch, CURLOPT_TIMECONDITION, 0); // 设置为 0,将其关闭
curl_exec($ch);

?>
5
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;
?>
7
Pawel Antczak
14 年前
你好。
在遇到“当处于安全模式或设置了 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。
10
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]" />
以及另外两个不属于 product 数组的表单输入
<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 变量。
8
zsalab
13 年前
如果启用了安全模式或 open_basedir,则使用 curl 处理重定向。该函数工作透明,标题和 returntransfer 选项没有问题。您可以使用可选的第二个参数处理最大重定向次数(如果超过最大重定向次数,则函数会将变量设置为零)。
第二个参数值
- maxredirect 为 null 或未设置:最多重定向五次,之后会发出 PHP 警告
- maxredirect 大于零:不会引发错误,但参数变量会设置为零
- maxredirect 小于或等于零:不跟随重定向



<?php
function curl_exec_follow(/*资源*/ $ch, /*整数*/ &$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('重定向次数过多。在跟随重定向时,libcurl 达到最大次数。', E_USER_WARNING);
} else {
$maxredirect = 0;
}
return
false;
}
curl_setopt($ch, CURLOPT_URL, $newurl);
}
}
return
curl_exec($ch);
}
?>
9
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 请求。
8
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);
?>

希望对您有所帮助;)
5
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。
4
scy-phpmanual at scytale dot name
14 年前
为了重置 CURLOPT_HTTPHEADER,将其设置为 array()。cURL C API 指出您应该将其设置为 NULL,但这在 PHP 包装器中不起作用。
6
rob
15 年前
文档中没有提到的是,您必须将 CURLOPT_COOKIEJAR 设置为文件,才能使 CURL 句柄实际使用 Cookie,如果未设置,则不会解析 Cookie。
4
markandrewslade at gmail dot com
7 年前
与文档相反,CURLOPT_STDERR 应设置为要写入的文件的句柄,而不是文件的路径。
4
ron at ttvavanti dot nl
20 年前
如果您指定了 CAINFO,请注意该文件必须为 PEM 格式!(如果不是,则不起作用)。
使用 OpenSSL,您可以使用
openssl x509 -in <cert> -inform d -outform PEM -out cert.pem
从二进制证书(从某个地方下载 CA 时获得的证书)创建 PEM 格式的证书。
4
eion at bigfoot dot com
18 年前
如果您尝试使用 CURLOPT_FOLLOWLOCATION 并收到此警告
警告:curl_setopt() [function.curl-setopt]:在安全模式或设置了 open_basedir 时,无法激活 CURLOPT_FOLLOWLOCATION...

那么您需要阅读https://php.net/ChangeLog-4.php,其中从 PHP 4.4.4/5.1.5 开始说明“在启用 open_basedir 或安全模式时,在 curl 中禁用 CURLOPT_FOLLOWLOCATION”。这是因为 curl 不是 PHP 的一部分,并且不知道 open_basedir 或安全模式的值,因此您可以通过重定向(使用 header('Location: ...'))到“file://” URL 来危害在安全模式下运行的 Web 服务器,curl 会很乐意检索这些 URL。

在 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)
{
//无法处理重定向到的URL
$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('重定向到', $new_url);
return
curl_redir_exec($ch);
} else {
$curl_loops=0;
return
$data;
}
}
?>
3
匿名用户
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。
2
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);
?>
1
php at miggy dot org
18 年前
请注意,如果你想使用代理并将其用作_缓存_,则必须执行

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

否则,默认情况下 Curl 会添加一个“Pragma: no-cache”头部,从而强制所有请求都缓存失效。
1
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”),你可能会浪费很多时间试图找出原因!
2
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);
?>
3
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
数组
(
[name] => PHP in Action
[price] => 10.9
)

---关键词--
rest, restful api, restful put, curl put, curl customrequest put
1
gskluzacek at gmail dot com
13 年前
仅供参考... 除非您明确设置用户代理,否则您的请求中不会发送任何用户代理,因为与某些其他选项不同,它没有默认值。

正如其他人所说,不发送用户代理可能会导致您无法获得预期的结果,例如:0 字节长度的内容、不同的内容等。
1
Andrew
15 年前
我注意到,如果您想在 curl_exec() 之后获取当前的 cookie 文件 - 您需要关闭当前的 curl 处理程序(如手册中所述),但是如果您希望在任何 curl_exec 之后将 cookie 导出到文件(无需 curl_close),您可以

<?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 才会被导出。
2
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);
?>
3
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
2
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
1
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');

?>
2
julien veneziano
14 年前
如果您需要在 DELETE 请求中发送数据,请使用

<?php
$request_body
= '一些数据';
$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);
?>
1
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 请求。
2
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)); ?>
1
alexchexes at gmail dot com
1 年前
如果你希望 cURL 成功地将 cookie 写入 CURLOPT_COOKIEJAR 指定的文件,请确保 cURL 具有修改该文件的必要权限(如果该文件已存在)。

我花了将近一天的时间试图理解为什么 cURL 无法将 cookie 保存到现有文件,即使我可以轻松地使用 file_put_contents() 修改完全相同的文件。此外,cURL 本身可以创建相同的文件并保存 cookie,但前提是该文件之前不存在。

最终,问题与文件所有权相关。我是在 WSL2 中工作,在一个符号链接的 Windows 目录中。wsl.conf 中的“[automount]”元数据未设置,导致从 PHP 创建的每个文件都具有默认所有者,这与运行 PHP 的用户不同。

一旦我配置了 wsl.conf,然后将整个目录的所有权更改为与运行 PHP 的用户匹配,cookie 就可以成功地写入任何文件,没有任何问题。
To Top