PHP蓝牙打印主要通过系统命令或Socket通信实现,需先配对并连接蓝牙设备(如Linux下使用bluetoothctl或Windows映射COM口),核心流程包括:初始化蓝牙连接、发送ESC/POS打印指令(文本、图片等)、处理异常,可借助PHP的exec()调用系统工具,或通过socket_create()建立RFCOMM连接,需适配不同操作系统(如Linux的/dev/rfcommX,Windows的COM端口),关键点在于指令转换(如文本转ESC/POS码)和连接稳定性,常见场景为小票打印,需处理配对失败、指令发送超时等异常,确保打印任务可靠完成。
PHP实现蓝牙打印功能代码详解与实战指南
在移动办公、零售收银、餐饮点单等场景中,蓝牙打印机凭借其便携性高、连接灵活的特点已成为主流输出设备,对于基于PHP开发的Web或App后台系统而言,如何实现与蓝牙打印机的通信,完成小票、标签等内容的打印,是常见的业务需求,本文将系统性地介绍PHP实现蓝牙打印功能的原理、代码实现及注意事项,帮助开发者快速落地这一功能。
技术原理:PHP与蓝牙打印的连接逻辑
PHP作为服务器端语言,由于安全模型限制,无法直接操作客户端的蓝牙硬件(如手机、电脑的蓝牙模块),实现PHP蓝牙打印的核心思路是"PHP生成打印指令,客户端负责蓝牙通信",具体实现路径如下:
- PHP服务器端:根据业务需求生成打印指令(如文本、条码、二维码等),通常采用ESC/POS指令集(主流票据打印机通用指令集)。
- 客户端代理:通过Web页面(H5)或App调用设备蓝牙API,连接打印机并接收PHP下发的指令。
- 打印执行:客户端解析指令并驱动打印机完成打印。
本文重点讲解PHP端的指令生成与接口设计,客户端部分以H5+JS为例简要说明,确保全流程可落地。
环境准备
- PHP环境:PHP 7.0+(支持主流字符串、函数操作,建议使用PHP 7.4+以获得更好的性能和安全性)。
- 蓝牙打印机:支持ESC/POS指令的蓝牙票据打印机(如得力、芯迈、佳博等品牌)。
- 客户端环境:
- Web端:支持Web蓝牙API的浏览器(Chrome、Edge等Android端浏览器,iOS部分版本支持有限)
- 移动端:支持蓝牙通信的iOS/Android应用
- 开发工具:蓝牙调试工具(如LightBlue、nRF Connect等)用于测试打印机连接。
核心代码实现
ESC/POS指令集基础
ESC/POS是Epson公司提出的针式打印机指令集,通过控制字符(如ESC、GS)组合实现文本、格式、条码等功能,常用指令如下:
| 功能 | 指令(十六进制) | 说明 |
|---|---|---|
| 初始化 | 1B 40 |
清空缓冲区,恢复默认设置 |
| 文本对齐 | 1B 61 00/01/02 |
左/中/右对齐 |
| 设置字号 | 1D 21 00/10/20 |
正常/2倍/4倍字号 |
| 设置字体 | 1B 4D 00/01 |
字体A/字体B |
| 换行 | 0A |
换行 |
| 切纸 | 1B 56 00 |
部分切纸(需打印机支持) |
| 打印二维码 | 1D 28 6B 04 00 31 50 30 |
二维码指令前缀,后跟数据 |
| 打印条码 | 1D 6B 02 |
CODE128条码指令前缀 |
| 开钱箱 | 1B 70 00 1B 70 01 |
脉冲控制开钱箱 |
PHP生成ESC/POS指令
封装一个EscPosCommand类,用于生成常用打印指令,并增加错误处理和日志记录功能:
<?php
class EscPosCommand {
/**
* 初始化打印机
* @return string 初始化指令
*/
public static function init() {
return self::hexToBytes("1B40");
}
/**
* 文本对齐(left:0, center:1, right:2)
* @param int $align 对齐方式
* @return string 对齐指令
* @throws InvalidArgumentException 参数无效时抛出异常
*/
public static function align($align = 0) {
if (!in_array($align, [0, 1, 2])) {
throw new InvalidArgumentException("对齐参数必须是0(左)、1(中)或2(右)");
}
return self::hexToBytes("1B61") . chr($align);
}
/**
* 设置字号(normal:0, double:1, quadruple:2)
* @param int $size 字号大小
* @return string 字号指令
* @throws InvalidArgumentException 参数无效时抛出异常
*/
public static function setSize($size = 0) {
if (!in_array($size, [0, 1, 2])) {
throw new InvalidArgumentException("字号参数必须是0(正常)、1(2倍)或2(4倍)");
}
return self::hexToBytes("1D21") . chr($size);
}
/**
* 设置字体(fontA:0, fontB:1)
* @param int $font 字体类型
* @return string 字体指令
* @throws InvalidArgumentException 参数无效时抛出异常
*/
public static function setFont($font = 0) {
if (!in_array($font, [0, 1])) {
throw new InvalidArgumentException("字体参数必须是0(字体A)或1(字体B)");
}
return self::hexToBytes("1B4D") . chr($font);
}
/**
* 打印文本(自动换行)
* @param string $content 要打印的文本
* @return string 文本指令
*/
public static function text($content) {
return $content . self::hexToBytes("0A");
}
/**
* 打印二维码
* @param string $text 二维码内容
* @param int $size 二维码大小(1-16)
* @param int $errorCorrectionLevel 纠错级别(0-3)
* @return string 二维码指令
* @throws InvalidArgumentException 参数无效时抛出异常
*/
public static function qrCode($text, $size = 5, $errorCorrectionLevel = 0) {
if (!in_array($errorCorrectionLevel, [0, 1, 2, 3])) {
throw new InvalidArgumentException("纠错级别参数必须是0(L)、1(M)、2(Q)或3(H)");
}
// 设置二维码模型
$cmd = self::hexToBytes("1D286B0400315030");
// 设置二维码大小
$cmd .= self::hexToBytes("1D286B0300") . chr($size);
// 设置纠错级别
$cmd .= self::hexToBytes("1D286B0400") . chr($errorCorrectionLevel);
// 存储二维码数据
$dataLen = strlen($text);
$cmd .= self::hexToBytes("1D286B") . pack('n', $dataLen) . $text;
// 打印二维码
$cmd .= self::hexToBytes("1D286B01031B");
return $cmd;
}
/**
* 打印条码(支持CODE128)
* @param string $text 条码内容
* @param int $height 条码高度(2-6)
* @return string 条码指令
* @throws InvalidArgumentException 参数无效时抛出异常