開発情報・ナレッジ

投稿者: ShiningStar株式会社 2024年8月26日 (月)

登録フォームにてアップロードされたファイルをGoogleドライブへコピーするサンプルプログラム

SPIRALの登録フォームにてアップロードされたファイルを、
Googleドライブへアップロードするサンプルプログラムをご紹介いたします。


全体像

SPIRALのAPIを用いてDB内のファイルをダウンロードし、
そのファイルをGoogleドライブのAPIを用いてGoogleドライブへアップロードします。

GoogleDriveへファイルをアップロードするにはGoogleAPIのアクセストークンが必要なので取得します。

DB設定

ファイル型フィールドを持つDBであれば利用可能です。
この際ファイル型フィールドの差し替えキーワードを控えておいてください。

設定方法

Google側の設定(OAuth認証の作成)
Google側に任意のプロジェクトを作成していください。
その後Google側設定画面へアクセスしてください。
認証情報より「+認証情報を作成」をクリックして「OAuthクライアントID」をクリックしてください。
アプリケーションの種類は「ウェブアプリケーション」
承認済みのリダイレクトURIには「http://localhost/oauth2callback.php」と入力してください。
そのまま作成まで進み、モーダルに「クライアントID」と「クライアントシークレット」が表示されますので、必ず控えてください。

次に「OAuth同意画面」をクリックしてください。
「OAuth consent screen」では任意の情報を入力してください。
「スコープ」では何も入力しなくて大丈夫です。
「Test users」ではテストユーザにご自身のログインされているGoogleアカウント(Gmail)を入力してください。

ファイルをアップロードをするにはアクセストークンが必要です。
しかし、アクセストークンには有効期限等があるので継続的にファイルのアップロードが出来るように、
リフレッシュトークンを生成して、リフレッシュトークンからアクセストークンを都度生成する形にします。
設定値ファイルをカスタムモジュールに作成

<?php
$client_id = 'クライアントIDを入力';
$client_secret = 'クライアントシークレットを入力';
$redirect_uri = 'http://localhost/oauth2callback.php'; 
            

モジュール名をconfig.phpとしてカスタムモジュールに保存して上記を貼り付けてください。
その後ご自身のGoogleの接続情報を記載してください
ステップ1 リフレッシュトークンの取得

<?php
require_once "config.php";

$auth_code = ''; // 認証コードをここに入力

if (empty($auth_code)) {
    // 認証コードが入力されていない場合、認証URLを生成
    $auth_url = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query([
        'client_id' => $client_id,
        'redirect_uri' => $redirect_uri,
        'response_type' => 'code',
        'scope' => 'https://www.googleapis.com/auth/drive',
        'access_type' => 'offline',
    ]);

    echo '認証URLをブラウザで開いて、認証コードを取得してください:';
    echo PHP_EOL . PHP_EOL;
    echo $auth_url . PHP_EOL;
} else {
    // 認証コードが入力されている場合、アクセストークンとリフレッシュトークンを取得
    $token_url = 'https://oauth2.googleapis.com/token';
    $post_fields = [
        'code' => $auth_code,
        'client_id' => $client_id,
        'client_secret' => $client_secret,
        'redirect_uri' => $redirect_uri,
        'grant_type' => 'authorization_code',
    ];

    $ch = curl_init($token_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_fields));

    $response = curl_exec($ch);

    if ($response === false) {
        echo 'Error: ' . curl_error($ch);
        curl_close($ch);
        exit();
    }

    curl_close($ch);

    $token_data = json_decode($response, true);
    var_dump($token_data);
}
?>
 
            

上記プログラムをカスタムプログラムに設置して実行してください。
そうすると認証URLが出力されますので、そのURLをブラウザに貼り付けて遷移してください。
遷移するとエラーが表示されると思いますが、大丈夫です。
リダイレクトされた後URLに
http://localhost/oauth2callback.php?code=XXX&scope=YYYY
といった形でcodeのパラメータが付与されていますので、
このcodeパラメータ「XXX」を$auth_codeに代入して再度実行してください。
実行結果より「refresh_token」の値を控えてください。
作成したカスタムモジュールを編集

<?php
$client_id = 'クライアントIDを入力';
$client_secret = 'クライアントシークレットを入力';
$redirect_uri = 'http://localhost/oauth2callback.php';

