2026-02-05 17:08:59 +03:00

239 lines
7.7 KiB
PHP

<?php
/**
* MainWP Database Logs.
*
* This file handles all interactions with the Client DB.
*
* @package MainWP/Dashboard
*/
namespace MainWP\Dashboard\Module\Log;
/**
* Class Logs
*/
class Log {
/**
* Log_Manager
*
* @var manager Hold Log_Manager class
* */
public $manager;
/**
* Log constructor.
*
* Run each time the class is called.
*
* @param Log_Manager $manager The main manager class.
*/
public function __construct( $manager ) {
$this->manager = $manager;
}
/**
* Log handler.
*
* @param Connector $connector Connector responsible for logging the event.
* @param string $message sprintf-ready error message string.
* @param array $args sprintf (and extra) arguments to use.
* @param int $site_id Target site id.
* @param string $context Context of the event.
* @param string $action Action of the event.
* @param int|null $state action status: null - N/A, 0 - failed, 1 - success.
* @param int $user_id User responsible for the event.
*
* @return bool|WP_Error True if updated, otherwise false|WP_Error
*/
public function log( $connector, $message, $args, $site_id, $context, $action, $state = null, $user_id = null ) { //phpcs:ignore -- NOSONAR - compatible.
if ( is_null( $user_id ) ) {
$user_id = get_current_user_id();
}
if ( is_null( $site_id ) ) {
$site_id = 0;
}
$cron_tracking = apply_filters( 'mainwp_module_log_cron_tracking', true, $connector, $message, $args, $site_id, $context, $action, $user_id, $state );
$author = new Log_Author( $user_id );
$agent = $author->get_current_agent();
// WP Cron tracking requires opt-in and WP Cron to be enabled.
if ( ! $cron_tracking && 'wp_cron' === $agent ) {
return false;
}
$user = new \WP_User( $user_id );
$user_meta = array(
'user_login' => (string) ! empty( $user->user_login ) ? $user->user_login : '',
'agent' => (string) $agent,
);
$system_user = '';
if ( 'wp_cli' === $agent ) {
$system_user = 'wp_cli';
if ( is_callable( 'posix_getuid' ) && is_callable( 'posix_getpwuid' ) ) {
$uid = posix_getuid();
$user_info = posix_getpwuid( $uid );
$user_meta['system_user_id'] = (int) $uid;
$user_meta['system_user_name'] = (string) $user_info['name'];
if ( ! empty( $user_meta['system_user_name'] ) ) {
$system_user = $user_meta['system_user_name'];
}
}
} elseif ( 'wp_cron' === $agent ) {
$system_user = 'wp_cron';
} elseif ( 'wp_rest_api' === $agent ) {
$system_user = 'wp_rest_api';
}
$dura = isset( $args['duration'] ) ? floatval( $args['duration'] ) : $this->manager->executor->get_exec_time();
if ( isset( $args['duration'] ) ) {
unset( $args['duration'] );
}
$dura_bulk = 1;
if ( isset( $args['duration_bulk'] ) ) {
$dura_bulk = intval( $args['duration_bulk'] );
unset( $args['duration_bulk'] );
}
if ( empty( $dura_bulk ) ) {
$dura_bulk = 1;
}
$dura = $dura / $dura_bulk;
// Prevent any meta with null values from being logged.
$logs_meta = array_filter(
$args,
function ( $e ) {
return ! is_null( $e );
}
);
// To support searching user on meta.
if ( empty( $logs_meta['user_login'] ) ) {
if ( ! empty( $user_meta['user_login'] ) ) {
$logs_meta['user_login'] = $user_meta['user_login'];
} elseif ( ! empty( $system_user ) ) {
$logs_meta['user_login'] = $system_user;
}
}
// Add user meta to Log meta.
$logs_meta['user_meta_json'] = wp_json_encode( $user_meta );
$recordarr = array(
'site_id' => (int) $site_id,
'user_id' => (int) $user_id,
'item' => (string) vsprintf( $message, $args ),
'connector' => (string) $connector,
'context' => (string) $context,
'action' => (string) $action,
'duration' => $dura,
'created' => time(),
'state' => $state,
'meta' => (array) $logs_meta,
);
if ( 0 === $recordarr['site_id'] ) {
unset( $recordarr['site_id'] );
}
if ( null === $recordarr['state'] || '' === $recordarr['state'] ) {
unset( $recordarr['state'] );
}
// This is helpful in development environments.
// error_log( $this->debug_backtrace( $recordarr ) ); //phpcs:ignore -- development.
return $this->log_record( $recordarr );
}
/**
* Log record.
*
* @param array $recordarr sprintf (and extra) arguments to use.
*
* @return bool|WP_Error True if updated, otherwise false|WP_Error
*/
public function log_record( $recordarr ) { //phpcs:ignore -- NOSONAR - compatible.
return $this->manager->db->insert( $recordarr );
}
/**
* Helper function to send a full backtrace of calls to the PHP error log for debugging.
*
* @param array $recordarr Record argument array.
*
* @return string $output MainWP Pro Reports backtrace.
*/
public function debug_backtrace( $recordarr ) {
// Record details.
$message = isset( $recordarr['item'] ) ? $recordarr['item'] : null;
$author = isset( $recordarr['author'] ) ? $recordarr['author'] : null;
$connector = isset( $recordarr['connector'] ) ? $recordarr['connector'] : null;
$context = isset( $recordarr['context'] ) ? $recordarr['context'] : null;
$action = isset( $recordarr['action'] ) ? $recordarr['action'] : null;
// Log meta.
$logs_meta = isset( $recordarr['meta'] ) ? $recordarr['meta'] : null;
unset( $logs_meta['user_meta'] );
if ( $logs_meta ) {
array_walk(
$logs_meta,
function ( &$value, $key ) {
$value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
}
);
$logs_meta = implode( ', ', $logs_meta );
}
// User meta.
$user_meta = isset( $recordarr['meta']['user_meta'] ) ? $recordarr['meta']['user_meta'] : null;
if ( $user_meta ) {
array_walk(
$user_meta,
function ( &$value, $key ) {
$value = sprintf( '%s: %s', $key, ( '' === $value ) ? 'null' : $value );
}
);
$user_meta = implode( ', ', $user_meta );
}
// Debug backtrace.
ob_start();
// @codingStandardsIgnoreStart
debug_print_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS ); // Option to ignore args requires PHP 5.3.6
// @codingStandardsIgnoreEnd
$backtrace = ob_get_clean();
$backtrace = array_values( array_filter( explode( "\n", $backtrace ) ) );
return sprintf(
"Pro Reports Debug Backtrace\n\n Summary | %s\n Author | %s\n Connector | %s\n Context | %s\n Action | %s\nReports Meta | %s\nAuthor Meta | %s\n\n%s\n",
$message,
$author,
$connector,
$context,
$action,
$logs_meta,
$user_meta,
implode( "\n", $backtrace )
);
}
}