3 * Tera_WURFL - PHP MySQL driven WURFL
\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
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
16 * Tera-WURFL remote webservice client for PHP
\r
17 * @package TeraWurflRemoteClient
\r
19 class TeraWurflRemoteClient {
\r
22 * XML Data Format - this should only be used to communicate with Tera-WURFL 2.1.1 and older
\r
25 public static $FORMAT_XML = 'xml';
\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
31 public static $FORMAT_JSON = 'json';
\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
37 public $autolookup = true;
\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
43 public $capabilities;
\r
45 * Array of errors that were encountered while processing the request and/or response.
\r
50 * The HTTP Headers that Tera-WURFL will look through to find the best User Agent, if one is not specified
\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
62 protected $userAgent;
\r
63 protected $webserviceUrl;
\r
66 protected $clientVersion = '2.1.2';
\r
67 protected $apiVersion;
\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
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
82 $this->capabilities = array();
\r
83 $this->errors = array();
\r
84 $this->webserviceUrl = $TeraWurflWebserviceURL;
\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
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
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
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
115 return $this->capabilities[$capability];
\r
117 return $this->capabilities[$capability];
\r
120 * Get the version of the Tera-WURFL Remote Client (this file)
\r
123 public function getClientVersion(){
\r
124 return $this->clientVersion;
\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
131 public function getAPIVersion(){
\r
132 return $this->apiVersion;
\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
139 protected function callTeraWurfl($uri){
\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
152 case self::$FORMAT_XML:
\r
153 if(!$this->xml = simplexml_load_file($uri)){
\r
154 throw new Exception("foo");
\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
165 * Parse the response into the capabilities array
\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
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
184 * Parse the response's errors into the errors array
\r
187 protected function loadErrors(){
\r
188 switch($this->format){
\r
189 case self::$FORMAT_JSON:
\r
190 $this->errors &= $this->json['errors'];
\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
201 * Cast strings into proper variable types, i.e. 'true' into true
\r
203 * @return Mixed String, Bool, Float
\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
217 * Is the given URL valid
\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
226 * Return the requesting client's User Agent
\r
230 public static function getUserAgent($source=null){
\r
231 if(is_null($source) || !is_array($source))$source = $_SERVER;
\r
233 if(isset($_GET['UA'])){
\r
234 $userAgent = $_GET['UA'];
\r
236 foreach(self::$userAgentHeaders as $header){
\r
237 if(array_key_exists($header,$source) && $source[$header]){
\r
238 $userAgent = $source[$header];
\r