HTML5 Canvas 賦予瀏覽器原生繪圖能力,但如何將用戶在畫布上的創作(如電子簽名、繪圖編輯)持久化到服務器?本文通過實際項目場景,詳細講解 Canvas 圖像數據的前端獲取、Base64 編碼傳輸、PHP 端解碼存儲全鏈路實現。
早期項目需求:專家評審系統要求專家在平板上手寫簽名。當時採用 Flash/ActiveX 方案極其繁瑣。如今 Canvas + Base64 + PHP 方案幾十行代碼即可搞定。
Canvas繪圖 → toDataURL()獲取Base64 → AJAX POST傳輸 → PHP base64_decode → 文件存儲
<canvas id="signaturePad" width="400" height="200"></canvas>
<button onclick="saveSignature()">保存簽名</button>
<script>
function saveSignature() {
const canvas = document.getElementById('signaturePad');
// 獲取 Base64 Data URL (格式: data:image/png;base64,xxxx)
const dataURL = canvas.toDataURL('image/png');
// 發送到後端
fetch('save_canvas.php', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'img=' + encodeURIComponent(dataURL)
}).then(res => res.text()).then(console.log);
}
</script>
<?php
// save_canvas.php
// 需 PHP 5.4+
// 1. 配置上傳目錄
define('UPLOAD_DIR', __DIR__ . '/uploads/signatures/');
if (!is_dir(UPLOAD_DIR)) {
mkdir(UPLOAD_DIR, 0755, true);
}
// 2. 接收並清洗 Base64 數據
$img = $_POST['img'] ?? '';
if (empty($img)) {
die('無圖像數據');
}
// 移除 Data URL 頭部信息
$img = str_replace('data:image/png;base64,', '', $img);
// 修正空格轉義問題(+ 被編碼為空格)
$img = str_replace(' ', '+', $img);
// 3. Base64 解碼
$data = base64_decode($img);
if ($data === false) {
die('Base64 解碼失敗');
}
// 4. 生成唯一文件名並存儲
$filename = uniqid('sign_', true) . '.png';
$filepath = UPLOAD_DIR . $filename;
$success = file_put_contents($filepath, $data);
if ($success === false) {
die('文件寫入失敗');
}
// 5. 返回結果
echo json_encode([
'success' => true,
'filename' => $filename,
'url' => '/uploads/signatures/' . $filename
]);
?>
data:[][;base64],
// 實例:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
mediatype:MIME 類型,Canvas 常用 image/png、image/jpeg;base64:標證數據經 Base64 編碼| 問題 | 原因 | 解決方案 |
|---|---|---|
| 解碼後圖片損壞 | 空格被編碼為 + 號 | str_replace(' ', '+', $data) |
| 文件體積為 0 | 未移除 Data URL 前綴 | str_replace('data:image/png;base64,', '', $data) |
| 大文件內存溢出 | Base64 體積約為原文 4/3 | 分塊上傳 / 調大 memory_limit / 使用流式處理 |
getimagesize() 或 finfo_file() 驗證真實 MIMEpost_max_size、upload_max_filesize 並校驗 strlen($data)location ~* \.php$ { deny all; }uniqid() 或 bin2hex(random_bytes(16)) 防止覆蓋與遍歷這套方案純前後端分離、無第三方依賴、兼容性極佳(IE9+),是 Canvas 數據服務端落地的標準範式。