You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 17:10:31