使用Cropper JS与class.upload.php时保存原图而非裁剪图的问题
问题:CropperJS裁剪后后端仍收到原图
在图片上传项目中使用Cropper JS和class.upload.php,所有功能看似正常,但PHP脚本保存的始终是未裁剪的原图。Chrome中查看文件输入框的src显示为裁剪后的图片,但后端接收的是原图。
前端HTML代码
<input type="file" class="upload-input" name="imageFile" accept="image/*" style="display:none;" id="input-1"> <div class="input-group mb-3"> <input type="text" class="form-control" id="filename-1" readonly placeholder="Upload your show image (Required)" style="width:100%;"> <div class="input-group-btn"> <button class="btn btn-outline-secondary upload-button" type="button" data-ratio="1/1">Select</button> </div> </div> <!-- Modal For Cropper --> <div class="modal fade photo-cropper" tabindex="-1" aria-labelledby="cropperModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="cropperModalLabel">Crop your image</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="upload-preview"> <img class="upload-image-preview" style="display: block; max-width: 100%;"> <div class="photo-cropper-controls"> <i class="fa fa-check-square" id="crop-confirm" aria-hidden="true"></i> <i class="fa fa-window-close" id="crop-cancel" aria-hidden="true"></i> </div> </div> </div> </div> </div> </div>
前端JS代码(原代码)
$(document).on('click', '.upload-button', function(e) { var ratio = $(this).data('ratio'); var activeInput = $('#input-1'); activeInput.click(); $(activeInput).change(function() { if(this.files && this.files[0]) { var imageFile = this.files[0]; var reader = new FileReader(); reader.onload = function (e) { $('.photo-cropper').modal('show'); $(document).on('shown.bs.modal', function (f) { $('.upload-image-preview').attr('src', e.target.result); $('.photo-cropper-controls').show(); $('.upload-image-preview').data('target', '#input-1'); $('.upload-image-preview').cropper('destroy'); $('.upload-image-preview').cropper({ aspectRatio: eval(ratio), viewMode: 1 }); }); } reader.readAsDataURL(imageFile); } }); }); $(document).on('click', '#crop-confirm', function() { var target = $('.upload-image-preview').data('target'); var imageData = $('.upload-image-preview').cropper('getCroppedCanvas', {maxWidth: 990}).toDataURL('image/jpeg'); $('.photo-cropper').modal('hide'); $(document).on('hidden.bs.modal', function (f) { $('.upload-image-preview').cropper('destroy'); }); $(target).attr('src', imageData); var filename = $(target).val().split('\\').pop(); $('#filename-1').val(filename); });
后端PHP代码
if(!empty($_FILES['imageFile'])) { require_once('assets/plugins/class.upload.php'); $handle = new upload($_FILES['imageFile']); if ($handle->uploaded) { $handle->file_safe_name = true; $handle->allowed = array('image/*'); $handle->image_ratio_y = true; $handle->image_x = 800; $handle->process('/upload/path/'); if ($handle->processed) { $image = $handle->file_dst_name; } } }
问题根源
你犯了一个常见误区:修改file输入框的src属性只是改变了预览图,并没有替换输入框实际要上传的文件数据。file输入的原始文件存在它的files数组里,src仅用于显示预览,不会影响表单提交时发送的内容,所以后端始终收到最初选择的原图。
解决方案
方案一:替换file输入的files数组(保留原表单提交逻辑)
将裁剪后的Canvas转为Blob,创建新的File对象替换原file输入的files数组:
修改#crop-confirm的点击事件代码:
$(document).on('click', '#crop-confirm', function() { var target = $('.upload-image-preview').data('target'); var $targetInput = $(target); // 获取裁剪后的Canvas var croppedCanvas = $('.upload-image-preview').cropper('getCroppedCanvas', {maxWidth: 990}); croppedCanvas.toBlob(function(blob) { // 从原文件获取文件名,保留后缀 var originalFilename = $targetInput.val().split('\\').pop(); var filename = originalFilename.replace(/\.[^/.]+$/, "") + '.jpg'; // 创建新的File对象 var croppedFile = new File([blob], filename, {type: 'image/jpeg'}); // 创建新的FileList替换原输入的files var newFileList = new DataTransfer(); newFileList.items.add(croppedFile); $targetInput[0].files = newFileList.files; // 更新文件名显示,不要修改file输入的src(浏览器安全限制) $('.photo-cropper').modal('hide'); $(document).one('hidden.bs.modal', function () { $('.upload-image-preview').cropper('destroy'); }); $('#filename-1').val(filename); }, 'image/jpeg', 0.9); // 0.9是JPEG质量,可调整 });
方案二:用FormData提交裁剪后的Blob(更灵活)
如果表单是AJAX提交,直接用FormData携带裁剪后的Blob,无需依赖原file输入:
修改表单提交逻辑(假设表单id为upload-form):
$('#upload-form').submit(function(e) { e.preventDefault(); var croppedCanvas = $('.upload-image-preview').cropper('getCroppedCanvas', {maxWidth: 990}); croppedCanvas.toBlob(function(blob) { var formData = new FormData(); formData.append('imageFile', blob, 'cropped-image.jpg'); // 其他表单字段可加入FormData // formData.append('otherField', $('#otherField').val()); $.ajax({ url: $(this).attr('action'), type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { console.log('上传成功'); }, error: function(xhr) { console.error('上传失败'); } }); }, 'image/jpeg', 0.9); });
PHP端代码无需修改,$_FILES['imageFile']结构与普通文件上传一致,class.upload.php可正常处理。
额外注意事项
- 避免重复绑定模态框
shown.bs.modal事件:原代码每次选择文件都会绑定一次,会导致多次初始化Cropper,建议改用one绑定或绑定前先解绑。 - 处理裁剪取消场景:清空file输入内容,避免提交原图。
内容的提问来源于stack exchange,提问作者PeteSE4
相关产品推荐
相关产品推荐

