Current File : //opt/RZphp72/includes/Services/Weather/Common.php |
<?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$
* @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.7
* @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";
}
// }}}
}
// }}}
?>