3 * OpenWeatherMap-PHP-API — A php api to parse weather data from http://www.OpenWeatherMap.org .
7 * Please see the LICENSE file distributed with this source code for further
8 * information regarding copyright and licensing.
10 * Please visit the following links to read about the usage policies and the license of
11 * OpenWeatherMap before using this class:
13 * @see http://www.OpenWeatherMap.org
14 * @see http://www.OpenWeatherMap.org/terms
15 * @see http://openweathermap.org/appid
20 use Cmfcmf\OpenWeatherMap\AbstractCache;
21 use Cmfcmf\OpenWeatherMap\CurrentWeather;
22 use Cmfcmf\OpenWeatherMap\Exception as OWMException;
23 use Cmfcmf\OpenWeatherMap\Fetcher\CurlFetcher;
24 use Cmfcmf\OpenWeatherMap\Fetcher\FetcherInterface;
25 use Cmfcmf\OpenWeatherMap\Fetcher\FileGetContentsFetcher;
26 use Cmfcmf\OpenWeatherMap\WeatherForecast;
27 use Cmfcmf\OpenWeatherMap\WeatherHistory;
30 * Main class for the OpenWeatherMap-PHP-API. Only use this class.
37 * @var string $weatherUrl The basic api url to fetch weather data from.
39 private $weatherUrl = "http://api.openweathermap.org/data/2.5/weather?";
42 * @var string $url The basic api url to fetch weekly forecast data from.
44 private $weatherHourlyForecastUrl = "http://api.openweathermap.org/data/2.5/forecast?";
47 * @var string $url The basic api url to fetch daily forecast data from.
49 private $weatherDailyForecastUrl = "http://api.openweathermap.org/data/2.5/forecast/daily?";
52 * @var string $url The basic api url to fetch history weather data from.
54 private $weatherHistoryUrl = "http://api.openweathermap.org/data/2.5/history/city?";
57 * The copyright notice. This is no official text, this hint was created regarding to http://openweathermap.org/copyright.
59 * @var string $copyright
61 const COPYRIGHT = "Weather data from <a href=\"http://www.openweathermap.org\">OpenWeatherMap.org</a>";
64 * @var \Cmfcmf\OpenWeatherMap\AbstractCache|bool $cacheClass The cache class.
66 private $cacheClass = false;
74 * @var FetcherInterface The url fetcher.
79 * Constructs the OpenWeatherMap object.
81 * @param null|FetcherInterface $fetcher The interface to fetch the data from OpenWeatherMap. Defaults to
82 * CurlFetcher() if cURL is available. Otherwise defaults to
83 * FileGetContentsFetcher() using 'file_get_contents()'.
84 * @param bool|string $cacheClass If set to false, caching is disabled. Otherwise this must be a class
85 * extending AbstractCache. Defaults to false.
86 * @param int $seconds How long weather data shall be cached. Default 10 minutes.
88 * @throws \Exception If $cache is neither false nor a valid callable extending Cmfcmf\OpenWeatherMap\Util\Cache.
91 public function __construct($fetcher = null, $cacheClass = false, $seconds = 600)
93 if ($cacheClass !== false && !($cacheClass instanceof AbstractCache)) {
94 throw new \Exception("The cache class must implement the FetcherInterface!");
96 if (!is_numeric($seconds)) {
97 throw new \Exception("\$seconds must be numeric.");
99 if (!isset($fetcher)) {
100 $fetcher = (function_exists('curl_version')) ? new CurlFetcher() : new FileGetContentsFetcher();
106 $this->cacheClass = $cacheClass;
107 $this->seconds = $seconds;
108 $this->fetcher = $fetcher;
112 * Returns the current weather at the place you specified as an object.
114 * @param array|int|string $query The place to get weather information for. For possible values see below.
115 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
116 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
117 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
119 * @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
120 * @throws \InvalidArgumentException If an argument error occurs.
122 * @return CurrentWeather The weather object.
124 * There are three ways to specify the place to get weather information for:
125 * - Use the city name: $query must be a string containing the city name.
126 * - Use the city id: $query must be an integer containing the city id.
127 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
129 * Available languages are (as of 17. July 2013):
144 * - Chinese Traditional - zh_tw
145 * - Chinese Simplified - zh_cn
150 public function getWeather($query, $units = 'imperial', $lang = 'en', $appid = '')
152 // Disable default error handling of SimpleXML (Do not throw E_WARNINGs).
153 libxml_use_internal_errors(true);
154 libxml_clear_errors();
156 $answer = $this->getRawWeatherData($query, $units, $lang, $appid, 'xml');
159 $xml = new \SimpleXMLElement($answer);
160 } catch (\Exception $e) {
161 // Invalid xml format. This happens in case OpenWeatherMap returns an error.
162 // OpenWeatherMap always uses json for errors, even if one specifies xml as format.
163 $error = json_decode($answer, true);
164 if (isset($error['message'])) {
165 throw new OWMException($error['message'], $error['cod']);
167 throw new OWMException('Unknown fatal error: OpenWeatherMap returned the following json object: ' . $answer);
171 return new CurrentWeather($xml, $units);
175 * Returns the current weather at the place you specified as an object.
177 * @param array|int|string $query The place to get weather information for. For possible values see below.
178 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
179 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
180 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
181 * @param int $days For how much days you want to get a forecast. Default 1, maximum: 16.
183 * @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
184 * @throws \InvalidArgumentException If an argument error occurs.
186 * @return WeatherForecast The WeatherForecast object.
188 * There are three ways to specify the place to get weather information for:
189 * - Use the city name: $query must be a string containing the city name.
190 * - Use the city id: $query must be an integer containing the city id.
191 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
193 * Available languages are (as of 17. July 2013):
208 * - Chinese Traditional - zh_tw
209 * - Chinese Simplified - zh_cn
214 public function getWeatherForecast($query, $units = 'imperial', $lang = 'en', $appid = '', $days = 1)
216 // Disable default error handling of SimpleXML (Do not throw E_WARNINGs).
217 libxml_use_internal_errors(true);
218 libxml_clear_errors();
221 $answer = $this->getRawHourlyForecastData($query, $units, $lang, $appid, 'xml');
222 } else if ($days <= 16) {
223 $answer = $this->getRawDailyForecastData($query, $units, $lang, $appid, 'xml', $days);
225 throw new \InvalidArgumentException('Error: forecasts are only available for the next 16 days. $days must be lower than 17.');
229 $xml = new \SimpleXMLElement($answer);
230 } catch (\Exception $e) {
231 // Invalid xml format. This happens in case OpenWeatherMap returns an error.
232 // OpenWeatherMap always uses json for errors, even if one specifies xml as format.
233 $error = json_decode($answer, true);
234 if (isset($error['message'])) {
235 throw new OWMException($error['message'], $error['cod']);
237 throw new OWMException('Unknown fatal error: OpenWeatherMap returned the following json object: ' . $answer);
241 return new WeatherForecast($xml, $units, $days);
245 * Returns the weather history for the place you specified as an object.
247 * @param array|int|string $query The place to get weather information for. For possible values see below.
248 * @param \DateTime $start
249 * @param int $endOrCount
250 * @param string $type
251 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
252 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
253 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
255 * @throws OpenWeatherMap\Exception If OpenWeatherMap returns an error.
256 * @throws \InvalidArgumentException If an argument error occurs.
258 * @return WeatherHistory The WeatherHistory object.
260 * There are three ways to specify the place to get weather information for:
261 * - Use the city name: $query must be a string containing the city name.
262 * - Use the city id: $query must be an integer containing the city id.
263 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
265 * Available languages are (as of 17. July 2013):
280 * - Chinese Traditional - zh_tw
281 * - Chinese Simplified - zh_cn
286 public function getWeatherHistory($query, \DateTime $start, $endOrCount = 1, $type = 'hour', $units = 'imperial', $lang = 'en', $appid = '')
288 if (!in_array($type, array('tick', 'hour', 'day'))) {
289 throw new \InvalidArgumentException('$type must be either "tick", "hour" or "day"');
292 $xml = json_decode($this->getRawWeatherHistory($query, $start, $endOrCount, $type, $units, $lang, $appid), true);
294 if ($xml['cod'] != 200) {
295 throw new OWMException($xml['message'], $xml['cod']);
298 return new WeatherHistory($xml, $query);
302 * @deprecated Use {@link self::getRawWeatherData()} instead.
304 public function getRawData($query, $units = 'imperial', $lang = 'en', $appid = '', $mode = 'xml')
306 return $this->getRawWeatherData($query, $units, $lang, $appid, $mode);
310 * Directly returns the xml/json/html string returned by OpenWeatherMap for the current weather.
312 * @param array|int|string $query The place to get weather information for. For possible values see below.
313 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
314 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
315 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
316 * @param string $mode The format of the data fetched. Possible values are 'json', 'html' and 'xml' (default).
318 * @return string Returns false on failure and the fetched data in the format you specified on success.
320 * Warning If an error occurred, OpenWeatherMap returns data in json format ALWAYS
322 * There are three ways to specify the place to get weather information for:
323 * - Use the city name: $query must be a string containing the city name.
324 * - Use the city id: $query must be an integer containing the city id.
325 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
327 * Available languages are (as of 17. July 2013):
342 * - Chinese Traditional - zh_tw
343 * - Chinese Simplified - zh_cn
348 public function getRawWeatherData($query, $units = 'imperial', $lang = 'en', $appid = '', $mode = 'xml')
350 $url = $this->buildUrl($query, $units, $lang, $appid, $mode, $this->weatherUrl);
352 return $this->cacheOrFetchResult($url);
356 * Directly returns the xml/json/html string returned by OpenWeatherMap for the hourly forecast.
358 * @param array|int|string $query The place to get weather information for. For possible values see below.
359 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
360 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
361 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
362 * @param string $mode The format of the data fetched. Possible values are 'json', 'html' and 'xml' (default).
364 * @return string Returns false on failure and the fetched data in the format you specified on success.
366 * Warning If an error occurred, OpenWeatherMap returns data in json format ALWAYS
368 * There are three ways to specify the place to get weather information for:
369 * - Use the city name: $query must be a string containing the city name.
370 * - Use the city id: $query must be an integer containing the city id.
371 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
373 * Available languages are (as of 17. July 2013):
388 * - Chinese Traditional - zh_tw
389 * - Chinese Simplified - zh_cn
394 public function getRawHourlyForecastData($query, $units = 'imperial', $lang = 'en', $appid = '', $mode = 'xml')
396 $url = $this->buildUrl($query, $units, $lang, $appid, $mode, $this->weatherHourlyForecastUrl);
398 return $this->cacheOrFetchResult($url);
402 * Directly returns the xml/json/html string returned by OpenWeatherMap for the daily forecast.
404 * @param array|int|string $query The place to get weather information for. For possible values see below.
405 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
406 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
407 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
408 * @param string $mode The format of the data fetched. Possible values are 'json', 'html' and 'xml' (default)
409 * @param int $cnt How many days of forecast shall be returned? Maximum (and default): 16
411 * @throws \InvalidArgumentException If $cnt is higher than 16.
412 * @return string Returns false on failure and the fetched data in the format you specified on success.
414 * Warning If an error occurred, OpenWeatherMap returns data in json format ALWAYS
416 * There are three ways to specify the place to get weather information for:
417 * - Use the city name: $query must be a string containing the city name.
418 * - Use the city id: $query must be an integer containing the city id.
419 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
421 * Available languages are (as of 17. July 2013):
436 * - Chinese Traditional - zh_tw
437 * - Chinese Simplified - zh_cn
442 public function getRawDailyForecastData($query, $units = 'imperial', $lang = 'en', $appid = '', $mode = 'xml', $cnt = 16)
445 throw new \InvalidArgumentException('$cnt must be 16 or below!');
447 $url = $this->buildUrl($query, $units, $lang, $appid, $mode, $this->weatherDailyForecastUrl) . "&cnt=$cnt";
449 return $this->cacheOrFetchResult($url);
453 * Directly returns the xml/json/html string returned by OpenWeatherMap for the daily forecast.
455 * @param array|int|string $query The place to get weather information for. For possible values see below.
456 * @param \DateTime $start The \DateTime object of the date to get the first weather information from.
457 * @param \DateTime|int $endOrCount Can be either a \DateTime object representing the end of the period to
458 * receive weather history data for or an integer counting the number of
460 * @param string $type The period of the weather history requested. Can be either be either "tick",
462 * @param string $units Can be either 'metric' or 'imperial' (default). This affects almost all units returned.
463 * @param string $lang The language to use for descriptions, default is 'en'. For possible values see below.
464 * @param string $appid Your app id, default ''. See http://openweathermap.org/appid for more details.
466 * @throws \InvalidArgumentException
468 * @return string Returns false on failure and the fetched data in the format you specified on success.
470 * Warning If an error occurred, OpenWeatherMap returns data in json format ALWAYS
472 * There are three ways to specify the place to get weather information for:
473 * - Use the city name: $query must be a string containing the city name.
474 * - Use the city id: $query must be an integer containing the city id.
475 * - Use the coordinates: $query must be an associative array containing the 'lat' and 'lon' values.
477 * Available languages are (as of 17. July 2013):
492 * - Chinese Traditional - zh_tw
493 * - Chinese Simplified - zh_cn
498 public function getRawWeatherHistory($query, \DateTime $start, $endOrCount = 1, $type = 'hour', $units = 'imperial', $lang = 'en', $appid = '')
500 if (!in_array($type, array('tick', 'hour', 'day'))) {
501 throw new \InvalidArgumentException('$type must be either "tick", "hour" or "day"');
504 $queryUrl = $this->weatherHistoryUrl . $this->buildQueryUrlParameter($query) . "&start={$start->format('U')}";
506 if ($endOrCount instanceof \DateTime) {
507 $queryUrl .= "&end={$endOrCount->format('U')}";
508 } else if (is_numeric($endOrCount) && $endOrCount > 0) {
509 $queryUrl .= "&cnt=$endOrCount";
511 throw new \InvalidArgumentException('$endOrCount must be either a \DateTime or a positive integer.');
513 $queryUrl .= "&type=$type&units=$units&lang=$lang";
515 if (!empty($appid)) {
516 $queryUrl .= "&APPID=$appid";
519 return $this->cacheOrFetchResult($queryUrl);
523 * Fetches the result or delivers a cached version of the result.
531 private function cacheOrFetchResult($url)
533 if ($this->cacheClass !== false) {
534 /** @var \Cmfcmf\OpenWeatherMap\AbstractCache $cache */
535 $cache = $this->cacheClass;
536 $cache->setSeconds($this->seconds);
537 if ($cache->isCached($url)) {
538 return $cache->getCached($url);
540 $result = $this->fetcher->fetch($url);
541 $cache->setCached($url, $result);
543 $result = $this->fetcher->fetch($url);
550 * Build the url to fetch weather data from.
557 * @param string $url The url to prepend.
559 * @return bool|string The fetched url, false on failure.
563 private function buildUrl($query, $units, $lang, $appid, $mode, $url)
565 $queryUrl = $this->buildQueryUrlParameter($query);
567 $url = $url . "$queryUrl&units=$units&lang=$lang&mode=$mode";
568 if (!empty($appid)) {
569 $url .= "&APPID=$appid";
576 * Builds the query string for the url.
580 * @return string The built query string for the url.
581 * @throws \InvalidArgumentException If the query parameter is invalid.
585 private function buildQueryUrlParameter($query)
588 case (is_array($query) && isset($query['lat']) && isset($query['lon']) && is_numeric($query['lat']) && is_numeric($query['lon'])):
589 return "lat={$query['lat']}&lon={$query['lon']}";
590 case (is_numeric($query)):
592 case (is_string($query)):
593 return "q=" . urlencode($query);
595 throw new \InvalidArgumentException('Error: $query has the wrong format. See the documentation of OpenWeatherMap::getRawData() to read about valid formats.');