許多網站無需用戶輸入位置即可展示當地天氣,核心原理是通過 IP 地址定位城市,再調用天氣 API。本文梳理基於 ThinkPHP 的完整實現邏輯,涵蓋 IP 獲取、地址解析、城市代碼映射、天氣數據獲取與模板渲染全流程。
$_SERVER['REMOTE_ADDR'],考慮代理情況兼容 HTTP_X_FORWARDED_FOR、HTTP_CLIENT_IPpublic 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
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 分鐘,同城複用 |
geoip2/geoip2,精度更高、更新及時這套方案雖基於 ThinkPHP 3.x 風格,但核心邏輯具備通用性。理解「IP → 地址 → 城市代碼 → 天氣數據」的轉換鏈路,是構建位置感知服務的基礎技能。