この記事ではフォームに電子署名(マウスやスマートフォンのタップで描けるサイン)を、
追加する方法をご紹介いたします。
DB設定
DBを新規作成する場合はDBタイトルをsignDBとして作成してください。
既存のDBを利用する場合は後述するサンキューページ内のPHPにて利用したいDBタイトルを記載してください。
電子署名を格納したいDBにファイル型フィールドを追加してください。
本サンプルにつきましてはファイル型フィールドの差し替えキーワードをsignatureImgとして設定しています。
入力画面
HTML
<dl class="cf"> <dt class="title"> ファイル </dt> <dd class="data file"> <canvas id="signature-pad" width="400" height="200" style="border:1px solid #000;"></canvas> <button type="button" id="clear">クリア</button> <input type="hidden" name="signature" id="signature-base64"> </dd> </dl>
JavaScirpt
<script> document.addEventListener("DOMContentLoaded", function() { var canvas = document.getElementById('signature-pad'); var ctx = canvas.getContext('2d'); var drawing = false; function getTouchPos(canvasDom, touchEvent) { var rect = canvasDom.getBoundingClientRect(); return { x: touchEvent.touches[0].clientX - rect.left, y: touchEvent.touches[0].clientY - rect.top }; } function startDrawing(e) { drawing = true; // タッチイベントの場合は座標を調整 if (e.touches) { e.preventDefault(); // スクロールを防ぎます var touch = getTouchPos(canvas, e); draw(touch.x, touch.y); } else { draw(e.offsetX, e.offsetY); } } function draw(x, y) { if (!drawing) return; ctx.lineWidth = 2; ctx.lineCap = 'round'; ctx.lineTo(x, y); ctx.stroke(); ctx.beginPath(); ctx.moveTo(x, y); } function stopDrawing() { drawing = false; ctx.beginPath(); document.getElementById('signature-base64').value = canvas.toDataURL(); } function clearCanvas() { ctx.clearRect(0, 0, canvas.width, canvas.height); } canvas.addEventListener('mousedown', startDrawing); canvas.addEventListener('mousemove', (e) => { if (drawing) { draw(e.offsetX, e.offsetY); } }); canvas.addEventListener('mouseup', stopDrawing); canvas.addEventListener('mouseout', stopDrawing); // タッチイベントリスナーを追加 canvas.addEventListener('touchstart', startDrawing); canvas.addEventListener('touchmove', (e) => { var touch = getTouchPos(canvas, e); draw(touch.x, touch.y); }); canvas.addEventListener('touchend', stopDrawing); document.getElementById('clear').addEventListener('click', clearCanvas); }); </script>
JavaScriptは/bodyの直前へ貼り付けてください。
確認画面
PHP
<? //<!-- SMP_DYNAMIC_PAGE DISPLAY_ERRORS=OFF NAME=XXX --> ?> <?php // POSTリクエストからサインデータを取得 $signatureData = $SPIRAL->getParam("signature"); ?>
※下記HTMLより上の位置に貼り付けないと動作いたしません。
HTML
<dl class="cf"> <dt class="title"> 電子サイン </dt><dd class="data file"> <img src="<?echo $signatureData;?>" alt="サイン画像" /> </dd> </dl>
サンキューページ
PHP
<? //<!-- SMP_DYNAMIC_PAGE DISPLAY_ERRORS=OFF NAME=XXX --> ?> <?php // APIの設定値 define("API_LOCATOR_URL", "https://www.pi-pe.co.jp/api/locator"); //原則変更不要 define("API_TOKEN", ""); //SPIRALAPIトークンを指定 define("API_SECRET", ""); //SPIRALAPIトークンシークレットを指定 define("FILE_FIELD", "signatureImg"); //電子署名のファイルを格納するファイル型フィールド名を指定 define("DB_NAME", ""); //格納されるDB名を指定 define("FILE_NAME", "signature"); //格納されるファイル名を指定 // POSTからBase64のサインデータを取得 $signatureData = $SPIRAL->getParam("signature"); // APIリクエストを送信する関数 function sendApiRequest($url, $method, $data, $headers) { $curl = curl_init($url); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); curl_setopt($curl, CURLOPT_POSTFIELDS, $data); curl_setopt($curl, CURLOPT_HTTPHEADER, $headers); $response = curl_exec($curl); if (curl_errno($curl)) { $error_msg = 'Curl error: ' . curl_error($curl); curl_close($curl); throw new Exception($error_msg); } curl_close($curl); return $response; } // ロケータAPIを呼び出して、サービスURLを取得 $locatorResponse = sendApiRequest(API_LOCATOR_URL, "POST", json_encode(["spiral_api_token" => API_TOKEN]), [ "X-SPIRAL-API: locator/apiserver/request", "Content-Type: application/json; charset=UTF-8", ]); $locatorData = json_decode($locatorResponse, true); $APIURL = $locatorData['location']; // データ更新APIの呼び出し $id = $SPIRAL->getContextByFieldTitle("id"); $time = time(); // 署名データの準備 $signatureData = explode(',', $signatureData, 2)[1]; $decodedData = base64_decode($signatureData); // POSTデータの構築部分を修正 $multipartBoundary = "SPIRAL_API_MULTIPART_BOUNDARY"; // JSONデータパート $jsonData = json_encode([ "spiral_api_token" => API_TOKEN, "db_title" => DB_NAME, "id" => $id, "passkey" => $time, "data" => [["name" => FILE_FIELD, "value" => $signatureData]], "signature" => hash_hmac('sha1', API_TOKEN . "&" . $time, API_SECRET, false) ]); $postData = "--" . $multipartBoundary . "\r\n"; $postData .= "Content-Disposition: form-data; name=\"json\"\r\n"; $postData .= "Content-Type: application/json\r\n\r\n"; // JSONデータのコンテントタイプを指定 $postData .= $jsonData . "\r\n"; // ファイルデータパート $postData .= "--" . $multipartBoundary . "\r\n"; $postData .= "Content-Disposition: form-data; name=\"" . FILE_FIELD . "\"; filename=\"" . FILE_NAME . ".png\"\r\n"; $postData .= "Content-Type: application/octet-stream\r\n\r\n"; $postData .= $decodedData . "\r\n"; $postData .= "--" . $multipartBoundary . "--\r\n"; // 終了バウンダリー // curlリクエスト部分 $curl = curl_init($APIURL); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, $postData); curl_setopt($curl, CURLOPT_HTTPHEADER, [ "X-SPIRAL-API: database/update/request", "Content-Type: multipart/form-data; boundary=" . $multipartBoundary, ]); // APIリクエスト送信 $updateResponse = sendApiRequest($APIURL, "POST", $postData, [ "X-SPIRAL-API: database/update/request", "Content-Type: multipart/form-data; boundary=" . $multipartBoundary, ]); ?>
その後APIの設定値の値をお使いの環境のものに指定をしてください。
解説
入力ページにてJavaScriptを用いて電子署名を書いてその画像をbase64形式に変換しPOSTを行います。
POSTされたbase64の画像データをデコードしバイナリに変換を行います。
フォーム上にて登録されたレコードに対して、バイナリ化した画像ファイルを SPIRAL API で更新する処理になっています。