PluginProbe
UpdraftPlus: WP Backup & Migration Plugin / 1.16.5
UpdraftPlus: WP Backup & Migration Plugin v1.16.5
1.26.7 1.26.6 1.26.5 1.26.4 1.26.3 1.9.19 1.9.25 1.9.26 1.9.30 1.9.31 1.9.32 1.9.4 1.9.40 1.9.41 1.9.42 1.9.43 1.9.44 1.9.45 1.9.46 1.9.5 1.9.50 1.9.51 1.9.60 1.9.62 1.9.63 All 371 releases
updraftplus / includes / Google / IO / Stream.php

Stream.php in UpdraftPlus: WP Backup & Migration Plugin 1.16.5, at includes/Google/IO/Stream.php

282 lines 7.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Copyright 2013 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 /**
19 * Http Streams based implementation of Google_IO.
20 *
21 * @author Stuart Langley <slangley@google.com>
22 */
23
24 if (!class_exists('Google_Client')) {
25 require_once dirname(__FILE__) . '/../autoload.php';
26 }
27
28 class Google_IO_Stream extends Google_IO_Abstract
29 {
30 const TIMEOUT = "timeout";
31 const ZLIB = "compress.zlib://";
32 private $options = array();
33 private $trappedErrorNumber;
34 private $trappedErrorString;
35
36 private static $DEFAULT_HTTP_CONTEXT = array(
37 "follow_location" => 0,
38 "ignore_errors" => 1,
39 );
40
41 private static $DEFAULT_SSL_CONTEXT = array(
42 "verify_peer" => true,
43 );
44
45 public function __construct(Google_Client $client)
46 {
47 if (!ini_get('allow_url_fopen')) {
48 $error = 'The stream IO handler requires the allow_url_fopen runtime ' .
49 'configuration to be enabled';
50 $client->getLogger()->critical($error);
51 throw new Google_IO_Exception($error);
52 }
53
54 parent::__construct($client);
55 }
56
57 /**
58 * Execute an HTTP Request
59 *
60 * @param Google_Http_Request $request the http request to be executed
61 * @return array containing response headers, body, and http code
62 * @throws Google_IO_Exception on curl or IO error
63 */
64 public function executeRequest(Google_Http_Request $request)
65 {
66 $default_options = stream_context_get_options(stream_context_get_default());
67
68 $requestHttpContext = array_key_exists('http', $default_options) ?
69 $default_options['http'] : array();
70
71 if ($request->getPostBody()) {
72 $requestHttpContext["content"] = $request->getPostBody();
73 }
74
75 $requestHeaders = $request->getRequestHeaders();
76 if ($requestHeaders && is_array($requestHeaders)) {
77 $headers = "";
78 foreach ($requestHeaders as $k => $v) {
79 $headers .= "$k: $v\r\n";
80 }
81 $requestHttpContext["header"] = $headers;
82 }
83
84 $requestHttpContext["method"] = $request->getRequestMethod();
85 $requestHttpContext["user_agent"] = $request->getUserAgent();
86
87 $requestSslContext = array_key_exists('ssl', $default_options) ?
88 $default_options['ssl'] : array();
89
90 # UpdraftPlus patch
91 // if (!array_key_exists("cafile", $requestSslContext)) {
92 // $requestSslContext["cafile"] = dirname(__FILE__) . '/cacerts.pem';
93 // }
94
95 $url = $request->getUrl();
96
97 if (preg_match('#^https?://([^/]+)/#', $url, $umatches)) { $cname = $umatches[1]; } else { $cname = false; }
98
99 # UpdraftPlus patch
100 // Added
101 if (empty($this->options['disable_verify_peer'])) {
102 $requestSslContext['verify_peer'] = true;
103 if (version_compare(PHP_VERSION, '5.6.0', '>=')) {
104 if (!empty($cname)) $requestSslContext['peer_name'] = $cname;
105 } else {
106 if (!empty($cname)) {
107 $requestSslContext['CN_match'] = $cname;
108 $retry_on_fail = true;
109 }
110 }
111 } else {
112 $requestSslContext['allow_self_signed'] = true;
113 }
114 if (!empty($this->options['cafile'])) $requestSslContext['cafile'] = $this->options['cafile'];
115
116 $options = array(
117 "http" => array_merge(
118 self::$DEFAULT_HTTP_CONTEXT,
119 $requestHttpContext
120 ),
121 "ssl" => array_merge(
122 # UpdraftPlus patch
123 // self::$DEFAULT_SSL_CONTEXT,
124 $requestSslContext
125 )
126 );
127
128 $context = stream_context_create($options);
129
130 # UpdraftPlus patch
131 // $url = $request->getUrl();
132
133 if ($request->canGzip()) {
134 $url = self::ZLIB . $url;
135 }
136
137 $this->client->getLogger()->debug(
138 'Stream request',
139 array(
140 'url' => $url,
141 'method' => $request->getRequestMethod(),
142 'headers' => $requestHeaders,
143 'body' => $request->getPostBody()
144 )
145 );
146
147 // We are trapping any thrown errors in this method only and
148 // throwing an exception.
149 $this->trappedErrorNumber = null;
150 $this->trappedErrorString = null;
151
152 // START - error trap.
153 set_error_handler(array($this, 'trapError'));
154 $fh = fopen($url, 'r', false, $context);
155
156 # UpdraftPLus patch
157 if (!$fh && isset($retry_on_fail) && !empty($cname) && 'www.googleapis.com' == $cname) {
158 // Reset
159 $this->trappedErrorNumber = null;
160 $this->trappedErrorString = null;
161 global $updraftplus;
162 $updraftplus->log("Using Stream, and fopen failed; retrying different CN match to try to overcome");
163 // www.googleapis.com does not match the cert now being presented - *.storage.googleapis.com; presumably, PHP's stream handler isn't handling alternative names properly. Rather than turn off all verification, let's retry with a new name to match.
164 $options['ssl']['CN_match'] = 'www.storage.googleapis.com';
165 $context = stream_context_create($options);
166 $fh = fopen($url, 'r', false, $context);
167 }
168
169 restore_error_handler();
170 // END - error trap.
171
172 if ($this->trappedErrorNumber) {
173 $error = sprintf(
174 "HTTP Error: Unable to connect: '%s'",
175 $this->trappedErrorString
176 );
177
178 $this->client->getLogger()->error('Stream ' . $error);
179 throw new Google_IO_Exception($error, $this->trappedErrorNumber);
180 }
181
182 $response_data = false;
183 $respHttpCode = self::UNKNOWN_CODE;
184 if ($fh) {
185 if (isset($this->options[self::TIMEOUT])) {
186 stream_set_timeout($fh, $this->options[self::TIMEOUT]);
187 }
188
189 $response_data = stream_get_contents($fh);
190 fclose($fh);
191
192 $respHttpCode = $this->getHttpResponseCode($http_response_header);
193 }
194
195 if (false === $response_data) {
196 $error = sprintf(
197 "HTTP Error: Unable to connect: '%s'",
198 $respHttpCode
199 );
200
201 $this->client->getLogger()->error('Stream ' . $error);
202 throw new Google_IO_Exception($error, $respHttpCode);
203 }
204
205 $responseHeaders = $this->getHttpResponseHeaders($http_response_header);
206
207 $this->client->getLogger()->debug(
208 'Stream response',
209 array(
210 'code' => $respHttpCode,
211 'headers' => $responseHeaders,
212 'body' => $response_data,
213 )
214 );
215
216 return array($response_data, $responseHeaders, $respHttpCode);
217 }
218
219 /**
220 * Set options that update the transport implementation's behavior.
221 * @param $options
222 */
223 public function setOptions($options)
224 {
225 $this->options = $options + $this->options;
226 }
227
228 /**
229 * Method to handle errors, used for error handling around
230 * stream connection methods.
231 */
232 public function trapError($errno, $errstr)
233 {
234 $this->trappedErrorNumber = $errno;
235 $this->trappedErrorString = $errstr;
236 }
237
238 /**
239 * Set the maximum request time in seconds.
240 * @param $timeout in seconds
241 */
242 public function setTimeout($timeout)
243 {
244 $this->options[self::TIMEOUT] = $timeout;
245 }
246
247 /**
248 * Get the maximum request time in seconds.
249 * @return timeout in seconds
250 */
251 public function getTimeout()
252 {
253 return $this->options[self::TIMEOUT];
254 }
255
256 /**
257 * Test for the presence of a cURL header processing bug
258 *
259 * {@inheritDoc}
260 *
261 * @return boolean
262 */
263 protected function needsQuirk()
264 {
265 return false;
266 }
267
268 protected function getHttpResponseCode($response_headers)
269 {
270 $header_count = count($response_headers);
271
272 for ($i = 0; $i < $header_count; $i++) {
273 $header = $response_headers[$i];
274 if (strncasecmp("HTTP", $header, strlen("HTTP")) == 0) {
275 $response = explode(' ', $header);
276 return $response[1];
277 }
278 }
279 return self::UNKNOWN_CODE;
280 }
281 }
282