从 PHP 打印到 POS 打印机

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25973046/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 18:05:06  来源:igfitidea点击:

Printing to POS printer from PHP

phpprintingkiosk

提问by Giu

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.

我们希望打印到连接 apache 运行的 POS 打印机。由于应用程序的设计和部署,打印应该从服务器完成(它应该检测订单并发送到不同的打印机和不同的打印格式......账单,厨房订单等等......)。出于这个原因和其他原因(例如从 iPad 访问应用程序),我们放弃了 QZ-Print 小程序等选项,需要直接在服务器端打印。

We searched a lot, and found that there are an extension called php-printer but seems outdated, and just works under WIndows.

我们搜索了很多,发现有一个叫php-printer的扩展,但是好像已经过时了,只能在WINdows下使用。

We followed this code: (http://mocopat.wordpress.com/2012/01/18/php-direct-printing-printer-dot-matrix-lx-300/)

我们遵循以下代码:(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);

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.

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

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.

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

Some ideas how to achieve this?

一些想法如何实现这一目标?

Thanks in advance.

提前致谢。

回答by mike42

Author of escpos-phphere.

escpos-php 的作者在这里。

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.

如果您的打印机确实支持 ESC/POS(大多数热敏收据打印机似乎使用它的一些子集),那么我认为驱动程序将适应您的用例:USB 或网络打印、徽标、某些格式。其中一些是最近添加的。

USB printing

USB打印

escpos-php prints to a file pointer. On Linux, you can make the USB printer visible as a a file using the usblpdriver, and then just fopen()it (USB receipt example, blog post about installing a USB printer on Linux).

escpos-php 打印到文件指针。在 Linux 上,您可以使用usblp驱动程序使 USB 打印机作为文件可见,然后只是fopen()它(USB 收据示例关于在 Linux 上安装 USB 打印机的博客文章)。

So printing "Hello world" on a USB printer is only slightly different to printing to a networked printer:

因此,在 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();

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 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);

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.

因此,在您的 POS 系统中,您需要一个函数,该函数根据您的客户配置和首选目的地返回文件指针。收据打印机响应很快,但如果您有几台 iPad 下订单,您应该使用文件锁 ( flock())将操作包装到每台打印机,以避免与并发相关的麻烦。

Also note that USB support on Windows is un-tested.

另请注意,Windows 上的 USB 支持未经测试。

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:

可以从 PNG 文件打印徽标,如下所示:

use Mike42\Escpos\EscposImage;
$logo = EscposImage::load("foo.png");
$printer -> graphics($logo);

And for formatting, the README.mdand the example below should get you started. For most receipts, you only really need:

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

  • selectPrintMode()to alter font sizes.
  • setEmphasis()to toggle bold.
  • setJustification()to left-align or center some text or images.
  • cut()after each receipt.
  • selectPrintMode()改变字体大小。
  • setEmphasis()切换粗体。
  • setJustification()左对齐或居中一些文本或图像。
  • cut()每次收据后。

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 437which 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.

您可以使用 IBM代码页 437中的字符,这些字符是为绘制许多打印机支持的框而设计的 - 只需在输出中包含字符 0xB3 到 0xDA。它们并不完美,但看起来少了很多“文本”-y。

$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);

Full example

完整示例

The below example is also now includedwith 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:

扫描输出:

Example formatted receipt including logo

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

PHP source code to generate it:

生成它的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";
    }
}