PluginProbe
Authorizer / 2.6.17
Authorizer v2.6.17
3.15.3 3.15.2 3.15.1 3.15.0 3.14.3 3.14.4 3.14.2 3.14.1 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.9.0 2.9.1 2.9.10 2.9.11 2.9.12 2.9.13 2.9.2 2.9.3 2.9.6 All 126 releases
authorizer / vendor / google-api-php-client / src / Google / Http / MediaFileUpload.php

MediaFileUpload.php in Authorizer 2.6.17, at vendor/google-api-php-client/src/Google/Http/MediaFileUpload.php

342 lines 9.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 private $resumeUri;
49
50 /** @var int $progress */
51 private $progress;
52
53 /** @var Google_Client */
54 private $client;
55
56 /** @var Google_Http_Request */
57 private $request;
58
59 /** @var string */
60 private $boundary;
61
62 /**
63 * Result code from last HTTP call
64 * @var int
65 */
66 private $httpResultCode;
67
68 /**
69 * @param $mimeType string
70 * @param $data string The bytes you want to upload.
71 * @param $resumable bool
72 * @param bool $chunkSize File will be uploaded in chunks of this many bytes.
73 * only used if resumable=True
74 */
75 public function __construct(
76 Google_Client $client,
77 Google_Http_Request $request,
78 $mimeType,
79 $data,
80 $resumable = false,
81 $chunkSize = false,
82 $boundary = false
83 ) {
84 $this->client = $client;
85 $this->request = $request;
86 $this->mimeType = $mimeType;
87 $this->data = $data;
88 $this->size = strlen($this->data);
89 $this->resumable = $resumable;
90 if (!$chunkSize) {
91 $chunkSize = 256 * 1024;
92 }
93 $this->chunkSize = $chunkSize;
94 $this->progress = 0;
95 $this->boundary = $boundary;
96
97 // Process Media Request
98 $this->process();
99 }
100
101 /**
102 * Set the size of the file that is being uploaded.
103 * @param $size - int file size in bytes
104 */
105 public function setFileSize($size)
106 {
107 $this->size = $size;
108 }
109
110 /**
111 * Return the progress on the upload
112 * @return int progress in bytes uploaded.
113 */
114 public function getProgress()
115 {
116 return $this->progress;
117 }
118
119 /**
120 * Return the HTTP result code from the last call made.
121 * @return int code
122 */
123 public function getHttpResultCode()
124 {
125 return $this->httpResultCode;
126 }
127
128 /**
129 * Sends a PUT-Request to google drive and parses the response,
130 * setting the appropiate variables from the response()
131 *
132 * @param Google_Http_Request $httpRequest the Reuqest which will be send
133 *
134 * @return false|mixed false when the upload is unfinished or the decoded http response
135 *
136 */
137 private function makePutRequest(Google_Http_Request $httpRequest)
138 {
139 if ($this->client->getClassConfig("Google_Http_Request", "enable_gzip_for_uploads")) {
140 $httpRequest->enableGzip();
141 } else {
142 $httpRequest->disableGzip();
143 }
144
145 $response = $this->client->getIo()->makeRequest($httpRequest);
146 $response->setExpectedClass($this->request->getExpectedClass());
147 $code = $response->getResponseHttpCode();
148 $this->httpResultCode = $code;
149
150 if (308 == $code) {
151 // Track the amount uploaded.
152 $range = explode('-', $response->getResponseHeader('range'));
153 $this->progress = $range[1] + 1;
154
155 // Allow for changing upload URLs.
156 $location = $response->getResponseHeader('location');
157 if ($location) {
158 $this->resumeUri = $location;
159 }
160
161 // No problems, but upload not complete.
162 return false;
163 } else {
164 return Google_Http_REST::decodeHttpResponse($response, $this->client);
165 }
166 }
167
168 /**
169 * Send the next part of the file to upload.
170 * @param [$chunk] the next set of bytes to send. If false will used $data passed
171 * at construct time.
172 */
173 public function nextChunk($chunk = false)
174 {
175 if (false == $this->resumeUri) {
176 $this->resumeUri = $this->fetchResumeUri();
177 }
178
179 if (false == $chunk) {
180 $chunk = substr($this->data, $this->progress, $this->chunkSize);
181 }
182 $lastBytePos = $this->progress + strlen($chunk) - 1;
183 $headers = array(
184 'content-range' => "bytes $this->progress-$lastBytePos/$this->size",
185 'content-type' => $this->request->getRequestHeader('content-type'),
186 'content-length' => $this->chunkSize,
187 'expect' => '',
188 );
189
190 $httpRequest = new Google_Http_Request(
191 $this->resumeUri,
192 'PUT',
193 $headers,
194 $chunk
195 );
196 return $this->makePutRequest($httpRequest);
197 }
198
199 /**
200 * Resume a previously unfinished upload
201 * @param $resumeUri the resume-URI of the unfinished, resumable upload.
202 */
203 public function resume($resumeUri)
204 {
205 $this->resumeUri = $resumeUri;
206 $headers = array(
207 'content-range' => "bytes */$this->size",
208 'content-length' => 0,
209 );
210 $httpRequest = new Google_Http_Request(
211 $this->resumeUri,
212 'PUT',
213 $headers
214 );
215 return $this->makePutRequest($httpRequest);
216 }
217
218 /**
219 * @return array|bool
220 * @visible for testing
221 */
222 private function process()
223 {
224 $postBody = false;
225 $contentType = false;
226
227 $meta = $this->request->getPostBody();
228 $meta = is_string($meta) ? json_decode($meta, true) : $meta;
229
230 $uploadType = $this->getUploadType($meta);
231 $this->request->setQueryParam('uploadType', $uploadType);
232 $this->transformToUploadUrl();
233 $mimeType = $this->mimeType ?
234 $this->mimeType :
235 $this->request->getRequestHeader('content-type');
236
237 if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) {
238 $contentType = $mimeType;
239 $postBody = is_string($meta) ? $meta : json_encode($meta);
240 } else if (self::UPLOAD_MEDIA_TYPE == $uploadType) {
241 $contentType = $mimeType;
242 $postBody = $this->data;
243 } else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) {
244 // This is a multipart/related upload.
245 $boundary = $this->boundary ? $this->boundary : mt_rand();
246 $boundary = str_replace('"', '', $boundary);
247 $contentType = 'multipart/related; boundary=' . $boundary;
248 $related = "--$boundary\r\n";
249 $related .= "Content-Type: application/json; charset=UTF-8\r\n";
250 $related .= "\r\n" . json_encode($meta) . "\r\n";
251 $related .= "--$boundary\r\n";
252 $related .= "Content-Type: $mimeType\r\n";
253 $related .= "Content-Transfer-Encoding: base64\r\n";
254 $related .= "\r\n" . base64_encode($this->data) . "\r\n";
255 $related .= "--$boundary--";
256 $postBody = $related;
257 }
258
259 $this->request->setPostBody($postBody);
260
261 if (isset($contentType) && $contentType) {
262 $contentTypeHeader['content-type'] = $contentType;
263 $this->request->setRequestHeaders($contentTypeHeader);
264 }
265 }
266
267 private function transformToUploadUrl()
268 {
269 $base = $this->request->getBaseComponent();
270 $this->request->setBaseComponent($base . '/upload');
271 }
272
273 /**
274 * Valid upload types:
275 * - resumable (UPLOAD_RESUMABLE_TYPE)
276 * - media (UPLOAD_MEDIA_TYPE)
277 * - multipart (UPLOAD_MULTIPART_TYPE)
278 * @param $meta
279 * @return string
280 * @visible for testing
281 */
282 public function getUploadType($meta)
283 {
284 if ($this->resumable) {
285 return self::UPLOAD_RESUMABLE_TYPE;
286 }
287
288 if (false == $meta && $this->data) {
289 return self::UPLOAD_MEDIA_TYPE;
290 }
291
292 return self::UPLOAD_MULTIPART_TYPE;
293 }
294
295 public function getResumeUri()
296 {
297 return ( $this->resumeUri !== null ? $this->resumeUri : $this->fetchResumeUri() );
298 }
299
300 private function fetchResumeUri()
301 {
302 $result = null;
303 $body = $this->request->getPostBody();
304 if ($body) {
305 $headers = array(
306 'content-type' => 'application/json; charset=UTF-8',
307 'content-length' => Google_Utils::getStrLen($body),
308 'x-upload-content-type' => $this->mimeType,
309 'x-upload-content-length' => $this->size,
310 'expect' => '',
311 );
312 $this->request->setRequestHeaders($headers);
313 }
314
315 $response = $this->client->getIo()->makeRequest($this->request);
316 $location = $response->getResponseHeader('location');
317 $code = $response->getResponseHttpCode();
318
319 if (200 == $code && true == $location) {
320 return $location;
321 }
322 $message = $code;
323 $body = @json_decode($response->getResponseBody());
324 if (!empty($body->error->errors) ) {
325 $message .= ': ';
326 foreach ($body->error->errors as $error) {
327 $message .= "{$error->domain}, {$error->message};";
328 }
329 $message = rtrim($message, ';');
330 }
331
332 $error = "Failed to start the resumable upload (HTTP {$message})";
333 $this->client->getLogger()->error($error);
334 throw new Google_Exception($error);
335 }
336
337 public function setChunkSize($chunkSize)
338 {
339 $this->chunkSize = $chunkSize;
340 }
341 }
342