Globalweather.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP version 4 |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2004 The PHP Group |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license, |
  9. // | that is bundled with this package in the file LICENSE, and is |
  10. // | available through the world-wide-web at |
  11. // | http://www.php.net/license/2_02.txt. |
  12. // | If you did not receive a copy of the PHP license and are unable to |
  13. // | obtain it through the world-wide-web, please send a note to |
  14. // | license@php.net so we can mail you a copy immediately. |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Alexander Wirtz <alex@pc4p.net> |
  17. // +----------------------------------------------------------------------+
  18. //
  19. // $Id: Globalweather.php,v 1.16 2004/01/06 19:36:27 eru Exp $
  20. require_once "Services/Weather/Common.php";
  21. // {{{ class Services_Weather_Globalweather
  22. /**
  23. * PEAR::Services_Weather_Globalweather
  24. *
  25. * This class acts as an interface to the soap service of capescience.com. It searches for given
  26. * locations and retrieves current weather data.
  27. *
  28. * GlobalWeather is a SOAP frontend for METAR data, provided by CapeScience. If you want to
  29. * use METAR, you should try this class first, as it is much more comfortable (and also a bit
  30. * faster) than the native METAR-class provided by this package.
  31. *
  32. * For a working example, please take a look at
  33. * docs/Services_Weather/examples/globalweather-basic.php
  34. *
  35. * @author Alexander Wirtz <alex@pc4p.net>
  36. * @link http://www.capescience.com/webservices/globalweather/index.shtml
  37. * @example docs/Services_Weather/examples/globalweather-basic.php
  38. * @package Services_Weather
  39. * @license http://www.php.net/license/2_02.txt
  40. * @version 1.2
  41. */
  42. class Services_Weather_Globalweather extends Services_Weather_Common {
  43. // {{{ properties
  44. /**
  45. * WSDL object, provided by CapeScience
  46. *
  47. * @var object $_wsdl
  48. * @access private
  49. */
  50. var $_wsdl;
  51. /**
  52. * SOAP object to access station data, provided by CapeScience
  53. *
  54. * @var object $_stationSoap
  55. * @access private
  56. */
  57. var $_stationSoap;
  58. /**
  59. * SOAP object to access weather data, provided by CapeScience
  60. *
  61. * @var object $_weaterSoap
  62. * @access private
  63. */
  64. var $_weatherSoap;
  65. // }}}
  66. // {{{ constructor
  67. /**
  68. * Constructor
  69. *
  70. * Requires SOAP to be installed
  71. *
  72. * @param array $options
  73. * @param mixed $error
  74. * @throws PEAR_Error
  75. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  76. * @see Science_Weather::Science_Weather
  77. * @access private
  78. */
  79. function Services_Weather_Globalweather($options, &$error)
  80. {
  81. $perror = null;
  82. $this->Services_Weather_Common($options, $perror);
  83. if (Services_Weather::isError($perror)) {
  84. $error = $perror;
  85. return;
  86. }
  87. include_once "SOAP/Client.php";
  88. $this->_wsdl = new SOAP_WSDL("http://live.capescience.com/wsdl/GlobalWeather.wsdl");
  89. if (isset($this->_wsdl->fault) && Services_Weather::isError($this->_wsdl->fault)) {
  90. $error = Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  91. return;
  92. }
  93. eval($this->_wsdl->generateAllProxies());
  94. if (!class_exists("WebService_GlobalWeather_StationInfo") || !class_exists("WebService_GlobalWeather_GlobalWeather")) {
  95. $error = Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  96. return;
  97. }
  98. $this->_stationSoap = &new WebService_GlobalWeather_StationInfo;
  99. $this->_weatherSoap = &new WebService_GlobalWeather_GlobalWeather;
  100. }
  101. // }}}
  102. // {{{ _checkLocationID()
  103. /**
  104. * Checks the id for valid values and thus prevents silly requests to GlobalWeather server
  105. *
  106. * @param string $id
  107. * @return PEAR_Error|bool
  108. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_NO_LOCATION
  109. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_INVALID_LOCATION
  110. * @access private
  111. */
  112. function _checkLocationID($id)
  113. {
  114. if (!strlen($id)) {
  115. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_NO_LOCATION);
  116. } elseif ($this->_stationSoap->isValidCode($id) === false) {
  117. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_INVALID_LOCATION);
  118. }
  119. return true;
  120. }
  121. // }}}
  122. // {{{ searchLocation()
  123. /**
  124. * Searches IDs for given location, returns array of possible locations or single ID
  125. *
  126. * @param string $location
  127. * @param bool $useFirst If set, first ID of result-array is returned
  128. * @return PEAR_Error|array|string
  129. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  130. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION
  131. * @access public
  132. */
  133. function searchLocation($location, $useFirst = false)
  134. {
  135. // Get search data from server and unserialize
  136. $search = $this->_stationSoap->searchByName($location);
  137. if (Services_Weather::isError($search)) {
  138. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  139. } else {
  140. if (!is_array($search) || !sizeof($search)) {
  141. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION);
  142. } else {
  143. if (!$useFirst && (sizeof($search) > 1)) {
  144. $searchReturn = array();
  145. for ($i = 0; $i < sizeof($search); $i++) {
  146. $searchReturn[$search[$i]->icao] = $search[$i]->name.", ".$search[$i]->country;
  147. }
  148. } elseif ($useFirst || (sizeof($search) == 1)) {
  149. $searchReturn = $search[0]->icao;
  150. }
  151. }
  152. }
  153. return $searchReturn;
  154. }
  155. // }}}
  156. // {{{ searchLocationByCountry()
  157. /**
  158. * Returns IDs with location-name for a given country or all available countries, if no value was given
  159. *
  160. * @param string $country
  161. * @return PEAR_Error|array
  162. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  163. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION
  164. * @access public
  165. */
  166. function searchLocationByCountry($country = "")
  167. {
  168. // Return the available countries as no country was given
  169. if (!strlen($country)) {
  170. $countries = $this->_stationSoap->listCountries();
  171. if (Services_Weather::isError($countries)) {
  172. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  173. }
  174. return $countries;
  175. }
  176. // Now for the real search
  177. $countryLocs = $this->_stationSoap->searchByCountry($country);
  178. // Check result for validity
  179. if (Services_Weather::isError($countryLocs)) {
  180. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  181. } elseif (!is_array($countryLocs)) {
  182. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_LOCATION);
  183. }
  184. // Construct the result
  185. $locations = array();
  186. foreach ($countryLocs as $location) {
  187. $locations[$location->icao] = $location->name.", ".$location->country;
  188. }
  189. asort($locations);
  190. return $locations;
  191. }
  192. // }}}
  193. // {{{ getUnits()
  194. /**
  195. * Returns the units for the current query
  196. *
  197. * @param string $id
  198. * @param string $unitsFormat
  199. * @return array
  200. * @deprecated
  201. * @access public
  202. */
  203. function getUnits($id = null, $unitsFormat = "")
  204. {
  205. return $this->getUnitsFormat($unitsFormat);
  206. }
  207. // }}}
  208. // {{{ getLocation()
  209. /**
  210. * Returns the data for the location belonging to the ID
  211. *
  212. * @param string $id
  213. * @return PEAR_Error|array
  214. * @throws PEAR_Error
  215. * @access public
  216. */
  217. function getLocation($id = "")
  218. {
  219. $status = $this->_checkLocationID($id);
  220. if (Services_Weather::isError($status)) {
  221. return $status;
  222. }
  223. $locationReturn = array();
  224. if ($this->_cacheEnabled && ($location = $this->_cache->get("GW-".$id, "location"))) {
  225. // Get data from cache
  226. $this->_location = $location;
  227. $locationReturn["cache"] = "HIT";
  228. } else {
  229. $location = $this->_stationSoap->getStation($id);
  230. if (Services_Weather::isError($location)) {
  231. return $location;
  232. }
  233. $this->_location = $location;
  234. if ($this->_cacheEnabled) {
  235. // ...and cache it
  236. $expire = constant("SERVICES_WEATHER_EXPIRES_LOCATION");
  237. $this->_cache->extSave("GW-".$id, $this->_location, "", $expire, "location");
  238. }
  239. $locationReturn["cache"] = "MISS";
  240. }
  241. if (strlen($this->_location->region) && strlen($this->_location->country)) {
  242. $locname = $this->_location->name.", ".$this->_location->region.", ".$this->_location->country;
  243. } elseif (strlen($this->_location->country)) {
  244. $locname = $this->_location->name.", ".$this->_location->country;
  245. } else {
  246. $locname = $this->_location->name;
  247. }
  248. $locationReturn["name"] = $locname;
  249. $locationReturn["latitude"] = $this->_location->latitude;
  250. $locationReturn["longitude"] = $this->_location->longitude;
  251. $locationReturn["elevation"] = $this->_location->elevation;
  252. return $locationReturn;
  253. }
  254. // }}}
  255. // {{{ getWeather()
  256. /**
  257. * Returns the weather-data for the supplied location
  258. *
  259. * @param string $id
  260. * @param string $unitsFormat
  261. * @return PEAR_Error|array
  262. * @throws PEAR_Error
  263. * @access public
  264. */
  265. function getWeather($id = "", $unitsFormat = "")
  266. {
  267. static $clouds;
  268. if (!isset($clouds)) {
  269. $clouds = array(
  270. "sky clear",
  271. "few",
  272. "scattered",
  273. "broken",
  274. "overcast",
  275. );
  276. }
  277. $status = $this->_checkLocationID($id);
  278. if (Services_Weather::isError($status)) {
  279. return $status;
  280. }
  281. // Get other data
  282. $units = $this->getUnitsFormat($unitsFormat);
  283. $weatherReturn = array();
  284. if ($this->_cacheEnabled && ($weather = $this->_cache->get("GW-".$id, "weather"))) {
  285. // Same procedure...
  286. $this->_weather = $weather;
  287. $weatherReturn["cache"] = "HIT";
  288. } else {
  289. // ...as last function
  290. $weather = $this->_weatherSoap->getWeatherReport($id);
  291. if (Services_Weather::isError($weather)) {
  292. return $weather;
  293. }
  294. $this->_weather = $weather;
  295. if ($this->_cacheEnabled) {
  296. // ...and cache it
  297. $expire = constant("SERVICES_WEATHER_EXPIRES_WEATHER");
  298. $this->_cache->extSave("GW-".$id, $this->_weather, "", $expire, "weather");
  299. }
  300. $weatherReturn["cache"] = "MISS";
  301. }
  302. $update = trim(str_replace(array("T", "Z"), " ", $this->_weather->timestamp))." GMT";
  303. $weatherReturn["update"] = gmdate(trim($this->_dateFormat." ".$this->_timeFormat), strtotime($update));
  304. if (strlen($this->_weather->station->region) && strlen($this->_weather->station->country)) {
  305. $locname = $this->_weather->station->name.", ".$this->_weather->station->region.", ".$this->_weather->station->country;
  306. } elseif (strlen($this->_weather->station->country)) {
  307. $locname = $this->_weather->station->name.", ".$this->_weather->station->country;
  308. } else {
  309. $locname = $this->_weather->station->name;
  310. }
  311. $weatherReturn["station"] = $locname;
  312. $weatherReturn["wind"] = $this->convertSpeed($this->_weather->wind->prevailing_speed, "mps", $units["wind"]);
  313. $weatherReturn["windDegrees"] = $this->_weather->wind->prevailing_direction->degrees;
  314. $weatherReturn["windDirection"] = $this->_weather->wind->prevailing_direction->compass;
  315. if ($this->_weather->wind->prevailing_speed != $this->_weather->wind->gust_speed) {
  316. $weatherReturn["windGust"] = $this->convertSpeed($this->_weather->wind->gust_speed, "mps", $units["wind"]);
  317. }
  318. if ($this->_weather->wind->varying_from_direction != "" && $this->_weather->wind->varying_to_direction != "") {
  319. $weatherReturn["windVar"] = array (
  320. "from" => $this->_weather->wind->varying_from_direction,
  321. "to" => $this->_weather->wind->varying_to_direction
  322. );
  323. }
  324. $weatherReturn["visibility"] = $this->convertDistance($this->_weather->visibility->distance / 1000, "km", $units["vis"]);
  325. $weatherReturn["visQualifier"] = $this->_weather->visibility->qualifier;
  326. $condition = array();
  327. for ($i = 0; $i < sizeof($this->_weather->phenomena); $i++) {
  328. $condition[] = $this->_weather->phenomena[$i]->string;
  329. }
  330. $weatherReturn["condition"] = implode(", ", $condition);
  331. $layers = array();
  332. for ($i = 0; $i < sizeof($this->_weather->sky->layers); $i++) {
  333. if (strtoupper($this->_weather->sky->layers[$i]->type) != "CLEAR") {
  334. $layers[$i] = array();
  335. $layers[$i]["amount"] = $clouds[$this->_weather->sky->layers[$i]->extent];
  336. $layers[$i]["height"] = $this->convertDistance($this->_weather->sky->layers[$i]->altitude / 1000, "km", "ft");
  337. if (strtoupper($this->_weather->sky->layers[$i]->type) != "CLOUD") {
  338. $layers[$i]["type"] = ucwords(str_replace("_", "", $this->_weather->sky->layers[$i]->type));
  339. }
  340. }
  341. }
  342. if (sizeof($layers)) {
  343. $weatherReturn["clouds"] = $layers;
  344. }
  345. $weatherReturn["temperature"] = $this->convertTemperature($this->_weather->temperature->ambient, "c", $units["temp"]);
  346. $feltTemperature = $this->calculateWindChill($this->convertTemperature($weatherReturn["temperature"], $units["temp"], "f"), $this->convertSpeed($weatherReturn["wind"], $units["wind"], "mph"));
  347. $weatherReturn["feltTemperature"] = $this->convertTemperature($feltTemperature, "f", $units["temp"]);
  348. $weatherReturn["dewPoint"] = $this->convertTemperature($this->_weather->temperature->dewpoint, "c", $units["temp"]);
  349. $weatherReturn["humidity"] = $this->_weather->temperature->relative_humidity;
  350. $weatherReturn["pressure"] = $this->convertPressure($this->_weather->pressure->altimeter, "hpa", $units["pres"]);
  351. return $weatherReturn;
  352. }
  353. // }}}
  354. // {{{ getForecast()
  355. /**
  356. * GlobalWeather has no forecast per se, so this function is just for
  357. * compatibility purposes.
  358. *
  359. * @param string $int
  360. * @param int $days
  361. * @param string $unitsFormat
  362. * @return bool
  363. * @access public
  364. * @deprecated
  365. */
  366. function getForecast($id = null, $days = null, $unitsFormat = null)
  367. {
  368. return false;
  369. }
  370. // }}}
  371. }
  372. // }}}
  373. ?>