CURLRequest 类

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

这个类模仿了 Guzzle 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,由于一个 bug,请求消息体也不会被重置。

加载库

可以通过手动方式或通过 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 请求非常简单,只需创建请求并获取返回的 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 在 safe_mode 中或启用 open_basedir 时,跟随重定向将不起作用。

auth

允许你为 HTTP 基本认证摘要认证 提供认证细节。你的脚本可能需要做额外的工作来支持摘要认证 - 这只是简单地为你传递用户名和密码。值必须是一个数组,其中第一个元素是用户名,第二个是密码。第三个参数应该是要使用的认证类型,可以是 basicdigest:

<?php

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

body

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

<?php

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

第二种方法是通过传递一个 body 选项。这是为了保持 Guzzle API 的兼容性,功能完全相同。值必须是一个字符串:

<?php

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

cert

要指定客户端证书的位置,需要以字符串形式传递包含完整路径的 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 编码的数据作为请求的 body 上传。添加了 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 选项一起使用。你只能使用其中一个。使用 form_params 进行 application/x-www-form-urlencoded 请求,使用 multipart 进行 multipart/form-data 请求。

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

允许指定请求的用户代理:

<?php

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

verify

此选项描述了 SSL 证书验证行为。如果 verify 选项为 true,它将启用 SSL 证书验证并使用操作系统提供的默认 CA 包。如果设置为 false,它将禁用证书验证(这是不安全的,并允许中间人攻击!)。你可以将其设置为包含 CA 包路径的字符串,以使用自定义证书启用验证。默认值为 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]);

version

要设置要使用的 HTTP 协议,你可以传递带有版本号的字符串或浮点数(通常为 1.01.1,v4.3.0 开始支持 2.0)。

<?php

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