我在2014年写的那个临时PHP修复方案已经有近2000万次安装了。今天我正式宣布弃用它。
My temporary PHP fix from 2014 has nearly 20M installs. Today I'm deprecating it

原始链接: https://jakeasmith.com/blog/http-build-url/

十二年前,作者在一次公司迁移期间编写了一个 174 行的 PHP “垫片”代码,用以复制 `http_build_url()` 的功能。这段代码本意是作为临时解决方案,但被上传到 Packagist 后意外地变得无处不在,获得了近 2000 万次安装,并支撑着 WordPress 插件和 Debian 软件包等主要平台。 最近,作者重新审视了该项目,发现了一个严重的漏洞——在特定条件下,该代码会意外地从 URL 中删除字母“a”。尽管该软件包的使用范围极广,作者还是正式弃用了它。作者没有选择修复漏洞或将项目移交给新的维护者(作者警告称此举可能会引入安全风险),而是决定彻底废弃该库。 作者鼓励用户迁移到现代的、符合标准的替代方案,例如 PHP League 的 URI 库,或是 PHP 8.5 中即将推出的原生 URI API。这一决定标志着这个长期存在的非预期工具正式终结,也提醒了人们“临时”代码是如何深深植入互联网基础设施的。

开发者 Jake Smith 宣布弃用他在 2014 年创建的一个 PHP polyfill,该项目出人意料地积累了近 2000 万次安装。该工具最初旨在作为 `http_build_url` 的临时修复方案,却被沿用了十多年。Smith 认为现在是时候结束该项目了,并指出社区和现代 PHP 版本中已有更好的替代方案。 这则发布在 Hacker News 上的公告引发了开发者们怀旧的讨论。用户们反思了“临时”代码最终成为基础设施永久组成部分这一常见现象,另一些人则对该项目长期的实用价值向 Smith 表示祝贺。Smith 对社区的支持表示感谢,并表示愿意继续回答关于该 polyfill 漫长且出人意料的生命周期的问题。
相关文章

原文

Twelve years ago, I wrote 174 lines of PHP as a stopgap for AOL’s content management system. I put it on Packagist in case anyone else needed the same patch, and somehow it’s been installed nearly 20 million times since. Today I marked it deprecated.

A temporary shim

In 2014, we were in the middle of upgrading AOL’s CMS from PHP 5.2 to 5.3. Part of that upgrade was dropping version 1 of the pecl_http extension, which gave us a function called http_build_url(). A CMS deals with a lot of URLs, and ours called that function in dozens of places. I wasn’t touching those. The function seemed straightforward enough to reproduce, so I wrote my own http_build_url(), defined only if the real one didn’t already exist. The old code never knew anything had changed.

Composer was just taking off at the time, which made sharing it easy. I figured it would earn its keep for a year or two, until the PHP community moved on to something better.

That’s a lot of installs

Well, it wasn’t temporary. It’s been installed from Packagist nearly 20 million times, and it still picks up over 400,000 installs a month.

Packagist install statistics for jakeasmith/http_build_url as of September 15, 2026: 19,864,271 total installs and 401,308 in the last 30 days. Daily installs climb steadily from near zero in 2014 to about 13,000 a day in 2026.

And it turns out Composer is only part of the picture. WPML, the market-leading multilingual plugin for WordPress, bundles the polyfill directly in its codebase, and WPML says it’s installed on over 1.5 million sites. The domain-name library idna-convert depends on it too, which is how it ships inside the source of SPIP, a French content management system, and how it ended up packaged in Debian and Ubuntu. Between all of them, there’s a pretty good chance you’ve visited a website that is still running my code.

I never imagined it would go this far.

Coming back to it

I didn’t grasp how far it had spread until a few months ago, when I looked at the package for the first time in years. I knew it had users. By 2021 I’d been out of PHP for a while, and the downloads were surprising enough that I asked for a new maintainer. Three people offered. Shortly after I asked, we lost a family member unexpectedly, and it turned our world upside down for a while. I never followed up, and that’s on me. By the time things settled, other goals had taken over, and I forgot about the package for years.

Along with the numbers, there were a handful of GitHub issues, including one where joining a path onto a URL with a trailing slash strips every letter “a” out of the path. So much for straightforward. Under a comment that reads // Workaround for trailing slashes, my code tacks an “a” onto the path so there’s always a last segment to cut off, then cuts it off with a find-and-replace. When the path ends in a slash, that last segment is just the “a”, and the find-and-replace takes every other “a” in the path with it. I can’t believe the bug went unnoticed for as long as it did.

So I had a decision to make. I could dive back into PHP after almost a decade away, hand the package to one of the people who’d offered, or let it keep sitting there.

None of the above

It was always meant to be temporary, so I’m retiring it. The PHP League’s URI library has been the community’s answer for years, and PHP 8.5 now ships a standards-compliant URI API in the language itself (thanks to jawira for pointing me at it). Both are better than a 174-line shim from 2014. Maintaining the package would only delay the move everyone should be making, and handing it over would add a risk on top of that. I don’t doubt anyone who offered, and ozh has kept a fork going for YOURLS. But a widely installed package with a new maintainer nobody downstream has vetted is exactly what attackers look for. Veritasium’s video on the xz Utils backdoor is the best telling I’ve seen of how that plays out.

The package will keep installing, but it won’t get new fixes, including for the missing-”a” bug. After this long without a change, even a one-line fix could have unintended consequences for someone, with no one around to support it. The README shows how to switch.

I wrote this code to ease a painful migration, for myself and anyone else going through the same one. Thank you to everyone who sent a pull request or offered to take it over, and to the people who kept filing issues long after I’d stopped reading them. It was a good run for a temporary fix.

P.S. We never migrated AOL’s CMS off the “temporary” polyfill. It ran there until the whole platform was shut down around 2020.

联系我们 contact @ memedata.com