Skip to content

Commit

Permalink
Initial import and cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
Synchro committed Nov 22, 2012
1 parent 849fa51 commit 4b0782b
Show file tree
Hide file tree
Showing 4 changed files with 1,050 additions and 1 deletion.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
UASparser
=========

User Agent String parser for PHP from user-agent-string.info
A User Agent String parser for PHP

This is a parser for the user agent strings presented by HTTP clients of various flavours. This code is based on the libraries available from http://user-agent-string.info

Licensed under the LGPL, see license.txt for details.

This version amended by by Marcus Bointon removes the view source option for security, cleans up phpdocs and code formatting (to PSR-2 style), fixes poor code in the example script.
365 changes: 365 additions & 0 deletions UASparser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,365 @@
<?php
/**
* PHP version 5
*
* @package UASparser
* @author Jaroslav Mallat (http://mallat.cz/)
* @copyright Copyright (c) 2008 Jaroslav Mallat
* @copyright Copyright (c) 2010 Alex Stanev (http://stanev.org)
* @copyright Copyright (c) 2012 Martin van Wingerden (http://www.copernica.com)
* @version 0.51
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
* @link http://user-agent-string.info/download/UASparser
*/

class UASparser
{
/**
* @var integer How often to update UAS database
*/
public $updateInterval = 86400; // 1 day

private static $_ini_url = 'http://user-agent-string.info/rpc/get_data.php?key=free&format=ini';
private static $_ver_url = 'http://user-agent-string.info/rpc/get_data.php?key=free&format=ini&ver=y';
private static $_md5_url = 'http://user-agent-string.info/rpc/get_data.php?format=ini&md5=y';
private static $_info_url = 'http://user-agent-string.info';
private $_cache_dir = null;
private $_data = null;

/**
* Constructor with an optional cache directory
* @param string $cacheDirectory
* @param integer $updateInterval
* @internal param \cache $string directory to be used by this instance
*/
public function __construct($cacheDirectory = null, $updateInterval = null)
{
if ($cacheDirectory) {
$this->SetCacheDir($cacheDirectory);
}
if ($updateInterval) {
$this->updateInterval = $updateInterval;
}
}

/**
* Parse the useragent string if given otherwise parse the current user agent
* @param string $useragent user agent string
* @return array
*/
public function Parse($useragent = null)
{
// intialize some variables
$browser_id = $os_id = null;
$result = array();

// initialize the return value
$result['typ'] = 'unknown';
$result['ua_family'] = 'unknown';
$result['ua_name'] = 'unknown';
$result['ua_version'] = 'unknown';
$result['ua_url'] = 'unknown';
$result['ua_company'] = 'unknown';
$result['ua_company_url'] = 'unknown';
$result['ua_icon'] = 'unknown.png';
$result["ua_info_url"] = 'unknown';
$result["os_family"] = 'unknown';
$result["os_name"] = 'unknown';
$result["os_url"] = 'unknown';
$result["os_company"] = 'unknown';
$result["os_company_url"] = 'unknown';
$result["os_icon"] = 'unknown.png';

// if no user agent is supplied process the one from the server vars
if (!isset($useragent) && isset($_SERVER['HTTP_USER_AGENT'])) {
$useragent = $_SERVER['HTTP_USER_AGENT'];
}

// if we haven't loaded the data yet, do it now
if (!$this->_data) {
$this->_data = $this->_loadData();
}

// we have no data or no valid user agent, just return the default data
if (!$this->_data || !isset($useragent)) {
return $result;
}

// crawler
foreach ($this->_data['robots'] as $test) {
if ($test[0] == $useragent) {
$result['typ'] = 'Robot';
if ($test[1]) {
$result['ua_family'] = $test[1];
}
if ($test[2]) {
$result['ua_name'] = $test[2];
}
if ($test[3]) {
$result['ua_url'] = $test[3];
}
if ($test[4]) {
$result['ua_company'] = $test[4];
}
if ($test[5]) {
$result['ua_company_url'] = $test[5];
}
if ($test[6]) {
$result['ua_icon'] = $test[6];
}
if ($test[7]) { // OS set
$os_data = $this->_data['os'][$test[7]];
if ($os_data[0]) {
$result['os_family'] = $os_data[0];
}
if ($os_data[1]) {
$result['os_name'] = $os_data[1];
}
if ($os_data[2]) {
$result['os_url'] = $os_data[2];
}
if ($os_data[3]) {
$result['os_company'] = $os_data[3];
}
if ($os_data[4]) {
$result['os_company_url'] = $os_data[4];
}
if ($os_data[5]) {
$result['os_icon'] = $os_data[5];
}
}
if ($test[8]) {
$result['ua_info_url'] = self::$_info_url . $test[8];
}
return $result;
}
}

// find a browser based on the regex
foreach ($this->_data['browser_reg'] as $test) {
if (@preg_match($test[0], $useragent, $info)) { // $info may contain version
$browser_id = $test[1];
break;
}
}

// a valid browser was found
if ($browser_id) { // browser detail
$browser_data = $this->_data['browser'][$browser_id];
if ($this->_data['browser_type'][$browser_data[0]][0]) {
$result['typ'] = $this->_data['browser_type'][$browser_data[0]][0];
}
if (isset($info[1])) {
$result['ua_version'] = $info[1];
}
if ($browser_data[1]) {
$result['ua_family'] = $browser_data[1];
}
if ($browser_data[1]) {
$result['ua_name'] = $browser_data[1] . (isset($info[1]) ? ' ' . $info[1] : '');
}
if ($browser_data[2]) {
$result['ua_url'] = $browser_data[2];
}
if ($browser_data[3]) {
$result['ua_company'] = $browser_data[3];
}
if ($browser_data[4]) {
$result['ua_company_url'] = $browser_data[4];
}
if ($browser_data[5]) {
$result['ua_icon'] = $browser_data[5];
}
if ($browser_data[6]) {
$result['ua_info_url'] = self::$_info_url . $browser_data[6];
}
}

// browser OS, does this browser match contain a reference to an os?
if (isset($this->_data['browser_os'][$browser_id])) { // os detail
$os_id = $this->_data['browser_os'][$browser_id][0]; // Get the os id
$os_data = $this->_data['os'][$os_id];
if ($os_data[0]) {
$result['os_family'] = $os_data[0];
}
if ($os_data[1]) {
$result['os_name'] = $os_data[1];
}
if ($os_data[2]) {
$result['os_url'] = $os_data[2];
}
if ($os_data[3]) {
$result['os_company'] = $os_data[3];
}
if ($os_data[4]) {
$result['os_company_url'] = $os_data[4];
}
if ($os_data[5]) {
$result['os_icon'] = $os_data[5];
}
return $result;
}

// search for the os
foreach ($this->_data['os_reg'] as $test) {
if (@preg_match($test[0], $useragent)) {
$os_id = $test[1];
break;
}
}

// a valid os was found
if ($os_id) { // os detail
$os_data = $this->_data['os'][$os_id];
if ($os_data[0]) {
$result['os_family'] = $os_data[0];
}
if ($os_data[1]) {
$result['os_name'] = $os_data[1];
}
if ($os_data[2]) {
$result['os_url'] = $os_data[2];
}
if ($os_data[3]) {
$result['os_company'] = $os_data[3];
}
if ($os_data[4]) {
$result['os_company_url'] = $os_data[4];
}
if ($os_data[5]) {
$result['os_icon'] = $os_data[5];
}
}
return $result;
}

/**
* Load the data from the files
* @return boolean
*/
private function _loadData()
{
if (!file_exists($this->_cache_dir)) {
return false;
}

if (file_exists($this->_cache_dir . '/cache.ini')) {
$cacheIni = parse_ini_file($this->_cache_dir . '/cache.ini');

// should we reload the data because it is already old?
if ($cacheIni['lastupdate'] < time() - $this->updateInterval || $cacheIni['lastupdatestatus'] != '0') {
$this->_downloadData();
}
} else {
$this->_downloadData();
}

// we have file with data, parse and return it
if (file_exists($this->_cache_dir . '/uasdata.ini')) {
return @parse_ini_file($this->_cache_dir . '/uasdata.ini', true);
} else {
trigger_error('ERROR: No datafile (uasdata.ini in Cache Dir), maybe update the file manually.');
}
return false;
}

/**
* Download the data
*/
private function _downloadData()
{
// support for at least on of the two is needed
if (!ini_get('allow_url_fopen') && !function_exists('curl_init')) {
trigger_error(
'ERROR: function file_get_contents not allowed URL open. Update the datafile (uasdata.ini in Cache Dir) manually.'
);
return;
}

// by default status is failed
$status = 1;
$cacheIni = array();
if (file_exists($this->_cache_dir . '/cache.ini')) {
$cacheIni = parse_ini_file($this->_cache_dir . '/cache.ini');
}

// Get the version for the server
$ver = $this->get_contents(self::$_ver_url);
if (strlen($ver) != 11) {
if ($cacheIni['localversion']) {
$ver = $cacheIni['localversion'];
} else {
$ver = 'none';
}
}

// Download the ini file
if ($ini = $this->get_contents(self::$_ini_url)) {
// download the has file
$md5hash = $this->get_contents(self::$_md5_url);
// validate the hash, if okay store the new ini file
if (md5($ini) == $md5hash) {
@file_put_contents($this->_cache_dir . '/uasdata.ini', $ini);
$status = 0;
}
}

// build a new cache file and store it
$cacheIni = "; cache info for class UASparser - http://user-agent-string.info/download/UASparser\n";
$cacheIni .= "[main]\n";
$cacheIni .= "localversion = \"$ver\"\n";
$cacheIni .= 'lastupdate = "' . time() . "\"\n";
$cacheIni .= "lastupdatestatus = \"$status\"\n";
@file_put_contents($this->_cache_dir . '/cache.ini', $cacheIni);
}

/**
* Get the content of a certain url with a defined timeout
* @param string $url
* @param int|string $timeout
* @return string
*/
private function get_contents($url, $timeout = 5)
{
// use file_get_contents
if (ini_get('allow_url_fopen')) {
$ctx = stream_context_create(array('http' => array('timeout' => $timeout)));
return file_get_contents($url, false, $ctx);
} // fall back to curl
elseif (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}

// no options left
return '';
}

/**
* Set the cache directory
* @param string
*/
public function SetCacheDir($cache_dir)
{

// The directory does not exist at this moment, try to make it
if (!file_exists($cache_dir)) {
@mkdir($cache_dir, 0777, true);
}

// perform some extra checks
if (!is_writable($cache_dir) || !is_dir($cache_dir)) {
trigger_error('ERROR: Cache dir(' . $cache_dir . ') is not a directory or not writable');
return;
}

// store the cache dir
$cache_dir = realpath($cache_dir);
$this->_cache_dir = $cache_dir;
}
}
Loading

0 comments on commit 4b0782b

Please sign in to comment.