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, 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 Alexander Wirtz
  42.  * @license     http://www.opensource.org/licenses/bsd-license.php  BSD License
  43.  * @version     CVS: $Id: Common.php,v 1.51 2005/11/13 22:27:32 eru Exp $
  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 Alexander Wirtz
  73.  * @license     http://www.opensource.org/licenses/bsd-license.php  BSD License
  74.  * @version     Release: 1.4.0
  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.         // The error handling in Cache is a bit crummy (read: not existent)
  244.         // so we have to do that on our own...
  245.         @include_once "Cache.php";
  246.         @$cache = new Cache($cacheType$cacheOptions);
  247.         if (is_object($cache&& (strtolower(get_class($cache)) == "cache" || is_subclass_of($cache"cache"))) {
  248.             $this->_cache        $cache;
  249.             $this->_cacheEnabled = true;
  250.         else {
  251.             $this->_cache        = null;
  252.             $this->_cacheEnabled = false;
  253.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_CACHE_INIT_FAILED__FILE____LINE__);
  254.         }
  255.  
  256.         return true;
  257.     }
  258.     // }}}
  259.  
  260.     // {{{ setUnitsFormat()
  261.     /**
  262.      * Changes the representation of the units (standard/metric)
  263.      *
  264.      * @param   string                      $unitsFormat 
  265.      * @param   array                       $customUnitsFormat 
  266.      * @access  public
  267.      */
  268.     function setUnitsFormat($unitsFormat$customUnitsFormat = array())
  269.     {
  270.         static $acceptedFormats;
  271.         if (!isset($acceptedFormats)) {
  272.             $acceptedFormats = array(
  273.                 "temp"   => array("c""f"),
  274.                 "vis"    => array("m""km""ft""sm"),
  275.                 "height" => array("m""ft"),
  276.                 "wind"   => array("mph""kmh""kt""mps""fps""bft"),
  277.                 "pres"   => array("in""hpa""mb""mm""atm"),
  278.                 "rain"   => array("in""mm")
  279.             );
  280.         }
  281.  
  282.         if (strlen($unitsFormat&& in_array(strtolower($unitsFormat{0})array("c""m""s"))) {
  283.             $this->_unitsFormat strtolower($unitsFormat{0});
  284.             if ($this->_unitsFormat == "c" && is_array($customUnitsFormat)) {
  285.                 foreach ($customUnitsFormat as $key => $value{
  286.                     if (array_key_exists($key$acceptedFormats&& in_array($value$acceptedFormats[$key])) {
  287.                         $this->_customUnitsFormat[$key$value;
  288.                     }
  289.                 }
  290.             elseif ($this->_unitsFormat == "c"{
  291.                 $this->_unitsFormat "s";
  292.             }
  293.         }
  294.     }
  295.     // }}}
  296.  
  297.     // {{{ setHttpOption()
  298.     /**
  299.      * Sets an option for usage in HTTP_Request objects
  300.      *
  301.      * @param   string                      $varName 
  302.      * @param   mixed                       $varValue 
  303.      * @access  public
  304.      */
  305.     function setHttpOption($varName$varValue)
  306.     {
  307.         if (is_string($varName&& $varName != "" && !empty($varValue)) {
  308.             $this->_httpOptions[$varName$varValue;
  309.         }
  310.     }
  311.     // }}}
  312.  
  313.     // {{{ setHttpTimeout()
  314.     /**
  315.      * Sets the timeout in seconds for HTTP requests
  316.      *
  317.      * @param   int                         $httpTimeout 
  318.      * @access  public
  319.      */
  320.     function setHttpTimeout($httpTimeout)
  321.     {
  322.         if (is_int($httpTimeout)) {
  323.             $this->_httpOptions["timeout"$httpTimeout;
  324.         }
  325.     }
  326.     // }}}
  327.  
  328.     // {{{ setHttpProxy()
  329.     /**
  330.      * Sets the proxy for HTTP requests
  331.      *
  332.      * @param   string                      $httpProxy 
  333.      * @access  public
  334.      */
  335.     function setHttpProxy($httpProxy)
  336.     {
  337.         if (($proxy parse_url($httpProxy)) !== false && $proxy["scheme"== "http"{
  338.             if (isset($proxy["user"]&& $proxy["user"!= ""{
  339.                 $this->_httpOptions["proxy_user"$proxy["user"];
  340.             }
  341.             if (isset($proxy["pass"]&& $proxy["pass"!= ""{
  342.                 $this->_httpOptions["proxy_pass"$proxy["pass"];
  343.             }
  344.             if (isset($proxy["host"]&& $proxy["host"!= ""{
  345.                 $this->_httpOptions["proxy_host"$proxy["host"];
  346.             }
  347.             if (isset($proxy["port"]&& $proxy["port"!= ""{
  348.                 $this->_httpOptions["proxy_port"$proxy["port"];
  349.             }
  350.  
  351.             return true;
  352.         else {
  353.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_HTTP_PROXY_INVALID__FILE____LINE__);
  354.         }
  355.     }
  356.     // }}}
  357.  
  358.     // {{{ getUnitsFormat()
  359.     /**
  360.      * Returns the selected units format
  361.      *
  362.      * @param   string                      $unitsFormat 
  363.      * @return  array 
  364.      * @access  public
  365.      */
  366.     function getUnitsFormat($unitsFormat "")
  367.     {
  368.         // This is cheap'o stuff
  369.         if (strlen($unitsFormat&& in_array(strtolower($unitsFormat{0})array("c""m""s"))) {
  370.             $unitsFormat strtolower($unitsFormat{0});
  371.         else {
  372.             $unitsFormat $this->_unitsFormat;
  373.         }
  374.  
  375.         $c $this->_customUnitsFormat;
  376.         $m = array(
  377.             "temp"   => "c",
  378.             "vis"    => "km",
  379.             "height" => "m",
  380.             "wind"   => "kmh",
  381.             "pres"   => "mb",
  382.             "rain"   => "mm"
  383.         );
  384.         $s = array(
  385.             "temp"   => "f",
  386.             "vis"    => "sm",
  387.             "height" => "ft",
  388.             "wind"   => "mph",
  389.             "pres"   => "in",
  390.             "rain"   => "in"
  391.         );
  392.  
  393.         return ${$unitsFormat};
  394.     }
  395.     // }}}
  396.  
  397.     // {{{ setDateTimeFormat()
  398.     /**
  399.      * Changes the representation of time and dates (see http://www.php.net/date)
  400.      *
  401.      * @param   string                      $dateFormat 
  402.      * @param   string                      $timeFormat 
  403.      * @access  public
  404.      */
  405.     function setDateTimeFormat($dateFormat ""$timeFormat "")
  406.     {
  407.         if (strlen($dateFormat)) {
  408.             $this->_dateFormat $dateFormat;
  409.         }
  410.         if (strlen($timeFormat)) {
  411.             $this->_timeFormat $timeFormat;
  412.         }
  413.     }
  414.     // }}}
  415.  
  416.     // {{{ convertTemperature()
  417.     /**
  418.      * Convert temperature between f and c
  419.      *
  420.      * @param   float                       $temperature 
  421.      * @param   string                      $from 
  422.      * @param   string                      $to 
  423.      * @return  float 
  424.      * @access  public
  425.      */
  426.     function convertTemperature($temperature$from$to)
  427.     {
  428.         $from strtolower($from{0});
  429.         $to   strtolower($to{0});
  430.  
  431.         $result = array(
  432.             "f" => array(
  433.                 "f" => $temperature,            "c" => ($temperature - 32/ 1.8
  434.             ),
  435.             "c" => array(
  436.                 "f" => 1.8 * $temperature + 32"c" => $temperature
  437.             )
  438.         );
  439.  
  440.         return round($result[$from][$to]2);
  441.     }
  442.     // }}}
  443.  
  444.     // {{{ convertSpeed()
  445.     /**
  446.      * Convert speed between mph, kmh, kt, mps, fps and bft
  447.      *
  448.      * Function will return "false" when trying to convert from
  449.      * Beaufort, as it is a scale and not a true measurement
  450.      *
  451.      * @param   float                       $speed 
  452.      * @param   string                      $from 
  453.      * @param   string                      $to 
  454.      * @return  float|int|bool
  455.      * @access  public
  456.      * @link    http://www.spc.noaa.gov/faq/tornado/beaufort.html
  457.      */
  458.     function convertSpeed($speed$from$to)
  459.     {
  460.         $from strtolower($from);
  461.         $to   strtolower($to);
  462.  
  463.         static $factor;
  464.         static $beaufort;
  465.         if (!isset($factor)) {
  466.             $factor = array(
  467.                 "mph" => array(
  468.                     "mph" => 1,         "kmh" => 1.609344"kt" => 0.8689762"mps" => 0.44704,   "fps" => 1.4666667
  469.                 ),
  470.                 "kmh" => array(
  471.                     "mph" => 0.6213712"kmh" => 1,        "kt" => 0.5399568"mps" => 0.2777778"fps" => 0.9113444
  472.                 ),
  473.                 "kt"  => array(
  474.                     "mph" => 1.1507794"kmh" => 1.852,    "kt" => 1,         "mps" => 0.5144444"fps" => 1.6878099
  475.                 ),
  476.                 "mps" => array(
  477.                     "mph" => 2.2369363"kmh" => 3.6,      "kt" => 1.9438445"mps" => 1,         "fps" => 3.2808399
  478.                 ),
  479.                 "fps" => array(
  480.                     "mph" => 0.6818182"kmh" => 1.09728,  "kt" => 0.5924838"mps" => 0.3048,    "fps" => 1
  481.                 )
  482.             );
  483.  
  484.             // Beaufort scale, measurements are in knots
  485.             $beaufort = array(
  486.                   1,   3,   6,  10,
  487.                  16,  21,  27,  33,
  488.                  40,  47,  55,  63
  489.             );
  490.         }
  491.  
  492.         if ($from == "bft"{
  493.             return false;
  494.         elseif ($to == "bft"{
  495.             $speed round($speed $factor[$from]["kt"]0);
  496.             for ($i = 0; $i sizeof($beaufort)$i++{
  497.                 if ($speed <= $beaufort[$i]{
  498.                     return $i;
  499.                 }
  500.             }
  501.             return sizeof($beaufort);
  502.         else {
  503.             return round($speed $factor[$from][$to]2);
  504.         }
  505.     }
  506.     // }}}
  507.  
  508.     // {{{ convertPressure()
  509.     /**
  510.      * Convert pressure between in, hpa, mb, mm and atm
  511.      *
  512.      * @param   float                       $pressure 
  513.      * @param   string                      $from 
  514.      * @param   string                      $to 
  515.      * @return  float 
  516.      * @access  public
  517.      */
  518.     function convertPressure($pressure$from$to)
  519.     {
  520.         $from strtolower($from);
  521.         $to   strtolower($to);
  522.  
  523.         static $factor;
  524.         if (!isset($factor)) {
  525.             $factor = array(
  526.                 "in"   => array(
  527.                     "in" => 1,         "hpa" => 33.863887"mb" => 33.863887"mm" => 25.4,      "atm" => 0.0334213
  528.                 ),
  529.                 "hpa"  => array(
  530.                     "in" => 0.02953,   "hpa" => 1,         "mb" => 1,         "mm" => 0.7500616"atm" => 0.0009869
  531.                 ),
  532.                 "mb"   => array(
  533.                     "in" => 0.02953,   "hpa" => 1,         "mb" => 1,         "mm" => 0.7500616"atm" => 0.0009869
  534.                 ),
  535.                 "mm"   => array(
  536.                     "in" => 0.0393701"hpa" => 1.3332239"mb" => 1.3332239"mm" => 1,         "atm" => 0.0013158
  537.                 ),
  538.                 "atm"  => array(
  539.                     "in" => 29,921258"hpa" => 1013.2501"mb" => 1013.2501"mm" => 759.999952"atm" => 1
  540.                 )
  541.             );
  542.         }
  543.  
  544.         return round($pressure $factor[$from][$to]2);
  545.     }
  546.     // }}}
  547.  
  548.     // {{{ convertDistance()
  549.     /**
  550.      * Convert distance between km, ft and sm
  551.      *
  552.      * @param   float                       $distance 
  553.      * @param   string                      $from 
  554.      * @param   string                      $to 
  555.      * @return  float 
  556.      * @access  public
  557.      */
  558.     function convertDistance($distance$from$to)
  559.     {
  560.         $to   strtolower($to);
  561.         $from strtolower($from);
  562.  
  563.         static $factor;
  564.         if (!isset($factor)) {
  565.             $factor = array(
  566.                 "m" => array(
  567.                     "m" => 1,            "km" => 1000,      "ft" => 3.280839895"sm" => 0.0006213699
  568.                 ),
  569.                 "km" => array(
  570.                     "m" => 0.001,        "km" => 1,         "ft" => 3280.839895"sm" => 0.6213699
  571.                 ),
  572.                 "ft" => array(
  573.                     "m" => 0.3048,       "km" => 0.0003048"ft" => 1,           "sm" => 0.0001894
  574.                 ),
  575.                 "sm" => array(
  576.                     "m" => 0.0016093472"km" => 1.6093472"ft" => 5280.0106,   "sm" => 1
  577.                 )
  578.             );
  579.         }
  580.  
  581.         return round($distance $factor[$from][$to]2);
  582.     }
  583.     // }}}
  584.  
  585.     // {{{ calculateWindChill()
  586.     /**
  587.      * Calculate windchill from temperature and windspeed (enhanced formula)
  588.      *
  589.      * Temperature has to be entered in deg F, speed in mph!
  590.      *
  591.      * @param   float                       $temperature 
  592.      * @param   float                       $speed 
  593.      * @return  float 
  594.      * @access  public
  595.      * @link    http://www.nws.noaa.gov/om/windchill/
  596.      */
  597.     function calculateWindChill($temperature$speed)
  598.     {
  599.         return round(35.74 + 0.6215 * $temperature - 35.75 * pow($speed0.16+ 0.4275 * $temperature pow($speed0.16));
  600.     }
  601.     // }}}
  602.  
  603.     // {{{ calculateHumidity()
  604.     /**
  605.      * Calculate humidity from temperature and dewpoint
  606.      * This is only an approximation, there is no exact formula, this
  607.      * one here is called Magnus-Formula
  608.      *
  609.      * Temperature and dewpoint have to be entered in deg C!
  610.      *
  611.      * @param   float                       $temperature 
  612.      * @param   float                       $dewPoint 
  613.      * @return  float 
  614.      * @access  public
  615.      * @link    http://www.faqs.org/faqs/meteorology/temp-dewpoint/
  616.      */
  617.     function calculateHumidity($temperature$dewPoint)
  618.     {
  619.         // First calculate saturation steam pressure for both temperatures
  620.         if ($temperature >= 0{
  621.             $a = 7.5;
  622.             $b = 237.3;
  623.         else {
  624.             $a = 7.6;
  625.             $b = 240.7;
  626.         }
  627.         $tempSSP = 6.1078 * pow(10($a $temperature($b $temperature));
  628.  
  629.         if ($dewPoint >= 0{
  630.             $a = 7.5;
  631.             $b = 237.3;
  632.         else {
  633.             $a = 7.6;
  634.             $b = 240.7;
  635.         }
  636.         $dewSSP  = 6.1078 * pow(10($a $dewPoint($b $dewPoint));
  637.  
  638.         return round(100 * $dewSSP $tempSSP1);
  639.     }
  640.     // }}}
  641.  
  642.     // {{{ calculateDewPoint()
  643.     /**
  644.      * Calculate dewpoint from temperature and humidity
  645.      * This is only an approximation, there is no exact formula, this
  646.      * one here is called Magnus-Formula
  647.      *
  648.      * Temperature has to be entered in deg C!
  649.      *
  650.      * @param   float                       $temperature 
  651.      * @param   float                       $humidity 
  652.      * @return  float 
  653.      * @access  public
  654.      * @link    http://www.faqs.org/faqs/meteorology/temp-dewpoint/
  655.      */
  656.     function calculateDewPoint($temperature$humidity)
  657.     {
  658.         if ($temperature >= 0{
  659.             $a = 7.5;
  660.             $b = 237.3;
  661.         else {
  662.             $a = 7.6;
  663.             $b = 240.7;
  664.         }
  665.  
  666.         // First calculate saturation steam pressure for temperature
  667.         $SSP = 6.1078 * pow(10($a $temperature($b $temperature));
  668.  
  669.         // Steam pressure
  670.         $SP  $humidity / 100 * $SSP;
  671.  
  672.         $v   log($SP / 6.107810);
  673.  
  674.         return round($b $v ($a $v)1);
  675.     }
  676.     // }}}
  677.  
  678.     // {{{ polar2cartesian()
  679.     /**
  680.      * Convert polar coordinates to cartesian coordinates
  681.      *
  682.      * @param   float                       $latitude 
  683.      * @param   float                       $longitude 
  684.      * @return  array 
  685.      * @access  public
  686.      */
  687.     function polar2cartesian($latitude$longitude)
  688.     {
  689.         $theta deg2rad($latitude);
  690.         $phi   deg2rad($longitude);
  691.  
  692.         $x SERVICES_WEATHER_RADIUS_EARTH * cos($phicos($theta);
  693.         $y SERVICES_WEATHER_RADIUS_EARTH * sin($phicos($theta);
  694.         $z SERVICES_WEATHER_RADIUS_EARTH             * sin($theta);
  695.  
  696.         return array($x$y$z);
  697.     }
  698.     // }}}
  699.  
  700.  
  701.     // {{{ calculateSunRiseSet()
  702.     /**
  703.      * Calculates sunrise and sunset for a location
  704.      *
  705.      * The sun position algorithm taken from the 'US Naval Observatory's
  706.      * Almanac for Computers', implemented by Ken Bloom <kekabloom[at]ucdavis[dot]edu>
  707.      * for the zmanim project, converted to C by Moshe Doron <mosdoron[at]netvision[dot]net[dot]il>
  708.      * and finally taken from the PHP5 sources and converted to native PHP as a wrapper.
  709.      *
  710.      * The date has to be entered as a timestamp!
  711.      *
  712.      * @param   int                         $date 
  713.      * @param   int                         $retformat 
  714.      * @param   float                       $latitude 
  715.      * @param   float                       $longitude 
  716.      * @param   float                       $zenith 
  717.      * @param   float                       $gmt_offset 
  718.      * @param   bool                        $sunrise 
  719.      * @return  PEAR_Error|mixed
  720.      * @throws  PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID
  721.      * @throws  PEAR_Error::SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID
  722.      * @throws  PEAR_Error::SERVICES_WEATHER_ERROR_UNKNOWN_ERROR
  723.      * @access  public
  724.      */
  725.     function calculateSunRiseSet($date$retformat = null$latitude = null$longitude = null$zenith = null$gmt_offset = null$sunrise = true)
  726.     {
  727.         // Date must be timestamp for now
  728.         if (!is_int($date)) {
  729.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_DATE_INVALID__FILE____LINE__);
  730.         }
  731.  
  732.         // Check for proper return format
  733.         if ($retformat === null{
  734.             $retformat  = SUNFUNCS_RET_STRING;
  735.         elseif (!in_array($retformatarray(SUNFUNCS_RET_TIMESTAMPSUNFUNCS_RET_STRINGSUNFUNCS_RET_DOUBLE)) ) {
  736.             return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_SUNFUNCS_RETFORM_INVALID__FILE____LINE__);
  737.         }
  738.  
  739.         // Set default values for coordinates
  740.         if ($latitude === null{
  741.             $latitude   = SUNFUNCS_DEFAULT_LATITUDE;
  742.         else {
  743.             $latitude   = (float) $latitude;
  744.         }
  745.         if ($longitude === null{
  746.             $longitude  = SUNFUNCS_DEFAULT_LONGITUDE;
  747.         else {
  748.             $longitude  = (float) $longitude;
  749.         }
  750.         if ($zenith === null{
  751.             if($sunrise{
  752.                 $zenith = SUNFUNCS_SUNRISE_ZENITH;
  753.             else {
  754.                 $zenith = SUNFUNCS_SUNSET_ZENITH;
  755.             }
  756.         else {
  757.             $zenith     = (float) $zenith;
  758.         }
  759.  
  760.         // Default value for GMT offset
  761.         if ($gmt_offset === null{
  762.             $gmt_offset date("Z"$date/ 3600;
  763.         else {
  764.             $gmt_offset = (float) $gmt_offset;
  765.         }
  766.  
  767.         // If we have PHP5, then act as wrapper for the appropriate functions
  768.         if ($sunrise && function_exists("date_sunrise")) {
  769.             return date_sunrise($date$retformat$latitude$longitude$zenith$gmt_offset);
  770.         }
  771.         if (!$sunrise && function_exists("date_sunset")) {
  772.             return date_sunset($date$retformat$latitude$longitude$zenith$gmt_offset);
  773.         }
  774.  
  775.         // Apparently we have PHP4, so calculate the neccessary steps in native PHP
  776.         // Step 1: First calculate the day of the year
  777.         $N date("z"$date+ 1;
  778.  
  779.         // Step 2: Convert the longitude to hour value and calculate an approximate time
  780.         $lngHour $longitude / 15;
  781.  
  782.         // Use 18 for sunset instead of 6
  783.         if ($sunrise{
  784.             // Sunrise
  785.             $t $N ((6 - $lngHour/ 24);
  786.         else {
  787.             // Sunset
  788.             $t $N ((18 - $lngHour/ 24);
  789.         }
  790.  
  791.         // Step 3: Calculate the sun's mean anomaly
  792.         $M (0.9856 * $t- 3.289;
  793.  
  794.         // Step 4: Calculate the sun's true longitude
  795.         $L $M (1.916 * sin(deg2rad($M))) (0.020 * sin(deg2rad(2 * $M))) + 282.634;
  796.  
  797.         while ($L < 0{
  798.             $Lx $L + 360;
  799.             assert($Lx != $L)// askingtheguru: really needed?
  800.             $L $Lx;
  801.         }
  802.  
  803.         while ($L >= 360{
  804.             $Lx $L - 360;
  805.             assert($Lx != $L)// askingtheguru: really needed?
  806.             $L $Lx;
  807.         }
  808.  
  809.         // Step 5a: Calculate the sun's right ascension
  810.         $RA rad2deg(atan(0.91764 * tan(deg2rad($L))));
  811.  
  812.         while ($RA < 0{
  813.             $RAx $RA + 360;
  814.             assert($RAx != $RA)// askingtheguru: really needed?
  815.             $RA $RAx;
  816.         }
  817.  
  818.         while ($RA >= 360{
  819.             $RAx $RA - 360;
  820.             assert($RAx != $RA)// askingtheguru: really needed?
  821.             $RA $RAx;
  822.         }
  823.  
  824.         // Step 5b: Right ascension value needs to be in the same quadrant as L
  825.         $Lquadrant  floor($L / 90* 90;
  826.         $RAquadrant floor($RA / 90* 90;
  827.  
  828.         $RA $RA ($Lquadrant $RAquadrant);
  829.  
  830.         // Step 5c: Right ascension value needs to be converted into hours
  831.         $RA /= 15;
  832.  
  833.         // Step 6: Calculate the sun's declination
  834.         $sinDec = 0.39782 * sin(deg2rad($L));
  835.         $cosDec cos(asin($sinDec));
  836.  
  837.         // Step 7a: Calculate the sun's local hour angle
  838.         $cosH (cos(deg2rad($zenith)) ($sinDec sin(deg2rad($latitude)))) ($cosDec cos(deg2rad($latitude)));
  839.  
  840.         // XXX: What's the use of this block.. ?
  841.         // if (sunrise && cosH > 1 || !sunrise && cosH < -1) {
  842.         //     throw doesnthappen();
  843.         // }
  844.  
  845.         // Step 7b: Finish calculating H and convert into hours
  846.         if ($sunrise{
  847.             // Sunrise
  848.             $H = 360 - rad2deg(acos($cosH));
  849.         else {
  850.             // Sunset
  851.             $H rad2deg(acos($cosH));
  852.         }
  853.         $H $H / 15;
  854.  
  855.         // Step 8: Calculate local mean time
  856.         $T $H $RA (0.06571 * $t- 6.622;
  857.  
  858.         // Step 9: Convert to UTC
  859.         $UT $T $lngHour;
  860.  
  861.         while ($UT < 0{
  862.             $UTx $UT + 24;
  863.             assert($UTx != $UT)// askingtheguru: really needed?
  864.             $UT $UTx;
  865.         }
  866.  
  867.         while ($UT >= 24{
  868.             $UTx $UT - 24;
  869.             assert($UTx != $UT)// askingtheguru: really needed?
  870.             $UT $UTx;
  871.         }
  872.  
  873.         $UT $UT $gmt_offset;
  874.  
  875.         // Now bring the result into the chosen format and return
  876.         switch ($retformat{
  877.             case SUNFUNCS_RET_TIMESTAMP:
  878.                 return floor($date ($date (24 * 3600))) floor(60 * $UT);
  879.             case SUNFUNCS_RET_STRING:
  880.                 $N floor($UT);
  881.                 return sprintf("%02d:%02d"$Nfloor(60 * ($UT $N)));
  882.             case SUNFUNCS_RET_DOUBLE:
  883.                 return $UT;
  884.             default:
  885.                 return Services_Weather::raiseError(SERVICES_WEATHER_ERROR_UNKNOWN_ERROR__FILE____LINE__);
  886.         }
  887.     }
  888.     // }}}
  889.  
  890.     // {{{ getWeatherIcon()
  891.     /**
  892.      * Gets a number corresponding to a weather icon.
  893.      *
  894.      * These numbers just happen to correspond with the icons that you get with
  895.      * the weather.com SDK, but open versions of them have been created. Input
  896.      * must be in standard units. For the icons that include day/night, we use
  897.      * the present time and the provided lat/lon to determine if the sun is up.
  898.      * A complete set of icon descriptions can be found here:
  899.      * http://sranshaft.wincustomize.com/Articles.aspx?AID=60165&u=0
  900.      *
  901.      * There are a number of icon sets here:
  902.      * http://www.desktopsidebar.com/forums/index.php?showtopic=2441&st=0
  903.      * http://www.desktopsidebar.com/forums/index.php?showtopic=819
  904.      *
  905.      * @param   string                      $condition      The condition.
  906.      * @param   array                       $clouds         The clouds at various levels.
  907.      * @param   float                       $wind           Wind speed in mph.
  908.      * @param   float                       $temperature    Temperature in deg F.
  909.      * @param   float                       $latitude       Point latitude.
  910.      * @param   float                       $longitude      Point longitude.
  911.      * @author  Seth Price  <seth@pricepages.org>
  912.      * @access  public
  913.      */
  914.     function getWeatherIcon($condition$clouds = array()$wind = 5$temperature = 70$latitude = -360$longitude = -360)
  915.     {
  916.         // Search for matches that don't use the time of day
  917.         $hail     = (bool) stristr($condition"hail");
  918.         $dust     = (bool) stristr($condition"dust")     || (bool) stristr($condition"sand");
  919.         $smoke    = (bool) stristr($condition"smoke")    || (bool) stristr($condition"volcanic ash");
  920.  
  921.         // Slightly more complex matches that might or might not use the time of day
  922.         $near     = (bool) stristr($condition"vicinity"|| (bool) stristr($condition"recent");
  923.         $light    = (bool) stristr($condition"light");
  924.         $heavy    = (bool) stristr($condition"heavy");
  925.         $ice      = (bool) stristr($condition"ice")      || (bool) stristr($condition"pellets");
  926.         $rain     = (bool) stristr($condition"rain");
  927.         $snow     = (bool) stristr($condition"snow");
  928.         $fog      = (bool) stristr($condition"fog")      || (bool) stristr($condition"spray")        || (bool) stristr($condition"mist");
  929.         $haze     = (bool) stristr($condition"haze");
  930.         $ts       = (bool) stristr($condition"thunderstorm");
  931.         $freezing = (bool) stristr($condition"freezing");
  932.         $wind     = (bool) stristr($condition"squall")   || $wind > 25;
  933.         $nsw      = (bool) stristr($condition"no significant weather");
  934.         $hot      $temperature > 95;
  935.         $frigid   $temperature < 5;
  936.  
  937.  
  938.         if ($hail{
  939.             return 6;  // Hail
  940.         }
  941.         if ($dust{
  942.             return 19; // Dust
  943.         }
  944.         if ($smoke{
  945.             return 22; // Smoke
  946.         }
  947.  
  948.         // Get some of the dangerous conditions fist
  949.         if ($rain && $snow && ($ice || $freezing)) {
  950.             return 7;  // Icy/Clouds Rain-Snow
  951.         }
  952.         if (($ts || $rain&& ($ice || $freezing)) {
  953.             return 10; // Icy/Rain
  954.         }
  955.         if (($fog || $haze&& ($ice || $freezing)) {
  956.             return 8;  // Icy/Haze Rain
  957.         }
  958.         if ($rain && $snow{
  959.             return 5;  // Cloudy/Snow-Rain Mix
  960.         }
  961.         if ($fog && $rain{
  962.             return 9;  // Haze/Rain
  963.         }
  964.         if ($wind && $rain{
  965.             return 1;  // Wind/Rain
  966.         }
  967.         if ($wind && $snow{
  968.             return 43; // Windy/Snow
  969.         }
  970.         if ($snow && $light{
  971.             return 13; // Flurries
  972.         }
  973.         if ($light && $rain{
  974.             return 11; // Light Rain
  975.         }
  976.  
  977.         // Get the maximum coverage of the clouds at any height. For most
  978.         // people, overcast at 1000ft is the same as overcast at 10000ft.
  979.         //
  980.         // 0 == clear, 1 == hazey, 2 == partly cloudy, 3 == mostly cloudy, 4 == overcast
  981.         $coverage = 0;
  982.         foreach ($clouds as $layer{
  983.             if ($coverage < 1 && stristr($layer["amount"]"few")) {
  984.                 $coverage = 1;
  985.             elseif ($coverage < 2 && stristr($layer["amount"]"scattered")) {
  986.                 $coverage = 2;
  987.             elseif ($coverage < 3 && (stristr($layer["amount"]"broken"|| stristr($layer["amount"]"cumulus"))) {
  988.                 $coverage = 3;
  989.             elseif ($coverage < 4 && stristr($layer["amount"]"overcast")) {
  990.                 $coverage = 4;
  991.             }
  992.         }
  993.  
  994.         // Check if it is day or not. 0 is night, 2 is day, and 1 is unknown
  995.         // or twilight (~(+|-)1 hour of sunrise/sunset). Note that twilight isn't
  996.         // always accurate because of issues wrapping around the 24hr clock. Oh well...
  997.         if ($latitude < 90 && $latitude > -90 && $longitude < 180 && $longitude > -180{
  998.             // Calculate sunrise/sunset and current time in GMT
  999.             $sunrise   $this->calculateSunRiseSet(gmmktime()SUNFUNCS_RET_TIMESTAMP$latitude$longitudeSERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH0true);
  1000.             $sunset    $this->calculateSunRiseSet(gmmktime()SUNFUNCS_RET_TIMESTAMP$latitude$longitudeSERVICES_WEATHER_SUNFUNCS_SUNRISE_ZENITH0false);
  1001.             $timeOfDay gmmktime();
  1002.  
  1003.             // Now that we have the sunrise/sunset times and the current time,
  1004.             // we need to figure out if it is day, night, or twilight. Wrapping
  1005.             // these times around the 24hr clock is a pain.
  1006.             if ($sunrise $sunset{
  1007.                 if ($timeOfDay ($sunrise + 3600&& $timeOfDay ($sunset - 3600)) {
  1008.                     $isDay = 2;
  1009.                 elseif ($timeOfDay ($sunrise - 3600&& $timeOfDay ($sunset + 3600)) {
  1010.                     $isDay = 1;
  1011.                 else {
  1012.                     $isDay = 0;
  1013.                 }
  1014.             else {
  1015.                 if ($timeOfDay ($sunrise - 3600&& $timeOfDay ($sunset + 3600)) {
  1016.                     $isDay = 0;
  1017.                 elseif ($timeOfDay ($sunrise + 3600&& $timeOfDay ($sunset - 3600)) {
  1018.                     $isDay = 1;
  1019.                 else {
  1020.                     $isDay = 2;
  1021.                 }
  1022.             }
  1023.         else {
  1024.             // Default to twilight because it tends to have neutral icons.
  1025.             $isDay = 1;
  1026.         }
  1027.  
  1028.         // General precipitation
  1029.         if ($ts && $near{
  1030.             switch ($isDay{
  1031.                 case 0:
  1032.                 case 1:
  1033.                     return 38; // Lightning
  1034.                 case 2:
  1035.                     return 37; // Lightning/Day
  1036.             }
  1037.         }
  1038.         if ($ts{
  1039.             switch ($isDay{
  1040.                 case 0:
  1041.                     return 47; // Thunderstorm/Night
  1042.                 case 1:
  1043.                 case 2:
  1044.                     return 0;  // Rain/Lightning
  1045.             }
  1046.         }
  1047.         if ($snow{
  1048.             switch ($isDay{
  1049.                 case 0:
  1050.                     return 46; // Snow/Night
  1051.                 case 1:
  1052.                 case 2:
  1053.                     return 41; // Snow
  1054.             }
  1055.         }
  1056.         if ($rain{
  1057.             switch ($isDay{
  1058.                 case 0:
  1059.                     return 45; // Rain/Night
  1060.                 case 1:
  1061.                     return 40; // Rain
  1062.                 case 2:
  1063.                     return 39; // Rain/Day
  1064.             }
  1065.         }
  1066.  
  1067.         // Cloud conditions near the ground
  1068.         if ($fog{
  1069.             return 20; // Fog
  1070.         }
  1071.         if ($haze{
  1072.             return 21; // Haze
  1073.         }
  1074.  
  1075.         // Cloud conditions
  1076.         if ($coverage == 4{
  1077.             return 26; // Mostly Cloudy
  1078.         }
  1079.         if ($coverage == 3{
  1080.             switch ($isDay{
  1081.                 case 0:
  1082.                     return 27; // Mostly Cloudy/Night
  1083.                 case 1:
  1084.                     return 26; // Mostly Cloudy
  1085.                 case 2:
  1086.                     return 28; // Mostly Cloudy/Day
  1087.             }
  1088.         }
  1089.         if ($coverage == 2{
  1090.             switch ($isDay{
  1091.                 case 0:
  1092.                     return 29; // Partly Cloudy/Night
  1093.                 case 1:
  1094.                     return 26; // Mostly Cloudy
  1095.                 case 2:
  1096.                     return 30; // Partly Cloudy/Day
  1097.             }
  1098.         }
  1099.         if ($coverage == 1{
  1100.             switch ($isDay{
  1101.                 case 0:
  1102.                 case 1:
  1103.                     return 33; // Hazy/Night
  1104.                 case 2:
  1105.                     return 34; // Hazy/Day
  1106.             }
  1107.         }
  1108.  
  1109.         // Catch-alls
  1110.         if ($wind{
  1111.             return 23; // Wind
  1112.         }
  1113.         if ($hot{
  1114.             return 36; // Hot!
  1115.         }
  1116.         if ($frigid{
  1117.             return 25; // Frigid
  1118.         }
  1119.  
  1120.         if ($nsw{
  1121.             switch ($isDay{
  1122.                 case 0:
  1123.                 case 1:
  1124.                     // Use night for twilight because the moon is generally
  1125.                     // out then, so it will match with most icon sets.
  1126.                     return 31; // Clear Night
  1127.                 case 2:
  1128.                     return 32; // Clear Day
  1129.             }
  1130.         }
  1131.  
  1132.         return "na";
  1133.     }
  1134.     // }}}
  1135. }
  1136. // }}}
  1137. ?>

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