remove old readme
[atutor.git] / themes / simplified-desktop / TeraWurflRemoteClient.php
1 <?php\r
2 /**\r
3  * Tera_WURFL - PHP MySQL driven WURFL\r
4  * \r
5  * Tera-WURFL was written by Steve Kamerman, and is based on the\r
6  * Java WURFL Evolution package by Luca Passani and WURFL PHP Tools by Andrea Trassati.\r
7  * This version uses a MySQL database to store the entire WURFL file, multiple patch\r
8  * files, and a persistent caching mechanism to provide extreme performance increases.\r
9  * \r
10  * @package TeraWurflRemoteClient\r
11  * @author Steve Kamerman <stevekamerman AT gmail.com>\r
12  * @version Stable 2.1.2 $Date: 2010/05/14 15:53:02\r
13  * @license http://www.mozilla.org/MPL/ MPL Vesion 1.1\r
14  */\r
15 /**\r
16  * Tera-WURFL remote webservice client for PHP\r
17  * @package TeraWurflRemoteClient\r
18  */\r
19 class TeraWurflRemoteClient {\r
20         \r
21         /**\r
22          * XML Data Format - this should only be used to communicate with Tera-WURFL 2.1.1 and older\r
23          * @var String\r
24          */\r
25         public static $FORMAT_XML = 'xml';\r
26         /**\r
27          * The JSON Data Format is the default transport for Tera-WURFL 2.1.2 and newer due to it's smaller size\r
28          * and better performance with the builtin PHP functions \r
29          * @var String\r
30          */\r
31         public static $FORMAT_JSON = 'json';\r
32         /**\r
33          * If you try to use a capability that has not been retrieved yet and this is set to true,\r
34          * it will generate another request to the webservice and retrieve this capability automatically.\r
35          * @var Bool\r
36          */\r
37         public $autolookup = true;\r
38         /**\r
39          * Flattened version of Tera-WURFL's capabilities array, containing only capability names and values.\r
40          * Since it is 'Flattened', there a no groups in this array, just individual capabilities.\r
41          * @var Array\r
42          */\r
43         public $capabilities;\r
44         /**\r
45          * Array of errors that were encountered while processing the request and/or response.\r
46          * @var Array\r
47          */\r
48         public $errors;\r
49         /**\r
50          * The HTTP Headers that Tera-WURFL will look through to find the best User Agent, if one is not specified\r
51          * @var Array\r
52          */\r
53         public static $userAgentHeaders = array(\r
54                 'HTTP_X_DEVICE_USER_AGENT',\r
55                 'HTTP_X_ORIGINAL_USER_AGENT',\r
56                 'HTTP_X_OPERAMINI_PHONE_UA',\r
57                 'HTTP_X_SKYFIRE_PHONE',\r
58                 'HTTP_X_BOLT_PHONE_UA',\r
59                 'HTTP_USER_AGENT'\r
60         );\r
61         protected $format;\r
62         protected $userAgent;\r
63         protected $webserviceUrl;\r
64         protected $xml;\r
65         protected $json;\r
66         protected $clientVersion = '2.1.2';\r
67         protected $apiVersion;\r
68         \r
69         /**\r
70          * Creates a TeraWurflRemoteClient object.  NOTE: in Tera-WURFL 2.1.2 the default data format is JSON.\r
71          * This format is not supported in Tera-WURFL 2.1.1 or earlier, so if you must use this client with \r
72          * an earlier version of the server, set the second parameter to TeraWurflRemoteClient::$FORMAT_XML\r
73          * @param String URL to the master Tera-WURFL Server's webservice.php\r
74          * @param String TeraWurflRemoteClient::$FORMAT_JSON or TeraWurflRemoteClient::$FORMAT_XML\r
75          */\r
76         public function __construct($TeraWurflWebserviceURL,$data_format='json'){\r
77                 $this->format = $data_format;\r
78                 if(!self::validURL($TeraWurflWebserviceURL)){\r
79                         throw new Exception("TeraWurflRemoteClient Error: the specified webservice URL is invalid.  Please make sure you pass the full url to Tera-WURFL's webservice.php.");\r
80                         exit(1);\r
81                 }\r
82                 $this->capabilities = array();\r
83                 $this->errors = array();\r
84                 $this->webserviceUrl = $TeraWurflWebserviceURL;\r
85         }\r
86         /**\r
87          * Get the requested capabilities from Tera-WURFL for the given user agent\r
88          * @param String HTTP User Agent of the device being detected\r
89          * @param Array Array of capabilities that you would like to retrieve\r
90          * @return bool Success\r
91          */\r
92         public function getCapabilitiesFromAgent($userAgent, Array $capabilities){\r
93                 $this->userAgent = (is_null($userAgent))? self::getUserAgent(): $userAgent;\r
94                 // build request string\r
95                 $uri = $this->webserviceUrl . (strpos($this->webserviceUrl,'?')===false?'?':'&') \r
96                 . 'ua=' . urlencode($this->userAgent)\r
97                 . '&format=' . $this->format\r
98                 . '&search=' . implode('|',$capabilities);\r
99                 $this->callTeraWurfl($uri);\r
100                 $this->loadCapabilities();\r
101                 $this->loadErrors();\r
102                 return true;\r
103         }\r
104         /**\r
105          * Returns the value of the requested capability\r
106          * @param String The WURFL capability you are looking for (e.g. "is_wireless_device")\r
107          * @return Mixed String, Numeric, Bool\r
108          */\r
109         public function getDeviceCapability($capability){\r
110                 $capability = strtolower($capability);\r
111                 if(!array_key_exists($capability, $this->capabilities)){\r
112                         if($this->autolookup){\r
113                                 $this->getCapabilitiesFromAgent($this->userAgent, array($capability), array());\r
114                         }\r
115                         return $this->capabilities[$capability];\r
116                 }\r
117                 return $this->capabilities[$capability];\r
118         }\r
119         /**\r
120          * Get the version of the Tera-WURFL Remote Client (this file)\r
121          * @return String\r
122          */\r
123         public function getClientVersion(){\r
124                 return $this->clientVersion;\r
125         }\r
126         /**\r
127          * Get the version of the Tera-WURFL Webservice (webservice.php on server).  This is only available\r
128          * after a query has been made since it is returned in the XML response.\r
129          * @return String\r
130          */\r
131         public function getAPIVersion(){\r
132                 return $this->apiVersion;\r
133         }\r
134         /**\r
135          * Make the webservice call to the server using the GET method and load the XML response into $this->xml \r
136          * @param String The URI of the master server\r
137          * @return void\r
138          */\r
139         protected function callTeraWurfl($uri){\r
140                 try{\r
141                         switch($this->format){\r
142                                 case self::$FORMAT_JSON:\r
143                                         $data = file_get_contents($uri);\r
144                                         $this->json = json_decode($data,true);\r
145                                         if(is_null($this->json)){\r
146                                                 // Trigger the catch block\r
147                                                 throw new Exception("foo");\r
148                                         }\r
149                                         unset($data);\r
150                                         break;\r
151                                 default:\r
152                                 case self::$FORMAT_XML:\r
153                                         if(!$this->xml = simplexml_load_file($uri)){\r
154                                                 throw new Exception("foo");\r
155                                         }\r
156                                         break;\r
157                         }\r
158                 }catch(Exception $ex){\r
159                         // Can't use builtin logging here through Tera-WURFL since it is on the client, not the server\r
160                         throw new Exception("TeraWurflRemoteClient Error: Could not query Tera-WURFL master server.");\r
161                         exit(1);\r
162                 }\r
163         }\r
164         /**\r
165          * Parse the response into the capabilities array\r
166          * @return void\r
167          */\r
168         protected function loadCapabilities(){\r
169                 switch($this->format){\r
170                         case self::$FORMAT_JSON:\r
171                                 $this->apiVersion = $this->json['apiVersion'];\r
172                                 $this->capabilities = $this->json['capabilities'];\r
173                                 break;\r
174                         default:\r
175                         case self::$FORMAT_XML:\r
176                                 $this->apiVersion = $this->xml->device['apiVersion'];\r
177                                 foreach($this->xml->device->capability as $cap){\r
178                                         $this->capabilities[(string)$cap['name']] = self::niceCast((string)$cap['value']);\r
179                                 }\r
180                                 break;\r
181                 }\r
182         }\r
183         /**\r
184          * Parse the response's errors into the errors array\r
185          * @return void\r
186          */\r
187         protected function loadErrors(){\r
188                 switch($this->format){\r
189                         case self::$FORMAT_JSON:\r
190                                 $this->errors &= $this->json['errors'];\r
191                                 break;\r
192                         default:\r
193                         case self::$FORMAT_XML:\r
194                                 foreach($this->xml->errors->error as $error){\r
195                                         $this->errors[(string)$error['name']]=(string)$error['description'];\r
196                                 }\r
197                                 break;\r
198                 }\r
199         }\r
200         /**\r
201          * Cast strings into proper variable types, i.e. 'true' into true\r
202          * @param $value\r
203          * @return Mixed String, Bool, Float\r
204          */\r
205         protected static function niceCast($value){\r
206                 // Clean Boolean values\r
207                 if($value === 'true')$value=true;\r
208                 if($value === 'false')$value=false;\r
209                 if(!is_bool($value)){\r
210                         // Clean Numeric values by loosely comparing the (float) to the (string)\r
211                         $numval = (float)$value;\r
212                         if(strcmp($value,$numval)==0)$value=$numval;\r
213                 }\r
214                 return $value;\r
215         }\r
216         /**\r
217          * Is the given URL valid\r
218          * @param $url\r
219          * @return Bool\r
220          */\r
221         protected static function validURL($url){\r
222                 if(preg_match('/^(http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/',$url)) return true;\r
223                 return false;\r
224         }       \r
225         /**\r
226          * Return the requesting client's User Agent\r
227          * @param $source\r
228          * @return String\r
229          */\r
230         public static function getUserAgent($source=null){\r
231                 if(is_null($source) || !is_array($source))$source = $_SERVER;\r
232                 $userAgent = '';\r
233                 if(isset($_GET['UA'])){\r
234                         $userAgent = $_GET['UA'];\r
235                 }else{\r
236                         foreach(self::$userAgentHeaders as $header){\r
237                                 if(array_key_exists($header,$source) && $source[$header]){\r
238                                         $userAgent = $source[$header];\r
239                                         break;\r
240                                 }\r
241                         }\r
242                 }\r
243                 return $userAgent;\r
244         }\r
245 }