Ethernet POS Documentation - PHP sample of Cloud printing

Notes

This sample shows a PHP implementation of Ethernet POS Cloud connection. In this mode, print jobs are rendered and stored on the web server. Through a special page request, those print jobs are downloaded by Ethernet POS and transmitted to the printer.

This sample contains three important files:

  • print_queue.php : Implements a print queue as a PHP class. Print jobs are written in a serialized way on disk, and read as a whole unique print job.
  • client.php : Implements the client side part of this sample. This is a simple page that writes a print job in the print queue on form submission.
  • server.php : Implements the server side part of this sample. This is a page that must be polled by Ethernet POS to download print jobs. When requested, this page reads the whole print jobs queue data, and returns it to Ethernet POS.

To test this code, you must copy the 3 .php files on a web server, in the same folder. Then, in the Ethernet POS configuration tool, enable the HTTP(S) polling feature, and enter the URL corresponding to the server.php file. Finally, to test this Cloud printing feature, open a web browser, and enter the URL corresponding to the client.php file.

Print Queue Code <?php

// This file implements a printer virtual queue. It exposes an object that
// allows to either append a printing job, or retreive and flush the whole jobs
// queue. To simplify security setup for this sample, queue persistance is done
// in a temporary file.

class PrintQueue
{
    private $name;
    private $file;
    private $lock;
    private $last_error;

    public function __construct($name = "default")
    {
        $this->name = $name;
        $this->file = false;
        $this->last_error = '';
    }

    public function open()
    {
        if ($this->file !== false)
            return true;

        $path = sprintf("%s/ethpos_%s.queue",
                        sys_get_temp_dir(),
                        $this->name);

        // File must be opened read/write.
        $file = @fopen($path, 'a+');
        if ($file === false) {
            $this->fillLastError();
            return false;
        }

        // And we serialize its access through an exclusive lock.
        if (!@flock($file, LOCK_EX)) {
            $this->fillLastError();
            return false;
        }

        $this->file = $file;

        return true;
    }

    public function close()
    {
        if ($this->file !== false) {
            flock($this->file, LOCK_UN);
            fclose($this->file);
            $this->file = false;
        }
    }

    public function write($data)
    {
        if (@fwrite($this->file, $data) === false) {
            $this->fillLastError();
            return false;
        }

        return true;
    }

    public function read()
    {
        $data = '';

        if (@fseek($this->file, 0) < 0) {
            $this->fillLastError();
            return false;
        }

        for (;;) {
            // Read by chunck of 4 KB.
            $r = @fread($this->file, 4096);
            if ($r === false) {
                $this->fillLastError();
                return false;
            }

            // Stop if there is no more data to read.
            if (strlen($r) == 0)
                break;

            $data .= $r;
        }

        return $data;
    }

    public function truncate()
    {
        if (!@ftruncate($this->file, 0)) {
            $this->fillLastError();
            return false;
        }

        return true;
    }

    public function lastError()
    {
        return $this->last_error;
    }

    private function fillLastError()
    {
        $err = error_get_last();
        $err_msg = $err['message'];

        // Remove function prefix if any, to report just the error
        // message.
        $pos = strpos($err_msg, "): ");
        if ($pos !== false)
            $err_msg = substr($err_msg, $pos + 3);
    
        $this->last_error = $err_msg;
    }
}

Download print_queue.php

Client Code <?php

// This file implements a simple page that allows to add a print job to the
// print queue, in response to a click to the Print button.

include 'print_queue.php';

// Helper function
function post($key, $default = '')
{
    return isset($_POST[$key]) ? $_POST[$key] : $default;
}

// Initializations
$def_text = "This is a PHP client/server Ethernet POS\nsample.\n\n" .
            "Regards\nThe Active+ Software Team";
$text = post('text', $def_text);
$qrcode = post('qrcode') == 'yes';
$cut = post('cut', 'yes') == 'yes';
$error = '';

if (post('print') != '') {
    // Prepare data to print
    $url = "https://www.activeplus.com";
    $data = "\x1b@";

    // Align center
    $data .= "\x1ba\x01";

    // Set bold
    $data .= "\x1bE\x01";

    // Write header
    $data .= "Ethernet POS sample.\n$url\n\n";

    // Align left
    $data .= "\x1ba\x00";

    // Remove bold
    $data .= "\x1bE\x00";

    if ($text != '') {
        // Add Raw text
        $data .= trim($text) . "\n\n";
    }
    if ($qrcode) {
        // Align center
        $data .= "\x1ba\x01";

        // Set QR code size 4
        $data .= sprintf("\x1d(k\x03\x00\x31%c%c", 67, 4);

        // Set QR code data
        $len = strlen($url) + 3;
        $data .= sprintf("\x1d(k%c%c\x31%c\x30%s", $len & 0xff,
                         $len >> 8,
                         80,
                         $url);

        // Add QR code print command
        $data .= sprintf("\x1d(k\x03\x00\x31%c%c", 81, 48);
        $data .= "\n\n";
    }
    if ($cut) {
        // Add paper cut command
        $data .= "\x1dV\x41\x03";
    }

    $queue = new PrintQueue();
    if (!$queue->open() || !$queue->write($data))
        $error = $queue->lastError();
    $queue->close();
}

?>
<!doctype html>
<html>
    <head>
        <meta charset="utf-8" />
        <title>Ethernet POS sample of a PHP client/server implementation</title>
    </head>
    <body>
        <form action="<?= htmlspecialchars($_SERVER['REQUEST_URI']) ?>" method="post">
            <h3>Ethernet POS sample of PHP client/server implementation</h3>
            <p>
                This page contains the client side implementation
                of this sample. Each click on Print button will
                generate a print job according to the following
                inputs.
            </p>
            <table>
                <tr>
                    <td>Text to print:</td>
                    <td>
                        <textarea name="text" cols="43" rows="10"><?= htmlspecialchars($text) ?></textarea>
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input type="checkbox" name="qrcode" value="yes"<? if ($qrcode) echo ' checked="checked"'; ?> />
                        Print a QR code
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input type="checkbox" name="cut" value="yes"<? if ($cut) echo ' checked="checked"'; ?> />
                        Add a cut paper command
                    </td>
                </tr>
                <tr>
                    <td colspan="2">
                        <input type="submit" name="print" value="Print" />
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>

Download client.php

Server Code <?php

// This page just returns the whole contents of the print queue, or a server
// error if something wrong occured. No security mechanism is provided for this
// sample, but an authentication mechanism should be setup for a production
// system.

include 'print_queue.php';

$queue = new PrintQueue();
if (!$queue->open()) {
    header('HTTP/1.0 500 ' . $queue->lastError());
    die();
}

$data = $queue->read();
if ($data === false) {
    header('HTTP/1.0 500 ' . $queue->lastError());
    die();
}

// Ethernet POS requires application/octet-stream content type.
header('Content-Type: application/octet-stream');
header('Content-Length: ' . strlen($data));
echo $data;

// Once data has been sent, reset queue file contents.
$queue->truncate();

// And cleanup.
$queue->close();

?>

Download server.php