すべてのプロダクト
Search
ドキュメントセンター

Object Storage Service:PHP SDK V2 で署名付き URL を使用してオブジェクトをアップロードする

最終更新日:Aug 07, 2025

デフォルトでは、Object Storage Service (OSS) バケット内のオブジェクトのアクセス制御リスト (ACL) は非公開に設定されています。 つまり、オブジェクト所有者のみがオブジェクトにアクセスできます。 このトピックでは、OSS SDK for PHP を使用して、HTTP PUT メソッドを使用して指定された期間内に特定のオブジェクトをユーザーがアップロードできるようにする署名付き URL を生成する方法について説明します。 有効期間内は、ユーザーは署名付き URL を使用してオブジェクトに繰り返しアクセスできます。 署名付き URL の有効期限が切れた場合は、署名付き URL を再生成して、ユーザーのアクセスを延長できます。

注意事項

  • このトピックのサンプルコードでは、中国 (杭州) リージョンのリージョン ID cn-hangzhou を使用しています。 デフォルトでは、パブリックエンドポイントを使用してバケット内のリソースにアクセスします。 バケットが配置されているのと同じリージョン内の他の Alibaba Cloud サービスからバケット内のリソースにアクセスする場合は、内部エンドポイントを使用します。 サポートされているリージョンとエンドポイントの詳細については、「リージョンとエンドポイント」をご参照ください。

  • 署名付き URL を生成するために特定の権限は必要ありません。 ただし、サードパーティが署名付き URL を使用してオブジェクトをアップロードできるようにするには、oss:PutObject 権限が必要です。 詳細については、「カスタムポリシーを使用して RAM ユーザーに権限を付与する」をご参照ください。

  • このトピックでは、署名アルゴリズム V4 を使用して、最長 7 日間の有効期間を持つ署名付き URL を生成します。 詳細については、「(推奨) URL に V4 署名を含める」をご参照ください。

  • このトピックでは、アクセス認証情報は環境変数から取得されます。 詳細については、「OSS SDK for PHP のアクセス認証情報を構成する」をご参照ください。

プロセス

次の図は、HTTP PUT リクエストを許可する署名付き URL を使用してオブジェクトを OSS にアップロードする方法を示しています。

