remotefilesystem 是 composer 内部负责发起 http 请求、下载远程文件的核心类,只管“把 url 变成本地文件”,不处理依赖解析或自动加载;它自带重试、超时、多 url 回退、ssl 验证和缓存检查,不是通用 http 客户端,也不能绕过它直接用 curl 下载包。

RemoteFilesystem 是什么,不是什么
RemoteFilesystem 是 Composer 内部负责发起 HTTP 请求、下载远程文件(如 ZIP 包、packages.json)的核心类,位于 src/Composer/Util/RemoteFilesystem.php。它不是通用 HTTP 客户端,也不处理依赖解析或自动加载——只管“把 URL 变成本地文件”。它的输入是 URL 和目标路径,输出是写入成功的文件或抛出异常。
常见误解是把它当 file_get_contents() 的封装:错。它自带重试、超时、HTTP 状态码判断、多 URL 切换(比如 dist → source fallback)、SSL 验证和缓存检查。你不能绕过它直接用 cURL 下载包,否则会跳过校验、缓存、事件钩子等关键环节。
pre-file-download 事件如何真正介入下载流程
这个事件在 RemoteFilesystem::get() 执行前触发,由 PreFileDownloadEvent 实例携带 $url、$fileName 和 $options 参数。插件或脚本可安全修改这三者:
-
$event->setUrl():替换为镜像地址(如把https://api.github.com/.../archive/refs/tags/v1.2.3.zip换成https://ghproxy.com/...) -
$event->setOptions(['http' => ['header' => ['Authorization: Bearer xxx']]]):注入私有仓库认证头 -
$event->setFileName():仅限调试,生产环境慎用(影响后续校验路径)
注意:pre-file-download 不改变元数据获取逻辑(比如 packages.json 的拉取),只作用于 dist ZIP、source tarball、patch 文件等「最终产物」下载阶段。如果你发现事件没触发,大概率是因为该请求走的是 VCS 克隆(Git/Svn),而非 RemoteFilesystem ——VCS 下载由 VcsDownloader 处理,不发此事件。
并发下载时 RemoteFilesystem 怎么避免资源竞争
Composer 2.2+ 内置并发靠的是单进程内多个 CurlMulti 句柄复用,而非多线程或多进程。RemoteFilesystem 在并发模式下会被实例化多次,但所有实例共享同一个 CurlMulti 管理器(由 CurlRemoteFilesystem 封装)。关键点在于:
围绕关键发现、作用机制、临床相关性及研究局限性展开讨论。适用于撰写或优化任何生物医学论文的“讨论(Discussion)”部分——包括结果解读、与既往文献关联、阐释意外发现、界定研究局限性,以及撰写结论。当用户输入以下任一指令时也会自动触发该功能: - “write my discussion” - “help me discuss my findings” - “how do I compare to prior studies” - “write the limitations par
- 每个下载任务绑定独立的
curl_handle,但共用底层连接池(keep-alive 复用) - 临时文件名由
tempnam(sys_get_temp_dir(), 'composer')生成,避免写冲突 - SHA 校验和写入在下载完成后立即执行,不依赖文件锁 —— 因为每个包下载路径唯一,且校验失败会直接删临时文件重试
所以你看到 Downloading https://a.zip 和 Downloading https://b.zip 同时滚动,背后是同一组 cURL 句柄在轮询响应,不是并行 fork 出一堆 PHP 进程。这也是为什么调高 http-max-concurrent-downloads 到 20 却报 file_put_contents(/tmp/...): failed to open stream —— 临时目录空间或 inodes 耗尽,不是锁问题。
校验失败后 RemoteFilesystem 怎么重试
校验失败(比如 SHA256 不匹配)会触发完整重试链:先删掉已写入的临时文件,再回到 RemoteFilesystem::get() 开头,重新走 pre-file-download → 下载 → 校验。但注意,它不会无脑重试 3 次 —— 默认只重试 1 次(除非你显式配置 "retries": 3),且第二次尝试会跳过缓存、强制重新拉取。
真正决定是否重试的逻辑在 CurlDownloader::doDownload() 里,依据是错误类型:
- 网络层错误(CURL 错误码 28/7/6)→ 重试
- HTTP 404/401 → 不重试(认为是永久性错误)
- 校验失败 → 触发
InvalidPackageException,上层捕获后调用retryDownload()
这意味着:如果镜像源返回了损坏的 ZIP(常见于同步延迟或 CDN 缓存污染),Composer 会下载两次,第二次仍失败就报错退出,不会自动切备用 URL —— 备用 URL 切换只发生在首次下载 404 或 503 时,校验失败不算“不可达”,而是“内容错误”,得靠人工换镜像或清缓存。










