答案是OpenSSL配置冲突导致TLS握手卡死。需运行php -r "print_r(openssl_get_cert_locations());"确认curl.cainfo与openssl.cafile指向同一cacert.pem绝对路径,且路径全英文无空格;改完php.ini后必须重启终端生效。

Composer install 挂起在 “Loading composer repositories” 或卡在 SSL 握手阶段,大概率不是网络慢,而是 OpenSSL 配置冲突——比如 curl.cainfo 和 openssl.cafile 指向不同证书文件,或其中一个为空、路径不存在、权限不可读。
确认是否真存在 OpenSSL 配置冲突
PHP 启动时若发现 curl.cainfo 和 openssl.cafile 不一致,某些 OpenSSL 版本(尤其是 Windows 下的 1.1.x)会静默降级为阻塞式 TLS 握手,导致 Composer 卡住不动,也不报错。
- 运行
php -r "print_r(openssl_get_cert_locations());",看default_cert_file和curl_ca_bundle是否指向同一文件;不一致就危险 - 检查
php --ini显示的 php.ini 路径,打开它,确认两行配置都存在且值相同:curl.cainfo = "/path/to/cacert.pem"openssl.cafile = "/path/to/cacert.pem" - 如果其中一行被注释、写成
""、或路径含中文/空格但没加引号,就会触发冲突
Windows 下 DLL 与 CA 文件路径混合失效
Windows 环境最常出现“配置看起来对,但就是卡住”的情况,根源是 PHP 加载 php_openssl.dll 时依赖的 libssl-1_1-x64.dll 和 CA 文件之间存在符号链路断裂。
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 确保
php_openssl.dll所在目录(即extension_dir)下,同时存在libssl-1_1-x64.dll和libcrypto-1_1-x64.dll -
cacert.pem必须放在**全英文、无空格路径**下(如C:\php\ssl\cacert.pem),不能放在Documents或桌面 - 如果用的是 PHP 官方 ZIP 包,别用
php.ini-development或php.ini-production的默认副本——它们可能漏配openssl.cafile
Linux/macOS 上 OpenSSL 库版本与 PHP 编译不匹配
不是“有没有 openssl”,而是 PHP 运行时加载的 OpenSSL 动态库和编译时链接的不一致,会导致 TLS 握手卡在 SNI 阶段(尤其访问 CDN 后的镜像站时)。
- 运行
ldd $(php -r 'echo dirname((new ReflectionExtension("openssl"))->getFilename());')/openssl.so | grep ssl,确认输出的 libssl 路径和openssl version -d一致 - 若不一致(例如 PHP 用的是
/usr/local/ssl/lib,而系统装的是/usr/lib/x86_64-linux-gnu/libssl.so.1.1),需重装 PHP 并指定--with-openssl=/usr - Docker 中用 Alpine 镜像时,musl libc 不兼容 glibc 编译的 OpenSSL 扩展,直接换
debian:slim基础镜像更省事
临时验证:绕过配置冲突而非绕过 SSL
不要用 COMPOSER_DISABLE_TLS=1 或 --no-verify-peer,那只是掩盖问题。真正要验证是不是配置冲突,就强制统一 CA 路径:
- 下载最新
cacert.pem到已知路径,例如/tmp/cacert.pem - 临时覆盖配置运行:
php -d curl.cainfo=/tmp/cacert.pem -d openssl.cafile=/tmp/cacert.pem $(which composer) install - 如果这下不卡了,说明原配置确实冲突;回去改 php.ini,别留空值、别混用路径、别跨驱动器
最容易被忽略的一点:改完 php.ini 后,CLI 模式下必须新开终端(不是 php restart),否则环境变量和 ini 缓存仍沿用旧状态——这也是为什么很多人“明明改了却没用”。

