サンプルコード

  1. オブジェクト所有者は、HTTP PUT リクエストを許可する署名付き URL を生成します。

    重要

    HTTP PUT リクエストを許可する署名付き URL を生成するときにリクエストヘッダーを指定する場合は、署名付き URL を使用して開始された PUT リクエストにリクエストヘッダーが含まれていることを確認してください。 これにより、リクエストの失敗と署名エラーを防ぎます。

    <?php
    
    // Include the autoload file to load dependencies.
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // Define and describe command-line options.
    $optsdesc = [
        "region" => ['help' => 'The region in which the bucket is located.', 'required' => True], // (Required) Specify the region in which the bucket is located.
        "endpoint" => ['help' => 'The domain names that other services can use to access OSS.', 'required' => False], // (Optional) Specify the endpoint for accessing OSS.
        "bucket" => ['help' => 'The name of the bucket', 'required' => True], // (Required) Specify the name of the bucket.
        "key" => ['help' => 'The name of the object', 'required' => True], // (Required) Specify the name of the object.
    ];
    
    // Convert the descriptions to a list of long options required by getopt.
    // Add a colon (:) to the end of each option to indicate that a value is required.
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // Parse the command-line options.
    $options = getopt("", $longopts);
    
    // Check whether required options are missing.
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // Obtain help information.
            echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
            exit(1); // Exit the program if a required option is missing.
        }
    }
    
    // Assign the values parsed from the command-line options to the corresponding variables.
    $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 access credentials from environment variables.
    // Use EnvironmentVariableCredentialsProvider to retrieve the AccessKey ID and AccessKey secret from environment variables.
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // Use the default configuration of the SDK.
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // Specify the credential provider.
    $cfg->setRegion($region); // Specify the region in which the bucket is located.
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // Specify the endpoint if one is provided.
    }
    
    // Create an OSS client instance.
    $client = new Oss\Client($cfg);
    
    // Create a PutObjectRequest object to upload the data.
    $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key);
    
    // Call the presign method to generate a presigned request.
    $result = $client->presign($request);
    
    // Display the result of the presign operation.
    // Display the presigned URL, which can be used to upload the specified 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.
    );
    
  2. ユーザーは署名付き URL を使用してオブジェクトをアップロードします。

    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;
    
            // <signedUrl> を承認 URL に置き換えます。
            URL signedUrl = new URL("<signedUrl>");
    
            // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
            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 returned:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Uploaded successfully using the network 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 {
    	// ファイルを開きます。
    	file, err := os.Open(filePath)
    	if err != nil {
    		return fmt.Errorf("ファイルを開けませんでした: %w", err)
    	}
    	defer file.Close()
    
    	// 新しい HTTP クライアントを作成します。
    	client := &http.Client{}
    
    	// PUT リクエストを作成します。
    	req, err := http.NewRequest("PUT", signedUrl, file)
    	if err != nil {
    		return fmt.Errorf("リクエストの作成に失敗しました: %w", err)
    	}
    
    	// リクエストを送信します。
    	resp, err := client.Do(req)
    	if err != nil {
    		return fmt.Errorf("リクエストの送信に失敗しました: %w", err)
    	}
    	defer resp.Body.Close()
    
    	// レスポンスを読み取ります。
    	body, err := io.ReadAll(resp.Body)
    	if err != nil {
    		return fmt.Errorf("レスポンスの読み取りに失敗しました: %w", err)
    	}
    
    	fmt.Printf("Status code returned: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Uploaded successfully using the network library.")
    	}
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// <signedUrl> を承認 URL に置き換えます。
    	signedUrl := "<signedUrl>"
    
    	// ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
    	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:
            # ファイルを開きます。
            with open(file_path, 'rb') as file:
                # PUT リクエストを送信してファイルをアップロードします。
                response = requests.put(signed_url, data=file)
         
            print(f"Status code returned: {response.status_code}")
            if response.status_code == 200:
                print("Uploaded successfully using the network library.")
            print(response.text)
     
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # <signedUrl> を承認 URL に置き換えます。
        signed_url = "<signedUrl>"
        
        // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
        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 {
            // 読み取りストリームを作成します。
            const fileStream = fs.createReadStream(filePath);
            
            // PUT リクエストを送信してファイルをアップロードします。
            const response = await axios.put(signedUrl, fileStream, {
                headers: {
                    'Content-Type': 'application/octet-stream' // 要件に基づいて Content-Type を調整します。
                }
            });
    
            console.log(`Status code returned: ${response.status}`);
            if (response.status === 200) {
                console.log('Uploaded successfully using the network library.');
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // メイン関数。
    (async () => {
        // <signedUrl> を承認 URL に置き換えます。
        const signedUrl = '<signedUrl>';
        
        // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
        const filePath = 'C:\\Users\\demo.txt';
    
        await uploadFile(signedUrl, filePath);
    })();

    browser.js

    重要

    Browser.js を使用してファイルをアップロードし、403 SignatureDoesNotMatch エラーが発生した場合、通常、ブラウザが Content-Type リクエストヘッダーを自動的に追加するためにエラーが発生します。 署名付き URL の生成時にこのヘッダーが指定されていない場合、署名の検証は失敗します。 この問題を解決するには、署名付き URL を生成するときに Content-Type リクエストヘッダーを指定する必要があります。

    <!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>
    
        <!-- ファイルを選択 -->
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // これを手順 1 で生成された署名付き URL に置き換えます。
            const signedUrl = "<signedUrl>"; 
    
    
            document.getElementById('uploadButton').addEventListener('click', async () => {
                const fileInput = document.getElementById('fileInput');
                const file = fileInput.files[0];
    
                if (!file) {
                    alert('アップロードするファイルを選択してください。');
                    return;
                }
    
                try {
                    await upload(file, signedUrl);
                    alert('ファイルが正常にアップロードされました!');
                } catch (error) {
                    console.error('Error during upload:', error);
                    alert('アップロードに失敗しました: ' + error.message);
                }
            });
    
            /**
             * OSS にファイルをアップロードします。
             * @param {File} file - アップロードするファイル。
             * @param {string} presignedUrl - 署名付き URL。
             */
            const upload = async (file, presignedUrl) => {
                const response = await fetch(presignedUrl, {
                    method: 'PUT',
                    body: 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;
    
    // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
    var filePath = "C:\\Users\\demo.txt";
    // <signedUrl> を承認 URL に置き換えます。
    var presignedUrl = "<signedUrl>";
    
    // HTTP クライアントを作成し、ローカルファイルストリームを開きます。
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // PUT リクエストを作成します。
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // リクエストを送信します。
    var response = await httpClient.SendAsync(request);
    
    // レスポンスを処理します。
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded successfully! 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) {
            // URL を設定します。
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // リクエストメソッドを PUT に設定します。
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // ファイルを開きます。
            FILE *file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Failed to open the file: " << filePath << std::endl;
                return;
            }
    
            // ファイルサイズを取得します。
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            fseek(file, 0, SEEK_SET);
    
            // ファイルサイズを設定します。
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // 入力ファイルハンドルを設定します。
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
    
            // リクエストを実行します。
            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 returned: " << httpCode << std::endl;
    
                if (httpCode == 200) {
                    std::cout << "Uploaded successfully using the network library." << std::endl;
                }
            }
    
            // ファイルを閉じます。
            fclose(file);
    
            // クリーンアップします。
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // <signedUrl> を承認 URL に置き換えます。
        std::string signedUrl = "<signedUrl>";
    
        // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
        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 returned: " + responseCode);
    
                    if (responseCode == 200) {
                        Log.d(TAG, "Uploaded successfully using the network library.");
                    }
    
                    return "Upload completed. 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();
            // <signedUrl> を承認 URL に置き換えます。
            String signedUrl = "<signedUrl>";
            // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
            String filePath = "C:\\Users\\demo.txt";
            activity.uploadFile(signedUrl, filePath);
        }
    }
    

一般的なシナリオ

特定のリクエストヘッダーとユーザーメタデータを含む署名付き URL を使用してファイルをアップロードする

  1. オブジェクト所有者は、HTTP PUT リクエストを許可する署名付き URL を生成します。

    <?php
    
    // 依存関係を読み込むためにオートロードファイルを含めます。
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // コマンドラインオプションを定義して説明します。
    $optsdesc = [
        "region" => ['help' => 'バケットが配置されているリージョン。', 'required' => True], // (必須) バケットが配置されているリージョンを指定します。
        "endpoint" => ['help' => '他のサービスが OSS にアクセスするために使用できるドメイン名。', 'required' => False], // (オプション) OSS にアクセスするためのエンドポイントを指定します。
        "bucket" => ['help' => 'バケットの名前', 'required' => True], // (必須) バケットの名前を指定します。
        "key" => ['help' => 'オブジェクトの名前', 'required' => True], // (必須) オブジェクトの名前を指定します。
    ];
    
    // getopt で必要な長いオプションのリストに変換します。
    // 各オプションの末尾にコロン (:) を追加して、値が必要であることを示します。
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // コマンドラインオプションを解析します。
    $options = getopt("", $longopts);
    
    // 必須オプションが欠落しているかどうかを確認します。
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // ヘルプ情報を取得します。
            echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
            exit(1); // 必須オプションが欠落している場合はプログラムを終了します。
        }
    }
    
    // コマンドラインオプションから解析された値を対応する変数に割り当てます。
    $region = $options["region"]; // バケットが配置されているリージョン。
    $bucket = $options["bucket"]; // バケットの名前。
    $key = $options["key"];       // オブジェクトの名前。
    
    // 環境変数からアクセス認証情報を読み込みます。
    // EnvironmentVariableCredentialsProvider を使用して、環境変数から AccessKey ID と AccessKey シークレットを取得します。
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // SDK のデフォルト構成を使用します。
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // 認証プロバイダーを指定します。
    $cfg->setRegion($region); // バケットが配置されているリージョンを指定します。
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // エンドポイントが提供されている場合は指定します。
    }
    
    // OSS クライアントインスタンスを作成します。
    $client = new Oss\Client($cfg);
    
    // コンテンツタイプをテキストに設定します。
    $contentType = "text/plain; charset=utf-8";
    
    // カスタムメタデータを指定します。
    $metadata = [
        "key1" => "value1",
        "key2" => "value2",
    ];
    
    // データをアップロードするための PutObjectRequest オブジェクトを作成します。 contentType パラメーターと metadata パラメーターが署名計算に含まれていることに注意してください。
    $request = new Oss\Models\PutObjectRequest(bucket: $bucket, key: $key, contentType: $contentType, metadata: $metadata);
    
    // presign メソッドを呼び出して、署名付きリクエストを生成します。
    $result = $client->presign($request);
    
    // 署名操作の結果を表示します。
    // 指定されたオブジェクトのアップロードに使用できる署名付き URL を表示します。
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL . // 署名結果の詳細。
        'put object url:' . $result->url . PHP_EOL                           // 署名付き URL。
    );
    
  2. 署名付き URL を持っているユーザーは、それを使用してオブジェクトをアップロードします。

    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;
    
            // <signedUrl> を承認 URL に置き換えます。
            URL signedUrl = new URL("<signedUrl>");
    
            // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
            String pathName = "C:\\Users\\demo.txt";
    
            // リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
            Map<String, String> headers = newHashMap<String, String>();
            // オブジェクトのストレージクラスを指定します。
            headers.put(OSSHeaders.STORAGE_CLASS, StorageClass.Standard.toString());
            // ContentType を指定します。
            headers.put(OSSHeaders.CONTENT_TYPE, "text/plain;charset=utf8");
    
            // カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
            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);
                // 署名付き URL の生成時にカスタムメタデータやストレージクラスなどのヘッダーパラメーターが設定されている場合、これらのパラメーターは、署名付き URL を使用してファイルをアップロードするときにもサーバーに送信する必要があります。 サーバーに送信された署名が生成された署名と異なる場合、署名エラーが報告されます。
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
                for(Map.Entry meta: userMetadata.entrySet()){
                    // userMeta を使用する場合、SDK は内部的に userMeta に "x-oss-meta-" というプレフィックスを追加します。 他の方法を使用してアップロード用の署名付き URL を生成する場合は、userMeta に "x-oss-meta-" というプレフィックスを追加する必要もあります。
                    put.addHeader("x-oss-meta-"+meta.getKey().toString(), meta.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("Status code returned:"+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("Uploaded successfully using the network library.");
                }
                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 {
    	// ファイルを開きます。
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// ファイルの内容を読み取ります。
    	fileBytes, err := ioutil.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// リクエストを作成します。
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// リクエストヘッダーを設定します。
    	for key, value := range headers {
    		req.Header.Set(key, value)
    	}
    
    	// カスタムメタデータを設定します。
    	for key, value := range metadata {
    		req.Header.Set(fmt.Sprintf("x-oss-meta-%s", key), value)
    	}
    
    	// リクエストを送信します。
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// レスポンスを処理します。
    	fmt.Printf("Status code returned: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("Uploaded successfully using the network library.")
    	} else {
    		fmt.Println("Upload failed.")
    	}
    	body, _ := ioutil.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// <signedUrl> を承認 URL に置き換えます。
    	signedUrl := "<signedUrl>"
    
    	// ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
    	filePath := "C:\\Users\\demo.txt"
    
    	// リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
    	headers := map[string]string{
    		"Content-Type": "text/plain;charset=utf8",
    		"x-oss-storage-class": "Standard",
    	}
    
    	// カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
    	metadata := map[string]string{
    		"key1": "value1",
    		"key2": "value2",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers, metadata)
    	if err != nil {
    		fmt.Printf("An error occurred: %v\n", err)
    	}
    }
    

    Python

    import requests
    from requests.auth import HTTPBasicAuth
    import os
    
    def upload_file(signed_url, file_path, headers=None, metadata=None):
        """
        署名付き URL を使用して OSS にファイルをアップロードします。
    
        :param signed_url: 署名付き URL。
        :param file_path: アップロードするファイルのフルパス。
        :param headers: オプション。 カスタム HTTP ヘッダー。
        :param metadata: オプション。 カスタムメタデータ。
        :return: なし
        """
        if not headers:
            headers = {}
        if not metadata:
            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"Status code returned: {response.status_code}")
                if response.status_code == 200:
                    print("Uploaded successfully using the network library.")
                else:
                    print("Upload failed.")
                print(response.text)
        except Exception as e:
            print(f"An error occurred: {e}")
    
    if __name__ == "__main__":
        # <signedUrl> を承認 URL に置き換えます。
        signed_url = "<signedUrl>"
       
        # ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、スクリプトが配置されているディレクトリからファイルがアップロードされます。
        file_path = "C:\\Users\\demo.txt"
    
        # リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
        headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        }
    
        # カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
        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 {
            // ヘッダーを更新し、メタデータプレフィックスを追加します。
            for (const [key, value] of Object.entries(metadata)) {
                headers[`x-oss-meta-${key}`] = value;
            }
    
            // ファイルストリームを読み取ります。
            const fileStream = fs.createReadStream(filePath);
    
            // PUT リクエストを送信します。
            const response = await axios.put(signedUrl, fileStream, {
                headers: headers
            });
    
            console.log(`Status code returned: ${response.status}`);
            if (response.status === 200) {
                console.log("Uploaded successfully using the network library.");
            } else {
                console.log("Upload failed.");
            }
            console.log(response.data);
        } catch (error) {
            console.error(`An error occurred: ${error.message}`);
        }
    }
    
    // メイン関数。
    (async () => {
        // <signedUrl> を承認 URL に置き換えます。
        const signedUrl = "<signedUrl>";
    
        // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、スクリプトが配置されているディレクトリからファイルがアップロードされます。
        const filePath = "C:\\Users\\demo.txt";
    
        // リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
        const headers = {
             "Content-Type": "text/plain;charset=utf8",
             "x-oss-storage-class": "Standard"
        };
    
        // カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
        const metadata = {
             "key1": "value1",
             "key2": "value2"
        };
    
        await uploadFile(signedUrl, filePath, headers, metadata);
    })();
    

    Browser.js

    重要

    Browser.js を使用してファイルをアップロードし、403 SignatureDoesNotMatch エラーが発生した場合、通常、ブラウザが Content-Type リクエストヘッダーを自動的に追加するためにエラーが発生します。 署名付き URL の生成時にこのヘッダーが指定されていない場合、署名の検証は失敗します。 この問題を解決するには、署名付き URL を生成するときに Content-Type リクエストヘッダーを指定する必要があります。

    <!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 (OSS SDK for Java)</h1>
    
        <input type="file" id="fileInput" />
        <button id="uploadButton">Upload File</button>
    
        <script>
            // これを実際の署名付き URL に置き換えます。
            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('Error during upload:', error);
                        alert('アップロードに失敗しました: ' + error.message);
                    }
                } else {
                    alert('アップロードするファイルを選択してください。');
                }
            });
    
            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(`Upload failed, status: ${response.status}`);
                }
    
                alert('ファイルが正常にアップロードされました');
                console.log('File uploaded successfully');
            };
        </script>
    </body>
    </html>

    C#

    using System.Net.Http.Headers;
    
    // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
    var filePath = "C:\\Users\\demo.txt";
    // <signedUrl> を承認 URL に置き換えます。
    var presignedUrl = "<signedUrl>";
    
    // HTTP クライアントを作成し、ローカルファイルストリームを開きます。
    using var httpClient = new HttpClient(); 
    using var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
    using var content = new StreamContent(fileStream);
                
    // PUT リクエストを作成します。
    var request = new HttpRequestMessage(HttpMethod.Put, presignedUrl);
    request.Content = content;
    
    // 署名付き URL の生成時にカスタムメタデータやストレージクラスなどのヘッダーパラメーターが設定されている場合、これらのパラメーターは、署名付き URL を使用してファイルをアップロードするときにもサーバーに送信する必要があります。 サーバーに送信された署名が生成された署名と異なる場合、署名エラーが報告されます。
    // リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
    request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/plain") { CharSet = "utf8" };  // ContentType を指定します。       
    // カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
    request.Content.Headers.Add("x-oss-meta-key1", "value1");
    request.Content.Headers.Add("x-oss-meta-key2", "value2");
    // オブジェクトのストレージクラスを指定します。
    request.Content.Headers.Add("x-oss-storage-class", "Standard");
    
    // リクエストヘッダーを出力します。
    Console.WriteLine("Request headers:");
    foreach (var header in request.Content.Headers)
    {
        Console.WriteLine($"{header.Key}: {string.Join(", ", header.Value)}");
    }
    
    // リクエストを送信します。
    var response = await httpClient.SendAsync(request);
    
    // レスポンスを処理します。
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine($"Uploaded successfully! Status code: {response.StatusCode}");
        Console.WriteLine("Response headers:");
        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>
    #include <map>
    #include <string>
    
    // 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) {
            // URL を設定します。
            curl_easy_setopt(curl, CURLOPT_URL, signedUrl.c_str());
    
            // リクエストメソッドを PUT に設定します。
            curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    
            // ファイルを開きます。
            FILE* file = fopen(filePath.c_str(), "rb");
            if (!file) {
                std::cerr << "Failed to open the file: " << filePath << std::endl;
                return;
            }
    
            // ファイルサイズを設定します。
            fseek(file, 0, SEEK_END);
            long fileSize = ftell(file);
            rewind(file);
    
            // ファイル読み取りコールバックを設定します。
            curl_easy_setopt(curl, CURLOPT_READDATA, file);
            curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)fileSize);
    
            // リクエストヘッダーを設定します。
            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);
    
            // レスポンス処理コールバックを設定します。
            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
            curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
    
            // リクエストを実行します。
            res = curl_easy_perform(curl);
    
            // レスポンスを確認します。
            if (res != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl;
            } else {
                long responseCode;
                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
                std::cout << "Status code returned: " << responseCode << std::endl;
                if (responseCode == 200) {
                    std::cout << "Uploaded successfully using the network library." << std::endl;
                } else {
                    std::cout << "Upload failed." << std::endl;
                }
                std::cout << readBuffer << std::endl;
            }
    
            // クリーンアップします。
            fclose(file);
            curl_slist_free_all(chunk);
            curl_easy_cleanup(curl);
        }
    
        curl_global_cleanup();
    }
    
    int main() {
        // <signedUrl> を承認 URL に置き換えます。
        std::string signedUrl = "<signedUrl>";
    
        // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
        std::string filePath = "C:\\Users\\demo.txt";
    
        // リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
        std::map<std::string, std::string> headers = {
             {"Content-Type", "text/plain;charset=utf8"},
             {"x-oss-storage-class", "Standard"}
        };
    
        // カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
        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);
    
            // <signedUrl> を承認 URL に置き換えます。
            String signedUrl = "<signedUrl>";
    
            // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、デフォルトでは、サンプルプログラムのプロジェクトに対応するパスからファイルがアップロードされます。
            String pathName = "/storage/emulated/0/demo.txt";
    
            // リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL の生成時に使用された情報と同じである必要があります。
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "text/plain;charset=utf8");
            headers.put("x-oss-storage-class", "Standard");
    
            // カスタムメタデータを設定します。 カスタムメタデータは、URL の生成時に使用されたカスタムメタデータと同じである必要があります。
            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);
    
                    // リクエストヘッダーを設定します。
                    for (Entry<String, String> header : headers.entrySet()) {
                        connection.setRequestProperty(header.getKey(), header.getValue());
                    }
    
                    // カスタムメタデータを設定します。
                    for (Entry<String, String> meta : userMetadata.entrySet()) {
                        connection.setRequestProperty("x-oss-meta-" + meta.getKey(), meta.getValue());
                    }
    
                    // ファイルを読み取ります。
                    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();
    
                    // レスポンスを取得します。
                    int responseCode = connection.getResponseCode();
                    Log.d(TAG, "Status code returned: " + responseCode);
                    if (responseCode == 200) {
                        Log.d(TAG, "Uploaded successfully using the network library.");
                    } else {
                        Log.d(TAG, "Upload failed.");
                    }
    
                    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, "Uploaded successfully.", Toast.LENGTH_SHORT).show();
                } else {
                    Toast.makeText(SignUrlUploadActivity.this, "Upload failed.", Toast.LENGTH_SHORT).show();
                }
            }
        }
    }
    

