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 / Http / MediaFileUpload.php

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

307 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Copyright 2012 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 if (!class_exists('Google_Client')) {
19 require_once dirname(__FILE__) . '/../autoload.php';
20 }
21
22 /**
23 * Manage large file uploads, which may be media but can be any type
24 * of sizable data.
25 */
26 class Google_Http_MediaFileUpload
27 {
28 const UPLOAD_MEDIA_TYPE = 'media';
29 const UPLOAD_MULTIPART_TYPE = 'multipart';
30 const UPLOAD_RESUMABLE_TYPE = 'resumable';
31
32 /** @var string $mimeType */
33 private $mimeType;
34
35 /** @var string $data */
36 private $data;
37
38 /** @var bool $resumable */
39 private $resumable;
40
41 /** @var int $chunkSize */
42 private $chunkSize;
43
44 /** @var int $size */
45 private $size;
46
47 /** @var string $resumeUri */
48 // UpdraftPlus patch
49 public $resumeUri;
50 // private $resumeUri;
51
52 /** @var int $progress */
53 // UpdraftPlus patch
54 public $progress;
55 // private $progress;
56
57 /** @var Google_Client */
58 private $client;
59
60 /** @var Google_Http_Request */
61 private $request;
62
63 /** @var string */
64 private $boundary;
65
66 /**
67 * Result code from last HTTP call
68 * @var int
69 */
70 private $httpResultCode;
71
72 /**
73 * @param $mimeType string
74 * @param $data string The bytes you want to upload.
75 * @param $resumable bool
76 * @param bool $chunkSize File will be uploaded in chunks of this many bytes.
77 * only used if resumable=True
78 */
79 public function __construct(
80 Google_Client $client,
81 Google_Http_Request $request,
82 $mimeType,
83 $data,
84 $resumable = false,
85 $chunkSize = false,
86 $boundary = false
87 ) {
88 $this->client = $client;
89 $this->request = $request;
90 $this->mimeType = $mimeType;
91 $this->data = $data;
92 $this->size = strlen($this->data);
93 $this->resumable = $resumable;
94 if (!$chunkSize) {
95 $chunkSize = 256 * 1024;
96 }
97 $this->chunkSize = $chunkSize;
98 $this->progress = 0;
99 $this->boundary = $boundary;
100
101 // Process Media Request
102 $this->process();
103 }
104
105 /**
106 * Set the size of the file that is being uploaded.
107 * @param $size - int file size in bytes
108 */
109 public function setFileSize($size)
110 {
111 $this->size = $size;
112 }
113
114 /**
115 * Return the progress on the upload
116 * @return int progress in bytes uploaded.
117 */
118 public function getProgress()
119 {
120 return $this->progress;
121 }
122
123 /**
124 * Return the HTTP result code from the last call made.
125 * @return int code
126 */
127 public function getHttpResultCode()
128 {
129 return $this->httpResultCode;
130 }
131
132 /**
133 * Send the next part of the file to upload.
134 * @param [$chunk] the next set of bytes to send. If false will used $data passed
135 * at construct time.
136 */
137 public function nextChunk($chunk = false)
138 {
139 if (false == $this->resumeUri) {
140 $this->resumeUri = $this->getResumeUri();
141 }
142
143 if (false == $chunk) {
144 $chunk = substr($this->data, $this->progress, $this->chunkSize);
145 }
146
147 $lastBytePos = $this->progress + strlen($chunk) - 1;
148 $headers = array(
149 'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
150 'content-type' => $this->request->getRequestHeader('content-type'),
151 'content-length' => $this->chunkSize,
152 'expect' => '',
153 );
154
155 $httpRequest = new Google_Http_Request(
156 $this->resumeUri,
157 'PUT',
158 $headers,
159 $chunk
160 );
161
162 if ($this->client->getClassConfig("Google_Http_Request", "enable_gzip_for_uploads")) {
163 $httpRequest->enableGzip();
164 } else {
165 $httpRequest->disableGzip();
166 }
167
168 $response = $this->client->getIo()->makeRequest($httpRequest);
169 $response->setExpectedClass($this->request->getExpectedClass());
170 $code = $response->getResponseHttpCode();
171 $this->httpResultCode = $code;
172
173 if (308 == $code) {
174 // Track the amount uploaded.
175 $range = explode('-', $response->getResponseHeader('range'));
176 $this->progress = $range[1] + 1;
177
178 // Allow for changing upload URLs.
179 $location = $response->getResponseHeader('location');
180 if ($location) {
181 $this->resumeUri = $location;
182 }
183
184 // No problems, but upload not complete.
185 return false;
186 } else {
187 return Google_Http_REST::decodeHttpResponse($response, $this->client);
188 }
189 }
190
191 /**
192 * @param $meta
193 * @param $params
194 * @return array|bool
195 * @visible for testing
196 */
197 private function process()
198 {
199 $postBody = false;
200 $contentType = false;
201
202 $meta = $this->request->getPostBody();
203 $meta = is_string($meta) ? json_decode($meta, true) : $meta;
204
205 $uploadType = $this->getUploadType($meta);
206 $this->request->setQueryParam('uploadType', $uploadType);
207 $this->transformToUploadUrl();
208 $mimeType = $this->mimeType ?
209 $this->mimeType :
210 $this->request->getRequestHeader('content-type');
211
212 if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
213 $contentType = $mimeType;
214 $postBody = is_string($meta) ? $meta : json_encode($meta);
215 } else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
216 $contentType = $mimeType;
217 $postBody = $this->data;
218 } else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
219 // This is a multipart/related upload.
220 $boundary = $this->boundary ? $this->boundary : mt_rand();
221 $boundary = str_replace('"', '', $boundary);
222 $contentType = 'multipart/related; boundary=' . $boundary;
223 $related = "--$boundary\r\n";
224 $related .= "Content-Type: application/json; charset=UTF-8\r\n";
225 $related .= "\r\n" . json_encode($meta) . "\r\n";
226 $related .= "--$boundary\r\n";
227 $related .= "Content-Type: $mimeType\r\n";
228 $related .= "Content-Transfer-Encoding: base64\r\n";
229 $related .= "\r\n" . base64_encode($this->data) . "\r\n";
230 $related .= "--$boundary--";
231 $postBody = $related;
232 }
233
234 $this->request->setPostBody($postBody);
235
236 if (isset($contentType) && $contentType) {
237 $contentTypeHeader['content-type'] = $contentType;
238 $this->request->setRequestHeaders($contentTypeHeader);
239 }
240 }
241
242 private function transformToUploadUrl()
243 {
244 $base = $this->request->getBaseComponent();
245 $this->request->setBaseComponent($base . '/upload');
246 }
247
248 /**
249 * Valid upload types:
250 * - resumable (UPLOAD_RESUMABLE_TYPE)
251 * - media (UPLOAD_MEDIA_TYPE)
252 * - multipart (UPLOAD_MULTIPART_TYPE)
253 * @param $meta
254 * @return string
255 * @visible for testing
256 */
257 public function getUploadType($meta)
258 {
259 if ($this->resumable) {
260 return self::UPLOAD_RESUMABLE_TYPE;
261 }
262
263 if (false == $meta && $this->data) {
264 return self::UPLOAD_MEDIA_TYPE;
265 }
266
267 return self::UPLOAD_MULTIPART_TYPE;
268 }
269
270 private function getResumeUri()
271 {
272 $result = null;
273 $body = $this->request->getPostBody();
274 if ($body) {
275 $headers = array(
276 'content-type' => 'application/json; charset=UTF-8',
277 'content-length' => Google_Utils::getStrLen($body),
278 'x-upload-content-type' => $this->mimeType,
279 'x-upload-content-length' => $this->size,
280 'expect' => '',
281 );
282 $this->request->setRequestHeaders($headers);
283 }
284
285 $response = $this->client->getIo()->makeRequest($this->request);
286 $location = $response->getResponseHeader('location');
287 $code = $response->getResponseHttpCode();
288
289 if (200 == $code && true == $location) {
290 return $location;
291 }
292 $message = $code;
293 $body = @json_decode($response->getResponseBody());
294 if (!empty( $body->error->errors ) ) {
295 $message .= ': ';
296 foreach ($body->error->errors as $error) {
297 $message .= "{$error->domain}, {$error->message};";
298 }
299 $message = rtrim($message, ';');
300 }
301
302 $error = "Failed to start the resumable upload (HTTP {$message})";
303 $this->client->getLogger()->error($error);
304 throw new Google_Exception($error);
305 }
306 }
307