CURLRequest 类

CURLRequest 类是一个基于 CURL 的轻量级 HTTP 客户端,允许你与其他网站和服务器进行通信。它可以用于获取 Google 搜索结果、检索网页或图像,以及与 API 交互等多种用途。

该类的设计灵感来源于 Guzzle HTTP Client 库,因为它是使用最广泛的 HTTP 客户端库之一。在可能的情况下,我们保持了语法的一致性,以便当你的应用需要比本库更强大的功能时,只需极少修改即可迁移到 Guzzle。

备注

本类需要 PHP 安装 cURL 库。这是非常常见的库,通常默认可用,但部分主机可能未提供,若遇到问题请与主机服务商确认。

CURLRequest 配置

共享选项

重要

此设置仅用于向后兼容。新项目请勿使用。即使你正在使用,我们也建议禁用它。

备注

自 v4.4.0 起,默认值已改为 false

若要在请求间共享所有选项,请在 app/Config/CURLRequest.php 中将 $shareOptions 设为 true

<?php

namespace Config;

use CodeIgniter\Config\BaseConfig;

class CURLRequest extends BaseConfig
{
    // ...
    public bool $shareOptions = true;
}

如果使用类的实例发送多个请求,此行为可能导致带有不必要标头和正文的错误请求。

备注

在 v4.2.0 之前,由于一个错误,即使 $shareOptions 设为 false 请求体也不会重置。

加载类库

可以通过手动加载或通过 Services 类 加载本库。

使用 Services 类加载时,调用 curlrequest() 方法或全局函数 service()

<?php

$client = service('curlrequest'); // Since v4.5.0, this code is recommended due to performance improvements

// The code above is the same as the code below.
$client = \Config\Services::curlrequest();

你可以在第一个参数中传递默认选项数组来修改 cURL 处理请求的方式。选项将在本文档后续部分说明:

<?php

$options = [
    'baseURI' => 'http://example.com/api/v1/',
    'timeout' => 3,
];
$client = service('curlrequest', $options);

备注

$shareOptions 为 false 时,传递给类构造函数的默认选项将用于所有请求。其他选项将在发送请求后重置。

手动创建类时,需要传入几个依赖项。第一个参数是 Config\App 类的实例,第二个是 URI 实例,第三个是 Response 对象,第四个是可选的默认 $options 数组:

<?php

use Config\App;

$client = new \CodeIgniter\HTTP\CURLRequest(
    config(App::class),
    new \CodeIgniter\HTTP\URI(),
    new \CodeIgniter\HTTP\Response(config(App::class)),
    $options,
);

使用类库

使用 CURL 请求只需创建 Request 并获取 Response 对象。它负责处理通信,之后你可以完全控制信息处理方式。

发起请求

主要通过 request() 方法进行通信,该方法触发请求并返回 Response 实例。它接受 HTTP 方法、URL 和选项数组作为参数:

<?php

$client = service('curlrequest');

$response = $client->request('GET', 'https://api.github.com/user', [
    'auth' => ['user', 'pass'],
]);

重要

默认情况下,如果返回的 HTTP 状态码大于等于 400,CURLRequest 将抛出 HTTPException。若需获取响应,请参阅 http_errors 选项。

备注

$shareOptions 为 false 时,传递给方法的选项将用于该请求。发送请求后这些选项会被清除。若要将选项应用于所有请求,请在构造函数中传递选项。

由于响应是 CodeIgniter\HTTP\Response 的实例,你可以访问所有常规信息:

<?php

echo $response->getStatusCode();
echo $response->getBody();
echo $response->header('Content-Type');
$language = $response->negotiateLanguage(['en', 'fr']);

虽然 request() 方法最灵活,但也可以使用以下快捷方法。它们都将 URL 作为第一个参数,选项数组作为第二个:

<?php

$client->get('http://example.com');
$client->delete('http://example.com');
$client->head('http://example.com');
$client->options('http://example.com');
$client->patch('http://example.com');
$client->put('http://example.com');
$client->post('http://example.com');

基础 URI

可以在类实例化时通过选项设置 baseURI。这允许你设置基础 URI,之后使用该客户端的所有请求都使用相对 URL。这在处理 API 时特别方便:

<?php

$client = service('curlrequest', [
    'baseURI' => 'https://example.com/api/v1/',
]);

// GET http:example.com/api/v1/photos
$client->get('photos');

// GET http:example.com/api/v1/photos/13
$client->delete('photos/13');

