PageRenderTime 56ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/wurfl_class.php

https://github.com/Br3nda/wurfl_php
PHP | 692 lines | 410 code | 40 blank | 242 comment | 91 complexity | cd068015508e58b6b1e95932676ec8cb MD5 | raw file
  1. <?php
  2. /* ***** BEGIN LICENSE BLOCK *****
  3. * Version: MPL 1.1
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. * http://www.mozilla.org/MPL/
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. *
  15. * The Original Code is WURFL PHP Libraries.
  16. *
  17. * The Initial Developer of the Original Code is
  18. * Andrea Trasatti.
  19. * Portions created by the Initial Developer are Copyright (C) 2004-2005
  20. * the Initial Developer. All Rights Reserved.
  21. *
  22. * Contributor(s): Herouth Maoz.
  23. *
  24. * ***** END LICENSE BLOCK ***** */
  25. /*
  26. * $Id$
  27. * $RCSfile: wurfl_class.php,v $ v2.1 beta3 (Feb, 28 2006)
  28. * Author: Andrea Trasatti ( atrasatti AT users DOT sourceforge DOT net )
  29. * Multicache implementation: Herouth Maoz ( herouth AT spamcop DOT net )
  30. *
  31. */
  32. /*
  33. *
  34. * This is a working example of a class to read the WURFL xml, take a user agent
  35. * and make something useful with it. Once you will have created an object with
  36. * this class you have access to all its capabilities.
  37. *
  38. * More info can be found here in the PHP section:
  39. * http://wurfl.sourceforge.net/
  40. *
  41. * Questions or comments can be sent to
  42. * "Andrea Trasatti" <atrasatti AT users DOT sourceforge DOT net>
  43. *
  44. * Please, support this software, send any suggestion and improvement to me
  45. * or the mailing list and we will try to keep it updated and make it better
  46. * every day.
  47. *
  48. * If you like it and use it, please let me know or contact the wmlprogramming
  49. * mailing list: wmlprogramming@yahoogroups.com
  50. *
  51. */
  52. if ( !defined('WURFL_CONFIG') )
  53. @require_once('./wurfl_config.php');
  54. if ( !defined('WURFL_CONFIG') )
  55. die("NO CONFIGURATION");
  56. if ( defined('WURFL_PARSER_FILE') )
  57. require_once(WURFL_PARSER_FILE);
  58. else
  59. require_once("./wurfl_parser.php");
  60. /**
  61. *
  62. * wurfl_class
  63. *
  64. * Example:
  65. * $myDevice = new wurfl_class($wurfl, $wurfl_agents); // $wurfl is the parsed
  66. * // XML, $wurfl_agents is the list of agents and id's. When you first
  67. * // start the class simply pass them as empty variables and will be filled.
  68. * // Pass the variables with all the values if you already have them.
  69. * $myDevice->GetDeviceCapabilitiesFromAgent('SIE-S45');
  70. * if ( $myDevice->browser_is_wap )
  71. * if ( $myDevice->capabilities['downloadfun']['downloadfun_support'] )
  72. * echo "downloadfun supported";
  73. * else
  74. * echo "WAP is supported, downloadfun is not";
  75. *
  76. */
  77. class wurfl_class {
  78. /**
  79. * associative array created by wurfl_parser.php
  80. * @var associative array
  81. */
  82. var $_wurfl="";
  83. /**
  84. * associative array user_agent=>id
  85. * @var associative array
  86. */
  87. var $_wurfl_agents="";
  88. /**
  89. * device's complete user agent (just in case)
  90. * @var string
  91. */
  92. var $user_agent="";
  93. /**
  94. * best fitting user agent found in the xml
  95. * @var string
  96. */
  97. var $wurfl_agent="";
  98. /**
  99. * wurfl_id
  100. * @var string
  101. */
  102. var $id="";
  103. /**
  104. * if true, Openwave's GUI (mostly wml 1.3) is supported
  105. * @var bool
  106. */
  107. var $GUI=false;
  108. /**
  109. * device brand (manufacturer)
  110. * @var string
  111. */
  112. var $brand='';
  113. /**
  114. * device model
  115. * @var string
  116. */
  117. var $model='';
  118. /**
  119. * if this is a WAP device, this is set to true
  120. * @var bool
  121. */
  122. var $browser_is_wap=false;
  123. /**
  124. * associative array with all the device's capabilities.
  125. *
  126. * Example :
  127. * $this->capabilities['downloadfun']['downloadfun_support']
  128. * true if downloadfun is supported, otherwise false
  129. *
  130. * @var associative array
  131. */
  132. var $capabilities=array();
  133. /**
  134. * Constructor, checks the user agent and sets the variables.
  135. *
  136. * @param $_ua device's user_agent
  137. * @param $wurfl wurfl in array format as provided by wurfl_parser
  138. * @param $wurfl_agents array set by wurfl_parser
  139. * @param $_check_accept if true will check accept headers for wml, wap, xhtml.
  140. * Note: any i-mode device might be cut out
  141. *
  142. * @access public
  143. *
  144. */
  145. function wurfl_class($wurfl=Array(), $wurfl_agents=Array()) {
  146. $this->_wurfl = $wurfl;
  147. $this->_wurfl_agents = $wurfl_agents;
  148. $this->_toLog('constructor', 'Class Initiated', LOG_NOTICE);
  149. }
  150. /**
  151. * Given the device's id reads all its capabilities
  152. *
  153. * @param $_id wurfl_id di un telefonino
  154. *
  155. * @access private
  156. *
  157. */
  158. function _GetFullCapabilities($_id) {
  159. $this->_toLog('_GetFullCapabilities', "searching for $_id", LOG_INFO);
  160. $$_id = $this->_GetDeviceCapabilitiesFromId($_id);
  161. $_curr_device = $$_id;
  162. $_fallback_list[] = $_id;
  163. while ( $_curr_device['fall_back'] != 'generic' && $_curr_device['fall_back'] != 'root' ) {
  164. $_fallback_list[] = $_curr_device['fall_back'];
  165. $this->_toLog('_GetFullCapabilities', 'parent device:'.$_curr_device['fall_back'].' now going to read its capabilities', LOG_INFO);
  166. $$_curr_device['fall_back'] = $this->_GetDeviceCapabilitiesFromId($_curr_device['fall_back']);
  167. $_curr_device = $$_curr_device['fall_back'];
  168. }
  169. $this->_toLog('_GetFullCapabilities', 'reading capabilities of \'generic\' device', LOG_INFO);
  170. $generic = $this->_GetDeviceCapabilitiesFromId('generic');
  171. $_fallback_list[] = 'generic';
  172. end($_fallback_list);
  173. $_final = $generic;
  174. for ( $i=sizeof($_fallback_list)-2; $i>= 0; $i-- ) {
  175. $curr_device = $_fallback_list[$i];
  176. //echo "capabilities di $curr_device<br>\n";
  177. while ( list($key, $val) = each($$curr_device) ) {
  178. if ( is_array($val) ) {
  179. //echo "array_merge per $key:<br>";
  180. //echo "<pre>\n";
  181. //var_export($_final[$key]);
  182. //var_export($val);
  183. //echo "</pre>\n";
  184. $_final[$key] = array_merge($_final[$key], $val);
  185. } else {
  186. //echo "scrivo $key=$val<br>\n";
  187. $_final[$key] = $val;
  188. }
  189. }
  190. }
  191. $this->capabilities = $_final;
  192. }
  193. /**
  194. * Given a device id reads its capabilities
  195. *
  196. * @param $_id device's wurfl_id
  197. *
  198. * @access private
  199. *
  200. */
  201. function _GetDeviceCapabilitiesFromId($_id) {
  202. $this->_toLog('_GetDeviceCapabilitiesFromId', "reading id:$_id", LOG_INFO);
  203. if ( $_id == 'upgui_generic' ) {
  204. $this->GUI = true;
  205. }
  206. if ( in_array($_id, $this->_wurfl_agents) ) {
  207. $this->_toLog('_GetDeviceCapabilitiesFromId', 'I have it in wurfl_agents cache, done', LOG_INFO);
  208. // If the device for this id does not exist, and we use multicache,
  209. // attempt to load the cache entry that matches the current id.
  210. if ( ! isset( $this->_wurfl['devices'][$_id] ) && WURFL_USE_MULTICACHE ) {
  211. for ($i=0;$i<3;$i++) {
  212. if ( is_file(MULTICACHE_TOUCH) )
  213. sleep(5);
  214. else
  215. break;
  216. }
  217. if ( $i>=3 ) {
  218. $this->_toLog('_GetDeviceCapabilitiesFromId', "CACHE CORRUPTED! ".MULTICACHE_TOUCH." on my way", LOG_WARNING);
  219. error_log("WURFL: Updating cache stuck");
  220. return;
  221. }
  222. $fname = MULTICACHE_DIR . "/" . urlencode( $_id ) . MULTICACHE_SUFFIX;
  223. $genericfname = MULTICACHE_DIR . "/generic" . MULTICACHE_SUFFIX;
  224. if ( !is_file($fname) && is_file($genericfname) ) {
  225. $this->_toLog('_GetDeviceCapabilitiesFromId', "the id $_id is not present in Multicache files, using the generic: CACHE CORRUPTED!", LOG_WARNING);
  226. $fname = $genericfname;
  227. } else if ( !is_file($fname) && !is_file($genericfname) ) {
  228. $this->_toLog('_GetDeviceCapabilitiesFromId', "the id $_id is not present in Multicache files, nor the generic: CACHE CORRUPTED!", LOG_ERR);
  229. error_log("WURFL: the id $_id is not present in Multicache");
  230. return;
  231. }
  232. @include( $fname );
  233. $this->_wurfl['devices'][$_id] = $_cached_devices[$_id];
  234. }
  235. return $this->_wurfl['devices'][$_id];
  236. }
  237. $this->_toLog('_GetDeviceCapabilitiesFromId', "the id $_id is not present in wurfl_agents", LOG_ERR);
  238. error_log("WURFL: the id $_id is not present in wurfl_agents");
  239. return;
  240. // I should never get here!!
  241. return false;
  242. }
  243. /**
  244. * Given the user_agent reads the device's capabilities
  245. *
  246. * @param $_user_agent device's user_agent
  247. *
  248. * @access private
  249. *
  250. * @return boolean
  251. *
  252. */
  253. function GetDeviceCapabilitiesFromAgent($_user_agent, $_check_accept=false) {
  254. // Would be cool to log user agent and headers to future use to feed WURFL
  255. // Resetting properties
  256. $this->user_agent = '';
  257. $this->wurfl_agent = '';
  258. $this->id = '';
  259. $this->GUI = false;
  260. $this->brand = '';
  261. $this->model = '';
  262. $this->browser_is_wap = false;
  263. $this->capabilities = array();
  264. // removing the possible Openwave MAG tag
  265. $_user_agent = trim(ereg_replace("UP.Link.*", "", $_user_agent));
  266. /* This is being remove because too many devices use Mozilla, MSIE and so on as strings in the UA
  267. Use the web_browser_patch.xml if you want to catch web browsers
  268. if ( ( stristr($_user_agent, 'Opera') && stristr($_user_agent, 'Windows') )
  269. || ( stristr($_user_agent, 'Opera') && stristr($_user_agent, 'Linux') )
  270. || stristr($_user_agent, 'Gecko')
  271. || ( (stristr($_user_agent, 'MSIE 6') || stristr($_user_agent, 'MSIE 5') ) && !stristr($_user_agent, 'MIDP') && !stristr($_user_agent, 'Windows CE') && !stristr($_user_agent, 'Symbian') )
  272. ) {
  273. // This is a web browser. Not even searching
  274. $this->_toLog('constructor', 'Web browser', LOG_INFO);
  275. $this->browser_is_wap=false;
  276. $this->capabilities['product_info']['brand_name'] = 'Generic Web browser';
  277. $this->capabilities['product_info']['model_name'] = '1.0';
  278. $this->capabilities['product_info']['is_wireless_device'] = false;
  279. $this->capabilities['product_info']['device_claims_web_support'] = true;
  280. return true;
  281. } else if ( $_check_accept == true ) {
  282. */
  283. if ( $_check_accept == true ) {
  284. if (
  285. !eregi('wml', $_SERVER['HTTP_ACCEPT'])
  286. && !eregi('wap', $_SERVER['HTTP_ACCEPT'])
  287. && !eregi('xhtml', $_SERVER['HTTP_ACCEPT'])
  288. ) {
  289. $this->_toLog('constructor', 'This browser does not support wml, nor wap, nor xhtml, we will never know if it was an i-mode browser', LOG_WARNING);
  290. $this->browser_is_wap=false;
  291. }
  292. }
  293. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'searching for '.$_user_agent, LOG_INFO);
  294. if ( trim($_user_agent) == '' || !$_user_agent ) {
  295. // NO USER AGENT??? This is not a WAP device
  296. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'No user agent', LOG_ERR);
  297. $this->browser_is_wap=false;
  298. return false;
  299. }
  300. if ( WURFL_USE_CACHE === true ) {
  301. $this->_ReadFastAgentToId($_user_agent);
  302. // if I find the device in my cache I'm done
  303. if ( $this->browser_is_wap === true ) {
  304. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'Device found in local cache, the id is '.$this->id, LOG_INFO);
  305. if ( count($this->capabilities) == 0 )
  306. $this->_GetFullCapabilities($this->id);
  307. else
  308. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'capabilities found in cache', LOG_INFO);
  309. return true;
  310. } else if ( count($this->_wurfl) == 0 ) {
  311. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'cache enabled, WURFL is not loaded, now loading', LOG_INFO);
  312. if ( $this->_cacheIsValid() ) {
  313. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'loading WURFL from cache', LOG_INFO);
  314. list($cache_stat, $this->_wurfl, $this->_wurfl_agents) = load_cache();
  315. } else {
  316. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'loading WURFL from XML', LOG_INFO);
  317. $xml_info = parse();
  318. $cache_stat = $xml_info[0];
  319. $this->_wurfl = $xml_info[1];
  320. $this->_wurfl_agents = $xml_info[2];
  321. }
  322. }
  323. } else if ( WURFL_AUTOLOAD === false ) {
  324. // if not using cache and for some reason AUTOLOAD is off, I need to load it
  325. if ( count($this->_wurfl) == 0 ) {
  326. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'WURFL is not loaded, now loading', LOG_INFO);
  327. $xml_info = parse();
  328. $cache_stat = $xml_info[0];
  329. $this->_wurfl = $xml_info[1];
  330. $this->_wurfl_agents = $xml_info[2];
  331. }
  332. } else {
  333. // If I'm here it means cache is disabled and autoload is on
  334. global $wurfl, $wurfl_agents;
  335. $this->_wurfl = $wurfl;
  336. $this->_wurfl_agents = $wurfl_agents;
  337. }
  338. $_ua = $_user_agent;
  339. $_ua_len = strlen($_ua);
  340. $_wurfl_user_agents = array_keys($this->_wurfl_agents);
  341. // Searching in wurfl_agents
  342. // The user_agent should not become shorter than 4 characters
  343. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'Searching in the agent database for '.$_ua, LOG_INFO);
  344. // Search for an exact match first
  345. if ( in_array($_ua, $_wurfl_user_agents) ) {
  346. $this->user_agent = $_ua;
  347. $this->wurfl_agent = $_ua;
  348. $this->id = $this->_wurfl_agents[$_ua];
  349. // calling FullCapabilities to define $this->capabilities
  350. $this->_GetFullCapabilities($this->id);
  351. $this->browser_is_wap = $this->capabilities['product_info']['is_wireless_device'];
  352. $this->brand = $this->capabilities['product_info']['brand_name'];
  353. $this->model = $this->capabilities['product_info']['model_name'];
  354. reset($this->_wurfl_agents);
  355. reset($_wurfl_user_agents);
  356. if ( WURFL_USE_CACHE ) {
  357. $this->_WriteFastAgentToId();
  358. }
  359. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'I found an exact match for '.$_ua.' with id '.$this->id, LOG_INFO);
  360. return true;
  361. }
  362. // I request to set a short list of UA's among which I should search an unknown user agent
  363. $_short_ua_len = 4;
  364. $_set_short_wurfl_ua = true;
  365. $_last_good_short_ua = array();
  366. while ( $_ua_len > 4 ) {
  367. $_short_wurfl_ua = array();
  368. $_tmp_short_ua = substr($_ua, 0, $_short_ua_len); // The current user agent's first chars
  369. // DEBUG fast search echo "_tmp_short_ua=$_tmp_short_ua ";
  370. foreach ( $_wurfl_user_agents as $_x ) {
  371. // If it was requested to generate a short list of user agents AND the first
  372. // characters of the searched user agent and the user agent in WURFL match,
  373. // I add the current ID to the short list
  374. if ( $_set_short_wurfl_ua === true && substr($_x, 0, $_short_ua_len) == $_tmp_short_ua )
  375. $_short_wurfl_ua[] = $_x;
  376. if ( substr($_x, 0, $_ua_len) == $_ua ) {
  377. $this->user_agent = $_user_agent;
  378. $this->wurfl_agent = $_x;
  379. $this->id = $this->_wurfl_agents[$_x];
  380. // calling FullCapabilities to define $this->capabilities
  381. $this->_GetFullCapabilities($this->id);
  382. $this->browser_is_wap = $this->capabilities['product_info']['is_wireless_device'];
  383. $this->brand = $this->capabilities['product_info']['brand_name'];
  384. $this->model = $this->capabilities['product_info']['model_name'];
  385. reset($this->_wurfl_agents);
  386. reset($_wurfl_user_agents);
  387. if ( WURFL_USE_CACHE ) {
  388. $this->_WriteFastAgentToId();
  389. }
  390. return true;
  391. }
  392. }
  393. // If the list of user agents that match the first 4 chars of the current user
  394. // agent is empty I can quit searching
  395. if ( $_short_ua_len == 4 && count($_short_wurfl_ua) == 0 ) {
  396. // DEBUG fast search echo "no match even for the first 4 chars<br>\n";
  397. break;
  398. } else if ( count($_short_wurfl_ua) == 0 ) {
  399. // I restore the last good list of short user agents
  400. $_wurfl_user_agents = $_last_good_short_ua;
  401. // DEBUG fast search echo "restoring last_good_short_ua";
  402. // I won't continue building a new short user agent list (longer
  403. // than this)
  404. $_set_short_wurfl_ua = false;
  405. } else {
  406. // This is the last list of user agents that matched the first part of
  407. // the agent
  408. $_last_good_short_ua = $_short_wurfl_ua;
  409. // Next round I search for a short_ua 1 char longer
  410. $_short_ua_len++;
  411. // I will search the user agent among a shorter list at the next round!!
  412. $_wurfl_user_agents = $_short_wurfl_ua;
  413. // DEBUG fast search echo "short list has ".count($_short_wurfl_ua)." elements";
  414. }
  415. // shortening the agent by one each time
  416. $_ua = substr($_ua, 0, -1);
  417. $_ua_len--;
  418. reset($_wurfl_user_agents);
  419. // DEBUG fast search echo "<br>\n";
  420. }
  421. $this->_toLog('GetDeviceCapabilitiesFromAgent', "I couldn't find the device in my list, the headers are my last chance", LOG_WARNING);
  422. if ( strstr($_user_agent, 'UP.Browser/') && strstr($_user_agent, '(GUI)') ) {
  423. $this->browser_is_wap = true;
  424. $this->user_agent = $_user_agent;
  425. $this->wurfl_agent = 'upgui_generic';
  426. $this->id = 'upgui_generic';
  427. } else if ( strstr($_user_agent, 'UP.Browser/') ) {
  428. $this->browser_is_wap = true;
  429. $this->user_agent = $_user_agent;
  430. $this->wurfl_agent = 'uptext_generic';
  431. $this->id = 'uptext_generic';
  432. } else if ( isset( $_SERVER['HTTP_ACCEPT'] ) && (eregi('wml', $_SERVER['HTTP_ACCEPT']) || eregi('wap', $_SERVER['HTTP_ACCEPT'])) ) {
  433. $this->browser_is_wap = true;
  434. $this->user_agent = $_user_agent;
  435. $this->wurfl_agent = 'generic';
  436. $this->id = 'generic';
  437. } else {
  438. $this->_toLog('GetDeviceCapabilitiesFromAgent', 'This should not be a WAP device, quitting', LOG_WARNING);
  439. $this->browser_is_wap=false;
  440. $this->user_agent = $_user_agent;
  441. $this->wurfl_agent = 'generic';
  442. $this->id = 'generic';
  443. return true;
  444. }
  445. if ( WURFL_USE_CACHE ) {
  446. $this->_WriteFastAgentToId($_user_agent);
  447. }
  448. // FullCapabilities defines $this->capabilities
  449. $this->_GetFullCapabilities($this->id);
  450. return true;
  451. }
  452. /**
  453. * Given a capability name returns the value (true|false|<anythingelse>)
  454. *
  455. * @param $capability capability name as a string
  456. *
  457. * @access public
  458. *
  459. */
  460. function getDeviceCapability($capability) {
  461. $this->_toLog('_GetDeviceCapability', 'Searching for '.$capability.' as a capability', LOG_INFO);
  462. $deviceCapabilities = $this->capabilities;
  463. foreach ( $deviceCapabilities as $group ) {
  464. if ( !is_array($group) ) {
  465. continue;
  466. }
  467. while ( list($key, $value)=each($group) ) {
  468. if ($key==$capability) {
  469. $this->_toLog('_GetDeviceCapability', 'I found it, value is '.$value, LOG_INFO);
  470. return $value;
  471. }
  472. }
  473. }
  474. $this->_toLog('_GetDeviceCapability', 'I could not find the requested capability, returning false', LOG_WARNING);
  475. return false;
  476. }
  477. /**
  478. * Saves to file the correspondence between user_agent and wurfl_id
  479. *
  480. * @access private
  481. *
  482. */
  483. function _WriteFastAgentToId() {
  484. $_ua = $this->user_agent;
  485. if ( is_file(WURFL_AGENT2ID_FILE) && !is_writeable(WURFL_AGENT2ID_FILE) ) {
  486. $this->_toLog('_WriteFastAgentToId', 'Unable to write '.WURFL_AGENT2ID_FILE, LOG_ERR);
  487. return;
  488. } else if ( !is_writeable(dirname(WURFL_AGENT2ID_FILE)) ) {
  489. $this->_toLog('_WriteFastAgentToId', 'Unable to create file in '.dirname(WURFL_AGENT2ID_FILE), LOG_ERR);
  490. return;
  491. }
  492. $_ua = trim(ereg_replace("UP.Link.*", "", $_ua));
  493. if ( !is_readable(WURFL_AGENT2ID_FILE) ) {
  494. if ( is_file(WURFL_AGENT2ID_FILE) ) {
  495. $this->_toLog('_WriteFastAgentToId', 'Unable to read '.WURFL_AGENT2ID_FILE, LOG_WARNING);
  496. }
  497. $cached_agents = Array();
  498. } else {
  499. // $cached_agents[0]['user_agent'] = 'SIE-S45/00'; //ua completo
  500. // $cached_agents[0]['wurfl_agent'] = 'SIE-S45/00'; //ua nel WURFL
  501. // $cached_agents[0]['id'] = 'sie_s45_ver1';
  502. // $cached_agents[0]['is_wap'] = true;
  503. include(WURFL_AGENT2ID_FILE);
  504. }
  505. // check if the device is already cached
  506. foreach($cached_agents as $one) {
  507. if ( $one['user_agent'] == $_ua ) {
  508. $this->_toLog('_WriteFastAgentToId', $_ua.' is already cached', LOG_INFO);
  509. return;
  510. }
  511. }
  512. $new_item_id = count($cached_agents);
  513. $cached_agents[$new_item_id]['user_agent'] = $_ua; // full UA
  514. // $cached_agents[$new_item_id]['wurfl_agent'] = $this->wurfl_agent; // corresponding UA stored in WURFL
  515. // $cached_agents[$new_item_id]['id'] = $this->id; // WURFL unique id
  516. $cached_agents[$new_item_id]['is_wap'] = true;
  517. $cached_agents[$new_item_id]['capabilities'] = $this->capabilities;
  518. $new_item_id++; // increment by one so that it still reflects the array count
  519. // cache resize in case it gets bigger than MAX_UA_CACHE
  520. if ( $new_item_id > MAX_UA_CACHE ) {
  521. $resized_agents = array_slice($cached_agents, ($new_item_id-MAX_UA_CACHE), MAX_UA_CACHE);
  522. $cached_agents = $resized_agents;
  523. $this->_toLog('_WriteFastAgentToId', 'Cache resized to '.MAX_UA_CACHE.' elements', LOG_INFO);
  524. }
  525. // store in cache file
  526. $filename = uniqid(WURFL_AGENT2ID_FILE, true);
  527. $fp_cache = fopen($filename, 'w');
  528. if ( !$fp_cache ) {
  529. $this->_toLog('_WriteFastAgentToId', 'Unable to open temp file '.$filename.' for writing', LOG_WARNING);
  530. return;
  531. } else {
  532. $this->_toLog('_WriteFastAgentToId', 'Created temp file '.$filename.' ', LOG_INFO);
  533. }
  534. fwrite($fp_cache, "<?php \n");
  535. fwrite($fp_cache, '$cached_agents = '.var_export($cached_agents, true));
  536. // If you like serialization better comment the above line, uncomment
  537. // the following and the line in _ReadFastAgentToId
  538. //fwrite($fp_cache, '$cached_agents = \''.rawurlencode(serialize($cached_agents))."';\n");
  539. fwrite($fp_cache, "?>");
  540. fclose($fp_cache);
  541. $rv = @rename($filename,WURFL_AGENT2ID_FILE);
  542. /*
  543. if( !$rv ){
  544. $this->_toLog('_WriteFastAgentToId', 'Unable to rename '.$filename.' to '. WURFL_AGENT2ID_FILE, LOG_WARNING);
  545. return;
  546. }
  547. */
  548. if( !$rv ){
  549. $this->_toLog('_WriteFastAgentToId', 'Unable to rename '.$filename.' to '. WURFL_AGENT2ID_FILE, LOG_WARNING);
  550. $unl = @unlink(WURFL_AGENT2ID_FILE);
  551. if (!$unl)
  552. $this->_toLog('_WriteFastAgentToId', 'Unable to delete '. WURFL_AGENT2ID_FILE, LOG_WARNING);
  553. $rv = @rename($filename,WURFL_AGENT2ID_FILE);
  554. if ( !$rv )
  555. $this->_toLog('_WriteFastAgentToId', 'Still unable to rename '.$filename.' to '. WURFL_AGENT2ID_FILE, LOG_WARNING);
  556. return;
  557. }
  558. $this->_toLog('_WriteFastAgentToId', 'Done caching user_agent to wurfl_id', LOG_INFO);
  559. return;
  560. }
  561. /**
  562. * Reads the file with the correspondence between user_agent and wurfl_id
  563. *
  564. * @param $_ua device's user_agent
  565. *
  566. * @access private
  567. *
  568. */
  569. function _ReadFastAgentToId($_ua) {
  570. // check cache validity
  571. if ( !$this->_cacheIsValid() ) {
  572. return false;
  573. }
  574. // Load cache file
  575. if ( is_file(WURFL_AGENT2ID_FILE) || is_link(WURFL_AGENT2ID_FILE) ) {
  576. include(WURFL_AGENT2ID_FILE);
  577. // unserialization
  578. //$a = unserialize(rawurldecode($cache_agents));
  579. } else {
  580. return false;
  581. }
  582. foreach ( $cached_agents as $device ) {
  583. if ( $device['user_agent'] == $_ua ) {
  584. $this->user_agent = $device['user_agent'];
  585. $this->wurfl_agent = $device['capabilities']['user_agent'];
  586. $this->id = $device['capabilities']['id'];
  587. $this->browser_is_wap = $device['is_wap'];
  588. $this->capabilities = $device['capabilities'];
  589. $this->brand = $device['capabilities']['product_info']['brand_name'];
  590. $this->model = $device['capabilities']['product_info']['model_name'];
  591. $this->_toLog('_ReadFastAgentToId', 'Found '.$_ua.' with id='.$device['capabilities']['id'], LOG_INFO);
  592. break;
  593. }
  594. }
  595. return true;
  596. }
  597. /**
  598. * Check filemtimes to see if the cache should be updated
  599. *
  600. * @access private
  601. *
  602. */
  603. function _cacheIsValid() {
  604. // First of all check configuration. If autoupdate is set to false always
  605. // return true, otherwise check
  606. if ( WURFL_CACHE_AUTOUPDATE === false )
  607. return true;
  608. // WURFL hasn't been loaded into memory, I'll do it now
  609. $wurfl_stat = filemtime(WURFL_FILE);
  610. if ( defined('WURFL_PATCH_FILE') && file_exists(WURFL_PATCH_FILE) ) {
  611. $patch_stat = filemtime(WURFL_PATCH_FILE);
  612. if ( $patch_stat > $wurfl_stat ) {
  613. // if the patch file is newer than the WURFL I set wurfl_stat to that time
  614. $wurfl_stat = $patch_stat;
  615. }
  616. }
  617. $cache_stat = stat_cache();
  618. if ( $wurfl_stat <= $cache_stat ) {
  619. return true;
  620. } else {
  621. $this->_toLog('_cacheIsValid', 'cache file is outdated', LOG_INFO);
  622. return false;
  623. }
  624. }
  625. /**
  626. * This function checks and prepares the text to be logged
  627. *
  628. * @access private
  629. */
  630. function _toLog($func, $text, $requestedLogLevel=LOG_NOTICE){
  631. if ( !defined('LOG_LEVEL') || LOG_LEVEL == 0 || ($requestedLogLevel-1) >= LOG_LEVEL ) {
  632. return;
  633. }
  634. if ( $requestedLogLevel == LOG_ERR ) {
  635. $warn_banner = 'ERROR: ';
  636. } else if ( $requestedLogLevel == LOG_WARNING ) {
  637. $warn_banner = 'WARNING: ';
  638. } else {
  639. $warn_banner = '';
  640. }
  641. // Thanks laacz
  642. $_textToLog = date('r')." [".php_uname('n')." ".getmypid()."]"."[$func] ".$warn_banner . $text;
  643. $_logFP = fopen(WURFL_LOG_FILE, "a+");
  644. fputs($_logFP, $_textToLog."\n");
  645. fclose($_logFP);
  646. return;
  647. }
  648. }
  649. ?>