90%的“Permission denied”是属主非当前用户所致,需定位报错路径→查ls -ld归属→用sudo chown -R $USER:$USER修复,禁用chmod 777和sudo composer install。

报错路径就是病灶,别猜,直接查归属
Composer 报 Permission denied,90% 不是权限位(rwx)不够,而是文件或目录的属主(owner)不是当前用户。错误信息里明确写的路径,就是你要修的地方:vendor/、composer.lock、~/.composer/cache/,甚至 /tmp —— 它在哪,你就去哪查。
立刻执行这三行:
-
ls -ld vendor/—— 看第三列是不是$(whoami),若显示root root,就是它了 ls -ld composer.lockls -ld $(composer config --global cache-dir)
只要任意一行 owner 不是你自己,就确认是所有权错配。别碰 chmod -R 777,它会让 vendor/bin/phpunit 这类可执行文件在 CI 中被拒收,Git 也会报 ownership changed。
修复必须分范围:项目内 vs 全局缓存
不能一刀切。项目内问题和全局缓存污染要分开处理,否则修了这儿,坏了那儿。
- 项目内(
vendor/、composer.lock):sudo chown -R $USER:$USER vendor/ composer.lock(注意末尾不加/,否则可能漏掉文件) - 全局缓存被占:
sudo chown -R $USER:$USER $(composer config --global cache-dir) - 整个
~/.composer都属root:sudo chown -R $USER:$USER ~/.composer,再加固:chmod -R u+rw ~/.composer
sudo 只用于这一条 chown 命令,不是让你跑 sudo composer install —— 后者才是污染源头,会把新生成的 vendor/ 子目录全设为 root 所有,后续 composer update 可能只失败一半,连 chown -R 都救不回来。
Docker / CI / Windows 下的隐性坑
这些环境里权限问题往往不报在明面上,但一样卡住:
- Docker:宿主机 UID 是 1000,容器却以 UID 0(
root)运行 → 启动时加user:1000,或修复时用数字 UID:sudo chown -R 1000:1000 vendor/ - CI(如 GitHub Actions):默认非
root用户 → 开头加mkdir -p .composer-cache && chmod 700 .composer-cache,再设COMPOSER_CACHE_DIR="$PWD/.composer-cache" - Windows:报
Access is denied且错误出现在生成.bat文件时 → 大概率是杀软拦截,临时禁用 Windows Defender 实时防护,或改用 Git Bash 运行
嵌套污染最容易被忽略:一次 sudo composer install 可能让 vendor/ 下混进个别 root 所有子目录,ls -la vendor/ 才能发现;这种情况下 chown -R 仍有效,但如果 autoload.php 已损坏,删掉 vendor/ 和 composer.lock 重来反而更快。
vendor/bin 脚本执行不了?先看 shebang 再 chmod
Linux/macOS 下 vendor/bin/phpunit 报 Permission denied,根本原因是 ZIP 解压丢失可执行位,Git 也不跟踪权限变更。临时修复:chmod +x vendor/bin/phpunit;但下次 composer install 又会重置。
一劳永逸的做法是在 composer.json 加钩子:
"scripts": {
"post-install-cmd": "chmod +x vendor/bin/*",
"post-update-cmd": "chmod +x vendor/bin/*"
}
注意:这个方案仅对 POSIX 系统有效,Windows 忽略该命令。Windows 下报“不是内部或外部命令”,不是权限问题,而是 #!/usr/bin/env php 在 Windows 完全无效 —— 正确做法是显式调用:php vendor/bin/phpunit。
还有一种更隐蔽的情况:ls -l 显示已有 x 位,但执行仍报 No such file or directory。本质是 shebang 指向了错误的 PHP 路径。检查:head -n1 vendor/bin/phpunit 看是否为 #!/usr/bin/env php,再运行 which php 确认 CLI PHP 真实路径。如果 which php 无输出,说明 php 命令不在 $PATH 中 —— 这比权限问题更基础,也更常被忽略。


















