TheRakeshPurohit /
rtCamp
| 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 | use GuzzleHttp\Psr7; |
||||||
| 19 | use GuzzleHttp\Psr7\Request; |
||||||
| 20 | use GuzzleHttp\Psr7\Uri; |
||||||
| 21 | use Psr\Http\Message\RequestInterface; |
||||||
| 22 | |||||||
| 23 | /** |
||||||
| 24 | * Manage large file uploads, which may be media but can be any type |
||||||
| 25 | * of sizable data. |
||||||
| 26 | */ |
||||||
| 27 | class Google_Http_MediaFileUpload |
||||||
| 28 | { |
||||||
| 29 | const UPLOAD_MEDIA_TYPE = 'media'; |
||||||
| 30 | const UPLOAD_MULTIPART_TYPE = 'multipart'; |
||||||
| 31 | const UPLOAD_RESUMABLE_TYPE = 'resumable'; |
||||||
| 32 | |||||||
| 33 | /** @var string $mimeType */ |
||||||
| 34 | private $mimeType; |
||||||
| 35 | |||||||
| 36 | /** @var string $data */ |
||||||
| 37 | private $data; |
||||||
| 38 | |||||||
| 39 | /** @var bool $resumable */ |
||||||
| 40 | private $resumable; |
||||||
| 41 | |||||||
| 42 | /** @var int $chunkSize */ |
||||||
| 43 | private $chunkSize; |
||||||
| 44 | |||||||
| 45 | /** @var int $size */ |
||||||
| 46 | private $size; |
||||||
| 47 | |||||||
| 48 | /** @var string $resumeUri */ |
||||||
| 49 | private $resumeUri; |
||||||
| 50 | |||||||
| 51 | /** @var int $progress */ |
||||||
| 52 | private $progress; |
||||||
| 53 | |||||||
| 54 | /** @var Google_Client */ |
||||||
| 55 | private $client; |
||||||
| 56 | |||||||
| 57 | /** @var Psr\Http\Message\RequestInterface */ |
||||||
| 58 | private $request; |
||||||
| 59 | |||||||
| 60 | /** @var string */ |
||||||
| 61 | private $boundary; |
||||||
| 62 | |||||||
| 63 | /** |
||||||
| 64 | * Result code from last HTTP call |
||||||
| 65 | * @var int |
||||||
| 66 | */ |
||||||
| 67 | private $httpResultCode; |
||||||
| 68 | |||||||
| 69 | /** |
||||||
| 70 | * @param $mimeType string |
||||||
| 71 | * @param $data string The bytes you want to upload. |
||||||
| 72 | * @param $resumable bool |
||||||
| 73 | * @param bool $chunkSize File will be uploaded in chunks of this many bytes. |
||||||
| 74 | * only used if resumable=True |
||||||
| 75 | */ |
||||||
| 76 | public function __construct( |
||||||
| 77 | Google_Client $client, |
||||||
| 78 | RequestInterface $request, |
||||||
| 79 | $mimeType, |
||||||
| 80 | $data, |
||||||
| 81 | $resumable = false, |
||||||
| 82 | $chunkSize = false |
||||||
| 83 | ) { |
||||||
| 84 | $this->client = $client; |
||||||
| 85 | $this->request = $request; |
||||||
| 86 | $this->mimeType = $mimeType; |
||||||
| 87 | $this->data = $data; |
||||||
| 88 | $this->resumable = $resumable; |
||||||
| 89 | $this->chunkSize = $chunkSize; |
||||||
|
0 ignored issues
–
show
|
|||||||
| 90 | $this->progress = 0; |
||||||
| 91 | |||||||
| 92 | $this->process(); |
||||||
| 93 | } |
||||||
| 94 | |||||||
| 95 | /** |
||||||
| 96 | * Set the size of the file that is being uploaded. |
||||||
| 97 | * @param $size - int file size in bytes |
||||||
|
0 ignored issues
–
show
|
|||||||
| 98 | */ |
||||||
| 99 | public function setFileSize($size) |
||||||
| 100 | { |
||||||
| 101 | $this->size = $size; |
||||||
| 102 | } |
||||||
| 103 | |||||||
| 104 | /** |
||||||
| 105 | * Return the progress on the upload |
||||||
| 106 | * @return int progress in bytes uploaded. |
||||||
| 107 | */ |
||||||
| 108 | public function getProgress() |
||||||
| 109 | { |
||||||
| 110 | return $this->progress; |
||||||
| 111 | } |
||||||
| 112 | |||||||
| 113 | /** |
||||||
| 114 | * Send the next part of the file to upload. |
||||||
| 115 | * @param [$chunk] the next set of bytes to send. If false will used $data passed |
||||||
|
0 ignored issues
–
show
The type
the was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||||
| 116 | * at construct time. |
||||||
| 117 | */ |
||||||
| 118 | public function nextChunk($chunk = false) |
||||||
| 119 | { |
||||||
| 120 | $resumeUri = $this->getResumeUri(); |
||||||
| 121 | |||||||
| 122 | if (false == $chunk) { |
||||||
| 123 | $chunk = substr($this->data, $this->progress, $this->chunkSize); |
||||||
| 124 | } |
||||||
| 125 | |||||||
| 126 | $lastBytePos = $this->progress + strlen($chunk) - 1; |
||||||
| 127 | $headers = array( |
||||||
| 128 | 'content-range' => "bytes $this->progress-$lastBytePos/$this->size", |
||||||
| 129 | 'content-length' => strlen($chunk), |
||||||
| 130 | 'expect' => '', |
||||||
| 131 | ); |
||||||
| 132 | |||||||
| 133 | $request = new Request( |
||||||
| 134 | 'PUT', |
||||||
| 135 | $resumeUri, |
||||||
| 136 | $headers, |
||||||
| 137 | Psr7\stream_for($chunk) |
||||||
|
0 ignored issues
–
show
The function
stream_for was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 138 | ); |
||||||
| 139 | |||||||
| 140 | return $this->makePutRequest($request); |
||||||
| 141 | } |
||||||
| 142 | |||||||
| 143 | /** |
||||||
| 144 | * Return the HTTP result code from the last call made. |
||||||
| 145 | * @return int code |
||||||
| 146 | */ |
||||||
| 147 | public function getHttpResultCode() |
||||||
| 148 | { |
||||||
| 149 | return $this->httpResultCode; |
||||||
| 150 | } |
||||||
| 151 | |||||||
| 152 | /** |
||||||
| 153 | * Sends a PUT-Request to google drive and parses the response, |
||||||
| 154 | * setting the appropiate variables from the response() |
||||||
| 155 | * |
||||||
| 156 | * @param Google_Http_Request $httpRequest the Reuqest which will be send |
||||||
|
0 ignored issues
–
show
The type
Google_Http_Request was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||||||
| 157 | * |
||||||
| 158 | * @return false|mixed false when the upload is unfinished or the decoded http response |
||||||
| 159 | * |
||||||
| 160 | */ |
||||||
| 161 | private function makePutRequest(RequestInterface $request) |
||||||
| 162 | { |
||||||
| 163 | $response = $this->client->execute($request); |
||||||
| 164 | $this->httpResultCode = $response->getStatusCode(); |
||||||
| 165 | |||||||
| 166 | if (308 == $this->httpResultCode) { |
||||||
| 167 | // Track the amount uploaded. |
||||||
| 168 | $range = $response->getHeaderLine('range'); |
||||||
| 169 | if ($range) { |
||||||
| 170 | $range_array = explode('-', $range); |
||||||
| 171 | $this->progress = $range_array[1] + 1; |
||||||
| 172 | } |
||||||
| 173 | |||||||
| 174 | // Allow for changing upload URLs. |
||||||
| 175 | $location = $response->getHeaderLine('location'); |
||||||
| 176 | if ($location) { |
||||||
| 177 | $this->resumeUri = $location; |
||||||
| 178 | } |
||||||
| 179 | |||||||
| 180 | // No problems, but upload not complete. |
||||||
| 181 | return false; |
||||||
| 182 | } |
||||||
| 183 | |||||||
| 184 | return Google_Http_REST::decodeHttpResponse($response, $this->request); |
||||||
| 185 | } |
||||||
| 186 | |||||||
| 187 | /** |
||||||
| 188 | * Resume a previously unfinished upload |
||||||
| 189 | * @param $resumeUri the resume-URI of the unfinished, resumable upload. |
||||||
| 190 | */ |
||||||
| 191 | public function resume($resumeUri) |
||||||
| 192 | { |
||||||
| 193 | $this->resumeUri = $resumeUri; |
||||||
| 194 | $headers = array( |
||||||
| 195 | 'content-range' => "bytes */$this->size", |
||||||
| 196 | 'content-length' => 0, |
||||||
| 197 | ); |
||||||
| 198 | $httpRequest = new Request( |
||||||
| 199 | 'PUT', |
||||||
| 200 | $this->resumeUri, |
||||||
| 201 | $headers |
||||||
| 202 | ); |
||||||
| 203 | |||||||
| 204 | return $this->makePutRequest($httpRequest); |
||||||
| 205 | } |
||||||
| 206 | |||||||
| 207 | /** |
||||||
| 208 | * @return Psr\Http\Message\RequestInterface $request |
||||||
| 209 | * @visible for testing |
||||||
| 210 | */ |
||||||
| 211 | private function process() |
||||||
| 212 | { |
||||||
| 213 | $this->transformToUploadUrl(); |
||||||
| 214 | $request = $this->request; |
||||||
| 215 | |||||||
| 216 | $postBody = ''; |
||||||
| 217 | $contentType = false; |
||||||
| 218 | |||||||
| 219 | $meta = (string) $request->getBody(); |
||||||
| 220 | $meta = is_string($meta) ? json_decode($meta, true) : $meta; |
||||||
|
0 ignored issues
–
show
|
|||||||
| 221 | |||||||
| 222 | $uploadType = $this->getUploadType($meta); |
||||||
| 223 | $request = $request->withUri( |
||||||
| 224 | Uri::withQueryValue($request->getUri(), 'uploadType', $uploadType) |
||||||
| 225 | ); |
||||||
| 226 | |||||||
| 227 | $mimeType = $this->mimeType ?: $request->getHeaderLine('content-type'); |
||||||
| 228 | |||||||
| 229 | if (self::UPLOAD_RESUMABLE_TYPE == $uploadType) { |
||||||
| 230 | $contentType = $mimeType; |
||||||
| 231 | $postBody = is_string($meta) ? $meta : json_encode($meta); |
||||||
| 232 | } else if (self::UPLOAD_MEDIA_TYPE == $uploadType) { |
||||||
| 233 | $contentType = $mimeType; |
||||||
| 234 | $postBody = $this->data; |
||||||
| 235 | } else if (self::UPLOAD_MULTIPART_TYPE == $uploadType) { |
||||||
| 236 | // This is a multipart/related upload. |
||||||
| 237 | $boundary = $this->boundary ?: mt_rand(); |
||||||
| 238 | $boundary = str_replace('"', '', $boundary); |
||||||
| 239 | $contentType = 'multipart/related; boundary=' . $boundary; |
||||||
| 240 | $related = "--$boundary\r\n"; |
||||||
| 241 | $related .= "Content-Type: application/json; charset=UTF-8\r\n"; |
||||||
| 242 | $related .= "\r\n" . json_encode($meta) . "\r\n"; |
||||||
| 243 | $related .= "--$boundary\r\n"; |
||||||
| 244 | $related .= "Content-Type: $mimeType\r\n"; |
||||||
| 245 | $related .= "Content-Transfer-Encoding: base64\r\n"; |
||||||
| 246 | $related .= "\r\n" . base64_encode($this->data) . "\r\n"; |
||||||
| 247 | $related .= "--$boundary--"; |
||||||
| 248 | $postBody = $related; |
||||||
| 249 | } |
||||||
| 250 | |||||||
| 251 | $request = $request->withBody(Psr7\stream_for($postBody)); |
||||||
|
0 ignored issues
–
show
The function
stream_for was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||
| 252 | |||||||
| 253 | if (isset($contentType) && $contentType) { |
||||||
| 254 | $request = $request->withHeader('content-type', $contentType); |
||||||
| 255 | } |
||||||
| 256 | |||||||
| 257 | return $this->request = $request; |
||||||
| 258 | } |
||||||
| 259 | |||||||
| 260 | /** |
||||||
| 261 | * Valid upload types: |
||||||
| 262 | * - resumable (UPLOAD_RESUMABLE_TYPE) |
||||||
| 263 | * - media (UPLOAD_MEDIA_TYPE) |
||||||
| 264 | * - multipart (UPLOAD_MULTIPART_TYPE) |
||||||
| 265 | * @param $meta |
||||||
| 266 | * @return string |
||||||
| 267 | * @visible for testing |
||||||
| 268 | */ |
||||||
| 269 | public function getUploadType($meta) |
||||||
| 270 | { |
||||||
| 271 | if ($this->resumable) { |
||||||
| 272 | return self::UPLOAD_RESUMABLE_TYPE; |
||||||
| 273 | } |
||||||
| 274 | |||||||
| 275 | if (false == $meta && $this->data) { |
||||||
| 276 | return self::UPLOAD_MEDIA_TYPE; |
||||||
| 277 | } |
||||||
| 278 | |||||||
| 279 | return self::UPLOAD_MULTIPART_TYPE; |
||||||
| 280 | } |
||||||
| 281 | |||||||
| 282 | public function getResumeUri() |
||||||
| 283 | { |
||||||
| 284 | if (null === $this->resumeUri) { |
||||||
| 285 | $this->resumeUri = $this->fetchResumeUri(); |
||||||
| 286 | } |
||||||
| 287 | |||||||
| 288 | return $this->resumeUri; |
||||||
| 289 | } |
||||||
| 290 | |||||||
| 291 | private function fetchResumeUri() |
||||||
| 292 | { |
||||||
| 293 | $body = $this->request->getBody(); |
||||||
| 294 | if ($body) { |
||||||
|
0 ignored issues
–
show
|
|||||||
| 295 | $headers = array( |
||||||
| 296 | 'content-type' => 'application/json; charset=UTF-8', |
||||||
| 297 | 'content-length' => $body->getSize(), |
||||||
| 298 | 'x-upload-content-type' => $this->mimeType, |
||||||
| 299 | 'x-upload-content-length' => $this->size, |
||||||
| 300 | 'expect' => '', |
||||||
| 301 | ); |
||||||
| 302 | foreach ($headers as $key => $value) { |
||||||
| 303 | $this->request = $this->request->withHeader($key, $value); |
||||||
| 304 | } |
||||||
| 305 | } |
||||||
| 306 | |||||||
| 307 | $response = $this->client->execute($this->request, false); |
||||||
| 308 | $location = $response->getHeaderLine('location'); |
||||||
| 309 | $code = $response->getStatusCode(); |
||||||
| 310 | |||||||
| 311 | if (200 == $code && true == $location) { |
||||||
| 312 | return $location; |
||||||
| 313 | } |
||||||
| 314 | |||||||
| 315 | $message = $code; |
||||||
| 316 | $body = json_decode((string) $this->request->getBody(), true); |
||||||
| 317 | if (isset($body['error']['errors'])) { |
||||||
| 318 | $message .= ': '; |
||||||
| 319 | foreach ($body['error']['errors'] as $error) { |
||||||
| 320 | $message .= "{$error['domain']}, {$error['message']};"; |
||||||
| 321 | } |
||||||
| 322 | $message = rtrim($message, ';'); |
||||||
| 323 | } |
||||||
| 324 | |||||||
| 325 | $error = "Failed to start the resumable upload (HTTP {$message})"; |
||||||
| 326 | $this->client->getLogger()->error($error); |
||||||
| 327 | |||||||
| 328 | throw new Google_Exception($error); |
||||||
| 329 | } |
||||||
| 330 | |||||||
| 331 | private function transformToUploadUrl() |
||||||
| 332 | { |
||||||
| 333 | $parts = parse_url((string) $this->request->getUri()); |
||||||
| 334 | if (!isset($parts['path'])) { |
||||||
| 335 | $parts['path'] = ''; |
||||||
| 336 | } |
||||||
| 337 | $parts['path'] = '/upload' . $parts['path']; |
||||||
| 338 | $uri = Uri::fromParts($parts); |
||||||
| 339 | $this->request = $this->request->withUri($uri); |
||||||
| 340 | } |
||||||
| 341 | |||||||
| 342 | public function setChunkSize($chunkSize) |
||||||
| 343 | { |
||||||
| 344 | $this->chunkSize = $chunkSize; |
||||||
| 345 | } |
||||||
| 346 | |||||||
| 347 | public function getRequest() |
||||||
| 348 | { |
||||||
| 349 | return $this->request; |
||||||
| 350 | } |
||||||
| 351 | } |
||||||
| 352 |
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.