Library / SDK
mike42/escpos-php avatar
mike42/escpos-php

mike42/escpos-php: Receipt Printing From PHP Without a Vendor SDK

PHP library for printing to ESC/POS-compatible thermal and impact printers

2,793 stars884 forksPHPNOASSERTION

At a glance

What is it?
A PHP library that implements a subset of Epson's ESC/POS protocol so a web app can send formatted receipts, barcodes and cut commands to thermal printers over Ethernet, USB, serial, SMB or CUPS. It is aimed at PHP point-of-sale backends, and its main constraint is that it talks to hardware directly.
Who is it for?
Adopt mike42/escpos-php if your backend is PHP and you control the printer connection, whether that is a raw TCP socket on port 9100, a local device file, or a CUPS queue. Do not adopt it if you need a browser or a mobile client to reach the printer directly, or if your printer is not in the compatibility table and you cannot test it.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 53 days ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap mike42/escpos-php fills in a PHP point-of-sale stack

Thermal receipt printers do not accept HTML or PDF. They accept a byte stream in Epson's ESC/POS command language, and every vendor that ships a printer also ships a driver, usually for Windows, usually closed. A PHP web application that needs to print a receipt therefore has two options: shell out to a vendor tool, or generate the byte stream itself. This library does the second. The README describes it as implementing "a subset of Epson's ESC/POS protocol" and says it was built "to add drop-in support for receipt printing to any PHP app, including web-based point-of-sale (POS) applications."

The audience is narrow and specific. You need a PHP runtime on a machine that can reach the printer, and you need to be comfortable with the printer being a device your code opens rather than a service you call. If your receipts are rendered by a browser and handed to the operating system's print dialog, this library is not in that path at all.

How the Printer, Connector and command buffer fit together

The architecture is three objects. A print connector owns the transport and exposes a write method. A Printer object wraps that connector and translates method calls such as text, cut or barcode into ESC/POS byte sequences, buffering them. Nothing is sent until you call close, at which point the buffer is flushed through the connector. That is why the hello-world example can point a FilePrintConnector at php://stdout and pipe the output into netcat.

The connector is the only part that knows about hardware, and the README lists the combinations it is known to work with: Ethernet on Linux, Mac and Windows; USB on Linux and Windows, with Mac marked "Not tested"; USB-serial and serial on all three; parallel on Linux and Windows; SMB shared on Linux and Windows, with Mac marked "No"; and CUPS hosted on Linux and Mac, with Windows marked "No". Those gaps are worth reading before you design a deployment, because a Mac workstation with an SMB-shared printer is explicitly outside the supported set.

Printer-specific behaviour is handled through bundled definitions loaded from JSON, which is why the json extension is a hard requirement. The README also notes two printers that need extra calls to release paper: the Epson FX-890 needs feedForm() and the Epson TM-U295 needs release(). That is the kind of detail you only learn from a compatibility table, and it is the strongest argument for checking your exact model against the list before writing code.

Installing mike42/escpos-php and printing a first receipt

The library is distributed through Packagist, so installation is a Composer command run from your project root. The README gives exactly this:

bash
composer require mike42/escpos-php

Before you run it, check the runtime requirements. The README states PHP 8.2 or newer, plus the json, intl and zlib extensions. The intl extension is the one people miss, because it is not enabled by default in every distribution and the library uses it for character encoding. The README also suggests installing either imagick or gd, which are used to speed up image processing when present; without them the gfx-php library is used as a fallback.

The first real use is the hello-world receipt from the README. It writes to standard output rather than a printer, which makes it a safe way to confirm the library loads and produces bytes:

php
<?php
/* Call this file 'hello-world.php' */
require __DIR__ . '/vendor/autoload.php';
use Mike42\Escpos\PrintConnectors\FilePrintConnector;
use Mike42\Escpos\Printer;
$connector = new FilePrintConnector("php://stdout");
$printer = new Printer($connector);
$printer -> text("Hello World!\n");
$printer -> cut();
$printer -> close();

Run it and you should see ESC/POS control bytes plus the text on your terminal, not a formatted receipt. To get it onto paper, the README shows piping that output to a printer with an Ethernet interface using netcat:

bash
php hello-world.php | nc 10.x.x.x. 9100

For a USB printer attached locally through usblp on Linux, the README redirects to the device file instead:

bash
php hello-world.php > /dev/usb/lp0

If the printer is installed in a local cups server, the README writes to a file and then submits it raw, so cups does not try to interpret the stream:

bash
php hello-world.php > foo.txt
lpr -o raw -H localhost -P 

Note that the last command in the README is truncated at the queue name, so you will need to supply your own -P value. The repository also carries a larger set of runnable examples under example/, including barcode.php, qr-code.php, graphics.php, print-from-pdf.php and text-size.php, which is where to look once hello-world works.

Where escpos-php stops being the right tool

