导读:本期聚焦于小伙伴创作的《如何在 Nginx 服务器上使用 PHP 安全写入 JSON 文件》,敬请观看详情。把用户提交的数据存成 JSON 文件时,若权限配置不当或缺少校验,极易被绕过写入恶意内容甚至覆盖系统文件。在 Nginx 搭配 PHP 的运行环境下,安全写入不仅要确认目录归属与 open_basedir 限制,还要对输入做严格过滤、用临时文件加原子替换避免并发损坏。不少人直接调用 file_put_contents 拼接路径,结果造成目录遍历漏洞。正确的做法是先定义可控存储目录,用 json_encode 前清洗数据结构,再借助锁机制与重命名保证一致性,同时设置好 Nginx 的 location 拒绝外部直接访问写入目录。

在 Nginx 与 PHP 共同运行的 Web 环境中,让 PHP 把业务数据以 JSON 格式持久化到文件,是很多接口和小型后台常用的做法。但这种看起来简单的写文件动作,如果忽略权限、路径校验和并发处理,就会变成服务器被篡改的入口。本文从实际部署角度,说明如何既完成写入又避免常见安全问题。

如何在 Nginx 服务器上使用 PHP 安全写入 JSON 文件

一、明确 Nginx 与 PHP 的权限边界

大多数 Nginx 搭配 PHP-FPM 的方案里,Nginx 进程和 PHP-FPM 进程往往使用不同系统用户。Nginx 一般用 www-data 或 nginx 用户运行,而 PHP-FPM 的子进程池也可以配置成同样的用户,或者单独的用户。写入 JSON 文件的权限,本质上取决于 PHP-FPM 进程用户对目标目录是否有写权限,而不是 Nginx 是否有写权限。

如果目录归属混乱,比如把存储目录设成 777 权限,任何本地用户或异常进程都能修改其中的 JSON 文件。更合理的做法是新建一个专用目录,例如 /var/www/storage/json,将其拥有者设为 PHP-FPM 的运行用户,权限设为 750 或 700。同时,在 php.ini 中通过 open_basedir 限制 PHP 只能访问指定前缀路径,防止脚本被诱导写出到系统关键位置。

二、避免路径拼接导致目录遍历

很多漏洞来源于直接用用户输入拼文件路径。例如用用户提交的 filename 参数拼接成写入地址,攻击者可传入 ../../etc/cron.d/evil 这类字符串,绕过预期目录。安全写入的第一步,是永远使用固定基目录,并对用户侧传入的文件标识做白名单过滤。

下面示例展示如何安全地构造目标路径:

<?php
$baseDir = '/var/www/storage/json/';
// 仅允许字母数字下划线作为文件标识
if (!preg_match('/^[a-zA-Z0-9_]+$/', $_POST['name'] ?? '')) {
    die('invalid name');
}
$fileName = $baseDir . $_POST['name'] . '.json';
// 确认最终路径仍在基目录内
$realBase = realpath($baseDir);
if (strpos(realpath(dirname($fileName)), $realBase) !== 0) {
    die('path traversal');
}
?>

上述代码先校验名称格式,再用 realpath 比对实际目录前缀,双重保险阻止遍历。即便后续逻辑变化,也不会把文件写到基目录之外。

三、数据校验与 JSON 编码

写入前必须对数据结构做清洗。若直接把 $_POST 数组交给 json_encode,可能包含意料之外的字段,或被插入构造好的嵌套结构影响前端解析。推荐先定义允许字段,再组装干净数组。

同时应注意 json_encode 的选项错误。默认情况下中文会被编码成 unicode,若希望可读可加 JSON_UNESCAPED_UNICODE。还要检查返回值是否为 false,避免把 false 当成字符串写入。

<?php
$allowed = ['uid' => 1, 'score' => 1];
$data = [];
foreach ($allowed as $k => $type) {
    if (isset($_POST[$k])) {
        $data[$k] = $type === 1 ? (int)$_POST[$k] : $_POST[$k];
    }
}
$json = json_encode($data, JSON_UNESCAPED_UNICODE);
if ($json === false) {
    die('encode error');
}
?>

经过类型强制转换和字段限制,生成的 JSON 内容可控,也不会因特殊字符产生解析异常。这一步是安全写入的内容层防护。

四、原子写入与并发控制

直接用 file_put_contents 写目标文件,在并发请求下可能读到写了一半的内容。更稳妥的方式是先写临时文件,再 rename 到正式路径。rename 在同类文件系统上是原子操作,外部读到的要么旧版要么新版。

配合 flock 还能避免多个 PHP 进程同时写同一文件。下面给出完整安全写入函数示例:

<?php
function safe_write_json($file, $json) {
    $tmp = $file . '.' . uniqid() . '.tmp';
    $fp = fopen($tmp, 'w');
    if (!$fp) return false;
    flock($fp, LOCK_EX);
    fwrite($fp, $json);
    fflush($fp);
    flock($fp, LOCK_UN);
    fclose($fp);
    return rename($tmp, $file);
}

safe_write_json($fileName, $json);
?>

该函数先落盘临时文件并加独占锁,写完释放锁再原子替换。即使中途崩溃,也只会留下临时文件,不会影响原 JSON 可用性。定期清理残留 tmp 即可。

五、Nginx 层屏蔽外部访问

JSON 存储目录不应被浏览器直接下载,否则可能泄露业务数据。在 Nginx 配置中,对该 location 拒绝访问:

location /storage/json/ {
    deny all;
    return 403;
}

这样即使有人猜到文件路径,Nginx 也会直接返回 403。结合 PHP 侧基目录限制,形成双层的存储隔离。注意该配置要放在 server 块内并重新加载生效。

六、综合建议

总结来看,在 Nginx 服务器上用 PHP 安全写 JSON 文件,核心在于:固定且受限的目录、严格的输入与路径校验、干净的数据编码、原子且加锁的写入方式,以及 Nginx 对存储路径的拒绝访问。把这些环节串起来,就能在普通业务场景下规避绝大部分写文件相关的安全风险。

实际项目中还可把 JSON 写入封装成类,统一处理异常和日志。当业务增长后,若文件并发量变大,再考虑迁移到 SQLite 或 Redis,但上述安全原则依然适用。

NginxPHPJSON_file_write修改时间:2026-08-02 15:24:28

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。