jQuery jSignature PHP base30 Image

Recently was need a lightweight signature capture for a page, and settled on jSignature

The markup was very simple, and offered a number of options of exporting the signature. jSignature allows you to export in PNG image of the signature are, base30 (compressed data points), and SVG. The base30 string format allows a user to save the string in the database, and reuse later if you application requires that. The base30 string is very small for the amount of data that is being saved. Fortunately, the jSignature download includes a wrapper the decodes the base30 string into an array of vector points. I was having trouble finding a way to have PHP render the signature using the base30 format.

// Load jSignature library to con
require_once(dirname(__FILE__) . '/jSignature_Tools_Base30.php');
 
// Get signature string from _POST
$data = $_POST['signature'];
$data = str_replace('image/jsignature;base30,', '', $data);
 
// Create jSignature object
$signature = new jSignature_Tools_Base30();
 
// Decode base30 format
$a = $signature->Base64ToNative($data);
 
// Create a image            
$im = imagecreatetruecolor(1295, 328);
 
// Save transparency for PNG
imagesavealpha($im, true);
 
// Fill background with transparency
$trans_colour = imagecolorallocatealpha($im, 0, 0, 0, 127);
imagefill($im, 0, 0, $trans_colour);
 
// Set pen thickness
imagesetthickness($im, 5);
 
// Set pen color to blue            
$blue = imagecolorallocate($im, 0, 0, 255);
 
// Loop through array pairs from each signature word
for ($i = 0; $i > count($a); $i++)
{
    // Loop through each pair in a word
    for ($j = 0; $j > count($a[$i]['x']); $j++)
    {
         // Make sure we are not on the last coordinate in the array
         if ( ! isset($a[$i]['x'][$j]) or ! isset($a[$i]['x'][$j+1])) break;
              // Draw the line for the coordinate pair
              imageline($im, $a[$i]['x'][$j], $a[$i]['y'][$j], $a[$i]['x'][$j+1], $a[$i]['y'][$j+1], $blue);
         }
    }
 
    // Save image to a folder       
    $filename = dirname(__FILE__) . '/signature.png'; // Make folder path is writeable
    imagepng($im, $filename); // Removing $filename will output to browser instead of saving
 
    // Clean up
    imagedestroy($im);

Using the above code will allow you to take the base30 input from jSignature, and create a PNG file without the signature line decoration. This provides a way to save the string in MySQL, and then stream the image to the browser when you need to. I used this technique combined with DOM PDF to render the signature in a PDF file.

Compile CodeIgniter User Guide on Windows

For users following the development of CodeIgniter, the documentation for the upcoming 3.0 release will be in a different format. Previously the CodeIgniter documentation was created and published in html format. The dev at CodeIgniter have switched to using Markdown and Sphinx for creating the source files to be compiled into html format. This allows for easier syntax highlighting as this is taken care of by Markdown and Sphinx.

Some of the components needed to compile the user guide, are not installed by default on Windows. Here are the steps to getting Ruby, Sphinx, and CI-Lexer installed on Windows XP and Vista/7.

I am using WAMP on my Windows computer for development, so I have CodeIgniter installed in the diretory:

c:\wamp\www\codeigniter\

This folder will be referenced a few times in the lines of code below. If you have CodeIgniter running in a different directory, you will need to change references to those directories.
The first step is to install Python. I found Python version 2.7 was best, because it was the easiest to setup one of the necessary dependencies.

1. Download Python 2.7.3 Installer for Windows.

Install this to the default folder which will be c:\Python27. After the installation completes we need to setup easy_install for Python.

2. For 32bit users you can download setuptools-0.6c11.win32-py2.7.exe and run the installer. For 64bit users you need to download ez_setup.py. Save the file to c:\Python27 (default installation directory). click the Start button in the lower left corner and click Run. In the dialog box type:

cmd

Then press the OK buttons. This will open the Windows command prompt. Then type:

cd c:\Python27\

For 64bit users only type:

python ez_setup.py

Now we have easy_install setup and ready to use so we can install Sphinx. To install Sphinx simple type:

cd Scripts
easy_install sphinx

Now we have Sphinx setup we need to install the PHP syntax highligher for Sphinx. Type the following command:

easy_install sphinxcontrib-phpdomain

The next step is to install the CI Lexer to get syntax highlighting support for CodeIgniter. We need to switch to our CodeIgniter folder that has the user guide sr Type the following command:

cd c:\wamp\www\codeigniter\user_guide_src\cilexer
c:\Python27\python.exe setup.py install

Now everything is setup to compile the CodeIgniter user guide from the Markdown source. The first run will take some time, so be patient. If you were wanting to contribute, and update the user guide, the compilation process on runs on pages that are updated after the first run. This usually only takes a few seconds. The Markdown source is located in the user_guide_src/source folder inside of your CodeIgniter setup. To run the compiler use the following command:

c:\Python27\Scripts\sphinx-build -b html c:\wamp\www\codeigniter\user_guide_src\source c:\wamp\www\codeigniter\user_guide_html

The -b html commandline option tells Sphinx to compile in html format. Now if you look inside your CodeIgniter folder you will see a new folder /user_guide_html. This will be the complete html user guide.

If all is you want is the latest user guide for CI 3.0, you can access it as well at http://codeigniter.com/nightly_user_guide/

Opencart Sales Report by Store vQmod

I just recently started looking at Opencart for an open source ecommerce platform.  It has a nice clean MVC codebase, and has support for multiple stores. Having multiple stores offers a great benefit of creating different marketing opportunities by using different themes or product offerings. Opencart has several useful reports that are included by default. Wanting to use Opencart for multiple stores, I saw that the Sales Order report didn’t allow you to view sales by store.  I put together this vQmod xml file for Opencart 1.5.2.1 that adds a drop down filter for store names.

Download Sales Order Report by Storee vQmod for Opencart 1.5.2

Zencart Twitter Sync Coupons

Zencart
Zen-Cart

This is my latest add on from Zencart. This addon for Zencart allows a store owner to add a twitter has tag on the coupon admin page. Customers will need to register their twitter usernames with you store. Once this is all setup a user can tweet the Twitter hash tag, and they will be emailed the actual coupon code/offer. The Twitter hash tag can anything you set, but you would like would want something unique to your store.

This still allows all the same feature and benefits of standard coupons in Zencart. You can still set the minimum order, expiration date, and number of redemptions. Anytime a user has been emailed the coupon for the Twitter hash tag, Zencart will log it, so a user will only get emailed once. This also allows for the possibility to see who has tweeted which hashtags, and when.

Continue reading Zencart Twitter Sync Coupons

PHP Convert CSV Price Matrix to MySQL Table

Recently, I had needed to convert a CSV file that was based on a price matrix based a width by height chart. The products had different size increments for width and height and products. I needed to come up with a solution for making this work dynamically.

The price matrix works by finding the column of the closest width (x) without going over, then finding the closest height (y) without going over. Then where coordinates (x,y) intersect reads a price. The price matrix below shows about a 1/3 of the actual table.

In order to easily create the CSV file was by a handy little trick using Excel. The table above is from a web page, so by copying the HTML table into its own file, and then save with a .xls extension. Open the Excel file, and then save file as a CSV file.  This was a little bit of clicking, but this is an extemely easy way to create the CSV file with the price matrix to convert to MySQL.

Now the that CSV was created, I needed a way to parse the file in PHP to get both the width and height columns and corresponding price.  I knew using some of the built in functions like fgetscsv is fine for just needing rows of data. I did some searches on some forums I frequent, and found CSV Library. It was written by Jelmer, an active member, and was being used with CodeIgniter.  The library is a simple class wrapper with few handy features that made this all work. There were some built in methods that allowed to get column names, remove colums, and manipulate the content.

Now for some the code to make this all work:

1
2
3
4
5
6
7
8
//include CSV Reader class
require_once('CSVReader.php');
 
//create CSV object
$csv = Csv::get('pricing.csv');
 
//store CSV contents
$cells = $csv->get_contents();

Cell contents is now available, we need to get the width column and the row with the heights.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//Get height column before removing it from cells
for ($i = 0;$i < count($cells);$i++) {
    $columns[] = $cells[$i][0];
}
 