当向 request() 方法或任何快捷方法提供相对 URI 时,它将根据 RFC 2986 第 2 节 描述的规则与 baseURI 组合。以下是组合解析的示例:

baseURI

URI

结果

http://foo.com

/bar

http://foo.com/bar

http://foo.com/foo

/bar

http://foo.com/bar

http://foo.com/foo

bar

http://foo.com/bar

http://foo.com/foo/

bar

http://foo.com/foo/bar

http://foo.com

http://baz.com

http://baz.com

http://foo.com/?bar

bar

http://foo.com/bar

使用响应

每个 request() 调用返回的 Response 对象包含大量有用信息和实用方法。最常用的方法用于确定响应内容。

获取状态码和原因短语:

<?php

$code   = $response->getStatusCode();   // 200
$reason = $response->getReasonPhrase(); // OK

从响应中检索标头:

<?php

// Get a header line
echo $response->getHeaderLine('Content-Type');

// Get all headers
foreach ($response->headers() as $name => $value) {
    echo $name . ': ' . $response->getHeaderLine($name) . "\n";
}

使用 getBody() 方法获取正文:

<?php

$body = $response->getBody();

正文是远程服务器返回的原始内容。如果内容类型需要格式化,你需要确保脚本能处理:

<?php

if (str_contains($response->header('content-type'), 'application/json')) {
    $body = json_decode($body);
}

请求选项

本节描述可传递给构造函数、request() 方法或任何快捷方法的所有可用选项。

allow_redirects

默认情况下,cURL 不会跟踪远程服务器返回的任何 “Location:” 标头。allow_redirects 选项允许你修改此行为。

设为 true 时跟踪重定向:

<?php

$client->request('GET', 'http://example.com', ['allow_redirects' => true]);
/*
 * Sets the following defaults:
 *   'max'       => 5,                // Maximum number of redirects to follow before stopping
 *   'strict'    => true,             // Ensure POST requests stay POST requests through redirects
 *   'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols
 */

警告

请注意启用重定向可能会跳转到意外 URL,并可能导致 SSRF 攻击。

设为 false 将应用请求的默认设置:

<?php

$client->request('GET', 'http://example.com', ['allow_redirects' => false]);

可以传递数组作为 allow_redirects 的值来指定新设置:

<?php

$client->request('GET', 'http://example.com', ['allow_redirects' => [
    'max'       => 10,
    'protocols' => ['https'], // Force HTTPS domains only.
]]);

备注

当 PHP 处于安全模式或启用 open_basedir 时,跟踪重定向无效。

auth

允许为 HTTP 基本认证摘要认证 提供凭据。值必须是数组,第一个元素是用户名,第二个是密码。第三个参数是认证类型(basicdigest):

<?php

$client->request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]);

body

对于支持正文的请求类型(如 PUT 或 POST),有两种设置正文的方式。第一种是使用 setBody() 方法:

<?php

$client->setBody($body)->request('PUT', 'http://example.com');

第二种是通过传递 body 选项。此方法为保持与 Guzzle API 兼容,功能与上例相同。值必须是字符串:

<?php

$client->request('PUT', 'http://example.com', ['body' => $body]);

cert

要指定 PEM 格式客户端证书的位置,可将完整文件路径作为字符串传递给 cert 选项。若需密码,可将值设为数组,第一个元素是证书路径,第二个是密码:

<?php

$client->request('GET', '/', ['cert' => ['/path/server.pem', 'password']]);

connect_timeout

默认情况下,CodeIgniter 不限制 cURL 连接网站的时间。可通过 connect_timeout 选项修改(单位:秒),0 表示无限等待:

<?php

$client->request('GET', 'http://example.com', ['connect_timeout' => 0]);

debug

debug 设为 true 时,将启用额外调试信息并输出到 STDERR。

这是通过设置 CURLOPT_VERBOSE 并回显输出来实现的。使用 spark serve 运行内置服务器时,输出将显示在控制台;否则写入服务器错误日志:

<?php

$client->request('GET', 'http://example.com', ['debug' => true]);

可将文件名作为 debug 的值来将输出写入文件:

<?php

$client->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']);

delay

允许在发送请求前暂停指定毫秒数:

<?php

// Delay for 2 seconds
$client->request('GET', 'http://example.com', ['delay' => 2000]);

form_params

通过 form_params 选项发送 application/x-www-form-urlencoded POST 请求的关联数组。如果未设置,会将 Content-Type 标头设为 application/x-www-form-urlencoded

