PHP项目如何对接天气查询接口?

wen PHP项目 22

本文目录导读:

PHP项目如何对接天气查询接口?

  1. 准备工作
  2. PHP对接实现
  3. 进阶功能封装
  4. 前端展示示例(HTML+JS)
  5. 错误处理和注意事项
  6. 完整项目结构

我来详细说明PHP项目对接天气查询接口的完整流程,以国内常用的和风天气OpenWeatherMap为例。

准备工作

选择天气API服务商

  • 和风天气 (国内首选):https://dev.heweather.com
  • OpenWeatherMap (国际):https://openweathermap.org
  • 彩云天气:https://docs.caiyunapp.com

获取API密钥

以和风天气为例:

  • 注册账号
  • 创建应用获取 API Key
  • 选择免费版或付费版

PHP对接实现

基础封装类

<?php
class WeatherAPI {
    private $apiKey;
    private $baseUrl;
    public function __construct($apiKey, $service = 'heweather') {
        $this->apiKey = $apiKey;
        // 根据服务商设置base URL
        switch ($service) {
            case 'heweather':
                $this->baseUrl = 'https://devapi.qweather.com/v7';
                break;
            case 'openweather':
                $this->baseUrl = 'https://api.openweathermap.org/data/2.5';
                break;
        }
    }
    /**
     * 发送HTTP请求
     */
    private function sendRequest($url) {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if (curl_errno($ch)) {
            throw new Exception('CURL Error: ' . curl_error($ch));
        }
        curl_close($ch);
        if ($httpCode !== 200) {
            throw new Exception("HTTP Error: $httpCode");
        }
        return json_decode($response, true);
    }
    /**
     * 获取实时天气 - 和风天气
     */
    public function getCurrentWeather($location) {
        $url = $this->baseUrl . "/weather/now?location=$location&key={$this->apiKey}";
        return $this->sendRequest($url);
    }
    /**
     * 获取未来3天天气预报 - 和风天气
     */
    public function getForecast($location, $days = 3) {
        $url = $this->baseUrl . "/weather/3d?location=$location&key={$this->apiKey}";
        return $this->sendRequest($url);
    }
    /**
     * 获取实时天气 - OpenWeatherMap
     */
    public function getCurrentWeatherOWM($location) {
        $url = $this->baseUrl . "/weather?q=$location&appid={$this->apiKey}&units=metric&lang=zh_cn";
        return $this->sendRequest($url);
    }
}

使用示例

<?php
// 1. 基础使用 - 获取实时天气
try {
    $weather = new WeatherAPI('YOUR_API_KEY_HERE', 'heweather');
    $result = $weather->getCurrentWeather('101010100'); // 北京城市ID
    if ($result['code'] === '200') {
        $now = $result['now'];
        echo "当前温度:{$now['temp']}°C\n";
        echo "天气状况:{$now['text']}\n";
        echo "风速:{$now['windSpeed']} km/h\n";
        echo "湿度:{$now['humidity']}%\n";
    }
} catch (Exception $e) {
    echo "Error: " . $e->getMessage();
}
// 2. 通过城市名称查询
function getWeatherByName($cityName) {
    // 先获取城市ID (和风天气需要)
    $geoUrl = "https://geoapi.qweather.com/v2/city/lookup";
    $geoUrl .= "?location=$cityName&key=YOUR_API_KEY";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $geoUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $geoResponse = json_decode(curl_exec($ch), true);
    curl_close($ch);
    if (!empty($geoResponse['location'])) {
        $cityId = $geoResponse['location'][0]['id'];
        // 使用城市ID查询天气
        $weatherAPI = new WeatherAPI('YOUR_API_KEY');
        return $weatherAPI->getCurrentWeather($cityId);
    }
    return null;
}
// 3. 通过IP定位获取天气
function getWeatherByIP() {
    $ip = $_SERVER['REMOTE_ADDR'] ?? '8.8.8.8'; // 生产环境使用真实IP
    // 使用和风天气的IP定位
    $locationUrl = "https://geoapi.qweather.com/v2/ip?key=YOUR_API_KEY&ip=$ip";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $locationUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $location = json_decode(curl_exec($ch), true);
    curl_close($ch);
    if (!empty($location['location'])) {
        $cityId = $location['location'][0]['id'];
        $weatherAPI = new WeatherAPI('YOUR_API_KEY');
        return $weatherAPI->getCurrentWeather($cityId);
    }
    return null;
}

