LoginSignup
15
23

[PHP] Dropbox API でファイル情報を取得

Last updated at Posted at 2018-02-27

PHPでDropboxAPIを使う

Dropbox API v2 は公式のPHP用sdkが用意されていないので、直接HTTPリクエストを利用します。
cURL関数を使うのがよいでしょう。

事前準備:API用の登録を行う

https://www.dropbox.com/developers
↑ここから「Create your app」→「Dropbox API」で登録します。
登録したら、「generate access token」でアクセストークンを生成してメモしておきます。

【追記】2021/09/30 以降の認証方式

従来の永続的なアクセストークンは廃止されるとのこと。
代わりに、リフレッシュトークンを利用して短期的なアクセストークンを取得して各APIを呼び出す必要があるようです。
(参考)
Migrating App Permissions and Access Tokens
Dropbox API: アプリの権限とアクセス トークンの移行

  • アクセストークン取得方法

(1) ブラウザでAUTHORIZATION_CODEを取得する

https://api.dropbox.com/oauth2/authorize?token_access_type=offline&response_type=code&client_id=<APP_KEY>

(2) コマンドでリフレッシュトークンを取得

curl https://api.dropbox.com/oauth2/token \
    -d code=<AUTHORIZATION_CODE> \
    -d grant_type=authorization_code \
    -u <APP_KEY>:<APP_SECRET>

(3) リフレッシュトークンでアクセストークンを取得

curl https://api.dropbox.com/oauth2/token \
    -d grant_type=refresh_token \
    -d refresh_token=<REFRESH_TOKEN> \
    -u <APP_KEY>:<APP_SECRET>

これをコード化すると…

アクセストークン取得.php
	private function getAccessToken()
	{
		$url = 'https://api.dropboxapi.com/oauth2/token';
		$data = [
			'grant_type' => 'refresh_token',
			'refresh_token' => self::REFRESH_TOKEN,
		];

		$ch = curl_init();

		$options = array(
			CURLOPT_URL => $url,
			CURLOPT_RETURNTRANSFER => true,
			CURLOPT_USERPWD => self::APP_KEY . ":" . self::APP_SECRET,
			CURLOPT_POSTFIELDS => http_build_query($data)
		);

		curl_setopt_array($ch, $options);

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

		$token = '';
		if (!curl_errno($ch) && $http_code == "200") {
			$res = json_decode($res, true); //連想配列で返す
			$token = $res['access_token'];
		} else {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		return $token;
	}

(4) 取得したアクセストークンを利用

    $this->access_token = $this->getAccessToken();

【追記2】チーム向けDropboxの仕様変更

Dropbox Businessのチームプランを利用している場合に限りますが、フォルダツリーが「チームフォルダ」形式から「チームスペース」形式へと順次変更されるようです。
(参考)
DBX Team Files Guide
チーム スペースを使用するチームへの対応ガイド

端的にいうと、チームフォルダへアクセスするにはヘッダーでDropbox-API-Path-Rootを指定する必要があるようです。

指定する値は、アカウント情報から取得できるnamespace_idです。

例)
    "root_info": {
        ".tag": "user",
        "home_namespace_id": "3235641",
        "root_namespace_id": "3235641"
    },

従来どおりチームフォルダへアクセスする場合は、以下のようにヘッダーに追記すればよさそうです。

  --header 'Dropbox-API-Path-Root: {".tag": "root", "root": "<root_namespace_id>"}

または

  --header 'Dropbox-API-Path-Root: {".tag": "namespace_id", "namespace_id": "<root_namespace_id>"}

これをコード化すると…

