開発情報・ナレッジ

投稿者:SPIRERS ナレッジ向上チーム 2022年2月1日 (火)

ver.2 で DB に登録されているファイルをダウンロードするサンプルプログラム

SPIRAL ver.2 おいて、ver.2.18時点では、サイト側にファイルダウンロード機能が実装されていません。(※)
今回は、 DB に保存されているファイルをサイト側でダウンロード可能にするボタンを作ってみました。
ファイルをダウンロードさせる機能を作りたいと思っている方は参考にしてください。
※ 今後のアップデートで実装される可能性があります。

変更・改定履歴

  • 改定

    パワーポイントのファイルがダウンロードできるよう JavaScript 修正

前提

DB からファイルを取得し、ダウンロードボタンを作成します。
DB にファイルのフィールドを追加の上、試してみてください。

PHP / API

まず、API にてファイルの情報を取得するPHPの処理を書きます。
[API_KEY][APP_ID][DB_ID]は、各環境に合わせた値の設定をお願いします。
[xxx(レコードID)][ファイルフィールドの識別名]は、取得したいファイルデータの情報に合わせて設定してください。
ファイルは、1つのみを想定しています。

PHP
<?php
//------------------------------
// 設定値用モジュール
//------------------------------
define("API_URL", "https://api.spiral-platform.com/v1/");
define("API_KEY", "");
define("APP_ID", "");
define("DB_ID", "");



//------------------------------
// ページ内処理 サンプル
//------------------------------

$commonBase = CommonBase::getInstance();

// ファイルが入っている レコード情報を取得 
// xxx は、レコードIDをセット
$data = $commonBase->apiGetCurlAction("apps/".APP_ID."/dbs/".DB_ID."/records/xxx");
	
if(array_key_exists('status', $data)){
    //APIのエラーが発生した場合、APIのレスポンスにstatusが200以外で返ってくるので、statusをチェック
    if($data["status"] != 200){
        $SPIRAL->setTHValue("error", true);
        $SPIRAL->setTHValue("errorTxt", "エラーが発生しました。");
    }
}elseif(isset($data["error"])){
    // APIの通信自体が失敗した場合
    $SPIRAL->setTHValue("error", true);
	$SPIRAL->setTHValue("errorTxt", print_r($data,true));
}else{
    //取得成功時
    // 識別名 は、ファイルレコードの識別名 
    if(isset($data["item"]["識別名"])){
		// ファイルのデータを取得(今回はファイル1つの想定)
        $imgData = $commonBase->apiGetCurlAction(str_replace(API_URL, '', $data["item"]["識別名"][0]["url"]));
        if($imgData){
            // ファイルのデータからファイル名のデータを Thymeleaf に渡す(今回はファイル1つの想定)
            $SPIRAL->setTHValue("fileName", $data["item"]["識別名"][0]["fileName"]);
            // 取得したより、base64形式データをHTMLに渡す
            $SPIRAL->setTHValue("fileData", $imgData);
			// ファイル名から拡張子を取得
			// 拡張子名は小文字で統一し、HTMLに渡す
			$SPIRAL->setTHValue("extension", substr($data["item"]["識別名"][0]["fileName"], strrpos($data["item"]["識別名"][0]["fileName"], '.') + 1));
        }else{
			// ファイルデータが取得できない場合
            $SPIRAL->setTHValue("error", true);
            $SPIRAL->setTHValue("errorTxt", "エラーが発生しました。");
        }        
    }else{
		// ファイルデータが存在しない場合
        $SPIRAL->setTHValue("error", true);
        $SPIRAL->setTHValue("errorTxt", "添付ファイルが存在しません。");
    }
}

//------------------------------
// 共通用モジュール
//------------------------------
class CommonBase
{
	/**
	 * シングルトンインスタンス
	 * @var UserManager
	 */
	protected static $singleton;

	public function __construct()
	{
		if (self::$singleton) {
			throw new Exception('must be singleton');
		}
		self::$singleton = $this;
	}

	/**
	 * シングルトンインスタンスを返す
	 * @return UserManager
	 */
	public static function getInstance()
	{
		if (!self::$singleton) {
			return new CommonBase();
		} else {
			return self::$singleton;
		}
	}

	/**
	 * ver.2 API
	 * @return Result
	 */
	function apiGetCurlAction($addUrlPass)
	{
		$header = array(
			"Authorization:Bearer " . API_KEY,
			"X-Spiral-Api-Version: 1.1",
		);
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_URL, API_URL . $addUrlPass);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
		curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
		curl_setopt($curl, CURLOPT_TIMEOUT_MS, 10000);
		$response = curl_exec($curl);
		if(json_decode($response)){
			return json_decode($response, true);
		}else{
			return base64_encode($response);
		}       	
	}
}

HTML(Thymeleaf)

PHP より渡された値をボタンの引数にセットします。

HTML(Thymeleaf)
<?php
//------------------------------
// 設定値用モジュール
//------------------------------
define("API_URL", "https://api.spiral-platform.com/v1/");
define("API_KEY", "");
define("APP_ID", "");
define("DB_ID", "");
define("FILE_FIELD", "");

//------------------------------
// ページ内処理 サンプル
//------------------------------

$commonBase = CommonBase::getInstance();

