从 PHP 打印到 POS 打印机
我们希望打印到连接 apache 运行的 POS 打印机.由于应用程序的设计和部署,打印应该从服务器完成(它应该检测订单并发送到不同的打印机和不同的打印格式......账单,厨房订单等等......).出于这个原因和其他原因(例如从 iPad 访问应用程序),我们放弃了 QZ-Print 小程序等选项,需要直接在服务器端打印.
我们搜索了很多,发现有一个叫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 临时 untuk simpan 文件.$file = tempnam($tmpdir, 'ctk');# nama 文件临时 yang akan dicetak$handle = fopen($file, 'w');$condensed = Chr(27) .铬(33).铬(4);$bold1 = Chr(27) .铬(69);$bold0 = Chr(27) .铬(70);$initialized = chr(27).chr(64);$condensed1 = chr(15);$condensed0 = chr(18);$corte = Chr(27) .铬(109);$Data = $initialized;$数据 .= $condensed1;$Data .= "==========================
";$Data .= "| ".$bold1."OFIDZ MAJEZTY".$bold0." |
";$Data .= "==========================
";$Data .= "Ofidz Majezty 来了
";$Data .= "我们爱 PHP 印度尼西亚
";$Data .= "我们爱 PHP 印度尼西亚
";$Data .= "我们爱 PHP 印度尼西亚
";$Data .= "我们爱 PHP 印度尼西亚
";$Data .= "我们爱 PHP 印度尼西亚
";$Data .= "----------------------------------------
";$数据 .= $corte;fwrite($handle, $Data);fclose($handle);copy($file, "//localhost/KoTickets");#Lakukan cetak取消链接($文件);
它可以工作,但是这会发送纯文本,我们需要发送图像(徽标),并格式化更可爱的帐单.我们尝试以相同的方式创建 PDF 并发送"到打印机,但只是打印空白.
我找到了一个可以使用网络打印机的库(github 上的 escpos-php),但我们也需要使用 USB 打印机,以避免我们的客户更换硬件.
如何实现这一目标的一些想法?
提前致谢.
解决方案escpos-php 的作者在这里.>
如果您的打印机确实支持 ESC/POS(大多数热敏收据打印机似乎使用它的某些子集),那么我认为该驱动程序将适应您的用例:USB 或网络打印、徽标、某些格式.其中一些是最近添加的.
USB 打印
escpos-php 打印到文件指针.在 Linux 上,您可以使用 usblp
驱动程序使 USB 打印机作为 aa 文件可见,然后只需 fopen()
它(USB 收据示例,关于在 Linux 上安装 USB 打印机的博文).
因此,在 USB 打印机上打印Hello world"与在网络打印机上打印仅略有不同:
text("Hello World!
");$打印机 ->切();$打印机 ->关闭();
或者,更像是您当前成功使用的代码,您可以写入临时文件并复制它:
text("Hello World!
");$打印机 ->切();$打印机 ->关闭();/* 将它复制到打印机 */copy($file, "//localhost/KoTickets");取消链接($文件);
因此,在您的 POS 系统中,您需要一个函数,该函数根据您的客户配置和首选目的地返回文件指针.收据打印机响应很快,但如果您有几台 iPad 下订单,您应该使用文件锁将操作包装到每台打印机 (flock()) 以避免与并发相关的麻烦.
另请注意,Windows 上的 USB 支持未经测试.
标志 &格式化
一旦您确定了如何与打印机通信,您就可以使用全套格式和图像命令.
可以像这样从 PNG 文件打印徽标:
使用 Mike42EscposEscposImage;$logo = EscposImage::load("foo.png");$打印机 ->图形($标志);
对于格式化,README.md 和下面的示例应该可以帮助您开始了.对于大多数收据,您只需要:
selectPrintMode()
改变字体大小.setEmphasis()
切换粗体.setJustification()
将某些文本或图像左对齐或居中.cut()
在每次收据之后.
我还建议您在当前使用的示例中绘制这样的框:
==========||==========
您可以使用 IBM 代码页 437 中的字符,这些字符专为绘制许多支持的框而设计打印机 - 只在输出中包含字符 0xB3 到 0xDA.它们并不完美,但看起来少了很多文本"-y.
$box = "xda".str_repeat("xc4", 10)."xbf
";$box .= "xb3".str_repeat(" ", 10)."xb3
";$box .= "xc0".str_repeat("xc4", 10)."xd9
";$打印机 ->textRaw($box);
完整示例
以下示例现在也包含司机.我认为它看起来像一个相当典型的商店收据,格式方面,并且可以很容易地适应您的厨房场景.
扫描输出:
生成它的PHP源代码:
setJustification(打印机::JUSTIFY_CENTER);$打印机 ->图形($标志);/* 店铺名称 */$打印机 ->选择打印模式(打印机:: MODE_DOUBLE_WIDTH);$打印机 ->text("ExampleMart Ltd.
");$打印机 ->选择打印模式();$打印机 ->text("42号店.
");$打印机 ->喂养();/* 收据标题 */$打印机 ->设置重点(真);$打印机 ->text("销售发票
");$打印机 ->设置重点(假);/* 项目 */$打印机 ->setJustification(打印机::JUSTIFY_LEFT);$打印机 ->设置重点(真);$打印机 ->文本(新项目('','$'));$打印机 ->设置重点(假);foreach ($items as $item) {$打印机 ->文本($项目);}$打印机 ->设置重点(真);$打印机 ->文本($小计);$打印机 ->设置重点(假);$打印机 ->喂养();/* 税收和总额 */$打印机 ->文本($税);$打印机 ->选择打印模式(打印机:: MODE_DOUBLE_WIDTH);$打印机 ->文本($总计);$打印机 ->选择打印模式();/*页脚*/$打印机 ->饲料(2);$打印机 ->setJustification(打印机::JUSTIFY_CENTER);$打印机 ->text("感谢您在 ExampleMart 购物
");$打印机 ->text("交易时间请访问example.com
");$打印机 ->饲料(2);$打印机 ->文本($日期.
");/* 剪下收据并打开钱箱 */$打印机 ->切();$打印机 ->脉冲();$打印机 ->关闭();/* 一个包装器来组织项目名称 &价格列*/类项目{私人 $name;私人$价格;私人 $dollarSign;公共函数 __construct($name = '', $price = '', $dollarSign = false){$this ->名称 = $name;$this ->价格= $价格;$this ->美元符号 = $dollarSign;}公共函数 __toString(){$rightCols = 10;$leftCols = 38;如果 ($this -> 美元符号) {$leftCols = $leftCols/2 - $rightCols/2;}$left = str_pad($this -> name, $leftCols) ;$sign = ($this -> DollarSign ? '$' : '');$right = str_pad($sign . $this -> price, $rightCols, ' ', STR_PAD_LEFT);返回 "$left$right
";}}
We are looking to print to a POS printer connected where apache is running. Due to design of the application, and deployment, printing should be done from Server (it should detect the order and send to different printers and different formats of printing...bill, kitchen orders, and so on...). For this reason and others (like access application from an iPad for example) we discard options like QZ-Print applet and needst o print directly server side.
We searched a lot, and found that there are an extension called php-printer but seems outdated, and just works under WIndows.
We followed this code: (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 .= "==========================
";
$Data .= "| ".$bold1."OFIDZ MAJEZTY".$bold0." |
";
$Data .= "==========================
";
$Data .= "Ofidz Majezty is here
";
$Data .= "We Love PHP Indonesia
";
$Data .= "We Love PHP Indonesia
";
$Data .= "We Love PHP Indonesia
";
$Data .= "We Love PHP Indonesia
";
$Data .= "We Love PHP Indonesia
";
$Data .= "--------------------------
";
$Data .= $corte;
fwrite($handle, $Data);
fclose($handle);
copy($file, "//localhost/KoTickets"); # Lakukan cetak
unlink($file);
And it works, but this sends plain text, and we need to send image (logo), and format a more cute bill. We tried creating a PDF and "sending" to the printer in the same way, but just prints blank.
I found a library to work with network printers (escpos-php on github), but we need to work with USB printers too, to avoid our customers to change hardware.
Some ideas how to achieve this?
Thanks in advance.
解决方案Author of escpos-php here.
If your printers do support ESC/POS (most thermal receipt printers seem to use some sub-set of it), then I think the driver will accommodate your use case: USB or network printing, logo, some formatting. Some of these are quite recent additions.
USB printing
escpos-php prints to a file pointer. On Linux, you can make the USB printer visible as a a file using the usblp
driver, and then just fopen()
it (USB receipt example, blog post about installing a USB printer on Linux).
So printing "Hello world" on a USB printer is only slightly different to printing to a networked printer:
<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42EscposPrintConnectorsFilePrintConnector;
use Mike42EscposPrinter;
$connector = new FilePrintConnector("/dev/usb/lp0");
$printer = new Printer($connector);
$printer -> text("Hello World!
");
$printer -> cut();
$printer -> close();
Or, more like the code you are currently using successfully, you could write to a temp file and copy it:
<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42EscposPrintConnectorsFilePrintConnector;
use Mike42EscposPrinter;
/* 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!
");
$printer -> cut();
$printer -> close();
/* Copy it over to the printer */
copy($file, "//localhost/KoTickets");
unlink($file);
So in your POS system, you would need a function which returns a file pointer based on your customer configuration and preferred destination. Receipt printers respond quite quickly, but if you have a few iPads making orders, you should wrap operations to each printer with a file lock (flock()) to avoid concurrency-related trouble.
Also note that USB support on Windows is un-tested.
Logo & Formatting
Once you have figured out how you plan to talk to the printer, you can use the full suite of formatting and image commands.
A logo can be printed from a PNG file like so:
use Mike42EscposEscposImage;
$logo = EscposImage::load("foo.png");
$printer -> graphics($logo);
And for formatting, the README.md and the example below should get you started. For most receipts, you only really need:
selectPrintMode()
to alter font sizes.setEmphasis()
to toggle bold.setJustification()
to left-align or center some text or images.cut()
after each receipt.
I would also suggest that where you are currently using an example that draws boxes like this:
=========
| |
=========
You could make use of the characters in IBM Code page 437 which are designed for drawing boxes that are supported by many printers- just include characters 0xB3 to 0xDA in the output. They aren't perfect, but it looks a lot less "text"-y.
$box = "xda".str_repeat("xc4", 10)."xbf
";
$box .= "xb3".str_repeat(" ", 10)."xb3
";
$box .= "xc0".str_repeat("xc4", 10)."xd9
";
$printer -> textRaw($box);
Full example
The below example is also now included with the driver. I think it looks like a fairly typical store receipt, formatting-wise, and could be easily adapted to your kitchen scenario.
Scanned output:
PHP source code to generate it:
<?php
require __DIR__ . '/vendor/autoload.php';
use Mike42EscposPrinter;
use Mike42EscposEscposImage;
use Mike42EscposPrintConnectorsFilePrintConnector;
/* 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.
");
$printer -> selectPrintMode();
$printer -> text("Shop No. 42.
");
$printer -> feed();
/* Title of receipt */
$printer -> setEmphasis(true);
$printer -> text("SALES INVOICE
");
$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
");
$printer -> text("For trading hours, please visit example.com
");
$printer -> feed(2);
$printer -> text($date . "
");
/* 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
";
}
}
相关文章