必须启用cURL重定向跟随并用CURLINFO_EFFECTIVE_URL获取最终URL,优先信任Header中的charset,生产环境推荐cURL而非file_get_contents。

短链接还原时遇到 301/302 重定向无法捕获怎么办
PHP 本身不自动跟随重定向,file_get_contents() 或 curl_exec() 默认拿到的是跳转响应而非最终目标 URL。必须显式启用重定向跟随,否则会卡在中间跳转页(比如返回 Location: https://example.com/real 的 header)。
-
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true)是必需的,但仅此不够 - 若跳转链含跨域(如 t.co → twitter.com),还需加
curl_setopt($ch, CURLOPT_MAXREDIRS, 5)防止无限跳 - 某些短链服务(如 bit.ly)返回 302 +
Cache-Control: no-store,需确保curl_setopt($ch, CURLOPT_HEADER, false)关闭头输出干扰解析 - 用
curl_getinfo($ch, CURLINFO_EFFECTIVE_URL)获取最终落地 URL,而不是解析Locationheader —— 后者在多级跳时不可靠
支持哪些编码格式的短链响应体
短链服务返回的响应体通常为空或极简 HTML,但少数(如微信内嵌短链、企业微信跳转页)可能返回 UTF-8、GBK 甚至带 BOM 的 UTF-8-BOM 页面。PHP 的 mb_detect_encoding() 在空响应或无 Content-Type 时极易误判。
- 优先信任 HTTP header 中的
Content-Type: text/html; charset=utf-8,用mb_convert_encoding($html, 'UTF-8', $detected)统一转码 - 若 header 缺失 charset,且响应体含
<meta charset="gbk">,需用正则提取:/<meta[^>]+charset\s*=\s*[\'"]([^\'"]+)[\'"]/i - 避免直接用
iconv('GBK', 'UTF-8', $html)—— GBK 检测失败时会触发 warning 并截断内容;应改用mb_convert_encoding($html, 'UTF-8', 'UTF-8, GBK, BIG5')多候选 fallback - 对纯跳转型页面(无 body),编码问题可忽略;重点在 header 解析,而非内容解码
curl 与 file_get_contents 的实际兼容差异
file_get_contents() 看似简单,但在短链还原场景下限制明显:不支持设置超时精度(只能秒级)、无法获取跳转链详情、默认禁用重定向(即使设了 stream_context_create(['http'=>['follow_location'=>true]]),也常因 open_basedir 或 allow_url_fopen 关闭而失败)。
- 生产环境建议统一用
curl:可控性高,能捕获每跳的HTTP_CODE和EFFECTIVE_URL - 若必须用
file_get_contents(),需确认allow_url_fopen=On且未被open_basedir限制路径 - 微信短链(如
https://w.url.cn/s/AbcXyz)常返回 302 + Set-Cookie,file_get_contents()无法携带 cookie 上下文,必然失败;curl 则可通过CURLOPT_COOKIEJAR和CURLOPT_COOKIEFILE模拟会话 - 超时控制:curl 可分别设
CURLOPT_CONNECTTIMEOUT_MS(毫秒级连接超时)和CURLOPT_TIMEOUT_MS(总耗时),比file_get_contents()的整数秒更精准
function expandShortUrl($url) {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_CONNECTTIMEOUT_MS => 3000,
CURLOPT_TIMEOUT_MS => 10000,
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; ShortLinkExpander/1.0)',
CURLOPT_NOBODY => false,
CURLOPT_HEADER => false,
]);
$result = curl_exec($ch);
$finalUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
return $finalUrl ?: $url;
}
有些短链服务会校验 User-Agent 或拒绝空 referer,有些则依赖 JS 重定向(此时 PHP curl 无法执行 JS)。真要处理这类,得上 Puppeteer 或 Playwright,PHP 层只适合做“纯 HTTP 协议层还原”。











