Services_Weather
[ class tree: Services_Weather ] [ index: Services_Weather ] [ all elements ]

Source for file Common.php

Documentation is available at Common.php

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

Documentation generated on Mon, 11 Mar 2019 15:50:58 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.