Composer脚本无法原生拦截执行并等待用户确认,因它默认非交互且不透传stdin;需用bash脚本包装并在开头调用read实现确认,或PHP脚本中先校验posix_isatty(STDIN)再fgets读取,CI环境则自动跳过。

Composer脚本如何拦截执行并等待用户确认
Composer 本身不提供交互式确认机制,composer run 或脚本执行默认是非交互的。想在脚本真正运行前弹出“是否继续?”,必须绕过 Composer 的纯 CLI 模式,改用 shell 层级的交互控制。
用 shell 命令包装 script 并捕获用户输入
最直接有效的方式是把实际逻辑写成独立脚本(如 bin/deploy.sh),然后在 composer.json 的 scripts 里调用它,并在脚本开头做确认 —— 这样能完全掌控 stdin 行为。
常见错误是试图在 PHP 脚本里用 fgets(STDIN):Composer 在非 tty 环境下会静默失败或直接跳过,CI/IDE 终端也可能没正确暴露 STDIN。
- 在
composer.json中定义:"scripts": { "deploy": "bash bin/deploy.sh" } -
bin/deploy.sh开头加确认逻辑:#!/bin/bash read -p "⚠️ 即将执行部署,确认继续?(y/N): " -n 1 -r echo if [[ ! $REPLY =~ ^[Yy]$ ]]; then echo "已取消" exit 1 fi # 后续真实操作,比如 php artisan migrate && npm run build
- 确保脚本可执行:
chmod +x bin/deploy.sh
PHP 脚本中安全读取用户输入的条件
如果坚持用 PHP 写脚本(比如复用 Laravel Command 类),必须先验证 STDIN 是否可用且关联到终端,否则会卡住或返回空字符串。
- 检查是否在交互环境:
if (!function_exists('posix_isatty') || !posix_isatty(STDIN)) { die("非交互环境,跳过确认"); } - 读取时设超时和 trim:
$input = trim(fgets(STDIN, 2));(避免因换行符误判) - 不要依赖
readline():Windows 下常不可用,且 Composer 进程可能未启用 readline 扩展 - CI 场景(GitHub Actions、GitLab CI)默认无 TTY,
posix_isatty(STDIN)会返回false,此时应自动跳过确认或强制设为 yes/no
为什么不能用 composer.json 的 "prompt" 字段
Composer 官方没有 prompt 字段。有人误以为 config.prompt 或插件能实现,但那是针对仓库认证或私包源配置的,和运行时脚本无关。所有试图在 scripts 值里内联 read 或 php -r "fputs..." 的写法,在 Windows、Docker、某些 IDE 终端里都会失效 —— 因为 Composer 启动子进程时不一定透传 stdin 句柄。
真正的边界在于:Composer 是命令协调器,不是交互运行时。需要交互,就得把控制权交还给 shell 或明确启动一个带 TTY 的子进程。