进阶功能封装

带缓存的天气预报类

<?php
class WeatherService {
    private $api;
    private $cacheDir;
    private $cacheTime = 1800; // 30分钟缓存
    public function __construct($apiKey) {
        $this->api = new WeatherAPI($apiKey);
        $this->cacheDir = __DIR__ . '/cache/weather/';
        if (!is_dir($this->cacheDir)) {
            mkdir($this->cacheDir, 0755, true);
        }
    }
    /**
     * 获取天气(带缓存)
     */
    public function getWeatherWithCache($location) {
        $cacheFile = $this->cacheDir . md5($location) . '.json';
        // 检查缓存
        if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $this->cacheTime) {
            return json_decode(file_get_contents($cacheFile), true);
        }
        // 从API获取数据
        $data = $this->api->getCurrentWeather($location);
        // 写入缓存
        if (!empty($data)) {
            file_put_contents($cacheFile, json_encode($data));
        }
        return $data;
    }
    /**
     * 获取格式化天气报告
     */
    public function getWeatherReport($location) {
        $data = $this->getWeatherWithCache($location);
        if (isset($data['now'])) {
            $now = $data['now'];
            return [
                'temperature' => $now['temp'] . '°C',
                'feels_like' => $now['feelsLike'] . '°C',
                'condition' => $now['text'],
                'wind' => $now['windDir'] . ' ' . $now['windScale'] . '级',
                'humidity' => $now['humidity'] . '%',
                'update_time' => $data['updateTime']
            ];
        }
        return null;
    }
}
// 使用示例
$weatherService = new WeatherService('YOUR_API_KEY');
$report = $weatherService->getWeatherReport('101010100');
echo "当前温度:{$report['temperature']}\n";
echo "天气状况:{$report['condition']}\n";

前端展示示例(HTML+JS)

<!-- weather_display.php -->
<!DOCTYPE html>
<html>
<head>天气预报</title>
    <style>
        .weather-card {
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 20px;
            margin: 20px;
            max-width: 300px;
        }
        .temperature {
            font-size: 48px;
            font-weight: bold;
            color: #333;
        }
        .condition {
            font-size: 24px;
            color: #666;
        }
    </style>
</head>
<body>
    <div id="weather" class="weather-card">
        <h2>当前天气</h2>
        <div class="temperature" id="temp">--°C</div>
        <div class="condition" id="condition">加载中...</div>
    </div>
    <script>
        function updateWeather() {
            fetch('api/get_weather.php?city=北京')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('temp').textContent = 
                        data.temperature + '°C';
                    document.getElementById('condition').textContent = 
                        data.condition;
                })
                .catch(error => {
                    console.error('获取天气失败:', error);
                });
        }
        // 每30分钟更新一次
        updateWeather();
        setInterval(updateWeather, 1800000);
    </script>
</body>
</html>

PHP API端点

<?php
// api/get_weather.php
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
require_once '../WeatherService.php';
try {
    $city = $_GET['city'] ?? '北京';
    $weatherService = new WeatherService('YOUR_API_KEY');
    $report = $weatherService->getWeatherReport($city);
    if ($report) {
        echo json_encode([
            'success' => true,
            'temperature' => $report['temperature'],
            'condition' => $report['condition'],
            'humidity' => $report['humidity'],
            'wind' => $report['wind']
        ]);
    } else {
        echo json_encode(['success' => false, 'message' => '天气数据获取失败']);
    }
} catch (Exception $e) {
    echo json_encode(['success' => false, 'message' => $e->getMessage()]);
}

