如题,destoon 网站在切换分站城市后访问某些页面时,分站城市自动跳转(切换)到 IP 定位城市。

控制和存储当前分站城市的是 cookiexx_city,字段名前缀由 config.inc.php 中的 cookie_pre 定义。

在代码中全局搜索,找到根目录下 common.inc.php

$cityid = 0;
$city_name = $L['allcity'];
$city_domain = $city_template = $city_sitename = '';
if($DT['city']) include DT_ROOT.'/include/city.inc.php';

city.inc.php 中存在设置 cookie 值的脚本。

...
$city = get_cookie('city');
if ($city){

} else {
...
set_cookie('city', $r['areaid'].'|'.$r['domain'], $DT_TIME + 30*86400);
...
}

通过设置过期时间,确认 xx_city 被修改的位置就是这里。

所有的请求都会引入 common.inc.php 文件,但在 xx_city 值存在的情况下,就不会走根据访问 IP 定位城市的逻辑分支。

也就是说这个存在问题的页面本身或者页面内的某个请求修改了 xx_city 的值,使其为空(这是我的猜测)。

通过控制台 Network 查看页面加载后所有的请求,找到修改 cookie xx_city 值的请求。

判断条件:请求的 Response Headers 中 Set-Cookie 项中是否存在 xx_city,存在表示修改了 xx_city 值。

找到下面的这个请求:

xx/api/online.png.php?username=xx&style=0

代码中知道这个请求来源于在线交流的图片的 src,正常返回的是图片 url 。

找到请求文件,确认了问题的根源:

$_COOKIE = array();
...

请求开始就将 cookie 置空。注意不是删除所有 cookie,而是将当前请求中获取到的 cookie 数组置空,即不使用客户端的 cookie。

不太清楚开发者用意,但不使用客户端的 cookie 会在此次请求中丢失 city,最终会让城市分站自动定位当前城市。

解决办法

置空 $_COOKIE 之前先将其中的 city 值取出,置空后再重新赋值。

$city = array();
foreach ($_COOKIE as $key => $item) {
    if (strpos($key, 'city') !== false) {
        $city[0] = $key;
        $city[1] = $item;
        break;
    }
}
$_COOKIE = array();
if ($city) {
    $_COOKIE[$city[0]] = $city[1];
}

因为置空是在引入 common.inc.php 之前,所以 cookie 前缀不可知,get_cookieset_cookie 不可用,只能遍历得到需要的键值对。

在本地搭建的时候,因为请求是写死的,是远程服务器上的图片请求,xx_city 的 domain 值不同,所以未影响到本地。