全部产品
Search
文档中心

Object Storage Service:Unggah objek dengan URL bertanda tangan menggunakan OSS SDK for PHP 2.0

更新时间:Aug 07, 2025

Secara default, daftar kontrol akses (ACL) dari sebuah objek dalam bucket Object Storage Service (OSS) diatur ke privat, yang berarti hanya pemilik objek yang memiliki izin untuk mengaksesnya. Topik ini menjelaskan cara menggunakan OSS SDK for PHP untuk menghasilkan URL bertanda tangan yang memungkinkan pengguna mengunggah objek tertentu dalam periode yang ditentukan menggunakan metode HTTP PUT. Selama periode validitas, pengguna dapat mengakses objek tersebut secara berulang menggunakan URL bertanda tangan. Jika URL bertanda tangan kedaluwarsa, Anda dapat membuat ulang URL bertanda tangan untuk memperpanjang akses bagi pengguna.

Catatan

  • Kode contoh dalam topik ini menggunakan ID Wilayah cn-hangzhou dari wilayah Hangzhou, Tiongkok. Secara default, titik akhir publik digunakan untuk mengakses sumber daya dalam bucket. Jika Anda ingin mengakses sumber daya di bucket dari layanan Alibaba Cloud lainnya di wilayah yang sama dengan lokasi bucket, gunakan titik akhir internal. Untuk informasi lebih lanjut tentang wilayah dan titik akhir yang didukung, lihat Wilayah dan Titik Akhir.

  • Anda tidak memerlukan izin khusus untuk menghasilkan URL bertanda tangan. Namun, untuk mengizinkan pihak ketiga menggunakan URL bertanda tangan untuk mengunggah objek, Anda harus memiliki izin oss:PutObject. Untuk informasi lebih lanjut, lihat Memberikan Izin kepada Pengguna RAM Menggunakan Kebijakan Kustom.

  • Dalam topik ini, algoritma tanda tangan V4 digunakan untuk menghasilkan URL bertanda tangan dengan periode validitas hingga 7 hari. Untuk informasi lebih lanjut, lihat (Direkomendasikan) Sertakan Tanda Tangan V4 dalam URL.

  • Dalam topik ini, kredensial akses diperoleh dari variabel lingkungan. Untuk informasi lebih lanjut, lihat Konfigurasi Kredensial Akses untuk OSS SDK for PHP.

Proses

Gambar berikut menunjukkan cara menggunakan URL bertanda tangan yang mengizinkan permintaan HTTP PUT untuk mengunggah objek ke OSS.

