PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.0.1
Defender Security – Malware Scanner, Login Security & Firewall v3.0.1
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
defender-security / src / model / notification.php

notification.php in Defender Security – Malware Scanner, Login Security & Firewall 3.0.1, at src/model/notification.php

389 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WP_Defender\Model;
4
5 use Calotes\Model\Setting;
6 use WP_Defender\Traits\Formats;
7 use WP_Defender\Traits\User;
8
9 /**
10 *
11 * Class Notification
12 *
13 * @package WP_Defender\Model
14 */
15 abstract class Notification extends Setting {
16 use User, Formats;
17
18 public const STATUS_DISABLED = 'disabled', STATUS_ACTIVE = 'enabled';
19 public const USER_SUBSCRIBED = 'subscribed', USER_SUBSCRIBE_WAITING = 'waiting', USER_SUBSCRIBE_CANCELED = 'cancelled', USER_SUBSCRIBE_NA = 'na';
20
21 /**
22 * Notification title.
23 *
24 * @var string
25 * @defender_property
26 * @sanitize_text_field
27 */
28 public $title;
29
30 /**
31 * Unique ID for this notification.
32 *
33 * @var string
34 * @defender_property
35 * @sanitize_text_field
36 */
37 public $slug;
38
39 /**
40 * @var string
41 * @defender_property
42 */
43 public $description;
44
45 /**
46 * This is the status of the current notification, can be active or disabled.
47 *
48 * @var string
49 * @defender_property
50 * @sanitize_text_field
51 */
52 public $status;
53
54 /**
55 * This is notification or report.
56 *
57 * @var string
58 * @defender_property
59 * @sanitize_text_field
60 */
61 public $type;
62
63 /**
64 * Report sending frequency. Only when $type is report.
65 *
66 * @var string
67 * @defender_property
68 * @sanitize_text_field
69 */
70 public $frequency;
71
72 /**
73 * Report sending day. Only when $type is report.
74 *
75 * @var string
76 * @defender_property
77 * @sanitize_text_field
78 */
79 public $day;
80
81 /**
82 * This is for when user select report as monthly, we will have the day number, instead of text.
83 *
84 * @var int
85 * @sanitize_text_field
86 * @defender_property
87 */
88 public $day_n;
89
90 /**
91 * Same as $day.
92 *
93 * @var string
94 * @defender_property
95 * @sanitize_text_field
96 */
97 public $time;
98
99 /**
100 * Holding a list of site user ids, so when sending, we send though this list.
101 *
102 * @var array
103 * @defender_property
104 * @sanitize_text_field
105 */
106 public $in_house_recipients = array();
107
108 /**
109 * For additional users, this should contain a list of email and name.
110 *
111 * @var array
112 * @defender_property
113 * @sanitize_text_field
114 */
115 public $out_house_recipients = array();
116
117 /**
118 * This when we want to run the report/notification without any email sending.
119 *
120 * @var bool
121 * @defender_property
122 */
123 public $dry_run = false;
124
125 /**
126 * This is contains the meta settings of this notification.
127 *
128 * @var array
129 * @defender_property
130 */
131 public $configs = array();
132
133 /**
134 * Tracking.
135 *
136 * @var int
137 * @defender_property
138 */
139 public $last_sent = 0;
140
141 /**
142 * @var int
143 * @defender_property
144 */
145 public $est_timestamp;
146
147 /**
148 * Return the default user, we will use this if there is no user in the notification.
149 *
150 * @return array
151 */
152 protected function get_default_user() {
153 $user_id = get_current_user_id();
154
155 return array(
156 'name' => $this->get_user_display( $user_id ),
157 'id' => $user_id,
158 'email' => $this->get_current_user_email( $user_id ),
159 'role' => $this->get_current_user_role( $user_id ),
160 'avatar' => get_avatar_url( $this->get_current_user_email( $user_id ) ),
161 'status' => self::USER_SUBSCRIBED,
162 );
163 }
164
165 /**
166 * Check if the current moment is right for sending.
167 *
168 * @return bool|void
169 */
170 public function maybe_send() {
171 // @since 2.7.0 We can remove 'dry_run'-condition in the next version.
172 if ( true === $this->dry_run ) {
173 // No send, but need to track as sent, so we can requeue it.
174 if ( 'report' === $this->type ) {
175 $this->last_sent = $this->est_timestamp;
176 $this->est_timestamp = $this->get_next_run()->getTimestamp();
177 $this->save();
178 }
179
180 return;
181 }
182
183 if ( ! $this->check_active_status() ) {
184 return false;
185 }
186
187 if ( 'notification' === $this->type ) {
188 return true;
189 }
190
191 if ( 0 === $this->last_sent ) {
192 return false;
193 }
194
195 $now = new \DateTime( 'now', wp_timezone() );
196 $time = apply_filters( 'defender_current_time_for_report', $now );
197 // Testing.
198 if ( defined( 'WP_DEFENDER_TESTING' ) && true === constant( 'WP_DEFENDER_TESTING' ) ) {
199 return true;
200 }
201
202 return $time->getTimestamp() >= $this->est_timestamp;
203 }
204
205 /**
206 * @return \DateTime|false
207 * @throws \Exception
208 */
209 public function get_next_run() {
210 if ( 'notification' === $this->type ) {
211 return false;
212 }
213 if ( ! $this->check_active_status() ) {
214 return false;
215 }
216
217 // Create estimate object.
218 $est = new \DateTime( 'now', wp_timezone() );
219 if ( ! empty( $this->last_sent ) ) {
220 //set the timestamp of previous
221 $est->setTimestamp( $this->last_sent );
222 }
223
224 // Est should be set as the last send. Create now timestamp.
225 $now = new \DateTime( 'now', wp_timezone() );
226 $interval = \DateInterval::createFromDateString( (string) $est->getOffset() . 'seconds' );
227 [$hour, $min] = explode( ':', $this->time );
228 $hour = (int) $hour;
229 $min = (int) $min;
230 switch ( $this->frequency ) {
231 case 'daily':
232 // Set the time.
233 $est->add( $interval );
234 $est->setTime( $hour, $min, 0 );
235 // Convert to current timezone.
236 while ( $est->getTimestamp() < $now->getTimestamp() ) {
237 $est->add( new \DateInterval( 'P1D' ) );
238 $est->setTime( $hour, $min, 0 );
239 }
240 break;
241 case 'weekly':
242 $est->modify( 'this ' . $this->day );
243 $est->add( $interval );
244 $est->setTime( $hour, $min, 0 );
245 while ( $est->getTimestamp() < $now->getTimestamp() ) {
246 $est->modify( 'next ' . $this->day );
247 $est->setTime( $hour, $min, 0 );
248 }
249 break;
250 case 'monthly':
251 // We will need to check if the date is passed today, if not, use this, if yes, then queue for next month.
252 $est->setDate( $est->format( 'Y' ), $est->format( 'm' ), 1 );
253 if ( 31 === (int) $this->day_n ) {
254 $this->day_n = $est->format( 't' );
255 }
256 $est->add( new \DateInterval( 'P' . ( $this->day_n - 1 ) . 'D' ) );
257 $est->setTime( $hour, $min, 0 );
258 while ( $est->getTimestamp() < $now->getTimestamp() ) {
259 // Already over, move to next month.
260 $est->modify( 'next month' );
261 $est->setTime( $hour, $min, 0 );
262 }
263 break;
264 }
265
266 return $est;
267 }
268
269 /**
270 * We have multiple issues where the email keep sending for no reason, this for debugging later.
271 *
272 * @param string $email
273 */
274 public function save_log( $email ) {
275 $track = new Email_Track();
276 $track->timestamp = time();
277 $track->source = $this->slug;
278 $track->to = $email;
279 $track->save();
280 }
281
282 public function check_active_status() {
283 // Exception after migrating Scheduled scanning to Scan settings.
284 if ( 'malware-report' === $this->slug && true === ( new \WP_Defender\Model\Setting\Scan() )->scheduled_scanning ) {
285 return true;
286 }
287 return $this->status === self::STATUS_ACTIVE;
288 }
289
290 /**
291 * This will return the interval at string.
292 *
293 * @return string
294 */
295 public function to_string() {
296 if ( ! $this->check_active_status() ) {
297 return '-';
298 }
299 $date = new \DateTime( 'now', wp_timezone() );
300 $date->setTimestamp( $this->est_timestamp );
301 switch ( $this->frequency ) {
302 case 'daily':
303 return sprintf( __( '%s at %s', 'wpdef' ), ucfirst( $this->frequency ), $date->format( 'h:i A' ) );
304 case 'weekly':
305 return sprintf( __( '%s on %s at %s', 'wpdef' ), ucfirst( $this->frequency ), ucfirst( $this->day ), $date->format( 'h:i A' ) );
306 case 'monthly':
307 default:
308 return sprintf( __( '%s/%d, %s', 'wpdef' ), ucfirst( $this->frequency ), $this->day_n, $date->format( 'h:i A' ) );
309 }
310 }
311
312 /**
313 * @param false $for_hub
314 *
315 * @return false|string|void
316 * @throws \Exception
317 */
318 public function get_next_run_as_string( $for_hub = false ) {
319 if ( 'notification' === $this->type ) {
320
321 return $for_hub ? false : __( 'Never', 'wpdef' );
322 }
323
324 if ( $for_hub ) {
325 return $this->check_active_status()
326 ? $this->persistent_hub_datetime_format( $this->est_timestamp )
327 : false;
328 } else {
329 if ( $this->check_active_status() ) {
330 $format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
331 $date = new \DateTime( 'now', wp_timezone() );
332 $date->setTimestamp( $this->est_timestamp );
333
334 return $date->format( $format );
335 } else {
336 return __( 'Never', 'wpdef' );
337 }
338 }
339 }
340
341 /**
342 * We still need to validate the out house recipients email.
343 */
344 public function after_validate() {
345 foreach ( $this->out_house_recipients as $recipient ) {
346 $recipient['email'] = trim( $recipient['email'] );
347 if ( empty( $recipient['email'] ) ) {
348 continue;
349 }
350 if ( ! filter_var( $recipient['email'], FILTER_VALIDATE_EMAIL ) ) {
351 $this->errors[] = sprintf( __( 'Email %s is invalid format', 'wpdef' ), $recipient['email'] );
352 }
353 }
354 }
355
356 public function save() {
357 if ( empty( $this->last_sent ) ) {
358 $this->last_sent = time();
359 }
360 $next_run = $this->get_next_run();
361 if ( is_object( $next_run ) ) {
362 $this->est_timestamp = $next_run->getTimestamp();
363 }
364 parent::save();
365 }
366
367 /**
368 * Inject next run to parent function.
369 *
370 * @return array
371 */
372 public function export() {
373
374 $data = parent::export();
375
376 global $l10n;
377
378 if ( isset( $l10n['wpdef'] ) ) {
379 $data['title'] = __( $data['title'], 'wpdef' );
380 $data['description'] = __( $data['description'], 'wpdef' );
381 }
382
383 $data['next_run'] = $this->get_next_run_as_string();
384 $data['all_subscribers'] = array_merge( $this->in_house_recipients, $this->out_house_recipients );
385
386 return $data;
387 }
388 }
389