Ejse.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  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: Ejse.php,v 1.6 2004/01/06 19:36:27 eru Exp $
  20. require_once "Services/Weather/Common.php";
  21. // {{{ class Services_Weather_Ejse
  22. /**
  23. * PEAR::Services_Weather_Ejse
  24. *
  25. * This class acts as an interface to the soap service of EJSE. It retrieves
  26. * current weather data and forecasts based on postal codes (ZIP).
  27. *
  28. * Currently this service is only available for US territory.
  29. *
  30. * For a working example, please take a look at
  31. * docs/Services_Weather/examples/ejse-basic.php
  32. *
  33. * @author Alexander Wirtz <alex@pc4p.net>
  34. * @link http://www.ejse.com/services/weather_xml_web_services.htm
  35. * @example docs/Services_Weather/examples/ejse-basic.php
  36. * @package Services_Weather
  37. * @license http://www.php.net/license/2_02.txt
  38. * @version 1.2
  39. */
  40. class Services_Weather_Ejse extends Services_Weather_Common {
  41. // {{{ properties
  42. /**
  43. * WSDL object, provided by EJSE
  44. *
  45. * @var object $_wsdl
  46. * @access private
  47. */
  48. var $_wsdl;
  49. /**
  50. * SOAP object to access weather data, provided by EJSE
  51. *
  52. * @var object $_weaterSoap
  53. * @access private
  54. */
  55. var $_weatherSoap;
  56. // }}}
  57. // {{{ constructor
  58. /**
  59. * Constructor
  60. *
  61. * Requires SOAP to be installed
  62. *
  63. * @param array $options
  64. * @param mixed $error
  65. * @throws PEAR_Error
  66. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA
  67. * @see Science_Weather::Science_Weather
  68. * @access private
  69. */
  70. function Services_Weather_Ejse($options, &$error)
  71. {
  72. $perror = null;
  73. $this->Services_Weather_Common($options, $perror);
  74. if (Services_Weather::isError($perror)) {
  75. $error = $perror;
  76. return;
  77. }
  78. include_once "SOAP/Client.php";
  79. $this->_wsdl = new SOAP_WSDL("http://www.ejse.com/WeatherService/Service.asmx?WSDL");
  80. if (isset($this->_wsdl->fault) && Services_Weather::isError($this->_wsdl->fault)) {
  81. $error = Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  82. return;
  83. }
  84. eval($this->_wsdl->generateAllProxies());
  85. if (!class_exists("WebService_Service_ServiceSoap")) {
  86. $error = Services_Weather::raiseError(SERVICES_WEATHER_ERROR_WRONG_SERVER_DATA);
  87. return;
  88. }
  89. $this->_weatherSoap = &new WebService_Service_ServiceSoap;
  90. }
  91. // }}}
  92. // {{{ _checkLocationID()
  93. /**
  94. * Checks the id for valid values and thus prevents silly requests to EJSE server
  95. *
  96. * @param string $id
  97. * @return PEAR_Error|bool
  98. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_NO_LOCATION
  99. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_INVALID_LOCATION
  100. * @access private
  101. */
  102. function _checkLocationID($id)
  103. {
  104. if (!strlen($id)) {
  105. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_NO_LOCATION);
  106. } elseif (!ctype_digit($id) || (strlen($id) != 5)) {
  107. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_INVALID_LOCATION);
  108. }
  109. return true;
  110. }
  111. // }}}
  112. // {{{ searchLocation()
  113. /**
  114. * EJSE offers no search function to date, so this function is disabled.
  115. * Maybe this is the place to interface to some online postcode service...
  116. *
  117. * @param string $location
  118. * @param bool $useFirst
  119. * @return bool
  120. * @access public
  121. * @deprecated
  122. */
  123. function searchLocation($location = null, $useFirst = null)
  124. {
  125. return $false;
  126. }
  127. // }}}
  128. // {{{ searchLocationByCountry()
  129. /**
  130. * EJSE offers no search function to date, so this function is disabled.
  131. * Maybe this is the place to interface to some online postcode service...
  132. *
  133. * @param string $country
  134. * @return bool
  135. * @access public
  136. * @deprecated
  137. */
  138. function searchLocationByCountry($country = null)
  139. {
  140. return $false;
  141. }
  142. // }}}
  143. // {{{ getUnits()
  144. /**
  145. * Returns the units for the current query
  146. *
  147. * @param string $id
  148. * @param string $unitsFormat
  149. * @return array
  150. * @deprecated
  151. * @access public
  152. */
  153. function getUnits($id = null, $unitsFormat = "")
  154. {
  155. return $this->getUnitsFormat($unitsFormat);
  156. }
  157. // }}}
  158. // {{{ getLocation()
  159. /**
  160. * Returns the data for the location belonging to the ID
  161. *
  162. * @param string $id
  163. * @return PEAR_Error|array
  164. * @throws PEAR_Error
  165. * @access public
  166. */
  167. function getLocation($id = "")
  168. {
  169. $status = $this->_checkLocationID($id);
  170. if (Services_Weather::isError($status)) {
  171. return $status;
  172. }
  173. $locationReturn = array();
  174. if ($this->_cacheEnabled && ($weather = $this->_cache->get($id, "weather"))) {
  175. // Get data from cache
  176. $this->_weather = $weather;
  177. $locationReturn["cache"] = "HIT";
  178. } else {
  179. $weather = $this->_weatherSoap->getWeatherInfo($id);
  180. if (Services_Weather::isError($weather)) {
  181. return $weather;
  182. }
  183. $this->_weather = $weather;
  184. if ($this->_cacheEnabled) {
  185. // ...and cache it
  186. $expire = constant("SERVICES_WEATHER_EXPIRES_WEATHER");
  187. $this->_cache->extSave($id, $this->_weather, "", $expire, "weather");
  188. }
  189. $locationReturn["cache"] = "MISS";
  190. }
  191. $locationReturn["name"] = $this->_weather->Location;
  192. return $locationReturn;
  193. }
  194. // }}}
  195. // {{{ getWeather()
  196. /**
  197. * Returns the weather-data for the supplied location
  198. *
  199. * @param string $id
  200. * @param string $unitsFormat
  201. * @return PEAR_Error|array
  202. * @throws PEAR_Error
  203. * @access public
  204. */
  205. function getWeather($id = "", $unitsFormat = "")
  206. {
  207. $status = $this->_checkLocationID($id);
  208. if (Services_Weather::isError($status)) {
  209. return $status;
  210. }
  211. // Get other data
  212. $units = $this->getUnitsFormat($unitsFormat);
  213. $weatherReturn = array();
  214. if ($this->_cacheEnabled && ($weather = $this->_cache->get($id, "weather"))) {
  215. // Same procedure...
  216. $this->_weather = $weather;
  217. $weatherReturn["cache"] = "HIT";
  218. } else {
  219. // ...as last function
  220. $weather = $this->_weatherSoap->getWeatherInfo($id);
  221. if (Services_Weather::isError($weather)) {
  222. return $weather;
  223. }
  224. $this->_weather = $weather;
  225. if ($this->_cacheEnabled) {
  226. // ...and cache it
  227. $expire = constant("SERVICES_WEATHER_EXPIRES_WEATHER");
  228. $this->_cache->extSave($id, $this->_weather, "", $expire, "weather");
  229. }
  230. $weatherReturn["cache"] = "MISS";
  231. }
  232. if (!isset($compass)) {
  233. // Yes, NNE and the likes are multiples of 22.5, but as the other
  234. // services return integers for this value, these directions are
  235. // rounded up
  236. $compass = array(
  237. "north" => array("N", 0),
  238. "north northeast" => array("NNE", 23),
  239. "northeast" => array("NE", 45),
  240. "east northeast" => array("ENE", 68),
  241. "east" => array("E", 90),
  242. "east southeast" => array("ESE", 113),
  243. "southeast" => array("SE", 135),
  244. "south southeast" => array("SSE", 158),
  245. "south" => array("S", 180),
  246. "south southwest" => array("SSW", 203),
  247. "southwest" => array("SW", 225),
  248. "west southwest" => array("WSW", 248),
  249. "west" => array("W", 270),
  250. "west northwest" => array("WNW", 293),
  251. "northwest" => array("NW", 315),
  252. "north northwest" => array("NNW", 338)
  253. );
  254. }
  255. preg_match("/(\w+) (\d+), (\d+), at (\d+:\d+ \wM) [^\(]+(\(([^\)]+)\))?/", $this->_weather->LastUpdated, $update);
  256. if (isset($update[5])) {
  257. $timestring = $update[6];
  258. } else {
  259. $timestring = $update[2]." ".$update[1]." ".$update[3]." ".$update[4]." EST";
  260. }
  261. $weatherReturn["update"] = gmdate(trim($this->_dateFormat." ".$this->_timeFormat), strtotime($timestring));
  262. $weatherReturn["station"] = $this->_weather->ReportedAt;
  263. $weatherReturn["conditionIcon"] = $this->_weather->IconIndex;
  264. preg_match("/(-?\d+)\D+/", $this->_weather->Temprature, $temperature);
  265. $weatherReturn["temperature"] = $this->convertTemperature($temperature[1], "f", $units["temp"]);
  266. preg_match("/(-?\d+)\D+/", $this->_weather->FeelsLike, $feltTemperature);
  267. $weatherReturn["feltTemperature"] = $this->convertTemperature($feltTemperature[1], "f", $units["temp"]);
  268. $weatherReturn["condition"] = $this->_weather->Forecast;
  269. if (preg_match("/([\d\.]+)\D+/", $this->_weather->Visibility, $visibility)) {
  270. $weatherReturn["visibility"] = $this->convertDistance($visibility[1], "sm", $units["vis"]);
  271. } else {
  272. $weatherReturn["visibility"] = trim($this->_weather->Visibility);
  273. }
  274. preg_match("/([\d\.]+) inches and (\w+)/", $this->_weather->Pressure, $pressure);
  275. $weatherReturn["pressure"] = $this->convertPressure($pressure[1], "in", $units["pres"]);
  276. $weatherReturn["pressureTrend"] = $pressure[2];
  277. preg_match("/(-?\d+)\D+/", $this->_weather->DewPoint, $dewPoint);
  278. $weatherReturn["dewPoint"] = $this->convertTemperature($dewPoint[1], "f", $units["temp"]);
  279. preg_match("/(\d+) (\w+)/", $this->_weather->UVIndex, $uvIndex);
  280. $weatherReturn["uvIndex"] = $uvIndex[1];
  281. $weatherReturn["uvText"] = $uvIndex[2];
  282. $weatherReturn["humidity"] = str_replace("%", "", $this->_weather->Humidity);
  283. if (preg_match("/From the ([\w\ ]+) at ([\d\.]+) (gusting to ([\d\.]+) )?mph/", $this->_weather->Wind, $wind)) {
  284. $weatherReturn["wind"] = $this->convertSpeed($wind[2], "mph", $units["wind"]);
  285. if (isset($wind[4])) {
  286. $weatherReturn["windGust"] = $this->convertSpeed($wind[4], "mph", $units["wind"]);
  287. }
  288. $weatherReturn["windDegrees"] = $compass[strtolower($wind[1])][1];
  289. $weatherReturn["windDirection"] = $compass[strtolower($wind[1])][0];
  290. } elseif (strtolower($this->_weather->Wind) == "calm") {
  291. $weatherReturn["wind"] = 0;
  292. $weatherReturn["windDegrees"] = 0;
  293. $weatherReturn["windDirection"] = "CALM";
  294. }
  295. return $weatherReturn;
  296. }
  297. // }}}
  298. // {{{ getForecast()
  299. /**
  300. * Get the forecast for the next days
  301. *
  302. * @param string $int
  303. * @param int $days Values between 1 and 9
  304. * @param string $unitsFormat
  305. * @return PEAR_Error|array
  306. * @throws PEAR_Error
  307. * @access public
  308. */
  309. function getForecast($id = "", $days = 2, $unitsFormat = "")
  310. {
  311. $status = $this->_checkLocationID($id);
  312. if (Services_Weather::isError($status)) {
  313. return $status;
  314. }
  315. if (!in_array($days, range(1, 9))) {
  316. $days = 2;
  317. }
  318. // Get other data
  319. $units = $this->getUnitsFormat($unitsFormat);
  320. $forecastReturn = array();
  321. if ($this->_cacheEnabled && ($forecast = $this->_cache->get($id, "forecast"))) {
  322. // Same procedure...
  323. $this->_forecast = $forecast;
  324. $forecastReturn["cache"] = "HIT";
  325. } else {
  326. // ...as last function
  327. $forecast = $this->_weatherSoap->GetNineDayForecastInfo($id);
  328. if (Services_Weather::isError($forecast)) {
  329. return $forecast;
  330. }
  331. $this->_forecast = $forecast;
  332. if ($this->_cacheEnabled) {
  333. // ...and cache it
  334. $expire = constant("SERVICES_WEATHER_EXPIRES_FORECAST");
  335. $this->_cache->extSave($id, $this->_forecast, "", $expire, "forecast");
  336. }
  337. $forecastReturn["cache"] = "MISS";
  338. }
  339. $forecastReturn["days"] = array();
  340. for ($i = 1; $i <= $days; $i++) {
  341. preg_match("/(-?\d+)\D+/", $this->_forecast->{"Day".$i}->High, $temperatureHigh);
  342. preg_match("/(-?\d+)\D+/", $this->_forecast->{"Day".$i}->Low, $temperatureLow);
  343. $day = array(
  344. "tempertureHigh" => $this->convertTemperature($temperatureHigh[1], "f", $units["temp"]),
  345. "temperatureLow" => $this->convertTemperature($temperatureLow[1], "f", $units["temp"]),
  346. "day" => array(
  347. "condition" => $this->_forecast->{"Day".$i}->Forecast,
  348. "conditionIcon" => $this->_forecast->{"Day".$i}->IconIndex,
  349. "precipitation" => trim(str_replace("%", "", $this->_forecast->{"Day".$i}->PrecipChance))
  350. )
  351. );
  352. $forecastReturn["days"][] = $day;
  353. }
  354. return $forecastReturn;
  355. }
  356. // }}}
  357. }
  358. // }}}
  359. ?>