マルチパートアップロードに署名付き URL を使用する

次のサンプルコードは、各パートの署名付き URL を生成し、それらを使用してオブジェクトをパートごとにアップロードする方法を示しています。

<?php

// 依存関係を読み込むためにオートロードファイルを含めます。
require_once __DIR__ . '/../vendor/autoload.php';

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

// コマンドラインオプションを定義して説明します。
$optsdesc = [
    "region" => ['help' => 'バケットが配置されているリージョン。', 'required' => true],
    "bucket" => ['help' => 'バケットの名前', 'required' => true],
    "key" => ['help' => 'オブジェクトの名前', 'required' => true],
];

// getopt で必要な長いオプションのリストを作成します。
$longopts = array_map(function ($key) {
    return "$key:";
}, array_keys($optsdesc));

// コマンドラインオプションを解析します。
$options = getopt("", $longopts);

// 必須オプションが欠落しているかどうかを確認します。
foreach ($optsdesc as $key => $value) {
    if ($value['required'] === true && empty($options[$key])) {
        echo "Error: the following arguments are required: --$key, " . $value['help'] . "\n";
        exit(1);
    }
}

// コマンドラインオプションから解析された値を対応する変数に割り当てます。
$region = $options["region"];
$bucket = $options["bucket"];
$key = $options["key"];