Kode contoh

  1. Pemilik objek menghasilkan URL bertanda tangan yang mengizinkan permintaan HTTP PUT.

    Penting

    Jika Anda menentukan header permintaan saat menghasilkan URL bertanda tangan yang mengizinkan permintaan HTTP PUT, pastikan bahwa header permintaan tersebut termasuk dalam permintaan PUT yang dimulai menggunakan URL bertanda tangan. Ini mencegah kegagalan permintaan dan kesalahan tanda tangan.

    <?php
    
    // Sertakan file autoload untuk memuat dependensi.
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // Tentukan dan jelaskan opsi baris perintah.
    $optsdesc = [
        "region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => True], // (Diperlukan) Tentukan wilayah tempat bucket berada.
        "endpoint" => ['help' => 'Nama domain yang dapat digunakan layanan lain untuk mengakses OSS.', 'required' => False], // (Opsional) Tentukan titik akhir untuk mengakses OSS.
        "bucket" => ['help' => 'Nama bucket', 'required' => True], // (Diperlukan) Tentukan nama bucket.
        "key" => ['help' => 'Nama objek', 'required' => True], // (Diperlukan) Tentukan nama objek.
    ];
    
    // Ubah deskripsi menjadi daftar opsi panjang yang diperlukan oleh getopt.
    // Tambahkan titik dua (:) di akhir setiap opsi untuk menunjukkan bahwa nilai diperlukan.
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // Analisis opsi baris perintah.
    $options = getopt("", $longopts);
    
    // Periksa apakah opsi yang diperlukan hilang.
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // Dapatkan informasi bantuan.
            echo "Error: argumen berikut diperlukan: --$key, $help" . PHP_EOL;
            exit(1); // Keluar dari program jika opsi yang diperlukan hilang.
        }
    }
    
    // Tetapkan nilai yang diurai dari opsi baris perintah ke variabel yang sesuai.
    $region = $options["region"]; // Wilayah tempat bucket berada.
    $bucket = $options["bucket"]; // Nama bucket.
    $key = $options["key"]; // Nama objek 
    
    // Muat kredensial akses dari variabel lingkungan.
    // Gunakan EnvironmentVariableCredentialsProvider untuk mengambil ID AccessKey dan Rahasia AccessKey dari variabel lingkungan.
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // Gunakan konfigurasi default dari SDK.
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // Tentukan penyedia kredensial.
    $cfg->setRegion($region); // Tentukan wilayah tempat bucket berada.
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // Tentukan titik akhir jika ada yang diberikan.
    }
    
    // Buat instance klien OSS.
    $client = new Oss\Client($cfg);
    
    // Buat objek PutObjectRequest untuk mengunggah data.
    $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key);
    
    // Panggil metode presign untuk menghasilkan permintaan bertanda tangan.
    $result = $client->presign($request);
    
    // Tampilkan hasil operasi presign.
    // Tampilkan URL bertanda tangan, yang dapat digunakan untuk mengunggah objek yang ditentukan.
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL . // Detail hasil presign.
        'put object url:' . $result->url . PHP_EOL                           // URL bertanda tangan.
    );
    
  2. Pengguna menggunakan URL bertanda tangan untuk mengunggah objek.

    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;
    
            // Ganti <signedUrl> dengan URL otorisasi.
            URL signedUrl = new URL("<signedUrl>");
    
            // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
            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("Kode status yang dikembalikan:" + response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Berhasil diunggah menggunakan pustaka jaringan.");
                }
                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 {
    	// Buka file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("Gagal membuka file: %w", err)
    	}
    	defer file.Close()
    
    	// Buat klien HTTP baru.
    	client := &http.Client{}
    
    	// Buat permintaan PUT.
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("Gagal membuat permintaan: %w", err)
    	}
    
    	// Kirim permintaan.
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("Gagal mengirim permintaan: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// Baca tanggapan.
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("Gagal membaca tanggapan: %w", err)
    	}
    
    	fmt.Printf("Kode status yang dikembalikan: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Berhasil diunggah menggunakan pustaka jaringan.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Ganti <signedUrl> dengan URL otorisasi.
    	signedUrl := "<signedUrl>"
    
    	// Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
    	filePath := "C:\\Users\\demo.txt"
    
    	err := uploadFile(signedUrl, filePath)
    	if err != nil {
    		fmt.Println("Terjadi kesalahan:", err)
    	}
    }
    

    python

    import requests
    
    def upload_file(signed_url, file_path):
        try:
            # Buka file.
            with open(file_path, 'rb') as file:
                # Kirim permintaan PUT untuk mengunggah file.
                response = requests.put(signed_url, data=file)
         
            print(f"Kode status yang dikembalikan: {response.status_code}")
            if response.status_code == 200:
                print("Berhasil diunggah menggunakan pustaka jaringan.")
            print(response.text)
     
        except Exception as e:
            print(f"Terjadi kesalahan: {e}")
    
    if __name__ == "__main__":
        # Ganti <signedUrl> dengan URL otorisasi.
        signed_url = "<signedUrl>"
        
        # Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
        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 {
            // Buat aliran baca.
            const fileStream = fs.createReadStream(filePath);
            
            // Kirim permintaan PUT untuk mengunggah file.
            const response = await axios.put(signedUrl, fileStream, {
                headers: {
                    'Content-Type': 'application/octet-stream' // Sesuaikan Content-Type berdasarkan kebutuhan Anda.
                }
            });
    
            console.log(`Kode status yang dikembalikan: ${response.status}`);
            if (response.status === 200) {
                console.log('Berhasil diunggah menggunakan pustaka jaringan.');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`Terjadi kesalahan: ${error.message}`);
        }
    }
    
    // Fungsi utama.
    (async () => {
        // Ganti <signedUrl> dengan URL otorisasi.
        const signedUrl = '<signedUrl>';
        
        // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    Penting

    Jika Anda menggunakan Browser.js untuk mengunggah file dan mengalami kesalahan 403 SignatureDoesNotMatch, kesalahan ini biasanya terjadi karena browser secara otomatis menambahkan header permintaan Content-Type. Jika header ini tidak ditentukan saat URL bertanda tangan dihasilkan, verifikasi tanda tangan gagal. Untuk menyelesaikan masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL bertanda tangan.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Contoh Unggah File</title>
    </head>
    <body>
        <h1>Contoh Unggah File</h1>
    
        <!-- Pilih file -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Unggah File</button>
    
        <script>
            // Ganti ini dengan URL bertanda tangan yang dihasilkan pada Langkah 1.
            const signedUrl = "<signedUrl>"; 
    
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('Silakan pilih file untuk diunggah.');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('File berhasil diunggah!');
                } catch (error) {
                    console.error('Kesalahan selama unggah:', error);
                    alert('Unggah gagal: ' + error.message);
                }
            });
    
            /**
             * Unggah file ke OSS.
             * @param {File} file - File yang akan diunggah.
             * @param {string} presignedUrl - URL bertanda tangan.
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: file,  // Unggah seluruh file.
                });
    
                if (!response.ok) {
                    throw new Error(`Unggah gagal, status: ${response.status}`);
                }
    
                console.log('File berhasil diunggah');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
    var filePath = "C:\\Users\\demo.txt";
    // Ganti <signedUrl> dengan URL otorisasi.
    var presignedUrl = "<signedUrl>";
    
    // Buat klien HTTP dan buka aliran file lokal.
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // Buat permintaan PUT.
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // Kirim permintaan.
    var response = await httpClient.SendAsync(request);
    
    // Proses tanggapan.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Berhasil diunggah! Kode status: {response.StatusCode}");
        Console.WriteLine("Header tanggapan:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Unggah gagal! Kode status: {response.StatusCode}");
        Console.WriteLine("Isi tanggapan: " + 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) {
            // Setel URL.
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Setel metode permintaan ke PUT.
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Buka file.
            FILE *file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Gagal membuka file: " << filePath << std::endl;
                return;
            }
    
            // Dapatkan ukuran file.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // Setel ukuran file.
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Setel pegangan file input.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // Eksekusi permintaan.
            res = curl_easy_perform(curl);
    
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() gagal: " << curl_easy_strerror(res) << std::endl;
            } else {
                long httpCode = 0;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode);
                std::cout << "Kode status yang dikembalikan: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "Berhasil diunggah menggunakan pustaka jaringan." << std::endl;
                }
            }
    
            // Tutup file.
            fclose(file);
    
            // Bersihkan.
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Ganti <signedUrl> dengan URL otorisasi.
        std::string signedUrl = "<signedUrl>";
    
        // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
        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, "Kode status yang dikembalikan: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "Berhasil diunggah menggunakan pustaka jaringan.");
                    }
    
                    return "Unggah selesai. Kode status: " + responseCode;
    
                } catch (IOException e) {
                    e.printStackTrace();
                    return "Unggah gagal: " + 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();
            // Ganti <signedUrl> dengan URL otorisasi.
            String signedUrl = "<signedUrl>";
            // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

Skenario umum

Gunakan URL bertanda tangan yang berisi header permintaan spesifik dan metadata pengguna untuk mengunggah file

  1. Pemilik objek menghasilkan URL bertanda tangan yang mengizinkan permintaan HTTP PUT.

    <?php
    
    // Sertakan file autoload untuk memuat dependensi.
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // Tentukan dan jelaskan opsi baris perintah.
    $optsdesc = [
        "region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => True], // (Diperlukan) Tentukan wilayah tempat bucket berada.
        "endpoint" => ['help' => 'Nama domain yang dapat digunakan layanan lain untuk mengakses OSS.', 'required' => False], // (Opsional) Tentukan titik akhir untuk mengakses OSS.
        "bucket" => ['help' => 'Nama bucket', 'required' => True], // (Diperlukan) Tentukan nama bucket.
        "key" => ['help' => 'Nama objek', 'required' => True], // (Diperlukan) Tentukan nama objek.
    ];
    
    // Ubah deskripsi menjadi daftar opsi panjang yang diperlukan oleh getopt.
    // Tambahkan titik dua (:) di akhir setiap opsi untuk menunjukkan bahwa nilai diperlukan.
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // Analisis opsi baris perintah.
    $options = getopt("", $longopts);
    
    // Periksa apakah opsi yang diperlukan hilang.
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // Dapatkan informasi bantuan.
            echo "Error: argumen berikut diperlukan: --$key, $help" . PHP_EOL;
            exit(1); // Keluar dari program jika opsi yang diperlukan hilang.
        }
    }
    
    // Tetapkan nilai yang diurai dari opsi baris perintah ke variabel yang sesuai.
    $region = $options["region"]; // Wilayah tempat bucket berada.
    $bucket = $options["bucket"]; // Nama bucket.
    $key = $options["key"];       // Nama objek.
    
    // Muat kredensial akses dari variabel lingkungan.
    // Gunakan EnvironmentVariableCredentialsProvider untuk mengambil ID AccessKey dan Rahasia AccessKey dari variabel lingkungan.
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // Gunakan konfigurasi default dari SDK.
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // Tentukan penyedia kredensial.
    $cfg->setRegion($region); // Tentukan wilayah tempat bucket berada.
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // Tentukan titik akhir jika ada yang diberikan.
    }
    
    // Buat instance klien OSS.
    $client = new Oss\Client($cfg);
    
    // Setel tipe konten ke teks.
    $contentType = "text/plain; charset=utf-8";
    
    // Tentukan metadata kustom.
    $metadata = [
        "key1" => "value1",
        "key2" => "value2",
    ];
    
    // Buat objek PutObjectRequest untuk mengunggah data. Perhatikan bahwa parameter contentType dan metadata disertakan untuk perhitungan tanda tangan. 
    $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key, contentType: $contentType, metadata: $metadata);
    
    // Panggil metode presign untuk menghasilkan permintaan bertanda tangan.
    $result = $client->presign($request);
    
    // Tampilkan hasil operasi presign.
    // Tampilkan URL bertanda tangan, yang dapat digunakan untuk mengunggah objek yang ditentukan.
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL . // Detail hasil presign.
        'put object url:' . $result->url . PHP_EOL                           // URL bertanda tangan.
    );
    
  2. Pengguna yang memiliki URL bertanda tangan menggunakannya untuk mengunggah objek.

    curl

    curl -X PUT \
         -H "Content-Type: text/plain;charset=utf8" \
         -H "x-oss-storage-class: Standard" \
         -H "x-oss-meta-key1: value1" \
         -H "x-oss-meta-key2: value2" \
         -T "C:\\Users\\demo.txt" \
         "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 com.aliyun.oss.internal.OSSHeaders;
    import com.aliyun.oss.model.StorageClass;
    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;
    
            // Ganti <signedUrl> dengan URL otorisasi.
            URL signedUrl = new URL("<signedUrl>");
    
            // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
            String pathName = "C:\\Users\\demo.txt";
    
            // Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> headers = new HashMap<String, String>();
            //Tentukan kelas penyimpanan objek.
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            //Tentukan ContentType.
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // Tentukan metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
            Map<String, String> userMetadata = new HashMap<String, String>();
            userMetadata.put("key1","value1");
            userMetadata.put("key2","value2");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // Jika parameter header seperti metadata kustom dan kelas penyimpanan diatur saat URL bertanda tangan dihasilkan, parameter ini juga harus dikirim ke server saat Anda menggunakan URL bertanda tangan untuk mengunggah file. Jika tanda tangan yang dikirim ke server berbeda dari tanda tangan yang dihasilkan, kesalahan tanda tangan dilaporkan.
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // Jika Anda menggunakan userMeta, SDK secara internal menambahkan awalan "x-oss-meta-" ke userMeta. Saat Anda menggunakan metode lain untuk menghasilkan URL bertanda tangan untuk unggahan, Anda juga harus menambahkan awalan "x-oss-meta-" ke userMeta.
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Kode status yang dikembalikan:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Berhasil diunggah menggunakan pustaka jaringan.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io/ioutil"
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string, metadata map[string]string) error {
    	// Buka file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Baca isi file.
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Buat permintaan.
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Setel header permintaan.
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// Setel metadata kustom.
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// Kirim permintaan.
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Proses tanggapan.
    	fmt.Printf("Kode status yang dikembalikan: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Berhasil diunggah menggunakan pustaka jaringan.")
    	} else {
    		fmt.Println("Unggah gagal.")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Ganti <signedUrl> dengan URL otorisasi.
    	signedUrl := "<signedUrl>"
    
    	// Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
    	headers := map[string]string{
    		"Content-Type": "text/plain;charset=utf8",
    		"x-oss-storage-class": "Standard",
    	}
    
    	// Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
    	metadata := map[string]string{
    		"key1": "value1",
    		"key2": "value2",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers, metadata)
    	if err != nil {
    		fmt.Printf("Terjadi kesalahan: %v\n", err)
    	}
    }
    

    Python

    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        Gunakan URL bertanda tangan untuk mengunggah file ke OSS.
    
        :param signed_url: URL bertanda tangan.
        :param file_path: Jalur lengkap file yang akan diunggah.
        :param headers: Opsional. Header HTTP kustom.
        :param metadata: Opsional. Metadata kustom.
        :return: None
        """
        if not headers:
            headers = {}
        if not metadata:
            metadata = {}
    
        # Perbarui header dan tambahkan awalan metadata.
        for key, value in metadata.items():
            headers[f'x-oss-meta-{key}'] = value
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Kode status yang dikembalikan: {response.status_code}")
                if response.status_code == 200:
                    print("Berhasil diunggah menggunakan pustaka jaringan.")
                else:
                    print("Unggah gagal.")
                print(response.text)
        except Exception as e:
            print(f"Terjadi kesalahan: {e}")
    
    if __name__ == "__main__":
        # Ganti <signedUrl> dengan URL otorisasi.
        signed_url = "<signedUrl>"
       
        # Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari direktori tempat skrip berada secara default.
        file_path = "C:\\Users\\demo.txt"
    
        # Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        # Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
        metadata = {
             "key1": "value1",
             "key2": "value2"
        }
    
        upload_file(signed_url, file_path, headers, metadata)
    

    Node.js

    const fs = require('fs');
    const axios = require('axios');
    
    async function uploadFile(signedUrl, filePath, headers = {}, metadata = {}) {
        try {
            // Perbarui header dan tambahkan awalan metadata.
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // Baca aliran file.
            const fileStream = fs.createReadStream(filePath);
    
            // Kirim permintaan PUT.
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Kode status yang dikembalikan: ${response.status}`);
            if (response.status === 200) {
                console.log("Berhasil diunggah menggunakan pustaka jaringan.");
            } else {
                console.log("Unggah gagal.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`Terjadi kesalahan: ${error.message}`);
        }
    }
    
    // Fungsi utama.
    (async () => {
        // Ganti <signedUrl> dengan URL otorisasi.
        const signedUrl = "<signedUrl>";
    
        // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari direktori tempat skrip berada secara default.
        const filePath = "C:\\Users\\demo.txt";
    
        // Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    Penting

    Jika Anda menggunakan Browser.js untuk mengunggah file dan mengalami kesalahan 403 SignatureDoesNotMatch, kesalahan ini biasanya terjadi karena browser secara otomatis menambahkan header permintaan Content-Type. Jika header ini tidak ditentukan saat URL bertanda tangan dihasilkan, verifikasi tanda tangan gagal. Untuk menyelesaikan masalah ini, Anda harus menentukan header permintaan Content-Type saat menghasilkan URL bertanda tangan.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Contoh Unggah File</title>
    </head>
    <body>
        <h1>Contoh Unggah File (OSS SDK for Java)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Unggah File</button>
    
        <script>
            // Ganti ini dengan URL bertanda tangan sebenarnya.
            const signedUrl = "<signedUrl>"; 
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (file) {
                    try {
                        await upload(file, signedUrl);
                    } catch (error) {
                        console.error('Kesalahan selama unggah:', error);
                        alert('Unggah gagal: ' + error.message);
                    }
                } else {
                    alert('Silakan pilih file untuk diunggah.');
                }
            });
    
            const upload = async (file, presignedUrl) => {
                const headers = {
                    "Content-Type": "text/plain;charset=utf8",
                    'x-oss-storage-class': 'Standard',
                    'x-oss-meta-key1': 'value1',
                    'x-oss-meta-key2': 'value2'
                };
    
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    headers: headers,
                    body: file
                });
    
                if (!response.ok) {
                    throw new Error(`Unggah gagal, status: ${response.status}`);
                }
    
                alert('File berhasil diunggah');
                console.log('File berhasil diunggah');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
    var filePath = "C:\\Users\\demo.txt";
    // Ganti <signedUrl> dengan URL otorisasi.
    var presignedUrl = "<signedUrl>";
    
    // Buat klien HTTP dan buka aliran file lokal.
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // Buat permintaan PUT.
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // Jika parameter header seperti metadata kustom dan kelas penyimpanan diatur saat URL bertanda tangan dihasilkan, parameter ini juga harus dikirim ke server saat Anda menggunakan URL bertanda tangan untuk mengunggah file. Jika tanda tangan yang dikirim ke server berbeda dari tanda tangan yang dihasilkan, kesalahan tanda tangan dilaporkan.
    // Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // Tentukan ContentType.       
    // Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
    request.Content.Headers.Add("x-oss-meta-key1", "value1");
    request.Content.Headers.Add("x-oss-meta-key2", "value2");
    // Tentukan kelas penyimpanan objek.
    request.Content.Headers.Add("x-oss-storage-class", "Standard");
    
    // Keluarkan header permintaan.
    Console.WriteLine("Header permintaan:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // Kirim permintaan.
    var response = await httpClient.SendAsync(request);
    
    // Proses tanggapan.
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Berhasil diunggah! Kode status: {response.StatusCode}");
        Console.WriteLine("Header tanggapan:");
        foreach (var header in response.Headers)
        {
            Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
        }
    }
    else
    {
        string responseContent = await response.Content.ReadAsStringAsync();
        Console.WriteLine($"Unggah gagal! Kode status: {response.StatusCode}");
        Console.WriteLine("Isi tanggapan: " + responseContent);
    }

    C++

    #include <iostream>
    #include <fstream>
    #include <curl/curl.h>
    #include <map>
    #include <string>
    
    // Fungsi callback yang digunakan untuk memproses respons HTTP.
    size_t WriteCallback(void* contents, size_t size, size_t nmemb, std::string* output) {
        size_t totalSize = size * nmemb;
        output->append((char*)contents, totalSize);
        return totalSize;
    }
    
    void uploadFile(const std::string& signedUrl, const std::string& filePath, const std::map<std::string, std::string>& headers, const std::map<std::string, std::string>& metadata) {
        CURL* curl;
        CURLcode res;
        std::string readBuffer;
    
        curl_global_init(CURL_GLOBAL_DEFAULT);
        curl = curl_easy_init();
    
        if (curl) {
            // Setel URL.
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // Setel metode permintaan ke PUT.
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // Buka file.
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Gagal membuka file: " << filePath << std::endl;
                return;
            }
    
            // Setel ukuran file.
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // Setel callback pembacaan file.
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // Setel header permintaan.
            struct curl_slist* chunk = nullptr;
            for (const auto& header : headers) {
                std::string headerStr = header.first + ": " + header.second;
                chunk = curl_slist_append(chunk, headerStr.c_str());
            }
            for (const auto& meta : metadata) {
                std::string metaStr = "x-oss-meta-" + meta.first + ": " + meta.second;
                chunk = curl_slist_append(chunk, metaStr.c_str());
            }
            curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
    
            // Setel callback pemrosesan respons.
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // Eksekusi permintaan.
            res = curl_easy_perform(curl);
    
            // Periksa respons.
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() gagal: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Kode status yang dikembalikan: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "Berhasil diunggah menggunakan pustaka jaringan." << std::endl;
                } else {
                    std::cout << "Unggah gagal." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // Bersihkan.
            fclose(file);
            curl_slist_free_all(chunk);
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // Ganti <signedUrl> dengan URL otorisasi.
        std::string signedUrl = "<signedUrl>";
    
        // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
        std::string filePath = "C:\\Users\\demo.txt";
    
        // Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
        std::map<std::string, std::string> headers = {
             {"Content-Type", "text/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
        std::map<std::string, std::string> metadata = {
             {"key1", "value1"},
             {"key2", "value2"}
        };
    
        uploadFile(signedUrl, filePath, headers, metadata);
    
        return 0;
    }
    

    Android

    import android.os.AsyncTask;
    import android.util.Log;
    
    import java.io.DataOutputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Map.Entry;
    
    public class SignUrlUploadActivity extends AppCompatActivity {
    
        private static final String TAG = "SignUrlUploadActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // Ganti <signedUrl> dengan URL otorisasi.
            String signedUrl = "<signedUrl>";
    
            // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur yang sesuai dengan proyek program sampel secara default.
            String pathName = "/storage/emulated/0/demo.txt";
    
            // Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan saat URL dihasilkan.
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "text/plain;charset=utf8");
            headers.put("x-oss-storage-class", "Standard");
    
            // Setel metadata kustom. Metadata kustom harus sama dengan metadata kustom yang digunakan saat URL dihasilkan.
            Map<String, String> userMetadata = new HashMap<>();
            userMetadata.put("key1", "value1");
            userMetadata.put("key2", "value2");
    
            new UploadTask().execute(signedUrl, pathName, headers, userMetadata);
        }
    
        private class UploadTask extends AsyncTask<Object, Void, Integer> {
            @Override
            protected Integer doInBackground(Object... params) {
                String signedUrl = (String) params[0];
                String pathName = (String) params[1];
                Map<String, String> headers = (Map<String, String>) params[2];
                Map<String, String> userMetadata = (Map<String, String>) params[3];
    
                try {
                    URL url = new URL(signedUrl);
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("PUT");
                    connection.setDoOutput(true);
                    connection.setUseCaches(false);
    
                    // Setel header permintaan.
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // Setel metadata kustom.
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // Baca file.
                    File file = new File(pathName);
                    FileInputStream fileInputStream = new FileInputStream(file);
                    DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
    
                    byte[] buffer = new byte[1024];
                    int count;
                    while ((count = fileInputStream.read(buffer)) != -1) {
                        dos.write(buffer, 0, count);
                    }
    
                    fileInputStream.close();
                    dos.flush();
                    dos.close();
    
                    // Dapatkan respons.
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Kode status yang dikembalikan: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "Berhasil diunggah menggunakan pustaka jaringan.");
                    } else {
                        Log.d(TAG, "Unggah gagal.");
                    }
    
                    InputStream is = connection.getInputStream();
                    byte[] responseBuffer = new byte[1024];
                    StringBuilder responseStringBuilder = new StringBuilder();
                    while ((count = is.read(responseBuffer)) != -1) {
                        responseStringBuilder.append(new String(responseBuffer, 0, count));
                    }
                    Log.d(TAG, responseStringBuilder.toString());
    
                    return responseCode;
                } catch (IOException e) {
                    e.printStackTrace();
                    return -1;
                }
            }
    
            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                if (result == 200) {
                    Toast.makeText(SignUrlUploadActivity.this, "Berhasil diunggah.", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Unggah gagal.", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

Gunakan URL bertanda tangan untuk unggahan multipart

Kode contoh berikut menunjukkan cara menghasilkan URL bertanda tangan untuk setiap bagian dan menggunakannya untuk mengunggah objek dalam beberapa bagian:

<?php

// Sertakan file autoload untuk memuat dependensi.
require_once __DIR__ . '/../vendor/autoload.php';

use AlibabaCloud\Oss\V2 as Oss;
use GuzzleHttp\Psr7\LazyOpenStream;
use GuzzleHttp\Client;

// Tentukan dan jelaskan opsi baris perintah.
$optsdesc = [
    "region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => true],
    "bucket" => ['help' => 'Nama bucket', 'required' => true],
    "key" => ['help' => 'Nama objek', 'required' => true],
];

// Buat daftar opsi panjang yang diperlukan oleh getopt.
$longopts = array_map(function ($key) {
    return "$key:";
}, array_keys($optsdesc));

// Analisis opsi baris perintah.
$options = getopt("", $longopts);

// Periksa apakah opsi yang diperlukan hilang.
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === true && empty($options[$key])) {
        echo "Error: argumen berikut diperlukan: --$key, " . $value['help'] . "\n";
        exit(1);
    }
}

// Tetapkan nilai yang diurai dari opsi baris perintah ke variabel yang sesuai.
$region = $options["region"];
$bucket = $options["bucket"];
$key = $options["key"];

// Tentukan jalur file lokal.
$bigFileName = "/Users/localpath/yourfilename"; // Ganti nilai dengan jalur file aktual yang ingin diunggah.
$partSize = 1 * 1024 * 1024; // Setel ukuran bagian. Dalam contoh ini, ukuran bagian adalah 1 MB.
$fileSize = filesize($bigFileName); // Query ukuran total file.
$partsNum = intdiv($fileSize, $partSize) + (int)($fileSize % $partSize > 0 ? 1 : 0); // Hitung jumlah bagian.

// Muat kredensial akses dari variabel lingkungan.
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// Gunakan konfigurasi default, dan tentukan penyedia kredensial dan wilayah.
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($region);

// Buat instance klien.
$client = new Oss\Client($cfg);

// Langkah 1: Iniasi unggahan multipart.
// Panggil metode InitiateMultipartUpload dan dapatkan ID unggahan.
$initResult = $client->initiateMultipartUpload(
    new Oss\Models\InitiateMultipartUploadRequest(
        bucket: $bucket,
        key: $key
    )
);

// Simpan ID unggahan yang dikembalikan.
$uploadId = $initResult->uploadId;

// Langkah 2: Ulangi setiap bagian untuk membuat URL bertanda tangan untuk setiap bagian dan unggah bagian tersebut.
$parts = []; // Simpan ETag dan nomor setiap bagian.

for ($i = 1; $i <= $partsNum; $i++) {
    // Buat objek UploadPartRequest.
    $request = new Oss\Models\UploadPartRequest(
        bucket: $bucket,
        key: $key,
        partNumber: $i,
        uploadId: $uploadId
    );

    // Hasilkan URL bertanda tangan untuk sebuah bagian untuk mengizinkan unggahan bagian menggunakan klien eksternal.
    $signedResult = $client->presign($request);

    // Dapatkan URL bertanda tangan dan metode permintaan.
    $signedUrl = $signedResult->url;
    $method = $signedResult->method;

    // Hitung offset bagian saat ini dan panjangnya.
    $offset = ($i - 1) * $partSize;
    $length = min($partSize, $fileSize - $offset);

    // Buka aliran file besar, cari ke offset bagian saat ini, dan baca kontennya.
    $file = new LazyOpenStream($bigFileName, 'rb');
    $file->seek($offset);
    $content = $file->read($length);

    // Gunakan klien HTTP untuk mengirim permintaan PUT untuk mengunggah bagian.
    $http = new Client();
    $response = $http->request($method, $signedUrl, [
        'body' => $content
    ]);

    // Dapatkan ETag dari respons, yang akan digunakan untuk menggabungkan bagian menjadi objek.
    $etag = $response->getHeaderLine('ETag');

    // Simpan informasi bagian dalam array, yang akan digunakan untuk mengirim permintaan CompleteMultipartUpload.
    $parts[] = new Oss\Models\UploadPart(
        partNumber: $i,
        etag: $etag
    );

    // (Opsional) Tampilkan kemajuan unggahan.
    echo "Unggah bagian {$i} sukses. ETag: {$etag}\n";
}

// Langkah 3: Selesaikan unggahan multipart.
// Buat CompleteMultipartUploadRequest untuk menggabungkan semua bagian.
$completeRequest = new Oss\Models\CompleteMultipartUploadRequest(
    bucket: $bucket,
    key: $key,
    uploadId: $uploadId,
    completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
        parts: $parts
    )
);

// Kirim permintaan.
$comResult = $client->completeMultipartUpload($completeRequest);

// Tampilkan detail respons.
printf(
    'kode status: %s' . PHP_EOL .
    'ID permintaan: %s' . PHP_EOL .
    'hasil unggahan multipart lengkap: %s' . PHP_EOL,
    $comResult->statusCode,
    $comResult->requestId,
    var_export($comResult, true)
);

Gunakan URL bertanda tangan untuk mengunggah objek dan atur parameter panggilan balik unggahan

  1. Pemilik objek menghasilkan URL bertanda tangan yang mencakup parameter panggilan balik unggahan dan mengizinkan permintaan HTTP PUT.

    <?php
    
    // Sertakan file autoload untuk memuat dependensi.
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // Tentukan dan jelaskan opsi baris perintah.
    $optsdesc = [
        "region" => ['help' => 'Wilayah tempat bucket berada.', 'required' => True], // (Diperlukan) Tentukan wilayah tempat bucket berada.
        "endpoint" => ['help' => 'Nama domain yang dapat digunakan layanan lain untuk mengakses OSS.', 'required' => False], // (Opsional) Tentukan titik akhir untuk mengakses OSS.
        "bucket" => ['help' => 'Nama bucket', 'required' => True], // (Diperlukan) Tentukan nama bucket.
        "key" => ['help' => 'Nama objek', 'required' => True], // (Diperlukan) Tentukan nama objek.
    ];
    
    // Ubah deskripsi menjadi daftar opsi panjang yang diperlukan oleh getopt.
    // Tambahkan titik dua (:) di akhir setiap opsi untuk menunjukkan bahwa nilai diperlukan.
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // Analisis opsi baris perintah.
    $options = getopt("", $longopts);
    
    // Periksa apakah opsi yang diperlukan telah dikonfigurasi.
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // Dapatkan informasi bantuan.
            echo "Error: argumen berikut diperlukan: --$key, $help" . PHP_EOL;
            exit(1); // Keluar dari program jika opsi yang diperlukan hilang.
        }
    }
    
    // Tetapkan nilai yang diurai dari opsi baris perintah ke variabel yang sesuai.
    $region = $options["region"]; // Wilayah tempat bucket berada.
    $bucket = $options["bucket"]; // Nama bucket.
    $key = $options["key"];       // Nama objek.
    
    // Muat kredensial akses dari variabel lingkungan.
    // Gunakan EnvironmentVariableCredentialsProvider untuk mengambil ID AccessKey dan Rahasia AccessKey dari variabel lingkungan.
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // Gunakan konfigurasi default dari SDK.
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // Tentukan penyedia kredensial.
    $cfg->setRegion($region); // Tentukan wilayah tempat bucket berada.
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // Tentukan titik akhir jika ada yang diberikan.
    }
    
    // Buat instance OSSClient.
    $client = new Oss\Client($cfg);
    
    // Sertakan header x-oss-callback dan x-oss-callback-var.
    // Tentukan URL panggilan balik.
    $call_back_url = "http://www.example.com/callback";
    
    // Konstruksi parameter panggilan balik: Tentukan URL panggilan balik dan badan permintaan, keduanya harus dienkripsi Base64.
    // Ganti ${x:var1} dan ${x:var2} dengan placeholder {var1} dan {var2}.
    $callback_body_template = "bucket={bucket}&object={object}&my_var_1={var1}&my_var_2={var2}";
    $callback_body_replaced = str_replace(
        ['{bucket}', '{object}', '{var1}', '{var2}'],
        [$bucket, $key, 'value1', 'value2'],
        $callback_body_template
    );
    $callback = base64_encode(json_encode([
        "callbackUrl" => $call_back_url,
        "callbackBody" => $callback_body_replaced
    ]));
    
    // Definisikan dan enkripsi Base64 variabel panggilan balik kustom.
    $callback_var = base64_encode(json_encode([
        "x:var1" => "value1",
        "x:var2" => "value2"
    ]));
    
    // Buat objek PutObjectRequest untuk mengunggah data. 
    // Perhatikan bahwa Content-Type, metadata, dan header disertakan untuk perhitungan tanda tangan. 
    $request = new Oss\Models\PutObjectRequest(
        bucket: $bucket,
        key: $key,
        callback:$callback,
        callbackVar:$callback_var,
    );
    
    // Panggil metode presign untuk menghasilkan permintaan bertanda tangan.
    $result = $client->presign($request);
    
    // Tampilkan URL bertanda tangan, yang dapat digunakan untuk mengunggah objek yang ditentukan.
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL .
        'put object url:' . $result->url . PHP_EOL
    );
    
  2. Pengguna lain menggunakan URL bertanda tangan untuk permintaan PUT untuk mengunggah objek.

    curl

    curl -X PUT \
         -H "x-oss-callback: eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9" \
         -H "x-oss-callback-var: eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==" \
         -T "C:\\Users\\demo.txt" \
         "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******************************************************"

    Python

    import requests
    
    def upload_file(signed_url, file_path, headers=None):
        """
        Unggah file ke OSS menggunakan URL bertanda tangan.
    
        :param signed_url: URL bertanda tangan.
        :param file_path: Jalur lengkap file yang akan diunggah.
        :param headers: Opsional. Header HTTP kustom.
        :return: None
        """
        if not headers:
            headers = {}
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"Kode status HTTP yang dikembalikan: {response.status_code}")
                if response.status_code == 200:
                    print("File berhasil diunggah menggunakan pustaka jaringan.")
                else:
                    print("Unggah gagal")
                print(response.text)
        except Exception as e:
            print(f"Terjadi kesalahan: {e}")
    
    if __name__ == "__main__":
        # Ganti <signedUrl> dengan URL bertanda tangan.
        signed_url = "<signedUrl>"
    
        # Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari direktori tempat skrip berada.
        file_path = "C:\\Users\\demo.txt"
    
        headers = {
            "x-oss-callback": "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
            "x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
        }
    
        upload_file(signed_url,  file_path, headers)

    Go

    package main
    
    import (
    	"bytes"
    	"fmt"
    	"io"
    
    	"net/http"
    	"os"
    )
    
    func uploadFile(signedUrl string, filePath string, headers map[string]string) error {
    	// Buka file.
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// Baca isi file.
    	fileBytes, err := io.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// Buat permintaan.
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// Setel header permintaan.
    	for key, value := range headers {
    		req.Header.Add(key, value)
    	}
    
    	// Kirim permintaan.
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// Proses respons.
    	fmt.Printf("Kode status HTTP yang dikembalikan: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("File berhasil diunggah menggunakan pustaka jaringan.")
    	} else {
    		fmt.Println("Unggah gagal")
    	}
    	body, _ := io.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// Ganti <signedUrl> dengan URL bertanda tangan.
    	signedUrl := "<signedUrl>"
    	// Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur lokal yang sesuai dengan proyek program sampel.
    	filePath := "C:\\Users\\demo.txt"
    
    	// Setel header permintaan. Informasi header permintaan harus sama dengan informasi yang digunakan untuk menghasilkan URL.
    	headers := map[string]string{
    		"x-oss-callback":     "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
    		"x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers)
    	if err != nil {
    		fmt.Printf("Terjadi kesalahan: %v\n", err)
    	}
    }
    

    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;
    
            // Ganti <signedUrl> dengan URL bertanda tangan.
            URL signedUrl = new URL("<signedUrl>");
    
            // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari jalur lokal yang sesuai dengan proyek program sampel.
            String pathName = "C:\\Users\\demo.txt";
    
            // Setel header permintaan, termasuk x-oss-callback dan x-oss-callback-var.
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("x-oss-callback", "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9");
            headers.put("x-oss-callback-var", "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==");
    
            try {
                HttpPut put = new HttpPut(signedUrl.toString());
                System.out.println(put);
                HttpEntity entity = new FileEntity(new File(pathName));
                put.setEntity(entity);
                // Jika Anda menyetel parameter header saat menghasilkan URL bertanda tangan, Anda juga harus mengirim parameter ini ke server saat menggunakan URL bertanda tangan untuk mengunggah file. Jika tanda tangan tidak sesuai dengan informasi yang dikirim ke server, kesalahan tanda tangan dilaporkan.
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Kode status HTTP yang dikembalikan: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("File berhasil diunggah menggunakan pustaka jaringan.");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // Periksa apakah file ada.
        if (!file_exists($filePath)) {
            echo "File tidak ada: $filePath\n";
            return;
        }
    
        // Inisialisasi sesi cURL.
        $ch = curl_init();
    
        // Setel opsi cURL.
        curl_setopt($ch, CURLOPT_URL, $signedUrl);
        curl_setopt($ch, CURLOPT_PUT, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'rb'));
        curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
        curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function($key, $value) {
            return "$key: $value";
        }, array_keys($headers), $headers));
    
        // Eksekusi permintaan cURL.
        $response = curl_exec($ch);
    
        // Dapatkan kode status HTTP.
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // Tutup sesi cURL.
        curl_close($ch);
    
        // Keluarkan hasilnya.
        echo "Kode status HTTP yang dikembalikan: $httpCode\n";
        if ($httpCode == 200) {
            echo "File berhasil diunggah menggunakan pustaka jaringan.\n";
        } else {
            echo "Unggah gagal\n";
        }
        echo $response . "\n";
    }
    
    // Ganti <signedUrl> dengan URL bertanda tangan.
    $signedUrl = "<signedUrl>";
    
    // Tentukan jalur lengkap file lokal. Jika Anda tidak menentukan jalur lokal, file akan diunggah dari direktori tempat skrip berada.
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

Referensi

  • Untuk kode contoh lengkap menggunakan URL bertanda tangan, kunjungi GitHub.

  • Untuk informasi lebih lanjut tentang operasi API yang menghasilkan URL bertanda tangan, lihat Presign.