aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/system_log.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib/system_log.php')
-rw-r--r--engine/lib/system_log.php311
1 files changed, 311 insertions, 0 deletions
diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php
new file mode 100644
index 000000000..84302632e
--- /dev/null
+++ b/engine/lib/system_log.php
@@ -0,0 +1,311 @@
+<?php
+/**
+ * Elgg system log.
+ * Listens to events and writes crud events into the system log database.
+ *
+ * @package Elgg.Core
+ * @subpackage Logging
+ */
+
+/**
+ * Retrieve the system log based on a number of parameters.
+ *
+ * @todo too many args, and the first arg is too confusing
+ *
+ * @param int|array $by_user The guid(s) of the user(s) who initiated the event.
+ * Use 0 for unowned entries. Anything else falsey means anyone.
+ * @param string $event The event you are searching on.
+ * @param string $class The class of object it effects.
+ * @param string $type The type
+ * @param string $subtype The subtype.
+ * @param int $limit Maximum number of responses to return.
+ * @param int $offset Offset of where to start.
+ * @param bool $count Return count or not
+ * @param int $timebefore Lower time limit
+ * @param int $timeafter Upper time limit
+ * @param int $object_id GUID of an object
+ * @param string $ip_address The IP address.
+ * @return mixed
+ */
+function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "", $limit = 10,
+ $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0,
+ $ip_address = "") {
+
+ global $CONFIG;
+
+ $by_user_orig = $by_user;
+ if (is_array($by_user) && sizeof($by_user) > 0) {
+ foreach ($by_user as $key => $val) {
+ $by_user[$key] = (int) $val;
+ }
+ } else {
+ $by_user = (int)$by_user;
+ }
+
+ $event = sanitise_string($event);
+ $class = sanitise_string($class);
+ $type = sanitise_string($type);
+ $subtype = sanitise_string($subtype);
+ $ip_address = sanitise_string($ip_address);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+
+ $where = array();
+
+ if ($by_user_orig !== "" && $by_user_orig !== false && $by_user_orig !== null) {
+ if (is_int($by_user)) {
+ $where[] = "performed_by_guid=$by_user";
+ } else if (is_array($by_user)) {
+ $where [] = "performed_by_guid in (" . implode(",", $by_user) . ")";
+ }
+ }
+ if ($event != "") {
+ $where[] = "event='$event'";
+ }
+ if ($class !== "") {
+ $where[] = "object_class='$class'";
+ }
+ if ($type != "") {
+ $where[] = "object_type='$type'";
+ }
+ if ($subtype !== "") {
+ $where[] = "object_subtype='$subtype'";
+ }
+
+ if ($timebefore) {
+ $where[] = "time_created < " . ((int) $timebefore);
+ }
+ if ($timeafter) {
+ $where[] = "time_created > " . ((int) $timeafter);
+ }
+ if ($object_id) {
+ $where[] = "object_id = " . ((int) $object_id);
+ }
+ if ($ip_address) {
+ $where[] = "ip_address = '$ip_address'";
+ }
+
+ $select = "*";
+ if ($count) {
+ $select = "count(*) as count";
+ }
+ $query = "SELECT $select from {$CONFIG->dbprefix}system_log where 1 ";
+ foreach ($where as $w) {
+ $query .= " and $w";
+ }
+
+ if (!$count) {
+ $query .= " order by time_created desc";
+ $query .= " limit $offset, $limit"; // Add order and limit
+ }
+
+ if ($count) {
+ $numrows = get_data_row($query);
+ if ($numrows) {
+ return $numrows->count;
+ }
+ } else {
+ return get_data($query);
+ }
+
+ return false;
+}
+
+/**
+ * Return a specific log entry.
+ *
+ * @param int $entry_id The log entry
+ *
+ * @return mixed
+ */
+function get_log_entry($entry_id) {
+ global $CONFIG;
+
+ $entry_id = (int)$entry_id;
+
+ return get_data_row("SELECT * from {$CONFIG->dbprefix}system_log where id=$entry_id");
+}
+
+/**
+ * Return the object referred to by a given log entry
+ *
+ * @param int $entry_id The log entry
+ *
+ * @return mixed
+ */
+function get_object_from_log_entry($entry_id) {
+ $entry = get_log_entry($entry_id);
+
+ if ($entry) {
+ $class = $entry->object_class;
+ // surround with try/catch because object could be disabled
+ try {
+ $object = new $class($entry->object_id);
+ } catch (Exception $e) {
+
+ }
+ if ($object) {
+ return $object;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Log a system event related to a specific object.
+ *
+ * This is called by the event system and should not be called directly.
+ *
+ * @param object $object The object you're talking about.
+ * @param string $event The event being logged
+ * @return void
+ */
+function system_log($object, $event) {
+ global $CONFIG;
+ static $log_cache;
+ static $cache_size = 0;
+
+ if ($object instanceof Loggable) {
+
+ /* @var ElggEntity|ElggExtender $object */
+ if (datalist_get('version') < 2012012000) {
+ // this is a site that doesn't have the ip_address column yet
+ return;
+ }
+
+ // reset cache if it has grown too large
+ if (!is_array($log_cache) || $cache_size > 500) {
+ $log_cache = array();
+ $cache_size = 0;
+ }
+
+ // Has loggable interface, extract the necessary information and store
+ $object_id = (int)$object->getSystemLogID();
+ $object_class = $object->getClassName();
+ $object_type = $object->getType();
+ $object_subtype = $object->getSubtype();
+ $event = sanitise_string($event);
+ $time = time();
+
+ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
+ } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_REAL_IP']));
+ } else {
+ $ip_address = $_SERVER['REMOTE_ADDR'];
+ }
+ $ip_address = sanitise_string($ip_address);
+
+ $performed_by = elgg_get_logged_in_user_guid();
+
+ if (isset($object->access_id)) {
+ $access_id = $object->access_id;
+ } else {
+ $access_id = ACCESS_PUBLIC;
+ }
+ if (isset($object->enabled)) {
+ $enabled = $object->enabled;
+ } else {
+ $enabled = 'yes';
+ }
+
+ if (isset($object->owner_guid)) {
+ $owner_guid = $object->owner_guid;
+ } else {
+ $owner_guid = 0;
+ }
+
+ // Create log if we haven't already created it
+ if (!isset($log_cache[$time][$object_id][$event])) {
+ $query = "INSERT DELAYED into {$CONFIG->dbprefix}system_log
+ (object_id, object_class, object_type, object_subtype, event,
+ performed_by_guid, owner_guid, access_id, enabled, time_created, ip_address)
+ VALUES
+ ('$object_id','$object_class','$object_type', '$object_subtype', '$event',
+ $performed_by, $owner_guid, $access_id, '$enabled', '$time', '$ip_address')";
+
+ insert_data($query);
+
+ $log_cache[$time][$object_id][$event] = true;
+ $cache_size += 1;
+ }
+ }
+}
+
+/**
+ * This function creates an archive copy of the system log.
+ *
+ * @param int $offset An offset in seconds from now to archive (useful for log rotation)
+ *
+ * @return bool
+ */
+function archive_log($offset = 0) {
+ global $CONFIG;
+
+ $offset = (int)$offset;
+ $now = time(); // Take a snapshot of now
+
+ $ts = $now - $offset;
+
+ // create table
+ $query = "CREATE TABLE {$CONFIG->dbprefix}system_log_$now as
+ SELECT * from {$CONFIG->dbprefix}system_log WHERE time_created<$ts";
+
+ if (!update_data($query)) {
+ return false;
+ }
+
+ // delete
+ // Don't delete on time since we are running in a concurrent environment
+ if (delete_data("DELETE from {$CONFIG->dbprefix}system_log WHERE time_created<$ts") === false) {
+ return false;
+ }
+
+ // alter table to engine
+ if (!update_data("ALTER TABLE {$CONFIG->dbprefix}system_log_$now engine=archive")) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Default system log handler, allows plugins to override, extend or disable logging.
+ *
+ * @param string $event Event name
+ * @param string $object_type Object type
+ * @param Loggable $object Object to log
+ *
+ * @return true
+ */
+function system_log_default_logger($event, $object_type, $object) {
+ system_log($object['object'], $object['event']);
+
+ return true;
+}
+
+/**
+ * System log listener.
+ * This function listens to all events in the system and logs anything appropriate.
+ *
+ * @param String $event Event name
+ * @param String $object_type Type of object
+ * @param Loggable $object Object to log
+ *
+ * @return true
+ * @access private
+ */
+function system_log_listener($event, $object_type, $object) {
+ if (($object_type != 'systemlog') && ($event != 'log')) {
+ elgg_trigger_event('log', 'systemlog', array('object' => $object, 'event' => $event));
+ }
+
+ return true;
+}
+
+/** Register event to listen to all events **/
+elgg_register_event_handler('all', 'all', 'system_log_listener', 400);
+
+/** Register a default system log handler */
+elgg_register_event_handler('log', 'systemlog', 'system_log_default_logger', 999);