勉強したことのメモ

Webエンジニア / プログラマが勉強したことのメモ。

PHPからDBX Platformを利用してサーバ内のファイルをアップロードする方法

   2024/03/29  PHP

PHPで何らかのファイルを保存するようなケースだと今まではローカルに保存する、もしくはメールに添付する形を取っていた。今回新たな選択肢としてDropboxにアップロードできるようになりたい。調べたところDBX Platformというサービスがあり、こちらを利用することで実装できる模様。以下に実装方法をメモ。

 

Dropbox側の準備

アプリの作成

以下ページにて「アプリを作成」ボタンをクリックする。

https://www.dropbox.com/developers

以下内容でアプリを作成する(Name your appは適宜変更)。

パーミッションの設定

「Permissions」タブをクリックして以下のパーミッション設定を行う。

App key及びApp secretの取得

「Settings」タブをクリックしてセッティングページ内の「App key」「App secret」をメモしておく。

アクセスコードの取得

以下をブラウザから開きアクセスコードを取得する。【】内を適宜変更すること。

https://www.dropbox.com/oauth2/authorize?token_access_type=offline&response_type=code&client_id=【App key】

リフレッシュトークンの取得

サーバにSSH接続し以下コマンドでリフレッシュトークンを取得する。【】内を適宜変更すること。

curl https://api.dropbox.com/oauth2/token -d code=【アクセスコード】 -d grant_type=authorization_code -u 【App key】:【App secret】

成功すると以下のようなJSONデータが返ってくるのでrefresh_token部分をメモっておく。

{
    "access_token": "xxxxxxxxxxxxxxxxxxxxx",
    "token_type": "bearer",
    "expires_in": 14400,
    "refresh_token": "xxxxxxxxxxxxxxxxxxxxx",
    "scope": "xxxxxxxxxxxxxxxxxxxxx",
    "uid": "xxxxxxxxxxxxxxxxxxxxx",
    "account_id": "xxxxxxxxxxxxxxxxxxxxx"
}

また、この時点で作成したアプリと紐づくディレクトリが生成される筈。今回の場合は「/アプリ/php_connection_test」というディレクトリが生成され、こちらがルートディレクトリになる。

 

PHP側

ソースコード

<?php
const APP_KEY = '【App key】';
const APP_SECRET = '【App secret】';
const REFRESH_TOKEN = '【リフレッシュトークン】';

//一時的なアクセストークンを取得
function getAccessToken() {
    $url = 'https://api.dropboxapi.com/oauth2/token';
    $data = [
        'grant_type'    => 'refresh_token',
        'refresh_token' => REFRESH_TOKEN,
        'client_id'     => APP_KEY,
        'client_secret' => APP_SECRET
    ];

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));

    $res = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    $access_token = '';
    if( !curl_errno($ch) && $http_code == "200" ){
        $res = json_decode($res, true);
        $access_token = $res['access_token'];
    } else {
        echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
    }

    curl_close($ch);

    return $access_token;
}

//ファイルアップロード
function uploadFile($access_token, $local_filepath, $upload_filepath) {
    $url = "https://content.dropboxapi.com/2/files/upload";
    $headers = array(
        "Authorization: Bearer " . $access_token, // 取得したアクセストークン
        "Content-Type: application/octet-stream",
        "Dropbox-API-Arg: " . json_encode(array(
            "path" => $upload_filepath,
            "mode" => "add",
            "autorename" => true
        )),
    );
    $file = fopen($local_filepath, 'rb');
    $size = filesize($local_filepath);

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_PUT, true);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($ch, CURLOPT_INFILE, $file);
    curl_setopt($ch, CURLOPT_INFILESIZE, $size);
    $res = curl_exec($ch);
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

    if (!curl_errno($ch) && $http_code == "200") {
        $flg = true;
    } else {
        $flg = false;
    }

    fclose($file);
    curl_close($ch);

    return $flg;
}

//一時的なアクセストークンを取得
$access_token = getAccessToken();

//アップロードするファイル(相対パス、絶対パスどちらでもOK)
$local_file = './002.jpg';

//アップロード先のファイル名(アプリフォルダがルートディレクトリになる)
$upload_file = '/002.jpg';

$flg = uploadFile($access_token, $local_file, $upload_file);

if( $flg ){
    echo 'success';
}else{
    echo 'error';
}

注意点

ローカル側のファイル($local_file)は相対パス、絶対パスどちらでも問題無いがアップロード先のファイル名($upload_file)は「/アプリ/php_connection_test」というルートディレクトリから見たパスになるため「/xxxxxx.jpg」のような形で設定する。

 

エラー対応

Your app is not permitted to access this endpoint because it does not have the required scope 'files.content.write'. The owner of the app can enable~~ エラー

パーミッション設定で「files.content.write」にチェックを入れ忘れていたため発生した模様。

尚、パーミッション設定後は再度「アクセスコードの取得→リフレッシュトークンの取得」を行う必要がある点に注意する。

missing_scopeエラー

こちらのコミュニティページによると「App Console を介してアプリにスコープを追加しただけでは、そのスコープが既存のアクセストークンに遡及的に付与されるわけではないことに注意」とある。

これは上記のパーミッション設定変更後、「アクセスコードの取得→リフレッシュトークンの取得」を行わなかったため発生した模様。

「アクセスコードの取得→リフレッシュトークンの取得」を再度行うことで解決した。

 

参考サイト

https://comment-out.net/2023/08/25/1924.html

 - PHP