Link to home
Start Free TrialLog in
Avatar of RiccardoQuest
RiccardoQuest

asked on

Issues with signature

Im working on a signature for a form as at the end of the form i need to capture the signature of the users filling it out.

I have two issues which are when on a mobile device (i.e mobile or tablet) the code doesnt work to fill the box in.

The second issue is that i am unable to get the signature into the database.

I have tried to get the information into the database two ways one through direct php taking the variable #debug and attmepting to insert that into the database. The other way is the way in the documents attached through ajax post url.

In theory i would like all this done on one page if possible. Can anyone shed some light on these two areas im having issues with.

SIGN.PHP ->
<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="robots" content="noindex, nofollow">
  <meta name="googlebot" content="noindex, nofollow">

  
  

  
  
  

  

  <script type="text/javascript" src="//code.jquery.com/jquery-1.8.3.js"></script>

  

  

  <style type="text/css">
    
  </style>

  <title></title>

  
    




<script type='text/javascript'>//<![CDATA[
$(window).load(function(){
$(document).ready(function () {
    /** Set Canvas Size **/
    var canvasWidth = 400;
    var canvasHeight = 75;

    /** IE SUPPORT **/
    var canvasDiv = document.getElementById('signaturePad');
    canvas = document.createElement('canvas');
    canvas.setAttribute('width', canvasWidth);
    canvas.setAttribute('height', canvasHeight);
    canvas.setAttribute('id', 'canvas');
    canvasDiv.appendChild(canvas);
    if (typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
    }
    var context = canvas.getContext("2d");

    var clickX = new Array();
    var clickY = new Array();
    var clickDrag = new Array();
    var paint;

    /** Redraw the Canvas **/
    function redraw() {
        canvas.width = canvas.width; // Clears the canvas

        context.strokeStyle = "#000000";
        context.lineJoin = "miter";
        context.lineWidth = 2;

        for (var i = 0; i < clickX.length; i++) {
            context.beginPath();
            if (clickDrag[i] && i) {
                context.moveTo(clickX[i - 1], clickY[i - 1]);
            } else {
                context.moveTo(clickX[i] - 1, clickY[i]);
            }
            context.lineTo(clickX[i], clickY[i]);
            context.closePath();
            context.stroke();
        }
    }

    /** Save Canvas **/
    $("#saveSig").click(function saveSig() {
        //encode URI
        var sigData = encodeURIComponent(canvas.toDataURL("image/png"));
        $("#imgData").html('Thank you! Your signature was saved');
        var ajax = XMLHttpRequest();
        ajax.open("POST", 'post-sign.php');
        ajax.setRequestHeader('Content-Type', 'application/upload');
        ajax.send(sigData);
        $('#debug').html(sigData);
    });

    /** Clear Canvas **/
    $('#clearSig').click(
        function clearSig() {
            clickX = new Array();
            clickY = new Array();
            clickDrag = new Array();
            context.clearRect(0, 0, canvas.width, canvas.height);
    });

    /**Draw when moving over Canvas **/
    $('#signaturePad').mousemove(function (e) {
        if (paint) {
            addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
            redraw();
        }
    });

    /**Stop Drawing on Mouseup **/
    $('#signaturePad').mouseup(function (e) {
        paint = false;
    });

    /** Starting a Click **/
    function addClick(x, y, dragging) {
        clickX.push(x);
        clickY.push(y);
        clickDrag.push(dragging);
    }

    $('#signaturePad').mousedown(function (e) {
        var mouseX = e.pageX - this.offsetLeft;
        var mouseY = e.pageY - this.offsetTop;

        paint = true;
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
        redraw();
    });

});
});//]]> 

</script>

  
</head>

<body>
  <center>
    <fieldset style="width: 435px">
        <br/>
        <br/>
        <div id="signaturePad" style="border: 1px solid #ccc; height: 55px; width: 400px;"></div>
        <br/>
        <button id="clearSig" type="button">Clear Signature</button>&nbsp;
        <button id="saveSig" type="button">Save Signature</button>
        <div id="imgData"></div>
        <!-- removed double imgData here -->
        <br/>
        <br/>
    </fieldset>
</center>
<div id="debug"></div>
  
</body>

</html>

Open in new window


DB FILE ->
--
-- Table structure for table `pad`
--

