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

MediaFileUpload.php in InfiniteWP Client trunk, at lib/Google/Http/MediaFileUpload.php

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