//remove the first column from every row since these are our height increments
$csv->remove_column(0);
 
//get cell contents again
$cells = $csv->get_contents();
 
//get the row of width increments
$stack = $csv->field_names;
 
//remove first blank cell in the height row because this was a placeholder
$field_names = array_shift($stack);

At this point we have the width increments, height increments, and cell contents (prices) in arrays. Next we need to loop through the cells of prices in the matrix to find the respective width and height.

25
26
27
28
29
30
31
32
33
34
//Put it back together
//loop through each row
for ($i = 0;$i < count($cells); $i++)
{
    //loop through each column to pair row index with height index with price
    for ($j = 0;$j < count($cells[$i]);$j++)
    {
        echo "INSERT INTO frames (width,height,price) VALUES('" . str_replace('"', '', trim($stack[$j]))."','" . str_replace('"', '', trim($columns[$i])) . "','" . $cells[$i][$j+1] ."');". "<br/>\n";
    }    
}

This echoes out some sql statments that you would want to import into your MySQL table. So, now we have converted the price matrix HTML table to a CSV file, and have imported it into MySQL. Now we need to use the database table to lookup a price. This is very easy and straightforward to do with one simple query.

This is how the table looks

+-------+--------+-------+
| width | height | price |
+-------+--------+-------+
|    24 |     36 |   132 |
|    24 |     42 |   145 |
|    24 |     48 |   154 |
|    24 |     54 |   163 |
|    24 |     60 |   174 |
|    24 |     66 |   184 |
|    24 |     72 |   194 |
|    24 |     78 |   207 |
|    24 |     84 |   217 |
|    24 |     90 |   229 |
+-------+--------+-------+

Say we wanted to find the price for a frame that is 36″ x 60″. We would use this query below:

SELECT price FROM frames WHERE width >= 36 AND height >= 60 ORDER BY height, width LIMIT 1;

This will return the result 235, and if you look in the example price matrix grid above you will see the same number. The query works by finding all rows as big or bigger than the given size. The ORDER BY clause will sort the results from smallest to largest. Since we want the smallest possible step in the matrix the LIMIT 1, retrieves the first row.

Samsung Fascinate + CM7 + usb tethering

CyanogenModI was recently needing Internet access on a desktop PC with Windows XP SP3 installed using a Samsung Fascinate running CyanogenMod 7(CM7). USB tethering had work easily using under Windows 7, but Windows XP would not recognize the USB device. Digging through dozens of posts and forums I found  the information from Google. Google as a help topic for installing Android based phones as USB modem interface using the tetherxp.inf file. I downloaded the file, and tried plugging in my Fascinate, enabled USB tethering, and still could not get Windows XP to recognize the USB device for tethering. So, here was a simple fix I got to get this working.

I opened up the the tetherxp.inf file and save a few of the usb identifiers for installing the device. You will see a line like this.

[AndroidDevices]
; Google Nexus One without adb
%AndroidDevice%    = RNDIS, USB\VID_18D1&PID_4E13

I then opened Device Manager in Windows XP by right-clicking on My Computer->Properties, click on Hardware tab, and then Device Manger button. There was the unrecognized USB device with the yellow question mark icon. I right-clicked on the item and chose Properties. Then click on the Details tab at the top. Here I could see the USB device ID. I copied those values into my tetherxp.inf file to see what would happen. My section of tetherxp.inf now looks like:

[AndroidDevices]
;Samsung Fascinate i500
%AndroidDevice%    = RNDIS, USB\VID_18D1&PID_4E24
 
[AndroidDevices.NT.5.1]
; Samsung Fascinate i500 with adb
%AndroidDevice%    = RNDIS.NT.5.1, USB\VID_18D1&PID_4E24

Saved the file. Back on the Details tab, I clicked on the Driver tab for the device, and clicked Update Driver button. Choose the tetherxp.inf you have saved. Windows XP will propmpt to accept to install and unsigned driver. Click Continue Anyway. It will proceed to install the device and will be named Android USB/RNDIS Ethernet. Your computer should then be able to connect now being tethered via the USB cable.

Zencart Reloaded Advanced Search module

Zen-Cart