$refresh_token = "ステップ1で取得したリフレッシュトークンを入力"; 
            

$refresh_tokenの行を追記してください。
先ほど控えた値を$refresh_tokenの値に入力してください。
ステップ2 ファイルダウンロード及びGoogleドライブへアップロード

<? //<!-- SMP_DYNAMIC_PAGE DISPLAY_ERRORS=OFF NAME=XXX --> ?>
<?php
//変更不要
require_once "config.php";
define("MULTIPART_BOUNDARY", "SPIRAL_API_MULTIPART_BOUNDARY");

//設定値
define("API_TOKEN", ""); // APIトークン
define("API_SECRET", ""); // APIシークレット
define("DB_TITLE", ""); // DBタイトル
define("FILE_FIELD", "file"); // ファイルフィールド名
define("DELETE_FLG", 1); //削除する:1 削除しない:0 
define("FOLDER_ID", "");  // Google DriveのフォルダID

// ロケータAPIのURLとトークン
$locator = "https://www.pi-pe.co.jp/api/locator";
$locator_token = API_TOKEN; 

// ロケータのAPI用のHTTPヘッダ
$locator_headers = array(
    "X-SPIRAL-API: locator/apiserver/request",
    "Content-Type: application/json; charset=UTF-8",
);

// リクエストデータを作成
$locator_parameters = array("spiral_api_token" => $locator_token);

// JSON形式にエンコード
$locator_json = json_encode($locator_parameters);

// cURLでロケータURLを取得
$curl = curl_init($locator);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $locator_json);
curl_setopt($curl, CURLOPT_HTTPHEADER, $locator_headers);
$response = curl_exec($curl);

// エラーがあればエラー内容を表示
if (curl_errno($curl)) {
    echo curl_error($curl);
    exit;
}
$response_json = json_decode($response, true);
curl_close($curl);

// スパイラルAPIのURLを取得
$api_url = $response_json['location'];

// SPIRAL APIからファイルを取得する関数
function getFileFromSpiralApi($apiUrl, $id) {
    $parameters = [
        "spiral_api_token" => API_TOKEN,
        "passkey" => time(),
        "db_title" => DB_TITLE,
        "file_field_title" => FILE_FIELD,
        "key_field_title" => "id",
        "key_field_value" => $id,
    ];

    $key = $parameters["spiral_api_token"] . "&" . $parameters["passkey"];
    $parameters["signature"] = hash_hmac('sha1', $key, API_SECRET, false);

    $json = json_encode($parameters);

    $apiHeaders = [
        "X-SPIRAL-API: database/get_file/request",
        "Content-Type: application/json; charset=UTF-8",
    ];

    $curl = curl_init($apiUrl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $json);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $apiHeaders);

    $response = curl_exec($curl);
    curl_close($curl);

    return json_decode($response, true);
}

// SPIRAL APIからファイルを削除する関数
function deleteFileFromSpiralApi($apiUrl, $id) {
    $passkey = time();
    $key = API_TOKEN . "&" . $passkey;
    $signature = hash_hmac('sha1', $key, API_SECRET, false);

    $jsonPart = [
        "spiral_api_token" => API_TOKEN,
        "passkey" => $passkey,
        "signature" => $signature,
        "db_title" => DB_TITLE,
        "search_condition" => [
            [
                "name" => "id",
                "value" => $id,
                "operator" => "=",
            ],
        ],
        "data" => [
            [
                "name" => FILE_FIELD,
                "value" => "", // 空値を指定してファイルを削除
            ],
        ],
    ];

    $json = json_encode($jsonPart);
    $boundary = "----------" . uniqid();
    $body = "--" . $boundary . "\r\n";
    $body .= "Content-Type: application/json; charset=UTF-8\r\n";
    $body .= "Content-Disposition: form-data; name=\"json\"\r\n\r\n";
    $body .= $json . "\r\n";
    $body .= "--" . $boundary . "--";

    $apiHeaders = [
        "Content-Type: multipart/form-data; boundary=" . $boundary,
        "X-SPIRAL-API: database/update/request",
    ];

    $curl = curl_init($apiUrl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $apiHeaders);

    $response = curl_exec($curl);
    curl_close($curl);

    return json_decode($response, true);
}

