1: <?php
2: /**
3: * This file contains the Horde_Service_Weather_Base class for abstracting
4: * access to various weather providers.
5: *
6: * Copyright 2011-2012 Horde LLC (http://www.horde.org/)
7: *
8: * @author Michael J Rubinsky <mrubinsk@horde.org>
9: * @license http://www.horde.org/licenses/bsd BSD
10: * @category Horde
11: * @package Service_Weather
12: */
13:
14: /**
15: * Horde_Service_Weather_Base class
16: *
17: * @author Michael J Rubinsky <mrubinsk@horde.org>
18: * @category Horde
19: * @package Service_Weather
20: */
21: abstract class Horde_Service_Weather_Base
22: {
23: /**
24: * Parameters
25: *
26: * @var array
27: */
28: protected $_params;
29:
30: /**
31: * Cache object
32: *
33: * @var Horde_Cache
34: */
35: protected $_cache;
36:
37: /**
38: * Lifetime for cached data.
39: *
40: * @var integer
41: */
42: protected $_cache_lifetime = 21600;
43:
44: /**
45: * Units to display results in.
46: *
47: * @var integer
48: */
49: public $units = Horde_Service_Weather::UNITS_STANDARD;
50:
51: /**
52: * URL to a logo for this provider
53: *
54: * @var string
55: */
56: public $logo;
57:
58: /**
59: * URL to the provider's site
60: *
61: * @var string
62: */
63: public $link;
64:
65: /**
66: * Title for the provider
67: *
68: * @var string
69: */
70: public $title;
71:
72: /**
73: * The http client
74: *
75: * @var Horde_Http_Client
76: */
77: protected $_http;
78:
79: /**
80: * Local cache of current conditions
81: *
82: */
83: protected $_current;
84:
85: /**
86: * Local cache of forecast
87: *
88: * @var array
89: */
90: protected $_forecast = array();
91:
92: /**
93: * Local cache of station data
94: *
95: * @var Horde_Service_Weather_Station
96: */
97: protected $_station;
98:
99: /**
100: * Last location requested.
101: *
102: * @var string
103: */
104: protected $_lastLocation;
105:
106: /**
107: * Last requested forecast length.
108: *
109: * @var integer
110: */
111: protected $_lastLength;
112:
113: /**
114: * Constructor.
115: *
116: * @param array $params Parameters:
117: * - 'cache': optional Horde_Cache object.
118: * - 'cache_lifetime': Lifetime of cached results.
119: */
120: public function __construct(array $params = array())
121: {
122: if (empty($params['http_client'])) {
123: throw new InvalidArgumentException('Missing http_client parameter.');
124: }
125: $this->_http = $params['http_client'];
126: unset($params['http_client']);
127: if (!empty($params['cache'])) {
128: $this->_cache = $params['cache'];
129: unset($params['cache']);
130: if (!empty($params['cache_lifetime'])) {
131: $this->_cache_lifetime = $params['cache_lifetime'];
132: unset($params['cache_lifetime']);
133: }
134: }
135:
136: $this->_params = $params;
137: }
138:
139: /**
140: * Returns the current observations.
141: *
142: * @param string $location The location string.
143: *
144: * @return Horde_Service_Weather_Current_Base
145: */
146: abstract public function getCurrentConditions($location);
147:
148: /**
149: * Returns the forecast for the current location.
150: *
151: * @param string $location The location code.
152: * @param integer $length The forecast length.
153: * @param integer $type The type of forecast to return.
154: *
155: * @return Horde_Service_Weather_Forecast_Base
156: */
157: abstract public function getForecast(
158: $location,
159: $length = Horde_Service_Weather::FORECAST_3DAY,
160: $type = Horde_Service_Weather::FORECAST_TYPE_STANDARD);
161:
162: /**
163: * Searches locations.
164: *
165: * @param string $location The location string to search.
166: * @param integer $type The type of search to perform.
167: */
168: abstract public function searchLocations(
169: $location,
170: $type = Horde_Service_Weather::SEARCHTYPE_STANDARD);
171:
172: /**
173: * Searches for locations that begin with the text in $search.
174: *
175: * @param string $search The text to search.
176: *
177: * @return array An array of stdClass objects with 'name' and 'code'
178: * properties
179: */
180: public function autocompleteLocation($search)
181: {
182: throw new Horde_Service_Weather_Exception('Not implemented');
183: }
184:
185: /**
186: * Returns a mapping of units for each UNIT type.
187: *
188: */
189: public function getUnits($type = null)
190: {
191: if (empty($type)) {
192: $type = $this->units;
193: }
194:
195: if ($type == Horde_Service_Weather::UNITS_STANDARD) {
196: return array(
197: 'temp' => Horde_Service_Weather_Translation::t('F'),
198: 'wind' => Horde_Service_Weather_Translation::t('mph'),
199: 'pres' => Horde_Service_Weather_Translation::t('inches'),
200: 'vis' => Horde_Service_Weather_Translation::t('miles'),
201: 'rain' => Horde_Service_Weather_Translation::t('inches'),
202: 'snow' => Horde_Service_Weather_Translation::t('inches'),
203: );
204: }
205:
206: return array(
207: 'temp' => Horde_Service_Weather_Translation::t('C'),
208: 'wind' => Horde_Service_Weather_Translation::t('kph'),
209: 'pres' => Horde_Service_Weather_Translation::t('millibars'),
210: 'vis' => Horde_Service_Weather_Translation::t('km'),
211: 'rain' => Horde_Service_Weather_Translation::t('millimeters'),
212: 'snow' => Horde_Service_Weather_Translation::t('centimeters'),
213: );
214:
215: }
216:
217: /**
218: * Returns the station information.
219: *
220: * @return Horde_Service_Weather_Station
221: */
222: public function getStation()
223: {
224: if (empty($this->_station)) {
225: throw new Horde_Service_Weather_Exception('No request made.');
226: }
227: return $this->_station;
228: }
229:
230: /**
231: * Check if an IP address is a globally unique address and not in RFC1918 or
232: * RFC3330 address space.
233: *
234: * @param string $ip The IPv4 IP address to check.
235: *
236: * @return boolean True if the IP address is globally unique.
237: * @link http://tools.ietf.org/html/rfc3330
238: * @link http://www.faqs.org/rfcs/rfc1918.html
239: */
240: protected function _ipIsUnique($ip)
241: {
242: // Make sure it's sane
243: $parts = explode('.', $ip);
244: if (count($parts) != 4) {
245: return false;
246: }
247:
248: // zero config IPs RFC3330
249: if ($parts[0] == 169 && $parts[1] == 254) {
250: return false;
251: }
252:
253: // reserved RFC 1918
254: if ($parts[0] == 10 ||
255: ($parts[0] == 192 && $parts[1] == 168) ||
256: ($parts[0] == 172 && ($parts[1] >= 16 && $parts[1] <= 31))) {
257:
258: return false;
259: }
260:
261: // Loopback
262: if ($parts[0] == 127) {
263: return false;
264: }
265:
266: return true;
267: }
268:
269: }