// ローカルファイルパスを指定します。
$bigFileName = "/Users/localpath/yourfilename"; // 値をアップロードする実際のファイルのパスに置き換えます。
$partSize = 1 * 1024 * 1024; // パートサイズを設定します。 この例では、パートサイズは 1 MB です。
$fileSize = filesize($bigFileName); // ファイルの合計サイズをクエリします。
$partsNum = intdiv($fileSize, $partSize) + (int)($fileSize % $partSize > 0 ? 1 : 0); // パートの数を計算します。

// 環境変数からアクセス認証情報を読み込みます。
$credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();

// デフォルト構成を使用し、認証プロバイダーとリージョンを指定します。
$cfg = Oss\Config::loadDefault();
$cfg->setCredentialsProvider($credentialsProvider);
$cfg->setRegion($region);

// クライアントインスタンスを作成します。
$client = new Oss\Client($cfg);

// 手順 1: マルチパートアップロードを開始します。
// InitiateMultipartUpload メソッドを呼び出して、アップロード ID を取得します。
$initResult = $client->initiateMultipartUpload(
    new Oss\Models\InitiateMultipartUploadRequest(
        bucket: $bucket,
        key: $key
    )
);

// 返されたアップロード ID を保存します。
$uploadId = $initResult->uploadId;

