Last active
September 18, 2024 18:44
-
-
Save metadaddy/23e75d00b21bc63576f0ba317ad43709 to your computer and use it in GitHub Desktop.
PHP sample code for a multipart file upload to Backblaze B2. Usage: php php_multipart.php [-v] <bucket_name> <local_file>
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// PHP sample code to show multipart file upload using the B2 Native API | |
// User supplies optional -v for verbose output from curl, then bucket name | |
// and path to local file | |
$rest_index = null; | |
$opts = getopt("v::", [], $rest_index); | |
$args = array_slice($argv, $rest_index); | |
$verbose = (count($opts) == 1); | |
if (count($args) != 2) { | |
echo "Usage: $argv[0] [-v] <bucket_name> <local_file>\n"; | |
exit(1); | |
} | |
$bucket_name = $args[0]; | |
$local_file = $args[1]; | |
// Safest way to pass credentials is as environment variables | |
$application_key_id = getenv("B2_APPLICATION_KEY_ID"); | |
$application_key = getenv("B2_APPLICATION_KEY"); | |
if (!$application_key_id || !$application_key) { | |
echo "You must set the B2_APPLICATION_KEY_ID and B2_APPLICATION_KEY environment variables"; | |
exit(2); | |
} | |
// | |
// First, call b2_authorize_account to get authorization token | |
// | |
// Basic auth for token request | |
$credentials = base64_encode("$application_key_id:$application_key"); | |
$url = "https://api.backblazeb2.com/b2api/v2/b2_authorize_account"; | |
$session = curl_init($url); | |
$headers = array( | |
"Accept: application/json", | |
"Authorization: Basic $credentials" | |
); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_HTTPGET, true); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "Calling b2_authorize_account... "; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code \n"; | |
echo "$server_output\n"; | |
$auth_response = json_decode($server_output); | |
$account_id = $auth_response->accountId; | |
$api_url = $auth_response->apiUrl; | |
$auth_token = $auth_response->authorizationToken; | |
// | |
// Get the id from the bucket name | |
// | |
$session = curl_init($api_url . "/b2api/v2/b2_list_buckets"); | |
$data = array( | |
"accountId" => $account_id, | |
"bucketName" => $bucket_name | |
); | |
$headers = array( | |
"Authorization: $auth_token" | |
); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_POSTFIELDS, json_encode($data)); | |
curl_setopt($session, CURLOPT_POST, true); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "Calling b2_list_buckets... "; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code \n"; | |
echo "$server_output\n"; | |
$list_response = json_decode($server_output); | |
$bucket_id = $list_response->buckets[0]->bucketId; | |
// | |
// Set up the large file upload | |
// | |
$file_name = basename($local_file); | |
$content_type = "b2/x-auto"; | |
$data = array( | |
"fileName" => $file_name, | |
"bucketId" => $bucket_id, | |
"contentType" => $content_type | |
); | |
$headers = array( | |
"Accept: application/json", | |
"Authorization: $auth_token" | |
); | |
$session = curl_init("$api_url/b2api/v2/b2_start_large_file"); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_POSTFIELDS, json_encode($data)); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "Calling b2_start_large_file... "; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code \n"; | |
echo "$server_output\n"; | |
$start_response = json_decode($server_output); | |
$file_id = $start_response->fileId; | |
// This sample uses the smallest permitted part size, 5 MB, to more easily show | |
// multipart uploads in action. The default part size is 100 MB | |
$part_size = 5 * 1000 * 1000; | |
$local_file_size = filesize($local_file); | |
$total_bytes_sent = 0; | |
$sha1_of_parts = array(); | |
$part_no = 1; | |
$file_handle = fopen($local_file, "r"); | |
// Loop through parts of file | |
// | |
// Note - for simplicity, this sample does not handle errors or implement the | |
// retry logic outlined at https://www.backblaze.com/b2/docs/uploading.html | |
// | |
// Production code should implement error handling and retry requests. | |
// | |
while ($total_bytes_sent < $local_file_size) { | |
// | |
// Get upload part URL | |
// | |
$data = array("fileId" => $file_id); | |
$headers = array( | |
"Accept: application/json", | |
"Authorization: $auth_token" | |
); | |
$session = curl_init("$api_url/b2api/v2/b2_get_upload_part_url"); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_POSTFIELDS, json_encode($data)); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "b2_get_upload_part_url..."; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code \n"; | |
echo "$server_output\n"; | |
$part_response = json_decode($server_output); | |
$large_file_auth_token = $part_response->authorizationToken; | |
$upload_url = $part_response->uploadUrl; | |
$bytes_sent_for_part = min($local_file_size - $total_bytes_sent, $part_size); | |
// | |
// Upload the part to the URL we just received | |
// | |
// Get a sha1 of the part we are going to send | |
fseek($file_handle, $total_bytes_sent); | |
$data_part = fread($file_handle, $bytes_sent_for_part); | |
array_push($sha1_of_parts, sha1($data_part)); | |
fseek($file_handle, $total_bytes_sent); | |
$session = curl_init($upload_url); | |
// NOTE - we need to set a blank Transfer-Encoding header, otherwise PHP will | |
// default to chunked transfer encoding and remove the content length header | |
$headers = array( | |
"Accept: application/json", | |
"Authorization: $large_file_auth_token", | |
"Transfer-Encoding:", | |
"Content-Length: $bytes_sent_for_part", | |
"X-Bz-Part-Number: $part_no", | |
"X-Bz-Content-Sha1: {$sha1_of_parts[$part_no - 1]}" | |
); | |
curl_setopt($session, CURLOPT_POST, true); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_INFILE, $file_handle); | |
curl_setopt($session, CURLOPT_INFILESIZE, (int)$bytes_sent_for_part); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "Calling b2_upload_part with $bytes_sent_for_part bytes... "; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code\n"; | |
echo "$server_output\n"; | |
$part_no++; | |
$total_bytes_sent += $bytes_sent_for_part; | |
} | |
fclose($file_handle); | |
// | |
// Finish the upload | |
// | |
$session = curl_init("$api_url/b2api/v2/b2_finish_large_file"); | |
$data = array( | |
"fileId" => $file_id, | |
"partSha1Array" => $sha1_of_parts | |
); | |
$headers = array( | |
"Accept: application/json", | |
"Authorization: $auth_token" | |
); | |
curl_setopt($session, CURLOPT_POSTFIELDS, json_encode($data)); | |
curl_setopt($session, CURLOPT_HTTPHEADER, $headers); | |
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); | |
curl_setopt($session, CURLOPT_VERBOSE, $verbose); | |
echo "b2_finish_large_file... "; | |
$server_output = curl_exec($session); | |
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE); | |
curl_close ($session); | |
echo "status: $http_code\n"; | |
echo "$server_output\n"; | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment