
本文介绍如何使用 qr-code-styling 库在前端生成 SVG 格式 QR 码,并通过 AJAX 将其安全发送至 PHP 后端,最终在服务器上保存为 SVG 或转换为 PNG/JPEG 图像。
本文介绍如何使用 qr-code-styling 库在前端生成 SVG 格式 QR 码,并通过 AJAX 将其安全发送至 PHP 后端,最终在服务器上保存为 SVG 或转换为 PNG/JPEG 图像。
在 Web 项目中,常需将动态生成的 QR 码持久化存储于服务端(如用于订单凭证、会员卡、API 接口分发等),而非仅在浏览器中渲染或触发客户端下载。由于你明确不使用 Node.js,且已选用 qr-code-styling 这一纯前端 SVG/Canvas 渲染库,关键挑战在于:如何可靠地将生成的 SVG 内容提交给 PHP,并确保编码、传输与保存无损。
✅ 正确获取 SVG 字符串(关键修复)
原代码中 document.querySelector('svg').outerHTML 存在严重隐患:
- 若页面含多个 SVG(如图标、其他组件),可能取错节点;
-
outerHTML在某些浏览器中对动态注入的 SVG 可能返回不完整或转义异常的字符串; - 更重要的是,
qrCode.append()并不保证立即完成 DOM 插入(尤其涉及图片加载时),直接读取易出错。
✅ 推荐方式:使用库提供的官方方法 getRawData('svg'),它返回一个 Promise,解析后得到标准化、未污染的 SVG 字符串:
立即学习“PHP免费学习笔记(深入)”;
const qrCode = new QRCodeStyling({ /* 配置同原文 */ });
// 确保 QR 码已初始化完成后再调用
qrCode.append(document.getElementById("canvas"));
// ✅ 安全获取原始 SVG 字符串
qrCode.getRawData('svg').then(svgBlob =>
svgBlob.text().then(svgString => {
// 发送至 PHP 后端
$.ajax({
url: 'ajax.php',
type: 'POST',
data: { svg: svgString }, // 使用命名参数更健壮
dataType: 'json',
success: res => console.log('Saved:', res),
error: err => console.error('Save failed:', err)
});
})
);? 提示:
getRawData()是 qr-code-styling v1.5+ 的稳定 API,兼容所有支持的输出类型('svg','png','jpeg')。若需直接保存 PNG,可传'png'并配合base64解码处理(见下文扩展)。
? PHP 后端接收与保存(增强健壮性)
ajax.php 需做三处关键改进:
- 启用 CORS(如跨域请求);
- 校验并清理输入,防止路径遍历或 XSS 注入;
-
支持 SVG 保存 + 可选 PNG 转换(推荐使用
imagick)。
<?php
header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
// ✅ 1. 安全接收 SVG 字符串
if (!isset($_POST['svg']) || !is_string($_POST['svg'])) {
http_response_code(400);
echo json_encode(['success' => false, 'error' => 'Invalid SVG data']);
exit;
}
$svgContent = trim($_POST['svg']);
// ✅ 2. 基础安全过滤(移除危险标签/属性,仅保留 SVG 核心结构)
$svgContent = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $svgContent);
$svgContent = preg_replace('/on\w+\s*=\s*["\'][^"\']*["\']/i', '', $svgContent);
// ✅ 3. 生成唯一文件名,避免覆盖
$filename = 'qrcode_' . date('Ymd_His') . '_' . uniqid() . '.svg';
$svgPath = __DIR__ . '/uploads/' . $filename;
// 创建 uploads 目录(如不存在)
if (!is_dir(__DIR__ . '/uploads')) {
mkdir(__DIR__ . '/uploads', 0755, true);
}
// ✅ 4. 保存 SVG
if (file_put_contents($svgPath, $svgContent) === false) {
http_response_code(500);
echo json_encode(['success' => false, 'error' => 'Failed to save SVG']);
exit;
}
// ✅ 5. (可选)转换为 PNG(需服务器安装 ImageMagick)
$pngPath = str_replace('.svg', '.png', $svgPath);
if (class_exists('Imagick')) {
try {
$imagick = new Imagick();
$imagick->setBackgroundColor(new ImagickPixel('transparent'));
$imagick->readImageBlob($svgContent);
$imagick->setImageFormat('png');
$imagick->writeImage($pngPath);
$imagick->clear();
$imagick->destroy();
} catch (Exception $e) {
error_log('SVG to PNG conversion failed: ' . $e->getMessage());
}
}
echo json_encode([
'success' => true,
'svg_url' => '/uploads/' . $filename,
'png_url' => isset($pngPath) ? '/uploads/' . basename($pngPath) : null
]);⚠️ 注意事项与最佳实践
-
MIME 类型无需强制设为
image/svg+xml:使用data: { svg: ... }发送时,jQuery 默认以application/x-www-form-urlencoded提交,更兼容 PHP 的$_POST;若坚持用php://input,则必须设置contentType: false+processData: false,且 PHP 需用file_get_contents('php://input')读取原始体(但需额外解析 URL 编码)。 -
PNG 转换依赖:若服务器无 ImageMagick,可改用
wkhtmltopdf的wkhtmltoimage,或前端用canvg渲染到<canvas></canvas>后调用toDataURL('image/png')发送 base64(增加前端负担)。 -
安全性兜底:生产环境务必验证
$svgContent是否以<svg> 开头、是否包含合法命名空间,建议用 XML 解析器校验结构。</svg> - 性能考虑:高频生成场景下,建议添加 Redis 缓存机制,避免重复生成相同内容。
通过以上方案,你即可在纯 PHP 环境中稳定接收前端生成的 QR 码 SVG,并按需落地为矢量或位图格式,满足服务端归档、邮件嵌入、打印输出等各类业务需求。



















