PHP图片上传裁剪后显示(同页AJAX)及异常修复
问题分析与解决方案
先拆解你遇到的两个核心问题,再给出针对性的修复方案:
问题根源
1. 0字节空文件生成的原因
- 变量作用域错误:你定义的
display_image()函数无法访问if(isset($_POST['image']))块里的$image_name变量,导致输出的图片路径变成uploads/,浏览器请求这个目录时会间接触发空文件生成; - 重复提交问题:页面刷新时,浏览器可能会重复发送上次的POST请求,若此时没有有效图片数据,
base64_decode($image)会得到空内容,写入文件就会生成0字节的无效文件; - 代码执行时机:你的PHP代码直接嵌入页面,每次加载都会运行,即使没有POST请求,变量未定义的问题也会间接引发异常。
2. 上传后图片无法显示的原因
display_image()函数中$image_name未在作用域内定义,生成的图片路径无效;- 前端AJAX成功回调仍在使用base64格式的图片,没有利用服务器返回的实际文件URL。
具体修复步骤
步骤1:修正PHP逻辑,解决变量作用域与空文件问题
调整PHP代码,添加数据验证,确保只有有效POST请求才处理图片,同时确保uploads目录存在:
<?php session_start(); // 开启会话用于处理重定向 if(isset($_POST['image'])){ $image = $_POST['image']; // 验证图片数据格式 if (strpos($image, 'data:image/') !== 0) { echo json_encode(['status' => 'error', 'message' => '无效的图片数据']); exit; } list($type, $image) = explode(';',$image); list(, $image) = explode(',',$image); $image = base64_decode($image); // 验证base64解码是否成功 if ($image === false) { echo json_encode(['status' => 'error', 'message' => '图片解码失败']); exit; } $image_name = time().'.png'; $upload_path = 'uploads/'.$image_name; // 确保uploads目录存在 if (!file_exists('uploads')) { mkdir('uploads', 0755, true); } file_put_contents($upload_path, $image); // 使用Post/Redirect/Get模式避免重复提交 $_SESSION['uploaded_image'] = $upload_path; header('Location: ' . $_SERVER['PHP_SELF']); exit; } ?>
步骤2:修改前端AJAX,使用服务器返回的图片URL
调整前端代码,移除base64显示逻辑,改用服务器实际文件路径:
$('.btn-upload-image').on('click', function () { resize.croppie('result', { type: 'canvas', size: 'viewport' }).then(function (img) { $.ajax({ type: "POST", url: window.location.href, data: {"image":img}, dataType: 'json', error: function() { // 重定向后AJAX会收到302响应,这里刷新页面显示图片 window.location.reload(); } }); }); });
步骤3:添加页面内的图片显示逻辑
在页面顶部添加代码,通过会话存储的路径显示上传后的图片:
<div class="container"> <?php if (isset($_SESSION['uploaded_image'])) { echo '<div class="mb-3">上传预览:<img src="' . $_SESSION['uploaded_image'] . '" width="70" height="70" ></div>'; unset($_SESSION['uploaded_image']); // 显示后清除会话,避免重复显示 } ?> <!-- 原有页面内容 --> </div>
步骤4:移除无效的display_image()函数
原函数因变量作用域问题无法正常工作,且我们已通过会话和AJAX实现图片显示,直接移除该函数及相关调用即可。
完整修正后的代码
<?php session_start(); if(isset($_POST['image'])){ $image = $_POST['image']; if (strpos($image, 'data:image/') !== 0) { echo json_encode(['status' => 'error', 'message' => '无效的图片数据']); exit; } list($type, $image) = explode(';',$image); list(, $image) = explode(',',$image); $image = base64_decode($image); if ($image === false) { echo json_encode(['status' => 'error', 'message' => '图片解码失败']); exit; } $image_name = time().'.png'; $upload_path = 'uploads/'.$image_name; if (!file_exists('uploads')) { mkdir('uploads', 0755, true); } file_put_contents($upload_path, $image); $_SESSION['uploaded_image'] = $upload_path; header('Location: ' . $_SERVER['PHP_SELF']); exit; } ?> <html lang="en"> <head> <title>PHP and jQuery - Crop Image and Upload using Croppie plugin</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.1/css/bootstrap.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.2/croppie.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/croppie/2.6.2/croppie.js"></script> <meta name="csrf-token" content="{{ csrf_token() }}"> </head> <body> <div class="container"> <?php if (isset($_SESSION['uploaded_image'])) { echo '<div class="mb-3">上传预览:<img src="' . $_SESSION['uploaded_image'] . '" width="70" height="70" ></div>'; unset($_SESSION['uploaded_image']); } ?> <div class="card" style="max-height: 500px;"> <div class="card-header bg-info">PHP and jQuery - Crop Image and Upload using Croppie plugin</div> <div class="card-body"> <div class="row"> <div class="col-md-4 text-center"> <div id="upload-demo"></div> </div> <div class="col-md-4" style="padding:5%;"> <strong>选择图片裁剪:</strong> <input type="file" id="image"> <button class="btn btn-success btn-block btn-upload-image" style="margin-top:2%">上传图片</button> </div> <div class="col-md-4"> <div id="preview-crop-image" style="background:#9d9d9d;width:300px;padding:50px 50px;height:300px;"></div> </div> </div> </div> </div> </div> <script type="text/javascript"> var resize = $('#upload-demo').croppie({ enableExif: true, enableOrientation: true, viewport: { width: 200, height: 200, type: 'circle' }, boundary: { width: 300, height: 300 } }); $('#image').on('change', function () { var reader = new FileReader(); reader.onload = function (e) { resize.croppie('bind',{ url: e.target.result }).then(function(){ console.log('图片绑定完成'); }); } reader.readAsDataURL(this.files[0]); }); $('.btn-upload-image').on('click', function () { resize.croppie('result', { type: 'canvas', size: 'viewport' }).then(function (img) { $.ajax({ type: "POST", url: window.location.href, data: {"image":img}, dataType: 'json', error: function() { window.location.reload(); } }); }); }); </script> </body> </html>
额外注意事项
- 确保服务器对
uploads目录有写入权限,否则图片无法保存; - 若使用Laravel框架(看到你用到了
{{ csrf_token() }}),建议将上传逻辑移至控制器,更符合框架规范; - 可添加文件大小、类型验证,防止上传恶意文件或过大图片。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

