この記事ではフォームに電子署名(マウスやスマートフォンのタップで描けるサイン)を、
追加する方法をご紹介いたします。
DB設定
電子署名を格納したいDBにフィールドタイプ:ファイルのフィールドを追加してください。
本サンプルにつきましては識別名をsignatureとして設定しています。
設定方法
登録フォームブロックを作成してください。
本サンプルにつきましては識別名をsignatureとして設定しています。
ソース編集を行う為、ソースデザインにて作成を行ってください。
登録フォームブロックが完成したらページを作成し上記で作成した登録フォームブロックを読み込む様にしてください。
登録フォームブロック 入力(Step1)
HTML
<!--/* signature */--> <div class="sp-form-item sp-form-field"> <div class="sp-form-label"> 電子サイン </div> <div> <canvas id="signature-pad" width="400" height="150" style="border: 1px solid #000;"></canvas> <input type="hidden" name="signature" id="signature-base64"> <span class="sp-form-noted" th:if="${fields['f02'].help != null}" th:text="${fields['f02'].help}">Help text</span> <span class="sp-form-error" th:data-zipcode="|zipCodeError${fields['f02'].name}|" th:text="${errors['f02']?.message}">Error message</span> </div> </div>
登録フォームブロック 確認(Step2)
HTML
<div class="sp-form-item sp-form-field"> <div class="sp-form-label" >電子サイン</div> <div class="sp-form-data"> <img th:src="${cp.result.value['signature']}" alt="Signature Image" /> <input type="hidden" name="signature" id="signature-base64" th:value="${cp.result.value['signature']}" /> </div>
任意の箇所へ貼り付けてください。
ページ設定
PHP
<? //変更不可 session_start(); $commonBase = CommonBase::getInstance(); //------------------------------ // 設定値 //------------------------------ define("API_URL", "https://api.spiral-platform.com/v1"); define("API_KEY", ""); define("APP_ROLE", ""); define("DB_ID", ""); //電子署名を格納するDBID define("APP_ID", ""); //電子署名を格納するDBが属しているアプリID $registForm = $SPIRAL->getRegistrationForm("signature"); //フォームの識別名 $fileFieldId = "1"; //ファイルフィールドID $fileFieldName = "signature"; //ファイルフィールド識別名 $fileName = "signatureImg.png"; //ファイル名 //step2での画像表示 $step = $registForm->getStep(); if($step == 2){ $base64 = $SPIRAL->getPostParam("signature"); $SPIRAL->setTHValue("signature",$base64); // 画像データの準備 $signatureData = explode(',', $base64, 2)[1]; $decodedData = base64_decode($signatureData); //ファイルアップロードトークン発行 $apiUrlPass = "/apps/". APP_ID. "/dbs/". DB_ID. "/". $fileFieldId. "/files/uploadToken"; $apiResponse = $commonBase->apiCurlAction("POST", $apiUrlPass); $fileUploadToken = $apiResponse["fileUploadToken"]; //ファイルアップロード $apiUrlPass = "/apps/". APP_ID. "/dbs/". DB_ID. "/". $fileFieldId. "/files"; // リクエストボディ(マルチパート形式) $requestBody = "--WebKitFormBoundary7MA4YWxkTrZu0gW\r\n"; $requestBody .= "Content-Disposition: form-data; name=\"file\"; filename=\"". $fileName. "\"\r\n"; $requestBody .= "Content-Type: image/png\r\n\r\n"; $requestBody .= $decodedData. "\r\n"; $requestBody .= "--WebKitFormBoundary7MA4YWxkTrZu0gW\r\n"; $requestBody .= "Content-Disposition: form-data; name=\"fileUploadToken\"\r\n\r\n"; $requestBody .= $fileUploadToken. "\r\n"; $requestBody .= "--WebKitFormBoundary7MA4YWxkTrZu0gW--"; $contentType = "Content-Type: multipart/form-data; boundary=WebKitFormBoundary7MA4YWxkTrZu0gW"; $apiResponse = $commonBase->apiCurlAction("POST", $apiUrlPass, $requestBody, $contentType); $_SESSION["filekey"] = $apiResponse["fileKey"]; } //完了ステップでのデータ送信 if($registForm->isCompletedStep()){ $record = $SPIRAL->getRecordValue(); $recordId = $record['item']['_id']; // 更新するデータを指定 $UpdateData = array( $fileFieldName => array($_SESSION["filekey"]) ); $resultRecordUpdate = $commonBase->apiCurlAction("PATCH", "/apps/". APP_ID. "/dbs/". DB_ID. "/records/". $recordId, $UpdateData); } //------------------------------ // 共通モジュール //------------------------------ 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; } } /** * V2用 API送信ロジック * @return Result */ function apiCurlAction($method, $addUrlPass, $data = null, $multiPart = null, $jsonDecode = null) { $header = array( "Authorization:Bearer ". API_KEY, "X-Spiral-Api-Version: 1.1", ); if($multiPart) { $header = array_merge($header, array($multiPart)); } else { $header = array_merge($header, array("Content-Type:application/json")); } if(APP_ROLE){ $header = array_merge($header, array("X-Spiral-App-Role: ".APP_ROLE)); } // curl $curl = curl_init(); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_URL, API_URL. $addUrlPass); curl_setopt($curl, CURLOPT_HTTPHEADER, $header); if ($method == "POST") { if ($multiPart) { curl_setopt($curl, CURLOPT_POSTFIELDS, $data); } else { curl_setopt($curl, CURLOPT_POSTFIELDS , json_encode($data)); } curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); } if ($method == "PATCH") { curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); } if ($method == "DELETE") { curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($data)); curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); } $response = curl_exec($curl); if (curl_errno($curl)) echo curl_error($curl); curl_close($curl); if($jsonDecode){ return $response; }else{ return json_decode($response, true); } } } ?>
JavaScript
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); });
貼り付けた後PHPにつきましては設定値欄をお使いの環境の物へ変更してください。
解説
入力ページにてJavaScriptを用いて電子署名を書いてその画像をbase64形式に変換しPOSTを行います。
POSTされたbase64の画像データをデコードしバイナリに変換を行います。
フォーム上にて登録されたレコードに対して、バイナリ化した画像ファイルを SPIRAL API で更新する処理になっています。