manager.php (6425B)
1 <?php 2 namespace Elementor\Core\Logger; 3 4 use Elementor\Core\Base\Module as BaseModule; 5 use Elementor\Core\Common\Modules\Ajax\Module; 6 use Elementor\Core\Logger\Loggers\Logger_Interface; 7 use Elementor\Core\Logger\Items\PHP; 8 use Elementor\Core\Logger\Items\JS; 9 use Elementor\Plugin; 10 use Elementor\Modules\System_Info\Module as System_Info; 11 12 if ( ! defined( 'ABSPATH' ) ) { 13 exit; // Exit if accessed directly 14 } 15 16 class Manager extends BaseModule { 17 18 protected $loggers = []; 19 20 protected $default_logger = ''; 21 22 public function get_name() { 23 return 'log'; 24 } 25 26 public function shutdown( $last_error = null ) { 27 if ( ! $last_error ) { 28 $last_error = error_get_last(); 29 } 30 31 if ( ! $last_error ) { 32 return; 33 } 34 35 if ( empty( $last_error['file'] ) ) { 36 return; 37 } 38 39 $error_path = ( wp_normalize_path( $last_error['file'] ) ); 40 // `untrailingslashit` in order to include other plugins prefixed with elementor. 41 $elementor_path = untrailingslashit( wp_normalize_path( ELEMENTOR_PATH ) ); 42 43 if ( false === strpos( $error_path, $elementor_path ) ) { 44 return; 45 } 46 47 $last_error['type'] = $this->get_log_type_from_php_error( $last_error['type'] ); 48 $last_error['trace'] = true; 49 50 $item = new PHP( $last_error ); 51 52 $this->get_logger()->log( $item ); 53 } 54 55 public function rest_error_handler( $error_number, $error_message, $error_file, $error_line ) { 56 $error = new \WP_Error( $error_number, $error_message, [ 57 'type' => $error_number, 58 'message' => $error_message, 59 'file' => $error_file, 60 'line' => $error_line, 61 ] ); 62 63 // Notify $e.data. 64 if ( ! headers_sent() ) { 65 header( 'Content-Type: application/json; charset=UTF-8' ); 66 67 http_response_code( 500 ); 68 69 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 70 echo wp_json_encode( $error->get_error_data() ); 71 } else { 72 echo wp_json_encode( [ 73 'message' => 'Server error, see Elementor => System Info', 74 ] ); 75 } 76 } 77 78 $this->shutdown( $error->get_error_data() ); 79 80 exit; 81 } 82 83 public function add_system_info_report() { 84 System_Info::add_report( 85 'log', [ 86 'file_name' => __DIR__ . '/log-reporter.php', 87 'class_name' => __NAMESPACE__ . '\Log_Reporter', 88 ] 89 ); 90 } 91 92 /** 93 * Javascript log. 94 * 95 * Log Elementor errors and save them in the database. 96 * 97 * Fired by `wp_ajax_elementor_js_log` action. 98 * 99 */ 100 public function js_log() { 101 /** @var Module $ajax */ 102 $ajax = Plugin::$instance->common->get_component( 'ajax' ); 103 104 // PHPCS ignore is added throughout this method because nonce verification happens in the $ajax->verify_request_nonce() method. 105 if ( ! $ajax->verify_request_nonce() || empty( $_POST['data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing 106 wp_send_json_error(); 107 } 108 109 // PHPCS - See comment above. 110 array_walk_recursive( $_POST['data'], function( &$value ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing 111 $value = sanitize_text_field( $value ); 112 } ); 113 114 // PHPCS - See comment above. 115 foreach ( $_POST['data'] as $error ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing 116 $error['type'] = Logger_Interface::LEVEL_ERROR; 117 118 if ( ! empty( $error['customFields'] ) ) { 119 $error['meta'] = $error['customFields']; 120 } 121 122 $item = new JS( $error ); 123 $this->get_logger()->log( $item ); 124 } 125 126 wp_send_json_success(); 127 } 128 129 public function register_logger( $name, $class ) { 130 $this->loggers[ $name ] = $class; 131 } 132 133 public function set_default_logger( $name ) { 134 if ( ! empty( $this->loggers[ $name ] ) ) { 135 $this->default_logger = $name; 136 } 137 } 138 139 public function register_default_loggers() { 140 $this->register_logger( 'db', 'Elementor\Core\Logger\Loggers\Db' ); 141 $this->set_default_logger( 'db' ); 142 } 143 144 /** 145 * @param string $name 146 * 147 * @return Logger_Interface 148 */ 149 public function get_logger( $name = '' ) { 150 $this->register_loggers(); 151 152 if ( empty( $name ) || ! isset( $this->loggers[ $name ] ) ) { 153 $name = $this->default_logger; 154 } 155 156 if ( ! $this->get_component( $name ) ) { 157 $this->add_component( $name, new $this->loggers[ $name ]() ); 158 } 159 160 return $this->get_component( $name ); 161 } 162 163 /** 164 * @param string $message 165 * @param array $args 166 * 167 * @return void 168 */ 169 public function log( $message, $args = [] ) { 170 $this->get_logger()->log( $message, $args ); 171 } 172 173 /** 174 * @param string $message 175 * @param array $args 176 * 177 * @return void 178 */ 179 public function info( $message, $args = [] ) { 180 $this->get_logger()->info( $message, $args ); 181 } 182 183 /** 184 * @param string $message 185 * @param array $args 186 * 187 * @return void 188 */ 189 public function notice( $message, $args = [] ) { 190 $this->get_logger()->notice( $message, $args ); 191 } 192 193 /** 194 * @param string $message 195 * @param array $args 196 * 197 * @return void 198 */ 199 public function warning( $message, $args = [] ) { 200 $this->get_logger()->warning( $message, $args ); 201 } 202 203 /** 204 * @param string $message 205 * @param array $args 206 * 207 * @return void 208 */ 209 public function error( $message, $args = [] ) { 210 $this->get_logger()->error( $message, $args ); 211 } 212 213 private function get_log_type_from_php_error( $type ) { 214 $error_map = [ 215 E_CORE_ERROR => Logger_Interface::LEVEL_ERROR, 216 E_ERROR => Logger_Interface::LEVEL_ERROR, 217 E_USER_ERROR => Logger_Interface::LEVEL_ERROR, 218 E_COMPILE_ERROR => Logger_Interface::LEVEL_ERROR, 219 E_RECOVERABLE_ERROR => Logger_Interface::LEVEL_ERROR, 220 E_PARSE => Logger_Interface::LEVEL_ERROR, 221 E_STRICT => Logger_Interface::LEVEL_ERROR, 222 223 E_WARNING => Logger_Interface::LEVEL_WARNING, 224 E_USER_WARNING => Logger_Interface::LEVEL_WARNING, 225 E_CORE_WARNING => Logger_Interface::LEVEL_WARNING, 226 E_COMPILE_WARNING => Logger_Interface::LEVEL_WARNING, 227 228 E_NOTICE => Logger_Interface::LEVEL_NOTICE, 229 E_USER_NOTICE => Logger_Interface::LEVEL_NOTICE, 230 E_DEPRECATED => Logger_Interface::LEVEL_NOTICE, 231 E_USER_DEPRECATED => Logger_Interface::LEVEL_NOTICE, 232 ]; 233 234 return isset( $error_map[ $type ] ) ? $error_map[ $type ] : Logger_Interface::LEVEL_ERROR; 235 } 236 237 private function register_loggers() { 238 if ( ! did_action( 'elementor/loggers/register' ) ) { 239 do_action( 'elementor/loggers/register', $this ); 240 } 241 } 242 243 public function __construct() { 244 register_shutdown_function( [ $this, 'shutdown' ] ); 245 246 add_action( 'admin_init', [ $this, 'add_system_info_report' ], 80 ); 247 248 add_action( 'wp_ajax_elementor_js_log', [ $this, 'js_log' ] ); 249 250 add_action( 'elementor/loggers/register', [ $this, 'register_default_loggers' ] ); 251 } 252 }