PluginProbe ʕ •ᴥ•ʔ
CloudSecure WP Security / 1.4.9
CloudSecure WP Security v1.4.9
1.4.10 1.4.9 trunk 0.9.0 1.0.2 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.19 1.3.2 1.3.20 1.3.21 1.3.22 1.3.23 1.3.24 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8
cloudsecure-wp-security / modules / server-error-notification.php
cloudsecure-wp-security / modules Last commit date
admin 1 month ago cli 2 months ago lib 3 months ago captcha.php 3 months ago cloudsecure-wp.php 1 month ago common.php 2 months ago config.php 2 years ago disable-access-system-file.php 4 months ago disable-author-query.php 2 years ago disable-login.php 2 months ago disable-restapi.php 2 months ago disable-xmlrpc.php 1 year ago htaccess.php 3 months ago login-log.php 2 months ago login-notification.php 1 year ago rename-login-page.php 3 months ago restrict-admin-page.php 3 months ago server-error-notification.php 2 months ago two-factor-authentication.php 1 month ago unify-messages.php 2 years ago update-notice.php 7 months ago waf-engine.php 1 month ago waf.php 1 month ago
server-error-notification.php
280 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 class CloudSecureWP_Server_Error_Notification extends CloudSecureWP_Common {
8 private const KEY_FEATURE = 'server_error_notification';
9 private const TABLE_NAME = 'cloudsecurewp_server_error';
10 private const MAX_ITEMS = 10000;
11
12 private $config;
13
14 function __construct( array $info, CloudSecureWP_Config $config ) {
15 parent::__construct( $info );
16 $this->config = $config;
17 }
18
19 /**
20 * 機能毎のKEY取得
21 *
22 * @return string
23 */
24 public function get_feature_key(): string {
25 return self::KEY_FEATURE;
26 }
27
28 /**
29 * テーブル名取得
30 *
31 * @return string
32 */
33 public function get_table_name(): string {
34 global $wpdb;
35
36 return $wpdb->prefix . self::TABLE_NAME;
37 }
38
39 /**
40 * サーバーエラーを追加
41 *
42 * @param array $error
43 *
44 * @return void
45 */
46 private function insert_error( array $error ): void {
47 global $wpdb;
48 $table_name = $wpdb->prefix . self::TABLE_NAME;
49 $max_items = self::MAX_ITEMS;
50 $error['created_at'] = current_time( 'mysql' );
51
52 if ( is_null( $error['message'] ) ) {
53 $error['message'] = '';
54 }
55
56 if ( is_null( $error['file'] ) ) {
57 $error['file'] = '';
58 }
59
60 if ( mb_strlen( $error['message'], 'UTF-8' ) > 65535 ) {
61 $error['message'] = mb_substr( $error['message'], 0, 65535, 'UTF-8' );
62 }
63
64 if ( mb_strlen( $error['file'], 'UTF-8' ) > 65535 ) {
65 $error['file'] = mb_substr( $error['file'], 0, 65535, 'UTF-8' );
66 }
67
68 try {
69 $wpdb->query( 'START TRANSACTION' );
70
71 $result = $wpdb->insert( $table_name, $error );
72 if ( $result === false || ! empty( $wpdb->last_error ) ) {
73 throw new Exception( 'Failed to insert server error.' );
74 }
75
76 $result = $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}cloudsecurewp_server_error WHERE id <= (SELECT id FROM (SELECT id FROM {$wpdb->prefix}cloudsecurewp_server_error ORDER BY id DESC LIMIT 1 OFFSET %d) tmp)", $max_items ) );
77 if ( $result === false || ! empty( $wpdb->last_error ) ) {
78 throw new Exception( 'Failed to delete old server errors.' );
79 }
80
81 $wpdb->query( 'COMMIT' );
82 } catch ( Exception $e ) {
83 $wpdb->query( 'ROLLBACK' );
84 }
85 }
86
87 /**
88 * サーバーエラーを取得
89 *
90 * @param string $orderby
91 * @param string $order
92 * @param int $per_page
93 * @param int $offset
94 *
95 * @return array
96 */
97 public function get_server_errors( string $orderby, string $order, int $per_page, int $offset ): array {
98 global $wpdb;
99 $table_name = $wpdb->prefix . self::TABLE_NAME;
100 $allowed_orderby = array( 'created_at', 'type', 'message', 'file', 'line', 'id' );
101 $orderby = in_array( $orderby, $allowed_orderby, true ) ? $orderby : 'created_at';
102 $order = ( 'asc' === $order ) ? 'ASC' : 'DESC';
103 $sql = "SELECT * FROM $table_name ORDER BY {$orderby} {$order} LIMIT %d OFFSET %d";
104
105 return array(
106 $wpdb->get_results( $wpdb->prepare( $sql, $per_page, $offset ), ARRAY_A ),
107 $wpdb->get_var( "SELECT count(*) FROM {$wpdb->prefix}cloudsecurewp_server_error" ),
108 );
109 }
110
111 /**
112 * 有効無効判定
113 *
114 * @return bool
115 */
116 public function is_enabled(): bool {
117 return $this->config->get( $this->get_feature_key() ) === 't';
118 }
119
120 /**
121 * 初期設定値取得
122 *
123 * @return array
124 */
125 public function get_default(): array {
126 return array( self::KEY_FEATURE => $this->check_environment() ? 't' : 'f' );
127 }
128
129 /**
130 * 設定値取得
131 */
132 public function get_settings(): array {
133 $settings = array();
134 $default = $this->get_default();
135
136 foreach ( $default as $key => $val ) {
137 $settings[ $key ] = $this->config->get( $key );
138 }
139
140 return $settings;
141 }
142
143 /**
144 * 設定値保存
145 *
146 * @param array $settings
147 *
148 * @return void
149 */
150 public function save_settings( array $settings ): void {
151 $default = $this->get_default();
152
153 foreach ( $default as $key => $val ) {
154 $this->config->set( $key, $settings[ $key ] ?? '' );
155 }
156
157 $this->config->save();
158 }
159
160 /**
161 * エラータイプ名称を取得
162 *
163 * @param int $error_type
164 *
165 * @return string
166 */
167 private function get_error_type_name( int $error_type ): string {
168 // 下記のコードを参考にさせていただきました。
169 // https://github.com/WordPress/WordPress/blob/aac1b7c487c9a5fd206f6845e4eba4164b02f02b/wp-includes/error-protection.php#L48
170 $constants = get_defined_constants( true );
171 $constants = $constants['Core'] ?? $constants['internal'];
172
173 foreach ( $constants as $constant => $value ) {
174 if ( 0 === strpos( $constant, 'E_' ) && $error_type === $value ) {
175 return $constant;
176 }
177 }
178
179 return '';
180 }
181
182 /**
183 * メール本文取得
184 *
185 * @param array{ type: int , message: string, file: string, line: int } $error
186 *
187 * @return string
188 */
189 private function get_body( array $error ): string {
190 $date = $this->get_date();
191 $time = $this->get_time();
192
193 $text = "$date $time にサーバーエラーが発生しました。" . PHP_EOL;
194 $text .= PHP_EOL;
195 $text .= '【サーバーエラー�
196 報】' . PHP_EOL;
197 $text .= PHP_EOL;
198 $text .= "・エラータイプ:{$error['type']}" . PHP_EOL;
199 $text .= PHP_EOL;
200 $text .= "・エラーメッセージ:{$error['message']}" . PHP_EOL;
201 $text .= PHP_EOL;
202 $text .= "・エラー箇所:{$error['file']}:{$error['line']}" . PHP_EOL;
203 $text .= PHP_EOL;
204 $text .= '--' . PHP_EOL;
205 $text .= 'CloudSecure WP Security' . PHP_EOL;
206
207 return $text;
208 }
209
210 /**
211 * 通知
212 */
213 public function notification( $args, $error ) {
214
215 $error['type'] = $this->get_error_type_name( $error['type'] );
216
217 $this->insert_error( $error );
218
219 $enable_email_server_error_notification = get_option( 'cloudsecurewp_enable_email_server_error_notification', 't' );
220 if ( 't' === $enable_email_server_error_notification ) {
221 $option_name = "cloudsecurewp_error_type_{$error['type']}_email_last_sent";
222 $last_sent = get_option( $option_name );
223 if ( ! $last_sent || time() > $last_sent + HOUR_IN_SECONDS ) {
224 update_option( $option_name, time() );
225
226 $admins = $this->get_admin_users();
227 foreach ( $admins as $admin ) {
228 $this->wp_send_mail( $admin->user_email, esc_html( 'サーバーエラー通知' ), $this->get_body( $error ) );
229 }
230 }
231 }
232
233 return $args;
234 }
235
236 /**
237 * 有効化
238 *
239 * @return void
240 */
241 public function activate(): void {
242 $this->save_settings( $this->get_default() );
243
244 global $wpdb;
245 $table_name = $this->get_table_name();
246 $table = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) ) );
247 $charset_collate = $wpdb->get_charset_collate();
248
249 if ( ! is_null( $table ) ) {
250 $sql = "ALTER TABLE {$table_name} ALTER message DROP DEFAULT";
251 $sql2 = "ALTER TABLE {$table_name} ALTER file DROP DEFAULT";
252 $wpdb->query( $sql );
253 $wpdb->query( $sql2 );
254
255 } else {
256 $sql = "CREATE TABLE {$table_name} (
257 id BIGINT( 20 ) UNSIGNED NOT NULL AUTO_INCREMENT,
258 type VARCHAR( 31 ) NOT NULL DEFAULT 0,
259 message VARCHAR( 65535 ) NOT NULL,
260 file VARCHAR( 65535 ) NOT NULL,
261 line INT NOT NULL DEFAULT 0,
262 created_at DATETIME,
263 UNIQUE KEY id ( id )
264 ) {$charset_collate}";
265
266 $wpdb->query( $sql );
267 }
268 }
269
270 /**
271 * 無効化
272 *
273 * @return void
274 */
275 public function deactivate(): void {
276 $this->config->set( $this->get_feature_key(), 'f' );
277 $this->config->save();
278 }
279 }
280