public function testMediaFile() { $client = $this->getClient(); $request = new Google_Http_Request('http://www.example.com', 'POST'); $media = new Google_Http_MediaFileUpload($client, $request, 'image/png', base64_decode('data:image/png;base64,a')); $this->assertEquals(0, $media->getProgress()); $this->assertGreaterThan(0, strlen($request->getPostBody())); }
private function upload_file($file, $parent_id, $try_again = true) { global $updraftplus; $opts = $this->get_opts(); $basename = basename($file); $service = $this->service; $client = $this->client; # See: https://github.com/google/google-api-php-client/blob/master/examples/fileupload.php (at time of writing, only shows how to upload in chunks, not how to resume) $client->setDefer(true); $local_size = filesize($file); $gdfile = new Google_Service_Drive_DriveFile(); $gdfile->title = $basename; $ref = new Google_Service_Drive_ParentReference(); $ref->setId($parent_id); $gdfile->setParents(array($ref)); $size = 0; $request = $service->files->insert($gdfile); $chunk_bytes = 1048576; $hash = md5($file); $transkey = 'gdresume_' . $hash; // This is unset upon completion, so if it is set then we are resuming $possible_location = $updraftplus->jobdata_get($transkey); if (is_array($possible_location)) { $headers = array('content-range' => "bytes */" . $local_size); $httpRequest = new Google_Http_Request($possible_location[0], 'PUT', $headers, ''); $response = $this->client->getIo()->makeRequest($httpRequest); $can_resume = false; if (308 == $response->getResponseHttpCode()) { $range = $response->getResponseHeader('range'); if (!empty($range) && preg_match('/bytes=0-(\\d+)$/', $range, $matches)) { $can_resume = true; $possible_location[1] = $matches[1] + 1; $updraftplus->log("{$basename}: upload already began; attempting to resume from byte " . $matches[1]); } } if (!$can_resume) { $updraftplus->log("{$basename}: upload already began; attempt to resume did not succeed (HTTP code: " . $response->getResponseHttpCode() . ")"); } } $media = new Google_Http_MediaFileUpload($client, $request, '.zip' == substr($basename, -4, 4) ? 'application/zip' : 'application/octet-stream', null, true, $chunk_bytes); $media->setFileSize($local_size); if (!empty($possible_location)) { $media->resumeUri = $possible_location[0]; $media->progress = $possible_location[1]; $size = $possible_location[1]; } if ($size >= $local_size) { return true; } $status = false; if (false == ($handle = fopen($file, 'rb'))) { $updraftplus->log("Google Drive: failed to open file: {$basename}"); $updraftplus->log("{$basename}: " . sprintf(__('%s Error: Failed to open local file', 'updraftplus'), 'Google Drive'), 'error'); return false; } if ($size > 0 && 0 != fseek($handle, $size)) { $updraftplus->log("Google Drive: failed to fseek file: {$basename}, {$size}"); $updraftplus->log("{$basename} (fseek): " . sprintf(__('%s Error: Failed to open local file', 'updraftplus'), 'Google Drive'), 'error'); return false; } $pointer = $size; try { while (!$status && !feof($handle)) { $chunk = fread($handle, $chunk_bytes); # Error handling?? $pointer += strlen($chunk); $status = $media->nextChunk($chunk); $updraftplus->jobdata_set($transkey, array($media->resumeUri, $media->getProgress())); $updraftplus->record_uploaded_chunk(round(100 * $pointer / $local_size, 1), $media->getProgress(), $file); } } catch (Google_Service_Exception $e) { $updraftplus->log("ERROR: Google Drive upload error (" . get_class($e) . "): " . $e->getMessage() . ' (line: ' . $e->getLine() . ', file: ' . $e->getFile() . ')'); $client->setDefer(false); fclose($handle); $updraftplus->jobdata_delete($transkey); if (false == $try_again) { throw $e; } # Reset this counter to prevent the something_useful_happened condition's possibility being sent into the far future and potentially missed if ($updraftplus->current_resumption > 9) { $updraftplus->jobdata_set('uploaded_lastreset', $updraftplus->current_resumption); } return $this->upload_file($file, $parent_id, false); } // The final value of $status will be the data from the API for the object // that has been uploaded. $result = false; if ($status != false) { $result = $status; } fclose($handle); $client->setDefer(false); $updraftplus->jobdata_delete($transkey); return true; }
private function do_upload_engine($basename, $from, $try_again = true) { global $updraftplus; $opts = $this->options; $service = $this->service; list($bucket_name, $path) = $this->split_bucket_path($opts['bucket_path']); if (empty($bucket_name)) { _e("Failure: No bucket details were given.", 'updraftplus'); return; } $bucket = $this->create_bucket_if_not_existing($bucket_name); if (is_wp_error($bucket)) { throw new Exception("Google Cloud Storage: Error accessing or creating bucket: " . $bucket->get_error_message()); } $storage_object = new Google_Service_Storage_StorageObject(); $storage_object->setName($path . $basename); $storage_object->setBucket($bucket_name); // In Google Cloud Storage, the storage class is a property of buckets, not objects - i.e. objects simply inherit from the bucket // $storage_class = (!empty($opts['storage_class']) && isset($this->storage_classes[$opts['storage_class']])) ? $opts['storage_class'] : 'STANDARD'; // $storage_object->setStorageClass($storage_class); $this->client->setDefer(true); $request = $this->service->objects->insert($bucket_name, $storage_object, array('mimeType' => $updraftplus->get_mime_type_from_filename($basename), 'uploadType' => 'media')); $hash = md5($basename); $transkey = 'gcresume_' . $hash; // This is unset upon completion, so if it is set then we are resuming $possible_location = $updraftplus->jobdata_get($transkey); $size = 0; $local_size = filesize($from); if (is_array($possible_location)) { $headers = array('content-range' => "bytes */" . $local_size); $httpRequest = new Google_Http_Request($possible_location[0], 'PUT', $headers, ''); $response = $this->client->getIo()->makeRequest($httpRequest); $can_resume = false; if (308 == $response->getResponseHttpCode()) { $range = $response->getResponseHeader('range'); if (!empty($range) && preg_match('/bytes=0-(\\d+)$/', $range, $matches)) { $can_resume = true; $possible_location[1] = $matches[1] + 1; $updraftplus->log("{$basename}: upload already began; attempting to resume from byte " . $matches[1]); } } if (!$can_resume) { $updraftplus->log("{$basename}: upload already began; attempt to resume did not succeed (HTTP code: " . $response->getResponseHttpCode() . ")"); } } // (('.zip' == substr($basename, -4, 4)) ? 'application/zip' : 'application/octet-stream'), $media = new Google_Http_MediaFileUpload($this->client, $request, $updraftplus->get_mime_type_from_filename($basename), null, true, $this->chunk_size); $media->setFileSize($local_size); if (!empty($possible_location)) { $media->resumeUri = $possible_location[0]; $media->progress = $possible_location[1]; $size = $possible_location[1]; } if ($size >= $local_size) { return true; } $status = false; if (false == ($handle = fopen($from, 'rb'))) { $updraftplus->log("Google Cloud Storage: failed to open file: {$basename}"); $updraftplus->log("{$basename}: " . sprintf(__('%s Error: Failed to open local file', 'updraftplus'), 'Google Drive'), 'error'); return false; } if ($size > 0 && 0 != fseek($handle, $size)) { $updraftplus->log("Google Cloud Storage: failed to fseek file: {$basename}, {$size}"); $updraftplus->log("{$basename} (fseek): " . sprintf(__('%s Error: Failed to open local file', 'updraftplus'), 'Google Drive'), 'error'); return false; } $pointer = $size; try { while (!$status && !feof($handle)) { $chunk = fread($handle, $this->chunk_size); # Error handling?? $pointer += strlen($chunk); $status = $media->nextChunk($chunk); $updraftplus->jobdata_set($transkey, array($media->resumeUri, $media->getProgress())); $updraftplus->record_uploaded_chunk(round(100 * $pointer / $local_size, 1), $media->getProgress(), $from); } } catch (Google_Service_Exception $e) { $updraftplus->log("ERROR: Google Cloud Storage upload error (" . get_class($e) . "): " . $e->getMessage() . ' (line: ' . $e->getLine() . ', file: ' . $e->getFile() . ')'); $this->client->setDefer(false); fclose($handle); $updraftplus->jobdata_delete($transkey); if (false == $try_again) { throw $e; } # Reset this counter to prevent the something_useful_happened condition's possibility being sent into the far future and potentially missed if ($updraftplus->current_resumption > 9) { $updraftplus->jobdata_set('uploaded_lastreset', $updraftplus->current_resumption); } return $this->do_upload_engine($basename, $from, false); } // The final value of $status will be the data from the API for the object // that has been uploaded. $result = false; if ($status != false) { $result = $status; } fclose($handle); $this->client->setDefer(false); $updraftplus->jobdata_delete($transkey); return true; }