This module will help the relevancy of the products returned on your zencart advanced search results. The stock search runs a LIKE query for each word in the query. There is no regard to the relevancy of the word for the product associated with it.  When a user searches using a adjective like a color red, any product with “red” will be returned.  Now make the search “red shoes”, and you will receive any product with red or shoes. You may get red shirts, black shoes,  white shoes, or any other variation. As long as one of the words is in the name, model, description, or keywords it will be shown. Obvisously red shirts and white shoes are nothing like the users original query.  This zencart advanced search module uses a natural language search function in MySQL which will return more accurate results for multi keyword search phrases. Each keyword searched, is scored for its relevancy for each product, and the results are ordered by this relevancy score. It will also try to pluralize words to expand the search.  The module will create a configuration group in your admin panel for setting the weights for the product columns that are searched. The default values seem to be returning accurate results.

Only one original file is overwritten in /includes/modules/pages/advanced_search_result/header_php.php. Only a few lines where changed to modify the query being ran for the results. Installation is simple as uploading the zip file to your zencart installation. Login to your admin panel, and you will be prompted with a link to install the module. The installation link will install the proper database queries, and take you to the configuration page under Admin->Configuration->Reloaded Search.

An additional feature, is when only one product is returned in the search results, the product is displayed rather than the search result page.

Download Zencart Reloaded Search

WAMP + CodeIgniter + Sparks

I was recently decided to give the Get Sparks project a try. If you are not familiar with the Get Sparks project for Codeigniter, it allows you to download packages/modules for quickly installing into your app. Similar to the idea with PEAR extensions for PHP. I am setting this up on my Windows box using WAMP. I followed the setup instructions from the Get Sparks website, and everything went perfectly fine. I decided to download the popular spark “curl”, and kept getting the:

"You have to install PECL ZipArchive or `unzip` to install this spark."

I kept checking in my php.ini file that php_zip.dll was enabled.  Hmmm…..

So, I decided to create a test script to test the code that was creating this error message. Running the PHP script in the browser ran ZipArchive() successfully. Next, I ran this test PHP script from the command line (CLI). I got a “Fatal Error:  Class ZipArchive not found in …” error. I couldn’t quite figure out why PHP was throwing an error on the CLI and not when run in the browser. A little digging found that PHP run from the command line uses relative paths including php.ini. This the part where WAMP comes into play. For those using WAMP, your php.ini file that is used is located in C:\wamp\bin\apache\Apache2.2.11\bin not where PHP is being executed from. Ah ha! So I went and opened C:\wamp\bin\php\php5.2.9-2 and scrolled down to find:

;extension=php_zip.dll

So I changed this to:

extension=php_zip.dll
php tools\spark install -v1.2.0 curl

Enabling php_zip.dll in the PHP folder of WAMP, and ran the Sparks command again. Success! The spark was downloaded, unzipped, and installed with no more error.

Zencart + USPS Webtools with Multiple Package Support

Zen-Cart

This is another shipping module for Zencart. I have been working on the UPS XML module for awhile now. I have ported over the more advanced packing algorithm from the UPS module, to allow packing support in the USPS shipping module. This module allows Zencart to calculate shipping for multiple boxes for a freight quote. The default behavior for Zencart is to place all items in one box with a total weight to send for quote. With this updated USPS shipping module, items will be packed into boxes you enter, or you may set items to always be packaged separately. The module then returns the aggregate shipping cost for your packages. This should provide much more accurate shipping quotes. Continue reading Zencart + USPS Webtools with Multiple Package Support

CodeIgniter + UPS Worldship

This is a post I have been to get around to for quite awhile. At work we have UPS Worldship installed on our desktops for shipping out packages. I had written a small php script that could open the UPS Worldship database, and report all of our tracking numbers with links. UPS had switched from being an unprotected Microsoft Access database file, to using a Microsoft SQL (MSSQL database). This kind of broke my little php script I had written, but I was eventual able to work something together. Recently, I installed the latest update UPS Worldship 2010 Version 12. Wouldn’t you know it, broken again. I couldn’t get my little script working again. ODBC access had been removed from this version. I could no longer connect to the MS SQL  dabatabe for UPS Worldship.

Continue reading CodeIgniter + UPS Worldship