// ファイルが入っている レコード情報を取得 
// xxx は、レコードIDをセット
$data = $commonBase->apiGetCurlAction("apps/".APP_ID."/dbs/".DB_ID."/records/xxx");
	
if(array_key_exists('status', $data)){
    //APIのエラーが発生した場合、APIのレスポンスにstatusが200以外で返ってくるので、statusをチェック
    if($data["status"] != 200){
        $SPIRAL->setTHValue("error", true);
        $SPIRAL->setTHValue("errorTxt", "添付ファイルが存在しません。");
    }
}elseif(isset($data["error"])){
    // APIの通信自体が失敗した場合
    $SPIRAL->setTHValue("error", true);
	$SPIRAL->setTHValue("errorTxt", print_r($data,true));
}else{
    //取得成功時
    // 識別名 は、ファイルレコードの識別名 
    if(isset($data["item"][FILE_FIELD][0]["fileName"])){
		// ファイルのデータを取得(今回はファイル1つの想定)
        $imgData = $commonBase->apiGetCurlAction(str_replace(API_URL, '', $data["item"][FILE_FIELD][0]["url"]));
        if($imgData){
            // ファイルのデータからファイル名のデータを Thymeleaf に渡す(今回はファイル1つの想定)
            $SPIRAL->setTHValue("fileName", $data["item"][FILE_FIELD][0]["fileName"]);
            // 取得したより、base64形式データをHTMLに渡す
            $SPIRAL->setTHValue("fileData", $imgData);
			// ファイル名から拡張子を取得
			// 拡張子名は小文字で統一し、HTMLに渡す
			$SPIRAL->setTHValue("extension", substr($data["item"][FILE_FIELD][0]["fileName"], strrpos($data["item"][FILE_FIELD][0]["fileName"], '.') + 1));
        }else{
			// ファイルデータが取得できない場合
            $SPIRAL->setTHValue("error", true);
            $SPIRAL->setTHValue("errorTxt", "エラーが発生しました。");
        }        
    }else{
		// ファイルデータが存在しない場合
        $SPIRAL->setTHValue("error", true);
        $SPIRAL->setTHValue("errorTxt", "添付ファイルが存在しません。");
    }
}

//------------------------------
// 共通用モジュール
//------------------------------
class CommonBase
{
	/**
	 * シングルトンインスタンス
	 * @var UserManager
	 */
	protected static $singleton;

	public function __construct()
	{
		if (self::$singleton) {
			throw new Exception('must be singleton');
		}
		self::$singleton = $this;
	}

	/**
	 * シングルトンインスタンスを返す
	 * @return UserManager
	 */
	public static function getInstance()
	{
		if (!self::$singleton) {
			return new CommonBase();
		} else {
			return self::$singleton;
		}
	}

	/**
	 * ver.2 API
	 * @return Result
	 */
	function apiGetCurlAction($addUrlPass)
	{
		$header = array(
			"Authorization:Bearer " . API_KEY,
			"X-Spiral-Api-Version: 1.1",
		);
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($curl, CURLOPT_URL, API_URL . $addUrlPass);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
		curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "GET");
		curl_setopt($curl, CURLOPT_TIMEOUT_MS, 10000);
		$response = curl_exec($curl);
		if(json_decode($response)){
			return json_decode($response, true);
		}else{
			return base64_encode($response);
		}       	
	}
}

JavaScript

HTML 側から引数で受け取った値をダウンロードする処理を書きます。
拡張子によって、MINEタイプが違います。今回は、「zip」「pdf」「jpg」「png」「pptx」に対応しています。

JavaScript
// イベント処理で設定している引数と同じ数だけ、関数でも引数をセット
function download(fileName,extension,base64){

    // BOM の用意(文字化け対策)
    var mime_ctype = "application/"+extension;

    if(extension == "pdf" ){
        var blob = toBlob('data:application/' + extension + ';base64,' + base64, mime_ctype);
    }else if(extension == "zip"){
        var blob = toBlob(base64, 'application/'+ extension);
    }else if(extension == "jpg" || extension == "png" || extension == "pptx" ){
        var blob = toBlob('data:image/' + extension + ';base64,' + base64, mime_ctype);
    }else{
        alert("ダウンロードできません。");
        return;
    }    
    
    var url = (window.URL || window.webkitURL).createObjectURL(blob);
    // IEはdownload属性が効かないので分岐
    if (window.navigator.msSaveOrOpenBlob) {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.responseType = 'blob';
        xhr.onloadend = function() {
            if(xhr.status !== 200) return;
            window.navigator.msSaveBlob(xhr.response, fileName);
        }
        xhr.send();
    } else {
        var a = document.getElementById('downloader');
        a.download = fileName;
        a.href = url;
        // ダウンロードリンクをクリックする
        a.click();
    }

    return; 
}
  
function toBlob(base64,mime_ctype) {
    const bin = atob(base64.replace(/^.*,/, ''));
    const buffer = new Uint8Array(bin.length);
    for (let i = 0; i < bin.length; i++) {
      buffer[i] = bin.charCodeAt(i);
    }
    // Blobを作成
    const blob = new Blob([buffer.buffer], {
      type: mime_ctype
    });
    return blob;
}

不具合やほかのやり方がある等あれば、
下記の「コンテンツに関しての要望はこちら」からご連絡ください。

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