CREATE TABLE IF NOT EXISTS `pad` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `session` varchar(255) NOT NULL,
  `image_location` varchar(255) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

Open in new window


POST-SIGN ->
   <?php
    if (isset($GLOBALS["HTTP_RAW_POST_DATA"]))
    {
    $session_id = $_SERVER['REMOTE_ADDR'];
    // Get the data
    $imageData=$GLOBALS['HTTP_RAW_POST_DATA'];

    $filteredData=substr($imageData, strpos($imageData, ",")+1);

    $unencodedData=base64_decode($filteredData);

    $imageName = "sign_" . rand(5,1000) . rand(1, 10) . rand(10000, 150000) . rand(1500, 100000000) . ".png";

    $filepath = "uploads/signature/" . $imageName;

    $fp = fopen("$filepath", 'wb' );
    fwrite( $fp, $unencodedData);
    fclose( $fp );

    //Connect to a mySQL database and store the user's information so you can link to it later
    $link = mysql_connect('localhost','USER', 'PASS') OR DIE(mysql_error);
    mysql_select_db("DB", $link);
    mysql_query("INSERT INTO pad (`session`, `image_location`) VALUES ('$session_id', '$imageName')") OR DIE(mysql_error());
    mysql_close($link);
    }
    ?>

Open in new window


