使用PHP向POS打印机打印

24
我们正在寻找一种方法将打印作业发送到连接在 Apache 运行的 POS 打印机。由于应用程序的设计和部署原因,打印作业应该从服务器端完成(它应该检测订单并将其发送到不同的打印机和不同的打印格式...账单,厨房订单等等)。出于这个原因和其他原因(例如从 iPad 访问应用程序),我们排除了像 QZ-Print applet 这样的选项,需要直接从服务器端打印。
我们进行了大量搜索,并发现有一个名为 php-printer 的扩展,但似乎已经过时,而且只能在 Windows 下运行。
我们遵循了这段代码: (http://mocopat.wordpress.com/2012/01/18/php-direct-printing-printer-dot-matrix-lx-300/)
$tmpdir = sys_get_temp_dir();   # ambil direktori temporary untuk simpan file.
$file =  tempnam($tmpdir, 'ctk');  # nama file temporary yang akan dicetak
$handle = fopen($file, 'w');
$condensed = Chr(27) . Chr(33) . Chr(4);
$bold1 = Chr(27) . Chr(69);
$bold0 = Chr(27) . Chr(70);
$initialized = chr(27).chr(64);
$condensed1 = chr(15);
$condensed0 = chr(18);
$corte = Chr(27) . Chr(109);
$Data  = $initialized;
$Data .= $condensed1;
$Data .= "==========================\n";
$Data .= "|     ".$bold1."OFIDZ MAJEZTY".$bold0."      |\n";
$Data .= "==========================\n";
$Data .= "Ofidz Majezty is here\n";
$Data .= "We Love PHP Indonesia\n";
$Data .= "We Love PHP Indonesia\n";
$Data .= "We Love PHP Indonesia\n";
$Data .= "We Love PHP Indonesia\n";
$Data .= "We Love PHP Indonesia\n";
$Data .= "--------------------------\n";
$Data .= $corte;
fwrite($handle, $Data);
fclose($handle);
copy($file, "//localhost/KoTickets");  # Lakukan cetak
unlink($file);

它可以工作,但是这只发送纯文本,我们需要发送图像(logo),并格式化更可爱的账单。我们尝试创建PDF并以相同的方式“发送”到打印机,但只会打印空白。

我找到了一个网络打印机库(在Github上的escpos-php),但我们也需要使用USB打印机,以避免我们的客户更改硬件。

有什么想法如何实现这一点吗?

提前致谢。

1个回答

63

Escpos-php的作者在此。

如果您的打印机支持ESC/POS(大多数热敏小票打印机似乎使用其某些子集),那么我认为该驱动程序可以适应您的用例:USB或网络打印、公司标志、一些格式设置。其中一些是最近添加的。

USB打印

Escpos-php将打印内容输出到文件指针。在Linux上,您可以使用usblp驱动程序将USB打印机设置为文件,并使用fopen()打开它(参考USB小票示例有关在Linux上安装USB打印机的博客文章)。

因此,在USB打印机上打印“Hello World”与在网络打印机上打印略有不同:

<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\Printer;
$connector = new FilePrintConnector("/dev/usb/lp0");
$printer = new Printer($connector);

$printer -> text("Hello World!\n");
$printer -> cut();

$printer -> close();

或者,更像你目前已经成功使用的代码,你可以写入临时文件并将其复制:

<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\Printer;

/* Open file */
$tmpdir = sys_get_temp_dir();
$file =  tempnam($tmpdir, 'ctk');

/* Do some printing */
$connector = new FilePrintConnector($file);
$printer = new Printer($connector);
$printer -> text("Hello World!\n");
$printer -> cut();

$printer -> close();

/* Copy it over to the printer */
copy($file, "//localhost/KoTickets");
unlink($file);
在您的POS系统中,需要一个函数来根据客户配置和首选目标返回文件指针。收据打印机反应非常迅速,但如果有几个iPad在下订单,您应该使用文件锁(flock())将每个打印机的操作封装起来,以避免并发相关问题。
此外,请注意Windows上的USB支持未经测试。
Logo和格式
一旦确定了与打印机通信的方式,就可以使用完整的格式和图像命令。
可以像这样从PNG文件打印徽标:
use Mike42\Escpos\EscposImage;
$logo = EscposImage::load("foo.png");
$printer -> graphics($logo);

对于格式设置,README.md和下面的示例应该会帮助您入门。对于大多数收据,您只需要:

  • selectPrintMode()更改字体大小。
  • setEmphasis()切换粗体。
  • setJustification()左对齐或居中一些文本或图像。
  • 每张收据后使用cut()

我还建议您在目前使用绘制此类框的示例时:

=========
|       |
=========

您可以利用IBM Code page 437中设计用于绘制多个打印机支持的框架字符- 只需在输出中包含字符0xB3至0xDA。它们不是完美的,但看起来要少得多“文本”。

$box = "\xda".str_repeat("\xc4", 10)."\xbf\n";
$box .= "\xb3".str_repeat(" ", 10)."\xb3\n";
$box .= "\xc0".str_repeat("\xc4", 10)."\xd9\n";
$printer -> textRaw($box);

完整示例

下面的示例现在也已经包含在驱动程序中。我认为它在格式上看起来像一个相当典型的商店收据,并且可以轻松地适应您的厨房场景。

扫描输出:

包括徽标的示例格式化收据

生成它的PHP源代码:

<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42\Escpos\Printer;
use Mike42\Escpos\EscposImage;
use Mike42\Escpos\PrintConnectors\FilePrintConnector;

/* Open the printer; this will change depending on how it is connected */
$connector = new FilePrintConnector("/dev/usb/lp0");
$printer = new Printer($connector);

/* Information for the receipt */
$items = array(
    new item("Example item #1", "4.00"),
    new item("Another thing", "3.50"),
    new item("Something else", "1.00"),
    new item("A final item", "4.45"),
);
$subtotal = new item('Subtotal', '12.95');
$tax = new item('A local tax', '1.30');
$total = new item('Total', '14.25', true);
/* Date is kept the same for testing */
// $date = date('l jS \of F Y h:i:s A');
$date = "Monday 6th of April 2015 02:56:25 PM";

/* Start the printer */
$logo = EscposImage::load("resources/escpos-php.png", false);
$printer = new Printer($connector);

/* Print top logo */
$printer -> setJustification(Printer::JUSTIFY_CENTER);
$printer -> graphics($logo);

/* Name of shop */
$printer -> selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
$printer -> text("ExampleMart Ltd.\n");
$printer -> selectPrintMode();
$printer -> text("Shop No. 42.\n");
$printer -> feed();

/* Title of receipt */
$printer -> setEmphasis(true);
$printer -> text("SALES INVOICE\n");
$printer -> setEmphasis(false);

/* Items */
$printer -> setJustification(Printer::JUSTIFY_LEFT);
$printer -> setEmphasis(true);
$printer -> text(new item('', '$'));
$printer -> setEmphasis(false);
foreach ($items as $item) {
    $printer -> text($item);
}
$printer -> setEmphasis(true);
$printer -> text($subtotal);
$printer -> setEmphasis(false);
$printer -> feed();

/* Tax and total */
$printer -> text($tax);
$printer -> selectPrintMode(Printer::MODE_DOUBLE_WIDTH);
$printer -> text($total);
$printer -> selectPrintMode();

/* Footer */
$printer -> feed(2);
$printer -> setJustification(Printer::JUSTIFY_CENTER);
$printer -> text("Thank you for shopping at ExampleMart\n");
$printer -> text("For trading hours, please visit example.com\n");
$printer -> feed(2);
$printer -> text($date . "\n");

/* Cut the receipt and open the cash drawer */
$printer -> cut();
$printer -> pulse();

$printer -> close();

/* A wrapper to do organise item names & prices into columns */
class item
{
    private $name;
    private $price;
    private $dollarSign;

    public function __construct($name = '', $price = '', $dollarSign = false)
    {
        $this -> name = $name;
        $this -> price = $price;
        $this -> dollarSign = $dollarSign;
    }

    public function __toString()
    {
        $rightCols = 10;
        $leftCols = 38;
        if ($this -> dollarSign) {
            $leftCols = $leftCols / 2 - $rightCols / 2;
        }
        $left = str_pad($this -> name, $leftCols) ;

        $sign = ($this -> dollarSign ? '$ ' : '');
        $right = str_pad($sign . $this -> price, $rightCols, ' ', STR_PAD_LEFT);
        return "$left$right\n";
    }
}

1
非常抱歉回复晚了。我以为我已经回复你了。是的,我已经使用了你的库,而且运行得非常好。只是有一些小问题,但我会在 GitHub 页面上发帖讨论。谢谢。 - Giu
2
如果从网络托管的应用程序中打印,则无法正常工作。 - talha2k
对我来说,它打印了垃圾字符而不是标志。我该怎么办? - Devender Gupta
有人可以指导如何使用蓝牙热敏打印机进行打印吗? - Ali Ahmad Pasa
如何支持非英语语言,我需要用于阿拉伯语脚本,但仍然显示反转字符。 - Salem
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接