// Google Driveにファイルをアップロードする関数(フォルダ指定対応)
function uploadFileToGoogleDrive($fileData, $fileName, $accessToken, $folderId = null) {
    $uploadUrl = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart";
    $boundary = "YOUR_BOUNDARY";

    $metadata = ["name" => $fileName];
    if ($folderId) {
        $metadata["parents"] = [$folderId];
    }

    $body = "--$boundary\r\n";
    $body .= "Content-Type: application/json; charset=UTF-8\r\n\r\n";
    $body .= json_encode($metadata) . "\r\n";
    $body .= "--$boundary\r\n";
    $body .= "Content-Type: application/octet-stream\r\n\r\n";
    $body .= $fileData . "\r\n";
    $body .= "--$boundary--";

    $headers = [
        "Authorization: Bearer " . $accessToken,
        "Content-Type: multipart/related; boundary=$boundary",
        "Content-Length: " . strlen($body),
    ];

    $curl = curl_init($uploadUrl);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $response = curl_exec($curl);
    curl_close($curl);

    return json_decode($response, true);
}

// Google OAuth2.0でアクセストークンを取得する関数
function getGoogleAccessToken($clientId, $clientSecret, $refreshToken) {
    $tokenUrl = "https://oauth2.googleapis.com/token";
    $tokenData = [
        "client_id" => $clientId,
        "client_secret" => $clientSecret,
        "refresh_token" => $refreshToken,
        "grant_type" => "refresh_token",
    ];

    $curl = curl_init($tokenUrl);
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($tokenData));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($curl);
    curl_close($curl);

    $responseData = json_decode($response, true);
    return $responseData["access_token"];
}

// SPIRALからファイルを取得
$id = $SPIRAL->getContextByFieldTitle("id"); 
$spiralFileData = getFileFromSpiralApi($api_url, $id);
//var_dump($spiralFileData); SPIRALからのファイル取得でうまく動作していない場合は確認

// Googleのアクセストークンを取得
$accessToken = getGoogleAccessToken($client_id, $client_secret, $refresh_token);
//var_dump($accessToken); Googleのアクセストークンの取得がうまく動作していない場合は確認

// Google Driveにファイルをアップロード
$fileData = base64_decode($spiralFileData["data"]);
$fileName = $spiralFileData["file_name"];
$uploadResult = uploadFileToGoogleDrive($fileData, $fileName, $accessToken, FOLDER_ID);
//var_dump($uploadResult); GoogleDriveへのアップロードがうまく動作していない場合は確認

//以下Googleドライブへのアップロードが成功した後の処理
if (isset($uploadResult["id"])) {
    // 削除フラグが立っている場合、SPIRALのDBからファイルを削除
    if (DELETE_FLG == 1) {
        $deleteResult = deleteFileFromSpiralApi($api_url, $id);
    }
}

?>  
            

上記プログラムを登録フォームのサンキューページに設置してください。
設定値をご自身の環境に合わせて修正してください。
GoogleドライブのフォルダIDについては、Googleドライブを開きアップロード先を想定されている任意のフォルダを開いた時のURL
https://drive.google.com/drive/folders/フォルダID
上記を確認し末尾の値を入力してください。

また本サンプルプログラムはSPIRALのファイルストレージ容量を節約する為に、
Googleドライブへアップが完了したファイルをSPIRALから削除する機能も実装しています。
削除を行いたい場合はdefine("DELETE_FLG", 1)を1にしてください。

Googleドライブへのアップロード成功時に削除以外の処理を行いたい場合は、
if (isset($uploadResult["id"]))の中の処理を変更してください。

うまく動作しない場合

Googleドライブ側でアップロードができているか確認する際に、
1分ほどラグがある可能性がありますので確認する際は少し時間を置いて確認してください。

SPIRALやGoogleドライブのAPIを実行した結果をdumpする様にコメントアウトで記載しています。
SPIRALのデータがダウンロード完了しているか、Googleドライブにアップロード成功しているか、ファイルの削除の更新APIがうまく動作しているか、
各種レスポンスを表示して確認してください。

その他

外部(Google)との連携になりますので、データの取扱や認証情報の取り扱いには十分お気をつけください。
特にクライアントIDやクライアントシークレット、認証キー等は他人に絶対に知られない様にしてください。
知られてしまうとGoogleアカウント上のデータが他人に操作、閲覧されてしまう可能性がございます。

解決しない場合はこちら コンテンツに関しての
要望はこちら