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

如何在Moodle中存储图片?自定义驾照上传模块开发求助

问题分析与解决方案

你的代码当前核心问题有两个:

  • 前端点击拍照后直接触发本地下载,未将图片数据传递到Moodle后端
  • 后端尝试使用create_file_from_url存储图片,但imgURL是前端JS变量,后端无法获取,且该方法仅适用于从外部URL拉取文件,不处理前端传来的base64格式图片

以下是修改后的完整方案:


1. 前端代码修改(替换原有JS和HTML)

移除下载按钮,通过AJAX将图片base64数据发送到后端:

修改后的HTML部分

echo '<body>
    <div id="container">
        <video autoplay="true" id="video"></video>
        <button id="btn">拍摄照片</button>
        <canvas id="canvas" class="hidden"></canvas>
    </div>
</body>';

修改后的JS部分

const video = document.querySelector('#video')
const btn = document.querySelector('#btn')
const canvas = document.querySelector('#canvas')

if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) {
    navigator.mediaDevices.getUserMedia({video: true})
    .then(stream => {
        video.srcObject = stream
    })
    .catch(error => {
        console.log('访问摄像头出错')
    })
}

btn.addEventListener('click', () =>{
    const width = video.videoWidth, height = video.videoHeight
    const context = canvas.getContext('2d')

    canvas.width = width
    canvas.height = height

    context.drawImage(video, 0, 0, width, height)
    // 移除base64前缀,只保留原始编码数据
    const imgData = canvas.toDataURL('image/png').replace('data:image/png;base64,', '')

    // 发送AJAX请求到后端
    fetch(window.location.href, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-Requested-With': 'XMLHttpRequest'
        },
        body: `action=uploadphoto&imgdata=${encodeURIComponent(imgData)}&id=<?php echo $id; ?>&sesskey=<?php echo sesskey(); ?>`
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            alert('照片上传成功!')
            btn.disabled = true // 可选:上传后禁用按钮
        } else {
            alert('上传失败:' + data.error)
        }
    })
    .catch(error => {
        console.error('上传出错:', error)
        alert('上传出错,请重试')
    })
})

2. 后端代码修改(view.php)

在require_capability之后添加上传处理逻辑,并删除原有无效的存储代码:

添加上传处理逻辑

// 处理照片上传请求
if (optional_param('action', '', PARAM_ALPHA) === 'uploadphoto' && confirm_sesskey()) {
    // 验证用户提交权限
    require_capability('mod/driverslicense:submit', $context);
    
    $imgdata = required_param('imgdata', PARAM_TEXT);
    // 解码base64数据
    $imgdata = base64_decode($imgdata);

    if ($imgdata === false) {
        echo json_encode(['success' => false, 'error' => '无效的图片数据']);
        die();
    }

    $fs = get_file_storage();

    // 构建文件存储信息:用用户ID作为itemid,确保每个用户照片独立存储
    $fileinfo = array(
        'contextid' => $context->id,
        'component' => 'mod_driverslicense',
        'filearea' => 'student_photos', // 自定义清晰的文件存储区域名
        'itemid' => $USER->id,
        'filepath' => '/',
        'filename' => 'drivers_license_' . $USER->id . '.png'
    );

    // 删除用户已存在的旧照片(可选)
    $existing_file = $fs->get_file(
        $fileinfo['contextid'],
        $fileinfo['component'],
        $fileinfo['filearea'],
        $fileinfo['itemid'],
        $fileinfo['filepath'],
        $fileinfo['filename']
    );
    if ($existing_file) {
        $existing_file->delete();
    }

    // 存储图片文件
    $file = $fs->create_file_from_string($fileinfo, $imgdata);

    if ($file) {
        echo json_encode(['success' => true]);
    } else {
        echo json_encode(['success' => false, 'error' => '图片存储失败']);
    }
    die();
}

删除原有无效代码

移除以下这段无法运行的代码:

$fs = get_file_storage();

// Prepare file record object
$fileinfo = array(
    'contextid' => $context->id, // ID of context
    'component' => 'mod_driverslicense',     // usually = table name
    'filearea' => 'driverslicense',     // usually = table name
    'itemid' => 0,               // usually = ID of row in table
    'filepath' => '/',           // any path beginning and ending in /
    'filename' => 'driverslicensefront.png'); // any filename


$fs->create_file_from_url($fileinfo, imgURL );

3. 额外配置(权限)

确保在模块的db/access.php中添加提交权限:

$capabilities = array(
    // ... 其他已有权限
    'mod/driverslicense:submit' => array(
        'captype' => 'write',
        'contextlevel' => CONTEXT_MODULE,
        'archetypes' => array(
            'student' => CAP_ALLOW
        )
    ),
);

内容的提问来源于stack exchange,提问作者Krupp J

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 09:20:40