首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

ThinkPHP 實現 IP 定位與天氣信息聯動:從業務邏輯到代碼落地

     編輯:PHP 相關知識

ThinkPHP 實現 IP 定位與天氣信息聯動:從業務邏輯到代碼落地

許多網站無需用戶輸入位置即可展示當地天氣,核心原理是通過 IP 地址定位城市,再調用天氣 API。本文梳理基於 ThinkPHP 的完整實現邏輯,涵蓋 IP 獲取、地址解析、城市代碼映射、天氣數據獲取與模板渲染全流程。

核心業務流程

  1. 獲取客戶端 IP:優先取 $_SERVER['REMOTE_ADDR'],考慮代理情況兼容 HTTP_X_FORWARDED_FOR、HTTP_CLIENT_IP
  2. IP 轉地理位置:使用 UTF-8 編碼的 IP 數據庫(如纯真库),解析出省市信息
  3. 城市名標準化:從完整地址(如「廣東省深圳市」)提取城市名(「深圳」)
  4. 城市代碼映射:遍歷城市代碼庫獲取天氣 API 所需城市代碼
  5. 調用天氣接口:請求第三方天氣 API(返回 JSON),解析數據
  6. 模板渲染:將天氣對象直接分配模板,便於維護擴展
  7. 用戶手動查詢覆蓋:用戶輸入城市優先級高於自動定位

關鍵代碼實現

控制器邏輯

public function weather_test() {
    require_once './Component/Citycode.php'; // 城市代碼庫
    
    $count = 0;
    $city_id = '101120301'; // 默認城市代碼
    $city_name_cin = $_POST['cityname'] ?? '';
    $city_sim_name = R('Test/get_user_cityname'); // 自動定位城市名
    
    // 優先級:用戶輸入 > 自動定位 > 默認
    if ($city_sim_name) $city_name_cin = $city_sim_name;
    if (!empty($_POST['cityname'])) $city_name_cin = $_POST['cityname'];
    
    // 遍歷獲取城市代碼
    foreach ($citycode as $key => $value) {
        if ($key == $city_name_cin) {
            $city_id = $citycode[$city_name_cin];
            $count++;
        }
    }
    
    if ($count == 0) {
        echo "未找到對應城市,使用默認城市";
    } else {
        echo "{$city_name_cin} 的天氣信息如下";
    }
    
    // 調用天氣 API(示例接口已失效,請替換為高德/和風/彩雲等可用接口)
    $weather_interface_url = "https://api.example.com/weather?cityId={$city_id}&key=YOUR_KEY";
    $all_weather_info = json_decode(file_get_contents($weather_interface_url));
    
    $this->assign('all_info', $all_weather_info);
    $this->display();
}

IP 獲取與城市解析方法

// 獲取客戶端真實 IP
public function get_user_ip() {
    // 支持代理鏈:優先 X-Forwarded-For,其次 X-Real-IP,最後 REMOTE_ADDR
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim($ips[0]);
    } elseif (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return $_SERVER['HTTP_CLIENT_IP'];
    }
    return $_SERVER['REMOTE_ADDR'];
}

// IP 解析城市名(依賴纯真库 UTFWry.dat)
public function get_user_cityname() {
    $host_ip = R('Test/get_user_ip');
    $Ip = new \Org\Net\IpLocation('UTFWry.dat'); // ThinkPHP 導入方式
    $area = $Ip->getlocation($host_ip);
    
    // 解析格式:中國|廣東|深圳|... → 提取「深圳」
    $city_allname = $area['country']; // 實際字段視具體庫而定
    $sim_cityname = explode('市', explode('省', $city_allname)[1])[0] ?? '';
    return $sim_cityname;
}

模板渲染示例

<div class="weather-container">
    <h3>即時天氣 - {$all_info->forecast->city}</h3>
    <p>天氣:{$all_info->realtime->weather} 溫度:{$all_info->realtime->temp}℃ 風向:{$all_info->realtime->WD}</p>
    <p>更新時間:{$all_info->realtime->time}</p>
    
    <h4>生活建議</h4>
    <ul>
        <li>防曬:{$all_info->index[0]->details}</li>
        <li>穿衣:{$all_info->index[1]->details}</li>
        <li>運動:{$all_info->index[2]->details}</li>
        <li>洗車:{$all_info->index[3]->details}</li>
        <li>晾曬:{$all_info->index[4]->details}</li>
    </ul>
    
    <h4>未來 4 天預報</h4>
    <table>
        <tr><th>項目</th><th>今天</th><th>明天</th><th>後天</th><th>大後天</th></tr>
        <tr><td>概況</td><td>{$all_info->forecast->weather1}</td><td>{$all_info->forecast->weather2}</td><td>{$all_info->forecast->weather3}</td><td>{$all_info->forecast->weather4}</td></tr>
        <tr><td>溫度</td><td>{$all_info->forecast->temp1}</td><td>{$all_info->forecast->temp2}</td><td>{$all_info->forecast->temp3}</td><td>{$all_info->forecast->temp4}</td></tr>
        <tr><td>風向</td><td>{$all_info->forecast->wind1}</td><td>{$all_info->forecast->wind2}</td><td>{$all_info->forecast->wind3}</td><td>{$all_info->forecast->wind4}</td></tr>
        <tr><td>風力</td><td>{$all_info->forecast->fl1}</td><td>{$all_info->forecast->fl2}</td><td>{$all_info->forecast->fl3}</td><td>{$all_info->forecast->fl4}</td></tr>
    </table>
</div>

關鍵技術點與避坑指南

環節常見問題解決方案
IP 獲取CDN/代理導致獲取到內網 IP正確解析 X-Forwarded-For 首個公網 IP,驗證 IP 格式合法性
IP 庫編碼GBK 庫在 UTF-8 專案中亂碼強制使用 UTF-8 版 IP 庫,或運行時 iconv 轉換
城市匹配「深圳市」vs「深圳」不匹配統一去除「省/市/區/縣」後綴,建立標準化映射表
接口容錯第三方 API 失效/超時設置超時、重試機制、降級默認數據、異常日誌告警
緩存策略頻繁請求觸發限流Redis 緩存天氣數據 10-30 分鐘,同城複用

現代化改進建議

  1. IP 庫升級:使用 MaxMind GeoIP2(mmdb 格式)+ Composer 包 geoip2/geoip2,精度更高、更新及時
  2. 天氣接口:接入高德地圖、和風天氣、彩雲天氣等商業級 API,支持 HTTPS、簽名鑒權
  3. 異步化處理:用戶請求時返回緩存數據,後台異步更新(ThinkPHP Queue + Redis)
  4. 前端體驗:GeoLocation API 獲取精確坐標(需用戶授權),作為 IP 定位補充
  5. 監控告警:記錄定位失敗率、API 成功率、響應時間,異常自動告警

這套方案雖基於 ThinkPHP 3.x 風格,但核心邏輯具備通用性。理解「IP → 地址 → 城市代碼 → 天氣數據」的轉換鏈路,是構建位置感知服務的基礎技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved