直接运行ls -l vendor/bin/可快速判断脚本执行权限是否生效,若第一列无x位(如-rw-r--r--)则不可执行;即使有x位但报“No such file or directory”,需检查shebang路径与which php结果是否匹配。

检查 vendor/bin 下脚本的执行权限是否生效
直接运行 ls -l vendor/bin/ 是最快判断方式。如果看到类似 -rw-r--r--(无 x 位),说明脚本没有执行权限,vendor/bin/phpunit 这类命令必然报 Permission denied。重点看第一列开头的字符:有 x 才代表可执行;- 或 ? 都不行。
常见误判是只看文件名后缀(如 .php)或以为 shebang 行存在就等于可运行——其实 Linux/macOS 完全不认后缀,只认权限位。
- 运行
head -n1 vendor/bin/phpunit确认首行是#!/usr/bin/env php(否则即使有x也找不到解释器) - 运行
which php看 CLI PHP 是否在 PATH 中;若为空,env php就会失败 - 若
ls -l显示-rwxr-xr-x却仍报No such file or directory,大概率是 shebang 指向了不存在的路径(比如#!/usr/local/bin/php,但实际在/opt/php/bin/php)
确认当前用户对 vendor/ 目录是否有写权限
Composer install 失败时抛出 file_put_contents(./vendor/autoload.php): failed to open stream: Permission denied,本质不是脚本没权限,而是它连 vendor/ 目录都创建不了——因为当前用户对该目录无写权限。
先用 ls -ld vendor/ 查归属和权限。如果显示 drwxr-xr-x 2 root root,而你当前是普通用户,那所有后续操作都会被拒。
- 不要用
sudo composer install—— 它会让整个vendor/归属变成root,之后再也没法用普通用户更新或删包 - 正确做法是归还所有权:
sudo chown -R $(whoami):$(whoami) vendor/ - 若
vendor/不存在,错误可能出在父目录(比如项目根目录),同样用ls -ld .检查
验证 Composer 脚本钩子是否真在运行
post-install-cmd 类脚本不执行,常被误认为“权限问题”,其实是 Composer 根本没触发它。默认情况下,生产环境部署时会跳过所有脚本(除非显式启用)。
运行 composer install --verbose,观察输出里有没有 Executing command (CWD): chmod +x vendor/bin/* 这类日志。没有,说明钩子没注册或被禁用。
- 检查
composer.json的scripts段是否正确定义,且 key 名是post-install-cmd(不是post-install或拼错) - 部署时若加了
--no-scripts或COMPOSER_NO_INTERACTION=1环境变量,钩子会被强制跳过 - Windows 下该钩子会被忽略(
chmod命令无效),但不会报错,容易误以为“成功运行”
区分 Windows 下的“权限拒绝”和“命令不可识别”
Windows 报 'phpunit' is not recognized as an internal or external command,和 Linux 的 Permission denied 完全是两回事。前者不是权限问题,是系统根本不知道这个命令在哪,也不理解 #!/usr/bin/env php。
此时 chmod +x、PowerShell 的 Set-ExecutionPolicy 全部无效——Windows 不读 Unix 权限位,也不支持 shebang。
- 最稳方案:
php vendor/bin/phpunit显式调用(绕过 shell 查找) - 手动补
.bat包装器:在vendor/bin/下新建phpunit.bat,内容为@php "%~dp0phpunit" %* - 换用自带
.bat的工具,比如laravel/installer生成的artisan,它本身就有artisan.bat
真正容易被忽略的是:权限检查必须分层做——先确认目录可写,再确认脚本可执行,最后确认解释器路径有效。三者缺一,vendor/bin/ 下的命令就跑不起来,而且错误信息往往指向最表层现象,掩盖真实断点。











