DocurainはExcelファイルをテンプレートとして、PDFや画像を生成します。主な用途としては納品書や請求書といった帳票が多いですが、実際にはそれだけに限らず利用されています。
今回はその一例として、不動産風チラシを作ってみます。
できあがったチラシ
今回作成したチラシはこのようなものになります。
要素ごとに分解すると、次のようになります。赤い部分が画像やQRコードのマクロ、青い部分がテキストになります。
このチラシは簡単なWebページ上で情報を入力し、送信すると生成されるようになっています(コードは後述します)。今回はPHPで作成していますが、他のプログラミング言語でも同じように実装できるでしょう。
作成したテンプレート
今回作成したテンプレートはこちらです(クリックでダウンロードできます)。ベースは入居募集にすぐ使える エクセルで作った「物件資料テンプレート」を無料で差し上げます! | 愛媛県松山市・収益不動産物件情報センター(洋館家・愛媛 松山道後店)よりいただきました。
利用した画像
チラシに埋め込んだ写真は、下記よりダウンロードしたものになります。
- 日当たりの良い青い空の下の白いコンクリートの建物:無料の写真素材
- アパート, インテリア, インテリア・デザインの無料の写真素材
- 寝室のインテリアセットアップ:無料の写真素材
- 分離型二世帯住宅の間取り図 間取り図ダウンロード | 間取り&3D住宅デザインソフト 3Dマイホームデザイナー
作成手順について
では、ここから作成していく手順を紹介します。
テンプレートファイルの作成
今回のチラシは明細行はありませんので、とてもシンプルなものです。まずセルA1にて #set
を使います。
#set($e=$ROOT)
これで ${ROOT}
だけではなく ${e}
を使ってアクセスできるようになるので、テンプレートのマクロ記述が簡単になります。まずテキスト部分について、すべて記述していきます。ここではDocurainの省略記法を使って %{name}
と書くことで、そこに物件名が入るといった具合です。
配列の出力
今回はおすすめポイント1〜3が配列となっています。これは配列の要素を指定することでアクセスできます。
%{goods[0]}
通常のプログラミング言語と同様、配列は1つ目の要素が [0]
と指定するので注意してください。
画像の指定
画像はセルに直接書くのではなく、図形を配置します。
そして図形のテキストとして #IMAGE(要素の値)
と記述します。例えば #IMAGE($e.appearance)
といった具合です。文字列として出力する場合には %{appearance}
としますが、マクロに渡す場合には $e.appearance
とするので注意してください。
QRコードの指定
QRコードも画像と同じように図形で配置します。QRコードは正方形なので、図形も正方形にしてください。
そして図形のテキストとして #QRCODE(要素の値)
と記述します。こちらも画像と同じく #QRCODE(e.url)
などとします。このURLは物件情報が掲載されたURLや、電話番号などになるでしょう。
フッターのテキスト
フッターではテンプレート上に書いた文字と、パラメータで渡す文字が混在しています。この場合でも ${}
を使って指定できます。
<TEL : %{tel} HP %{website}>
表示範囲の設定
テンプレートファイルにパラメータを埋め込み終わったら、印刷範囲の設定をしておきましょう。Excelのページレイアウトメニューで、印刷範囲の設定をします。A列を除いて(場合によっては1行目も除いて)帳票として作成したい部分を選択して、印刷範囲の設定を選択します。そして表示メニューで、改ページプレビューにしておくと、実際に帳票が作成される範囲が分かりやすくなります。
プログラミングについて
ではテンプレートファイルができあがったら、PHPによるプログラミングに入っていきます。今回はestimate.phpというファイルで作成しています。
環境の設定とライブラリインストール
PHPがインストールされていない場合にはインストールしてください。
次に適当なディレクトリを作成し、ライブラリをインストールします。composerを使うので、インストールしていない場合には下記のコマンドを実行します。
curl -sS https://getcomposer.org/installer | php
そしてGuzzleというHTTPクライアントをインストールします。
composer require guzzlehttp/guzzle:^7.0
入力画面の作成
今回は1つのファイルで入力画面と、PDF作成処理を行います。そこで、PHPファイルにGETアクセスした時(入力画面表示)とPOSTアクセスした時(PDF作成)で処理分けします。
<?php require 'vendor/autoload.php'; use GuzzleHttp\Client; if (!$_POST) { ?><!doctype html> <!-- 入力画面に関する記述 --> <?php } else { // PDF作成処理に関する記述 }
入力画面はBootstrapを使って作成しています。個々の入力項目の名前と、Excelテンプレートでの指定と合わせておくことで、PDF作成時の処理を簡単なものにしています。今回は入力画面で画像も指定しているので、formタグに enctype="multipart/form-data"
を記述しています。
<!-- 入力画面に関する記述 --> <html lang="ja"> <head> <meta charset="utf-8"> <title>不動産チラシ作成</title> <meta name="description" content="The HTML5 Herald"> <meta name="author" content="SitePoint"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="md-12"> <h2>不動産チラシ作成</h2> </div> <div class="col-md-12"> <form class="form" action="/estimate.php" method="POST" enctype="multipart/form-data"> <div class="row"> <div class="mb-12"> <label class="form-label"></label> <input type="text" class="form-control" name="name" placeholder="リバーサイド×× 701号室" value=""> </div> </div> <!-- 略 --> <div class="mb-12"> <label for="formFile" class="form-label">外観写真</label> <input class="form-control" name="appearance" type="file"> </div> <!-- 略 --> <div class="row"> <div class="col-auto"> <button type="submit" class="btn btn-primary mb-3">チラシ作成</button> </div> </div> </form> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> </body> </html>
入力項目は多いですが、結果として次のような表示になります。
これはPHP内蔵サーバを使って http://localhost:8000/estimate.php
にアクセスした時の表示です。サーバの起動は下記コマンドになります。estimate.phpがあるディレクトリにて実行してください。
php -S localhost:8000
PDF作成処理について
チラシの情報を入力して送信すると、PDF作成処理に入ります。まず、Docurainのシークレットキーと、テンプレートファイルのパス、APIエンドポイントを用意します。テンプレートファイルはあらかじめDocurain上にアップロードしておくこともできますが、開発中はトライアンドエラーになると思いますので、ローカルファイルを用いるインスタントAPIの方が効率的でしょう。
APIエンドポイントについては今回はPDFですが、jpgなども指定できます。詳しくはこちらを参照してください(要ログイン)。
// PDF作成処理に関する記述 $secret_key = 'YOUR_DOCURAIN_SECRET_KEY'; $template_path = '/path/to/real-estimate.xls'; $url = 'https://api.docurain.jp/api/instant/pdf';
パラメータの作成
次に送信するパラメータを用意します。ベースになるのはフォームで入力された内容($_POST)です。
$params = $_POST;
そして設定された画像を、それぞれDATA URI形式に変換します。PHPでは $_FILES
で受け取れますので、それぞれ変換してパラメータに指定していきます。画像サイズが大きいとエラーになってしまうので注意してください。
foreach ($_FILES as $name => $path) {
// Mimeタイプを設定
$uri = 'data:' . mime_content_type($path['tmp_name']) . ';base64,';
// Base64変換した文字列を設定
$uri .= base64_encode(file_get_contents($path['tmp_name']));
// パラメータに追加
$params[$name] = $uri;
}
作成したパラメータをJSON文字列にします。
$entity_json = json_encode($params);
リクエストパラメータの準備
次にテンプレート情報を含めて、リクエストパラメータを準備します。これは2つのパラメータがあります。
- entity
フォーム入力内容。JSONとして送信します。 - template
テンプレート用のExcelファイル。Content-Typeは拡張子(xlsまたはxlsx)によって異なります。内容はバイナリです。
内容はそれぞれ次のようになります。
$param = [ [ 'name' => 'entity', 'contents' => $entity_json, 'headers' => [ 'Content-Type' => 'application/json' ] ], [ 'name' => 'template', 'contents' => file_get_contents($template_path), 'headers' => [ 'Content-Type' => mime_content_type($template_path) ], 'filename' => basename($template_path) ], ];
HTTPヘッダーの準備
インスタントAPIの場合、レスポンスはエンドポイントによって異なりますので、Content-Typeを指定する必要はありません。認証ヘッダーのみになります。
$headers['Authorization'] = "token {$secret_key}";
リクエスト情報をまとめる
これで必要なリクエスト情報は集まりましたので、1つの変数にまとめます。
$options = [ 'http_errors' => false, 'headers' => $headers, 'multipart' => $param ];
リクエスト実行
そしてリクエストを実行します。
$client = new Client();
$res = $client->request('POST', $url, $options);
処理がうまくいったかどうかはレスポンスのステータスコードで判別してください。
if ($res->getStatusCode() === 200) { } else { // APIリクエストエラーの場合 echo $res->getBody(); }
処理がうまくいった場合には、HTTPヘッダーを付けて結果をファイル estimate.pdf
としてダウンロードさせます。
header("Content-Disposition: attachment; filename=estimate.pdf");
echo $res->getBody();
exit;
}
これでPDF出力処理の完成です。
全体のコード
長いですが、全体のコードは次のようになります。
<?php require 'vendor/autoload.php'; use GuzzleHttp\Client; if (!$_POST) { ?><!doctype html> <html lang="ja"> <head> <meta charset="utf-8"> <title>不動産チラシ作成</title> <meta name="description" content="The HTML5 Herald"> <meta name="author" content="SitePoint"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="md-12"> <h2>不動産チラシ作成</h2> </div> <div class="col-md-12"> <form class="form" action="/estimate.php" method="POST" enctype="multipart/form-data"> <div class="row"> <div class="mb-12"> <label class="form-label">物件名</label> <input type="text" class="form-control" name="name" placeholder="物件名" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">所在地</label> <input type="text" class="form-control" name="address" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">最寄り施設</label> <input type="text" class="form-control" name="location" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">交通</label> <input type="text" class="form-control" name="access" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">間取り(専有面積)</label> <input type="text" class="form-control" name="area" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">家賃</label> <input type="text" class="form-control" name="cost" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">共益費</label> <input type="text" class="form-control" name="fee" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">敷金</label> <input type="text" class="form-control" name="deposit" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">礼金</label> <input type="text" class="form-control" name="key_money" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">種別</label> <input type="text" class="form-control" name="type" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">築年数</label> <input type="text" class="form-control" name="build_at" placeholder="" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">設備1</label> <input type="text" class="form-control" name="facility1" placeholder="設備1" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">設備2</label> <input type="text" class="form-control" name="facility2" placeholder="設備2" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">備考</label> <input type="text" class="form-control" name="note" placeholder="特記事項です" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">PRポイント</label> <textarea class="form-control" name="pr" placeholder="PRポイントを書きます"></textarea> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">タイトル(チラシ上段)</label> <input type="text" class="form-control" name="title" placeholder="タイトル" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">一押しポイント1</label> <input type="text" class="form-control" name="goods[]" placeholder="一押しポイント1" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">一押しポイント2</label> <input type="text" class="form-control" name="goods[]" placeholder="一押しポイント2" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">一押しポイント3</label> <input type="text" class="form-control" name="goods[]" placeholder="一押しポイント3" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">QRコード用物件URL</label> <input type="text" class="form-control" name="url" placeholder="https://docurain.jp/" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">電話番号</label> <input type="text" class="form-control" name="tel" placeholder="000-0000-0000" value=""> </div> </div> <div class="row"> <div class="mb-12"> <label class="form-label">ホームページ</label> <input type="text" class="form-control" name="website" placeholder="https://docurain.jp/" value=""> </div> </div> <div class="mb-12"> <label for="formFile" class="form-label">外観写真</label> <input class="form-control" name="appearance" type="file"> </div> <div class="mb-12"> <label for="formFile" class="form-label">内観写真1</label> <input class="form-control" name="preview1" type="file"> </div> <div class="mb-12"> <label for="formFile" class="form-label">内観写真2</label> <input class="form-control" name="preview2" type="file"> </div> <div class="mb-12"> <label for="formFile" class="form-label">見取り図</label> <input class="form-control" name="floor" type="file"> </div> <div class="row"> <div class="col-auto"> <button type="submit" class="btn btn-primary mb-3">チラシ作成</button> </div> </div> </form> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW" crossorigin="anonymous"></script> </body> </html> <?php } else { $secret_key = 'YOUR_DOCURAIN_SECRET_KEY'; $params = $_POST; $template_path = '/path/to/real-estimate.xls'; foreach ($_FILES as $name => $path) { $uri = 'data:' . mime_content_type($path['tmp_name']) . ';base64,'; $uri .= base64_encode(file_get_contents($path['tmp_name'])); $params[$name] = $uri; } $entity_json = json_encode($params); $url = 'https://api.docurain.jp/api/instant/pdf'; $param = [ [ 'name' => 'entity', 'contents' => $entity_json, 'headers' => [ 'Content-Type' => 'application/json' ] ], [ 'name' => 'template', 'contents' => file_get_contents($template_path), 'headers' => [ 'Content-Type' => mime_content_type($template_path) ], 'filename' => basename($template_path) ], ]; $headers['Authorization'] = "token {$secret_key}"; $options = [ 'http_errors' => false, 'headers' => $headers, 'multipart' => $param ]; $client = new Client(); $res = $client->request('POST', $url, $options); if ($res->getStatusCode() === 200) { header("Content-Disposition: attachment; filename=estimate.pdf"); echo $res->getBody(); exit; } else { // APIリクエストエラーの場合 echo $res->getBody(); } }
Tips
今回の不動産風チラシの作成時における、幾つかのTipsを紹介します。
画像サイズについて
Docurainでは図形のサイズと画像サイズをぴったり合わせる(または等倍にする)と綺麗に出力されます。Excelでは図形サイズの指定がセンチメートル指定になるので、画像編集ソフトウェアを使う際にもセンチメートル指定で作成すると良いでしょう。
フォーマットはxls
Docurainではテンプレートファイルのフォーマットとしてxlsまたはxlsxを指定できます。今回はxlsを使った方が、画像がぴったり表示されました。もし片方のフォーマットでうまくいかない場合には、もう片方のフォーマットで試してみてください。
まとめ
今回はいわゆる帳票ではない、チラシ的なものをDocurainを通して作成しました。画像やQRコードなどを使うことで、表現力が大きく向上するのが分かってもらえたかと思います。これまでは業者に依頼していたようなものも、PDF出力して印刷することで自社内で完結できるようになるでしょう。
なお、通常であればWebページから一つ一つの帳票を作成することはないでしょう。システム連携してDBなどから自動的にDocurainのAPIを呼び出すはずです。とはいえ、こういったちょっとした帳票やチラシなどもDocurainから作れると覚えておくと、利用できる幅が広がるのではないでしょうか。
ぜひDocurainを使って、業務フローを強化、改善してください。