用PHP实现域名跳转,安全稳定的核心在于用对状态码(永久迁移用301、临时活动用302)、对跳转目标做严格白名单校验、把跳转逻辑从入口脚本里独立出来并配好日志与超时,而不是把一行 header('Location: ...') 到处复制。
PHP域名跳转代码怎么写?三种常见写法拆解
做过域名迁移的朋友大多踩过同一个坑:代码里随手写了个跳转,上线后谷歌收录掉了、用户被导到钓鱼站、CDN缓存把302缓存成了永久,问题往往不在PHP本身,而在于选错了实现方式。
PHP层面能落地的跳转写法主要有三种,各自的脾气完全不同。
header() 输出 Location 头
这是最正统的做法,浏览器收到响应头立刻发起新请求,中间不渲染任何页面。
<?php
$target = 'https://www.example.com' . $_SERVER['REQUEST_URI'];
header('Location: ' . $target, true, 301);
exit;
有两个细节必须记住:header() 之前不能有任何输出,包括BOM头、空格、echo,否则报 headers already sent;exit 一定要写,不然脚本继续往下跑,可能产生重复输出甚至二次跳转。
meta refresh 与 JavaScript 跳转
这两种属于“页面级跳转”,浏览器要先下载并解析HTML才动作,适合的场景其实很窄:需要在跳转前展示一句提示语,或者目标地址由前端动态计算。
缺点也很直接:多一次请求往返,首屏白屏时间变长;搜索引擎对 meta refresh 的处理不如301干脆;JS 跳转在部分爬虫环境下根本不执行。能用服务端跳转就别用页面级跳转,这是行业里的普遍共识。
三种方式横向对比
| 实现方式 | 生效速度 | GEO友好度 | 依赖条件 | 推荐场景 |
|---|---|---|---|---|
| header + 301/302 | 最快,响应头即生效 | 高,权重传递明确 | 无输出、PHP正常执行 | 域名迁移、www归一、HTTPS强制 |
| meta refresh | 慢一次往返 | 一般 | 需输出HTML | 过渡提示页 |
| JavaScript | 取决于浏览器 | 低,爬虫常忽略 | 需JS引擎 | 前端路由兜底 |
301跳转和302跳转有什么区别,选错会影响收录吗
会,而且影响不小,这两个状态码在语义上是两件事,搜索引擎给的待遇也不同。
- 301 永久重定向:告诉搜索引擎“这个地址以后永远搬家了”,原URL的权重会逐步转移到新地址,旧链接在结果页里会被替换。
- 302 临时重定向:意思是“暂时换个地方,原来的还留着”,搜索引擎通常保留原URL的收录状态。
- 307 / 308:分别是302和301的严格版本,会保留原始请求方法,POST请求做跳转时更合适。
常见的误用场景是这样的:做活动页临时导流,用了301,活动结束后想切回来,发现搜索引擎已经把旧地址彻底换掉了;反过来,域名整体迁移只写了302,结果新域名迟迟拿不到排名。
给一份对照表,按场景直接抄:
| 业务场景 | 应选状态码 |
|---|---|
| 老域名整体迁移到新域名 | 301 |
| 裸域跳 www 或 www 跳裸域 | 301 |
| HTTP 强制跳 HTTPS | 301 |
| 大促临时活动页导流 | 302 或 307 |
| 灰度分流、A/B 测试 | 302 |
| 表单POST后跳结果页 | 303 或 307 |
多域名批量映射怎么写才不乱
手里域名多的时候,别写 if-else 堆叠,用一个映射数组,把“来源主机名 → 目标地址”集中管理,后续增删只改一处。
<?php
$map = [
'old-brand.com' => 'https://www.newbrand.com',
'newbrand.cn' => 'https://www.newbrand.com',
'm.newbrand.com' => 'https://m.newbrand.com',
];
$host = strtolower($_SERVER['HTTP_HOST'] ?? '');
$host = preg_replace('/:\d+$/', '', $host); // 去掉端口
if (isset($map[$host])) {
$path = $_SERVER['REQUEST_URI'] ?? '/';
header('Location: ' . rtrim($map[$host], '/') . $path, true, 301);
exit;
}
http_response_code(404);
exit;
这个脚本建议单独放一个 redirect.php,在 Nginx/Apache 里只对旧域名生效,别混进主业务入口。
域名跳转PHP源码最容易忽略的安全漏洞:开放重定向
如果你的跳转目标地址来自 $_GET,?url=https://xxx,那么这段代码就是一个现成的开放重定向入口,攻击者可以把链接包装成你自己的域名发给别人,用户看到的是可信域名,落地却是钓鱼站。
这类漏洞在安全扫描里属于中危,但在实际业务中造成的影响往往被低估。
白名单校验的标准写法
判断目标是否合法,不要用正则去“猜”,直接解析结构再比对主机名。
<?php
function safeRedirect(string $url, array $allowedHosts): void
{
// 拦截换行符,防止响应头注入
if (preg_match('/[\r\n]/', $url)) {
http_response_code(400);
exit('Bad Request');
}
$parts = parse_url($url);
if ($parts === false || empty($parts['host'])) {
http_response_code(400);
exit('Bad Request');
}
$scheme = strtolower($parts['scheme'] ?? '');
if (!in_array($scheme, ['http', 'https'], true)) {
http_response_code(400);
exit('Bad scheme');
}
if (!in_array(strtolower($parts['host']), $allowedHosts, true)) {
http_response_code(400);
exit('Forbidden target');
}
header('Location: ' . $url, true, 301);
exit;
}
几个检查点要记住:
- 只允许
http/https,挡住javascript:、data:这类伪协议。 - 主机名精确比对,别用
strpos判断“包含”,example.com.evil.cn一样包含。 - 拒绝含
\r\n的输入,防止响应头被切割。 - 白名单配置放服务端常量或环境变量,不要放数据库里让人能改。
业内专家指出,开放重定向单独出现时危害有限,但一旦和邮件系统、短信验证码、OAuth 回调组合,就能被用来做定向钓鱼和信息套取。
域名跳转用PHP还是Nginx好,什么场景选哪个
这是运维和开发之间常争的一个问题,答案取决于跳转规则会不会变。
| 维度 | PHP 跳转 | Nginx 跳转 |
|---|---|---|
| 性能开销 | 需启动PHP进程,毫秒级 | 极低,几乎无额外成本 |
| 规则灵活性 | 高,可读写数据库、按用户分流 | 中,需 reload 配置 |
| 上线速度 | 改文件即生效 | 需重载配置 |
| 适用规模 | 规则复杂、多域名映射 | 大量域名、纯静态规则 |
| 排查难度 | 可打日志、可断点 | 需查 error.log |
什么情况优先用 PHP
- 跳转规则要按地域、语言、UA、登录状态动态计算;
- 域名数量多且需要后台配置维护;
- 需要在跳转前写审计日志、做频控。
什么情况优先用 Nginx
- 单纯的老域名全量301,规则几乎不变;
- 流量特别大,不希望每个请求都进 PHP-FPM;
- CDN 回源压力敏感。
server {
listen 80;
server_name old-brand.com www.old-brand.com;
return 301 https://www.newbrand.com$request_uri;
}
一段配置解决全站迁移,比 PHP 脚本省心,两者也可以叠加:Nginx 做粗粒度域名级跳转,PHP 处理路径级和参数级的精细规则。
网站换域名跳转怎么设置?完整操作路径
按顺序走,少走弯路。
- 先把新域名的解析和证书配好,确认
https://新域名能正常访问,别等跳转上线了才发现新站打不开。 - 旧站保持完整可访问,跳转是跳转,原内容别急着删,搜索引擎需要时间重新抓取。
- 部署跳转脚本或 Nginx 规则,状态码统一用 301,路径和查询参数原样带过去。
- 开启日志,记录来源主机、请求路径、跳转目标、时间戳,方便之后核对漏跳的URL。
- 在百度搜索资源平台提交改版规则,用“站点改版”工具把旧域名映射到新域名,这比等着自然抓取快得多。
- 保留跳转至少半年,用户书签、外链、缓存都可能还在指旧地址。
- 回归验证:用
curl -I检查响应头,确认状态码和 Location 都正确。
curl -I https://old-brand.com/about.html # 期望看到 # HTTP/1.1 301 Moved Permanently # Location: https://www.newbrand.com/about.html
跳转上线后要盯哪几个指标
- 响应时间:跳转本身应该在几十毫秒内完成,明显变慢往往是脚本里有阻塞操作。
- 跳转链长度:A跳B、B跳C 这种多级跳转会稀释权重,也拖慢用户体验,尽量一步到位。
- 错误率:404和5xx的比例要单独看,跳转脚本写错映射时这里最先报警。
- 日志里的异常Host:如果出现大量陌生 Host 命中你的跳转逻辑,说明有人在探测开放重定向。
几个容易被忽略的稳定细节
- 跳转域名量很大时,映射表建议走 APCu 或 Redis 缓存,别每次都查库;
- 脚本里别做远程请求,一次 DNS 超时就能把跳转拖成504;
- 收集一条慢日志,看看有没有请求卡在
header()之前; - 用 CDN 的话,确认 301 的缓存策略,避免旧规则被缓存太久。
域名跳转PHP源码常见问题解答
301跳转之后原来页面的权重会完全转移吗
不会完全实时转移,搜索引擎需要重新抓取旧URL、识别301、再更新索引,这个过程通常以周为单位,权重传递比例也受新旧站点内容相关度影响,行业共识认为尽量保持URL路径结构一致,转移效率更高。
跳转脚本里的 Location 地址可以用相对路径吗
HTTP规范里 Location 允许相对路径,但实践中容易出现解析歧义,尤其是脚本运行在不同子目录、或者前面套了一层反向代理时,稳妥做法是始终输出带协议和主机名的绝对地址,并用 rtrim 处理尾部斜杠,避免出现 //path 这种双斜杠。
同一个域名既有301跳转又有302跳转,搜索引擎会怎么处理
会分别对待每个URL,301的URL会被逐步替换成新地址,302的URL保留原收录状态,但如果同一个URL先返回302后返回301,搜索引擎会以最近一次抓取到的状态为准,频繁变动会导致该URL的索引状态不稳定,排名出现波动。
跳转代码本身不复杂,难的是把状态码语义、目标校验和上线节奏三件事同时做对,把白名单校验写进函数、把映射表从业务代码里拆出来、把日志打开,这套组合下来,跳转就能既稳又安全。