1<?php
2/**
3 * Feed API: WP_SimplePie_File class
4 *
5 * @package WordPress
6 * @subpackage Feed
7 * @since 4.7.0
8 */
9
10/**
11 * Core class for fetching remote files and reading local files with SimplePie.
12 *
13 * This uses Core's HTTP API to make requests, which gives plugins the ability
14 * to hook into the process.
15 *
16 * @since 2.8.0
17 */
18#[AllowDynamicProperties]
19class WP_SimplePie_File extends SimplePie\File {
20
21 /**
22 * Timeout.
23 *
24 * @var int How long the connection should stay open in seconds.
25 */
26 public $timeout = 10;
27
28 /**
29 * Constructor.
30 *
31 * @since 2.8.0
32 * @since 3.2.0 Updated to use a PHP5 constructor.
33 * @since 5.6.1 Multiple headers are concatenated into a comma-separated string,
34 * rather than remaining an array.
35 *
36 * @param string $url Remote file URL.
37 * @param int $timeout Optional. How long the connection should stay open in seconds.
38 * Default 10.
39 * @param int $redirects Optional. The number of allowed redirects. Default 5.
40 * @param string|array $headers Optional. Array or string of headers to send with the request.
41 * Default null.
42 * @param string $useragent Optional. User-agent value sent. Default null.
43 * @param bool $force_fsockopen Optional. Whether to force opening internet or unix domain socket
44 * connection or not. Default false.
45 */
46 public function __construct( $url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false ) {
47 $this->url = $url;
48 $this->timeout = $timeout;
49 $this->redirects = $redirects;
50 $this->headers = $headers;
51 $this->useragent = $useragent;
52
53 $this->method = SimplePie\SimplePie::FILE_SOURCE_REMOTE;
54
55 if ( preg_match( '/^http(s)?:\/\//i', $url ) ) {
56 $args = array(
57 'timeout' => $this->timeout,
58 'redirection' => $this->redirects,
59 );
60
61 if ( ! empty( $this->headers ) ) {
62 $args['headers'] = $this->headers;
63 }
64
65 if ( SimplePie\Misc::get_default_useragent() !== $this->useragent ) { // Use default WP user agent unless custom has been specified.
66 $args['user-agent'] = $this->useragent;
67 }
68
69 $res = wp_safe_remote_request( $url, $args );
70
71 if ( is_wp_error( $res ) ) {
72 $this->error = 'WP HTTP Error: ' . $res->get_error_message();
73 $this->success = false;
74
75 } else {
76 $this->headers = wp_remote_retrieve_headers( $res );
77
78 if ( $this->headers instanceof \WpOrg\Requests\Utility\CaseInsensitiveDictionary ) {
79 $this->headers = $this->headers->getAll();
80 }
81
82 /*
83 * SimplePie expects multiple headers to be stored as a comma-separated string,
84 * but `wp_remote_retrieve_headers()` returns them as an array, so they need
85 * to be converted.
86 *
87 * The only exception to that is the `content-type` header, which should ignore
88 * any previous values and only use the last one.
89 *
90 * @see SimplePie\HTTP\Parser::new_line().
91 */
92 foreach ( $this->headers as $name => $value ) {
93 if ( ! is_array( $value ) ) {
94 continue;
95 }
96
97 if ( 'content-type' === $name ) {
98 $this->headers[ $name ] = array_pop( $value );
99 } else {
100 $this->headers[ $name ] = implode( ', ', $value );
101 }
102 }
103
104 $this->body = wp_remote_retrieve_body( $res );
105 $this->status_code = wp_remote_retrieve_response_code( $res );
106 }
107 } else {
108 $this->error = '';
109 $this->success = false;
110 }
111 }
112}
113