创建带签名的新用户时签名文件总是损坏(0KB无法打开)
问题:签名文件生成后为0KB且无法打开
每次创建带签名的新用户时,生成的签名文件大小为0KB,无法打开;文件路径可正常访问,但文件损坏无法显示。此前功能正常运行,现在出现异常。已完成storage/app/public/signatures/的符号链接配置,文件能被创建但始终损坏。
相关代码
Laravel控制器(存储用户与签名)
public function store(Request $request) { // Save Signature from data URL to storage $signatureData = $request->signature; $fileName = time() . '.png'; $filePath = 'public/signatures/' . $fileName; // Save to storage/app/public $imageData = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $signatureData)); Storage::put($filePath, $imageData); // Validasi dan penyimpanan data user $user = User::create([ 'name' => $request->name, 'user_code' => $request->user_code, 'password' => Hash::make($request->password), 'signature_path' => 'signatures/' . $fileName, // Save part of path todatabase ]); // Add role(Jabatans) to user with pivot table $user->jabatans()->attach($request->jabatan_id); Session::flash('success', 'User Berhasil Dibuat'); return redirect()->route('user-create'); }
前端签名Canvas代码
<div class="mb-3"> <label for="signature">Signature</label> <canvas id="signature-pad" class="signature-pad" width=400 height=200 style="border:1px solid black;"></canvas> <button type="button" id="clearSignature" class="btn btn-secondary mt-2">Clear Signature</button> </div>
签名Pad相关JavaScript代码
<script> var canvas = document.getElementById('signature-pad'); var signaturePad = new SignaturePad(canvas); // Function to check if the form is completely filled out function isFormValid(formId) { const form = document.getElementById(formId); return form.checkValidity(); } // Function to display SweetAlert confirmation function showConfirmationAlert() { if (isFormValid('userForm')) { // Replace 'userForm' with your form's ID Swal.fire({ title: 'Are you sure?', text: 'Do you want to submit this form?', icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Yes' }).then((result) => { if (result.isConfirmed) { // Submit the form document.getElementById('userForm').submit(); // Replace 'userForm' with your form's ID // Show success alert Swal.fire( 'Success!', 'Your form has been submitted.', 'success' ); } }); } else { Swal.fire( 'Error!', 'Please fill out all required fields.', 'error' ); } } // Add an event listener to the clear signature button document.getElementById('clearSignature').addEventListener('click', function() { signaturePad.clear(); }); // Add an event listener to the submit button document.getElementById('submitButton').addEventListener('click', function(e) { e.preventDefault(); // Check the signature first if (signaturePad.isEmpty()) { Swal.fire({ icon: 'error', title: 'Oops...', text: 'Please provide your signature.', }); return; } // Then, check for user code duplication const userCode = document.getElementById('user_code').value; fetch('/check-usercode', { method: 'POST', body: JSON.stringify({ user_code: userCode }), headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': '{{ csrf_token() }}' } }) .then(response => response.json()) .then(data => { if (data.exists) { // If the user code already exists, show a warning with SweetAlert Swal.fire({ icon: 'error', title: 'Oops...', text: 'User code already exists!', }); } else { // If the user code is unique, display a form submission confirmation showConfirmationAlert(); } }) .catch(error => console.error('Error:', error)); }); </script>
排查与修复方案
1. 核心问题:签名数据未提交到后端
当前代码中没有将Canvas的签名数据作为表单字段提交。前端仅初始化了SignaturePad,但表单提交时,签名的base64数据并未传入后端,导致$request->signature为空,解码后写入空文件(0KB)。
修复步骤:
- 在表单内部添加隐藏输入框,用于存储签名数据:
<form id="userForm"> <!-- 其他表单字段 --> <input type="hidden" name="signature" id="signature-input"> <!-- 提交按钮等 --> </form>
- 修改
showConfirmationAlert函数,在提交表单前将签名数据存入隐藏输入框:
function showConfirmationAlert() { if (isFormValid('userForm')) { // 新增:将签名数据存入隐藏字段 document.getElementById('signature-input').value = signaturePad.toDataURL(); Swal.fire({ title: 'Are you sure?', text: 'Do you want to submit this form?', icon: 'warning', showCancelButton: true, confirmButtonColor: '#3085d6', cancelButtonColor: '#d33', confirmButtonText: 'Yes' }).then((result) => { if (result.isConfirmed) { document.getElementById('userForm').submit(); Swal.fire( 'Success!', 'Your form has been submitted.', 'success' ); } }); } else { Swal.fire( 'Error!', 'Please fill out all required fields.', 'error' ); } }
2. 优化后端解码逻辑,增加错误处理
避免空数据或无效数据写入文件,在控制器中添加校验:
public function store(Request $request) { // 新增:校验签名数据是否存在 $request->validate([ 'signature' => 'required|string', ]); $signatureData = $request->signature; $fileName = time() . '.png'; $filePath = 'public/signatures/' . $fileName; // 优化解码逻辑,添加错误检查 $imageData = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $signatureData), true); if ($imageData === false) { return back()->withErrors(['signature' => '签名数据无效,请重新签名']); } Storage::put($filePath, $imageData); // 剩余代码保持不变... }
3. 验证存储目录权限
确保存储目录有正确的写入权限:
# 赋予存储目录读写权限 chmod -R 755 storage/ # 调整目录所属用户(根据服务器环境,比如Apache用www-data,Nginx用nginx) chown -R www-data:www-data storage/
4. 调试数据传输过程
- 前端调试:在
showConfirmationAlert中打印签名数据,确认格式正确:
console.log(signaturePad.toDataURL()); // 应输出类似:data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...
- 后端调试:在控制器中打印接收到的签名数据,确认非空:
dd($request->signature); // 应输出完整的data URL字符串
内容的提问来源于stack exchange,提问作者Farhan Hermansyah
相关产品推荐
相关产品推荐

