Files
fdesk/app/common/service/QrCodeService.php
T
2026-02-24 17:35:58 +08:00

188 lines
5.6 KiB
PHP

<?php
namespace app\common\service;
use support\exception\BusinessException;
/**
* 二维码生成服务
*/
class QrCodeService
{
/**
* 生成物品二维码
*
* @param int $itemId 物品ID
* @param string $appUrl 应用访问地址
* @return string 二维码内容URL
*/
public function generateItemQrCode(int $itemId, string $appUrl): string
{
//return rtrim($appUrl, '/') . '/mobile/inv/claim/' . $itemId;
return "https://mweb-fdesk.hnxinyouhe.com/pages/scan/external-scan/" . $itemId;
}
/**
* 生成二维码图片并上传到 OSS
*
* @param int $itemId 物品ID
* @param string $content 二维码内容
* @param string $fileName 文件名
* @return array 返回OSS路径和完整URL
* @throws BusinessException
*/
public function generateAndUploadQrCode(int $itemId, string $content, string $fileName): array
{
// 使用 endroid/qr-code 库生成二维码
// 如果未安装,使用 API 方式生成
$tempPath = $this->generateQrCodeImage($content, $fileName);
if (!$tempPath) {
throw new BusinessException('二维码生成失败');
}
try {
// 上传到 OSS
$ossService = new OssService();
$ossPath = 'qr/' . $fileName;
$ossUrl = $ossService->uploadImage($tempPath, $ossPath);
// 删除临时文件
if (file_exists($tempPath)) {
unlink($tempPath);
}
return [
'path' => $ossPath,
'url' => $ossUrl,
];
} catch (\Throwable $e) {
// 删除临时文件
if (file_exists($tempPath)) {
unlink($tempPath);
}
throw new BusinessException('二维码上传失败:' . $e->getMessage());
}
}
/**
* 生成二维码图片(使用 QR Server API 或本地库)
*
* @param string $content 二维码内容
* @param string $fileName 文件名
* @return string 临时文件路径,失败返回 false
*/
private function generateQrCodeImage(string $content, string $fileName)
{
$tempDir = runtime_path() . '/qr_temp/';
if (!is_dir($tempDir)) {
mkdir($tempDir, 0755, true);
}
$tempPath = $tempDir . $fileName;
// 方式1: 使用 endroid/qr-code 库(推荐)
if (class_exists('\Endroid\QrCode\QrCode')) {
return $this->generateWithEndroid($content, $tempPath);
}
// 方式2: 使用在线 API(备用方案)
return $this->generateWithApi($content, $tempPath);
}
/**
* 使用 endroid/qr-code 生成二维码
*/
private function generateWithEndroid(string $content, string $tempPath): string
{
try {
// 5.x 版本使用静态工厂方法
if (method_exists(\Endroid\QrCode\QrCode::class, 'create')) {
$qrCode = \Endroid\QrCode\QrCode::create($content)
->setSize(300)
->setMargin(10);
} else {
// 4.x 及以下版本
$qrCode = new \Endroid\QrCode\QrCode($content);
if (method_exists($qrCode, 'setSize')) {
$qrCode->setSize(300);
}
if (method_exists($qrCode, 'setMargin')) {
$qrCode->setMargin(10);
}
}
// 获取 Writer
if (class_exists('\Endroid\QrCode\Writer\PngWriter')) {
$writer = new \Endroid\QrCode\Writer\PngWriter();
} else {
// 旧版本可能使用不同的命名空间
$writer = new \Endroid\QrCode\Writer();
}
$result = $writer->write($qrCode);
// 保存文件
if (method_exists($result, 'getString')) {
file_put_contents($tempPath, $result->getString());
} else {
// 更旧版本可能直接返回字符串
file_put_contents($tempPath, $result);
}
return $tempPath;
} catch (\Throwable $e) {
// 如果 endroid 库使用失败,回退到在线 API
error_log('endroid/qr-code 生成失败: ' . $e->getMessage() . ',使用在线 API 备用方案');
return $this->generateWithApi($content, $tempPath);
}
}
/**
* 使用在线 API 生成二维码(备用方案)
*/
private function generateWithApi(string $content, string $tempPath): string
{
$apiUrl = 'https://api.qrserver.com/v1/create-qr-code/?';
$params = [
'size' => '300x300',
'data' => $content,
'margin' => '10',
];
$url = $apiUrl . http_build_query($params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$imageData = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || !$imageData) {
return false;
}
file_put_contents($tempPath, $imageData);
return $tempPath;
}
/**
* 删除 OSS 上的二维码文件
*
* @param string $ossPath OSS路径
* @return bool
*/
public function deleteQrCode(string $ossPath): bool
{
try {
$ossService = new OssService();
return $ossService->deleteFile($ossPath);
} catch (\Throwable $e) {
return false;
}
}
}