根本原因是文件属主为root而非当前用户,应执行sudo chown -r $user:$user修复vendor/、composer.lock及~/.composer等目录归属,禁用sudo composer install和chmod 777。

Composer 不建议用 root 运行,因为它会让 vendor/、~/.composer、缓存、autoload.php 等全部变成 root 所有,后续普通用户或 Web 服务器(如 www-data)根本无法读写 —— 不是“不能装”,而是“装完就废”。
file_put_contents(.../vendor/autoload.php): Permission denied 是什么信号
这不是权限数字太小,而是文件属主是 root,而当前执行 PHP 的用户(比如你的 shell 用户或 www-data)没有所有权。Linux/macOS 的访问控制第一关是 owner/group,不是 chmod。
- 运行
ls -ld vendor/,如果输出里第二列是root,问题就在这儿 - 同理检查
composer.lock、$(composer config --global cache-dir)、~/.composer - 哪怕只有一处是
root,下次composer update或dump-autoload就可能静默失败或报错
sudo composer install 为什么是污染源头
它不是临时提权,而是把整个 vendor/ 目录树、所有生成的 PHP 文件、bin 脚本、甚至 autoload_static.php 全部设为 root:root。后果立竿见影:
-
php artisan或./vendor/bin/phpunit在 CI 中直接报Permission denied(因为 shell 用户不是 root) - PHP-FPM 以
www-data身份运行时,连require vendor/autoload.php都失败 -
composer clear-cache卡住,因为缓存目录也归了 root - 你之后再怎么
chmod 755 vendor/都没用 —— 没所有权,改权限不生效
COMPOSER_HOME 指向 /root/.composer 就等于全局失效
当你执行 composer global require laravel/installer,它默认把 laravel 命令装进 $(composer config --global home)/vendor/bin。如果这个路径是 /root/.composer,那:
- 你个人终端能运行
laravel,只是因为你碰巧用sudo装过,且 PATH 包含了/root/.composer/vendor/bin - 但 cron、Git hooks、CI runner、PHP-FPM 全部看不到它 —— 它们不是 root,也无权读
/root - 修复方法不是加 sudo,而是提前设好:
export COMPOSER_HOME="$HOME/.composer",再重装
真正该用 sudo 的地方其实极少
只有两类操作需要临时提权,且目的明确:改归属,不是跑命令。
- 修复已污染路径:
sudo chown -R $USER:$USER vendor/ ~/.composer - 安装 Composer 二进制到系统级路径(如
/usr/local/bin)—— 但更推荐装到$HOME/bin并加进 PATH -
composer self-update若原二进制在/usr/local/bin/composer且属 root,才需 sudo;否则下载到用户目录即可
复杂点在于:权限问题从来不是孤立的。一个 sudo composer create-project 可能同时污染项目目录、composer.lock、vendor/ 和全局缓存 —— 修复得全查,漏一处,后面就反复踩坑。











