PluginProbe
InfiniteWP Client / trunk
InfiniteWP Client vtrunk
1.13.10 1.13.7 trunk 0.1.4 0.1.5 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.11.0 1.11.1 1.12.1 1.12.3 All 92 releases
iwp-client / lib / google-extensions.php

google-extensions.php in InfiniteWP Client trunk, at lib/google-extensions.php

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