[ Mini Kiebo ]
Server: Windows NT AKFAR_SERVER 10.0 build 26200 (Windows 10) AMD64
Path:
D:
/
Jurnal PSCP
/
lib
/
pkp
/
plugins
/
generic
/
usageEvent
/
[
Home
]
File: PKPUsageEventPlugin.inc.php
<?php /** * @file plugins/generic/usageEvent/PKPUsageEventPlugin.inc.php * * Copyright (c) 2013-2021 Simon Fraser University * Copyright (c) 2003-2021 John Willinsky * Distributed under the GNU GPL v3. For full terms see the file docs/COPYING. * * @class PKPUsageEventPlugin * @ingroup plugins_generic_usageEvent * * @brief Base class for usage event plugin. Provide usage events to * other statistics plugins. */ import('lib.pkp.classes.plugins.GenericPlugin'); // User classification types. define('USAGE_EVENT_PLUGIN_CLASSIFICATION_BOT', 'bot'); define('USAGE_EVENT_PLUGIN_CLASSIFICATION_ADMIN', 'administrative'); abstract class PKPUsageEventPlugin extends GenericPlugin { // // Implement methods from PKPPlugin. // /** * @copydoc Plugin::register() */ function register($category, $path, $mainContextId = null) { $success = parent::register($category, $path, $mainContextId); if ($success) { $eventHooks = $this->getEventHooks(); foreach ($eventHooks as $hook) { HookRegistry::register($hook, array($this, 'getUsageEvent')); } } return $success; } /** * @copydoc LazyLoadPlugin::getName() */ function getName() { return 'usageeventplugin'; } /** * @copydoc Plugin::getInstallSitePluginSettingsFile() */ function getInstallSitePluginSettingsFile() { return PKP_LIB_PATH . DIRECTORY_SEPARATOR . $this->getPluginPath() . DIRECTORY_SEPARATOR . 'settings.xml'; } /** * @copydoc Plugin::getDisplayName() */ function getDisplayName() { return __('plugins.generic.usageEvent.displayName'); } /** * @copydoc Plugin::getDescription() */ function getDescription() { return __('plugins.generic.usageEvent.description'); } /** * @copydoc LazyLoadPlugin::getEnabled() */ function getEnabled($contextId = null) { return true; } /** * @copydoc Plugin::isSitePlugin() */ function isSitePlugin() { return true; } /** * @copydoc Plugin::getCanEnable() */ function getCanEnable() { return false; } /** * @copydoc Plugin::getCanDisable() */ function getCanDisable() { return false; } // // Public methods. // /** * Get the unique site id. * @return mixed string or null */ function getUniqueSiteId() { return $this->getSetting(CONTEXT_SITE, 'uniqueSiteId'); } // // Hook implementations. // /** * Get usage event and pass it to the registered plugins, if any. */ function getUsageEvent($hookName, $args) { // Check if we have a registration to receive the usage event. if (HookRegistry::getHooks('UsageEventPlugin::getUsageEvent')) { $usageEvent = $this->buildUsageEvent($hookName, $args); HookRegistry::call('UsageEventPlugin::getUsageEvent', array_merge(array($hookName, $usageEvent), $args)); } return false; } // // Protected methods. // /** * Get all hooks that must be used to * generate usage events. * @return array */ protected function getEventHooks() { return array( 'TemplateManager::display', 'FileManager::downloadFileFinished' ); } /** * Get all hooks that define the * finished file download. * @return array */ protected function getDownloadFinishedEventHooks() { return array( 'FileManager::downloadFileFinished' ); } /** * Build an usage event. * @param $hookName string * @param $args array * @return array */ protected function buildUsageEvent($hookName, $args) { // Finished downloading a file? if (in_array($hookName, $this->getDownloadFinishedEventHooks())) { // The usage event for this request is already build and // passed to any other registered hook. return null; } $application = Application::get(); $request = $application->getRequest(); $router = $request->getRouter(); /* @var $router PageRouter */ $templateMgr = $args[0]; /* @var $templateMgr TemplateManager */ // We are just interested in page requests. if (!is_a($router, 'PageRouter')) return false; // Check whether we are in journal context. $context = $router->getContext($request); if (!$context) return false; // Prepare request information. list($pubObject, $downloadSuccess, $assocType, $idParams, $canonicalUrlPage, $canonicalUrlOp, $canonicalUrlParams) = $this->getUsageEventData($hookName, $args, $request, $router, $templateMgr, $context); if (!$pubObject) return false; // Timestamp. $time = Core::getCurrentDate(); // Actual document size, MIME type. $htmlPageAssocTypes = $this->getHtmlPageAssocTypes(); if (in_array($assocType, $htmlPageAssocTypes)) { // HTML pages with no file downloads. $mimeType = 'text/html'; } elseif (is_a($pubObject, 'IssueGalley')) { $mimeType = $pubObject->getFileType(); } else { // Files. $path = $pubObject->getData('path'); $mimeType = $pubObject->getData('mimetype'); } $canonicalUrl = $router->url( $request, null, $canonicalUrlPage, $canonicalUrlOp, $canonicalUrlParams ); // Make sure we log the server name and not aliases. $configBaseUrl = Config::getVar('general', 'base_url'); $requestBaseUrl = $request->getBaseUrl(); if ($requestBaseUrl !== $configBaseUrl) { // Make sure it's not an url override (no alias on that case). if (!in_array($requestBaseUrl, Config::getContextBaseUrls()) && $requestBaseUrl !== Config::getVar('general', 'base_url[index]')) { // Alias found, replace it by base_url from config file. // Make sure we use the correct base url override value for the context, if any. $baseUrlReplacement = Config::getVar('general', 'base_url['.$context->getPath().']'); if (!$baseUrlReplacement) $baseUrlReplacement = $configBaseUrl; $canonicalUrl = str_replace($requestBaseUrl, $baseUrlReplacement, $canonicalUrl); } } // Public identifiers. // 1) A unique system internal ID that will help us to easily attribute // statistics to a specific publication object. array_unshift($idParams, 'c' . $context->getId()); $siteId = $this->getUniqueSiteId(); if (empty($siteId)) { // Create a globally unique, persistent site ID // so that we can uniquely identify publication // objects from this site, even if the URL or any // other externally influenced information changes. $siteId = uniqid(); $this->updateSetting(0, 'uniqueSiteId', $siteId); } array_unshift($idParams, $siteId); $applicationName = $application->getName(); $applicationId = $applicationName . ':' . implode('-', $idParams); $idKey = 'other::' . $applicationName; $identifiers = array($idKey => $applicationId); // 2) Standardized public identifiers, e.g. DOI, URN, etc. if ($this->isPubIdObjectType($pubObject)) { $pubIdPlugins = PluginRegistry::loadCategory('pubIds', true, $context->getId()); if (!empty($pubIdPlugins)) { foreach ($pubIdPlugins as $pubIdPlugin) { if (!$pubIdPlugin->getEnabled()) continue; $pubId = $pubObject->getStoredPubId($pubIdPlugin->getPubIdType()); if ($pubId) { $identifiers[$pubIdPlugin->getPubIdType()] = $pubId; } } } } // Service URI. $serviceUri = $router->url($request, $context->getPath()); // IP and Host. $ip = $request->getRemoteAddr(); $host = null; if (isset($_SERVER['REMOTE_HOST'])) { // We do NOT actively look up the remote host to // avoid the performance penalty. We only set the remote // host if we get it "for free". $host = $_SERVER['REMOTE_HOST']; } // HTTP user agent. $userAgent = $request->getUserAgent(); // HTTP referrer. $referrer = (isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null); // User and roles. $user = $request->getUser(); $roles = array(); if ($user) { $roleDao = DAORegistry::getDAO('RoleDAO'); /* @var $roleDao PKPRoleDAO */ $rolesByContext = $roleDao->getByUserIdGroupedByContext($user->getId()); foreach (array(CONTEXT_SITE, $context->getId()) as $workingContext) { if(isset($rolesByContext[$workingContext])) { foreach ($rolesByContext[$workingContext] as $roleId => $role) { $roles[] = $roleId; } } } } // Try a simple classification of the request. $classification = null; if (!empty($roles)) { // Access by editors, authors, etc. $internalRoles = array_diff($roles, array(ROLE_ID_READER)); if (!empty($internalRoles)) { $classification = USAGE_EVENT_PLUGIN_CLASSIFICATION_ADMIN; } } if ($request->isBot()) { // The bot classification overwrites other classifications. $classification = USAGE_EVENT_PLUGIN_CLASSIFICATION_BOT; } // TODO: Classify LOCKSS or similar as 'internal' access. /* * Comparison of our event log format with Apache log parameters... * * 1) default parameters: * %h: remote hostname or IP => $ip, $host * %l: remote logname (identd) => not supported, see $user, $roles instead * %u: remote user => not supported, see $user, $roles instead * %t: request time => $time * %r: query => derived objects: $pubObject, $assocType, $canonicalUrl, $identifiers, $serviceUri, $classification * %s: status => not supported (always 200 in our case) * * 2) other common parameters * %O: bytes sent => not supported (cannot be reliably determined from within PHP) * %X: connection status => $downloadSuccess (not reliable!) * %{ContentType}o: => $mimeType * %{User-agent}i: => $userAgent * %{Referer}i: => $referrer * * Several items, e.g. time etc., may differ from what Apache * would actually log. But the differences do not matter for our use * cases. */ // Collect all information into an array. $usageEvent = compact( 'time', 'pubObject', 'assocType', 'canonicalUrl', 'mimeType', 'identifiers', 'downloadSuccess', 'serviceUri', 'ip', 'host', 'user', 'roles', 'userAgent', 'referrer', 'classification' ); return $usageEvent; } /** * Get usage event details based on the passed hook. * Subclasses should extend to implement application specifics. * @param $hookName string * @param $hookArgs array * @param $request PKPRequest * @param $router PageRouter * @param $templateMgr PKPTemplateManager * @param $context Context * @return array With the following data: * DataObject the published object, boolean download success, integer used published object assoc type, * string used published object id foreign keys lookup (all parent associated objects id, * preceeded with a single letter to identify the object), string canonical url page, * string canonical url operation, array with canonical url parameters. * @see PKPUsageEventPlugin::buildUsageEvent() */ protected function getUsageEventData($hookName, $hookArgs, $request, $router, $templateMgr, $context) { $nullVar = null; $pubObject = $nullVar; $downloadSuccess = false; $canonicalUrlPage = $canonicalUrlOp = $assocType = null; $canonicalUrlParams = $idParams = array(); if ($hookName == 'TemplateManager::display') { $page = $router->getRequestedPage($request); $op = $router->getRequestedOp($request); // First check for a context index page view. if (($page == 'index' || empty($page)) && $op == 'index') { $pubObject = $templateMgr->getTemplateVars('currentContext'); if (is_a($pubObject, 'Context')) { $assocType = Application::getContextAssocType(); $canonicalUrlOp = ''; $canonicalUrlPage = 'index'; $downloadSuccess = true; } } } return array($pubObject, $downloadSuccess, $assocType, $idParams, $canonicalUrlPage, $canonicalUrlOp, $canonicalUrlParams); } // // Abstract protected methods. // /** * Get all assoc types that have their usage event * produced by html page access. * @return array */ abstract protected function getHtmlPageAssocTypes(); /** * Whether or not the passed object is of a type that can have * different public identifiers, like DOI, URN, etc. * @param $pubObject DataObject * @return boolean */ abstract protected function isPubIdObjectType($pubObject); }