PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 6.3.0
Defender Security – Malware Scanner, Login Security & Firewall v6.3.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
← All changes | src/model/class-notification.php +85 -24 5.3.1 → 6.3.0 View file →
@@ -93,12 +93,11 @@
93 93 /**
94 94 * This is for when user select report as monthly, we will have the day number, instead of text.
95 95 *
96 96 * @var int
97 - * @sanitize_text_field
98 97 * @defender_property
99 98 */
100 - public $day_n;
99 + public int $day_n = 1;
101 100
102 101 /**
103 102 * Same as $day.
104 103 *
@@ -163,17 +162,25 @@
163 162 *
164 163 * @return array
165 164 */
166 165 protected function get_default_user(): array {
166 + if ( ! is_user_logged_in() ) {
167 + return array();
168 + }
169 +
167 170 $user_id = get_current_user_id();
168 171
172 + $email = $this->get_current_user_email( $user_id );
173 +
169 174 return array(
170 - 'name' => $this->get_user_display( $user_id ),
171 - 'id' => $user_id,
172 - 'email' => $this->get_current_user_email( $user_id ),
173 - 'role' => $this->get_current_user_role( $user_id ),
174 - 'avatar' => get_avatar_url( $this->get_current_user_email( $user_id ) ),
175 - 'status' => self::USER_SUBSCRIBED,
175 + $email => array(
176 + 'name' => $this->get_user_display( $user_id ),
177 + 'id' => $user_id,
178 + 'email' => $email,
179 + 'role' => $this->get_current_user_role( $user_id ),
180 + 'avatar' => get_avatar_url( $email ),
181 + 'status' => self::USER_SUBSCRIBED,
182 + ),
176 183 );
177 184 }
178 185
179 186 /**
@@ -236,9 +243,9 @@
236 243 }
237 244
238 245 // Create estimate object.
239 246 $est = new DateTime( 'now', wp_timezone() );
240 - if ( ! empty( $this->last_sent ) ) {
247 + if ( $this->last_sent > 0 ) {
241 248 // set the timestamp of previous.
242 249 $est->setTimestamp( $this->last_sent );
243 250 }
244 251
@@ -244,9 +251,10 @@
244 251
245 252 // Est should be set as the last send. Create now timestamp.
246 253 $now = new DateTime( 'now', wp_timezone() );
247 254 $interval = DateInterval::createFromDateString( (string) $est->getOffset() . 'seconds' );
248 - [ $hour, $min ] = explode( ':', $this->time );
255 + $time_parts = array_pad( explode( ':', (string) $this->time ), 2, 0 );
256 + [ $hour, $min ] = $time_parts;
249 257 $hour = (int) $hour;
250 258 $min = (int) $min;
251 259 switch ( $this->frequency ) {
252 260 case 'daily':
@@ -259,8 +267,11 @@
259 267 $est->setTime( $hour, $min, 0 );
260 268 }
261 269 break;
262 270 case 'weekly':
271 + if ( '' === $this->day || null === $this->day ) {
272 + break;
273 + }
263 274 $est->modify( 'this ' . $this->day );
264 275 $est->add( $interval );
265 276 $est->setTime( $hour, $min, 0 );
266 277 while ( $est->getTimestamp() < $now->getTimestamp() ) {
@@ -270,16 +281,18 @@
270 281 break;
271 282 case 'monthly':
272 283 // We will need to check if the date is passed today, if not, use this, if yes, then queue for next month.
273 284 $est->setDate( (int) $est->format( 'Y' ), (int) $est->format( 'm' ), 1 );
274 - if ( 31 === (int) $this->day_n ) {
275 - $this->day_n = (int) $est->format( 't' );
276 - }
277 - $est->add( new DateInterval( 'P' . ( $this->day_n - 1 ) . 'D' ) );
285 + // Clamp day_n to a valid day in the current month.
286 + $day_n = max( 1, min( $this->day_n, (int) $est->format( 't' ) ) );
287 + $est->add( new DateInterval( 'P' . ( $day_n - 1 ) . 'D' ) );
278 288 $est->setTime( $hour, $min, 0 );
279 289 while ( $est->getTimestamp() < $now->getTimestamp() ) {
280 - // Already over, move to next month.
281 - $est->modify( 'next month' );
290 + // Already over, move to first day of next month.
291 + $est->modify( 'first day of next month' );
292 + // Re-clamp for the new month's length.
293 + $day_n = max( 1, min( $this->day_n, (int) $est->format( 't' ) ) );
294 + $est->add( new DateInterval( 'P' . ( $day_n - 1 ) . 'D' ) );
282 295 $est->setTime( $hour, $min, 0 );
283 296 }
284 297 break;
285 298 }
@@ -307,9 +320,9 @@
307 320 */
308 321 public function check_active_status(): bool {
309 322 // Exception after migrating Scheduled scanning to Scan settings.
310 323 if ( Malware_Report::SLUG === $this->slug
311 - && true === ( new \WP_Defender\Model\Setting\Scan() )->scheduled_scanning
324 + && ( new \WP_Defender\Model\Setting\Scan() )->is_enabled_scheduled_scanning()
312 325 ) {
313 326 return true;
314 327 }
315 328
@@ -370,16 +383,17 @@
370 383 if ( 'notification' === $this->type ) {
371 384 return $for_hub ? false : esc_html__( 'Never', 'defender-security' );
372 385 }
373 386
387 + $est_timestamp = ! is_int( $this->est_timestamp ) ? (int) $this->est_timestamp : $this->est_timestamp;
374 388 if ( $for_hub ) {
375 389 return $this->check_active_status()
376 - ? $this->persistent_hub_datetime_format( $this->est_timestamp )
390 + ? $this->persistent_hub_datetime_format( $est_timestamp )
377 391 : false;
378 392 } elseif ( $this->check_active_status() ) {
379 393 $format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
380 394 $date = new DateTime( 'now', wp_timezone() );
381 - $date->setTimestamp( (int) $this->est_timestamp );
395 + $date->setTimestamp( $est_timestamp );
382 396
383 397 return $date->format( $format );
384 398 } else {
385 399 return esc_html__( 'Never', 'defender-security' );
@@ -391,9 +405,9 @@
391 405 */
392 406 protected function after_validate(): void {
393 407 foreach ( $this->out_house_recipients as $recipient ) {
394 408 $recipient['email'] = trim( $recipient['email'] );
395 - if ( empty( $recipient['email'] ) ) {
409 + if ( '' === $recipient['email'] ) {
396 410 continue;
397 411 }
398 412 if ( ! filter_var( $recipient['email'], FILTER_VALIDATE_EMAIL ) ) {
399 413 /* translators: %s: Email address of a recipient. */
@@ -407,9 +421,9 @@
407 421 *
408 422 * @return void
409 423 */
410 424 public function save(): void {
411 - if ( empty( $this->last_sent ) ) {
425 + if ( $this->last_sent <= 0 ) {
412 426 $this->last_sent = time();
413 427 }
414 428 $next_run = $this->get_next_run();
415 429 if ( is_object( $next_run ) ) {
@@ -432,8 +446,31 @@
432 446 return $data;
433 447 }
434 448
435 449 /**
450 + * Prepare data for persistence.
451 + *
452 + * Recipients are indexed by email in memory (see after_load()), so re-index them back to
453 + * sequential arrays before storing. Otherwise they are JSON-encoded as objects, which on
454 + * downgrade breaks Defender 5 with "all_subscribers.slice is not a function".
455 + *
456 + * @param array $data The data array to import values from.
457 + *
458 + * @return array
459 + */
460 + protected function prepare_data( $data = array() ): array {
461 + $data = parent::prepare_data( $data );
462 +
463 + foreach ( array( 'in_house_recipients', 'out_house_recipients', 'all_subscribers' ) as $key ) {
464 + if ( isset( $data[ $key ] ) && is_array( $data[ $key ] ) ) {
465 + $data[ $key ] = array_values( $data[ $key ] );
466 + }
467 + }
468 +
469 + return $data;
470 + }
471 +
472 + /**
436 473 * Overrided method to manipulate user details dynamically.
437 474 */
438 475 protected function after_load(): void {
439 476 $in_house_recipients = array();
@@ -442,18 +479,42 @@
442 479 $id = $recipient['id'];
443 480 $user_data = get_userdata( $id );
444 481
445 482 if ( $user_data instanceof WP_User ) {
446 - $in_house_recipients[] = array(
483 + $in_house_recipients[ $user_data->user_email ] = array(
447 484 'name' => $user_data->display_name,
448 485 'id' => $user_data->ID,
449 486 'email' => $user_data->user_email,
450 487 'role' => $this->get_first_user_role( $user_data ),
451 488 'avatar' => get_avatar_url( $id ),
452 - 'status' => $recipient['status'],
489 + 'status' => $recipient['status'] ?? '',
453 490 );
454 491 }
455 492 }
456 493
457 - $this->in_house_recipients = $in_house_recipients;
494 + $this->in_house_recipients = $in_house_recipients;
495 + $this->out_house_recipients = $this->get_email_indexed_recipients( $this->out_house_recipients );
496 + }
497 +
498 + /**
499 + * Indexes recipients by email.
500 + *
501 + * @param array $recipients Recipients list.
502 + *
503 + * @return array
504 + */
505 + private function get_email_indexed_recipients( array $recipients ): array {
506 + $email_indexed_recipients = array();
507 +
508 + foreach ( $recipients as $recipient ) {
509 + if ( ! isset( $recipient['email'] ) ) {
510 + continue;
511 + }
512 +
513 + $email = trim( $recipient['email'] );
514 + $recipient['email'] = $email;
515 + $email_indexed_recipients[ $email ] = $recipient;
516 + }
517 +
518 + return $email_indexed_recipients;
458 519 }
459 520 }