代理认证有专用的 cURL 选项。为网站登录设置 CURLOPT_USERPWD 不会配置代理账号,选择 CURLOPT_HTTPAUTH 也不会选定代理认证方式。

<?php
$user = 'proxy-user';
$password = getenv('PROXY_PASSWORD');
if ($password === false) {
    throw new RuntimeException('Set PROXY_PASSWORD');
}

$ch = curl_init('https://example.com/');
curl_setopt_array($ch, [
    CURLOPT_PROXY => 'http://203.0.113.10:8080',
    CURLOPT_NOPROXY => '',
    CURLOPT_PROXYUSERPWD =>
        rawurlencode($user) . ':' . rawurlencode($password),
    CURLOPT_PROXYAUTH => CURLAUTH_BASIC,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CONNECTTIMEOUT => 5,
    CURLOPT_TIMEOUT => 15,
]);

$body = curl_exec($ch);
if ($body === false) {
    throw new RuntimeException(curl_error($ch), curl_errno($ch));
}
echo curl_getinfo($ch, CURLINFO_RESPONSE_CODE), PHP_EOL;

替换文档示例 IP,并使用该代理提供的凭据。此例有意选择 Basic;应使用服务支持且获准的方式,不要假定所有端点都需要它。

组合字段有编码规则

libcurl 文档说明,CURLOPT_PROXYUSERPWD 会对用户名和密码进行 URL 解码。示例先分别编码,再用分隔符连接。如果凭据本身包含字面百分号序列或其他特殊字符,这一点就很重要。

分开的代理用户名和密码选项直接接受各自的值:

curl_setopt($ch, CURLOPT_PROXYUSERNAME, $user);
curl_setopt($ch, CURLOPT_PROXYPASSWORD, $password);

执行请求前,可用它们作为另一种凭据形式。不要把代理组合字段的解码规则自动套用于 CURLOPT_USERPWD;libcurl 文档说明二者存在差异。

将各段认证分开

CURLOPT_PROXYAUTH 选择代理认证,而 CURLOPT_HTTPAUTH 选择与目标之间的 HTTP 认证。如果双方都要求登录,应分别配置对应选项,而不是把同一份凭据复制到两个位置。

CURLAUTH_ANY 允许协商,在选定方式之前可能增加一次质询-响应交换。它不能证明凭据正确。如果再手动添加 Proxy-Authorization 头,可能干扰库的认证处理。

通过明文连接发给代理的 Basic 凭据,不受网站后续 TLS 隧道保护。选择认证服务的使用方式时,应单独检查这段传输。

相关文章