不能直接在 composer.json 的 post-install-cmd 中执行 shell 命令,因其无来源校验、无环境隔离、易被恶意包劫持;应改用 php 脚本实现最小权限操作,并通过存在性检查、幂等标记和 ci 环境判断确保安全。

直接在 composer.json 里写 "scripts" 钩子执行敏感操作(比如 chmod、chown、写入配置)是危险的——Composer 默认以当前用户权限运行,若项目被第三方包污染或本地环境被入侵,钩子可能被劫持执行任意命令。
为什么不能用 post-install-cmd 直接调用 shell 命令
Composer 的脚本钩子默认启用 bin-dir 和 vendor-dir 的自动路径解析,但 post-install-cmd 等钩子会无条件执行字符串命令,不校验来源、不隔离环境、不验证参数。常见风险包括:
- 第三方包在
composer.json中声明恶意scripts,通过依赖传递触发 -
exec('chmod -R 777 storage/')类命令一旦写死,上线后无法审计或回滚 - 钩子中引用未定义环境变量(如
$APP_ENV),导致本地能跑、CI 失败
用 PHP 脚本替代 shell 命令做最小权限操作
把逻辑抽成独立 PHP 文件,由 Composer 调用,好处是:可加类型检查、可读取 composer.lock 校验依赖来源、能用 is_executable() 等函数做前置判断。
示例:在项目根目录建 scripts/secure-post-install.php:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
<?php // scripts/secure-post-install.php
if (PHP_SAPI !== 'cli') {
exit(1);
}
$lock = file_get_contents(__DIR__ . '/composer.lock');
if (empty($lock)) {
throw new RuntimeException('composer.lock missing — aborting secure install');
}
// 只允许修改已知目录,且必须存在
$dirs = ['storage', 'bootstrap/cache'];
foreach ($dirs as $dir) {
if (!is_dir($dir)) {
mkdir($dir, 0755, true);
}
chmod($dir, 0755); // 不用 777
}
然后在 composer.json 中声明:
"scripts": {
"post-install-cmd": [
"php scripts/secure-post-install.php"
]
}
避免钩子被意外触发的三个硬性约束
Composer 钩子会在 install、update、require 时都执行,而你通常只希望它在首次部署时运行。必须加控制:
- 检查
vendor/autoload.php是否已存在 —— 若存在,说明不是首次安装 - 用
file_exists('.installed')做幂等标记,成功后 touch 该文件 - CI 环境下禁用钩子:
"post-install-cmd": ["@php -r \"if (getenv('CI')) exit;\" && php scripts/secure-post-install.php"]
真正难的是权限边界和上下文感知:钩子不知道自己运行在 Docker 容器还是宿主机,也不知道 storage/ 是挂载卷还是本地目录。这些没法靠一行命令解决,得靠脚本里显式探测 is_writable()、posix_getuid()、getenv('COMPOSER_HOME') 才能安全落地。