Thank you :)
pad--1-.sql
sign.php
SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
You might want to check the legal requirements for a signature.  In the USA, since the DMCA (Bill Clinton's presidency, before the millennium) we have been able to use a checkbox or radio input control to indicate a legally binding agreement, and today we can do it with a keytap.  This might make the programming easier.  I know the Apple signature pads are visually appealing, but they are legally unnecessary.  This is true in the USA, YMMV elsewhere.

Here's how to understand the changes PHP has made with the MySQL extension.  The article also shows, step-by-step, how to remediate PHP scripts like yours that still rely on the unsupported extension.  There is no supported version of PHP that has not deprecated MySQL.
https://www.experts-exchange.com/articles/11177/PHP-MySQL-Deprecated-as-of-PHP-5-5-0.html

A quick-ref for the extensions' function mapping is available here:
https://iconoun.com/mysql_mysqli_pdo_function_map.php
Avatar of RiccardoQuest
RiccardoQuest

ASKER

I have implemented your code and it doesnt work for me. Also what does "$rawdata = file_get_contents("php://input");" mean? Its taking the data and?
I have implemented your code and it doesnt work for me
That is not helpful - how does it not work - do you get an error - if so what error do you get?
$rawdata = file_get_contents("php://input");

Open in new window

Reads the raw POST data.
When data is sent to the server it is sent as a string of bytes.
With a form type post those bytes would be something like
field1=value1&field2=value2

Open in new window

With such a post PHP processes the data and arranges it nicely for you inside global arrays ($_POST, $_GET etc)
You can still access the raw post using the above method.
In this case it is not a typical key/value pair that is being sent so we read the raw post directly, chop the first 22 bytes off for the content type and then base64_decode the rest.

If it is not working for you please give us more information so that we can help you resolve it.
if ($result) {
	// Success
	$filepath = "images/" . $imageName;
					
					// Delete previously uploaded image
					if (file_exists($filepath)) { unlink($filepath); }

					// Write $imgData into the image file
					$file = fopen($filepath, 'w');
					fwrite($file, $imgdata);
					fclose($file);
}

Open in new window


The code is working but i cant seem to create the actual file to be store on the imageName
Here's what I found in the Chrome console:
Uncaught TypeError: Failed to construct 'XMLHttpRequest': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

Not sure what to do with that yet...
Ray is right - I picked that up while testing your code and forgot to mention it.
...
    /** Save Canvas **/
    $("#saveSig").click(function saveSig() {
        //encode URI
        var sigData = canvas.toDataURL("image/png");
		$("#imgData").html('Thank you! Your signature was saved');
        // ADD new 
        var ajax = new XMLHttpRequest();
        ajax.open("POST", 'post-sign.php');
        ajax.setRequestHeader('Content-Type', 'application/upload');
        ajax.send(sigData);
        $('#debug').html(sigData);
    });
...

Open in new window

So that will do the upload however how do i implement the path of where to store the image? I.E images/signature
Line 4 of this post
$imageName = "sign_" . rand(5,1000) . rand(1, 10) . rand(10000, 150000) . rand(1500, 100000000) . ".png";

Open in new window

Change to
$imageName = $image_path . "sign_" . rand(5,1000) . rand(1, 10) . rand(10000, 150000) . rand(1500, 100000000) . ".png";

Open in new window

And then at the top of your code define $image_path as
$image_path = "images/signature/";

Open in new window

OK, some progress.  Let's step backward through this and I'll explain what I did and show you the code examples.

Here is the result of my scribbly signature.  User generated image
It was produced by this script
https://iconoun.com/demo/temp_riccardo_signature.php
<?php // demo/temp_riccardo_signature.php
/**
 * https://www.experts-exchange.com/questions/28977073/Issues-with-signature.html#a41848213
 */
error_reporting(E_ALL);

// THIS IS WHAT THE REQUEST DATA LOOKS LIKE
$_POST['q'] = 'data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAZAAAABLCAYAAABeMdGUAAAITUlEQVR4Xu2dvapeRRSG39yAaGGrQuwTOwshegdqYwoh2gkKmk4wQSUp7KJV7FSw0CbaWargBRjwBrwCvQNlwV4w2exzvr3n55u%2FZ4Mk5nwzs9az5lvvmd99RTwQgAAEIACBCAJXIspQBAIQgAAEICAEhE4AAQhAAAJRBBCQKGwUggAEIAABBIQ%2BAAEIQAACUQQQkChsFIIABCAAgdEE5B1JNyTZn%2FaM5h89FgIQgEAzBEZJsE9LehAIRwjYxOS7ZohjCAQgAIFBCIwgICYeDyXdlPRY0peSvpX0qqRflzjdXv59kLDhBgQgAIH6BHoXkFA8fpT0nqR%2FA6w2%2Brgj6aqkdxdhqU8dCyAAAQgMQKBnATklHh4eE5FvltGJjUpCgRkghLgAAQhAoA6BXgVkr3g4VZvSuiXprqT7dVDTKgQgAIGxCPQoICYetrZxXdLWtNVWhKzMI0mvMZU1VgfGGwhAoB6BHgXE1jTuRUxJ%2BVSW7cjybb71yNMyBCAAgc4J9CYgLgI2AnkzYj3jvyVevfndeTfDfAhAYEQCPSXScOoqdkeVC8gzEeIzYvzxCQIQgEA0gZ4E5HVJPy2HAmOnoD6T9KmkP5f1EHZkRXcdCkIAArMT6EVAbPTxzxKslNGD1fObpGuS3pD08%2BwdAP8hAAEIxBLoRUB89PG5JBtFpDyhGPXif4q%2FlIUABCBQhEAvCTT32gWL6UW6E5VCAAIzEehNQGzx3E6Vp9qNgMzUy%2FEVAhAoQiA1ERcxaqNST%2Fj%2BIzsQaGsZsQ8CEkuOchCAAAQWAj0ISLhmYWbHbuENg46A8BWAAAQgkEigBwGx69k%2FDPzMYTMCkthxluJ2OWXKSDCPFdQCAQhUIZAjGZc0PHynh7eTw2YEJD1qXA2TzpAaINA1gRzJuBQAm7r6RdLLkmz7rh0AtCeHzQhIetScYY4pxXRrqAECEDg7gRzJuJTRfvbDb9z1g4SpNnMOJC1iIb%2FUzQxpllAaAhCoSiA1GZc0Pjz7YVNZdo1JeJBwvTPrqC05DiUebXOEz%2Bc81DkCD3yAwLQEehAQs3F9kDBVPOwaE1v85S6s410%2F96HO4xZQAgIQaIJAbwLi9ra4hmFTO7ZbLOWqlRbi4X7YCM2ftW8t2NnEFwgjIDAzgZYTQSgSa8FoUUB8aie1P9WOSeiH2RK%2BPth8q21fKl%2FKQwACmQi0nAzCXT52fUn4JkF%2Fx3lLO4BSp3ZaEMX1oU3rH%2BvNDEz7ZfryUQ0EeifQg4D8Len51Ql0P4PwWJItsLeQ1HIIQI461n1yb53rkYbVY9NxPiWXco1%2B798T7IcABDYI9CAgZraJyAsr%2B30U0srLocKF%2FViue5P93s7sQrtn6slHGn9IemXVQKw%2Fe%2B3kcxCAQIcEWk4MYULemqoKXw5l70i3KS77r9bTmoCErwDeIyBbO9vYrVarN9EuBDog0IuAXGSnJckPJN1bWN%2BWZHdn1XhS10DM5pwjkPWi%2FmWx9nZ%2FkHRzgddy36gRX9qEAAQ6mprwpPb7ss5xWfBsquaOpKuZbus92lFyjD5yC8h6RHGZCPsp%2F9BvBORoL%2BDzEJiMQKtJIpy7%2F0rSRzviEi6s299tbeRcT66RQ656QjFyBluxXu%2B6elvS94xAztVtaAcCfRNoVUB8gdzovnRADGwU4tNZtnsoPAxXMlK5En%2Buek4JiAnsDUn2pz%2B2SeGLZQqLa15K9hbqhsAgBFoVkJQpIRMOv7nXLmK0pFh6NJJib9iVwnpit82GV%2BCH18D4ocAHK%2BGw9q0tv2%2FML69sYWv0IF8z3IDAmARGFBCL1HVJH0t6awnbOUYjW7uY7Dd5W9Tfm4zDOmIS%2Bda23S27%2FpL0lKTngjWjHJsAxvyW4BUEILBJYFQBcWfD0ci5tvquE7Zthf15Z%2F%2FzsiYeJn5HRMTE4xNJL0p6X9KzO%2B7lCk%2F355w%2B2%2BkuH4MABHomMLqA%2BGjEFuFvLYGypGn%2Fv3dUEBvf9QK11XOKdzgK%2BDoYQV02krF2tqalTtm9PuOBgJwixs8hAIEnCJxKaLVweTLLuZhrv6GbcFxb1kTsZUilRcT4bU0hneLq6xW%2BLnHq81s%2FP3IIEPGIIUwZCExOoHUBiV1Iviis4en1I9NDubrJHjFZx8Rs3iskR0Qj9AkByRVh6oHARARaF5AS9llC9umhu5Ludx7vHMk%2FRx2dY8R8CEDgKIESCfqoDTU%2BbyLySJJNY7V0JXwMi9TkzzviY6hTBgIQOLmoOzKicMur%2B9mjoKYKCO84H7mX4xsEChLoMWHmxBEeurN6e%2BSRKiCc%2F8jZo6gLAhMR6DFhThSeXa7mEhD6wi7cfAgCEOh5yoboPUkAAaFHQAACVQjwW2cV7FkbTRGQlLJZnaAyCECgPwIISH8xW1ucIgIpZfsnhwcQgEASAQQkCV8zhWOEgO27zYQPQyDQJwEEpM%2B4XTQKWf%2F7ZW8hfMi7P8YIPl5AoBYBBKQW%2BfztXnRNytZFjH72o8Z1Lvk9p0YIQKAKAQSkCvazNXrq7q3cd42dzTEaggAE6hNAQOrHoKQFl13ESOxLkqduCExAgCQyQZBxEQIQgEAJAghICarUCQEIQGACAgjIBEHGRQhAAAIlCCAgJahSJwQgAIEJCCAgEwQZFyEAAQiUIICAlKBKnRCAAAQmIICATBBkXIQABCBQggACUoIqdUIAAhCYgAACMkGQcRECEIBACQIISAmq1AkBCEBgAgIIyARBxkUIQAACJQggICWoUicEIACBCQggIBMEGRchAAEIlCCAgJSgSp0QgAAEJiCAgEwQZFyEAAQgUIIAAlKCKnVCAAIQmIAAAjJBkHERAhCAQAkC%2FwM8GjNbiSht9QAAAABJRU5ErkJggg%3D%3D';

// REVERSE THE URL ENCODING
$img = rawurldecode($_POST['q']);

// REMOVE HEADER data:image/png;base64,
$img = str_replace('data:image/png;base64,', NULL, $img);

// REVERSE BASE-64 ENCODING
$img = base64_decode($img);

// SHOW THE IMAGE
header('Content-type: image/png');
echo $img;

Open in new window

The way I got the information that is mocked-up in $_POST was by using a data-trap server-side script that captured the information from the front-end script.  The data trap wrote this information into the error_log so I could copy it out later, examine it, and decide what to do with it.  Here is the data trap.
<?php // demo/temp_riccardo_server.php
/**
 * https://www.experts-exchange.com/questions/28977073/Issues-with-signature.html#a41848213
 */
error_reporting(E_ALL);


// CAPTURE THE REQUEST VARIABLES, IF ANY
$req = NULL;
if (!empty($_GET))    $req .= 'GET: '    . print_r($_GET, TRUE)    . PHP_EOL . PHP_EOL;
if (!empty($_POST))   $req .= 'POST: '   . print_r($_POST, TRUE)   . PHP_EOL . PHP_EOL;
if (!empty($_FILES))  $req .= 'FILES: '  . print_r($_FILES, TRUE)  . PHP_EOL . PHP_EOL;
// if (!empty($_COOKIE)) $req .= 'COOKIE: ' . print_r($_COOKIE, TRUE) . PHP_EOL . PHP_EOL;

if (!empty($req)) error_log($req);

Open in new window

And finally, here is the client-side signature capture script, mostly copied from what was originally posted with the question.  I modified it a little bit to make it work with Chrome.  I think this $.(post) method will work cross-browser but I have not tested it.
<?php // demo/temp_riccardo.php
/**
 * https://www.experts-exchange.com/questions/28977073/Issues-with-signature.html#a41848213
 */
error_reporting(E_ALL);


// CREATE OUR WEB PAGE IN HTML5 FORMAT
$htm = <<<HTML5
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<style type="text/css">
/* STYLE SHEET HERE */
</style>

<script src="https://code.jquery.com/jquery-latest.min.js"></script>

<script>//<![CDATA[
$(document).ready(function () {
    /** Set Canvas Size **/
    var canvasWidth = 400;
    var canvasHeight = 75;

    /** IE SUPPORT **/
    var canvasDiv = document.getElementById('signaturePad');
    canvas = document.createElement('canvas');
    canvas.setAttribute('width', canvasWidth);
    canvas.setAttribute('height', canvasHeight);
    canvas.setAttribute('id', 'canvas');
    canvasDiv.appendChild(canvas);
    if (typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
    }
    var context = canvas.getContext("2d");

    var clickX = new Array();
    var clickY = new Array();
    var clickDrag = new Array();
    var paint;

    /** Redraw the Canvas **/
    function redraw() {
        canvas.width = canvas.width; // Clears the canvas

        context.strokeStyle = "#000000";
        context.lineJoin = "miter";
        context.lineWidth = 2;

        for (var i = 0; i < clickX.length; i++) {
            context.beginPath();
            if (clickDrag[i] && i) {
                context.moveTo(clickX[i - 1], clickY[i - 1]);
            } else {
                context.moveTo(clickX[i] - 1, clickY[i]);
            }
            context.lineTo(clickX[i], clickY[i]);
            context.closePath();
            context.stroke();
        }
    }

    /** Save Canvas **/
    $("#saveSig").click(function saveSig() {
        //encode URI
        var sigData = encodeURIComponent(canvas.toDataURL("image/png"));
        $("#imgData").html('Thank you! Your signature was saved');
        $.post('temp_riccardo_server.php', {q:sigData});
        $('#debug').html(sigData);
    });

    /** Clear Canvas **/
    $('#clearSig').click(function clearSig() {
            clickX = new Array();
            clickY = new Array();
            clickDrag = new Array();
            context.clearRect(0, 0, canvas.width, canvas.height);
    });

    /**Draw when moving over Canvas **/
    $('#signaturePad').mousemove(function (e) {
        if (paint) {
            addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
            redraw();
        }
    });

    /**Stop Drawing on Mouseup **/
    $('#signaturePad').mouseup(function (e) {
        paint = false;
    });

    /** Starting a Click **/
    function addClick(x, y, dragging) {
        clickX.push(x);
        clickY.push(y);
        clickDrag.push(dragging);
    }

    $('#signaturePad').mousedown(function (e) {
        var mouseX = e.pageX - this.offsetLeft;
        var mouseY = e.pageY - this.offsetTop;

        paint = true;
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
        redraw();
    });

});//]]>
</script>

<title>Signature Thing</title>
</head>

<body>
  <center>

    <fieldset style="width: 435px">
        <br/>
        <br/>
        <div id="signaturePad" style="border: 1px solid #ccc; height: 55px; width: 400px;"></div>
        <br/>
        <button id="clearSig" type="button">Clear Signature</button>&nbsp;
        <button id="saveSig" type="button">Save Signature</button>
        <div id="imgData"></div>
        <br/>
        <br/>
    </fieldset>

</center>
<div id="debug"></div>

</body>
</html>
HTML5;


// RENDER THE WEB PAGE
echo $htm;

Open in new window

How to get the image so you can store it?  Go back to the mockup script shown at the top of this comment.  The PNG image is located in $img.  The decoded one you want to keep is on line 17.  If you want to write this into a file, just use file_put_contents().  If you want to store this in a database, you must escape the variable before you use it in a query string.

Your server-side action script would need to process the POST request in much the same way that the mockup processed the data I captured and wrote into the error_log.  Obviously the error_log step is not necessary for your work -- just process the $_POST data when your server-side script receives it.

This is kind of a "sidebar" note, but you might want to be thoughtful about variable and file names.  Something named "session" is easy to confuse with the session, which is a term of art in PHP.  If it's really supposed to contain the remote IP address, a better name might be helpful.  Likewise, using a random number for the file name might be creating something that is unnecessarily confusing.  Since it's extremely unlikely that you will get two signatures from the same remote address at the same second, you might consider using a file name that is made up from the remote address and the timestamp.  This would let you sort or select the files relatively easily, in case you need to refer back to the signature image associated with a particular transaction.  Just a thought...

HTH, and please post back if I've made this confusing!  ~Ray
Ray ive tried to understand what youve coded and wrote however it is quite confusing.

Ive appilied the post part and the second part together see below:

<?php // demo/temp_riccardo.php
/**
 * https://www.experts-exchange.com/questions/28977073/Issues-with-signature.html#a41848213
 */
error_reporting(E_ALL);

// CAPTURE THE REQUEST VARIABLES, IF ANY
$req = NULL;
if (!empty($_GET))    $req .= 'GET: '    . print_r($_GET, TRUE)    . PHP_EOL . PHP_EOL;
if (!empty($_POST))   $req .= 'POST: '   . print_r($_POST, TRUE)   . PHP_EOL . PHP_EOL;
if (!empty($_FILES))  $req .= 'FILES: '  . print_r($_FILES, TRUE)  . PHP_EOL . PHP_EOL;
// if (!empty($_COOKIE)) $req .= 'COOKIE: ' . print_r($_COOKIE, TRUE) . PHP_EOL . PHP_EOL;

if (!empty($req)) error_log($req);

?>

$htm = <<<HTML5

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://code.jquery.com/jquery-latest.min.js"></script>

<script>//<![CDATA[
$(document).ready(function () {
    /** Set Canvas Size **/
    var canvasWidth = 400;
    var canvasHeight = 75;

    /** IE SUPPORT **/
    var canvasDiv = document.getElementById('signaturePad');
    canvas = document.createElement('canvas');
    canvas.setAttribute('width', canvasWidth);
    canvas.setAttribute('height', canvasHeight);
    canvas.setAttribute('id', 'canvas');
    canvasDiv.appendChild(canvas);
    if (typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
    }
    var context = canvas.getContext("2d");

    var clickX = new Array();
    var clickY = new Array();
    var clickDrag = new Array();
    var paint;

    /** Redraw the Canvas **/
    function redraw() {
        canvas.width = canvas.width; // Clears the canvas

        context.strokeStyle = "#000000";
        context.lineJoin = "miter";
        context.lineWidth = 2;

        for (var i = 0; i < clickX.length; i++) {
            context.beginPath();
            if (clickDrag[i] && i) {
                context.moveTo(clickX[i - 1], clickY[i - 1]);
            } else {
                context.moveTo(clickX[i] - 1, clickY[i]);
            }
            context.lineTo(clickX[i], clickY[i]);
            context.closePath();
            context.stroke();
        }
    }

    /** Save Canvas **/
    $("#saveSig").click(function saveSig() {
        //encode URI
        var sigData = encodeURIComponent(canvas.toDataURL("image/png"));
        $("#imgData").html('Thank you! Your signature was saved');
        $.post('temp_riccardo_server.php', {q:sigData});
        $('#debug').html(sigData);
    });

    /** Clear Canvas **/
    $('#clearSig').click(function clearSig() {
            clickX = new Array();
            clickY = new Array();
            clickDrag = new Array();
            context.clearRect(0, 0, canvas.width, canvas.height);
    });

    /**Draw when moving over Canvas **/
    $('#signaturePad').mousemove(function (e) {
        if (paint) {
            addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
            redraw();
        }
    });

    /**Stop Drawing on Mouseup **/
    $('#signaturePad').mouseup(function (e) {
        paint = false;
    });

    /** Starting a Click **/
    function addClick(x, y, dragging) {
        clickX.push(x);
        clickY.push(y);
        clickDrag.push(dragging);
    }

    $('#signaturePad').mousedown(function (e) {
        var mouseX = e.pageX - this.offsetLeft;
        var mouseY = e.pageY - this.offsetTop;

        paint = true;
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
        redraw();
    });

});//]]>
</script>

<title>Signature Thing</title>
</head>

<body>
  <center>

    <fieldset style="width: 435px">
        <br/>
        <br/>
        <div id="signaturePad" style="border: 1px solid #ccc; height: 55px; width: 400px;"></div>
        <br/>
        <button id="clearSig" type="button">Clear Signature</button>&nbsp;
        <button id="saveSig" type="button">Save Signature</button>
        <div id="imgData"></div>
        <br/>
        <br/>
    </fieldset>

</center>
<div id="debug"></div>

</body>
</html>
HTML5;


// RENDER THE WEB PAGE
echo $htm;

Open in new window


But I'm still not 100% on this.

I see you are trying to make it cross browser compatible and mobile compatible. Great!

I still need to sort this and I see you suggest referring back to the code before hand however im unsure how to implement that into this new part.

Storing the image in the db is key with a valid path so the image can be viewed on another page at a later date.
Right now ive taken Mr Hansens additional code it stores the path correctly however the size of the file is 0 bytes showing no data is actually stored:

User generated image
There's a concept we use in debugging complex applications that is called the SSCCE.  It guides us to deconstructing the larger problem into smaller problems so that each part of the problem can become its own "thought island" with known inputs and expected outputs.  When we try to look at the big picture, it's easy to be confused.  Conversely when we look at the parts in isolation we can often understand each of them, and eventually understand how they come together to make the big picture.

In this case, any solution we demonstrate will write information onto our server file system and our database.  Personally, that's too much exposure, and I don't want to leave such a code set on my server, so I will just try to explain a little bit of the theory.  Before you read on, please be sure you have a 100% clear understanding of HTTP client/server protocols.

On the client side, you have HTML, CSS, JavaScript (jQuery).  These technologies manipulate and respond to the human client's inputs.  In the instant case, they collect a signature object in a canvas, and send it to the server via a POST-method request.  The signature object is a string variable, representing a PNG image that has been encoded for safe transport across the internet.

On the server side, you have PHP and MySQL.  These technologies manipulate and respond to HTTP requests, such as the POST-method request that sends the encoded PNG image.  In this PHP script you need to do a few things: Decode the string variable into a PNG image, choose a name for the image file, write the image file into the server file system, write the URL into the database.  You can find good examples for each of these parts, but it's up to you, as the developer, to integrate the parts into a server-side application that responds to the AJAX request.

So my advice is this:  Deconstruct the parts until you have "bite-sized" pieces and work each of those pieces separately.  The decoding process is shown here.  you already have a scheme for choosing a name and location for the image file.  You write an image file to the server file system with file_put_contents().  There are many links that teach the basics of MySQL (here is one) and your next step would be to update the database.

Hope that helps.  If time permits I may write an E-E article on the subject.  Or you may get all the parts together and beat me to it!  Best of luck and best regards, ~Ray
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It works perfect on yours however now that ive done it on my web server it still doesnt have any data in the file. 0bytes

User generated image
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Ive got it working now thank you guys. I do have a further question in relation to this which is to make it work on mobiles as nothing can be entered when on a mobile device. Ill post the link to that question after this comment. Thank you again for your help with this issue