You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP调用ipinfo.io报Trying to get property 'country'非对象错误

错误触发原因

你遇到的Trying to get property 'country' of non-object报错,核心原因是json_decode(curl_exec($curlSession))没有返回预期的标准对象,属于典型的接口调用无容错导致的偶发问题,具体触发场景包括:

  • IP获取逻辑缺陷:HTTP_X_FORWARDED_FOR字段在经过多层代理时会返回逗号分隔的IP列表,直接把整段字符串拼到接口请求URL中,会导致接口返回参数错误,无法解析出合法JSON
  • Curl请求异常:偶发的网络波动、DNS解析失败、接口临时不可用、请求超时都会导致curl_exec返回false,传入json_decode后得到null而非预期对象
  • 接口返回非预期内容:触发免费接口调用频率限制时会返回429状态码的纯文本错误,请求内网/保留IP时接口会返回错误结构,未开启跟随跳转时HTTP请求会被强制跳转到HTTPS返回3xx响应,这些场景下json_decode都无法解析出带country字段的对象
修复方案

1. 修正IP获取逻辑

不要直接返回代理头的原始值,拆分多IP场景取第一个真实公网IP,过滤内网保留段,避免无效请求:

function getip() {
    $ip = '0.0.0.0';
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ipList = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        foreach ($ipList as $tmpIp) {
            $tmpIp = trim($tmpIp);
            if (filter_var($tmpIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                $ip = $tmpIp;
                break;
            }
        }
    } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        $tmpIp = trim($_SERVER['HTTP_CLIENT_IP']);
        if (filter_var($tmpIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            $ip = $tmpIp;
        }
    } elseif (!empty($_SERVER['REMOTE_ADDR'])) {
        $ip = trim($_SERVER['REMOTE_ADDR']);
    }
    if ($ip == '0.0.0.0') {
        if (getenv('HTTP_X_FORWARDED_FOR')) {
            $ipList = explode(',', getenv('HTTP_X_FORWARDED_FOR'));
            foreach ($ipList as $tmpIp) {
                $tmpIp = trim($tmpIp);
                if (filter_var($tmpIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    $ip = $tmpIp;
                    break;
                }
            }
        } elseif (getenv('HTTP_CLIENT_IP')) {
            $tmpIp = trim(getenv('HTTP_CLIENT_IP'));
            if (filter_var($tmpIp, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                $ip = $tmpIp;
            }
        } elseif (getenv('REMOTE_ADDR')) {
            $ip = trim(getenv('REMOTE_ADDR'));
        }
    }
    return $ip;
}

2. 给接口调用增加全链路容错

改用HTTPS请求,配置合理超时、跳转跟随,每一步返回值都做合法性校验,设置默认国家兜底,避免报错和页面加载阻塞:

function getCountry(){
    $ip = getip();
    // 按业务默认站点适配的国家填写,比如默认中文站填CN
    $defaultCountry = 'CN';
    if ($ip == '0.0.0.0') {
        return $defaultCountry;
    }
    $url="https://ipinfo.io/{$ip}/json";
    $curlSession = curl_init();
    curl_setopt($curlSession, CURLOPT_URL, $url);
    curl_setopt($curlSession, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curlSession, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curlSession, CURLOPT_CONNECTTIMEOUT, 2);
    curl_setopt($curlSession, CURLOPT_TIMEOUT, 3);
    curl_setopt($curlSession, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($curlSession);
    $httpCode = curl_getinfo($curlSession, CURLINFO_HTTP_CODE);
    curl_close($curlSession);
    if ($response === false || $httpCode != 200) {
        return $defaultCountry;
    }
    $jsonData = json_decode($response);
    if (!is_object($jsonData) || !isset($jsonData->country)) {
        return $defaultCountry;
    }
    return $jsonData->country;
}

生产环境可选优化

  • 增加本地缓存:IP归属地变动频率极低,可以把IP和国家的映射存在本地文件/缓存中,缓存有效期设7天,减少接口请求量,避免触发免费额度限制,同时加快页面加载速度
  • 结果写入Cookie:识别到用户所属国家后写入有效期30天的Cookie,后续访问直接读取Cookie值,不用重复调用接口

注意:免费版IP归属地接口有每日请求配额限制,站点流量较大时需要提前评估额度,避免超限后所有用户都走默认跳转逻辑。

内容的提问来源于stack exchange,提问作者zvon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 04:33:26