<?php

$client->request('POST', '/post', [
    'form_params' => [
        'foo' => 'bar',
        'baz' => ['hi', 'there'],
    ],
]);

备注

form_params 不能与 multipart 选项共用。对于 application/x-www-form-urlencoded 请求使用 form_params,对于 multipart/form-data 请求使用 multipart

headers

虽然可以使用 setHeader() 方法设置请求需要的标头,也可以通过选项传递关联数组。每个键是标头名称,值是该标头字段值的字符串或字符串数组:

<?php

$client->request('GET', '/', [
    'headers' => [
        'User-Agent' => 'testing/1.0',
        'Accept'     => 'application/json',
        'X-Foo'      => ['Bar', 'Baz'],
    ],
]);

如果标头在构造函数中传递,它们将被视为默认值,会被后续标头数组或 setHeader() 调用覆盖。

http_errors

默认情况下,当返回的 HTTP 状态码大于等于 400 时,CURLRequest 会抛出 HTTPException

若需查看响应正文,可将 http_errors 设为 false 以返回内容:

<?php

$client->request('GET', '/status/500');
// If the response code is 500, an HTTPException is thrown,
// and a detailed error report is displayed if in development mode.

$response = $client->request('GET', '/status/500', ['http_errors' => false]);
echo $response->getStatusCode(); // 500
echo $response->getBody();       // You can see the response body.

json

json 选项用于轻松上传 JSON 编码数据作为请求正文。会添加 application/json 的 Content-Type 标头,覆盖已设置的任何 Content-Type。数据可以是 json_encode() 接受的任何值:

<?php

$response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]);

备注

此选项不允许自定义 json_encode() 函数或 Content-Type 标头。如需此功能,需手动编码数据并通过 CURLRequest 的 setBody() 方法传递,同时使用 setHeader() 方法设置 Content-Type。

multipart

需要通过 POST 请求发送文件和其他数据时,可使用 multipart 选项和 CURLFile 类

值应为要发送的 POST 数据关联数组。为安全起见,已禁用通过前缀 @ 上传文件的旧方法。要发送的文件必须作为 CURLFile 实例传递:

<?php

$client->request('POST', '/post', [
    'multipart' => [
        'foo'      => 'bar',
        'userfile' => new \CURLFile('/path/to/file.txt'),
    ],
]);

备注

multipart 不能与 form_params 选项共用。对于 application/x-www-form-urlencoded 请求使用 form_params,对于 multipart/form-data 请求使用 multipart

proxy

在 4.4.0 版本加入.

可通过传递关联数组作为 proxy 选项来设置代理:

<?php

$client->request(
    'GET',
    'http://example.com',
    ['proxy' => 'http://localhost:3128'],
);

query

通过传递关联数组作为 query 选项来发送查询字符串参数:

<?php

// Send a GET request to /get?foo=bar
$client->request('GET', '/get', ['query' => ['foo' => 'bar']]);

timeout

默认情况下,cURL 函数执行没有时间限制。可通过 timeout 选项修改(单位:秒),0 表示无限等待:

<?php

$client->request('GET', 'http://example.com', ['timeout' => 5]);

user_agent

指定请求的 User Agent:

<?php

$client->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']);

verify

此选项描述 SSL 证书验证行为。若 verifytrue,启用 SSL 证书验证并使用操作系统提供的默认 CA 包。设为 false 将禁用验证(不安全,允许中间人攻击)。设为自定义证书路径可启用验证。默认值为 true:

<?php

// Use the system's CA bundle (this is the default setting)
$client->request('GET', '/', ['verify' => true]);

// Use a custom SSL certificate on disk.
$client->request('GET', '/', ['verify' => '/path/to/cert.pem']);

// Disable validation entirely. (Insecure!)
$client->request('GET', '/', ['verify' => false]);

force_ip_resolve

在 4.6.0 版本加入.

设置 HTTP 处理器使用 v4 (仅 IPv4)或 v6 (IPv6)协议:

<?php

// Force ipv4 resolve
$client->request('GET', '/', ['force_ip_resolve' => 'v4']); // v4 or v6

version

要设置使用的 HTTP 协议版本,可传递版本号字符串或浮点数(通常为 1.01.1,v4.3.0 起支持 2.0):

<?php

// Force HTTP/1.0
$client->request('GET', '/', ['version' => 1.0]);