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

Docker容器中PHP脚本无法重命名CSV文件的问题排查求助

Docker容器中PHP脚本无法重命名CSV文件的问题排查求助

我最近在Docker容器部署的服务器上遇到个棘手的问题:我写了个PHP脚本,用户首次访问网站时会创建一个CSV日志文件(比如test_visit_events_unfinished.csv),用来记录实验相关数据;当用户完成实验后,前端JS会发一个application/x-www-form-urlencoded格式的POST请求到PHP脚本,理论上这时候脚本应该把那个未完成的CSV重命名为test_visit_events_finished.csv,但现在这个重命名操作根本没生效!

我的核心需求

  • 新创建的CSV默认命名为[任务名]_unfinished.csv格式
  • 当触发finish动作时,直接把对应的未完成文件重命名为[任务名]_finished.csv,完全不修改文件内容

我已经尝试过的操作

我反复在代码里加了文件存在性检查,但执行时没有抛出任何错误,反而生成了一个新的_finished.csv文件,原来的_unfinished.csv还好好待在目录里。我已经确认过日志目录的写入权限没问题,现在怀疑是不是文件本身的权限不够?想问问大家怎么才能给这个动态生成的文件自动分配必要的权限?

相关代码片段

PHP核心逻辑

日志目录的定义和三个动作(init/append/finish)的处理代码如下,路径是确认过正确的,init和append动作都能正常工作:

define('LOGDIR', '/var/www/html/logs');
define('LOGEXT', ".csv");

// Check if 'action' key exists in POST data
if (isset($_POST['action']) && $_POST['action'] === "init") {
    // Get name of log file, and ensure it's named with _unfinished by default
    $fid = $_POST['task'] ?? 'default_task'; // Default task if 'task' is missing
    $unfinishedFileName = $fid . "_unfinished" . LOGEXT; // Append _unfinished to the filename

    // Save data for the first time
    $header = "cursor,timestamp,xpos,ypos,event,xpath,attrs,extras" . PHP_EOL;
    file_put_contents(LOGDIR . "/" . $unfinishedFileName, $header . $info_data);
    
    // Notify recording script
    echo round(microtime(true) * 1000);

} else if (isset($_POST['action']) && $_POST['action'] === "append") {
    // Get the log file name, use _unfinished if not specified
    $fid = $_POST['task'] ?? 'default_task'; // Default task if 'task' is missing
    $unfinishedFileName = $fid . "_unfinished" . LOGEXT; // Append _unfinished to the filename

    // Don't write blank lines
    if (trim($info_data)) {
        file_put_contents(LOGDIR . "/" . $unfinishedFileName, $info_data, FILE_APPEND);
    }

} else if (isset($_POST['action']) && $_POST['action'] === "finish") {
    // Get the log file name without the suffix
    $fid = $_POST['taskname'] ?? 'default_task'; // Default task if 'taskname' is missing
    $unfinishedFileName = $fid . "_unfinished" . LOGEXT; // File with _unfinished suffix
    $finishedFileName = $fid . "_finished" . LOGEXT; // File with _finished suffix

    $originalFilePath = LOGDIR . "/" . $unfinishedFileName;
    $finishedFilePath = LOGDIR . "/" . $finishedFileName;

    if (file_exists($originalFilePath)) {
        // Check if the _finished file already exists to avoid overwriting
        if (!file_exists($finishedFilePath)) {
            // Rename the file to mark it as finished
            if (!rename($originalFilePath, $finishedFilePath)) {
                exit('Failed to mark file as finished');
            }
            echo 'File marked as finished';
        } else {
            exit('A file with _finished already exists');
        }
    } else {
        exit('Original _unfinished file not found');
    }
}

目前的问题是:执行finish动作后,目录里确实出现了_finished.csv文件,但原来的_unfinished.csv并没有被重命名(还在原地),感觉像是新建了一个空的完成文件,而不是重命名原文件。

Docker权限配置

我在Dockerfile里设置了目录权限,确保www-data用户能读写日志目录:

RUN usermod -u 1000 www-data && \
    groupmod -g 1000 www-data && \
    chown -R www-data:www-data /var/www/html && \
    chmod -R 755 /var/www/html/logs

前端JS请求代码

触发finish动作的JS函数如下,用来传递要重命名的文件名:

async function finishExperiment(eventFile) {
    console.log("Now saving to: ", eventFile);
    // Send a request to the server to mark the log file as "finished"
    try {
        const response = await fetch("static/php/writeEvents.php", {
            method: "POST",
            headers: { 
                "Content-Type": "application/x-www-form-urlencoded"  // Set content type to 'x-www-form-urlencoded'
            },
            body: new URLSearchParams({
                action: "finish",         // The action type to perform
                taskname: eventFile       // The filename to mark as finished
            })
        });

        // Handle the response
        const data = await response.text();  // Assuming the server sends a plain text message
    } catch (error) {
        console.error("Error finishing the experiment:", error);
    }
}

有没有大佬能帮我看看问题出在哪?是不是权限的问题?或者是我代码里的某个细节忽略了?

备注:内容来源于stack exchange,提问作者zahntheo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.15 09:39:34