【PHP】DropboxAPIをPHPで使ってみる
私はDropbox結構前から使っていたんですが、今までWEBサービスと連携させたことはなかったです。
なので、今回DropboxにAPIを使って、PHPからアクセスしてみます。
以下の記事を参考にさせていただきました。
Dropboxアカウントを取得しましょう
Dropboxのサイトからアカウントを作成してください。
https://www.dropbox.com/ja/
DropboxのDeveloperサイトでアプリを作成しましょう
Dropboxの通常ユーザーのページとは別に、開発者用ページDBX Platformというものがあり、こちらからアプリを作成します。
https://www.dropbox.com/developers
アプリを作成といっても、ここでプログラムを組むわけではなく、API接続するために必要な情報を登録するだけです。
この画面で『アプリを作成』をクリックしてください。
1.APIを選んでください。
→ Scoped access
そう、「選んでください」と言いつつ、初めから選択肢など無いのです。
謹んでScoped accessを選択してください。
2.このアプリは、アプリの指定フォルダ内のみアクセスできるか、Dropboxアカウントの全てのフォルダにアクセスできるか、どちらにしますか?
こちらについてはセキュリティ的な観点から、『App folder』を推奨します。
3.あなたのアプリ名を入力してください。
今回、私はブラウザからアップロードした画像をPHPでDropboxに転送するプログラムを作成したかったので、「ImageTransferApp」と名前を付けました。
そうすると「利用条件に同意しなさい」というチェックボックスが表示されます。
ここでつまづきポイントですが、Google Chromeでは同意ボタンが表示されましたが、Microsoft Edgeでは同意ボタンが表示されず、ここから先に進めませんでした。
同志たちは最初からGoogle Chromeを使うようにしよう!
I agreeすると先に進めるようになるのですが、ここでもつまづきポイントがありました。
このスクリーンショット撮影時点では問題なく進めましたが、最初検証した時はI agreeをチェックしてもCreate appボタンが有効化されませんでした。
その時、アクセスタイプをApp folderとFull Dropboxを付け替えなどすると有効化されました。(その現象もEdgeで起きてたんだったかな・・・
問題なく、アプリが作成できると、上記のような画面になります。
Dropbox Appのパーミッションを設定しましょう
アプリが作成できたら、パーミッションタブを開いて、権限の設定を行います。
Permissionsタブを開きます。
とりあえず、これくらいの権限を与えておけば良かろうと思います。
Dropboxのアクセストークンを取得する
このあたりから、ややこしくなってきます。
Dropboxが提供するAPIでは、誰でも彼でも勝手にAPIを利用できるわけではなく、APIを利用するために、アクセストークンを取得する必要があります。
このアクセストークンがアプリの識別であり、どのDropboxアカウントに紐づいているかを表す記号でもあります。
以前は永続的アクセストークンが提供されていたようですが、現在は一時的なアクセストークンを毎回取得する必要があるようです。
一時的なアクセストークンの取得にはいくつかの手順があります。
上記手順は最初に1回実行したら、OKです。
そして、上記の手順で取得したApp Key、App Secret、リフレッシュトークンの3つを使って、一時アクセストークンを生成します。
一時アクセストークンは毎回取得する必要があります。
認証コードの取得
認証コードの取得には以下のURLにアクセスします。
https://www.dropbox.com/oauth2/authorize?token_access_type=offline&response_type=code&client_id=[AppKey]
[AppKey]の部分は、アプリ画面内に記載されています。
このApp Keyと記載されている部分の文字列を入れてください。
URLにブラウザからアクセスすると、以下のような表示が出ます。
続行しないと先には進めないので、続行してください。
アプリにアクセス権限を与えます。
そうすると、認証コードが生成されます。
認証コードはアプリの管理画面にも表示されませんので、どこかにメモっといてください。
リフレッシュトークンを取得
このリフレッシュトークンは、一時的なアクセストークンを使い続けていると有効期限が切れてしまうので、新しい一時的トークンを再取得するために必要になるトークンだと思います。
リフレッシュトークンの取得はコンソール(コマンドプロンプトやPowerShell、ターミナル等)から操作してください。
curl https://api.dropbox.com/oauth2/token \
-d code=[Access Code] \
-d grant_type=authorization_code \
-u [AppKey]:[AppSecret] \
WindowsのコマンドプロンプトやPowerShellなどで上記コマンドを実行すると、SSL認証に関する警告が出て、うまくいかないので、以下のコマンドを試してください。
curl https://api.dropbox.com/oauth2/token \
-d code=[Access Code] \
-d grant_type=authorization_code \
-u [AppKey]:[AppSecret] \
--ssl-no-revoke
コマンドプロンプトで実際にコマンドを実行してみました。
上記コマンドで取得したコードがリフレシュトークンです。
以下の画像の赤い線の部分です。
このrefresh_tokenの部分は後でプログラム内部で利用します。
ここまでで取得したApp KeyとApp Secretとリフレッシュトークンは定数などで呼び出せるようにしておいてください。
<?php
// 定数として記述しておく
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
ここまでの処理は最初に1回やっておけば大丈夫です。
一時的アクセストークンを取得する
さて、DropboxAPIに接続するには、一時的なアクセストークンを発行する必要があるのですが、『一時的』なので当然すぐ有効期限が切れてしまいます。
なので、ここからの処理は定型処理として、プログラムに記述しておきます。
<?php
// 定数として記述しておく
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// 一時的なアクセストークンを取得
private 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);
$this->access_token = $res['access_token'];
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $access_token;
}
// 一時的なアクセストークンを取得
$access_token = getAccessToken();
cURLを使って、アクセスします。
getAccessToken()を実行すると、戻り値として一時的なアクセストークンが返ってきます。
Dropbox内のファイル一覧を取得する
さて、一時的なアクセストークンが取得できたら、いよいよDropboxへのアクセスです。
<?php
// 定数として記述しておく
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// 一時アクセストークンを取得
private function getAccessToken() {
// さっきの処理
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイル一覧を取得
function getFileList($access_token, $dirname) {
$url = "https://api.dropboxapi.com/2/files/list_folder";
$headers = array(
"Authorization: Bearer " . $access_token,
"Content-Type: application/json",
);
$post = array(
"path" => $dirname, // 対象のディレクトリ
"recursive" => true, // サブフォルダ下も見る
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$options = array(
CURLOPT_POSTFIELDS => json_encode($post),
);
curl_setopt_array($ch, $options);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$files = array();
if (!curl_errno($ch) && $http_code == "200") {
$res = json_decode($res, true);
if ($res["entries"]) {
foreach ($res["entries"] as $index => $content) {
if ($content[".tag"] == "file") {
$files[] = $content;
}
}
}
if ($res["has_more"]) {
//続き読み込み
$morefiles = $this->getFileListRecursive($res["cursor"]);
$files = array_merge($files, $morefiles);
}
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $files;
}
// 一時的なアクセストークンを取得
$access_token = getAccessToken();
// ファイルの一覧を取得
$files = getFileList($access_token, "");
// 結果を出力
echo "<pre>";
var_dump($files);
echo "</pre>";
今回の注意すべき点としては、アクセス先ディレクトリがルートディレクトリの場合、”/”ではなく、””を指定する点ですね。
そして、””を指定した時のルートディレクトリがどこかというと、”Dropbox/アプリ/ImageTransferApp”となります。
Dropboxルートではなく、アプリディレクトリが作成され、さらにその下にアプリ名のディレクトリが作成され、アプリ名のディレクトリがルートとなります。
だって、Dropboxアプリ作成時に「App folder」を選んだもんね?
Dropbox内のファイルにアクセスするURLを取得する
Dropbox内のファイルURLを直接取得するのではなく、ファイルにアクセスするための一時URLを生成して、そのURLを返すという方式をとっています。
<?php
// 定数として記述しておく
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// 一時アクセストークンを取得
private function getAccessToken() {
// さっきの処理
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイルの一時アクセス用リンクURLを取得
function getFileURL($access_token, $local_filepath) {
$url = "https://api.dropboxapi.com/2/files/get_temporary_link";
$headers = array(
"Authorization: Bearer " . $access_token,
"Content-Type: application/json",
);
$post = array(
"path" => $local_filepath, // 対象ファイルのパス
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$options = array(
CURLOPT_POSTFIELDS => json_encode($post),
);
curl_setopt_array($ch, $options);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$file_uri = '';
if (!curl_errno($ch) && $http_code == "200") {
$res = json_decode($res, true);
$file_uri = $res['link'];
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $file_uri;
}
// 一時的なアクセストークンを取得
$access_token = getAccessToken();
// Dropbox内のファイルにアクセスするURLを取得する
$url = getFileURL($access_token, "/test/img.png");
// 結果を出力
echo "<pre>";
var_dump($res);
echo "</pre>";
Dropbox内にファイルをアップロードする
<?php
// 定数として記述しておく
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// 一時アクセストークンを取得
private function getAccessToken() {
// さっきの処理
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイルをアップロード(軽いファイル用)
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") {
$res = json_decode($res, true); //連想配列で返す
} else {
echo "ERROR: Failed to access DropBox via API : " . curl_error($ch) . "<br>";
}
fclose($file);
curl_close($ch);
return $res['path_lower'];
}
// 一時的なアクセストークンを取得
$access_token = getAccessToken();
// ファイルをアップロード
$remote_path = uploadFile($access_token, "C:\\Sample\\Sample.png", "/test/img02.png");
// 結果を出力
echo "<pre>";
var_dump($res);
echo "</pre>";
これ、コメントに(軽いファイル用)って書いてるんですけど、Dropbox HTTP APIの公式リファレンスを見ると、「Do not use this to upload a file larger than 150 MB.(150MB以上のサイズのファイルアップロードには使っちゃダメだよ)」って書いてるんですね。
150MB以上のファイルをアップロードする時にはupload_sessionっていうのを使うようです。
upload_sessionの使い方については、またの機会に掲載しようと思います。
ここまでの処理をクラス化してみたよ
class Dropbox {
const APP_KEY = '[App Key]';
const APP_SECRET = '[App Secret]';
const REFRESH_TOKEN = '[リフレッシュトークン]';
// 一時的なアクセストークン
private $access_token;
// コンストラクタ
public function __construct() {
// 一時的なアクセストークンを取得
$this->access_token = $this->getAccessToken();
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// 一時的なアクセストークンを取得
private function getAccessToken() {
$url = 'https://api.dropboxapi.com/oauth2/token';
$data = [
'grant_type' => 'refresh_token',
'refresh_token' => self::REFRESH_TOKEN,
'client_id' => self::APP_KEY,
'client_secret' => self::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;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイル一覧を取得
public function getFileList($dirname) {
$url = "https://api.dropboxapi.com/2/files/list_folder";
$headers = array(
"Authorization: Bearer " . $this->access_token, //取得したアクセストークン
"Content-Type: application/json",
);
$post = array(
"path" => $dirname, // 対象のディレクトリ
"recursive" => true, // サブフォルダ下も見る
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$options = array(
CURLOPT_POSTFIELDS => json_encode($post),
);
curl_setopt_array($ch, $options);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$files = array();
if (!curl_errno($ch) && $http_code == "200") {
$res = json_decode($res, true); //連想配列で返す
if ($res["entries"]) {
foreach ($res["entries"] as $index => $content) {
if ($content[".tag"] == "file") {
$files[] = $content;
}
}
}
if ($res["has_more"]) {
$morefiles = $this->getFileListRecursive($res["cursor"]);
$files = array_merge($files, $morefiles);
}
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $files;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイル一覧を取得
public function getFileListRecursive($cursor) {
$url = "https://api.dropboxapi.com/2/files/list_folder/continue";
$headers = array(
"Authorization: Bearer " . $this->access_token,
"Content-Type: application/json",
);
$post = array(
"cursor" => "{$cursor}", //ファイル取得レスポンスに含まれるカーソルがパラメータ
);
$ch = curl_init();
$options = array(
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($post),
CURLOPT_RETURNTRANSFER => true,
);
curl_setopt_array($ch, $options);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$files = array();
if (!curl_errno($ch) && $http_code == "200") {
$res = json_decode($res, true);
if ($res["entries"]) {
foreach ($res["entries"] as $content) {
if ($content[".tag"] == "file") {
$files[] = $content;
}
}
}
if ($res["has_more"]) {
$morefiles = $this->getFileListRecursive($res["cursor"]);
$files = array_merge($files, $morefiles);
}
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $files;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイルの一時アクセス用リンクURLを取得
public function getFileURL($local_filepath) {
$url = "https://api.dropboxapi.com/2/files/get_temporary_link";
$headers = array(
"Authorization: Bearer " . $this->access_token, //取得したアクセストークン
"Content-Type: application/json",
);
$post = array(
"path" => $local_filepath, // 対象ファイルのパス
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$options = array(
CURLOPT_POSTFIELDS => json_encode($post),
);
curl_setopt_array($ch, $options);
$res = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$file_uri = '';
if (!curl_errno($ch) && $http_code == "200") {
$res = json_decode($res, true);
$file_uri = $res['link'];
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
curl_close($ch);
return $file_uri;
}
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
// ファイルをアップロード(軽いファイル用)
public function uploadFile($local_filepath, $upload_filepath) {
$url = "https://content.dropboxapi.com/2/files/upload";
$headers = array(
"Authorization: Bearer " . $this->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") {
$res = json_decode($res, true);
} else {
echo "ERROR: Failed to access Dropbox API : " . curl_error($ch) . "<br>";
}
fclose($file);
curl_close($ch);
return $res['path_lower'];
}
}
// クラスのインスタンスを生成
$dropbox = new Dropbox();
// ファイル一覧を取得
// DropboxRoot => アプリ => アプリ名(アプリルート) => 指定ディレクトリパス
$files = $dropbox->getFileList('');
// ファイルアップロード
$remote_path = $dropbox->uploadFile('.\img\sea.jpg', '/sea.jpg');
echo "<div>UPLOAD PATH : {$remote_path}</div>";
// ファイルのアクセスURLを取得
// DropboxRoot => アプリ => アプリ名(アプリルート) => 指定ディレクトリパス
$url = $dropbox->getFileURL("/sea.jpg");
// 取得したURLの画像を表示してみる
echo "<div><img style='max-width:320px; max-height:320px;' src='{$url}'/></div>";
みんなはうまく動いたかな?
もしお困りごとがありましたら、お問い合わせフォームよりご相談ください。