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