// 手順 2: 各パートをループして、各パートの署名付き URL を作成し、パートをアップロードします。
$parts = []; // 各パートの ETag と番号を格納します。

for ($i = 1; $i <= $partsNum; $i++) {
    // UploadPartRequest オブジェクトを作成します。
    $request = new Oss\Models\UploadPartRequest(
        bucket: $bucket,
        key: $key,
        partNumber: $i,
        uploadId: $uploadId
    );

    // 外部クライアントを使用してパートのアップロードを許可するために、パートの署名付き URL を生成します。
    $signedResult = $client->presign($request);

    // 署名付き URL とリクエストメソッドを取得します。
    $signedUrl = $signedResult->url;
    $method = $signedResult->method;

    // 現在の部分のオフセットとその長さを計算します。
    $offset = ($i - 1) * $partSize;
    $length = min($partSize, $fileSize - $offset);

    // 大きなファイルストリームを開き、現在の部分のオフセットを探し、内容を読み取ります。
    $file = new LazyOpenStream($bigFileName, 'rb');
    $file->seek($offset);
    $content = $file->read($length);

    // HTTP クライアントを使用して、パートのアップロード用の PUT リクエストを送信します。
    $http = new Client();
    $response = $http->request($method, $signedUrl, [
        'body' => $content
    ]);

    // レスポンスから ETag を取得します。これは、パートをオブジェクトに結合するために使用されます。
    $etag = $response->getHeaderLine('ETag');

    // パート情報を配列に格納します。これは、CompleteMultipartUpload リクエストを送信するために使用されます。
    $parts[] = new Oss\Models\UploadPart(
        partNumber: $i,
        etag: $etag
    );

    // (オプション) アップロードの進捗状況を表示します。
    echo "Upload part {$i} success. ETag: {$etag}\n";
}