The library generates bytes. It does not queue jobs, retry, or report whether paper actually came out. If the connector writes to a TCP socket and the printer is powered off, the failure surfaces as a connection error at close time, and the README does not document a retry or acknowledgement mechanism. There is no job status to poll. For a busy counter where a dropped receipt matters, that means building your own confirmation path around it, or accepting that the print is fire-and-forget.

Browser-side printing is a hard boundary. The library runs in PHP on the server, so a client-side web app cannot call it. The README is also explicit that the server "must be able to communicate with your printer," which in practice means the PHP host needs network reachability to port 9100, or a device file, or a CUPS queue. Hosted PHP environments generally have none of those, and there is no cloud relay in the project.

Finally, ESC/POS is a subset here, not the full specification. Commands outside the implemented set are not available through the API, and the compatibility list is a record of what contributors have reported, not a certification. If your printer is not on it, the README asks you to open an issue so it can be added, which tells you the list grows by report rather than by testing.

escpos-php against Node-escpos and a CUPS-only setup

The closest alternative in the same problem space is node-escpos, which targets Node.js rather than PHP. The difference is not cosmetic: node-escpos fits a JavaScript backend or an Electron app where the printing process and the application share a runtime, while escpos-php assumes a PHP process that can reach the printer. If your stack is PHP, adding a Node service purely to print receipts means a second runtime, a second deployment and an IPC hop; if your stack is Node, escpos-php is the wrong choice for the mirror-image reason.

The other realistic alternative is not a library at all. You can install the printer as a CUPS queue and submit raw jobs with lpr, which is the approach the README itself shows for CUPS-hosted printers. That moves the problem to the operating system: CUPS handles the queue, the spooling and the retries, and your application only has to produce the file. The trade-off is that you lose the object API for barcodes, QR codes, character encodings and image conversion, and you have to generate the ESC/POS bytes some other way. The library's CUPS connector is effectively a middle path, keeping the command API while letting CUPS own the transport.

Maintenance, version history and the licence question

The repository is not archived, and the last push was on 2026-08-08, which is recent enough that the project is still receiving changes. The release history is worth reading as a signal about upgrade cost: v3.0 landed in October 2019, v4.0 in May 2022, and v5.0 in July 2026. That is a slow cadence with long gaps, so a major-version upgrade is a rare event rather than a routine chore, but it also means a breaking change arrives with years of accumulated drift behind it. Plan to read the release notes rather than assume a drop-in replacement.

The runtime requirement moved to PHP 8.2 or newer as part of that history, which is the practical constraint on older deployments. A PHP 7 application cannot take the current release.

On licensing, the repository metadata reports the licence as NOASSERTION, meaning no recognised SPDX identifier was detected, and the README links to LICENSE.md in the repository rather than naming a licence. The Packagist badge in the README points at the same file. That is not something to guess at: read LICENSE.md before you ship the library in a commercial product, and if the terms matter to your legal team, treat the absence of an SPDX identifier as a question to answer rather than a detail.

Editorial conclusion

Adopt mike42/escpos-php if your backend is PHP and you control the printer connection, whether that is a raw TCP socket on port 9100, a local device file, or a CUPS queue. Do not adopt it if you need a browser or a mobile client to reach the printer directly, or if your printer is not in the compatibility table and you cannot test it. Before committing, confirm your PHP version is 8.2 or newer, check that json, intl and zlib are enabled, and read LICENSE.md yourself, since the repository metadata reports the licence as NOASSERTION rather than a recognised SPDX identifier.

Frequently asked questions

What is the driver for an Epson ESC/POS printer in PHP?

mike42/escpos-php implements a subset of Epson's ESC/POS protocol in PHP, so a PHP application can generate receipt bytes itself instead of relying on a vendor driver. It supports Ethernet, USB, USB-serial, serial, parallel, SMB and CUPS interfaces depending on the operating system.

Which PHP version and extensions does mike42/escpos-php require?

The README states PHP 8.2 or newer, along with the json, intl and zlib extensions. It also suggests imagick or gd to speed up image processing, with gfx-php used as a fallback when neither is present.

How do I install mike42/escpos-php?

It is distributed on Packagist, so the README's install step is the Composer command composer require mike42/escpos-php run from your project root. After that, the hello-world example writes to php://stdout so you can check the output before pointing it at a printer.

Can mike42/escpos-php print from a web browser or a mobile app?

No. The library runs in PHP on the server, and the README states that the server where PHP is installed must be able to communicate with the printer. A client-side web or mobile app cannot call it directly.

Which printers work with mike42/escpos-php?

The README maintains a long list of reported models, including Epson TM-T20, TM-T88V, TM-U220 and TM-U295, plus Bixolon, Citizen, Star, Xprinter, Rongta and Zjiang units. The list is built from user reports, so a printer that is not on it is untested rather than necessarily unsupported.

Official sources

  1. Issues
  2. mike42/escpos-php on GitHub
  3. README
  4. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/mike42-escpos-php.svg)](https://hysenlabs.com/projects/mike42-escpos-php)