PageRenderTime 27ms CodeModel.GetById 10ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/vendor/google-api-php-client/src/Google/Http/MediaFileUpload.php

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