mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API CHANGE Moved "statistics" functionality into separate module, which is not distributed with a default silverstripe installation. see r52168
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@52163 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
bcbadd3670
commit
a42b76bc73
@ -82,9 +82,6 @@ class ContentController extends Controller {
|
|||||||
public function init() {
|
public function init() {
|
||||||
parent::init();
|
parent::init();
|
||||||
|
|
||||||
//Log page views
|
|
||||||
Statistics::collect();
|
|
||||||
|
|
||||||
// If we've accessed the homepage as /home/, then we should redirect to /.
|
// If we've accessed the homepage as /home/, then we should redirect to /.
|
||||||
if($this->dataRecord && $this->dataRecord instanceof SiteTree && RootURLController::should_be_on_root($this->dataRecord) && !$this->urlParams['Action'] && !$_POST && !$_FILES) {
|
if($this->dataRecord && $this->dataRecord instanceof SiteTree && RootURLController::should_be_on_root($this->dataRecord) && !$this->urlParams['Action'] && !$_POST && !$_FILES) {
|
||||||
$getVars = $_GET;
|
$getVars = $_GET;
|
||||||
|
@ -1,108 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @package cms
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data object that logs statistics for any page view in the system.
|
|
||||||
*
|
|
||||||
* Inbound links from external websites are distinquished by a 'true'
|
|
||||||
* value in the FromExternal field.
|
|
||||||
*
|
|
||||||
* The referring urls are recorded in the Referrer field.
|
|
||||||
*
|
|
||||||
* Information about the users browser version and operating system is also recorded.
|
|
||||||
*
|
|
||||||
* @package cms
|
|
||||||
*/
|
|
||||||
class PageView extends DataObject {
|
|
||||||
|
|
||||||
static $db = array(
|
|
||||||
"IP" => "Varchar(255)",
|
|
||||||
"Browser" => "Varchar(255)",
|
|
||||||
"BrowserVersion" => "Decimal",
|
|
||||||
"FromExternal" => "Boolean",
|
|
||||||
"Referrer" => "Varchar(255)",
|
|
||||||
"SearchEngine" => "Boolean",
|
|
||||||
"Keywords" => "Varchar(255)",
|
|
||||||
"OS" => "Varchar(255)"
|
|
||||||
);
|
|
||||||
|
|
||||||
static $has_one = array(
|
|
||||||
"Page" => "SiteTree",
|
|
||||||
"User" => "Member"
|
|
||||||
);
|
|
||||||
|
|
||||||
static $has_many = array();
|
|
||||||
|
|
||||||
static $many_many = array();
|
|
||||||
|
|
||||||
static $belongs_many_many = array();
|
|
||||||
|
|
||||||
static $defaults = array();
|
|
||||||
|
|
||||||
protected $hitdata = null;
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
$browscap = new Browscap();
|
|
||||||
$this->hitdata = $browscap->getBrowser(null, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* gathers data for this page view and writes
|
|
||||||
* it to the data source.
|
|
||||||
*/
|
|
||||||
function record() {
|
|
||||||
$this->init();
|
|
||||||
$this->recordBrowser();
|
|
||||||
$this->recordOS();
|
|
||||||
$this->recordUserID();
|
|
||||||
$this->recordPageID();
|
|
||||||
$this->recordIP();
|
|
||||||
$this->recordFromExternal();
|
|
||||||
$this->recordReferrer();
|
|
||||||
$this->write(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordFromExternal() {
|
|
||||||
$http_host = "http://".$_SERVER['HTTP_HOST'];
|
|
||||||
if (isset($_SERVER['HTTP_REFERER']) && !strstr($_SERVER['HTTP_REFERER'], $http_host) && $_SERVER['HTTP_REFERER'] != null)
|
|
||||||
$this->FromExternal = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordBrowser() {
|
|
||||||
if (isset($this->hitdata['Browser']))
|
|
||||||
$this->Browser = $this->hitdata['Browser'];
|
|
||||||
|
|
||||||
if (isset($this->hitdata['Version']))
|
|
||||||
$this->BrowserVersion = $this->hitdata['Version'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordReferrer() {
|
|
||||||
if(isset($_SERVER['HTTP_REFERER'])) $this->Referrer = $_SERVER['HTTP_REFERER'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordOS() {
|
|
||||||
if(isset($this->hitdata['Platform']))
|
|
||||||
$this->OS = $this->hitdata['Platform'];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordUserID() {
|
|
||||||
$isLogged = Session::get('loggedInAs');
|
|
||||||
$id = ($isLogged) ? $isLogged : -1;
|
|
||||||
$this->UserID = $id;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordPageID() {
|
|
||||||
$currentPage = Director::currentPage();
|
|
||||||
if ($currentPage) $this->PageID = $currentPage->ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recordIP() {
|
|
||||||
$this->IP = (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
|
|
||||||
? $_SERVER['HTTP_X_FORWARDED_FOR'] : $_SERVER['REMOTE_ADDR'];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
@ -364,22 +364,6 @@ $lang['en_US']['TreeSelectorField']['CANCEL'] = 'cancel';
|
|||||||
$lang['en_US']['TypeDropdown']['NONE'] = 'None';
|
$lang['en_US']['TypeDropdown']['NONE'] = 'None';
|
||||||
$lang['en_US']['FieldEditor']['EMAILSUBMISSION'] = 'Email submission to:';
|
$lang['en_US']['FieldEditor']['EMAILSUBMISSION'] = 'Email submission to:';
|
||||||
$lang['en_US']['FieldEditor']['EMAILONSUBMIT'] = 'Email form on submit:';
|
$lang['en_US']['FieldEditor']['EMAILONSUBMIT'] = 'Email form on submit:';
|
||||||
$lang['en_US']['Statistics']['TRENDS'] = 'Trends';
|
|
||||||
$lang['en_US']['Statistics']['LEGEND'] = 'Legend';
|
|
||||||
$lang['en_US']['Statistics']['REGISTEREDUSERS'] = 'Registered Users';
|
|
||||||
$lang['en_US']['Statistics']['CSVEXPORT'] = 'Export as CSV';
|
|
||||||
$lang['en_US']['Statistics']['ID'] = 'ID';
|
|
||||||
$lang['en_US']['Statistics']['EMAIL'] = 'Email';
|
|
||||||
$lang['en_US']['Statistics']['RECENTPAGEVIEWS'] = 'Recent Page Views';
|
|
||||||
$lang['en_US']['Statistics']['TIME'] = 'Time';
|
|
||||||
$lang['en_US']['Statistics']['BROWSER'] = 'Browser';
|
|
||||||
$lang['en_US']['Statistics']['OSABREV'] = 'OS';
|
|
||||||
$lang['en_US']['Statistics']['USER'] = 'User';
|
|
||||||
$lang['en_US']['Statistics']['PAGE'] = 'Page';
|
|
||||||
$lang['en_US']['Statistics']['PAGEVIEWS'] = 'Page Views';
|
|
||||||
$lang['en_US']['Statistics']['BROWSERS'] = 'Browsers';
|
|
||||||
$lang['en_US']['Statistics']['OS'] = 'Operating Systems';
|
|
||||||
$lang['en_US']['Statistics']['USERACTIVITY'] = 'User Activity';
|
|
||||||
$lang['en_US']['BBCodeParser']['BOLD'] = 'Bold Text';
|
$lang['en_US']['BBCodeParser']['BOLD'] = 'Bold Text';
|
||||||
$lang['en_US']['BBCodeParser']['BOLDEXAMPLE'] = 'Bold';
|
$lang['en_US']['BBCodeParser']['BOLDEXAMPLE'] = 'Bold';
|
||||||
$lang['en_US']['BBCodeParser']['ITALIC'] = 'Italic Text';
|
$lang['en_US']['BBCodeParser']['ITALIC'] = 'Italic Text';
|
||||||
|
@ -1,673 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package sapphire
|
|
||||||
* @subpackage misc
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Browscap.ini parsing class with caching and update capabilities
|
|
||||||
*
|
|
||||||
* PHP version 5
|
|
||||||
*
|
|
||||||
* LICENSE: This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*
|
|
||||||
* @author Jonathan Stoppani <st.jonathan@gmail.com>
|
|
||||||
* @copyright Copyright (c) 2006 Jonathan Stoppani
|
|
||||||
* @version 0.7
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
|
|
||||||
* @link http://garetjax.info/projects/browscap/
|
|
||||||
* @package sapphire
|
|
||||||
* @subpackage misc
|
|
||||||
*/
|
|
||||||
class Browscap
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Current version of the class.
|
|
||||||
*/
|
|
||||||
const VERSION = '0.7';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Different ways to access remote and local files.
|
|
||||||
*
|
|
||||||
* UPDATE_FOPEN: Uses the fopen url wrapper (use file_get_contents).
|
|
||||||
* UPDATE_FSOCKOPEN: Uses the socket functions (fsockopen).
|
|
||||||
* UPDATE_CURL: Uses the cURL extension.
|
|
||||||
* UPDATE_LOCAL: Updates from a local file (file_get_contents).
|
|
||||||
*/
|
|
||||||
const UPDATE_FOPEN = 'URL-wrapper';
|
|
||||||
const UPDATE_FSOCKOPEN = 'socket';
|
|
||||||
const UPDATE_CURL = 'cURL';
|
|
||||||
const UPDATE_LOCAL = 'local';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for regex patterns.
|
|
||||||
*
|
|
||||||
* REGEX_DELIMITER: Delimiter of all the regex patterns in the whole class.
|
|
||||||
* REGEX_MODIFIERS: Regex modifiers.
|
|
||||||
*/
|
|
||||||
const REGEX_DELIMITER = '@';
|
|
||||||
const REGEX_MODIFIERS = 'i';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The values to quote in the ini file
|
|
||||||
*/
|
|
||||||
const VALUES_TO_QUOTE = 'Browser|Parent';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Definitions of the function used by the uasort() function to order the
|
|
||||||
* userAgents array.
|
|
||||||
*
|
|
||||||
* ORDER_FUNC_ARGS: Arguments that the function will take.
|
|
||||||
* ORDER_FUNC_LOGIC: Internal logic of the function.
|
|
||||||
*/
|
|
||||||
const ORDER_FUNC_ARGS = '$a, $b';
|
|
||||||
const ORDER_FUNC_LOGIC = '$a=strlen($a);$b=strlen($b);return$a==$b?0:($a<$b?1:-1);';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The headers to be sent for checking the version and requesting the file.
|
|
||||||
*/
|
|
||||||
const REQUEST_HEADERS = "GET %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\nConnection: Close\r\n\r\n";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Options for auto update capabilities
|
|
||||||
*
|
|
||||||
* $remoteVerUrl: The location to use to check out if a new version of the
|
|
||||||
* browscap.ini file is available.
|
|
||||||
* $remoteIniUrl: The location from which download the ini file.
|
|
||||||
* The placeholder for the file should be represented by a %s.
|
|
||||||
* $timeout: The timeout for the requests.
|
|
||||||
* $updateInterval: The update interval in seconds.
|
|
||||||
* $errorInterval: The next update interval in seconds in case of an error.
|
|
||||||
* $doAutoUpdate: Flag to disable the automatic interval based update.
|
|
||||||
* $updateMethod: The method to use to update the file, has to be a value of
|
|
||||||
* an UPDATE_* constant, null or false.
|
|
||||||
*/
|
|
||||||
public $remoteIniUrl = 'http://browsers.garykeith.com/stream.asp?Lite_BrowsCapINI';
|
|
||||||
public $remoteVerUrl = 'http://browsers.garykeith.com/version-date.asp';
|
|
||||||
public $timeout = 5;
|
|
||||||
public $updateInterval = 432000; // 5 days
|
|
||||||
public $errorInterval = 7200; // 2 hours
|
|
||||||
public $doAutoUpdate = false;
|
|
||||||
public $updateMethod = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The path of the local version of the browscap.ini file from which to
|
|
||||||
* update (to be set only if used).
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $localFile = 'misc/browscap.ini';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The useragent to include in the requests made by the class during the
|
|
||||||
* update process.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $userAgent = 'PHP Browser Capabilities Project/%v %m';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag to enable only lowercase indexes in the result.
|
|
||||||
* The cache has to be rebuilt in order to apply this option.
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $lowercase = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag to enable/disable silent error management.
|
|
||||||
* In case of an error during the update process the class returns an empty
|
|
||||||
* array/object if the update process can't take place and the browscap.ini
|
|
||||||
* file does not exist.
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $silent = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to store the cached PHP arrays.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $cacheFilename = 'cache.php';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to store the downloaded ini file.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $iniFilename = 'browscap.ini';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Path to the cache directory
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
public $cacheDir = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Flag to be set to true after loading the cache
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $_cacheLoaded = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Where to store the value of the included PHP cache file
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $_userAgents = array();
|
|
||||||
private $_browsers = array();
|
|
||||||
private $_patterns = array();
|
|
||||||
private $_properties = array();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor class, checks for the existence of (and loads) the cache and
|
|
||||||
* if needed updated the definitions
|
|
||||||
*
|
|
||||||
* @param string $cache_dir
|
|
||||||
*/
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
// Silverstripe modification - user SilverStripe cache directory
|
|
||||||
$cache_dir = TEMP_FOLDER;
|
|
||||||
|
|
||||||
// has to be set to reach E_STRICT compatibility, does not affect system/app settings
|
|
||||||
date_default_timezone_set(date_default_timezone_get());
|
|
||||||
|
|
||||||
if (!isset($cache_dir)) {
|
|
||||||
throw new Browscap_Exception(
|
|
||||||
'You have to provide a path to read/store the browscap cache file'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache_dir = realpath($cache_dir);
|
|
||||||
|
|
||||||
// Is the cache dir really the directory or is it directly the file?
|
|
||||||
if (substr($cache_dir, -4) === '.php') {
|
|
||||||
$this->cacheFilename = basename($cache_dir);
|
|
||||||
$this->cacheDir = dirname($cache_dir);
|
|
||||||
} else {
|
|
||||||
$this->cacheDir = $cache_dir;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->cacheDir .= DIRECTORY_SEPARATOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the information about the browser by User Agent
|
|
||||||
*
|
|
||||||
* @param string $user_agent the user agent string
|
|
||||||
* @param bool $return_array whether return an array or an object
|
|
||||||
* @throws Browscap_Exception
|
|
||||||
* @return stdObject the object containing the browsers details. Array if
|
|
||||||
* $return_array is set to true.
|
|
||||||
*/
|
|
||||||
public function getBrowser($user_agent = null, $return_array = false)
|
|
||||||
{
|
|
||||||
// Load the cache at the first request
|
|
||||||
if (!$this->_cacheLoaded) {
|
|
||||||
$cache_file = $this->cacheDir . $this->cacheFilename;
|
|
||||||
$ini_file = $this->cacheDir . $this->iniFilename;
|
|
||||||
|
|
||||||
// Set the interval only if needed
|
|
||||||
if ($this->doAutoUpdate && file_exists($ini_file)) {
|
|
||||||
$interval = time() - filemtime($ini_file);
|
|
||||||
} else {
|
|
||||||
$interval = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find out if the cache needs to be updated
|
|
||||||
if (!file_exists($cache_file) || !file_exists($ini_file) || ($interval > $this->updateInterval)) {
|
|
||||||
try {
|
|
||||||
$this->updateCache();
|
|
||||||
} catch (Browscap_Exception $e) {
|
|
||||||
if (file_exists($ini_file)) {
|
|
||||||
// Adjust the filemtime to the $errorInterval
|
|
||||||
touch($ini_file, time() - $this->updateInterval + $this->errorInterval);
|
|
||||||
} else if ($this->silent) {
|
|
||||||
// Return an array if silent mode is active and the ini db doesn't exsist
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->silent) {
|
|
||||||
throw $e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_loadCache($cache_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Automatically detect the useragent
|
|
||||||
if (!isset($user_agent)) {
|
|
||||||
if (isset($_SERVER['HTTP_USER_AGENT'])) {
|
|
||||||
$user_agent = $_SERVER['HTTP_USER_AGENT'];
|
|
||||||
} else {
|
|
||||||
$user_agent = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$browser = array();
|
|
||||||
foreach ($this->_patterns as $key => $pattern) {
|
|
||||||
if (preg_match($pattern . 'i', $user_agent)) {
|
|
||||||
$browser = array(
|
|
||||||
$user_agent, // Original useragent
|
|
||||||
trim(strtolower($pattern), self::REGEX_DELIMITER),
|
|
||||||
$this->_userAgents[$key]
|
|
||||||
);
|
|
||||||
|
|
||||||
$browser = $value = $browser + $this->_browsers[$key];
|
|
||||||
|
|
||||||
while (array_key_exists(3, $value) && $value[3] != null && $value[3] != '') {
|
|
||||||
$value = $this->_browsers[$value[3]];
|
|
||||||
$browser += $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($browser[3])) {
|
|
||||||
$browser[3] = $this->_userAgents[$browser[3]];
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the keys for each property
|
|
||||||
$array = array();
|
|
||||||
foreach ($browser as $key => $value) {
|
|
||||||
$array[$this->_properties[$key]] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return_array ? $array : (object) $array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the ini file and updates the cache files
|
|
||||||
*
|
|
||||||
* @return bool whether the file was correctly written to the disk
|
|
||||||
*/
|
|
||||||
public function updateCache()
|
|
||||||
{
|
|
||||||
$ini_path = $this->cacheDir . $this->iniFilename;
|
|
||||||
$cache_path = $this->cacheDir . $this->cacheFilename;
|
|
||||||
|
|
||||||
// Choose the right url
|
|
||||||
if ($this->_getUpdateMethod() == self::UPDATE_LOCAL) {
|
|
||||||
$url = $this->localFile;
|
|
||||||
} else {
|
|
||||||
$url = $this->remoteIniUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_getRemoteIniFile($url, $ini_path);
|
|
||||||
|
|
||||||
$browsers = parse_ini_file($ini_path, true);
|
|
||||||
array_shift($browsers);
|
|
||||||
|
|
||||||
$this->_properties = array_keys($browsers['DefaultProperties']);
|
|
||||||
array_unshift(
|
|
||||||
$this->_properties,
|
|
||||||
'browser_name',
|
|
||||||
'browser_name_regex',
|
|
||||||
'browser_name_pattern',
|
|
||||||
'Parent'
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->_userAgents = array_keys($browsers);
|
|
||||||
usort(
|
|
||||||
$this->_userAgents,
|
|
||||||
create_function(self::ORDER_FUNC_ARGS, self::ORDER_FUNC_LOGIC)
|
|
||||||
);
|
|
||||||
|
|
||||||
$user_agents_keys = array_flip($this->_userAgents);
|
|
||||||
$properties_keys = array_flip($this->_properties);
|
|
||||||
|
|
||||||
$search = array('\*', '\?');
|
|
||||||
$replace = array('.*', '.');
|
|
||||||
|
|
||||||
foreach ($this->_userAgents as $user_agent) {
|
|
||||||
$pattern = preg_quote($user_agent, self::REGEX_DELIMITER);
|
|
||||||
$this->_patterns[] = self::REGEX_DELIMITER
|
|
||||||
. '^'
|
|
||||||
. str_replace($search, $replace, $pattern)
|
|
||||||
. '$'
|
|
||||||
. self::REGEX_DELIMITER;
|
|
||||||
|
|
||||||
if (!empty($browsers[$user_agent]['Parent'])) {
|
|
||||||
$parent = $browsers[$user_agent]['Parent'];
|
|
||||||
$browsers[$user_agent]['Parent'] = isset($user_agents_keys[$parent]) ? $user_agents_keys[$parent] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($browsers[$user_agent] as $key => $value) {
|
|
||||||
$key = $properties_keys[$key] . ".0";
|
|
||||||
$browser[$key] = $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_browsers[] = $browser;
|
|
||||||
unset($browser);
|
|
||||||
}
|
|
||||||
unset($user_agents_keys, $properties_keys, $browsers);
|
|
||||||
|
|
||||||
// Save the keys lowercased if needed
|
|
||||||
if ($this->lowercase) {
|
|
||||||
$this->_properties = array_map('strtolower', $this->_properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the whole PHP code
|
|
||||||
$cache = $this->_buildCache();
|
|
||||||
|
|
||||||
// Save and return
|
|
||||||
return (bool) file_put_contents($cache_path, $cache, LOCK_EX);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the cache into object's properties
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
private function _loadCache($cache_file)
|
|
||||||
{
|
|
||||||
require $cache_file;
|
|
||||||
|
|
||||||
$this->_browsers = $browsers;
|
|
||||||
$this->_userAgents = $userAgents;
|
|
||||||
$this->_patterns = $patterns;
|
|
||||||
$this->_properties = $properties;
|
|
||||||
|
|
||||||
$this->_cacheLoaded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the array to cache and creates the PHP string to write to disk
|
|
||||||
*
|
|
||||||
* @return string the PHP string to save into the cache file
|
|
||||||
*/
|
|
||||||
private function _buildCache()
|
|
||||||
{
|
|
||||||
$cacheTpl = "<?php\n\$properties=%s;\n\$browsers=%s;\n\$userAgents=%s;\n\$patterns=%s;\n";
|
|
||||||
|
|
||||||
$propertiesArray = $this->_array2string($this->_properties);
|
|
||||||
$patternsArray = $this->_array2string($this->_patterns);
|
|
||||||
$userAgentsArray = $this->_array2string($this->_userAgents);
|
|
||||||
$browsersArray = $this->_array2string($this->_browsers);
|
|
||||||
|
|
||||||
return sprintf(
|
|
||||||
$cacheTpl,
|
|
||||||
$propertiesArray,
|
|
||||||
$browsersArray,
|
|
||||||
$userAgentsArray,
|
|
||||||
$patternsArray
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the local copy of the ini file (by version checking) and adapts
|
|
||||||
* his syntax to the PHP ini parser
|
|
||||||
*
|
|
||||||
* @param string $url the url of the remote server
|
|
||||||
* @param string $path the path of the ini file to update
|
|
||||||
* @throws Browscap_Exception
|
|
||||||
* @return bool if the ini file was updated
|
|
||||||
*/
|
|
||||||
private function _getRemoteIniFile($url, $path)
|
|
||||||
{
|
|
||||||
// Check version
|
|
||||||
if (file_exists($path) && filesize($path)) {
|
|
||||||
$local_tmstp = filemtime($path);
|
|
||||||
|
|
||||||
if ($this->_getUpdateMethod() == self::UPDATE_LOCAL) {
|
|
||||||
$remote_tmstp = $this->_getLocalMTime();
|
|
||||||
} else {
|
|
||||||
$remote_tmstp = $this->_getRemoteMTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($remote_tmstp < $local_tmstp) {
|
|
||||||
// No update needed, return
|
|
||||||
touch($path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get updated .ini file
|
|
||||||
$browscap = $this->_getRemoteData($url);
|
|
||||||
|
|
||||||
|
|
||||||
$browscap = explode("\n", $browscap);
|
|
||||||
|
|
||||||
$pattern = self::REGEX_DELIMITER
|
|
||||||
. '('
|
|
||||||
. self::VALUES_TO_QUOTE
|
|
||||||
. ')="?([^"]*)"?$'
|
|
||||||
. self::REGEX_DELIMITER;
|
|
||||||
|
|
||||||
|
|
||||||
// Ok, lets read the file
|
|
||||||
$content = '';
|
|
||||||
foreach ($browscap as $subject) {
|
|
||||||
$subject = trim($subject);
|
|
||||||
$content .= preg_replace($pattern, '$1="$2"', $subject) . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file_put_contents($path, $content)) {
|
|
||||||
throw new Browscap_Exception("Could not write .ini content to $path");
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the remote ini file update timestamp
|
|
||||||
*
|
|
||||||
* @throws Browscap_Exception
|
|
||||||
* @return int the remote modification timestamp
|
|
||||||
*/
|
|
||||||
private function _getRemoteMTime()
|
|
||||||
{
|
|
||||||
$remote_datetime = $this->_getRemoteData($this->remoteVerUrl);
|
|
||||||
$remote_tmstp = strtotime($remote_datetime);
|
|
||||||
|
|
||||||
if (!$remote_tmstp) {
|
|
||||||
throw new Browscap_Exception("Bad datetime format from {$this->remoteVerUrl}");
|
|
||||||
}
|
|
||||||
|
|
||||||
return $remote_tmstp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the local ini file update timestamp
|
|
||||||
*
|
|
||||||
* @throws Browscap_Exception
|
|
||||||
* @return int the local modification timestamp
|
|
||||||
*/
|
|
||||||
private function _getLocalMTime()
|
|
||||||
{
|
|
||||||
if (!is_readable($this->localFile) || !is_file($this->localFile)) {
|
|
||||||
throw new Browscap_Exception("Local file is not readable");
|
|
||||||
}
|
|
||||||
|
|
||||||
return filemtime($this->localFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts the given array to the PHP string which represent it.
|
|
||||||
* This method optimizes the PHP code and the output differs form the
|
|
||||||
* var_export one as the internal PHP function does not strip whitespace or
|
|
||||||
* convert strings to numbers.
|
|
||||||
*
|
|
||||||
* @param array $array the array to parse and convert
|
|
||||||
* @return string the array parsed into a PHP string
|
|
||||||
*/
|
|
||||||
private function _array2string($array)
|
|
||||||
{
|
|
||||||
$strings = array();
|
|
||||||
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
if (is_int($key)) {
|
|
||||||
$key = '';
|
|
||||||
} else if (ctype_digit((string) $key) || strpos($key, '.0')) {
|
|
||||||
$key = intval($key) . '=>' ;
|
|
||||||
} else {
|
|
||||||
$key = "'" . str_replace("'", "\'", $key) . "'=>" ;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($value)) {
|
|
||||||
$value = $this->_array2string($value);
|
|
||||||
} else if (ctype_digit((string) $value)) {
|
|
||||||
$value = intval($value);
|
|
||||||
} else {
|
|
||||||
$value = "'" . str_replace("'", "\'", $value) . "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
$strings[] = $key . $value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'array(' . implode(',', $strings) . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks for the various possibilities offered by the current configuration
|
|
||||||
* of PHP to retrieve external HTTP data
|
|
||||||
*
|
|
||||||
* @return string the name of function to use to retrieve the file
|
|
||||||
*/
|
|
||||||
private function _getUpdateMethod()
|
|
||||||
{
|
|
||||||
// Caches the result
|
|
||||||
if ($this->updateMethod === null) {
|
|
||||||
if ($this->localFile !== null) {
|
|
||||||
$this->updateMethod = self::UPDATE_LOCAL;
|
|
||||||
} else if (ini_get('allow_url_fopen') && function_exists('file_get_contents')) {
|
|
||||||
$this->updateMethod = self::UPDATE_FOPEN;
|
|
||||||
} else if (function_exists('fsockopen')) {
|
|
||||||
$this->updateMethod = self::UPDATE_FSOCKOPEN;
|
|
||||||
} else if (extension_loaded('curl')) {
|
|
||||||
$this->updateMethod = self::UPDATE_CURL;
|
|
||||||
} else {
|
|
||||||
$this->updateMethod = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->updateMethod;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the data identified by the URL
|
|
||||||
*
|
|
||||||
* @param string $url the url of the data
|
|
||||||
* @throws Browscap_Exception
|
|
||||||
* @return string the retrieved data
|
|
||||||
*/
|
|
||||||
private function _getRemoteData($url)
|
|
||||||
{
|
|
||||||
switch ($this->_getUpdateMethod()) {
|
|
||||||
case self::UPDATE_LOCAL:
|
|
||||||
$file = file_get_contents($url);
|
|
||||||
|
|
||||||
if ($file !== false) {
|
|
||||||
return $file;
|
|
||||||
} else {
|
|
||||||
throw new Browscap_Exception('Cannot open the local file');
|
|
||||||
}
|
|
||||||
case self::UPDATE_FOPEN:
|
|
||||||
$file = file_get_contents($url);
|
|
||||||
|
|
||||||
if ($file !== false) {
|
|
||||||
return $file;
|
|
||||||
} // else try with the next possibility (break omitted)
|
|
||||||
case self::UPDATE_FSOCKOPEN:
|
|
||||||
$remote_url = parse_url($url);
|
|
||||||
$remote_handler = fsockopen($remote_url['host'], 80, $c, $e, $this->timeout);
|
|
||||||
|
|
||||||
if ($remote_handler) {
|
|
||||||
stream_set_timeout($remote_handler, $this->timeout);
|
|
||||||
|
|
||||||
if (isset($remote_url['query'])) {
|
|
||||||
$remote_url['path'] .= '?' . $remote_url['query'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$out = sprintf(
|
|
||||||
self::REQUEST_HEADERS,
|
|
||||||
$remote_url['path'],
|
|
||||||
$remote_url['host'],
|
|
||||||
$this->_getUserAgent()
|
|
||||||
);
|
|
||||||
|
|
||||||
fwrite($remote_handler, $out);
|
|
||||||
|
|
||||||
$response = fgets($remote_handler);
|
|
||||||
if (strpos($response, '200 OK') !== false) {
|
|
||||||
$file = '';
|
|
||||||
while (!feof($remote_handler)) {
|
|
||||||
$file .= fgets($remote_handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
$file = str_replace("\r\n", "\n", $file);
|
|
||||||
$file = explode("\n\n", $file);
|
|
||||||
array_shift($file);
|
|
||||||
|
|
||||||
$file = implode("\n\n", $file);
|
|
||||||
|
|
||||||
fclose($remote_handler);
|
|
||||||
|
|
||||||
return $file;
|
|
||||||
}
|
|
||||||
} // else try with the next possibility
|
|
||||||
case self::UPDATE_CURL:
|
|
||||||
$ch = curl_init($url);
|
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
||||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $this->timeout);
|
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT, $this->_getUserAgent());
|
|
||||||
|
|
||||||
$file = curl_exec($ch);
|
|
||||||
|
|
||||||
curl_close($ch);
|
|
||||||
|
|
||||||
if ($file !== false) {
|
|
||||||
return $file;
|
|
||||||
} // else try with the next possibility
|
|
||||||
case false:
|
|
||||||
throw new Browscap_Exception('Your server can\'t connect to external resources. Please update the file manually.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the useragent string to be used in the remote requests made by the
|
|
||||||
* class during the update process.
|
|
||||||
*
|
|
||||||
* @return string the formatted user agent
|
|
||||||
*/
|
|
||||||
private function _getUserAgent()
|
|
||||||
{
|
|
||||||
$ua = str_replace('%v', self::VERSION, $this->userAgent);
|
|
||||||
$ua = str_replace('%m', $this->_getUpdateMethod(), $ua);
|
|
||||||
|
|
||||||
return $ua;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Browscap.ini parsing class exception
|
|
||||||
*
|
|
||||||
* @author Jonathan Stoppani <st.jonathan@gmail.com>
|
|
||||||
* @copyright Copyright (c) 2006 Jonathan Stoppani
|
|
||||||
* @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License
|
|
||||||
* @link http://garetjax.info/projects/browscap/
|
|
||||||
* @package sapphire
|
|
||||||
* @subpackage misc
|
|
||||||
*/
|
|
||||||
class Browscap_Exception extends Exception
|
|
||||||
{}
|
|
@ -1,582 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @package cms
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Statistics class for gathering and formatting of statistical data for tables and charts in
|
|
||||||
* both public and administrative contexts.
|
|
||||||
* @package cms
|
|
||||||
*/
|
|
||||||
|
|
||||||
class Statistics extends Controller {
|
|
||||||
|
|
||||||
function __construct() {
|
|
||||||
}
|
|
||||||
|
|
||||||
static function trend_chart($table, $filter = "day", $name, $type, $color) {
|
|
||||||
$trendstrl = _t('Statistics.TRENDS', 'Trends');
|
|
||||||
$legendtrl = _t('Statistics.LEGEND', 'Legend');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="trendchart" style="display: none">
|
|
||||||
<h2>{$trendstrl}</h2>
|
|
||||||
<div><canvas id="chart" height="400" width="700"></canvas></div>
|
|
||||||
<div id="chart_legend"><legend>{$legendtrl}</legend></div>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">\n
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$bot = <<<HTML
|
|
||||||
var chart = new Plotr.{$type}Chart('chart',options);
|
|
||||||
|
|
||||||
chart.addDataset(chartdata);
|
|
||||||
|
|
||||||
|
|
||||||
chart.render();
|
|
||||||
|
|
||||||
chart.addLegend($('chart_legend'));
|
|
||||||
|
|
||||||
</script>
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$ds = "var chartdata = { \n";
|
|
||||||
|
|
||||||
foreach($table as $class) {
|
|
||||||
$record = DataObject::get($class, "", $class.".Created DESC");
|
|
||||||
$total = $record->TotalItems();
|
|
||||||
|
|
||||||
$props = $record->toArray();
|
|
||||||
$props = $props[0]->toMap();
|
|
||||||
$startyear = new SSDatetime($props['Created']);
|
|
||||||
$startyear = $startyear->Format('Y');
|
|
||||||
$startmonth = new SSDatetime($props['Created']);
|
|
||||||
$startmonth = $startmonth->Format('m');
|
|
||||||
|
|
||||||
|
|
||||||
if($filter == "day") {
|
|
||||||
$days = new SSDatetime($props['Created']);
|
|
||||||
$days = $days->Format('t');
|
|
||||||
|
|
||||||
$sum = 0;
|
|
||||||
|
|
||||||
$ds .= "{$class}: [";
|
|
||||||
|
|
||||||
for($i = 1; $i <= $days; $i++) {
|
|
||||||
|
|
||||||
foreach($record as $v) {
|
|
||||||
$props = $v->toMap();
|
|
||||||
$currdate = new SSDatetime($props['Created']);
|
|
||||||
$curryear = $currdate->Format('Y');
|
|
||||||
$currmonth = $currdate->Format('m');
|
|
||||||
$currday = $currdate->Format('j');
|
|
||||||
if($curryear == $startyear && $currmonth == $startmonth && $currday == $i) {
|
|
||||||
$sum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ds .= "[".($i-1).", {$sum}], ";
|
|
||||||
|
|
||||||
}
|
|
||||||
$ds .= "[]],\n";
|
|
||||||
|
|
||||||
|
|
||||||
} else if($filter == "month") {
|
|
||||||
|
|
||||||
$sum = 0;
|
|
||||||
|
|
||||||
$ds .= "{$class}Set: [";
|
|
||||||
|
|
||||||
for($i = 0; $i <= 11; $i++) {
|
|
||||||
$imonth = date('F', mktime(0,0,0,$i+1,1,1));
|
|
||||||
|
|
||||||
foreach($record as $v) {
|
|
||||||
$props = $v->toMap();
|
|
||||||
$currdate = new SSDatetime($props['Created']);
|
|
||||||
$curryear = $currdate->Format('Y');
|
|
||||||
$currmonth = $currdate->Format('m');
|
|
||||||
$currday = $currdate->Format('j');
|
|
||||||
if($curryear == $startyear && $currmonth == $i) {
|
|
||||||
$sum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$ds .= "[{$i}, {$sum}], ";
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$ds .= "[]],\n";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xt = "xTicks: [";
|
|
||||||
if($filter == "month") {
|
|
||||||
for($i = 0; $i <= 11; $i++) {
|
|
||||||
$imonth = date('F', mktime(0,0,0,$i+1,1,1));
|
|
||||||
$xt .= "{v:{$i}, label:'{$imonth}'}, ";
|
|
||||||
}
|
|
||||||
} else if($filter == "day") {
|
|
||||||
for($i = 1; $i <= $days; $i++) {
|
|
||||||
$xt .= "{v:".($i-1).", label:'{$i}'}, ";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$opts = <<<HTML
|
|
||||||
var options = {
|
|
||||||
|
|
||||||
axisLabelFontSize: 10,
|
|
||||||
|
|
||||||
padding: {left: 30, right: 0, top: 10, bottom: 30},
|
|
||||||
|
|
||||||
backgroundColor: '#cccccc',
|
|
||||||
|
|
||||||
colorScheme: '{$color}',\n\n
|
|
||||||
|
|
||||||
HTML;
|
|
||||||
$opts .= $xt . "]\n};";
|
|
||||||
|
|
||||||
|
|
||||||
return $top . $ds . "\n};\n\n" . $opts . "\n\n" . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function user_record_table() {
|
|
||||||
$records = DataObject::get('Member');
|
|
||||||
$baseURL = Director::baseURL();
|
|
||||||
$registereduserstrl = _t('Statistics.REGISTEREDUSERS', 'Registered Users');
|
|
||||||
$exporttrl = _t('Statistics.CSVEXPORT', 'Export as CSV');
|
|
||||||
$idtrl = _t('Statistics.ID', 'ID');
|
|
||||||
$emailtrl = _t('Statistics.EMAIL', 'Email');
|
|
||||||
$joinedtrl = _t('Statistics.JOINED');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="usertable" style="display: none">
|
|
||||||
<h2>{$registereduserstrl}</h2>
|
|
||||||
<p><a href="$baseURL/admin/statistics/usercsv">{$exporttrl}</a></p>
|
|
||||||
<table class="sortable-onload-1 rowstyle-alt no-arrow paginate-10 statstable" border="0" cellspacing="1" cellpadding="0">
|
|
||||||
<thead>
|
|
||||||
<tr><th class="sortable-numeric">{$idtrl}</th><th class="sortable-text">{$emailtrl}</th><th class="sortable-sortDatetime">{$joinedtrl}</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
HTML;
|
|
||||||
$bod = "";
|
|
||||||
foreach($records as $x) {
|
|
||||||
$r = $x->toMap();
|
|
||||||
$id = $r['ID'];
|
|
||||||
$email = $r['Email'];
|
|
||||||
$date = date("F j, Y G:i:s", strtotime($r['Created']));
|
|
||||||
$bod .= "<tr><td>$id</td><td>$email</td><td>$date</td></tr>";
|
|
||||||
}
|
|
||||||
$bot = <<<HTML
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
HTML;
|
|
||||||
//$js = "\n\n<script type=\"text/javascript\">\n\tvar usertable = new TableKit('usertable');\nusertable.initialize();\n</script>\n";
|
|
||||||
return $top . $bod . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function collect() {
|
|
||||||
$hit = new PageView();
|
|
||||||
$hit->record();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get_recent_views($limit = 15) {
|
|
||||||
$records = DataObject::get('PageView', null, 'Created DESC', null, $limit);
|
|
||||||
$recentpvtrl = _t('Statistics.RECENTPAGEVIEWS', 'Recent Page Views');
|
|
||||||
$idtrl = _t('Statistics.ID', 'ID');
|
|
||||||
$timetrl = _t('Statistics.TIME', 'Time');
|
|
||||||
$browsertrl = _t('Statistics.BROWSER', 'Browser');
|
|
||||||
$ostrl = _t('Statistics.OSABREV', 'OS');
|
|
||||||
$usertrl = _t('Statistics.USER', 'User');
|
|
||||||
$pagetrl = _t('Statistics.PAGE', 'Page');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="recentviewtable">
|
|
||||||
<h2>{$recentpvtrl}</h2>
|
|
||||||
<table class="sortable-onload-1 rowstyle-alt no-arrow paginate-10 statstable" border="0" cellspacing="1" cellpadding="0">
|
|
||||||
<thead>
|
|
||||||
<tr><th class="sortable-numeric">{$idtrl}</th><th class="sortable-sortDatetime">{$timetrl}</th><th class="sortable-text">{$browsertrl}</th><th class="sortable-text">{$ostrl}</th><th>{$usertrl}</th><th class="sortable-text">{$pagetrl}</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
HTML;
|
|
||||||
$bod = "";
|
|
||||||
foreach($records as $x) {
|
|
||||||
$r = $x->toMap();
|
|
||||||
$id = $r['ID'];
|
|
||||||
$time = $r['Created'];
|
|
||||||
$browser = $r['Browser'] . " " . $r['BrowserVersion'];
|
|
||||||
$os = $r['OS'];
|
|
||||||
$user = $r['UserID'];
|
|
||||||
$page = $r['PageID'];
|
|
||||||
$bod .= "<tr><td>$id</td><td>$time</td><td>$browser</td><td>$os</td><td>$user</td><td>$page</td></tr>";
|
|
||||||
}
|
|
||||||
$bot = <<<HTML
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
HTML;
|
|
||||||
return $top . $bod . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get_views($time = 'all') {
|
|
||||||
switch($time) {
|
|
||||||
case 'all':
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
$pt = time() - 31556926;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$pt = time() - 2629744;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$pt = time() - 604800;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'day':
|
|
||||||
$pt = time() - 86400;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'hour':
|
|
||||||
$pt = time() - 3600;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'minute':
|
|
||||||
$pt = time() - 60;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
}
|
|
||||||
$baseURL = Director::baseURL();
|
|
||||||
$pageviewstrl = _t('Statistics.PAGEVIEWS', 'Page Views');
|
|
||||||
$idtrl = _t('Statistics.ID', 'ID');
|
|
||||||
$timetrl = _t('Statistics.TIME', 'Time');
|
|
||||||
$browsertrl = _t('Statistics.BROWSER', 'Browser');
|
|
||||||
$ostrl = _t('Statistics.OSABREV', 'OS');
|
|
||||||
$usertrl = _t('Statistics.USER', 'User');
|
|
||||||
$pagetrl = _t('Statistics.PAGE', 'Page');
|
|
||||||
$exporttrl = _t('Statistics.CSVEXPORT', 'Export as CSV');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="viewtable" style="display: none">
|
|
||||||
<h2>{$pageviewstrl}</h2>
|
|
||||||
<p><a href="$baseURL/admin/statistics/viewcsv">{$exporttrl}</a></p>
|
|
||||||
<table class="sortable-onload-1 rowstyle-alt no-arrow paginate-10 statstable" border="0" cellspacing="1" cellpadding="0">
|
|
||||||
<thead>
|
|
||||||
<tr><th class="sortable-numeric">{$idtrl}</th><th class="sortable-sortDatetime">{$timetrl}</th><th class="sortable-text">{$browsertrl}</th><th class="sortable-text">{$ostrl}</th><th class="sortable-text">{$usertrl}</th><th class="sortable-text">{$pagetrl}</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
HTML;
|
|
||||||
$bod = "";
|
|
||||||
foreach($records as $x) {
|
|
||||||
$r = $x->toMap();
|
|
||||||
$id = $r['ID'];
|
|
||||||
$time = $r['Created'];
|
|
||||||
$browser = $r['Browser'] . " " . $r['BrowserVersion'];
|
|
||||||
$os = $r['OS'];
|
|
||||||
$user = $r['UserID'];
|
|
||||||
$page = $r['PageID'];
|
|
||||||
$bod .= "<tr><td>$id</td><td>$time</td><td>$browser</td><td>$os</td><td>$user</td><td>$page</td></tr>";
|
|
||||||
}
|
|
||||||
$bot = <<<HTML
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
HTML;
|
|
||||||
return $top . $bod . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function browser_chart($type = "Pie", $color = "blue") {
|
|
||||||
$browserstrl = _t('Statistics.BROWSERS', 'Browsers');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="browserchart" style="display: none">
|
|
||||||
<h2>{$browserstrl}</h2>
|
|
||||||
<div><canvas id="bchart" height="400" width="700"></canvas></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">\n
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$bot = <<<HTML
|
|
||||||
var bchart = new Plotr.{$type}Chart('bchart', boptions);
|
|
||||||
|
|
||||||
bchart.addDataset(bchartdata);
|
|
||||||
|
|
||||||
|
|
||||||
bchart.render();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$ds = "var bchartdata = { \n'Set': [";
|
|
||||||
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
$browsers = array();
|
|
||||||
foreach($records as $r) {
|
|
||||||
$ra = $r->toMap();
|
|
||||||
$cb = $ra['Browser'] . " " . $ra['BrowserVersion'];
|
|
||||||
if(isset($browsers[$cb]) && $browsers[$cb] >= 1) {
|
|
||||||
$browsers[$cb]++;
|
|
||||||
} else {
|
|
||||||
$browsers[$cb] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xt = "xTicks: [";
|
|
||||||
$i = 0;
|
|
||||||
foreach($browsers as $bn => $bc) {
|
|
||||||
$ds .= "[{$i}, {$bc}], ";
|
|
||||||
$xt .= "{v:" . $i . ", label:'" . $bn . "'}, ";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
$ds .= "]\n";
|
|
||||||
|
|
||||||
$opts = <<<HTML
|
|
||||||
var boptions = {
|
|
||||||
|
|
||||||
axisLabelFontSize: 10,
|
|
||||||
|
|
||||||
|
|
||||||
padding: {left: 30, right: 0, top: 10, bottom: 30},
|
|
||||||
|
|
||||||
backgroundColor: '#cccccc',
|
|
||||||
|
|
||||||
colorScheme: '{$color}',\n\n
|
|
||||||
|
|
||||||
HTML;
|
|
||||||
$opts .= $xt . "]\n};";
|
|
||||||
|
|
||||||
|
|
||||||
return $top . $ds . "\n};\n\n" . $opts . "\n\n" . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function os_chart($type = "Pie", $color = "blue") {
|
|
||||||
$ostrl = _t('Statistics.OS', 'Operating Systems');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="oschart" style="display: none">
|
|
||||||
<h2>{$ostrl}</h2>
|
|
||||||
<div><canvas id="ochart" height="400" width="700"></canvas></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">\n
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$bot = <<<HTML
|
|
||||||
var ochart = new Plotr.{$type}Chart('ochart', ooptions);
|
|
||||||
|
|
||||||
ochart.addDataset(ochartdata);
|
|
||||||
|
|
||||||
|
|
||||||
ochart.render();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$ds = "var ochartdata = { \n'Set': [";
|
|
||||||
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
$oss = array();
|
|
||||||
foreach($records as $r) {
|
|
||||||
$ra = $r->toMap();
|
|
||||||
$cb = $ra['OS'];
|
|
||||||
if(isset($oss[$cb]) && $oss[$cb] >= 1) {
|
|
||||||
$oss[$cb]++;
|
|
||||||
} else {
|
|
||||||
$oss[$cb] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xt = "xTicks: [";
|
|
||||||
$i = 0;
|
|
||||||
foreach($oss as $bn => $bc) {
|
|
||||||
$ds .= "[{$i}, {$bc}], ";
|
|
||||||
$xt .= "{v:" . $i . ", label:'" . $bn . "'}, ";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
$ds .= "]\n";
|
|
||||||
|
|
||||||
$opts = <<<HTML
|
|
||||||
var ooptions = {
|
|
||||||
|
|
||||||
axisLabelFontSize: 10,
|
|
||||||
|
|
||||||
|
|
||||||
padding: {left: 30, right: 0, top: 10, bottom: 30},
|
|
||||||
|
|
||||||
backgroundColor: '#cccccc',
|
|
||||||
|
|
||||||
colorScheme: '{$color}',\n\n
|
|
||||||
|
|
||||||
HTML;
|
|
||||||
$opts .= $xt . "]\n};";
|
|
||||||
|
|
||||||
|
|
||||||
return $top . $ds . "\n};\n\n" . $opts . "\n\n" . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function activity_chart($type = "Pie", $color = "blue") {
|
|
||||||
$useracttrl = _t('Statistics.USERACTIVITY', 'User Activity');
|
|
||||||
$top = <<<HTML
|
|
||||||
<div id="uacchart" style="display: none">
|
|
||||||
<h2>{$useracttrl}</h2>
|
|
||||||
<div><canvas id="uchart" height="400" width="700"></canvas></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="text/javascript">\n
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$bot = <<<HTML
|
|
||||||
var uacchart = new Plotr.{$type}Chart('uchart', uacoptions);
|
|
||||||
|
|
||||||
uacchart.addDataset(uacchartdata);
|
|
||||||
|
|
||||||
|
|
||||||
uacchart.render();
|
|
||||||
|
|
||||||
</script>
|
|
||||||
HTML;
|
|
||||||
|
|
||||||
$ds = "var uacchartdata = { \n'Set': [";
|
|
||||||
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
$users = array();
|
|
||||||
foreach($records as $r) {
|
|
||||||
$ra = $r->toMap();
|
|
||||||
$cb = $ra['UserID'];
|
|
||||||
if($cb == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(isset($users[$cb]) && $users[$cb] >= 1) {
|
|
||||||
$users[$cb]++;
|
|
||||||
} else {
|
|
||||||
$users[$cb] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$xt = "xTicks: [";
|
|
||||||
$i = 0;
|
|
||||||
foreach($users as $bn => $bc) {
|
|
||||||
$ds .= "[{$i}, {$bc}], ";
|
|
||||||
$xt .= "{v:" . $i . ", label:'" . $bn . "'}, ";
|
|
||||||
$i++;
|
|
||||||
}
|
|
||||||
$ds .= "]\n";
|
|
||||||
|
|
||||||
$opts = <<<HTML
|
|
||||||
var uacoptions = {
|
|
||||||
|
|
||||||
axisLabelFontSize: 10,
|
|
||||||
|
|
||||||
|
|
||||||
padding: {left: 30, right: 0, top: 10, bottom: 30},
|
|
||||||
|
|
||||||
backgroundColor: '#cccccc',
|
|
||||||
|
|
||||||
colorScheme: '{$color}',\n\n
|
|
||||||
|
|
||||||
HTML;
|
|
||||||
$opts .= $xt . "]\n};";
|
|
||||||
|
|
||||||
|
|
||||||
return $top . $ds . "\n};\n\n" . $opts . "\n\n" . $bot;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get_view_csv($time = 'all') {
|
|
||||||
$data = "ID, ClassName, Created, LastEdited, Browser, FromExternal, Referrer, SearchEngine, Keywords, OS, PageID, UserID, BrowserVersion, IP\n";
|
|
||||||
|
|
||||||
switch($time) {
|
|
||||||
case 'all':
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
break;
|
|
||||||
case 'year':
|
|
||||||
$pt = time() - 31556926;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'month':
|
|
||||||
$pt = time() - 2629744;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'week':
|
|
||||||
$pt = time() - 604800;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'day':
|
|
||||||
$pt = time() - 86400;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'hour':
|
|
||||||
$pt = time() - 3600;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
case 'minute':
|
|
||||||
$pt = time() - 60;
|
|
||||||
$pt = date("Y-m-d H:i:s", $pt);
|
|
||||||
$ct = time() + 10;
|
|
||||||
$ct = date("Y-m-d H:i:s", $ct);
|
|
||||||
$records = DataObject::get('PageView', "Created >= '$pt' AND Created <= '$ct'");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$records = DataObject::get('PageView');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach($records as $x) {
|
|
||||||
$r = $x->toMap();
|
|
||||||
$data .= implode(', ', $r) . "\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
static function get_user_csv() {
|
|
||||||
$data = "ID, ClassName, Created, LastEdited, FirstName, Surname, Email, Password, NumVisit, LastVisited, Bounced, AutoLoginHash, AutoLoginExpired, BlacklistedEmail, RememberLoginToken, IdentityURL, PasswordEncryption, Salt\n";
|
|
||||||
|
|
||||||
$records = DataObject::get('Member');
|
|
||||||
|
|
||||||
foreach($records as $x) {
|
|
||||||
$r = $x->toMap();
|
|
||||||
$data .= implode(', ', $r) . "\n";
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
10706
misc/browscap.ini
10706
misc/browscap.ini
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user