PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/php-pear-Services-Weather-1.4.6/Services_Weather-1.4.6/Weather/Common.php

#
PHP | 1412 lines | 805 code | 126 blank | 481 comment | 226 complexity | 42fb880569aa107262c5c2e4cf3c6681 MD5 | raw file
  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3. /**
  4. * PEAR::Services_Weather_Common
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * <LICENSE>
  9. * Copyright (c) 2005-2011, Alexander Wirtz
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * o Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. * o Redistributions in binary form must reproduce the above copyright notice,
  18. * this list of conditions and the following disclaimer in the documentation
  19. * and/or other materials provided with the distribution.
  20. * o Neither the name of the software nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  25. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  28. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  29. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  30. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  31. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  32. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  33. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  34. * POSSIBILITY OF SUCH DAMAGE.
  35. * </LICENSE>
  36. *
  37. * @category Web Services
  38. * @package Services_Weather
  39. * @author Alexander Wirtz <alex@pc4p.net>
  40. * @copyright 2005-2011 Alexander Wirtz
  41. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  42. * @version CVS: $Id: Common.php 314012 2011-08-01 11:04:57Z eru $
  43. * @link http://pear.php.net/package/Services_Weather
  44. * @filesource
  45. */
  46. require_once "Services/Weather.php";
  47. // {{{ constants
  48. // {{{ natural constants and measures
  49. define("SERVICES_WEATHER_RADIUS_EARTH", 6378.15);
  50. // }}}
  51. // {{{ default values for the sun-functions
  52. define("SERVICES_WEATHER_SUNFUNCS_DEFAULT_LATITUDE", 31.7667);
  53. define("SERVICES_WEATHER_SUNFUNCS_DEFAULT_LONGITUDE", 35.2333);
  54. define("SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH", 90.83);
  55. define("SERVICES_WEATHER_SUNFUNCS_SUNSET_ZENITH", 90.83);
  56. // }}}
  57. // }}}
  58. // {{{ class Services_Weather_Common
  59. /**
  60. * Parent class for weather-services. Defines common functions for unit
  61. * conversions, checks for cache enabling and does other miscellaneous
  62. * things.
  63. *
  64. * @category Web Services
  65. * @package Services_Weather
  66. * @author Alexander Wirtz <alex@pc4p.net>
  67. * @copyright 2005-2011 Alexander Wirtz
  68. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  69. * @version Release: 1.4.6
  70. * @link http://pear.php.net/package/Services_Weather
  71. */
  72. class Services_Weather_Common {
  73. // {{{ properties
  74. /**
  75. * Format of the units provided (standard/metric/custom)
  76. *
  77. * @var string $_unitsFormat
  78. * @access private
  79. */
  80. var $_unitsFormat = "s";
  81. /**
  82. * Custom format of the units
  83. *
  84. * @var array $_customUnitsFormat
  85. * @access private
  86. */
  87. var $_customUnitsFormat = array(
  88. "temp" => "f",
  89. "vis" => "sm",
  90. "height" => "ft",
  91. "wind" => "mph",
  92. "pres" => "in",
  93. "rain" => "in"
  94. );
  95. /**
  96. * Options for HTTP requests
  97. *
  98. * @var array $_httpOptions
  99. * @access private
  100. */
  101. var $_httpOptions = array();
  102. /**
  103. * Format of the used dates
  104. *
  105. * @var string $_dateFormat
  106. * @access private
  107. */
  108. var $_dateFormat = "m/d/y";
  109. /**
  110. * Format of the used times
  111. *
  112. * @var string $_timeFormat
  113. * @access private
  114. */
  115. var $_timeFormat = "G:i A";
  116. /**
  117. * Object containing the location-data
  118. *
  119. * @var object stdClass $_location
  120. * @access private
  121. */
  122. var $_location;
  123. /**
  124. * Object containing the weather-data
  125. *
  126. * @var object stdClass $_weather
  127. * @access private
  128. */
  129. var $_weather;
  130. /**
  131. * Object containing the forecast-data
  132. *
  133. * @var object stdClass $_forecast
  134. * @access private
  135. */
  136. var $_forecast;
  137. /**
  138. * Cache, containing the data-objects
  139. *
  140. * @var object Cache $_cache
  141. * @access private
  142. */
  143. var $_cache;
  144. /**
  145. * Provides check for Cache
  146. *
  147. * @var bool $_cacheEnabled
  148. * @access private
  149. */
  150. var $_cacheEnabled = false;
  151. // }}}
  152. // {{{ constructor
  153. /**
  154. * Constructor
  155. *
  156. * @param array $options
  157. * @param mixed $error
  158. * @throws PEAR_Error
  159. * @access private
  160. */
  161. function Services_Weather_Common($options, &$error)
  162. {
  163. // Set some constants for the case when PHP4 is used, as the
  164. // date_sunset/sunrise functions are not implemented there
  165. if (!defined("SUNFUNCS_RET_TIMESTAMP")) {
  166. define("SUNFUNCS_RET_TIMESTAMP", 0);
  167. define("SUNFUNCS_RET_STRING", 1);
  168. define("SUNFUNCS_RET_DOUBLE", 2);
  169. }
  170. // Set options accordingly
  171. if (isset($options["cacheType"])) {
  172. if (isset($options["cacheOptions"])) {
  173. $status = $this->setCache($options["cacheType"], $options["cacheOptions"]);
  174. } else {
  175. $status = $this->setCache($options["cacheType"]);
  176. }
  177. if (Services_Weather::isError($status)) {
  178. $error = $status;
  179. return;
  180. }
  181. }
  182. if (isset($options["unitsFormat"])) {
  183. if (isset($options["customUnitsFormat"])) {
  184. $this->setUnitsFormat($options["unitsFormat"], $options["customUnitsFormat"]);
  185. } else {
  186. $this->setUnitsFormat($options["unitsFormat"]);
  187. }
  188. }
  189. if (isset($options["httpTimeout"])) {
  190. $this->setHttpTimeout($options["httpTimeout"]);
  191. } else {
  192. $this->setHttpTimeout(60);
  193. }
  194. if (isset($options["httpProxy"])) {
  195. $status = $this->setHttpProxy($options["httpProxy"]);
  196. if (Services_Weather::isError($status)) {
  197. $error = $status;
  198. return;
  199. }
  200. }
  201. if (isset($options["dateFormat"])) {
  202. $this->setDateTimeFormat($options["dateFormat"], "");
  203. }
  204. if (isset($options["timeFormat"])) {
  205. $this->setDateTimeFormat("", $options["timeFormat"]);
  206. }
  207. }
  208. // }}}
  209. // {{{ setCache()
  210. /**
  211. * Enables caching the data, usage strongly recommended
  212. *
  213. * Requires Cache to be installed
  214. *
  215. * @param string $cacheType
  216. * @param array $cacheOptions
  217. * @return PEAR_Error|bool
  218. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED
  219. * @access public
  220. */
  221. function setCache($cacheType = "file", $cacheOptions = array())
  222. {
  223. if ($cacheType == "lite") {
  224. if ((@include_once "Cache/Lite.php") == false) {
  225. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
  226. } else {
  227. $cacheOptions["automaticSerialization"] = true;
  228. $cacheOptions["pearErrorMode"] = CACHE_LITE_ERROR_RETURN;
  229. $cacheOptions["lifeTime"] = null;
  230. @$cache = new Cache_Lite($cacheOptions);
  231. }
  232. } else {
  233. // The error handling in Cache is a bit crummy (read: not existent)
  234. // so we have to do that on our own...
  235. if ((@include_once "Cache.php") === false) {
  236. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
  237. } else {
  238. @$cache = new Cache($cacheType, $cacheOptions);
  239. }
  240. }
  241. if (is_object($cache) && (strtolower(get_class($cache)) == "cache_lite" || strtolower(get_class($cache)) == "cache" || is_subclass_of($cache, "cache"))) {
  242. $this->_cache = $cache;
  243. $this->_cacheEnabled = true;
  244. } else {
  245. $this->_cache = null;
  246. $this->_cacheEnabled = false;
  247. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
  248. }
  249. return true;
  250. }
  251. // }}}
  252. // {{{ _getCache()
  253. /**
  254. * Wrapper to retrieve cached data
  255. *
  256. * Requires Cache to be installed
  257. *
  258. * @param string $id
  259. * @param string $type
  260. * @return array|bool
  261. * @access private
  262. */
  263. function _getCache($id, $type)
  264. {
  265. if ($this->_cacheEnabled) {
  266. if (strtolower(get_class($this->_cache)) == "cache_lite") {
  267. $this->_cache->setLifeTime(constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)));
  268. $cache = $this->_cache->get($id, $type);
  269. } else {
  270. $cache = $this->_cache->get($id, $type);
  271. }
  272. return $cache;
  273. } else {
  274. return false;
  275. }
  276. }
  277. // }}}
  278. // {{{ _getUserCache()
  279. /**
  280. * Wrapper to retrieve cached user-data
  281. *
  282. * Requires Cache to be installed
  283. *
  284. * @param string $id
  285. * @param string $type
  286. * @return array|bool
  287. * @access private
  288. */
  289. function _getUserCache($id, $type)
  290. {
  291. if ($this->_cacheEnabled) {
  292. if (strtolower(get_class($this->_cache)) == "cache_lite") {
  293. $this->_cache->setLifeTime(constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)));
  294. $cache = $this->_cache->get($id, $type."_user");
  295. } else {
  296. $cache = $this->_cache->getUserdata($id, $type);
  297. }
  298. return $cache;
  299. } else {
  300. return false;
  301. }
  302. }
  303. // }}}
  304. // {{{ _saveCache()
  305. /**
  306. * Wrapper to save data to cache
  307. *
  308. * Requires Cache to be installed
  309. *
  310. * @param string $id
  311. * @param mixed $data
  312. * @param mixed $userData
  313. * @param string $type
  314. * @return array|bool
  315. * @access private
  316. */
  317. function _saveCache($id, $data, $userData, $type)
  318. {
  319. if ($this->_cacheEnabled) {
  320. if (strtolower(get_class($this->_cache)) == "cache_lite") {
  321. $this->_cache->setLifeTime(null);
  322. return ($this->_cache->save($data, $id, $type) && $this->_cache->save($userData, $id, $type."_user"));
  323. } else {
  324. return $this->_cache->extSave($id, $data, $userData, constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)), $type);
  325. }
  326. } else {
  327. return false;
  328. }
  329. }
  330. // }}}
  331. // {{{ setUnitsFormat()
  332. /**
  333. * Changes the representation of the units (standard/metric)
  334. *
  335. * @param string $unitsFormat
  336. * @param array $customUnitsFormat
  337. * @access public
  338. */
  339. function setUnitsFormat($unitsFormat, $customUnitsFormat = array())
  340. {
  341. static $acceptedFormats;
  342. if (!isset($acceptedFormats)) {
  343. $acceptedFormats = array(
  344. "temp" => array("c", "f"),
  345. "vis" => array("m", "km", "ft", "sm"),
  346. "height" => array("m", "ft"),
  347. "wind" => array("mph", "kmh", "kt", "mps", "fps", "bft"),
  348. "pres" => array("in", "hpa", "mb", "mm", "atm"),
  349. "rain" => array("in", "mm")
  350. );
  351. }
  352. if (strlen($unitsFormat) && in_array(strtolower($unitsFormat{0}), array("c", "m", "s"))) {
  353. $this->_unitsFormat = strtolower($unitsFormat{0});
  354. if ($this->_unitsFormat == "c" && is_array($customUnitsFormat)) {
  355. foreach ($customUnitsFormat as $key => $value) {
  356. if (array_key_exists($key, $acceptedFormats) && in_array($value, $acceptedFormats[$key])) {
  357. $this->_customUnitsFormat[$key] = $value;
  358. }
  359. }
  360. } elseif ($this->_unitsFormat == "c") {
  361. $this->_unitsFormat = "s";
  362. }
  363. }
  364. }
  365. // }}}
  366. // {{{ setHttpOption()
  367. /**
  368. * Sets an option for usage in HTTP_Request objects
  369. *
  370. * @param string $varName
  371. * @param mixed $varValue
  372. * @access public
  373. */
  374. function setHttpOption($varName, $varValue)
  375. {
  376. if (is_string($varName) && $varName != "" && !empty($varValue)) {
  377. $this->_httpOptions[$varName] = $varValue;
  378. }
  379. }
  380. // }}}
  381. // {{{ setHttpTimeout()
  382. /**
  383. * Sets the timeout in seconds for HTTP requests
  384. *
  385. * @param int $httpTimeout
  386. * @access public
  387. */
  388. function setHttpTimeout($httpTimeout)
  389. {
  390. if (is_int($httpTimeout)) {
  391. $this->_httpOptions["timeout"] = $httpTimeout;
  392. }
  393. }
  394. // }}}
  395. // {{{ setHttpProxy()
  396. /**
  397. * Sets the proxy for HTTP requests
  398. *
  399. * @param string $httpProxy
  400. * @access public
  401. */
  402. function setHttpProxy($httpProxy)
  403. {
  404. if (($proxy = parse_url($httpProxy)) !== false && $proxy["scheme"] == "http") {
  405. if (isset($proxy["user"]) && $proxy["user"] != "") {
  406. $this->_httpOptions["proxy_user"] = $proxy["user"];
  407. }
  408. if (isset($proxy["pass"]) && $proxy["pass"] != "") {
  409. $this->_httpOptions["proxy_pass"] = $proxy["pass"];
  410. }
  411. if (isset($proxy["host"]) && $proxy["host"] != "") {
  412. $this->_httpOptions["proxy_host"] = $proxy["host"];
  413. }
  414. if (isset($proxy["port"]) && $proxy["port"] != "") {
  415. $this->_httpOptions["proxy_port"] = $proxy["port"];
  416. }
  417. return true;
  418. } else {
  419. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID, __FILE__, __LINE__);
  420. }
  421. }
  422. // }}}
  423. // {{{ getUnitsFormat()
  424. /**
  425. * Returns the selected units format
  426. *
  427. * @param string $unitsFormat
  428. * @return array
  429. * @access public
  430. */
  431. function getUnitsFormat($unitsFormat = "")
  432. {
  433. // This is cheap'o stuff
  434. if (strlen($unitsFormat) && in_array(strtolower($unitsFormat{0}), array("c", "m", "s"))) {
  435. $unitsFormat = strtolower($unitsFormat{0});
  436. } else {
  437. $unitsFormat = $this->_unitsFormat;
  438. }
  439. $c = $this->_customUnitsFormat;
  440. $m = array(
  441. "temp" => "c",
  442. "vis" => "km",
  443. "height" => "m",
  444. "wind" => "kmh",
  445. "pres" => "mb",
  446. "rain" => "mm"
  447. );
  448. $s = array(
  449. "temp" => "f",
  450. "vis" => "sm",
  451. "height" => "ft",
  452. "wind" => "mph",
  453. "pres" => "in",
  454. "rain" => "in"
  455. );
  456. return ${$unitsFormat};
  457. }
  458. // }}}
  459. // {{{ setDateTimeFormat()
  460. /**
  461. * Changes the representation of time and dates (see http://www.php.net/date)
  462. *
  463. * @param string $dateFormat
  464. * @param string $timeFormat
  465. * @access public
  466. */
  467. function setDateTimeFormat($dateFormat = "", $timeFormat = "")
  468. {
  469. if (strlen($dateFormat)) {
  470. $this->_dateFormat = $dateFormat;
  471. }
  472. if (strlen($timeFormat)) {
  473. $this->_timeFormat = $timeFormat;
  474. }
  475. }
  476. // }}}
  477. // {{{ convertTemperature()
  478. /**
  479. * Convert temperature between f and c
  480. *
  481. * @param float $temperature
  482. * @param string $from
  483. * @param string $to
  484. * @return float
  485. * @access public
  486. */
  487. function convertTemperature($temperature, $from, $to)
  488. {
  489. if ($temperature == "N/A") {
  490. return $temperature;
  491. }
  492. $from = strtolower($from{0});
  493. $to = strtolower($to{0});
  494. $result = array(
  495. "f" => array(
  496. "f" => $temperature, "c" => ($temperature - 32) / 1.8
  497. ),
  498. "c" => array(
  499. "f" => 1.8 * $temperature + 32, "c" => $temperature
  500. )
  501. );
  502. return $result[$from][$to];
  503. }
  504. // }}}
  505. // {{{ convertSpeed()
  506. /**
  507. * Convert speed between mph, kmh, kt, mps, fps and bft
  508. *
  509. * Function will return "false" when trying to convert from
  510. * Beaufort, as it is a scale and not a true measurement
  511. *
  512. * @param float $speed
  513. * @param string $from
  514. * @param string $to
  515. * @return float|int|bool
  516. * @access public
  517. * @link http://www.spc.noaa.gov/faq/tornado/beaufort.html
  518. */
  519. function convertSpeed($speed, $from, $to)
  520. {
  521. $from = strtolower($from);
  522. $to = strtolower($to);
  523. static $factor;
  524. static $beaufort;
  525. if (!isset($factor)) {
  526. $factor = array(
  527. "mph" => array(
  528. "mph" => 1, "kmh" => 1.609344, "kt" => 0.8689762, "mps" => 0.44704, "fps" => 1.4666667
  529. ),
  530. "kmh" => array(
  531. "mph" => 0.6213712, "kmh" => 1, "kt" => 0.5399568, "mps" => 0.2777778, "fps" => 0.9113444
  532. ),
  533. "kt" => array(
  534. "mph" => 1.1507794, "kmh" => 1.852, "kt" => 1, "mps" => 0.5144444, "fps" => 1.6878099
  535. ),
  536. "mps" => array(
  537. "mph" => 2.2369363, "kmh" => 3.6, "kt" => 1.9438445, "mps" => 1, "fps" => 3.2808399
  538. ),
  539. "fps" => array(
  540. "mph" => 0.6818182, "kmh" => 1.09728, "kt" => 0.5924838, "mps" => 0.3048, "fps" => 1
  541. )
  542. );
  543. // Beaufort scale, measurements are in knots
  544. $beaufort = array(
  545. 1, 3, 6, 10,
  546. 16, 21, 27, 33,
  547. 40, 47, 55, 63
  548. );
  549. }
  550. if ($from == "bft") {
  551. return false;
  552. } elseif ($to == "bft") {
  553. $speed = round($speed * $factor[$from]["kt"], 0);
  554. for ($i = 0; $i < sizeof($beaufort); $i++) {
  555. if ($speed <= $beaufort[$i]) {
  556. return $i;
  557. }
  558. }
  559. return sizeof($beaufort);
  560. } else {
  561. return ($speed * $factor[$from][$to]);
  562. }
  563. }
  564. // }}}
  565. // {{{ convertPressure()
  566. /**
  567. * Convert pressure between in, hpa, mb, mm and atm
  568. *
  569. * @param float $pressure
  570. * @param string $from
  571. * @param string $to
  572. * @return float
  573. * @access public
  574. */
  575. function convertPressure($pressure, $from, $to)
  576. {
  577. $from = strtolower($from);
  578. $to = strtolower($to);
  579. static $factor;
  580. if (!isset($factor)) {
  581. $factor = array(
  582. "in" => array(
  583. "in" => 1, "hpa" => 33.863887, "mb" => 33.863887, "mm" => 25.4, "atm" => 0.0334213
  584. ),
  585. "hpa" => array(
  586. "in" => 0.02953, "hpa" => 1, "mb" => 1, "mm" => 0.7500616, "atm" => 0.0009869
  587. ),
  588. "mb" => array(
  589. "in" => 0.02953, "hpa" => 1, "mb" => 1, "mm" => 0.7500616, "atm" => 0.0009869
  590. ),
  591. "mm" => array(
  592. "in" => 0.0393701, "hpa" => 1.3332239, "mb" => 1.3332239, "mm" => 1, "atm" => 0.0013158
  593. ),
  594. "atm" => array(
  595. "in" => 29,921258, "hpa" => 1013.2501, "mb" => 1013.2501, "mm" => 759.999952, "atm" => 1
  596. )
  597. );
  598. }
  599. return ($pressure * $factor[$from][$to]);
  600. }
  601. // }}}
  602. // {{{ convertDistance()
  603. /**
  604. * Convert distance between km, ft and sm
  605. *
  606. * @param float $distance
  607. * @param string $from
  608. * @param string $to
  609. * @return float
  610. * @access public
  611. */
  612. function convertDistance($distance, $from, $to)
  613. {
  614. $to = strtolower($to);
  615. $from = strtolower($from);
  616. static $factor;
  617. if (!isset($factor)) {
  618. $factor = array(
  619. "m" => array(
  620. "m" => 1, "km" => 1000, "ft" => 3.280839895, "sm" => 0.0006213699
  621. ),
  622. "km" => array(
  623. "m" => 0.001, "km" => 1, "ft" => 3280.839895, "sm" => 0.6213699
  624. ),
  625. "ft" => array(
  626. "m" => 0.3048, "km" => 0.0003048, "ft" => 1, "sm" => 0.0001894
  627. ),
  628. "sm" => array(
  629. "m" => 0.0016093472, "km" => 1.6093472, "ft" => 5280.0106, "sm" => 1
  630. )
  631. );
  632. }
  633. return ($distance * $factor[$from][$to]);
  634. }
  635. // }}}
  636. // {{{ calculateWindChill()
  637. /**
  638. * Calculate windchill from temperature and windspeed (enhanced formula)
  639. *
  640. * Temperature has to be entered in deg F, speed in mph!
  641. *
  642. * @param float $temperature
  643. * @param float $speed
  644. * @return float
  645. * @access public
  646. * @link http://www.nws.noaa.gov/om/windchill/
  647. */
  648. function calculateWindChill($temperature, $speed)
  649. {
  650. return (35.74 + 0.6215 * $temperature - 35.75 * pow($speed, 0.16) + 0.4275 * $temperature * pow($speed, 0.16));
  651. }
  652. // }}}
  653. // {{{ calculateHumidity()
  654. /**
  655. * Calculate humidity from temperature and dewpoint
  656. * This is only an approximation, there is no exact formula, this
  657. * one here is called Magnus-Formula
  658. *
  659. * Temperature and dewpoint have to be entered in deg C!
  660. *
  661. * @param float $temperature
  662. * @param float $dewPoint
  663. * @return float
  664. * @access public
  665. * @link http://www.faqs.org/faqs/meteorology/temp-dewpoint/
  666. */
  667. function calculateHumidity($temperature, $dewPoint)
  668. {
  669. // First calculate saturation steam pressure for both temperatures
  670. if ($temperature >= 0) {
  671. $a = 7.5;
  672. $b = 237.3;
  673. } else {
  674. $a = 7.6;
  675. $b = 240.7;
  676. }
  677. $tempSSP = 6.1078 * pow(10, ($a * $temperature) / ($b + $temperature));
  678. if ($dewPoint >= 0) {
  679. $a = 7.5;
  680. $b = 237.3;
  681. } else {
  682. $a = 7.6;
  683. $b = 240.7;
  684. }
  685. $dewSSP = 6.1078 * pow(10, ($a * $dewPoint) / ($b + $dewPoint));
  686. return (100 * $dewSSP / $tempSSP);
  687. }
  688. // }}}
  689. // {{{ calculateDewPoint()
  690. /**
  691. * Calculate dewpoint from temperature and humidity
  692. * This is only an approximation, there is no exact formula, this
  693. * one here is called Magnus-Formula
  694. *
  695. * Temperature has to be entered in deg C!
  696. *
  697. * @param float $temperature
  698. * @param float $humidity
  699. * @return float
  700. * @access public
  701. * @link http://www.faqs.org/faqs/meteorology/temp-dewpoint/
  702. */
  703. function calculateDewPoint($temperature, $humidity)
  704. {
  705. if ($temperature >= 0) {
  706. $a = 7.5;
  707. $b = 237.3;
  708. } else {
  709. $a = 7.6;
  710. $b = 240.7;
  711. }
  712. // First calculate saturation steam pressure for temperature
  713. $SSP = 6.1078 * pow(10, ($a * $temperature) / ($b + $temperature));
  714. // Steam pressure
  715. $SP = $humidity / 100 * $SSP;
  716. $v = log($SP / 6.1078, 10);
  717. return ($b * $v / ($a - $v));
  718. }
  719. // }}}
  720. // {{{ polar2cartesian()
  721. /**
  722. * Convert polar coordinates to cartesian coordinates
  723. *
  724. * @param float $latitude
  725. * @param float $longitude
  726. * @return array
  727. * @access public
  728. */
  729. function polar2cartesian($latitude, $longitude)
  730. {
  731. $theta = deg2rad($latitude);
  732. $phi = deg2rad($longitude);
  733. $x = SERVICES_WEATHER_RADIUS_EARTH * cos($phi) * cos($theta);
  734. $y = SERVICES_WEATHER_RADIUS_EARTH * sin($phi) * cos($theta);
  735. $z = SERVICES_WEATHER_RADIUS_EARTH * sin($theta);
  736. return array($x, $y, $z);
  737. }
  738. // }}}
  739. // {{{ calculateMoonPhase()
  740. /**
  741. * Calculates the moon age and phase
  742. *
  743. * The algorithms for this functions were taken from the German Wikipedia
  744. * entry on Julian Daycount for getting the accurate JD to the second and
  745. * the overall moon calculation were done according to
  746. * Stephen R. Schmitt's website, which is cited multiple times on the web
  747. * for this kind of calculation.
  748. *
  749. * The date has to be entered as a timestamp!
  750. *
  751. * @param int $date
  752. * @return PEAR_Error|array
  753. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_MOONFUNCS_DATE_INVALID
  754. * @access public
  755. * @link http://de.wikipedia.org/wiki/Julianisches_Datum
  756. * @link http://mysite.verizon.net/res148h4j/javascript/script_moon_phase.html
  757. */
  758. function calculateMoonPhase($date)
  759. {
  760. // Date must be timestamp for now
  761. if (!is_int($date)) {
  762. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_MOONFUNCS_DATE_INVALID, __FILE__, __LINE__);
  763. }
  764. $moon = array();
  765. $year = date("Y", $date);
  766. $month = date("n", $date);
  767. $day = date("j", $date);
  768. $hour = date("G", $date);
  769. $min = date("i", $date);
  770. $sec = date("s", $date);
  771. $age = 0.0; // Moon's age in days from New Moon
  772. $distance = 0.0; // Moon's distance in Earth radii
  773. $latitude = 0.0; // Moon's ecliptic latitude in degrees
  774. $longitude = 0.0; // Moon's ecliptic longitude in degrees
  775. $phase = ""; // Moon's phase
  776. $zodiac = ""; // Moon's zodiac
  777. $icon = ""; // The icon to represent the moon phase
  778. $YY = 0;
  779. $MM = 0;
  780. $DD = 0;
  781. $HH = 0;
  782. $A = 0;
  783. $B = 0;
  784. $JD = 0;
  785. $IP = 0.0;
  786. $DP = 0.0;
  787. $NP = 0.0;
  788. $RP = 0.0;
  789. // Calculate Julian Daycount to the second
  790. if ($month > 2) {
  791. $YY = $year;
  792. $MM = $month;
  793. } else {
  794. $YY = $year - 1;
  795. $MM = $month + 12;
  796. }
  797. $DD = $day;
  798. $HH = $hour/24 + $min/1440 + $sec/86400;
  799. // Check for Gregorian date and adjust JD appropriately
  800. if (($year*10000 + $month*100 + $day) >= 15821015) {
  801. $A = floor($YY/100);
  802. $B = 2 - $A + floor($A/4);
  803. }
  804. $JD = floor(365.25*($YY+4716)) + floor(30.6001*($MM+1)) + $DD + $HH + $B - 1524.5;
  805. // Calculate moon's age in days
  806. $IP = ($JD - 2451550.1) / 29.530588853;
  807. if (($IP = $IP - floor($IP)) < 0) $IP++;
  808. $age = $IP * 29.530588853;
  809. switch ($age) {
  810. case ($age < 1.84566):
  811. $phase = "New"; break;
  812. case ($age < 5.53699):
  813. $phase = "Waxing Crescent"; break;
  814. case ($age < 9.22831):
  815. $phase = "First Quarter"; break;
  816. case ($age < 12.91963):
  817. $phase = "Waxing Gibbous"; break;
  818. case ($age < 16.61096):
  819. $phase = "Full"; break;
  820. case ($age < 20.30228):
  821. $phase = "Waning Gibbous"; break;
  822. case ($age < 23.99361):
  823. $phase = "Last Quarter"; break;
  824. case ($age < 27.68493):
  825. $phase = "Waning Crescent"; break;
  826. default:
  827. $phase = "New";
  828. }
  829. // Convert phase to radians
  830. $IP = $IP * 2 * pi();
  831. // Calculate moon's distance
  832. $DP = ($JD - 2451562.2) / 27.55454988;
  833. if (($DP = $DP - floor($DP)) < 0) $DP++;
  834. $DP = $DP * 2 * pi();
  835. $distance = 60.4 - 3.3 * cos($DP) - 0.6 * cos(2 * $IP - $DP) - 0.5 * cos(2 * $IP);
  836. // Calculate moon's ecliptic latitude
  837. $NP = ($JD - 2451565.2) / 27.212220817;
  838. if (($NP = $NP - floor($NP)) < 0) $NP++;
  839. $NP = $NP * 2 * pi();
  840. $latitude = 5.1 * sin($NP);
  841. // Calculate moon's ecliptic longitude
  842. $RP = ($JD - 2451555.8) / 27.321582241;
  843. if (($RP = $RP - floor($RP)) < 0) $RP++;
  844. $longitude = 360 * $RP + 6.3 * sin($DP) + 1.3 * sin(2 * $IP - $DP) + 0.7 * sin(2 * $IP);
  845. if ($longitude >= 360) $longitude -= 360;
  846. switch ($longitude) {
  847. case ($longitude < 33.18):
  848. $zodiac = "Pisces"; break;
  849. case ($longitude < 51.16):
  850. $zodiac = "Aries"; break;
  851. case ($longitude < 93.44):
  852. $zodiac = "Taurus"; break;
  853. case ($longitude < 119.48):
  854. $zodiac = "Gemini"; break;
  855. case ($longitude < 135.30):
  856. $zodiac = "Cancer"; break;
  857. case ($longitude < 173.34):
  858. $zodiac = "Leo"; break;
  859. case ($longitude < 224.17):
  860. $zodiac = "Virgo"; break;
  861. case ($longitude < 242.57):
  862. $zodiac = "Libra"; break;
  863. case ($longitude < 271.26):
  864. $zodiac = "Scorpio"; break;
  865. case ($longitude < 302.49):
  866. $zodiac = "Sagittarius"; break;
  867. case ($longitude < 311.72):
  868. $zodiac = "Capricorn"; break;
  869. case ($longitude < 348.58):
  870. $zodiac = "Aquarius"; break;
  871. default:
  872. $zodiac = "Pisces";
  873. }
  874. $moon["age"] = round($age, 2);
  875. $moon["distance"] = round($distance, 2);
  876. $moon["latitude"] = round($latitude, 2);
  877. $moon["longitude"] = round($longitude, 2);
  878. $moon["zodiac"] = $zodiac;
  879. $moon["phase"] = $phase;
  880. $moon["icon"] = (floor($age) - 1)."";
  881. return $moon;
  882. }
  883. // }}}
  884. // {{{ calculateSunRiseSet()
  885. /**
  886. * Calculates sunrise and sunset for a location
  887. *
  888. * The sun position algorithm taken from the 'US Naval Observatory's
  889. * Almanac for Computers', implemented by Ken Bloom <kekabloom[at]ucdavis[dot]edu>
  890. * for the zmanim project, converted to C by Moshe Doron <mosdoron[at]netvision[dot]net[dot]il>
  891. * and finally taken from the PHP5 sources and converted to native PHP as a wrapper.
  892. *
  893. * The date has to be entered as a timestamp!
  894. *
  895. * @param int $date
  896. * @param int $retformat
  897. * @param float $latitude
  898. * @param float $longitude
  899. * @param float $zenith
  900. * @param float $gmt_offset
  901. * @param bool $sunrise
  902. * @return PEAR_Error|mixed
  903. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID
  904. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID
  905. * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_ERROR
  906. * @access public
  907. */
  908. function calculateSunRiseSet($date, $retformat = null, $latitude = null, $longitude = null, $zenith = null, $gmt_offset = null, $sunrise = true)
  909. {
  910. // Date must be timestamp for now
  911. if (!is_int($date)) {
  912. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID, __FILE__, __LINE__);
  913. }
  914. // Check for proper return format
  915. if ($retformat === null) {
  916. $retformat = SUNFUNCS_RET_STRING;
  917. } elseif (!in_array($retformat, array(SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, SUNFUNCS_RET_DOUBLE)) ) {
  918. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID, __FILE__, __LINE__);
  919. }
  920. // Set default values for coordinates
  921. if ($latitude === null) {
  922. $latitude = SUNFUNCS_DEFAULT_LATITUDE;
  923. } else {
  924. $latitude = (float) $latitude;
  925. }
  926. if ($longitude === null) {
  927. $longitude = SUNFUNCS_DEFAULT_LONGITUDE;
  928. } else {
  929. $longitude = (float) $longitude;
  930. }
  931. if ($zenith === null) {
  932. if($sunrise) {
  933. $zenith = SUNFUNCS_SUNRISE_ZENITH;
  934. } else {
  935. $zenith = SUNFUNCS_SUNSET_ZENITH;
  936. }
  937. } else {
  938. $zenith = (float) $zenith;
  939. }
  940. // Default value for GMT offset
  941. if ($gmt_offset === null) {
  942. $gmt_offset = date("Z", $date) / 3600;
  943. } else {
  944. $gmt_offset = (float) $gmt_offset;
  945. }
  946. // If we have PHP5, then act as wrapper for the appropriate functions
  947. if ($sunrise && function_exists("date_sunrise")) {
  948. return date_sunrise($date, $retformat, $latitude, $longitude, $zenith, $gmt_offset);
  949. }
  950. if (!$sunrise && function_exists("date_sunset")) {
  951. return date_sunset($date, $retformat, $latitude, $longitude, $zenith, $gmt_offset);
  952. }
  953. // Apparently we have PHP4, so calculate the neccessary steps in native PHP
  954. // Step 1: First calculate the day of the year
  955. $N = date("z", $date) + 1;
  956. // Step 2: Convert the longitude to hour value and calculate an approximate time
  957. $lngHour = $longitude / 15;
  958. // Use 18 for sunset instead of 6
  959. if ($sunrise) {
  960. // Sunrise
  961. $t = $N + ((6 - $lngHour) / 24);
  962. } else {
  963. // Sunset
  964. $t = $N + ((18 - $lngHour) / 24);
  965. }
  966. // Step 3: Calculate the sun's mean anomaly
  967. $M = (0.9856 * $t) - 3.289;
  968. // Step 4: Calculate the sun's true longitude
  969. $L = $M + (1.916 * sin(deg2rad($M))) + (0.020 * sin(deg2rad(2 * $M))) + 282.634;
  970. while ($L < 0) {
  971. $Lx = $L + 360;
  972. assert($Lx != $L); // askingtheguru: really needed?
  973. $L = $Lx;
  974. }
  975. while ($L >= 360) {
  976. $Lx = $L - 360;
  977. assert($Lx != $L); // askingtheguru: really needed?
  978. $L = $Lx;
  979. }
  980. // Step 5a: Calculate the sun's right ascension
  981. $RA = rad2deg(atan(0.91764 * tan(deg2rad($L))));
  982. while ($RA < 0) {
  983. $RAx = $RA + 360;
  984. assert($RAx != $RA); // askingtheguru: really needed?
  985. $RA = $RAx;
  986. }
  987. while ($RA >= 360) {
  988. $RAx = $RA - 360;
  989. assert($RAx != $RA); // askingtheguru: really needed?
  990. $RA = $RAx;
  991. }
  992. // Step 5b: Right ascension value needs to be in the same quadrant as L
  993. $Lquadrant = floor($L / 90) * 90;
  994. $RAquadrant = floor($RA / 90) * 90;
  995. $RA = $RA + ($Lquadrant - $RAquadrant);
  996. // Step 5c: Right ascension value needs to be converted into hours
  997. $RA /= 15;
  998. // Step 6: Calculate the sun's declination
  999. $sinDec = 0.39782 * sin(deg2rad($L));
  1000. $cosDec = cos(asin($sinDec));
  1001. // Step 7a: Calculate the sun's local hour angle
  1002. $cosH = (cos(deg2rad($zenith)) - ($sinDec * sin(deg2rad($latitude)))) / ($cosDec * cos(deg2rad($latitude)));
  1003. // XXX: What's the use of this block.. ?
  1004. // if (sunrise && cosH > 1 || !sunrise && cosH < -1) {
  1005. // throw doesnthappen();
  1006. // }
  1007. // Step 7b: Finish calculating H and convert into hours
  1008. if ($sunrise) {
  1009. // Sunrise
  1010. $H = 360 - rad2deg(acos($cosH));
  1011. } else {
  1012. // Sunset
  1013. $H = rad2deg(acos($cosH));
  1014. }
  1015. $H = $H / 15;
  1016. // Step 8: Calculate local mean time
  1017. $T = $H + $RA - (0.06571 * $t) - 6.622;
  1018. // Step 9: Convert to UTC
  1019. $UT = $T - $lngHour;
  1020. while ($UT < 0) {
  1021. $UTx = $UT + 24;
  1022. assert($UTx != $UT); // askingtheguru: really needed?
  1023. $UT = $UTx;
  1024. }
  1025. while ($UT >= 24) {
  1026. $UTx = $UT - 24;
  1027. assert($UTx != $UT); // askingtheguru: really needed?
  1028. $UT = $UTx;
  1029. }
  1030. $UT = $UT + $gmt_offset;
  1031. // Now bring the result into the chosen format and return
  1032. switch ($retformat) {
  1033. case SUNFUNCS_RET_TIMESTAMP:
  1034. return intval($date - $date % (24 * 3600) + 3600 * $UT);
  1035. case SUNFUNCS_RET_STRING:
  1036. $N = floor($UT);
  1037. return sprintf("%02d:%02d", $N, floor(60 * ($UT - $N)));
  1038. case SUNFUNCS_RET_DOUBLE:
  1039. return $UT;
  1040. default:
  1041. return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_ERROR, __FILE__, __LINE__);
  1042. }
  1043. }
  1044. // }}}
  1045. // {{{ getWeatherIcon()
  1046. /**
  1047. * Gets a number corresponding to a weather icon.
  1048. *
  1049. * These numbers just happen to correspond with the icons that you get with
  1050. * the weather.com SDK, but open versions of them have been created. Input
  1051. * must be in standard units. For the icons that include day/night, we use
  1052. * the present time and the provided lat/lon to determine if the sun is up.
  1053. * A complete set of icon descriptions can be found here:
  1054. * http://sranshaft.wincustomize.com/Articles.aspx?AID=60165&u=0
  1055. *
  1056. * There are a number of icon sets here:
  1057. * http://www.desktopsidebar.com/forums/index.php?showtopic=2441&st=0
  1058. * http://www.desktopsidebar.com/forums/index.php?showtopic=819
  1059. *
  1060. * @param string $condition The condition.
  1061. * @param array $clouds The clouds at various levels.
  1062. * @param float $wind Wind speed in mph.
  1063. * @param float $temperature Temperature in deg F.
  1064. * @param float $latitude Point latitude.
  1065. * @param float $longitude Point longitude.
  1066. * @param int $reportTime The time when the weather report was generated.
  1067. * @author Seth Price <seth@pricepages.org>
  1068. * @access public
  1069. */
  1070. function getWeatherIcon($condition, $clouds = array(), $wind = 5, $temperature = 70, $latitude = -360, $longitude = -360, $reportTime = "")
  1071. {
  1072. // Search for matches that don't use the time of day
  1073. $hail = (bool) stristr($condition, "hail");
  1074. $dust = (bool) stristr($condition, "dust") || (bool) stristr($condition, "sand");
  1075. $smoke = (bool) stristr($condition, "smoke") || (bool) stristr($condition, "volcanic ash");
  1076. // Slightly more complex matches that might or might not use the time of day
  1077. $near = (bool) stristr($condition, "vicinity") || (bool) stristr($condition, "recent");
  1078. $light = (bool) stristr($condition, "light");
  1079. $heavy = (bool) stristr($condition, "heavy");
  1080. $ice = (bool) stristr($condition, "ice") || (bool) stristr($condition, "pellets");
  1081. // Have to add a space to prevent matching on "snow grains"
  1082. $rain = (bool) stristr($condition, " rain");
  1083. $snow = (bool) stristr($condition, "snow");
  1084. $fog = (bool) stristr($condition, "fog") || (bool) stristr($condition, "spray") || (bool) stristr($condition, "mist");
  1085. $haze = (bool) stristr($condition, "haze");
  1086. $ts = (bool) stristr($condition, "thunderstorm");
  1087. $freezing = (bool) stristr($condition, "freezing");
  1088. $wind = (bool) stristr($condition, "squall") || $wind > 25;
  1089. $nsw = (bool) stristr($condition, "no significant weather");
  1090. $hot = $temperature > 95;
  1091. $frigid = $temperature < 5;
  1092. if ($hail) {
  1093. return 6; // Hail
  1094. }
  1095. if ($dust) {
  1096. return 19; // Dust
  1097. }
  1098. if ($smoke) {
  1099. return 22; // Smoke
  1100. }
  1101. // Get some of the dangerous conditions fist
  1102. if ($rain && $snow && ($ice || $freezing)) {
  1103. return 7; // Icy/Clouds Rain-Snow
  1104. }
  1105. if (($ts || $rain) && ($ice || $freezing)) {
  1106. return 10; // Icy/Rain
  1107. }
  1108. if (($fog || $haze) && ($ice || $freezing)) {
  1109. return 8; // Icy/Haze Rain
  1110. }
  1111. if ($rain && $snow) {
  1112. return 5; // Cloudy/Snow-Rain Mix
  1113. }
  1114. if ($fog && $rain) {
  1115. return 9; // Haze/Rain
  1116. }
  1117. if ($wind && $rain) {
  1118. return 1; // Wind/Rain
  1119. }
  1120. if ($wind && $snow) {
  1121. return 43; // Windy/Snow
  1122. }
  1123. if ($snow && $light) {
  1124. return 13; // Flurries
  1125. }
  1126. if ($light && $rain) {
  1127. return 11; // Light Rain
  1128. }
  1129. // Get the maximum coverage of the clouds at any height. For most
  1130. // people, overcast at 1000ft is the same as overcast at 10000ft.
  1131. //
  1132. // 0 == clear, 1 == hazey, 2 == partly cloudy, 3 == mostly cloudy, 4 == overcast
  1133. $coverage = 0;
  1134. foreach ($clouds as $layer) {
  1135. if ($coverage < 1 && stristr($layer["amount"], "few")) {
  1136. $coverage = 1;
  1137. } elseif ($coverage < 2 && stristr($layer["amount"], "scattered")) {
  1138. $coverage = 2;
  1139. } elseif ($coverage < 3 && (stristr($layer["amount"], "broken") || stristr($layer["amount"], "cumulus"))) {
  1140. $coverage = 3;
  1141. } elseif ($coverage < 4 && stristr($layer["amount"], "overcast")) {
  1142. $coverage = 4;
  1143. }
  1144. }
  1145. // Check if it is day or not. 0 is night, 2 is day, and 1 is unknown
  1146. // or twilight (~(+|-)1 hour of sunrise/sunset). Note that twilight isn't
  1147. // always accurate because of issues wrapping around the 24hr clock. Oh well...
  1148. if ($latitude < 90 && $latitude > -90 && $longitude < 180 && $longitude > -180) {
  1149. // Use provided time by report if available, otherwise use current GMT time
  1150. if ($reportTime <> "" && is_numeric($reportTime)) {
  1151. $timeOfDay = $reportTime;
  1152. } else {
  1153. $timeOfDay = gmmktime();
  1154. }
  1155. // Calculate sunrise/sunset and current time in GMT
  1156. $sunrise = $this->calculateSunRiseSet($timeOfDay, SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude, SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH, 0, true);
  1157. $sunset = $this->calculateSunRiseSet($timeOfDay, SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude, SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH, 0, false);
  1158. // Now that we have the sunrise/sunset times and the current time,
  1159. // we need to figure out if it is day, night, or twilight. Wrapping
  1160. // these times around the 24hr clock is a pain.
  1161. if ($sunrise < $sunset) {
  1162. if ($timeOfDay > ($sunrise + 3600) && $timeOfDay < ($sunset - 3600)) {
  1163. $isDay = 2;
  1164. } elseif ($timeOfDay > ($sunrise - 3600) && $timeOfDay < ($sunset + 3600)) {
  1165. $isDay = 1;
  1166. } else {
  1167. $isDay = 0;
  1168. }
  1169. } else {
  1170. if ($timeOfDay < ($sunrise - 3600) && $timeOfDay > ($sunset + 3600)) {
  1171. $isDay = 0;
  1172. } elseif ($timeOfDay < ($sunrise + 3600) && $timeOfDay > ($sunset - 3600)) {
  1173. $isDay = 1;
  1174. } else {
  1175. $isDay = 2;
  1176. }
  1177. }
  1178. } else {
  1179. // Default to twilight because it tends to have neutral icons.
  1180. $isDay = 1;
  1181. }
  1182. // General precipitation
  1183. if ($ts && $near) {
  1184. switch ($isDay) {
  1185. case 0:
  1186. case 1:
  1187. return 38; // Lightning
  1188. case 2:
  1189. return 37; // Lightning/Day
  1190. }
  1191. }
  1192. if ($ts) {
  1193. switch ($isDay) {
  1194. case 0:
  1195. return 47; // Thunderstorm/Night
  1196. case 1:
  1197. case 2:
  1198. return 0; // Rain/Lightning
  1199. }
  1200. }
  1201. if ($snow) {
  1202. switch ($isDay) {
  1203. case 0:
  1204. return 46; // Snow/Night
  1205. case 1:
  1206. case 2:
  1207. return 41; // Snow
  1208. }
  1209. }
  1210. if ($rain) {
  1211. switch ($isDay) {
  1212. case 0:
  1213. return 45; // Rain/Night
  1214. case 1:
  1215. return 40; // Rain
  1216. case 2:
  1217. return 39; // Rain/Day
  1218. }
  1219. }
  1220. // Cloud conditions near the ground
  1221. if ($fog) {
  1222. return 20; // Fog
  1223. }
  1224. if ($haze) {
  1225. return 21; // Haze
  1226. }
  1227. // Cloud conditions
  1228. if ($coverage == 4) {
  1229. return 26; // Mostly Cloudy
  1230. }
  1231. if ($coverage == 3) {
  1232. switch ($isDay) {
  1233. case 0:
  1234. return 27; // Mostly Cloudy/Night
  1235. case 1:
  1236. return 26; // Mostly Cloudy
  1237. case 2:
  1238. return 28; // Mostly Cloudy/Day
  1239. }
  1240. }
  1241. if ($coverage == 2) {
  1242. switch ($isDay) {
  1243. case 0:
  1244. return 29; // Partly Cloudy/Night
  1245. case 1:
  1246. return 26; // Mostly Cloudy
  1247. case 2:
  1248. return 30; // Partly Cloudy/Day
  1249. }
  1250. }
  1251. if ($coverage == 1) {
  1252. switch ($isDay) {
  1253. case 0:
  1254. case 1:
  1255. return 33; // Hazy/Night
  1256. case 2:
  1257. return 34; // Hazy/Day
  1258. }
  1259. }
  1260. // Catch-alls
  1261. if ($wind) {
  1262. return 23; // Wind
  1263. }
  1264. if ($hot) {
  1265. return 36; // Hot!
  1266. }
  1267. if ($frigid) {
  1268. return 25; // Frigid
  1269. }
  1270. if ($nsw) {
  1271. switch ($isDay) {
  1272. case 0:
  1273. case 1:
  1274. // Use night for twilight because the moon is generally
  1275. // out then, so it will match with most icon sets.
  1276. return 31; // Clear Night
  1277. case 2:
  1278. return 32; // Clear Day
  1279. }
  1280. }
  1281. return "na";
  1282. }
  1283. // }}}
  1284. }
  1285. // }}}
  1286. ?>