By default, objects in an Object Storage Service (OSS) bucket are private and can be accessed only by the object owner. This topic describes how to use the OSS SDK for PHP to generate a presigned URL for a PUT request. This URL allows other users to temporarily upload files and can be used multiple times before it expires. After the URL expires, you must generate a new one.
Notes
The sample code in this topic uses the region ID
cn-hangzhoufor the China (Hangzhou) region. By default, a public endpoint is used to access resources in a bucket. If you want to access resources in the bucket from other Alibaba Cloud services in the same region as the bucket, use an internal endpoint. For more information about supported regions and endpoints, see Regions and endpoints.You do not need specific permissions to generate a presigned URL. However, to allow others to use the presigned URL for uploading an object, you must have the
oss:PutObjectpermission. For more information, see Authorize a RAM user to access multiple directories in a bucket.In this topic, the V4 signature algorithm is used to generate presigned URLs with a validity period of up to 7 days. For more information, see (Recommended) Include a V4 signature in a URL.
In this topic, access credentials are retrieved from environment variables. For more information, see Configure access credentials for OSS SDK for PHP.
Process
The following figure shows how to use a presigned URL that allows HTTP PUT requests to upload an object to OSS.
Sample code
The object owner generates a presigned URL that allows HTTP PUT requests.
ImportantIf you specify request headers when you generate a presigned URL that allows HTTP PUT requests, ensure that the request headers are included in the PUT request initiated using the presigned URL. This prevents request failures or signature errors.
<?php // Include the autoload file to ensure that dependency libraries are correctly loaded. require_once __DIR__ . '/../vendor/autoload.php'; use AlibabaCloud\Oss\V2 as Oss; // Define the descriptions for command-line arguments. $optsdesc = [ "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // The region in which the bucket is located. (Required) "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // The endpoint. (Optional) "bucket" => ['help' => 'The name of the bucket', 'required' => True], // The name of the bucket. (Required) "key" => ['help' => 'The name of the object', 'required' => True], // The name of the object. (Required) ]; // Convert the argument descriptions to the long option format required by getopt. // Add a colon (:) to the end of each argument to indicate that the argument requires a value. $longopts = \array_map(function ($key) { return "$key:"; }, array_keys($optsdesc)); // Parse the command-line arguments. $options = getopt("", $longopts); // Check whether required arguments are specified. foreach ($optsdesc as $key => $value) { if ($value['required'] === True && empty($options[$key])) { $help = $value['help']; // Obtain the help information of the argument. echo "Error: the following arguments are required: --$key, $help" . PHP_EOL; exit(1); // If a required argument is not specified, exit the program. } } // Extract values from the parsed arguments. $region = $options["region"]; // The region in which the bucket is located. $bucket = $options["bucket"]; // The name of the bucket. $key = $options["key"]; // The name of the object. // Load the access credential from the environment variable. // Use EnvironmentVariableCredentialsProvider to read the AccessKey ID and AccessKey secret from environment variables. $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider(); // Use the default configurations of the SDK. $cfg = Oss\Config::loadDefault(); $cfg->setCredentialsProvider($credentialsProvider); // Set the credential provider. $cfg->setRegion($region); // Set the region in which the bucket is located. if (isset($options["endpoint"])) { $cfg->setEndpoint($options["endpoint"]); // If an endpoint is provided, set the endpoint. } // Create an OSS client instance. $client = new Oss\Client($cfg); // Create a PutObjectRequest object to upload the object. $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key); // Call the presign method to generate a presigned URL. $result = $client->presign($request); // Print the presign result. // The presigned URL is printed. You can use this URL to upload the object. print( 'put object presign result:' . var_export($result, true) . PHP_EOL . // The details of the presign result. 'put object url:' . $result->url . PHP_EOL // The presigned URL that is used to directly upload the object. );A third party uses the presigned URL for the PUT request to upload a file.
curl
curl -X PUT -T /path/to/local/file "https://exampleobject.oss-cn-hangzhou.aliyuncs.com/exampleobject.txt?x-oss-date=20241112T083238Z&x-oss-expires=3599&x-oss-signature-version=OSS4-HMAC-SHA256&x-oss-credential=LTAI****************%2F20241112%2Fcn-hangzhou%2Foss%2Faliyun_v4_request&x-oss-signature=ed5a******************************************************"Java
import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.FileEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import java.io.*; import java.net.URL; import java.util.*; public class SignUrlUpload { public static void main(String[] args) throws Throwable { CloseableHttpClient httpClient = null; CloseableHttpResponse response = null; // Replace <signedUrl> with the presigned URL. URL signedUrl = new URL("<signedUrl>"); // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String pathName = "C:\\Users\\demo.txt"; try { HttpPut put = new HttpPut(signedUrl.toString()); System.out.println(put); HttpEntity entity = new FileEntity(new File(pathName)); put.setEntity(entity); httpClient = HttpClients.createDefault(); response = httpClient.execute(put); System.out.println("Status code:"+response.getStatusLine().getStatusCode()); if(response.getStatusLine().getStatusCode() == 200){ System.out.println("The object is uploaded by using the library."); } System.out.println(response.toString()); } catch (Exception e){ e.printStackTrace(); } finally { response.close(); httpClient.close(); } } }Go
package main import ( "fmt" "io" "net/http" "os" ) func uploadFile(signedUrl, filePath string) error { // Open the local file. file, err := os.Open(filePath) if err != nil { return fmt.Errorf("Unable to open the local file: %w", err) } defer file.Close() // Create an HTTP client. client := &http.Client{} // Create a PUT request. req, err := http.NewRequest("PUT", signedUrl, file) if err != nil { return fmt.Errorf("Failed to create the request: %w", err) } // Send the request. resp, err := client.Do(req) if err != nil { return fmt.Errorf("Failed to send the request:: %w", err) } defer resp.Body.Close() // Read the response. body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("Failed to read the request: %w", err) } fmt.Printf("Status code: %d\n", resp.StatusCode) if resp.StatusCode == 200 { fmt.Println("The object is uploaded by using the library.") } fmt.Println(string(body)) return nil } func main() { // Replace <signedUrl> with the presigned URL. signedUrl := "<signedUrl>" // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. filePath := "C:\\Users\\demo.txt" err := uploadFile(signedUrl, filePath) if err != nil { fmt.Println("An error occurred: ", err) } }python
import requests def upload_file(signed_url, file_path): try: # Open the local file that you want to upload. with open(file_path, 'rb') as file: # Send a PUT request to upload the local file. response = requests.put(signed_url, data=file) print(f"Status code: {response.status_code}") if response.status_code == 200: print("The object is uploaded by using the library.") print(response.text) except Exception as e: print(f"An error occurred: {e}") if __name__ == "__main__": # Replace <signedUrl> with the generated signed URL. signed_url = "<signedUrl>" # Specify the full path of the local file. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. file_path = "C:\\Users\\demo.txt" upload_file(signed_url, file_path)Node.js
const fs = require('fs'); const axios = require('axios'); async function uploadFile(signedUrl, filePath) { try { // Create a read stream. const fileStream = fs.createReadStream(filePath); // Send a PUT request to upload the local file. const response = await axios.put(signedUrl, fileStream, { headers: { 'Content-Type': 'application/octet-stream' // Specify the Content-Type parameter. } }); console.log(`Status code: ${response.status}`); if (response.status === 200) { console.log("The object is uploaded by using the library."); } console.log(response.data); } catch (error) { console.error(`An error occurred: ${error.message}`); } } // Specify the main function. (async () => { // Replace <signedUrl> with the presigned URL. const signedUrl = '<signedUrl>'; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. const filePath = 'C:\\Users\\demo.txt'; await uploadFile(signedUrl, filePath); })();browser.js
ImportantWhen uploading an object using Browser.js and a presigned URL, a 403 SignatureNotMatch error that indicates signature inconsistency may occur. This is typically caused by the browser's automatic inclusion of the Content-Type request header, which that was not specified when the presigned URL was generated. To prevent this error, ensure that the Content-Type header is specified when generating a presigned URL.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>File Upload Example</title> </head> <body> <h1>File Upload Example</h1> <! -- Select File --> <input type="file" id="fileInput" /> <button id="uploadButton">Upload File</button> <script> // Replace <signedUrl> with the presigned URL that was generated in Step 1. const signedUrl = "<signedUrl>"; document.getElementById('uploadButton').addEventListener('click', async () => { const fileInput = document.getElementById('fileInput'); const file = fileInput.files[0]; if (!file) { alert('Please select a file to upload.'); return; } try { await upload(file, signedUrl); alert('File uploaded successfully!'); } catch (error) { console.error('Error during upload:', error); alert('Upload failed: ' + error.message); } }); /** * Upload a file to OSS. * @param {File} file - The file to be uploaded. * @param {string} presignedUrl - The presigned URL. */ const upload = async (file, presignedUrl) => { const response = await fetch(presignedUrl, { method: 'PUT', body: file, // Upload the entire file. }); if (!response.ok) { throw new Error(`Upload failed, status: ${response.status}`); } console.log('File uploaded successfully'); }; </script> </body> </html>C#
using System.Net.Http.Headers; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. var filePath = "C:\\Users\\demo.txt"; // Replace <signedUrl> with the presigned URL. var presignedUrl = "<signedUrl>"; // Create an HTTP client and a local file stream. using var httpClient = new HttpClient(); using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read); using var content = new StreamContent(fileStream); // Create a PUT request. var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl); request.Content = content; // Send a request. var response = await httpClient.SendAsync(request); // Process the response. if (response.IsSuccessStatusCode) { Console.WriteLine($"Uploaded! Status Code: {response.StatusCode}"); Console.WriteLine("Response Header:"); foreach (var header in response.Headers) { Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}"); } } else { string responseContent = await response.Content.ReadAsStringAsync(); Console.WriteLine($"Upload Failed! Status Code: {response.StatusCode}"); Console.WriteLine("Response content: " + responseContent); }C++
#include <iostream> #include <fstream> #include <curl/curl.h> void uploadFile(const std::string& signedUrl, const std::string& filePath) { CURL *curl; CURLcode res; curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init(); if (curl) { // Specify the presigned URL. curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str()); // Set the request method to PUT. curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); // Open the local file. FILE *file = fopen(filePath.c_str(), "rb"); if (!file) { std::cerr << "Unable to open the file: " << filePath << std::endl; return; } // Query the size of the local file. fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); // Specify the size of the local file. curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize); // Specify the input file handle. curl_easy_setopt(curl, CURLOPT_READDATA, file); // Execute the request. res = curl_easy_perform(curl); if (res != CURLE_OK) { std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; } else { long httpCode = 0; curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); std::cout << "Status code: " << httpCode << std::endl; if (httpCode == 200) { std::cout << "The object is uploaded by using the network library." << std::endl; } } // Close the local file. fclose(file); // Clear the cURL handle. curl_easy_cleanup(curl); } curl_global_cleanup(); } int main() { // Replace <signedUrl> with the presigned URL. std::string signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. std::string filePath = "C:\\Users\\demo.txt"; uploadFile(signedUrl, filePath); return 0; }Android
package com.example.signurlupload; import android.os.AsyncTask; import android.util.Log; import java.io.DataOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; public class SignUrlUploadActivity { private static final String TAG = "SignUrlUploadActivity"; public void uploadFile(String signedUrl, String filePath) { new UploadTask().execute(signedUrl, filePath); } private class UploadTask extends AsyncTask<String, Void, String> { @Override protected String doInBackground(String... params) { String signedUrl = params[0]; String filePath = params[1]; HttpURLConnection connection = null; DataOutputStream dos = null; FileInputStream fis = null; try { URL url = new URL(signedUrl); connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("PUT"); connection.setDoOutput(true); connection.setRequestProperty("Content-Type", "application/octet-stream"); fis = new FileInputStream(filePath); dos = new DataOutputStream(connection.getOutputStream()); byte[] buffer = new byte[1024]; int length; while ((length = fis.read(buffer)) != -1) { dos.write(buffer, 0, length); } dos.flush(); dos.close(); fis.close(); int responseCode = connection.getResponseCode(); Log.d(TAG, "Status code: " + responseCode); if (responseCode == 200) { Log.d(TAG, "The object is uploaded by using the library."); } return "Object uploaded. Status code: " + responseCode; } catch (IOException e) { e.printStackTrace(); return "Upload failed: " + e.getMessage(); } finally { if (connection != null) { connection.disconnect(); } } } @Override protected void onPostExecute(String result) { Log.d(TAG, result); } } public static void main(String[] args) { SignUrlUploadActivity activity = new SignUrlUploadActivity(); // Replace <signedUrl> with the presigned URL. String signedUrl = "<signedUrl>"; // Specify the full path of the local file that you want to upload. If the path of the local file is not specified, the local file is uploaded from the path of the project to which the sample program belongs. String filePath = "C:\\Users\\demo.txt"; activity.uploadFile(signedUrl, filePath); } }
Common scenarios
References
For the complete sample code for presigned URLs, see GitHub examples.
For more information about the API operation for presigned URLs, see Presign.