CentOS 7 安装条码识别工具 zbar
终端命令
安装
sudo yum install -y epel-release
sudo yum --enablerepo=epel install -y zbar
which zbarimg && zbarimg --version
卸载
sudo yum remove -y zbar
php代码案例 从图片上传过来 到识别一维码
<?php
// /shopapi/upload.php
// 作用:上传图片 -> 读取面单条码(优先 Code128) -> 返回单号 ->(可选)入库
/* ====== CORS ====== */
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; }
/* ====== 仅 POST ====== */
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
header('Content-Type: application/json; charset=utf-8');
echo json_encode(['code'=>405, 'msg'=>'Method Not Allowed'], JSON_UNESCAPED_UNICODE);
exit;
}
/* ====== JSON 输出工具 ====== */
header('Content-Type: application/json; charset=utf-8');
function j($arr, int $code = 200){
http_response_code($code);
echo json_encode($arr, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);
exit;
}
/* ====== 可选:数据库配置(想入库就填) ====== */
$DB_DSN = ''; // 例:'mysql:host=127.0.0.1;dbname=shop;charset=utf8mb4'
$DB_USER = '';
$DB_PASS = '';
$SAVE_DB = $DB_DSN !== '';
/* ====== 工具:拼接当前域名 ====== */
function current_base_url(): string {
$isHttps = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
(isset($_SERVER['SERVER_PORT']) && (int)$_SERVER['SERVER_PORT'] === 443) ||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https');
$scheme = $isHttps ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
return $scheme . '://' . $host;
}
/* ====== 条码识别函数(优先 Code128,失败再开常见制式) ====== */
function readWaybillFromImage(string $imgPath): ?string {
$bin = '/usr/bin/zbarimg';
if (!is_file($imgPath)) return null;
// 1) 只开 Code128,最快最稳
$cmd1 = sprintf('%s --raw --set "*.enable=0" --set "code128.enable=1" %s 2>/dev/null',
$bin, escapeshellarg($imgPath));
$out = trim(shell_exec($cmd1) ?? '');
// 2) 读不到,再开常见的一些(部分快递会用 i25/ean13)
if ($out === '') {
$cmd2 = sprintf('%s --raw --set "*.enable=0" --set "code128.enable=1" --set "i25.enable=1" --set "ean13.enable=1" %s 2>/dev/null',
$bin, escapeshellarg($imgPath));
$out = trim(shell_exec($cmd2) ?? '');
}
if ($out) {
// 取 10~18 位数字,且排除 11 位手机号
if (preg_match_all('/(?<!\d)(\d{10,18})(?!\d)/', $out, $m)) {
foreach ($m[1] as $n) {
if (!preg_match('/^1[3-9]\d{9}$/', $n)) return $n;
}
}
}
return null;
}
/* ====== 接收上传 ====== */
if (empty($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) {
$err = $_FILES['file']['error'] ?? -1;
$map = [
UPLOAD_ERR_INI_SIZE=>'文件超出服务器限制',
UPLOAD_ERR_FORM_SIZE=>'文件超出表单限制',
UPLOAD_ERR_PARTIAL=>'文件只上传了一部分',
UPLOAD_ERR_NO_FILE=>'没有接收到文件',
UPLOAD_ERR_NO_TMP_DIR=>'临时目录不存在',
UPLOAD_ERR_CANT_WRITE=>'文件写入失败',
UPLOAD_ERR_EXTENSION=>'扩展中断上传'
];
j(['code'=>400, 'msg'=>'上传失败:'.($map[$err] ?? '未知错误')]);
}
/* ====== 基础校验 ====== */
$allowExt = ['jpg','jpeg','png','gif','webp'];
$maxSize = 8 * 1024 * 1024; // 8MB
$origName = $_FILES['file']['name'];
$tmpPath = $_FILES['file']['tmp_name'];
$size = (int)$_FILES['file']['size'];
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION));
if (!in_array($ext, $allowExt, true)) j(['code'=>400, 'msg'=>'不支持的图片格式']);
if ($size <= 0 || $size > $maxSize) j(['code'=>400, 'msg'=>'图片大小不符合要求(最大8MB)']);
$finfo = function_exists('finfo_open') ? finfo_open(FILEINFO_MIME_TYPE) : false;
if ($finfo) {
$mime = finfo_file($finfo, $tmpPath); finfo_close($finfo);
$okM = ['image/jpeg','image/png','image/gif','image/webp'];
if (!in_array($mime, $okM, true)) j(['code'=>400, 'msg'=>'文件类型校验失败']);
}
/* ====== 保存到 /shopapi/upload/YYYYMMDD ====== */
$rootDir = __DIR__;
$day = date('Ymd');
$saveDir = $rootDir . '/uploaddanhao/' . $day;
$relDir = '/shopapi/uploaddanhao/' . $day . '/';
if (!is_dir($saveDir) && !mkdir($saveDir, 0775, true)) j(['code'=>500, 'msg'=>'目录创建失败']);
$rand = bin2hex(random_bytes(8));
$saveName = $rand . '.' . $ext;
$dest = rtrim($saveDir, '/').'/'.$saveName;
if (!move_uploaded_file($tmpPath, $dest)) j(['code'=>500, 'msg'=>'保存文件失败']);
$idxFile = $rootDir . '/upload/index.html';
if (!file_exists($idxFile)) @file_put_contents($idxFile, '');
/* ====== 识别条码 -> 运单号 ====== */
$no = readWaybillFromImage($dest);
$base = current_base_url();
$url = $base . $relDir . $saveName;
$path = $relDir . $saveName;
/* ====== 可选:入库 ====== */
/*
CREATE TABLE `waybills` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`no` VARCHAR(20) NOT NULL,
`carrier` VARCHAR(20) DEFAULT NULL,
`src_img` VARCHAR(255) DEFAULT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `uniq_no` (`no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
*/
if ($SAVE_DB && $no) {
try {
$pdo = new PDO($DB_DSN, $DB_USER, $DB_PASS, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]);
$stmt = $pdo->prepare('INSERT IGNORE INTO waybills(no, carrier, src_img) VALUES(?,?,?)');
$stmt->execute([$no, null, $path]);
} catch (Throwable $e) {
// 入库失败不影响本次返回
}
}
/* ====== 返回 ====== */
if ($no) {
j(['code'=>0, 'msg'=>'ok', 'no'=>$no, 'url'=>$url, 'path'=>$path, 'name'=>$saveName]);
} else {
j(['code'=>422, 'msg'=>'未读到条码,可换角度/补光再拍', 'url'=>$url, 'path'=>$path, 'name'=>$saveName]);
}

浙公网安备 33010602011771号