// 手順 3: マルチパートアップロードを完了します。
// すべてのパートを結合するために CompleteMultipartUploadRequest を作成します。
$completeRequest = new Oss\Models\CompleteMultipartUploadRequest(
    bucket: $bucket,
    key: $key,
    uploadId: $uploadId,
    completeMultipartUpload: new Oss\Models\CompleteMultipartUpload(
        parts: $parts
    )
);

// リクエストを送信します。
$comResult = $client->completeMultipartUpload($completeRequest);

// レスポンスの詳細を表示します。
printf(
    'status code: %s' . PHP_EOL .
    'request id: %s' . PHP_EOL .
    'complete multipart upload result: %s' . PHP_EOL,
    $comResult->statusCode,
    $comResult->requestId,
    var_export($comResult, true)
);

署名付き URL を使用してオブジェクトをアップロードし、アップロードコールバックパラメーターを設定する

  1. オブジェクト所有者は、アップロードコールバックパラメーターを含み、HTTP PUT リクエストを許可する署名付き URL を生成します。

    <?php
    
    // 依存関係を読み込むためにオートロードファイルを含めます。
    require_once __DIR__ . '/../vendor/autoload.php';
    
    use AlibabaCloud\Oss\V2 as Oss;
    
    // コマンドラインオプションを定義して説明します。
    $optsdesc = [
        "region" => ['help' => 'バケットが配置されているリージョン。', 'required' => True], // (必須) バケットが配置されているリージョンを指定します。
        "endpoint" => ['help' => '他のサービスが OSS にアクセスするために使用できるドメイン名。', 'required' => False], // (オプション) OSS にアクセスするためのエンドポイントを指定します。
        "bucket" => ['help' => 'バケットの名前', 'required' => True], // (必須) バケットの名前を指定します。
        "key" => ['help' => 'オブジェクトの名前', 'required' => True], // (必須) オブジェクトの名前を指定します。
    ];
    
    // getopt で必要な長いオプションのリストに変換します。
    // 各オプションの末尾にコロン (:) を追加して、値が必要であることを示します。
    $longopts = \array_map(function ($key) {
        return "$key:";
    }, array_keys($optsdesc));
    
    // コマンドラインオプションを解析します。
    $options = getopt("", $longopts);
    
    // 必須オプションが構成されているかどうかを確認します。
    foreach ($optsdesc as $key => $value) {
        if ($value['required'] === True && empty($options[$key])) {
            $help = $value['help']; // ヘルプ情報を取得します。
            echo "Error: the following arguments are required: --$key, $help" . PHP_EOL;
            exit(1); // 必須オプションが欠落している場合はプログラムを終了します。
        }
    }
    
    // コマンドラインオプションから解析された値を対応する変数に割り当てます。
    $region = $options["region"]; // バケットが配置されているリージョン。
    $bucket = $options["bucket"]; // バケットの名前。
    $key = $options["key"];       // オブジェクトの名前。
    
    // 環境変数からアクセス認証情報を読み込みます。
    // EnvironmentVariableCredentialsProvider を使用して、環境変数から AccessKey ID と AccessKey シークレットを取得します。
    $credentialsProvider = new Oss\Credentials\EnvironmentVariableCredentialsProvider();
    
    // SDK のデフォルト構成を使用します。
    $cfg = Oss\Config::loadDefault();
    $cfg->setCredentialsProvider($credentialsProvider); // 認証プロバイダーを指定します。
    $cfg->setRegion($region); // バケットが配置されているリージョンを指定します。
    if (isset($options["endpoint"])) {
        $cfg->setEndpoint($options["endpoint"]); // エンドポイントが提供されている場合は指定します。
    }
    
    // OSSClient インスタンスを作成します。
    $client = new Oss\Client($cfg);
    
    // x-oss-callback ヘッダーと x-oss-callback-var ヘッダーを含めます。
    // コールバック URL を指定します。
    $call_back_url = "http://www.example.com/callback";
    
    // コールバックパラメーターを構築します。コールバック URL とリクエスト本文を指定します。どちらも Base64 エンコードされている必要があります。
    // ${x:var1} と ${x:var2} をプレースホルダー {var1} と {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
    ]));
    
    // カスタムコールバック変数を定義して Base64 エンコードします。
    $callback_var = base64_encode(json_encode([
        "x:var1" => "value1",
        "x:var2" => "value2"
    ]));
    
    // データをアップロードするための PutObjectRequest オブジェクトを作成します。
    // Content-Type、メタデータ、ヘッダーが署名計算に含まれていることに注意してください。
    $request = new Oss\Models\PutObjectRequest(
        bucket: $bucket,
        key: $key,
        callback:$callback,
        callbackVar:$callback_var,
    );
    
    // presign メソッドを呼び出して、署名付きリクエストを生成します。
    $result = $client->presign($request);
    
    // 指定されたオブジェクトのアップロードに使用できる署名付き URL を表示します。
    print(
        'put object presign result:' . var_export($result, true) . PHP_EOL .
        'put object url:' . $result->url . PHP_EOL
    );
    
  2. 他のユーザーは、PUT リクエストの署名付き URL を使用してオブジェクトをアップロードします。

    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):
        """
        署名付き URL を使用して OSS にファイルをアップロードします。
    
        :param signed_url: 署名付き URL。
        :param file_path: アップロードされるファイルのフルパス。
        :param headers: オプション。 カスタム HTTP ヘッダー。
        :return: なし
        """
        if not headers:
            headers = {}
    
        try:
            with open(file_path, 'rb') as file:
                response = requests.put(signed_url, data=file, headers=headers)
                print(f"返された HTTP ステータスコード: {response.status_code}")
                if response.status_code == 200:
                    print("ファイルはネットワークライブラリを使用してアップロードされます。")
                else:
                    print("アップロードに失敗しました")
                print(response.text)
        except Exception as e:
            print(f"エラーが発生しました: {e}")
    
    if __name__ == "__main__":
        # <signedUrl> を署名付き URL に置き換えます。
        signed_url = "<signedUrl>"
    
        # ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、ファイルはスクリプトが配置されているディレクトリからアップロードされます。
        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 {
    	// ファイルを開きます。
    	file, err := os.Open(filePath)
    	if err != nil {
    		return err
    	}
    	defer file.Close()
    
    	// ファイルの内容を読み取ります。
    	fileBytes, err := io.ReadAll(file)
    	if err != nil {
    		return err
    	}
    
    	// リクエストを作成します。
    	req, err := http.NewRequest("PUT", signedUrl, bytes.NewBuffer(fileBytes))
    	if err != nil {
    		return err
    	}
    
    	// リクエストヘッダーを設定します。
    	for key, value := range headers {
    		req.Header.Add(key, value)
    	}
    
    	// リクエストを送信します。
    	client := &http.Client{}
    	resp, err := client.Do(req)
    	if err != nil {
    		return err
    	}
    	defer resp.Body.Close()
    
    	// レスポンスを処理します。
    	fmt.Printf("返された HTTP ステータスコード: %d\n", resp.StatusCode)
    	if resp.StatusCode == 200 {
    		fmt.Println("ファイルはネットワークライブラリを使用してアップロードされます。")
    	} else {
    		fmt.Println("アップロードに失敗しました")
    	}
    	body, _ := io.ReadAll(resp.Body)
    	fmt.Println(string(body))
    
    	return nil
    }
    
    func main() {
    	// <signedUrl> を署名付き URL に置き換えます。
    	signedUrl := "<signedUrl>"
    	// ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、ファイルはサンプルプログラムのプロジェクトに対応するローカルパスからアップロードされます。
    	filePath := "C:\\Users\\demo.txt"
    
    	// リクエストヘッダーを設定します。 リクエストヘッダー情報は、URL を生成するために使用された情報と同じである必要があります。
    	headers := map[string]string{
    		"x-oss-callback":     "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
    		"x-oss-callback-var": "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    	}
    
    	err := uploadFile(signedUrl, filePath, headers)
    	if err != nil {
    		fmt.Printf("エラーが発生しました: %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;
    
            // <signedUrl> を署名付き URL に置き換えます。
            URL signedUrl = new URL("<signedUrl>");
    
            // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、ファイルはサンプルプログラムのプロジェクトに対応するローカルパスからアップロードされます。
            String pathName = "C:\\Users\\demo.txt";
    
            // リクエストヘッダー (x-oss-callback と 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);
                // 署名付き URL を生成するときにヘッダーパラメーターを設定した場合、署名付き URL を使用してファイルをアップロードするときにも、これらのパラメーターをサーバーに送信する必要があります。 署名がサーバーに送信された情報と一致しない場合、署名エラーが報告されます。
                for(Map.Entry header: headers.entrySet()){
                    put.addHeader(header.getKey().toString(),header.getValue().toString());
                }
    
                httpClient = HttpClients.createDefault();
    
                response = httpClient.execute(put);
    
                System.out.println("返された HTTP ステータスコード: "+response.getStatusLine().getStatusCode());
                if(response.getStatusLine().getStatusCode() == 200){
                    System.out.println("ファイルはネットワークライブラリを使用してアップロードされます。");
                }
                System.out.println(response.toString());
            } catch (Exception e){
                e.printStackTrace();
            } finally {
                response.close();
                httpClient.close();
            }
        }
    }       

    PHP

    <?php
    
    function uploadFile($signedUrl, $filePath, $headers = []) {
        // ファイルが存在するかどうかを確認します。
        if (!file_exists($filePath)) {
            echo "ファイルが存在しません: $filePath\n";
            return;
        }
    
        // cURL セッションを初期化します。
        $ch = curl_init();
    
        // 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));
    
        // cURL リクエストを実行します。
        $response = curl_exec($ch);
    
        // HTTP ステータスコードを取得します。
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
        // cURL セッションを閉じます。
        curl_close($ch);
    
        // 結果を出力します。
        echo "返された HTTP ステータスコード: $httpCode\n";
        if ($httpCode == 200) {
            echo "ファイルはネットワークライブラリを使用してアップロードされます。\n";
        } else {
            echo "アップロードに失敗しました\n";
        }
        echo $response . "\n";
    }
    
    // <signedUrl> を署名付き URL に置き換えます。
    $signedUrl = "<signedUrl>";
    
    // ローカルファイルのフルパスを指定します。 ローカルパスを指定しない場合、ファイルはスクリプトが配置されているディレクトリからアップロードされます。
    $filePath = "C:\\Users\\demo.txt";
    
    $headers = [
        "x-oss-callback" => "eyJjYWxsYmFja1VybCI6Imh0dHA6Ly93d3cuZXhhbXBsZS5jb20vY2FsbGJhY2siLCJjYWxsYmFja0JvZHkiOiJidWNrZXQ9JHtidWNrZXR9Jm9iamVjdD0ke29iamVjdH0mbXlfdmFyXzE9JHt4OnZhcjF9Jm15X3Zhcl8yPSR7eDp2YXIyfSJ9",
        "x-oss-callback-var" => "eyJ4OnZhcjEiOiJ2YWx1ZTEiLCJ4OnZhcjIiOiJ2YWx1ZTIifQ==",
    ];
    
    uploadFile($signedUrl, $filePath, $headers);
    
    ?>

参考資料

  • 署名付き URL を使用するための完全なサンプルコードについては、GitHub にアクセスしてください。

  • 署名付き URL を生成する API 操作の詳細については、「Presign」をご参照ください。