/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
- <?php
- /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
- /**
- * PEAR::Services_Weather_Common
- *
- * PHP versions 4 and 5
- *
- * <LICENSE>
- * Copyright (c) 2005-2011, Alexander Wirtz
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * o Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * o Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * o Neither the name of the software nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- * </LICENSE>
- *
- * @category Web Services
- * @package Services_Weather
- * @author Alexander Wirtz <alex@pc4p.net>
- * @copyright 2005-2011 Alexander Wirtz
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version CVS: $Id: Common.php 314012 2011-08-01 11:04:57Z eru $
- * @link http://pear.php.net/package/Services_Weather
- * @filesource
- */
- require_once "Services/Weather.php";
- // {{{ constants
- // {{{ natural constants and measures
- define("SERVICES_WEATHER_RADIUS_EARTH", 6378.15);
- // }}}
- // {{{ default values for the sun-functions
- define("SERVICES_WEATHER_SUNFUNCS_DEFAULT_LATITUDE", 31.7667);
- define("SERVICES_WEATHER_SUNFUNCS_DEFAULT_LONGITUDE", 35.2333);
- define("SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH", 90.83);
- define("SERVICES_WEATHER_SUNFUNCS_SUNSET_ZENITH", 90.83);
- // }}}
- // }}}
- // {{{ class Services_Weather_Common
- /**
- * Parent class for weather-services. Defines common functions for unit
- * conversions, checks for cache enabling and does other miscellaneous
- * things.
- *
- * @category Web Services
- * @package Services_Weather
- * @author Alexander Wirtz <alex@pc4p.net>
- * @copyright 2005-2011 Alexander Wirtz
- * @license http://www.opensource.org/licenses/bsd-license.php BSD License
- * @version Release: 1.4.6
- * @link http://pear.php.net/package/Services_Weather
- */
- class Services_Weather_Common {
- // {{{ properties
- /**
- * Format of the units provided (standard/metric/custom)
- *
- * @var string $_unitsFormat
- * @access private
- */
- var $_unitsFormat = "s";
- /**
- * Custom format of the units
- *
- * @var array $_customUnitsFormat
- * @access private
- */
- var $_customUnitsFormat = array(
- "temp" => "f",
- "vis" => "sm",
- "height" => "ft",
- "wind" => "mph",
- "pres" => "in",
- "rain" => "in"
- );
- /**
- * Options for HTTP requests
- *
- * @var array $_httpOptions
- * @access private
- */
- var $_httpOptions = array();
- /**
- * Format of the used dates
- *
- * @var string $_dateFormat
- * @access private
- */
- var $_dateFormat = "m/d/y";
- /**
- * Format of the used times
- *
- * @var string $_timeFormat
- * @access private
- */
- var $_timeFormat = "G:i A";
- /**
- * Object containing the location-data
- *
- * @var object stdClass $_location
- * @access private
- */
- var $_location;
- /**
- * Object containing the weather-data
- *
- * @var object stdClass $_weather
- * @access private
- */
- var $_weather;
- /**
- * Object containing the forecast-data
- *
- * @var object stdClass $_forecast
- * @access private
- */
- var $_forecast;
- /**
- * Cache, containing the data-objects
- *
- * @var object Cache $_cache
- * @access private
- */
- var $_cache;
- /**
- * Provides check for Cache
- *
- * @var bool $_cacheEnabled
- * @access private
- */
- var $_cacheEnabled = false;
- // }}}
- // {{{ constructor
- /**
- * Constructor
- *
- * @param array $options
- * @param mixed $error
- * @throws PEAR_Error
- * @access private
- */
- function Services_Weather_Common($options, &$error)
- {
- // Set some constants for the case when PHP4 is used, as the
- // date_sunset/sunrise functions are not implemented there
- if (!defined("SUNFUNCS_RET_TIMESTAMP")) {
- define("SUNFUNCS_RET_TIMESTAMP", 0);
- define("SUNFUNCS_RET_STRING", 1);
- define("SUNFUNCS_RET_DOUBLE", 2);
- }
- // Set options accordingly
- if (isset($options["cacheType"])) {
- if (isset($options["cacheOptions"])) {
- $status = $this->setCache($options["cacheType"], $options["cacheOptions"]);
- } else {
- $status = $this->setCache($options["cacheType"]);
- }
- if (Services_Weather::isError($status)) {
- $error = $status;
- return;
- }
- }
- if (isset($options["unitsFormat"])) {
- if (isset($options["customUnitsFormat"])) {
- $this->setUnitsFormat($options["unitsFormat"], $options["customUnitsFormat"]);
- } else {
- $this->setUnitsFormat($options["unitsFormat"]);
- }
- }
- if (isset($options["httpTimeout"])) {
- $this->setHttpTimeout($options["httpTimeout"]);
- } else {
- $this->setHttpTimeout(60);
- }
- if (isset($options["httpProxy"])) {
- $status = $this->setHttpProxy($options["httpProxy"]);
- if (Services_Weather::isError($status)) {
- $error = $status;
- return;
- }
- }
- if (isset($options["dateFormat"])) {
- $this->setDateTimeFormat($options["dateFormat"], "");
- }
- if (isset($options["timeFormat"])) {
- $this->setDateTimeFormat("", $options["timeFormat"]);
- }
- }
- // }}}
- // {{{ setCache()
- /**
- * Enables caching the data, usage strongly recommended
- *
- * Requires Cache to be installed
- *
- * @param string $cacheType
- * @param array $cacheOptions
- * @return PEAR_Error|bool
- * @throws PEAR_Error::SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED
- * @access public
- */
- function setCache($cacheType = "file", $cacheOptions = array())
- {
- if ($cacheType == "lite") {
- if ((@include_once "Cache/Lite.php") == false) {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
- } else {
- $cacheOptions["automaticSerialization"] = true;
- $cacheOptions["pearErrorMode"] = CACHE_LITE_ERROR_RETURN;
- $cacheOptions["lifeTime"] = null;
- @$cache = new Cache_Lite($cacheOptions);
- }
- } else {
- // The error handling in Cache is a bit crummy (read: not existent)
- // so we have to do that on our own...
- if ((@include_once "Cache.php") === false) {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
- } else {
- @$cache = new Cache($cacheType, $cacheOptions);
- }
- }
- if (is_object($cache) && (strtolower(get_class($cache)) == "cache_lite" || strtolower(get_class($cache)) == "cache" || is_subclass_of($cache, "cache"))) {
- $this->_cache = $cache;
- $this->_cacheEnabled = true;
- } else {
- $this->_cache = null;
- $this->_cacheEnabled = false;
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED, __FILE__, __LINE__);
- }
- return true;
- }
- // }}}
- // {{{ _getCache()
- /**
- * Wrapper to retrieve cached data
- *
- * Requires Cache to be installed
- *
- * @param string $id
- * @param string $type
- * @return array|bool
- * @access private
- */
- function _getCache($id, $type)
- {
- if ($this->_cacheEnabled) {
- if (strtolower(get_class($this->_cache)) == "cache_lite") {
- $this->_cache->setLifeTime(constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)));
- $cache = $this->_cache->get($id, $type);
- } else {
- $cache = $this->_cache->get($id, $type);
- }
-
- return $cache;
- } else {
- return false;
- }
- }
- // }}}
- // {{{ _getUserCache()
- /**
- * Wrapper to retrieve cached user-data
- *
- * Requires Cache to be installed
- *
- * @param string $id
- * @param string $type
- * @return array|bool
- * @access private
- */
- function _getUserCache($id, $type)
- {
- if ($this->_cacheEnabled) {
- if (strtolower(get_class($this->_cache)) == "cache_lite") {
- $this->_cache->setLifeTime(constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)));
- $cache = $this->_cache->get($id, $type."_user");
- } else {
- $cache = $this->_cache->getUserdata($id, $type);
- }
-
- return $cache;
- } else {
- return false;
- }
- }
- // }}}
- // {{{ _saveCache()
- /**
- * Wrapper to save data to cache
- *
- * Requires Cache to be installed
- *
- * @param string $id
- * @param mixed $data
- * @param mixed $userData
- * @param string $type
- * @return array|bool
- * @access private
- */
- function _saveCache($id, $data, $userData, $type)
- {
- if ($this->_cacheEnabled) {
- if (strtolower(get_class($this->_cache)) == "cache_lite") {
- $this->_cache->setLifeTime(null);
- return ($this->_cache->save($data, $id, $type) && $this->_cache->save($userData, $id, $type."_user"));
- } else {
- return $this->_cache->extSave($id, $data, $userData, constant("SERVICES_WEATHER_EXPIRES_".strtoupper($type)), $type);
- }
- } else {
- return false;
- }
- }
- // }}}
- // {{{ setUnitsFormat()
- /**
- * Changes the representation of the units (standard/metric)
- *
- * @param string $unitsFormat
- * @param array $customUnitsFormat
- * @access public
- */
- function setUnitsFormat($unitsFormat, $customUnitsFormat = array())
- {
- static $acceptedFormats;
- if (!isset($acceptedFormats)) {
- $acceptedFormats = array(
- "temp" => array("c", "f"),
- "vis" => array("m", "km", "ft", "sm"),
- "height" => array("m", "ft"),
- "wind" => array("mph", "kmh", "kt", "mps", "fps", "bft"),
- "pres" => array("in", "hpa", "mb", "mm", "atm"),
- "rain" => array("in", "mm")
- );
- }
- if (strlen($unitsFormat) && in_array(strtolower($unitsFormat{0}), array("c", "m", "s"))) {
- $this->_unitsFormat = strtolower($unitsFormat{0});
- if ($this->_unitsFormat == "c" && is_array($customUnitsFormat)) {
- foreach ($customUnitsFormat as $key => $value) {
- if (array_key_exists($key, $acceptedFormats) && in_array($value, $acceptedFormats[$key])) {
- $this->_customUnitsFormat[$key] = $value;
- }
- }
- } elseif ($this->_unitsFormat == "c") {
- $this->_unitsFormat = "s";
- }
- }
- }
- // }}}
- // {{{ setHttpOption()
- /**
- * Sets an option for usage in HTTP_Request objects
- *
- * @param string $varName
- * @param mixed $varValue
- * @access public
- */
- function setHttpOption($varName, $varValue)
- {
- if (is_string($varName) && $varName != "" && !empty($varValue)) {
- $this->_httpOptions[$varName] = $varValue;
- }
- }
- // }}}
- // {{{ setHttpTimeout()
- /**
- * Sets the timeout in seconds for HTTP requests
- *
- * @param int $httpTimeout
- * @access public
- */
- function setHttpTimeout($httpTimeout)
- {
- if (is_int($httpTimeout)) {
- $this->_httpOptions["timeout"] = $httpTimeout;
- }
- }
- // }}}
- // {{{ setHttpProxy()
- /**
- * Sets the proxy for HTTP requests
- *
- * @param string $httpProxy
- * @access public
- */
- function setHttpProxy($httpProxy)
- {
- if (($proxy = parse_url($httpProxy)) !== false && $proxy["scheme"] == "http") {
- if (isset($proxy["user"]) && $proxy["user"] != "") {
- $this->_httpOptions["proxy_user"] = $proxy["user"];
- }
- if (isset($proxy["pass"]) && $proxy["pass"] != "") {
- $this->_httpOptions["proxy_pass"] = $proxy["pass"];
- }
- if (isset($proxy["host"]) && $proxy["host"] != "") {
- $this->_httpOptions["proxy_host"] = $proxy["host"];
- }
- if (isset($proxy["port"]) && $proxy["port"] != "") {
- $this->_httpOptions["proxy_port"] = $proxy["port"];
- }
- return true;
- } else {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID, __FILE__, __LINE__);
- }
- }
- // }}}
- // {{{ getUnitsFormat()
- /**
- * Returns the selected units format
- *
- * @param string $unitsFormat
- * @return array
- * @access public
- */
- function getUnitsFormat($unitsFormat = "")
- {
- // This is cheap'o stuff
- if (strlen($unitsFormat) && in_array(strtolower($unitsFormat{0}), array("c", "m", "s"))) {
- $unitsFormat = strtolower($unitsFormat{0});
- } else {
- $unitsFormat = $this->_unitsFormat;
- }
- $c = $this->_customUnitsFormat;
- $m = array(
- "temp" => "c",
- "vis" => "km",
- "height" => "m",
- "wind" => "kmh",
- "pres" => "mb",
- "rain" => "mm"
- );
- $s = array(
- "temp" => "f",
- "vis" => "sm",
- "height" => "ft",
- "wind" => "mph",
- "pres" => "in",
- "rain" => "in"
- );
- return ${$unitsFormat};
- }
- // }}}
- // {{{ setDateTimeFormat()
- /**
- * Changes the representation of time and dates (see http://www.php.net/date)
- *
- * @param string $dateFormat
- * @param string $timeFormat
- * @access public
- */
- function setDateTimeFormat($dateFormat = "", $timeFormat = "")
- {
- if (strlen($dateFormat)) {
- $this->_dateFormat = $dateFormat;
- }
- if (strlen($timeFormat)) {
- $this->_timeFormat = $timeFormat;
- }
- }
- // }}}
- // {{{ convertTemperature()
- /**
- * Convert temperature between f and c
- *
- * @param float $temperature
- * @param string $from
- * @param string $to
- * @return float
- * @access public
- */
- function convertTemperature($temperature, $from, $to)
- {
- if ($temperature == "N/A") {
- return $temperature;
- }
- $from = strtolower($from{0});
- $to = strtolower($to{0});
- $result = array(
- "f" => array(
- "f" => $temperature, "c" => ($temperature - 32) / 1.8
- ),
- "c" => array(
- "f" => 1.8 * $temperature + 32, "c" => $temperature
- )
- );
- return $result[$from][$to];
- }
- // }}}
- // {{{ convertSpeed()
- /**
- * Convert speed between mph, kmh, kt, mps, fps and bft
- *
- * Function will return "false" when trying to convert from
- * Beaufort, as it is a scale and not a true measurement
- *
- * @param float $speed
- * @param string $from
- * @param string $to
- * @return float|int|bool
- * @access public
- * @link http://www.spc.noaa.gov/faq/tornado/beaufort.html
- */
- function convertSpeed($speed, $from, $to)
- {
- $from = strtolower($from);
- $to = strtolower($to);
- static $factor;
- static $beaufort;
- if (!isset($factor)) {
- $factor = array(
- "mph" => array(
- "mph" => 1, "kmh" => 1.609344, "kt" => 0.8689762, "mps" => 0.44704, "fps" => 1.4666667
- ),
- "kmh" => array(
- "mph" => 0.6213712, "kmh" => 1, "kt" => 0.5399568, "mps" => 0.2777778, "fps" => 0.9113444
- ),
- "kt" => array(
- "mph" => 1.1507794, "kmh" => 1.852, "kt" => 1, "mps" => 0.5144444, "fps" => 1.6878099
- ),
- "mps" => array(
- "mph" => 2.2369363, "kmh" => 3.6, "kt" => 1.9438445, "mps" => 1, "fps" => 3.2808399
- ),
- "fps" => array(
- "mph" => 0.6818182, "kmh" => 1.09728, "kt" => 0.5924838, "mps" => 0.3048, "fps" => 1
- )
- );
- // Beaufort scale, measurements are in knots
- $beaufort = array(
- 1, 3, 6, 10,
- 16, 21, 27, 33,
- 40, 47, 55, 63
- );
- }
- if ($from == "bft") {
- return false;
- } elseif ($to == "bft") {
- $speed = round($speed * $factor[$from]["kt"], 0);
- for ($i = 0; $i < sizeof($beaufort); $i++) {
- if ($speed <= $beaufort[$i]) {
- return $i;
- }
- }
- return sizeof($beaufort);
- } else {
- return ($speed * $factor[$from][$to]);
- }
- }
- // }}}
- // {{{ convertPressure()
- /**
- * Convert pressure between in, hpa, mb, mm and atm
- *
- * @param float $pressure
- * @param string $from
- * @param string $to
- * @return float
- * @access public
- */
- function convertPressure($pressure, $from, $to)
- {
- $from = strtolower($from);
- $to = strtolower($to);
- static $factor;
- if (!isset($factor)) {
- $factor = array(
- "in" => array(
- "in" => 1, "hpa" => 33.863887, "mb" => 33.863887, "mm" => 25.4, "atm" => 0.0334213
- ),
- "hpa" => array(
- "in" => 0.02953, "hpa" => 1, "mb" => 1, "mm" => 0.7500616, "atm" => 0.0009869
- ),
- "mb" => array(
- "in" => 0.02953, "hpa" => 1, "mb" => 1, "mm" => 0.7500616, "atm" => 0.0009869
- ),
- "mm" => array(
- "in" => 0.0393701, "hpa" => 1.3332239, "mb" => 1.3332239, "mm" => 1, "atm" => 0.0013158
- ),
- "atm" => array(
- "in" => 29,921258, "hpa" => 1013.2501, "mb" => 1013.2501, "mm" => 759.999952, "atm" => 1
- )
- );
- }
- return ($pressure * $factor[$from][$to]);
- }
- // }}}
- // {{{ convertDistance()
- /**
- * Convert distance between km, ft and sm
- *
- * @param float $distance
- * @param string $from
- * @param string $to
- * @return float
- * @access public
- */
- function convertDistance($distance, $from, $to)
- {
- $to = strtolower($to);
- $from = strtolower($from);
- static $factor;
- if (!isset($factor)) {
- $factor = array(
- "m" => array(
- "m" => 1, "km" => 1000, "ft" => 3.280839895, "sm" => 0.0006213699
- ),
- "km" => array(
- "m" => 0.001, "km" => 1, "ft" => 3280.839895, "sm" => 0.6213699
- ),
- "ft" => array(
- "m" => 0.3048, "km" => 0.0003048, "ft" => 1, "sm" => 0.0001894
- ),
- "sm" => array(
- "m" => 0.0016093472, "km" => 1.6093472, "ft" => 5280.0106, "sm" => 1
- )
- );
- }
- return ($distance * $factor[$from][$to]);
- }
- // }}}
- // {{{ calculateWindChill()
- /**
- * Calculate windchill from temperature and windspeed (enhanced formula)
- *
- * Temperature has to be entered in deg F, speed in mph!
- *
- * @param float $temperature
- * @param float $speed
- * @return float
- * @access public
- * @link http://www.nws.noaa.gov/om/windchill/
- */
- function calculateWindChill($temperature, $speed)
- {
- return (35.74 + 0.6215 * $temperature - 35.75 * pow($speed, 0.16) + 0.4275 * $temperature * pow($speed, 0.16));
- }
- // }}}
- // {{{ calculateHumidity()
- /**
- * Calculate humidity from temperature and dewpoint
- * This is only an approximation, there is no exact formula, this
- * one here is called Magnus-Formula
- *
- * Temperature and dewpoint have to be entered in deg C!
- *
- * @param float $temperature
- * @param float $dewPoint
- * @return float
- * @access public
- * @link http://www.faqs.org/faqs/meteorology/temp-dewpoint/
- */
- function calculateHumidity($temperature, $dewPoint)
- {
- // First calculate saturation steam pressure for both temperatures
- if ($temperature >= 0) {
- $a = 7.5;
- $b = 237.3;
- } else {
- $a = 7.6;
- $b = 240.7;
- }
- $tempSSP = 6.1078 * pow(10, ($a * $temperature) / ($b + $temperature));
- if ($dewPoint >= 0) {
- $a = 7.5;
- $b = 237.3;
- } else {
- $a = 7.6;
- $b = 240.7;
- }
- $dewSSP = 6.1078 * pow(10, ($a * $dewPoint) / ($b + $dewPoint));
- return (100 * $dewSSP / $tempSSP);
- }
- // }}}
- // {{{ calculateDewPoint()
- /**
- * Calculate dewpoint from temperature and humidity
- * This is only an approximation, there is no exact formula, this
- * one here is called Magnus-Formula
- *
- * Temperature has to be entered in deg C!
- *
- * @param float $temperature
- * @param float $humidity
- * @return float
- * @access public
- * @link http://www.faqs.org/faqs/meteorology/temp-dewpoint/
- */
- function calculateDewPoint($temperature, $humidity)
- {
- if ($temperature >= 0) {
- $a = 7.5;
- $b = 237.3;
- } else {
- $a = 7.6;
- $b = 240.7;
- }
- // First calculate saturation steam pressure for temperature
- $SSP = 6.1078 * pow(10, ($a * $temperature) / ($b + $temperature));
- // Steam pressure
- $SP = $humidity / 100 * $SSP;
- $v = log($SP / 6.1078, 10);
- return ($b * $v / ($a - $v));
- }
- // }}}
- // {{{ polar2cartesian()
- /**
- * Convert polar coordinates to cartesian coordinates
- *
- * @param float $latitude
- * @param float $longitude
- * @return array
- * @access public
- */
- function polar2cartesian($latitude, $longitude)
- {
- $theta = deg2rad($latitude);
- $phi = deg2rad($longitude);
- $x = SERVICES_WEATHER_RADIUS_EARTH * cos($phi) * cos($theta);
- $y = SERVICES_WEATHER_RADIUS_EARTH * sin($phi) * cos($theta);
- $z = SERVICES_WEATHER_RADIUS_EARTH * sin($theta);
- return array($x, $y, $z);
- }
- // }}}
- // {{{ calculateMoonPhase()
- /**
- * Calculates the moon age and phase
- *
- * The algorithms for this functions were taken from the German Wikipedia
- * entry on Julian Daycount for getting the accurate JD to the second and
- * the overall moon calculation were done according to
- * Stephen R. Schmitt's website, which is cited multiple times on the web
- * for this kind of calculation.
- *
- * The date has to be entered as a timestamp!
- *
- * @param int $date
- * @return PEAR_Error|array
- * @throws PEAR_Error::SERVICES_WEATHER_ERROR_MOONFUNCS_DATE_INVALID
- * @access public
- * @link http://de.wikipedia.org/wiki/Julianisches_Datum
- * @link http://mysite.verizon.net/res148h4j/javascript/script_moon_phase.html
- */
- function calculateMoonPhase($date)
- {
- // Date must be timestamp for now
- if (!is_int($date)) {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_MOONFUNCS_DATE_INVALID, __FILE__, __LINE__);
- }
- $moon = array();
- $year = date("Y", $date);
- $month = date("n", $date);
- $day = date("j", $date);
- $hour = date("G", $date);
- $min = date("i", $date);
- $sec = date("s", $date);
- $age = 0.0; // Moon's age in days from New Moon
- $distance = 0.0; // Moon's distance in Earth radii
- $latitude = 0.0; // Moon's ecliptic latitude in degrees
- $longitude = 0.0; // Moon's ecliptic longitude in degrees
- $phase = ""; // Moon's phase
- $zodiac = ""; // Moon's zodiac
- $icon = ""; // The icon to represent the moon phase
- $YY = 0;
- $MM = 0;
- $DD = 0;
- $HH = 0;
- $A = 0;
- $B = 0;
- $JD = 0;
- $IP = 0.0;
- $DP = 0.0;
- $NP = 0.0;
- $RP = 0.0;
- // Calculate Julian Daycount to the second
- if ($month > 2) {
- $YY = $year;
- $MM = $month;
- } else {
- $YY = $year - 1;
- $MM = $month + 12;
- }
- $DD = $day;
- $HH = $hour/24 + $min/1440 + $sec/86400;
- // Check for Gregorian date and adjust JD appropriately
- if (($year*10000 + $month*100 + $day) >= 15821015) {
- $A = floor($YY/100);
- $B = 2 - $A + floor($A/4);
- }
- $JD = floor(365.25*($YY+4716)) + floor(30.6001*($MM+1)) + $DD + $HH + $B - 1524.5;
- // Calculate moon's age in days
- $IP = ($JD - 2451550.1) / 29.530588853;
- if (($IP = $IP - floor($IP)) < 0) $IP++;
- $age = $IP * 29.530588853;
- switch ($age) {
- case ($age < 1.84566):
- $phase = "New"; break;
- case ($age < 5.53699):
- $phase = "Waxing Crescent"; break;
- case ($age < 9.22831):
- $phase = "First Quarter"; break;
- case ($age < 12.91963):
- $phase = "Waxing Gibbous"; break;
- case ($age < 16.61096):
- $phase = "Full"; break;
- case ($age < 20.30228):
- $phase = "Waning Gibbous"; break;
- case ($age < 23.99361):
- $phase = "Last Quarter"; break;
- case ($age < 27.68493):
- $phase = "Waning Crescent"; break;
- default:
- $phase = "New";
- }
- // Convert phase to radians
- $IP = $IP * 2 * pi();
- // Calculate moon's distance
- $DP = ($JD - 2451562.2) / 27.55454988;
- if (($DP = $DP - floor($DP)) < 0) $DP++;
- $DP = $DP * 2 * pi();
- $distance = 60.4 - 3.3 * cos($DP) - 0.6 * cos(2 * $IP - $DP) - 0.5 * cos(2 * $IP);
- // Calculate moon's ecliptic latitude
- $NP = ($JD - 2451565.2) / 27.212220817;
- if (($NP = $NP - floor($NP)) < 0) $NP++;
- $NP = $NP * 2 * pi();
- $latitude = 5.1 * sin($NP);
- // Calculate moon's ecliptic longitude
- $RP = ($JD - 2451555.8) / 27.321582241;
- if (($RP = $RP - floor($RP)) < 0) $RP++;
- $longitude = 360 * $RP + 6.3 * sin($DP) + 1.3 * sin(2 * $IP - $DP) + 0.7 * sin(2 * $IP);
- if ($longitude >= 360) $longitude -= 360;
- switch ($longitude) {
- case ($longitude < 33.18):
- $zodiac = "Pisces"; break;
- case ($longitude < 51.16):
- $zodiac = "Aries"; break;
- case ($longitude < 93.44):
- $zodiac = "Taurus"; break;
- case ($longitude < 119.48):
- $zodiac = "Gemini"; break;
- case ($longitude < 135.30):
- $zodiac = "Cancer"; break;
- case ($longitude < 173.34):
- $zodiac = "Leo"; break;
- case ($longitude < 224.17):
- $zodiac = "Virgo"; break;
- case ($longitude < 242.57):
- $zodiac = "Libra"; break;
- case ($longitude < 271.26):
- $zodiac = "Scorpio"; break;
- case ($longitude < 302.49):
- $zodiac = "Sagittarius"; break;
- case ($longitude < 311.72):
- $zodiac = "Capricorn"; break;
- case ($longitude < 348.58):
- $zodiac = "Aquarius"; break;
- default:
- $zodiac = "Pisces";
- }
- $moon["age"] = round($age, 2);
- $moon["distance"] = round($distance, 2);
- $moon["latitude"] = round($latitude, 2);
- $moon["longitude"] = round($longitude, 2);
- $moon["zodiac"] = $zodiac;
- $moon["phase"] = $phase;
- $moon["icon"] = (floor($age) - 1)."";
- return $moon;
- }
- // }}}
- // {{{ calculateSunRiseSet()
- /**
- * Calculates sunrise and sunset for a location
- *
- * The sun position algorithm taken from the 'US Naval Observatory's
- * Almanac for Computers', implemented by Ken Bloom <kekabloom[at]ucdavis[dot]edu>
- * for the zmanim project, converted to C by Moshe Doron <mosdoron[at]netvision[dot]net[dot]il>
- * and finally taken from the PHP5 sources and converted to native PHP as a wrapper.
- *
- * The date has to be entered as a timestamp!
- *
- * @param int $date
- * @param int $retformat
- * @param float $latitude
- * @param float $longitude
- * @param float $zenith
- * @param float $gmt_offset
- * @param bool $sunrise
- * @return PEAR_Error|mixed
- * @throws PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID
- * @throws PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID
- * @throws PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_ERROR
- * @access public
- */
- function calculateSunRiseSet($date, $retformat = null, $latitude = null, $longitude = null, $zenith = null, $gmt_offset = null, $sunrise = true)
- {
- // Date must be timestamp for now
- if (!is_int($date)) {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID, __FILE__, __LINE__);
- }
- // Check for proper return format
- if ($retformat === null) {
- $retformat = SUNFUNCS_RET_STRING;
- } elseif (!in_array($retformat, array(SUNFUNCS_RET_TIMESTAMP, SUNFUNCS_RET_STRING, SUNFUNCS_RET_DOUBLE)) ) {
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID, __FILE__, __LINE__);
- }
- // Set default values for coordinates
- if ($latitude === null) {
- $latitude = SUNFUNCS_DEFAULT_LATITUDE;
- } else {
- $latitude = (float) $latitude;
- }
- if ($longitude === null) {
- $longitude = SUNFUNCS_DEFAULT_LONGITUDE;
- } else {
- $longitude = (float) $longitude;
- }
- if ($zenith === null) {
- if($sunrise) {
- $zenith = SUNFUNCS_SUNRISE_ZENITH;
- } else {
- $zenith = SUNFUNCS_SUNSET_ZENITH;
- }
- } else {
- $zenith = (float) $zenith;
- }
- // Default value for GMT offset
- if ($gmt_offset === null) {
- $gmt_offset = date("Z", $date) / 3600;
- } else {
- $gmt_offset = (float) $gmt_offset;
- }
- // If we have PHP5, then act as wrapper for the appropriate functions
- if ($sunrise && function_exists("date_sunrise")) {
- return date_sunrise($date, $retformat, $latitude, $longitude, $zenith, $gmt_offset);
- }
- if (!$sunrise && function_exists("date_sunset")) {
- return date_sunset($date, $retformat, $latitude, $longitude, $zenith, $gmt_offset);
- }
- // Apparently we have PHP4, so calculate the neccessary steps in native PHP
- // Step 1: First calculate the day of the year
- $N = date("z", $date) + 1;
- // Step 2: Convert the longitude to hour value and calculate an approximate time
- $lngHour = $longitude / 15;
- // Use 18 for sunset instead of 6
- if ($sunrise) {
- // Sunrise
- $t = $N + ((6 - $lngHour) / 24);
- } else {
- // Sunset
- $t = $N + ((18 - $lngHour) / 24);
- }
- // Step 3: Calculate the sun's mean anomaly
- $M = (0.9856 * $t) - 3.289;
- // Step 4: Calculate the sun's true longitude
- $L = $M + (1.916 * sin(deg2rad($M))) + (0.020 * sin(deg2rad(2 * $M))) + 282.634;
- while ($L < 0) {
- $Lx = $L + 360;
- assert($Lx != $L); // askingtheguru: really needed?
- $L = $Lx;
- }
- while ($L >= 360) {
- $Lx = $L - 360;
- assert($Lx != $L); // askingtheguru: really needed?
- $L = $Lx;
- }
- // Step 5a: Calculate the sun's right ascension
- $RA = rad2deg(atan(0.91764 * tan(deg2rad($L))));
- while ($RA < 0) {
- $RAx = $RA + 360;
- assert($RAx != $RA); // askingtheguru: really needed?
- $RA = $RAx;
- }
- while ($RA >= 360) {
- $RAx = $RA - 360;
- assert($RAx != $RA); // askingtheguru: really needed?
- $RA = $RAx;
- }
- // Step 5b: Right ascension value needs to be in the same quadrant as L
- $Lquadrant = floor($L / 90) * 90;
- $RAquadrant = floor($RA / 90) * 90;
- $RA = $RA + ($Lquadrant - $RAquadrant);
- // Step 5c: Right ascension value needs to be converted into hours
- $RA /= 15;
- // Step 6: Calculate the sun's declination
- $sinDec = 0.39782 * sin(deg2rad($L));
- $cosDec = cos(asin($sinDec));
- // Step 7a: Calculate the sun's local hour angle
- $cosH = (cos(deg2rad($zenith)) - ($sinDec * sin(deg2rad($latitude)))) / ($cosDec * cos(deg2rad($latitude)));
- // XXX: What's the use of this block.. ?
- // if (sunrise && cosH > 1 || !sunrise && cosH < -1) {
- // throw doesnthappen();
- // }
- // Step 7b: Finish calculating H and convert into hours
- if ($sunrise) {
- // Sunrise
- $H = 360 - rad2deg(acos($cosH));
- } else {
- // Sunset
- $H = rad2deg(acos($cosH));
- }
- $H = $H / 15;
- // Step 8: Calculate local mean time
- $T = $H + $RA - (0.06571 * $t) - 6.622;
- // Step 9: Convert to UTC
- $UT = $T - $lngHour;
- while ($UT < 0) {
- $UTx = $UT + 24;
- assert($UTx != $UT); // askingtheguru: really needed?
- $UT = $UTx;
- }
- while ($UT >= 24) {
- $UTx = $UT - 24;
- assert($UTx != $UT); // askingtheguru: really needed?
- $UT = $UTx;
- }
- $UT = $UT + $gmt_offset;
- // Now bring the result into the chosen format and return
- switch ($retformat) {
- case SUNFUNCS_RET_TIMESTAMP:
- return intval($date - $date % (24 * 3600) + 3600 * $UT);
- case SUNFUNCS_RET_STRING:
- $N = floor($UT);
- return sprintf("%02d:%02d", $N, floor(60 * ($UT - $N)));
- case SUNFUNCS_RET_DOUBLE:
- return $UT;
- default:
- return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_ERROR, __FILE__, __LINE__);
- }
- }
- // }}}
- // {{{ getWeatherIcon()
- /**
- * Gets a number corresponding to a weather icon.
- *
- * These numbers just happen to correspond with the icons that you get with
- * the weather.com SDK, but open versions of them have been created. Input
- * must be in standard units. For the icons that include day/night, we use
- * the present time and the provided lat/lon to determine if the sun is up.
- * A complete set of icon descriptions can be found here:
- * http://sranshaft.wincustomize.com/Articles.aspx?AID=60165&u=0
- *
- * There are a number of icon sets here:
- * http://www.desktopsidebar.com/forums/index.php?showtopic=2441&st=0
- * http://www.desktopsidebar.com/forums/index.php?showtopic=819
- *
- * @param string $condition The condition.
- * @param array $clouds The clouds at various levels.
- * @param float $wind Wind speed in mph.
- * @param float $temperature Temperature in deg F.
- * @param float $latitude Point latitude.
- * @param float $longitude Point longitude.
- * @param int $reportTime The time when the weather report was generated.
- * @author Seth Price <seth@pricepages.org>
- * @access public
- */
- function getWeatherIcon($condition, $clouds = array(), $wind = 5, $temperature = 70, $latitude = -360, $longitude = -360, $reportTime = "")
- {
- // Search for matches that don't use the time of day
- $hail = (bool) stristr($condition, "hail");
- $dust = (bool) stristr($condition, "dust") || (bool) stristr($condition, "sand");
- $smoke = (bool) stristr($condition, "smoke") || (bool) stristr($condition, "volcanic ash");
- // Slightly more complex matches that might or might not use the time of day
- $near = (bool) stristr($condition, "vicinity") || (bool) stristr($condition, "recent");
- $light = (bool) stristr($condition, "light");
- $heavy = (bool) stristr($condition, "heavy");
- $ice = (bool) stristr($condition, "ice") || (bool) stristr($condition, "pellets");
- // Have to add a space to prevent matching on "snow grains"
- $rain = (bool) stristr($condition, " rain");
- $snow = (bool) stristr($condition, "snow");
- $fog = (bool) stristr($condition, "fog") || (bool) stristr($condition, "spray") || (bool) stristr($condition, "mist");
- $haze = (bool) stristr($condition, "haze");
- $ts = (bool) stristr($condition, "thunderstorm");
- $freezing = (bool) stristr($condition, "freezing");
- $wind = (bool) stristr($condition, "squall") || $wind > 25;
- $nsw = (bool) stristr($condition, "no significant weather");
- $hot = $temperature > 95;
- $frigid = $temperature < 5;
- if ($hail) {
- return 6; // Hail
- }
- if ($dust) {
- return 19; // Dust
- }
- if ($smoke) {
- return 22; // Smoke
- }
- // Get some of the dangerous conditions fist
- if ($rain && $snow && ($ice || $freezing)) {
- return 7; // Icy/Clouds Rain-Snow
- }
- if (($ts || $rain) && ($ice || $freezing)) {
- return 10; // Icy/Rain
- }
- if (($fog || $haze) && ($ice || $freezing)) {
- return 8; // Icy/Haze Rain
- }
- if ($rain && $snow) {
- return 5; // Cloudy/Snow-Rain Mix
- }
- if ($fog && $rain) {
- return 9; // Haze/Rain
- }
- if ($wind && $rain) {
- return 1; // Wind/Rain
- }
- if ($wind && $snow) {
- return 43; // Windy/Snow
- }
- if ($snow && $light) {
- return 13; // Flurries
- }
- if ($light && $rain) {
- return 11; // Light Rain
- }
- // Get the maximum coverage of the clouds at any height. For most
- // people, overcast at 1000ft is the same as overcast at 10000ft.
- //
- // 0 == clear, 1 == hazey, 2 == partly cloudy, 3 == mostly cloudy, 4 == overcast
- $coverage = 0;
- foreach ($clouds as $layer) {
- if ($coverage < 1 && stristr($layer["amount"], "few")) {
- $coverage = 1;
- } elseif ($coverage < 2 && stristr($layer["amount"], "scattered")) {
- $coverage = 2;
- } elseif ($coverage < 3 && (stristr($layer["amount"], "broken") || stristr($layer["amount"], "cumulus"))) {
- $coverage = 3;
- } elseif ($coverage < 4 && stristr($layer["amount"], "overcast")) {
- $coverage = 4;
- }
- }
- // Check if it is day or not. 0 is night, 2 is day, and 1 is unknown
- // or twilight (~(+|-)1 hour of sunrise/sunset). Note that twilight isn't
- // always accurate because of issues wrapping around the 24hr clock. Oh well...
- if ($latitude < 90 && $latitude > -90 && $longitude < 180 && $longitude > -180) {
- // Use provided time by report if available, otherwise use current GMT time
- if ($reportTime <> "" && is_numeric($reportTime)) {
- $timeOfDay = $reportTime;
- } else {
- $timeOfDay = gmmktime();
- }
- // Calculate sunrise/sunset and current time in GMT
- $sunrise = $this->calculateSunRiseSet($timeOfDay, SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude, SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH, 0, true);
- $sunset = $this->calculateSunRiseSet($timeOfDay, SUNFUNCS_RET_TIMESTAMP, $latitude, $longitude, SERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH, 0, false);
- // Now that we have the sunrise/sunset times and the current time,
- // we need to figure out if it is day, night, or twilight. Wrapping
- // these times around the 24hr clock is a pain.
- if ($sunrise < $sunset) {
- if ($timeOfDay > ($sunrise + 3600) && $timeOfDay < ($sunset - 3600)) {
- $isDay = 2;
- } elseif ($timeOfDay > ($sunrise - 3600) && $timeOfDay < ($sunset + 3600)) {
- $isDay = 1;
- } else {
- $isDay = 0;
- }
- } else {
- if ($timeOfDay < ($sunrise - 3600) && $timeOfDay > ($sunset + 3600)) {
- $isDay = 0;
- } elseif ($timeOfDay < ($sunrise + 3600) && $timeOfDay > ($sunset - 3600)) {
- $isDay = 1;
- } else {
- $isDay = 2;
- }
- }
- } else {
- // Default to twilight because it tends to have neutral icons.
- $isDay = 1;
- }
- // General precipitation
- if ($ts && $near) {
- switch ($isDay) {
- case 0:
- case 1:
- return 38; // Lightning
- case 2:
- return 37; // Lightning/Day
- }
- }
- if ($ts) {
- switch ($isDay) {
- case 0:
- return 47; // Thunderstorm/Night
- case 1:
- case 2:
- return 0; // Rain/Lightning
- }
- }
- if ($snow) {
- switch ($isDay) {
- case 0:
- return 46; // Snow/Night
- case 1:
- case 2:
- return 41; // Snow
- }
- }
- if ($rain) {
- switch ($isDay) {
- case 0:
- return 45; // Rain/Night
- case 1:
- return 40; // Rain
- case 2:
- return 39; // Rain/Day
- }
- }
- // Cloud conditions near the ground
- if ($fog) {
- return 20; // Fog
- }
- if ($haze) {
- return 21; // Haze
- }
- // Cloud conditions
- if ($coverage == 4) {
- return 26; // Mostly Cloudy
- }
- if ($coverage == 3) {
- switch ($isDay) {
- case 0:
- return 27; // Mostly Cloudy/Night
- case 1:
- return 26; // Mostly Cloudy
- case 2:
- return 28; // Mostly Cloudy/Day
- }
- }
- if ($coverage == 2) {
- switch ($isDay) {
- case 0:
- return 29; // Partly Cloudy/Night
- case 1:
- return 26; // Mostly Cloudy
- case 2:
- return 30; // Partly Cloudy/Day
- }
- }
- if ($coverage == 1) {
- switch ($isDay) {
- case 0:
- case 1:
- return 33; // Hazy/Night
- case 2:
- return 34; // Hazy/Day
- }
- }
- // Catch-alls
- if ($wind) {
- return 23; // Wind
- }
- if ($hot) {
- return 36; // Hot!
- }
- if ($frigid) {
- return 25; // Frigid
- }
- if ($nsw) {
- switch ($isDay) {
- case 0:
- case 1:
- // Use night for twilight because the moon is generally
- // out then, so it will match with most icon sets.
- return 31; // Clear Night
- case 2:
- return 32; // Clear Day
- }
- }
- return "na";
- }
- // }}}
- }
- // }}}
- ?>