wp/wp-includes/Requests/src/Transport/Curl.php
author ymh <ymh.work@gmail.com>
Mon, 08 Sep 2025 19:44:41 +0200
changeset 23 417f20492bf7
parent 21 48c4eec2b7e6
permissions -rw-r--r--
Update Docker configuration and plugin versions - Upgrade MariaDB from 10.6 to 11 with auto-upgrade support - Add WordPress debug environment variable to FPM container - Update PHP-FPM Dockerfile base image - Update Include Mastodon Feed plugin with bug fixes and improvements - Update Portfolio plugin (v2.58) with latest translations and demo data enhancements - Remove old README.md from Mastodon Feed plugin 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
21
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
<?php
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
 * cURL HTTP transport
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
 * @package Requests\Transport
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
namespace WpOrg\Requests\Transport;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
use RecursiveArrayIterator;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
use RecursiveIteratorIterator;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
use WpOrg\Requests\Capability;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
use WpOrg\Requests\Exception;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
use WpOrg\Requests\Exception\InvalidArgument;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
use WpOrg\Requests\Exception\Transport\Curl as CurlException;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
use WpOrg\Requests\Requests;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
use WpOrg\Requests\Transport;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
use WpOrg\Requests\Utility\InputValidator;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
 * cURL HTTP transport
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
 * @package Requests\Transport
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
final class Curl implements Transport {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
	const CURL_7_10_5 = 0x070A05;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
	const CURL_7_16_2 = 0x071002;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
	 * Raw HTTP data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
	 * @var string
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
	public $headers = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
	 * Raw body data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
	 * @var string
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
	public $response_data = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
	 * Information on the current request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
	 * @var array cURL information array, see {@link https://www.php.net/curl_getinfo}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
	public $info;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
	 * cURL version number
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
	 * @var int
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
	public $version;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
	 * cURL handle
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
	 * @var resource|\CurlHandle Resource in PHP < 8.0, Instance of CurlHandle in PHP >= 8.0.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
	private $handle;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
	 * Hook dispatcher instance
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
	 * @var \WpOrg\Requests\Hooks
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
	private $hooks;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
	 * Have we finished the headers yet?
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
	 * @var boolean
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
	private $done_headers = false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
	 * If streaming to a file, keep the file pointer
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
	 * @var resource
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
	private $stream_handle;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
	 * How many bytes are in the response body?
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
	 * @var int
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
	private $response_bytes;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
	 * What's the maximum number of bytes we should keep?
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
	 * @var int|bool Byte count, or false if no limit.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
	private $response_byte_limit;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
	 * Constructor
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
	public function __construct() {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
		$curl          = curl_version();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
		$this->version = $curl['version_number'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
		$this->handle  = curl_init();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
		curl_setopt($this->handle, CURLOPT_HEADER, false);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
		curl_setopt($this->handle, CURLOPT_RETURNTRANSFER, 1);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
		if ($this->version >= self::CURL_7_10_5) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
			curl_setopt($this->handle, CURLOPT_ENCODING, '');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
		if (defined('CURLOPT_PROTOCOLS')) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_protocolsFound
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
			curl_setopt($this->handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
		if (defined('CURLOPT_REDIR_PROTOCOLS')) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_redir_protocolsFound
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
			curl_setopt($this->handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
	 * Destructor
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
	public function __destruct() {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
		if (is_resource($this->handle)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
			curl_close($this->handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
	 * Perform a request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
	 * @param string|Stringable $url URL to request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
	 * @param array $headers Associative array of request headers
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
	 * @return string Raw HTTP result
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $url argument is not a string or Stringable.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $headers argument is not an array.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $data parameter is not an array or string.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
	 * @throws \WpOrg\Requests\Exception       On a cURL error (`curlerror`)
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
	public function request($url, $headers = [], $data = [], $options = []) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
		if (InputValidator::is_string_or_stringable($url) === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
			throw InvalidArgument::create(1, '$url', 'string|Stringable', gettype($url));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
		if (is_array($headers) === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
			throw InvalidArgument::create(2, '$headers', 'array', gettype($headers));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
		if (!is_array($data) && !is_string($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
			if ($data === null) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
				$data = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
			} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
				throw InvalidArgument::create(3, '$data', 'array|string', gettype($data));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
		if (is_array($options) === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
			throw InvalidArgument::create(4, '$options', 'array', gettype($options));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
		$this->hooks = $options['hooks'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
		$this->setup_handle($url, $headers, $data, $options);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
		$options['hooks']->dispatch('curl.before_send', [&$this->handle]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
		if ($options['filename'] !== false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
			// phpcs:ignore WordPress.PHP.NoSilencedErrors -- Silenced the PHP native warning in favour of throwing an exception.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
			$this->stream_handle = @fopen($options['filename'], 'wb');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
			if ($this->stream_handle === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
				$error = error_get_last();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
				throw new Exception($error['message'], 'fopen');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
		$this->response_data       = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
		$this->response_bytes      = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
		$this->response_byte_limit = false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
		if ($options['max_bytes'] !== false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
			$this->response_byte_limit = $options['max_bytes'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
		if (isset($options['verify'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
			if ($options['verify'] === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
				curl_setopt($this->handle, CURLOPT_SSL_VERIFYPEER, 0);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
			} elseif (is_string($options['verify'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
				curl_setopt($this->handle, CURLOPT_CAINFO, $options['verify']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
		if (isset($options['verifyname']) && $options['verifyname'] === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
			curl_setopt($this->handle, CURLOPT_SSL_VERIFYHOST, 0);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
		curl_exec($this->handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
		$response = $this->response_data;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
		$options['hooks']->dispatch('curl.after_send', []);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
		if (curl_errno($this->handle) === CURLE_WRITE_ERROR || curl_errno($this->handle) === CURLE_BAD_CONTENT_ENCODING) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
			// Reset encoding and try again
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
			curl_setopt($this->handle, CURLOPT_ENCODING, 'none');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
			$this->response_data  = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
			$this->response_bytes = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
			curl_exec($this->handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
			$response = $this->response_data;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
		$this->process_response($response, $options);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
		// Need to remove the $this reference from the curl handle.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
		// Otherwise \WpOrg\Requests\Transport\Curl won't be garbage collected and the curl_close() will never be called.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
		curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, null);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
		curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, null);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
		return $this->headers;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
	 * Send multiple requests simultaneously
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
	 * @param array $requests Request data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
	 * @param array $options Global options
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
	 * @return array Array of \WpOrg\Requests\Response objects (may contain \WpOrg\Requests\Exception or string responses as well)
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $requests argument is not an array or iterable object with array access.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
	 * @throws \WpOrg\Requests\Exception\InvalidArgument When the passed $options argument is not an array.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
	public function request_multiple($requests, $options) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
		// If you're not requesting, we can't get any responses ¯\_(ツ)_/¯
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
		if (empty($requests)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
			return [];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
		if (InputValidator::has_array_access($requests) === false || InputValidator::is_iterable($requests) === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
			throw InvalidArgument::create(1, '$requests', 'array|ArrayAccess&Traversable', gettype($requests));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   248
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   249
		if (is_array($options) === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   250
			throw InvalidArgument::create(2, '$options', 'array', gettype($options));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   251
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   252
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   253
		$multihandle = curl_multi_init();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   254
		$subrequests = [];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   255
		$subhandles  = [];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   256
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   257
		$class = get_class($this);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   258
		foreach ($requests as $id => $request) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   259
			$subrequests[$id] = new $class();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   260
			$subhandles[$id]  = $subrequests[$id]->get_subrequest_handle($request['url'], $request['headers'], $request['data'], $request['options']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   261
			$request['options']['hooks']->dispatch('curl.before_multi_add', [&$subhandles[$id]]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   262
			curl_multi_add_handle($multihandle, $subhandles[$id]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   263
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   264
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   265
		$completed       = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   266
		$responses       = [];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   267
		$subrequestcount = count($subrequests);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   268
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   269
		$request['options']['hooks']->dispatch('curl.before_multi_exec', [&$multihandle]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   270
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   271
		do {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   272
			$active = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   273
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   274
			do {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   275
				$status = curl_multi_exec($multihandle, $active);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   276
			} while ($status === CURLM_CALL_MULTI_PERFORM);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   277
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   278
			$to_process = [];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   279
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   280
			// Read the information as needed
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   281
			while ($done = curl_multi_info_read($multihandle)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   282
				$key = array_search($done['handle'], $subhandles, true);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   283
				if (!isset($to_process[$key])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   284
					$to_process[$key] = $done;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   285
				}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   286
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   287
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   288
			// Parse the finished requests before we start getting the new ones
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   289
			foreach ($to_process as $key => $done) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   290
				$options = $requests[$key]['options'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   291
				if ($done['result'] !== CURLE_OK) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   292
					//get error string for handle.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   293
					$reason          = curl_error($done['handle']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   294
					$exception       = new CurlException(
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   295
						$reason,
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   296
						CurlException::EASY,
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   297
						$done['handle'],
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   298
						$done['result']
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   299
					);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   300
					$responses[$key] = $exception;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   301
					$options['hooks']->dispatch('transport.internal.parse_error', [&$responses[$key], $requests[$key]]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   302
				} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   303
					$responses[$key] = $subrequests[$key]->process_response($subrequests[$key]->response_data, $options);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   304
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   305
					$options['hooks']->dispatch('transport.internal.parse_response', [&$responses[$key], $requests[$key]]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   306
				}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   307
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   308
				curl_multi_remove_handle($multihandle, $done['handle']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   309
				curl_close($done['handle']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   310
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   311
				if (!is_string($responses[$key])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   312
					$options['hooks']->dispatch('multiple.request.complete', [&$responses[$key], $key]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   313
				}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   314
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   315
				$completed++;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   316
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   317
		} while ($active || $completed < $subrequestcount);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   318
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   319
		$request['options']['hooks']->dispatch('curl.after_multi_exec', [&$multihandle]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   320
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   321
		curl_multi_close($multihandle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   322
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   323
		return $responses;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   324
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   325
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   326
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   327
	 * Get the cURL handle for use in a multi-request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   328
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   329
	 * @param string $url URL to request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   330
	 * @param array $headers Associative array of request headers
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   331
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   332
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   333
	 * @return resource|\CurlHandle Subrequest's cURL handle
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   334
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   335
	public function &get_subrequest_handle($url, $headers, $data, $options) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   336
		$this->setup_handle($url, $headers, $data, $options);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   337
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   338
		if ($options['filename'] !== false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   339
			$this->stream_handle = fopen($options['filename'], 'wb');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   340
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   341
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   342
		$this->response_data       = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   343
		$this->response_bytes      = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   344
		$this->response_byte_limit = false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   345
		if ($options['max_bytes'] !== false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   346
			$this->response_byte_limit = $options['max_bytes'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   347
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   348
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   349
		$this->hooks = $options['hooks'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   350
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   351
		return $this->handle;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   352
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   353
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   354
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   355
	 * Setup the cURL handle for the given data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   356
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   357
	 * @param string $url URL to request
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   358
	 * @param array $headers Associative array of request headers
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   359
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   360
	 * @param array $options Request options, see {@see \WpOrg\Requests\Requests::response()} for documentation
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   361
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   362
	private function setup_handle($url, $headers, $data, $options) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   363
		$options['hooks']->dispatch('curl.before_request', [&$this->handle]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   364
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   365
		// Force closing the connection for old versions of cURL (<7.22).
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   366
		if (!isset($headers['Connection'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   367
			$headers['Connection'] = 'close';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   368
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   369
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   370
		/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   371
		 * Add "Expect" header.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   372
		 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   373
		 * By default, cURL adds a "Expect: 100-Continue" to most requests. This header can
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   374
		 * add as much as a second to the time it takes for cURL to perform a request. To
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   375
		 * prevent this, we need to set an empty "Expect" header. To match the behaviour of
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   376
		 * Guzzle, we'll add the empty header to requests that are smaller than 1 MB and use
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   377
		 * HTTP/1.1.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   378
		 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   379
		 * https://curl.se/mail/lib-2017-07/0013.html
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   380
		 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   381
		if (!isset($headers['Expect']) && $options['protocol_version'] === 1.1) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   382
			$headers['Expect'] = $this->get_expect_header($data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   383
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   384
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   385
		$headers = Requests::flatten($headers);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   386
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   387
		if (!empty($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   388
			$data_format = $options['data_format'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   389
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   390
			if ($data_format === 'query') {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   391
				$url  = self::format_get($url, $data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   392
				$data = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   393
			} elseif (!is_string($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   394
				$data = http_build_query($data, '', '&');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   395
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   396
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   397
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   398
		switch ($options['type']) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   399
			case Requests::POST:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   400
				curl_setopt($this->handle, CURLOPT_POST, true);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   401
				curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   402
				break;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   403
			case Requests::HEAD:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   404
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   405
				curl_setopt($this->handle, CURLOPT_NOBODY, true);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   406
				break;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   407
			case Requests::TRACE:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   408
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   409
				break;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   410
			case Requests::PATCH:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   411
			case Requests::PUT:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   412
			case Requests::DELETE:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   413
			case Requests::OPTIONS:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   414
			default:
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   415
				curl_setopt($this->handle, CURLOPT_CUSTOMREQUEST, $options['type']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   416
				if (!empty($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   417
					curl_setopt($this->handle, CURLOPT_POSTFIELDS, $data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   418
				}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   419
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   420
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   421
		// cURL requires a minimum timeout of 1 second when using the system
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   422
		// DNS resolver, as it uses `alarm()`, which is second resolution only.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   423
		// There's no way to detect which DNS resolver is being used from our
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   424
		// end, so we need to round up regardless of the supplied timeout.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   425
		//
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   426
		// https://github.com/curl/curl/blob/4f45240bc84a9aa648c8f7243be7b79e9f9323a5/lib/hostip.c#L606-L609
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   427
		$timeout = max($options['timeout'], 1);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   428
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   429
		if (is_int($timeout) || $this->version < self::CURL_7_16_2) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   430
			curl_setopt($this->handle, CURLOPT_TIMEOUT, ceil($timeout));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   431
		} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   432
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_timeout_msFound
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   433
			curl_setopt($this->handle, CURLOPT_TIMEOUT_MS, round($timeout * 1000));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   434
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   435
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   436
		if (is_int($options['connect_timeout']) || $this->version < self::CURL_7_16_2) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   437
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT, ceil($options['connect_timeout']));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   438
		} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   439
			// phpcs:ignore PHPCompatibility.Constants.NewConstants.curlopt_connecttimeout_msFound
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   440
			curl_setopt($this->handle, CURLOPT_CONNECTTIMEOUT_MS, round($options['connect_timeout'] * 1000));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   441
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   442
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   443
		curl_setopt($this->handle, CURLOPT_URL, $url);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   444
		curl_setopt($this->handle, CURLOPT_USERAGENT, $options['useragent']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   445
		if (!empty($headers)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   446
			curl_setopt($this->handle, CURLOPT_HTTPHEADER, $headers);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   447
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   448
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   449
		if ($options['protocol_version'] === 1.1) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   450
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   451
		} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   452
			curl_setopt($this->handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   453
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   454
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   455
		if ($options['blocking'] === true) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   456
			curl_setopt($this->handle, CURLOPT_HEADERFUNCTION, [$this, 'stream_headers']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   457
			curl_setopt($this->handle, CURLOPT_WRITEFUNCTION, [$this, 'stream_body']);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   458
			curl_setopt($this->handle, CURLOPT_BUFFERSIZE, Requests::BUFFER_SIZE);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   459
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   460
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   461
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   462
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   463
	 * Process a response
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   464
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   465
	 * @param string $response Response data from the body
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   466
	 * @param array $options Request options
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   467
	 * @return string|false HTTP response data including headers. False if non-blocking.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   468
	 * @throws \WpOrg\Requests\Exception If the request resulted in a cURL error.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   469
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   470
	public function process_response($response, $options) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   471
		if ($options['blocking'] === false) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   472
			$fake_headers = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   473
			$options['hooks']->dispatch('curl.after_request', [&$fake_headers]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   474
			return false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   475
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   476
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   477
		if ($options['filename'] !== false && $this->stream_handle) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   478
			fclose($this->stream_handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   479
			$this->headers = trim($this->headers);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   480
		} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   481
			$this->headers .= $response;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   482
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   483
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   484
		if (curl_errno($this->handle)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   485
			$error = sprintf(
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   486
				'cURL error %s: %s',
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   487
				curl_errno($this->handle),
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   488
				curl_error($this->handle)
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   489
			);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   490
			throw new Exception($error, 'curlerror', $this->handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   491
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   492
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   493
		$this->info = curl_getinfo($this->handle);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   494
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   495
		$options['hooks']->dispatch('curl.after_request', [&$this->headers, &$this->info]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   496
		return $this->headers;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   497
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   498
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   499
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   500
	 * Collect the headers as they are received
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   501
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   502
	 * @param resource|\CurlHandle $handle cURL handle
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   503
	 * @param string $headers Header string
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   504
	 * @return integer Length of provided header
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   505
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   506
	public function stream_headers($handle, $headers) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   507
		// Why do we do this? cURL will send both the final response and any
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   508
		// interim responses, such as a 100 Continue. We don't need that.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   509
		// (We may want to keep this somewhere just in case)
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   510
		if ($this->done_headers) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   511
			$this->headers      = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   512
			$this->done_headers = false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   513
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   514
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   515
		$this->headers .= $headers;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   516
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   517
		if ($headers === "\r\n") {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   518
			$this->done_headers = true;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   519
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   520
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   521
		return strlen($headers);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   522
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   523
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   524
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   525
	 * Collect data as it's received
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   526
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   527
	 * @since 1.6.1
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   528
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   529
	 * @param resource|\CurlHandle $handle cURL handle
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   530
	 * @param string $data Body data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   531
	 * @return integer Length of provided data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   532
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   533
	public function stream_body($handle, $data) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   534
		$this->hooks->dispatch('request.progress', [$data, $this->response_bytes, $this->response_byte_limit]);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   535
		$data_length = strlen($data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   536
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   537
		// Are we limiting the response size?
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   538
		if ($this->response_byte_limit) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   539
			if ($this->response_bytes === $this->response_byte_limit) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   540
				// Already at maximum, move on
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   541
				return $data_length;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   542
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   543
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   544
			if (($this->response_bytes + $data_length) > $this->response_byte_limit) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   545
				// Limit the length
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   546
				$limited_length = ($this->response_byte_limit - $this->response_bytes);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   547
				$data           = substr($data, 0, $limited_length);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   548
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   549
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   550
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   551
		if ($this->stream_handle) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   552
			fwrite($this->stream_handle, $data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   553
		} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   554
			$this->response_data .= $data;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   555
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   556
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   557
		$this->response_bytes += strlen($data);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   558
		return $data_length;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   559
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   560
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   561
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   562
	 * Format a URL given GET data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   563
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   564
	 * @param string       $url  Original URL.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   565
	 * @param array|object $data Data to build query using, see {@link https://www.php.net/http_build_query}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   566
	 * @return string URL with data
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   567
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   568
	private static function format_get($url, $data) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   569
		if (!empty($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   570
			$query     = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   571
			$url_parts = parse_url($url);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   572
			if (empty($url_parts['query'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   573
				$url_parts['query'] = '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   574
			} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   575
				$query = $url_parts['query'];
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   576
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   577
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   578
			$query .= '&' . http_build_query($data, '', '&');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   579
			$query  = trim($query, '&');
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   580
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   581
			if (empty($url_parts['query'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   582
				$url .= '?' . $query;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   583
			} else {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   584
				$url = str_replace($url_parts['query'], $query, $url);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   585
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   586
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   587
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   588
		return $url;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   589
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   590
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   591
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   592
	 * Self-test whether the transport can be used.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   593
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   594
	 * The available capabilities to test for can be found in {@see \WpOrg\Requests\Capability}.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   595
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   596
	 * @codeCoverageIgnore
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   597
	 * @param array<string, bool> $capabilities Optional. Associative array of capabilities to test against, i.e. `['<capability>' => true]`.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   598
	 * @return bool Whether the transport can be used.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   599
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   600
	public static function test($capabilities = []) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   601
		if (!function_exists('curl_init') || !function_exists('curl_exec')) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   602
			return false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   603
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   604
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   605
		// If needed, check that our installed curl version supports SSL
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   606
		if (isset($capabilities[Capability::SSL]) && $capabilities[Capability::SSL]) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   607
			$curl_version = curl_version();
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   608
			if (!(CURL_VERSION_SSL & $curl_version['features'])) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   609
				return false;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   610
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   611
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   612
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   613
		return true;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   614
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   615
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   616
	/**
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   617
	 * Get the correct "Expect" header for the given request data.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   618
	 *
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   619
	 * @param string|array $data Data to send either as the POST body, or as parameters in the URL for a GET/HEAD.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   620
	 * @return string The "Expect" header.
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   621
	 */
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   622
	private function get_expect_header($data) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   623
		if (!is_array($data)) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   624
			return strlen((string) $data) >= 1048576 ? '100-Continue' : '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   625
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   626
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   627
		$bytesize = 0;
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   628
		$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($data));
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   629
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   630
		foreach ($iterator as $datum) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   631
			$bytesize += strlen((string) $datum);
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   632
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   633
			if ($bytesize >= 1048576) {
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   634
				return '100-Continue';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   635
			}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   636
		}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   637
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   638
		return '';
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   639
	}
48c4eec2b7e6 Add CLAUDE.md documentation and sync WordPress core files
ymh <ymh.work@gmail.com>
parents:
diff changeset
   640
}