错误处理和注意事项

错误处理

try {
    $weather = new WeatherAPI('YOUR_API_KEY');
    $result = $weather->getCurrentWeather('invalid_location');
    if ($result['code'] !== '200') {
        // 错误处理
        switch ($result['code']) {
            case '401':
                throw new Exception('API密钥无效');
            case '403':
                throw new Exception('请求被拒绝');
            case '404':
                throw new Exception('城市不存在');
            default:
                throw new Exception('未知错误');
        }
    }
} catch (Exception $e) {
    error_log("Weather API Error: " . $e->getMessage());
    echo json_encode(['error' => $e->getMessage()]);
}

性能优化建议

// 1. 使用连接池(如Redis缓存)
class WeatherCache {
    private $redis;
    public function __construct() {
        $this->redis = new Redis();
        $this->redis->connect('127.0.0.1', 6379);
    }
    public function getCachedWeather($location) {
        $key = "weather:$location";
        $cached = $this->redis->get($key);
        if ($cached) {
            return json_decode($cached, true);
        }
        // 从API获取并缓存
        $weather = new WeatherAPI('YOUR_API_KEY');
        $data = $weather->getCurrentWeather($location);
        // 缓存30分钟
        $this->redis->setex($key, 1800, json_encode($data));
        return $data;
    }
}
// 2. 批量查询优化
function batchGetWeather(array $locations) {
    $results = [];
    foreach ($locations as $location) {
        // 使用多线程或curl_multi并行请求
        $results[$location] = getWeatherFromAPI($location);
    }
    return $results;
}

安全注意事项

// 1. API密钥安全存储
// 不要在代码中硬编码API密钥,使用环境变量
$apiKey = getenv('WEATHER_API_KEY');
// 2. 请求频率限制
class RateLimiter {
    private $requests = [];
    private $limit = 100; // 每分钟100次
    public function checkLimit() {
        $now = time();
        $this->requests = array_filter($this->requests, function($time) use ($now) {
            return $time > ($now - 60);
        });
        if (count($this->requests) >= $this->limit) {
            throw new Exception('请求频率超限');
        }
        $this->requests[] = $now;
    }
}
// 3. 输入验证
function validateLocation($location) {
    // 只允许字母、数字和中文
    if (!preg_match('/^[a-zA-Z0-9\x{4e00}-\x{9fa5}]+$/u', $location)) {
        throw new Exception('无效的位置参数');
    }
    return true;
}

完整项目结构

weather_project/
├── api/
│   └── get_weather.php          # API端点
├── classes/
│   ├── WeatherAPI.php           # API封装类
│   ├── WeatherService.php       # 业务逻辑封装
│   └── WeatherCache.php         # 缓存类
├── config/
│   └── config.php               # 配置文件
├── templates/
│   └── weather_display.php      # 前端模板
├── cache/                       # 缓存目录
├── vendor/                      # Composer依赖
├── .env                         # 环境变量
└── index.php                    # 入口文件

配置文件示例

<?php
// config/config.php
return [
    'weather_api' => [
        'service' => 'heweather',  // heweather, openweather
        'api_key' => getenv('WEATHER_API_KEY'),
        'cache_time' => 1800,      // 缓存时间(秒)
        'timeout' => 10,           // 请求超时(秒)
        'retry_times' => 3,        // 重试次数
    ]
];

对接天气API的关键要点:

  1. 选择合适的API服务商:国内推荐和风天气,国际推荐OpenWeatherMap
  2. 实现缓存机制:减少API调用次数,提高响应速度
  3. 错误处理:完善异常捕获和错误提示
  4. 性能优化:使用缓存、连接池等技术
  5. 安全性:保护API密钥,验证用户输入

这样,你就可以在自己的PHP项目中轻松集成天气查询功能了,如果需要其他天气API的对接方式,可以进一步告诉我。

抱歉,评论功能暂时关闭!