Diff: STRATO-apps/wordpress_03/app/wp-includes/class-wp-http-curl.php
Keine Baseline-Datei – Diff nur gegen leer.
1
-
1
+
<?php
2
+
/**
3
+
* HTTP API: WP_Http_Curl class
4
+
*
5
+
* @package WordPress
6
+
* @subpackage HTTP
7
+
* @since 4.4.0
8
+
*/
9
+
10
+
/**
11
+
* Core class used to integrate Curl as an HTTP transport.
12
+
*
13
+
* HTTP request method uses Curl extension to retrieve the url.
14
+
*
15
+
* Requires the Curl extension to be installed.
16
+
*
17
+
* @since 2.7.0
18
+
* @deprecated 6.4.0 Use WP_Http
19
+
* @see WP_Http
20
+
*/
21
+
#[AllowDynamicProperties]
22
+
class WP_Http_Curl {
23
+
24
+
/**
25
+
* Temporary header storage for during requests.
26
+
*
27
+
* @since 3.2.0
28
+
* @var string
29
+
*/
30
+
private $headers = '';
31
+
32
+
/**
33
+
* Temporary body storage for during requests.
34
+
*
35
+
* @since 3.6.0
36
+
* @var string
37
+
*/
38
+
private $body = '';
39
+
40
+
/**
41
+
* The maximum amount of data to receive from the remote server.
42
+
*
43
+
* @since 3.6.0
44
+
* @var int|false
45
+
*/
46
+
private $max_body_length = false;
47
+
48
+
/**
49
+
* The file resource used for streaming to file.
50
+
*
51
+
* @since 3.6.0
52
+
* @var resource|false
53
+
*/
54
+
private $stream_handle = false;
55
+
56
+
/**
57
+
* The total bytes written in the current request.
58
+
*
59
+
* @since 4.1.0
60
+
* @var int
61
+
*/
62
+
private $bytes_written_total = 0;
63
+
64
+
/**
65
+
* Send a HTTP request to a URI using cURL extension.
66
+
*
67
+
* @since 2.7.0
68
+
*
69
+
* @param string $url The request URL.
70
+
* @param string|array $args Optional. Override the defaults.
71
+
* @return array|WP_Error Array containing 'headers', 'body', 'response', 'cookies', 'filename'. A WP_Error instance upon error
72
+
*/
73
+
public function request( $url, $args = array() ) {
74
+
$defaults = array(
75
+
'method' => 'GET',
76
+
'timeout' => 5,
77
+
'redirection' => 5,
78
+
'httpversion' => '1.0',
79
+
'blocking' => true,
80
+
'headers' => array(),
81
+
'body' => null,
82
+
'cookies' => array(),
83
+
'decompress' => false,
84
+
'stream' => false,
85
+
'filename' => null,
86
+
);
87
+
88
+
$parsed_args = wp_parse_args( $args, $defaults );
89
+
90
+
if ( isset( $parsed_args['headers']['User-Agent'] ) ) {
91
+
$parsed_args['user-agent'] = $parsed_args['headers']['User-Agent'];
92
+
unset( $parsed_args['headers']['User-Agent'] );
93
+
} elseif ( isset( $parsed_args['headers']['user-agent'] ) ) {
94
+
$parsed_args['user-agent'] = $parsed_args['headers']['user-agent'];
95
+
unset( $parsed_args['headers']['user-agent'] );
96
+
}
97
+
98
+
// Construct Cookie: header if any cookies are set.
99
+
WP_Http::buildCookieHeader( $parsed_args );
100
+
101
+
$handle = curl_init();
102
+
103
+
// cURL offers really easy proxy support.
104
+
$proxy = new WP_HTTP_Proxy();
105
+
106
+
if ( $proxy->is_enabled() && $proxy->send_through_proxy( $url ) ) {
107
+
108
+
curl_setopt( $handle, CURLOPT_PROXYTYPE, CURLPROXY_HTTP );
109
+
curl_setopt( $handle, CURLOPT_PROXY, $proxy->host() );
110
+
curl_setopt( $handle, CURLOPT_PROXYPORT, $proxy->port() );
111
+
112
+
if ( $proxy->use_authentication() ) {
113
+
curl_setopt( $handle, CURLOPT_PROXYAUTH, CURLAUTH_ANY );
114
+
curl_setopt( $handle, CURLOPT_PROXYUSERPWD, $proxy->authentication() );
115
+
}
116
+
}
117
+
118
+
$is_local = isset( $parsed_args['local'] ) && $parsed_args['local'];
119
+
$ssl_verify = isset( $parsed_args['sslverify'] ) && $parsed_args['sslverify'];
120
+
if ( $is_local ) {
121
+
/** This filter is documented in wp-includes/class-wp-http-streams.php */
122
+
$ssl_verify = apply_filters( 'https_local_ssl_verify', $ssl_verify, $url );
123
+
} elseif ( ! $is_local ) {
124
+
/** This filter is documented in wp-includes/class-wp-http.php */
125
+
$ssl_verify = apply_filters( 'https_ssl_verify', $ssl_verify, $url );
126
+
}
127
+
128
+
/*
129
+
* CURLOPT_TIMEOUT and CURLOPT_CONNECTTIMEOUT expect integers. Have to use ceil since.
130
+
* a value of 0 will allow an unlimited timeout.
131
+
*/
132
+
$timeout = (int) ceil( $parsed_args['timeout'] );
133
+
curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, $timeout );
134
+
curl_setopt( $handle, CURLOPT_TIMEOUT, $timeout );
135
+
136
+
curl_setopt( $handle, CURLOPT_URL, $url );
137
+
curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true );
138
+
curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, ( true === $ssl_verify ) ? 2 : false );
139
+
curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, $ssl_verify );
140
+
141
+
if ( $ssl_verify ) {
142
+
curl_setopt( $handle, CURLOPT_CAINFO, $parsed_args['sslcertificates'] );
143
+
}
144
+
145
+
curl_setopt( $handle, CURLOPT_USERAGENT, $parsed_args['user-agent'] );
146
+
147
+
/*
148
+
* The option doesn't work with safe mode or when open_basedir is set, and there's
149
+
* a bug #17490 with redirected POST requests, so handle redirections outside Curl.
150
+
*/
151
+
curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, false );
152
+
curl_setopt( $handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS );
153
+
154
+
switch ( $parsed_args['method'] ) {
155
+
case 'HEAD':
156
+
curl_setopt( $handle, CURLOPT_NOBODY, true );
157
+
break;
158
+
case 'POST':
159
+
curl_setopt( $handle, CURLOPT_POST, true );
160
+
curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] );
161
+
break;
162
+
case 'PUT':
163
+
curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, 'PUT' );
164
+
curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] );
165
+
break;
166
+
default:
167
+
curl_setopt( $handle, CURLOPT_CUSTOMREQUEST, $parsed_args['method'] );
168
+
if ( ! is_null( $parsed_args['body'] ) ) {
169
+
curl_setopt( $handle, CURLOPT_POSTFIELDS, $parsed_args['body'] );
170
+
}
171
+
break;
172
+
}
173
+
174
+
if ( true === $parsed_args['blocking'] ) {
175
+
curl_setopt( $handle, CURLOPT_HEADERFUNCTION, array( $this, 'stream_headers' ) );
176
+
curl_setopt( $handle, CURLOPT_WRITEFUNCTION, array( $this, 'stream_body' ) );
177
+
}
178
+
179
+
curl_setopt( $handle, CURLOPT_HEADER, false );
180
+
181
+
if ( isset( $parsed_args['limit_response_size'] ) ) {
182
+
$this->max_body_length = (int) $parsed_args['limit_response_size'];
183
+
} else {
184
+
$this->max_body_length = false;
185
+
}
186
+
187
+
// If streaming to a file open a file handle, and setup our curl streaming handler.
188
+
if ( $parsed_args['stream'] ) {
189
+
if ( ! WP_DEBUG ) {
190
+
$this->stream_handle = @fopen( $parsed_args['filename'], 'w+' );
191
+
} else {
192
+
$this->stream_handle = fopen( $parsed_args['filename'], 'w+' );
193
+
}
194
+
if ( ! $this->stream_handle ) {
195
+
return new WP_Error(
196
+
'http_request_failed',
197
+
sprintf(
198
+
/* translators: 1: fopen(), 2: File name. */
199
+
__( 'Could not open handle for %1$s to %2$s.' ),
200
+
'fopen()',
201
+
$parsed_args['filename']
202
+
)
203
+
);
204
+
}
205
+
} else {
206
+
$this->stream_handle = false;
207
+
}
208
+
209
+
if ( ! empty( $parsed_args['headers'] ) ) {
210
+
// cURL expects full header strings in each element.
211
+
$headers = array();
212
+
foreach ( $parsed_args['headers'] as $name => $value ) {
213
+
$headers[] = "{$name}: $value";
214
+
}
215
+
curl_setopt( $handle, CURLOPT_HTTPHEADER, $headers );
216
+
}
217
+
218
+
if ( '1.0' === $parsed_args['httpversion'] ) {
219
+
curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
220
+
} else {
221
+
curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1 );
222
+
}
223
+
224
+
/**
225
+
* Fires before the cURL request is executed.
226
+
*
227
+
* Cookies are not currently handled by the HTTP API. This action allows
228
+
* plugins to handle cookies themselves.
229
+
*
230
+
* @since 2.8.0
231
+
*
232
+
* @param resource $handle The cURL handle returned by curl_init() (passed by reference).
233
+
* @param array $parsed_args The HTTP request arguments.
234
+
* @param string $url The request URL.
235
+
*/
236
+
do_action_ref_array( 'http_api_curl', array( &$handle, $parsed_args, $url ) );
237
+
238
+
// We don't need to return the body, so don't. Just execute request and return.
239
+
if ( ! $parsed_args['blocking'] ) {
240
+
curl_exec( $handle );
241
+
242
+
$curl_error = curl_error( $handle );
243
+
244
+
if ( $curl_error ) {
245
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
246
+
curl_close( $handle );
247
+
}
248
+
249
+
return new WP_Error( 'http_request_failed', $curl_error );
250
+
}
251
+
252
+
if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ), true ) ) {
253
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
254
+
curl_close( $handle );
255
+
}
256
+
257
+
return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
258
+
}
259
+
260
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
261
+
curl_close( $handle );
262
+
}
263
+
264
+
return array(
265
+
'headers' => array(),
266
+
'body' => '',
267
+
'response' => array(
268
+
'code' => false,
269
+
'message' => false,
270
+
),
271
+
'cookies' => array(),
272
+
);
273
+
}
274
+
275
+
curl_exec( $handle );
276
+
277
+
$processed_headers = WP_Http::processHeaders( $this->headers, $url );
278
+
$body = $this->body;
279
+
$bytes_written_total = $this->bytes_written_total;
280
+
281
+
$this->headers = '';
282
+
$this->body = '';
283
+
$this->bytes_written_total = 0;
284
+
285
+
$curl_error = curl_errno( $handle );
286
+
287
+
// If an error occurred, or, no response.
288
+
if ( $curl_error || ( 0 === strlen( $body ) && empty( $processed_headers['headers'] ) ) ) {
289
+
if ( CURLE_WRITE_ERROR /* 23 */ === $curl_error ) {
290
+
if ( ! $this->max_body_length || $this->max_body_length !== $bytes_written_total ) {
291
+
if ( $parsed_args['stream'] ) {
292
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
293
+
curl_close( $handle );
294
+
}
295
+
296
+
fclose( $this->stream_handle );
297
+
298
+
return new WP_Error( 'http_request_failed', __( 'Failed to write request to temporary file.' ) );
299
+
} else {
300
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
301
+
curl_close( $handle );
302
+
}
303
+
304
+
return new WP_Error( 'http_request_failed', curl_error( $handle ) );
305
+
}
306
+
}
307
+
} else {
308
+
$curl_error = curl_error( $handle );
309
+
310
+
if ( $curl_error ) {
311
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
312
+
curl_close( $handle );
313
+
}
314
+
315
+
return new WP_Error( 'http_request_failed', $curl_error );
316
+
}
317
+
}
318
+
319
+
if ( in_array( curl_getinfo( $handle, CURLINFO_HTTP_CODE ), array( 301, 302 ), true ) ) {
320
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
321
+
curl_close( $handle );
322
+
}
323
+
324
+
return new WP_Error( 'http_request_failed', __( 'Too many redirects.' ) );
325
+
}
326
+
}
327
+
328
+
if ( PHP_VERSION_ID < 80000 ) { // curl_close() has no effect as of PHP 8.0.
329
+
curl_close( $handle );
330
+
}
331
+
332
+
if ( $parsed_args['stream'] ) {
333
+
fclose( $this->stream_handle );
334
+
}
335
+
336
+
$response = array(
337
+
'headers' => $processed_headers['headers'],
338
+
'body' => null,
339
+
'response' => $processed_headers['response'],
340
+
'cookies' => $processed_headers['cookies'],
341
+
'filename' => $parsed_args['filename'],
342
+
);
343
+
344
+
// Handle redirects.
345
+
$redirect_response = WP_Http::handle_redirects( $url, $parsed_args, $response );
346
+
if ( false !== $redirect_response ) {
347
+
return $redirect_response;
348
+
}
349
+
350
+
if ( true === $parsed_args['decompress']
351
+
&& true === WP_Http_Encoding::should_decode( $processed_headers['headers'] )
352
+
) {
353
+
$body = WP_Http_Encoding::decompress( $body );
354
+
}
355
+
356
+
$response['body'] = $body;
357
+
358
+
return $response;
359
+
}
360
+
361
+
/**
362
+
* Grabs the headers of the cURL request.
363
+
*
364
+
* Each header is sent individually to this callback, and is appended to the `$header` property
365
+
* for temporary storage.
366
+
*
367
+
* @since 3.2.0
368
+
*
369
+
* @param resource $handle cURL handle.
370
+
* @param string $headers cURL request headers.
371
+
* @return int Length of the request headers.
372
+
*/
373
+
private function stream_headers( $handle, $headers ) {
374
+
$this->headers .= $headers;
375
+
return strlen( $headers );
376
+
}
377
+
378
+
/**
379
+
* Grabs the body of the cURL request.
380
+
*
381
+
* The contents of the document are passed in chunks, and are appended to the `$body`
382
+
* property for temporary storage. Returning a length shorter than the length of
383
+
* `$data` passed in will cause cURL to abort the request with `CURLE_WRITE_ERROR`.
384
+
*
385
+
* @since 3.6.0
386
+
*
387
+
* @param resource $handle cURL handle.
388
+
* @param string $data cURL request body.
389
+
* @return int Total bytes of data written.
390
+
*/
391
+
private function stream_body( $handle, $data ) {
392
+
$data_length = strlen( $data );
393
+
394
+
if ( $this->max_body_length && ( $this->bytes_written_total + $data_length ) > $this->max_body_length ) {
395
+
$data_length = ( $this->max_body_length - $this->bytes_written_total );
396
+
$data = substr( $data, 0, $data_length );
397
+
}
398
+
399
+
if ( $this->stream_handle ) {
400
+
$bytes_written = fwrite( $this->stream_handle, $data );
401
+
} else {
402
+
$this->body .= $data;
403
+
$bytes_written = $data_length;
404
+
}
405
+
406
+
$this->bytes_written_total += $bytes_written;
407
+
408
+
// Upon event of this function returning less than strlen( $data ) curl will error with CURLE_WRITE_ERROR.
409
+
return $bytes_written;
410
+
}
411
+
412
+
/**
413
+
* Determines whether this class can be used for retrieving a URL.
414
+
*
415
+
* @since 2.7.0
416
+
*
417
+
* @param array $args Optional. Array of request arguments. Default empty array.
418
+
* @return bool False means this class can not be used, true means it can.
419
+
*/
420
+
public static function test( $args = array() ) {
421
+
if ( ! function_exists( 'curl_init' ) || ! function_exists( 'curl_exec' ) ) {
422
+
return false;
423
+
}
424
+
425
+
$is_ssl = isset( $args['ssl'] ) && $args['ssl'];
426
+
427
+
if ( $is_ssl ) {
428
+
$curl_version = curl_version();
429
+
// Check whether this cURL version support SSL requests.
430
+
if ( ! ( CURL_VERSION_SSL & $curl_version['features'] ) ) {
431
+
return false;
432
+
}
433
+
}
434
+
435
+
/**
436
+
* Filters whether cURL can be used as a transport for retrieving a URL.
437
+
*
438
+
* @since 2.7.0
439
+
*
440
+
* @param bool $use_class Whether the class can be used. Default true.
441
+
* @param array $args An array of request arguments.
442
+
*/
443
+
return apply_filters( 'use_curl_transport', true, $args );
444
+
}
445
+
}
446
+