Wednesday, March 18, 2015

Printing on receipt printer using PHP

Printing in PHP is actually not a right solution. In windows PHP, it does have a dll to do printing. On Mac, and others, you don't have such luck. PHP is server side script which could be anywhere in the world. Why do you need to send print commands at the server? Actually it is usually used in business where the client sent a print copy to the company like for example placing an order. However, the use is very limited. Most of the time the company employee will print using local browser to the local printer.

PHP printing does have its use if it is used within a close vicinity of the user like for example a retail shop. It usually employs one printer for all the requests. The printouts are usually receipts printed in narrow stripes of paper. That's why they are also called "receipt printer". This is especially useful in Point of Sale (POS) system. It is easier to write a web based POS program than a custom application.

Now, it defeats the purpose of having a web based program when you need to install print drivers on the user's computer just to do printing. Why not send print commands directly to the printer? Yes. it is actually done in this way.

There exists a series of printers that does not require drivers. They accept text as input. The early printers usually coded the text using ASCII "ESC" to format the printout. Thus it is usual to refer to this kind of printing as ESC POS because both are closely associated with each other.  Epson is the first one that patented the codes.

With the advance of technology, using a tablet or iPad to do mobile POS is becoming a trend. Device like iPad generally do not have print drivers. It is therefore well suited to run POS systems. The printers that works with mobile devices are usually bluetooth,  WIFI or network printers.

The PHP program to do printing is quite simple. In a few lines of code the printing can be done.

The program starts with

$fs = fsockopen(192.168.0.1.111, 9100);

You can see that the address is actually an Local IP address. 9100 is the normal port used.

The printing starts with an escape code ESC @. This is a command to initiate the printer.

$bytes = fwrite($fs, "\x1B@");

The next series of "fwrite" usually contains a series of ESC codes followed by text to format the text according to the coding commands. There are simply too many such coding commands to be described here.

The last "fwrite"  will be the ESC i - a command to cut paper. Some printers use GS V n to do paper cutting.

It is well known that fwrite don't always send all the data when used on "streams". The term normally refer to sending a series of data (streaming) to remote connected devices. As fwrite does return a value representing the number of bytes sent, it is usually used within a loop where a total byte count is kept and the fwrite is continuous send with the remainder text as value using substr($string, total_byte_sent) as value. You can read about "substr" command in PHP documentation.

After sending all the data, the last step is of course to close the stream

fclose($fs);

It is as simple as that. Actually it took me a week just to write this code as it is the first time I tried printing to streams in PHP.

In real life, the text are usually submitted form data or database so you normally have to use $_POST["var"] or SQL to get the text and then add the ESC codes to format it.

Below is a sample code.

function fwrite_stream($fp, $string) {
    for ($written = 0; $written < strlen($string); $written += $fwrite) {
        $fwrite = fwrite($fp, substr($string, $written));
        if ($fwrite === false) {
            return $written;
        }
    }
    return $written;
}
$fp = fsockopen("192.168.1.3",9100);
if (!$fp){
    die("Cannot open sock");
}
$mytext="Hello this is a test print 13 ";
$string="\x1B@".$mytext."\x1Bd\x07\x1Bi";
$bytes=fwrite_stream($fp, $string);
fclose($fp);
printf('wrote %d bytes',$bytes);