按跳转网址显示不同内容?看似简单实则坑多!

最近在折腾一个项目,需要根据用户从哪个网站跳转过来显示不同的内容。听起来挺简单的对?但实际操作起来坑还真不少,今天就把这些坑都填平了给你们看看。

先来个最简单的实现方案:

if(isset($_SERVER['HTTP_REFERER'])){

$referer = $_SERVER['HTTP_REFERER'];

if(strpos($referer, 'google.com') !== false){

header('Location: vip-page.php');

exit;

}

}

看起来很美是不是?但现实往往比代码残酷得多。首先HTTP_REFERER这个变量是可以伪造的,其次有些浏览器压根就不发送这个头信息。我测试的时候发现,用Chrome直接输入网址访问时,这个变量就是空的。

更坑爹的是,有些安全软件会主动过滤掉这个头信息。我遇到过最奇葩的情况是,某个杀毒软件会把所有referer都改成它自己的官网,当时排查这个问题差点没把我整崩溃。

为了解决这个问题,我搞了个增强版的判断逻辑:

function getRealReferer(){

$referer = '';

if(isset($_SERVER['HTTP_REFERER'])){

$referer = $_SERVER['HTTP_REFERER'];

// 过滤掉明显伪造的referer

if(strpos($referer, 'antivirus.com') !== false){

$referer = '';

}

}

return $referer;

}

$realReferer = getRealReferer();

if(empty($realReferer)){

// 如果没有referer,尝试其他判断方式

if(isset($_SERVER['HTTP_ORIGIN'])){

$realReferer = $_SERVER['HTTP_ORIGIN'];

}

}

这个方案稍微靠谱点了,但还不够完美。后来我发现有些流量统计工具会在URL后面加参数标记来源,比如utm_source之类的。于是我又加了个判断:

if(isset($_GET['utm_source'])){

$source = $_GET['utm_source'];

switch($source){

case 'weibo':

header('Location: weibo-landing.php');

break;

case 'baidu':

header('Location: baidu-special.php');

default:

// 默认跳转

}

exit;

}

说到跳转,这里有个大坑要提醒你们。很多新手会忘记在header跳转后加exit,结果代码继续执行,跳转根本没生效。我就见过有人调试了半天,最后发现是因为少写了个exit,那场面简直不要太尴尬。

为了防止跳转失效,我习惯性会这么写:

header('Location: target.php');

die('Redirecting...'); // 比exit更有逼格

有时候我们需要记录跳转来源做数据分析。这时候要注意防注入:

$referer = isset($_SERVER['HTTP_REFERER']) ?

htmlspecialchars($_SERVER['HTTP_REFERER'], ENT_QUOTES) : '';

$stmt = $pdo->prepare("INSERT INTO refer_log (referer, ip) VALUES (?, ?)");

$stmt->execute([$referer, $_SERVER['REMOTE_ADDR']]);

说到IP,有些特殊需求要根据IP所在地跳转。这时候可以这样:

$ip = $_SERVER['REMOTE_ADDR'];

$details = json_decode(file_get_contents("http://ipinfo.io/{$ip}/json"));

if($details->country == 'CN'){

header('Location: chinese-version.php');

} else {

}

但要注意,这种API调用是有频率限制的,而且会拖慢页面加载速度。最好在本地维护一个IP库,或者用CDN的边缘计算功能来实现。

有时候我们还需要处理移动端和PC端的跳转。这个判断就更有意思了:

$userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);

$isMobile = false;

$mobileAgents = ['iphone','android','ipod','blackberry','windows phone'];

foreach($mobileAgents as $agent){

if(strpos($userAgent, $agent) !== false){

$isMobile = true;

break;

}

}

if($isMobile){

header('Location: mobile-site.php');

} else {

不过现在响应式设计这么流行,这种跳转其实已经不太推荐了。除非是特别复杂的场景,否则还是用CSS媒体查询更靠谱。

最后说一个高级玩法:用Session来跟踪用户来源。这个适合需要多步跳转的场景:

session_start();

if(empty($_SESSION['origin'])){

$_SESSION['origin'] = $_SERVER['HTTP_REFERER'];

} else {

$_SESSION['origin'] = 'direct';

}

}

// 后续页面都可以通过$_SESSION['origin']来判断来源

这个方案的优点是即使用户在站内跳转多次,我们仍然能知道他最初是从哪来的。缺点是会增加服务器负担,而且对搜索引擎不太友好。

总结一下来路跳转的几个要点:

1. 永远不要完全信任HTTP_REFERER

2. 跳转后一定要记得exit或die

3. 记录来源时要防SQL注入

4. 移动端判断现在已经不太推荐了

5. 复杂场景可以考虑用Session跟踪

写完这些代码,我突然想到一个哲学问题:如果一个用户在隐身模式下访问网站,又没有referer,那他到底是从哪来的?算了,这种问题还是留给产品经理去思考,我们码农只管实现需求就行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值