Печать на POS-принтер из PHP

Мы ожидаем печати на принтер POS, подключенный к серверу apache. Из-за дизайна приложения и развертывания печать должна выполняться с сервера (он должен определять порядок и отправлять на разные принтеры и различные форматы печати … счет, заказы на кухню и т. Д.). По этой причине и другие (например, приложение для доступа с 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 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); 

И это работает, но это отправляет простой текст, и нам нужно отправить изображение (логотип) и форматировать более милый счет. Мы попытались создать PDF-файл и «отправить» на принтер таким же образом, но просто печатаем пустым.

Я нашел библиотеку для работы с сетевыми принтерами (escpos-php on github), но нам также нужно работать с USB-принтерами, чтобы наши клиенты не могли менять оборудование.

Некоторые идеи, как достичь этого?

Заранее спасибо.

Автор escpos-php здесь.

Если ваши принтеры поддерживают ESC / POS (большинство термопринтеров, похоже, используют некоторые подмножества), то я думаю, что драйвер будет использовать ваш прецедент: USB или сетевую печать, логотип, некоторое форматирование. Некоторые из них довольно свежие.

USB-печать

escpos-php печатает в указатель файла. В Linux вы можете сделать USB-принтер видимым как файл aa с usblp драйвера usblp , а затем просто fopen() it ( пример приема USB , сообщение в блоге об установке USB-принтера в Linux ).

Поэтому печать «Hello world» на USB-принтере немного отличается от печати на сетевом принтере:

 <?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 () ), чтобы избежать проблем, связанных с параллелизмом.

Также обратите внимание, что поддержка USB в Windows не проверена.

Логотип и форматирование

После того, как вы выяснили, как вы планируете разговаривать с принтером, вы можете использовать полный набор команд форматирования и изображения.

Логотип можно распечатать из PNG-файла следующим образом:

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

И для форматирования, README.md и приведенный ниже пример должны помочь вам начать работу. Для большинства квитанций вам действительно нужно:

  • selectPrintMode() чтобы изменить размер шрифта.
  • setEmphasis() для переключения жирным шрифтом.
  • setJustification() для выравнивания по левому setJustification() или центра текста или изображений.
  • cut() после каждого получения.

Я также предлагаю, чтобы в этом примере вы используете пример, который рисует такие поля:

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

Вы можете использовать символы в кодовой странице 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); 

Полный пример

Ниже приведен пример с драйвером. Я думаю, что это похоже на довольно типичную квитанцию ​​магазина, с форматированием и может быть легко адаптирована к вашему кухонному сценарию.

Отсканированный вывод:

Пример отформатированной квитанции, включая логотип

Исходный код 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 FY 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"; } }