この記事ではフォームに電子署名(マウスやスマートフォンのタップで描けるサイン)を、
追加する方法をご紹介いたします。
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 で更新する処理になっています。
