Create an HTML form with Digital / Electronic Signature using php

drooh picture drooh · Mar 21, 2017 · Viewed 15.6k times · Source

I'm looking for a solution to add a signature to a form. One where someone can sign with their mouse or with their finger on a touch device. I'm wondering if I can use something like jSignature https://willowsystems.github.io/jSignature/#/about/ to create an image, the process the form with php and create a PDF and then add the image to the PDF.

I've researched a bit and haven't found a clear solution for this. Basically I'm wanting to create a simple freelancer website contract that clients would sign online.

Answer

Flame picture Flame · Mar 30, 2020

I've created a fairly minimum prototype that uses the <canvas> element to allow signature drawings. This drawing is then added to the form as a base64 url.

Short explanation of the code:

  • Create a <canvas> element
  • Define events for mousedown (pencil down), mousemove (continue drawing) and mouseup (pencil up)
  • Draw on the canvas by creating a line between the previous and current coordinates. Note that if you would draw a lot of dots on the current coordinate, you will not get a smooth line when moving fast with your mouse.
  • When you stop drawing, we get the canvas contents as an image using canvas.toDataUrl(). This is then set on a hidden input on the form.

var canvas = document.getElementById('signature');
var ctx = canvas.getContext("2d");
var drawing = false;
var prevX, prevY;
var currX, currY;
var signature = document.getElementsByName('signature')[0];

canvas.addEventListener("mousemove", draw);
canvas.addEventListener("mouseup", stop);
canvas.addEventListener("mousedown", start);

function start(e) {
  drawing = true;
}

function stop() {
  drawing = false;
  prevX = prevY = null;
  signature.value = canvas.toDataURL();
}

function draw(e) {
  if (!drawing) {
    return;
  }
  // Test for touchmove event, this requires another property.
  var clientX = e.type === 'touchmove' ? e.touches[0].clientX : e.clientX;
  var clientY = e.type === 'touchmove' ? e.touches[0].clientY : e.clientY;
  currX = clientX - canvas.offsetLeft;
  currY = clientY - canvas.offsetTop;
  if (!prevX && !prevY) {
    prevX = currX;
    prevY = currY;
  }

  ctx.beginPath();
  ctx.moveTo(prevX, prevY);
  ctx.lineTo(currX, currY);
  ctx.strokeStyle = 'black';
  ctx.lineWidth = 2;
  ctx.stroke();
  ctx.closePath();

  prevX = currX;
  prevY = currY;
}

function onSubmit(e) {
  console.log({
    'name': document.getElementsByName('name')[0].value,
    'signature': signature.value,
  });
  return false;
}
canvas#signature {
  border: 2px solid black;
}

form>* {
  margin: 10px;
}
<form action="submit.php" onsubmit="return onSubmit(this)" method="post">
  <div>
    <input name="name" placeholder="Your name" required />
  </div>
  <div>
    <canvas id="signature" width="300" height="100"></canvas>
  </div>
  <div>
    <input type="hidden" name="signature" />
  </div>
  <button type="submit">Send</button>
  <form>

On the PHP side, you should then be able to decode that base64 string and save it to a file like this:

$img = $_POST['signature'];
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $img));
file_put_contents('storage/signature.png', $data);

Note for mobile touch events

If you need mobile/touch capability, simply change the events to:

  • mousemove : touchmove
  • mouseup : touchend
  • mousedown : touchstart

If you need both mobile and mouse inputs, you can duplicate the 3 addEventListener lines so all 6 events are tracked.