ルートネームスペース取得.php
	private function getRootNameSpace()
	{
		$url = "https://api.dropboxapi.com/2/users/get_current_account";

		$ch = curl_init();

		$headers = array(
			'Authorization: Bearer ' . $this->accessToken, //取得したアクセストークン
			'Content-Type: application/json',
		);

		$options = array(
			CURLOPT_URL => $url,
			CURLOPT_HTTPHEADER => $headers,
			CURLOPT_POST => true,
			CURLOPT_POSTFIELDS => null, //POSTパラメータ不要
			CURLOPT_RETURNTRANSFER => true,
		);

		curl_setopt_array($ch, $options);

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

		$root_id = '';
		if (!curl_errno($ch) && $http_code == "200") {
			$res = json_decode($res, true);
			$root_id = $res['root_info']['root_namespace_id'];
		} else {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		return $root_id;
	}

これを以降のAPIコール時のヘッダーに追加してあげればOKです。

    $this->root_namespace_id = $this->getRootNameSpace();

確認:Dropbox API Explorerでテスト

公式にHTTPリクエストのテスト画面があるので、ここで用意されているAPIの一覧やURL、パラメータを確認しておきましょう。

ファイル一覧を取得する

特定フォルダ下のファイル一覧を取得する場合は、

を使います。
オプションでサブフォルダ下も見るかどうかなど指定可能です。

list_folderで取得し、さらに続きがある場合はlist_folder/continueで続きを取得することになります。

ファイル一覧取得.php
	function getFileList($dirname)
	{
		$url = "https://api.dropboxapi.com/2/files/list_folder";

		$ch = curl_init();

		$headers = array(
			'Authorization: Bearer ' . $this->access_token, //取得したアクセストークン
			'Dropbox-API-Path-Root: {".tag": "root", "root": "' . $this->root_namespace_id . '"}', //チームフォルダへアクセスする場合
			'Content-Type: application/json',
		);

		$post = array(
			"path" => "{$dirname}", //対象のディレクトリ
			"recursive" => true, //サブフォルダ下も見る
		);

		$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 $index => $content) {
					if ($content[".tag"] == "file") {
						$files[] = $content;
					}
				}
			}
			if ($res["has_more"]) {
				//続き読み込み
				$morefiles = $this->getFileListRecursive($res["cursor"]);
				$files = array_merge($files, $morefiles);
			}
		} else {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		var_export($files);
	}
ファイル一覧取得(続き).php
	function getFileListRecursive($cursor)
	{
		$url = "https://api.dropboxapi.com/2/files/list_folder/continue";

		$ch = curl_init();

		$headers = array(
			'Authorization: Bearer ' . $this->access_token,
			'Dropbox-API-Path-Root: {".tag": "root", "root": "' . $this->root_namespace_id . '"}', //チームフォルダへアクセスする場合
			'Content-Type: application/json',
		);

		$post = array(
			"cursor" => "{$cursor}", //ファイル取得レスポンスに含まれるカーソルがパラメータ
		);

		$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 {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		return $files;
	}

指定ファイルの共有リンクを取得する

取得したファイルのダウンロード用のリンクが欲しい場合は共有リンクを取得します。

また、共有リンクを発行することもできます。

共有リンク取得.php
	function getSharedLink($path)
	{
		$url = "https://api.dropboxapi.com/2/sharing/list_shared_links";

		$ch = curl_init();

		$headers = array(
			'Authorization: Bearer ' . $this->access_token,
			'Dropbox-API-Path-Root: {".tag": "root", "root": "' . $this->root_namespace_id . '"}', //チームフォルダへアクセスする場合
			'Content-Type: application/json',
		);

		$post = array(
			"path" => "{$path}", //ファイルパス
			"direct_only" => true, //ファイルへのアクセスのみ許可
		);

		$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);

		$link = "";
		if (!curl_errno($ch) && $http_code == "200") {
			$res = json_decode($res, true);
			if ($res["links"]) {
				$links = $res["links"];
				$firstlink = $links[0];
				$link = $firstlink["url"];
			} else {
				//なければ共有リンク発行
				$link = $this->createSharedLink($path);
			}
		} else {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		return $link;
	}
共有リンク発行.php
	function createSharedLink($path)
	{
		$url = "https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings";

		$ch = curl_init();

		$headers = array(
			'Authorization: Bearer ' . $this->access_token,
			'Dropbox-API-Path-Root: {".tag": "root", "root": "' . $this->root_namespace_id . '"}', //チームフォルダへアクセスする場合
			'Content-Type: application/json',
		);

		$post = array(
			"path" => "{$path}", //ファイルパス
			"settings" => array(
				"requested_visibility" => array(
					".tag" => "public" //公開
				),
			),
		);

		$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);

		$link = "";
		if (!curl_errno($ch) && $http_code == "200") {
			$res = json_decode($res, true);
			if ($res["url"]) {
				$link = $res["url"];
			} elseif ($res["error"]) {
				//既に設定済みなど
				$error = $res["error"];
				print_r("WARNING: Failed to create shared link [{$path}] - {$error['.tag']}" . PHP_EOL);
			}
		} else {
			print_r("ERROR: Failed to access DropBox via API" . PHP_EOL);
			print_r(curl_error($ch) . PHP_EOL);
		}

		curl_close($ch);

		return $link;
	}

まとめ

このあたりを組み合わせて、Dropbox上のファイルのダウンロードページをつくったりしました。

ファイルアップロードもできるようにすればストレージをDropboxにしたWEBサービスもつくれそうです。
⇒2019/6/29アップロード編書きました。

15
23
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
23