PluginProbe
Sessions / 2.6.1
Sessions v2.6.1
2.1.0 2.10.0 2.11.0 2.12.0 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.2.0 2.3.0 2.3.1 2.4.0 2.4.1 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.1.0 3.1.1 All 39 releases
sessions / includes / features / class-wpcli.php

class-wpcli.php in Sessions 2.6.1, at includes/features/class-wpcli.php

744 lines 21.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WP-CLI for Sessions.
4 *
5 * Adds WP-CLI commands to Sessions
6 *
7 * @package Features
8 * @author Pierre Lannoy <https://pierre.lannoy.fr/>.
9 * @since 1.0.0
10 */
11
12 namespace POSessions\Plugin\Feature;
13
14 use POSessions\System\Environment;
15
16 use POSessions\System\Option;
17 use POSessions\System\Markdown;
18 use POSessions\Plugin\Feature\Analytics;
19 use POSessions\Plugin\Feature\Schema;
20 use POSessions\System\Session;
21 use POSessions\System\Timezone;
22 use POSessions\System\GeoIP;
23 use POSessions\System\User;
24 use POSessions\System\IP;
25 use POSessions\System\UserAgent;
26 use POSessions\System\Date;
27 use POSessions\System\EmojiFlag;
28 use Spyc;
29
30 /**
31 * Manages users' sessions and get details about their use.
32 *
33 * @package Features
34 * @author Pierre Lannoy <https://pierre.lannoy.fr/>.
35 * @since 1.0.0
36 */
37 class Wpcli {
38
39 /**
40 * List of exit codes.
41 *
42 * @since 1.0.0
43 * @var array $exit_codes Exit codes.
44 */
45 private $exit_codes = [
46 0 => 'operation successful.',
47 1 => 'unrecognized setting.',
48 2 => 'unrecognized action.',
49 3 => 'analytics are disabled.',
50 4 => 'unrecognized mode.',
51 5 => 'user doesn\'t exist.',
52 255 => 'unknown error.',
53 ];
54
55 /**
56 * Write ids as clean stdout.
57 *
58 * @param array $ids The ids.
59 * @param string $field Optional. The field to output.
60 * @since 1.0.0
61 */
62 private function write_ids( $ids, $field = '' ) {
63 $result = '';
64 $last = end( $ids );
65 foreach ( $ids as $key => $id ) {
66 if ( '' === $field ) {
67 $result .= $key;
68 } else {
69 $result .= $id[$field];
70 }
71 if ( $id !== $last ) {
72 $result .= ' ';
73 }
74 }
75 // phpcs:ignore
76 fwrite( STDOUT, $result );
77 }
78
79 /**
80 * Write an error.
81 *
82 * @param integer $code Optional. The error code.
83 * @param boolean $stdout Optional. Clean stdout output.
84 * @since 1.0.0
85 */
86 private function error( $code = 255, $stdout = false ) {
87 if ( \WP_CLI\Utils\isPiped() ) {
88 // phpcs:ignore
89 fwrite( STDOUT, '' );
90 // phpcs:ignore
91 exit( $code );
92 } elseif ( $stdout ) {
93 // phpcs:ignore
94 fwrite( STDERR, ucfirst( $this->exit_codes[ $code ] ) );
95 // phpcs:ignore
96 exit( $code );
97 } else {
98 \WP_CLI::error( $this->exit_codes[ $code ] );
99 }
100 }
101
102 /**
103 * Write an error from a WP_Error object.
104 *
105 * @param \WP_Error $err The error object.
106 * @param boolean $stdout Optional. Clean stdout output.
107 * @since 1.0.0
108 */
109 private function error_from_object( $err, $stdout = false ) {
110 $msg = $this->exit_codes[255];
111 if ( is_wp_error( $err ) ) {
112 $msg = $err->get_error_message();
113 }
114 if ( \WP_CLI\Utils\isPiped() ) {
115 // phpcs:ignore
116 fwrite( STDOUT, '' );
117 // phpcs:ignore
118 exit( 255 );
119 } elseif ( $stdout ) {
120 // phpcs:ignore
121 fwrite( STDERR, ucfirst( $msg ) );
122 // phpcs:ignore
123 exit( 255 );
124 } else {
125 \WP_CLI::error( $msg );
126 }
127 }
128
129 /**
130 * Write a warning.
131 *
132 * @param string $msg The message.
133 * @param string $result Optional. The result.
134 * @param boolean $stdout Optional. Clean stdout output.
135 * @since 1.0.0
136 */
137 private function warning( $msg, $result = '', $stdout = false ) {
138 if ( \WP_CLI\Utils\isPiped() || $stdout ) {
139 // phpcs:ignore
140 fwrite( STDOUT, $result );
141 } else {
142 \WP_CLI::warning( $msg );
143 }
144 }
145
146 /**
147 * Write a success.
148 *
149 * @param string $msg The message.
150 * @param string $result Optional. The result.
151 * @param boolean $stdout Optional. Clean stdout output.
152 * @since 1.0.0
153 */
154 private function success( $msg, $result = '', $stdout = false ) {
155 if ( \WP_CLI\Utils\isPiped() || $stdout ) {
156 // phpcs:ignore
157 fwrite( STDOUT, $result );
158 } else {
159 \WP_CLI::success( $msg );
160 }
161 }
162
163 /**
164 * Write a wimple line.
165 *
166 * @param string $msg The message.
167 * @param string $result Optional. The result.
168 * @param boolean $stdout Optional. Clean stdout output.
169 * @since 1.0.0
170 */
171 private function line( $msg, $result = '', $stdout = false ) {
172 if ( \WP_CLI\Utils\isPiped() || $stdout ) {
173 // phpcs:ignore
174 fwrite( STDOUT, $result );
175 } else {
176 \WP_CLI::line( $msg );
177 }
178 }
179
180 /**
181 * Write a wimple log line.
182 *
183 * @param string $msg The message.
184 * @param boolean $stdout Optional. Clean stdout output.
185 * @since 1.0.0
186 */
187 private function log( $msg, $stdout = false ) {
188 if ( ! \WP_CLI\Utils\isPiped() && ! $stdout ) {
189 \WP_CLI::log( $msg );
190 }
191 }
192
193 /**
194 * Get params from command line.
195 *
196 * @param array $args The command line parameters.
197 * @return array The true parameters.
198 * @since 1.0.0
199 */
200 private function get_params( $args ) {
201 $result = '';
202 if ( array_key_exists( 'settings', $args ) ) {
203 $result = \json_decode( $args['settings'], true );
204 }
205 if ( ! $result || ! is_array( $result ) ) {
206 $result = [];
207 }
208 return $result;
209 }
210
211 /**
212 * Get Sessions details and operation modes.
213 *
214 * ## EXAMPLES
215 *
216 * wp sessions status
217 *
218 *
219 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
220 *
221 */
222 public function status( $args, $assoc_args ) {
223 \WP_CLI::line( sprintf( '%s is running.', Environment::plugin_version_text() ) );
224 switch ( Option::network_get( 'rolemode' ) ) {
225 case -1:
226 \WP_CLI::line( 'Operation mode: no role limitation.' );
227 break;
228 case 0:
229 \WP_CLI::line( 'Operation mode: role limitation with cumulative privileges.' );
230 break;
231 case 1:
232 \WP_CLI::line( 'Operation mode: role limitation with least privileges.' );
233 break;
234
235 }
236 if ( Option::network_get( 'forceip' ) ) {
237 \WP_CLI::line( 'IP override: enabled.' );
238 } else {
239 \WP_CLI::line( 'IP override: disabled.' );
240 }
241 if ( Option::network_get( 'followip' ) ) {
242 \WP_CLI::line( 'IP follow-up: enabled.' );
243 } else {
244 \WP_CLI::line( 'IP follow-up: disabled.' );
245 }
246 if ( Option::network_get( 'analytics' ) ) {
247 \WP_CLI::line( 'Analytics: enabled.' );
248 } else {
249 \WP_CLI::line( 'Analytics: disabled.' );
250 }
251 if ( Option::network_get( 'metrics' ) ) {
252 \WP_CLI::line( 'Metrics collation: enabled.' );
253 } else {
254 \WP_CLI::line( 'Metrics collation: disabled.' );
255 }
256 if ( \DecaLog\Engine::isDecalogActivated() ) {
257 \WP_CLI::line( 'Logging support: ' . \DecaLog\Engine::getVersionString() . '.');
258 } else {
259 \WP_CLI::line( 'Logging support: no.' );
260 }
261 $geo = new GeoIP();
262 if ( $geo->is_installed() ) {
263 \WP_CLI::line( 'IP information support: yes (' . $geo->get_full_name() . ').');
264 } else {
265 \WP_CLI::line( 'IP information support: no.' );
266 }
267 if ( defined( 'PODD_VERSION' ) ) {
268 \WP_CLI::line( 'Device detection support: yes (Device Detector v' . PODD_VERSION . ').');
269 } else {
270 \WP_CLI::line( 'Device detection support: no.' );
271 }
272 }
273
274 /**
275 * Modify Sessions main settings.
276 *
277 * ## OPTIONS
278 *
279 * <enable|disable>
280 * : The action to take.
281 *
282 * <analytics|ip-override|ip-follow|metrics|kill-on-reset>
283 * : The setting to change.
284 *
285 * [--yes]
286 * : Answer yes to the confirmation message, if any.
287 *
288 * [--stdout]
289 * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by Sessions.
290 *
291 * ## EXAMPLES
292 *
293 * wp sessions settings disable analytics --yes
294 *
295 *
296 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
297 *
298 */
299 public function settings( $args, $assoc_args ) {
300 $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false );
301 $action = isset( $args[0] ) ? (string) $args[0] : '';
302 $setting = isset( $args[1] ) ? (string) $args[1] : '';
303 switch ( $action ) {
304 case 'enable':
305 switch ( $setting ) {
306 case 'analytics':
307 Option::network_set( 'analytics', true );
308 $this->success( 'analytics are now activated.', '', $stdout );
309 break;
310 case 'ip-follow':
311 Option::network_set( 'followip', true );
312 $this->success( 'IP follow-up is now activated.', '', $stdout );
313 break;
314 case 'ip-override':
315 Option::network_set( 'forceip', true );
316 $this->success( 'IP override is now activated.', '', $stdout );
317 break;
318 case 'metrics':
319 Option::network_set( 'metrics', true );
320 $this->success( 'metrics collation is now activated.', '', $stdout );
321 break;
322 case 'kill-on-reset':
323 Option::network_set( 'killonreset', true );
324 $this->success( 'users\' sessions will now be deleted after password resets.', '', $stdout );
325 break;
326 default:
327 $this->error( 1, $stdout );
328 }
329 break;
330 case 'disable':
331 switch ( $setting ) {
332 case 'analytics':
333 \WP_CLI::confirm( 'Are you sure you want to deactivate analytics?', $assoc_args );
334 Option::network_set( 'analytics', false );
335 $this->success( 'analytics are now deactivated.', '', $stdout );
336 break;
337 case 'ip-follow':
338 \WP_CLI::confirm( 'Are you sure you want to deactivate IP follow-up?', $assoc_args );
339 Option::network_set( 'followip', false );
340 $this->success( 'IP follow-up is now deactivated.', '', $stdout );
341 break;
342 case 'ip-override':
343 \WP_CLI::confirm( 'Are you sure you want to deactivate IP override?', $assoc_args );
344 Option::network_set( 'forceip', false );
345 $this->success( 'IP override is now deactivated.', '', $stdout );
346 break;
347 case 'metrics':
348 \WP_CLI::confirm( 'Are you sure you want to deactivate metrics collation?', $assoc_args );
349 Option::network_set( 'metrics', false );
350 $this->success( 'metrics collation is now deactivated.', '', $stdout );
351 break;
352 case 'kill-on-reset':
353 \WP_CLI::confirm( 'Are you sure you want to deactivate sessions deletion after password resets?', $assoc_args );
354 Option::network_set( 'killonreset', false );
355 $this->success( 'users\' sessions will now be left untouched after password resets.', '', $stdout );
356 break;
357 default:
358 $this->error( 1, $stdout );
359 }
360 break;
361 default:
362 $this->error( 2, $stdout );
363 }
364 }
365
366 /**
367 * Modify Sessions operation mode.
368 *
369 * ## OPTIONS
370 *
371 * <set>
372 * : The action to take.
373 *
374 * <none|cumulative|least>
375 * : The mode to set.
376 *
377 * [--yes]
378 * : Answer yes to the confirmation message, if any.
379 *
380 * [--stdout]
381 * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by Sessions.
382 *
383 * ## EXAMPLES
384 *
385 * wp sessions mode set none --yes
386 *
387 *
388 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
389 *
390 */
391 public function mode( $args, $assoc_args ) {
392 $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false );
393 $action = isset( $args[0] ) ? (string) $args[0] : '';
394 $mode = isset( $args[1] ) ? (string) $args[1] : '';
395 switch ( $action ) {
396 case 'set':
397 switch ( $mode ) {
398 case 'none':
399 \WP_CLI::confirm( 'Are you sure you want to deactivate role-mode?', $assoc_args );
400 Option::network_set( 'rolemode', -1 );
401 $this->success( 'operation mode is now "no role limitation".', '', $stdout );
402 break;
403 case 'cumulative':
404 Option::network_set( 'rolemode', 0 );
405 $this->success( 'operation mode is now "role limitation with cumulative privileges".', '', $stdout );
406 break;
407 case 'least':
408 Option::network_set( 'rolemode', 1 );
409 $this->success( 'operation mode is now "role limitation with least privileges".', '', $stdout );
410 break;
411 default:
412 $this->error( 4, $stdout );
413 break;
414 }
415 break;
416 default:
417 $this->error( 2, $stdout );
418 }
419 }
420
421 /**
422 * Get sessions analytics for today.
423 *
424 * ## OPTIONS
425 *
426 * [--site=<site_id>]
427 * : The site for which to display analytics. May be 0 (all network) or an integer site id. Only useful with multisite environments.
428 * ---
429 * default: 0
430 * ---
431 *
432 * [--format=<format>]
433 * : Set the output format. Note if json is chosen: full metadata is outputted too.
434 * ---
435 * default: table
436 * options:
437 * - table
438 * - json
439 * - csv
440 * - yaml
441 * - count
442 * ---
443 *
444 * [--stdout]
445 * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by Sessions.
446 *
447 * ## EXAMPLES
448 *
449 * wp sessions analytics
450 *
451 *
452 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
453 *
454 */
455 public function analytics( $args, $assoc_args ) {
456 $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false );
457 $site = (int) \WP_CLI\Utils\get_flag_value( $assoc_args, 'site', 0 );
458 $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' );
459 if ( ! Option::network_get( 'analytics' ) ) {
460 $this->error( 3, $stdout );
461 }
462 $analytics = Analytics::get_status_kpi_collection( [ 'site_id' => $site ] );
463 $result = [];
464 if ( array_key_exists( 'data', $analytics ) ) {
465 foreach ( $analytics['data'] as $kpi ) {
466 $item = [];
467 $item['kpi'] = $kpi['name'];
468 $item['description'] = $kpi['description'];
469 $item['value'] = $kpi['value']['human'];
470 if ( array_key_exists( 'ratio', $kpi ) && isset( $kpi['ratio'] ) ) {
471 $item['ratio'] = $kpi['ratio']['percent'] . '%';
472 } else {
473 $item['ratio'] = '-';
474 }
475 $item['variation'] = ( 0 < $kpi['variation']['percent'] ? '+' : '' ) . (string) $kpi['variation']['percent'] . '%';
476 $result[] = $item;
477 }
478 }
479 if ( 'json' === $format ) {
480 $detail = wp_json_encode( $analytics );
481 $this->line( $detail, $detail, $stdout );
482 } elseif ( 'yaml' === $format ) {
483 unset( $analytics['assets'] );
484 $detail = Spyc::YAMLDump( $analytics, true, true, true );
485 $this->line( $detail, $detail, $stdout );
486 } else {
487 \WP_CLI\Utils\format_items( $assoc_args['format'], $result, [ 'kpi', 'description', 'value', 'ratio', 'variation' ] );
488 }
489 }
490
491 /**
492 * Get information on exit codes.
493 *
494 * ## OPTIONS
495 *
496 * <list>
497 * : The action to take.
498 * ---
499 * options:
500 * - list
501 * ---
502 *
503 * [--format=<format>]
504 * : Allows overriding the output of the command when listing exit codes.
505 * ---
506 * default: table
507 * options:
508 * - table
509 * - json
510 * - csv
511 * - yaml
512 * - ids
513 * - count
514 * ---
515 *
516 * ## EXAMPLES
517 *
518 * Lists available exit codes:
519 * + wp sessions exitcode list
520 * + wp sessions exitcode list --format=json
521 *
522 *
523 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
524 *
525 */
526 public function exitcode( $args, $assoc_args ) {
527 $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false );
528 $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' );
529 $action = isset( $args[0] ) ? $args[0] : 'list';
530 $codes = [];
531 foreach ( $this->exit_codes as $key => $msg ) {
532 $codes[ $key ] = [ 'code' => $key, 'meaning' => ucfirst( $msg ) ];
533 }
534 switch ( $action ) {
535 case 'list':
536 if ( 'ids' === $format ) {
537 $this->write_ids( $codes );
538 } else {
539 \WP_CLI\Utils\format_items( $format, $codes, [ 'code', 'meaning' ] );
540 }
541 break;
542 }
543 }
544
545 /**
546 * Get the WP-CLI help file.
547 *
548 * @param array $attributes 'style' => 'markdown', 'html'.
549 * 'mode' => 'raw', 'clean'.
550 * @return string The output of the shortcode, ready to print.
551 * @since 1.0.0
552 */
553 public static function sc_get_helpfile( $attributes ) {
554 $md = new Markdown();
555 return $md->get_shortcode( 'WP-CLI.md', $attributes );
556 }
557
558 /**
559 * Manage active sessions.
560 *
561 * ## OPTIONS
562 *
563 * <list|kill>
564 * : The action to take.
565 * ---
566 * options:
567 * - list
568 * - kill
569 * ---
570 *
571 * [<user_id>]
572 * : The id of the user to perform an action/search on. If nothing is specified, it's on all users.
573 *
574 * [--detail=<detail>]
575 * : The details of the output when listing application passwords.
576 * ---
577 * default: short
578 * options:
579 * - short
580 * - full
581 * ---
582 *
583 * [--format=<format>]
584 * : Allows overriding the output of the command when listing application passwords. Note if json or yaml is chosen: full metadata is outputted too.
585 * ---
586 * default: table
587 * options:
588 * - table
589 * - json
590 * - csv
591 * - yaml
592 * - ids
593 * - count
594 * ---
595 *
596 * [--yes]
597 * : Answer yes to the confirmation message, if any.
598 *
599 * [--stdout]
600 * : Use clean STDOUT output to use results in scripts. Unnecessary when piping commands because piping is detected by Sessions.
601 *
602 * ## EXAMPLES
603 *
604 * List active sessions:
605 * + wp sessions active list
606 * + wp sessions active list 1
607 *
608 * Kill active sessions:
609 * + wp sessions active kill
610 * + wp sessions active kill 1 --yes
611 *
612 *
613 * === For other examples and recipes, visit https://github.com/Pierre-Lannoy/wp-sessions/blob/master/WP-CLI.md ===
614 *
615 */
616 public function active( $args, $assoc_args ) {
617 $stdout = \WP_CLI\Utils\get_flag_value( $assoc_args, 'stdout', false );
618 $format = \WP_CLI\Utils\get_flag_value( $assoc_args, 'format', 'table' );
619 $detail = \WP_CLI\Utils\get_flag_value( $assoc_args, 'detail', 'short' );
620 $id = '';
621 $action = isset( $args[0] ) ? $args[0] : 'list';
622 if ( isset( $args[1] ) ) {
623 $id = (int) $args[1];
624 if ( false === get_userdata( $id ) ) {
625 $this->error( 5, $stdout );
626 }
627 }
628 switch ( $action ) {
629 case 'list':
630 $sessions = [];
631 $list = [];
632 $tz = Timezone::network_get();
633 if ( '' !== $id ) {
634 $list[] = [
635 'user_id' => $id,
636 'meta_value' => Session::get_user_sessions( $id ),
637 ];
638 } else {
639 $list = Session::get_all_sessions();
640 }
641 foreach ( $list as $user ) {
642 if ( array_key_exists( 'meta_value', $user ) && is_array( $user['meta_value'] ) ) {
643 foreach ( $user['meta_value'] as $token => $session ) {
644 $sessions[ $token ]['token'] = $token;
645 $sessions[ $token ]['user-id'] = (int) $user['user_id'];
646 $sessions[ $token ]['user'] = User::get_user_string( $user['user_id'] );
647 if ( array_key_exists( 'expiration', $session ) ) {
648 $datetime = new \DateTime( date( 'Y-m-d H:i:s', $session['expiration'] ) );
649 $datetime->setTimezone( $tz );
650 $sessions[ $token ]['standard exp'] = $datetime->format( 'Y-m-d H:i' );
651 } else {
652 $sessions[ $token ]['standard exp'] = 'never';
653 }
654 if ( array_key_exists( 'login', $session ) ) {
655 $datetime = new \DateTime( date( 'Y-m-d H:i:s', $session['login'] ) );
656 $datetime->setTimezone( $tz );
657 $sessions[ $token ]['login'] = $datetime->format( 'Y-m-d H:i' );
658 } else {
659 $sessions[ $token ]['login'] = 'never';
660 }
661 if ( array_key_exists( 'session_idle', $session ) ) {
662 $value = $session['session_idle'] - time();
663 if ( 0 === $value ) {
664 $sessions[ $token ]['idle exp'] = 'now';
665 } else {
666 $value = 0 - $value;
667 if ( $value < 72 * HOUR_IN_SECONDS ) {
668 $sessions[ $token ]['idle exp'] = implode( ', ', Date::get_age_array_from_seconds( $value, true, true ) );
669 } else {
670 $sessions[ $token ]['idle exp'] = (int) round( $value / ( 24 * HOUR_IN_SECONDS ), 0 ) . 'days';
671 }
672 }
673 } else {
674 $sessions[ $token ]['idle exp'] = '-';
675 }
676 $sessions[ $token ]['ip'] = $session['ip'];
677 if ( 'full' === $detail ) {
678 $sessions[ $token ]['device'] = '-';
679 $sessions[ $token ]['os'] = '-';
680 $sessions[ $token ]['client'] = '-';
681 if ( array_key_exists( 'ua', $session ) ) {
682 $device = UserAgent::get( $session['ua'] );
683 $sessions[ $token ]['device'] = ( '' !== $device->brand_name ? $device->brand_name : esc_html__( 'Generic', 'sessions' ) ) . ( '' !== $device->model_name ? ' ' . $device->model_name : '' );
684 $sessions[ $token ]['os'] = $device->os_name . ( '' !== $device->os_version ? ' ' . $device->os_version : '' );
685 $sessions[ $token ]['client'] = ( '' !== $device->client_name ? $device->client_name : $device->client_full_type );
686 if ( $device->client_is_browser ) {
687 $sessions[ $token ]['client'] = $device->client_name . ( '' !== $device->client_version ? ' ' . $device->client_version : '' );
688 }
689 }
690 }
691 }
692 }
693 }
694 usort(
695 $sessions,
696 function ( $a, $b ) {
697 return strcmp( strtolower( $a[ 'user' ] ), strtolower( $b[ 'user' ] ) );
698 }
699 );
700 if ( 'full' === $detail ) {
701 $detail = [ 'user', 'ip', 'device', 'os', 'client', 'login', 'idle exp', 'standard exp' ];
702 } else {
703 $detail = [ 'user', 'ip', 'login', 'idle exp', 'standard exp' ];
704 }
705 if ( 'ids' === $format ) {
706 $this->write_ids( $sessions, 'uuid' );
707 } elseif ( 'yaml' === $format ) {
708 $details = Spyc::YAMLDump( $sessions, true, true, true );
709 $this->line( $details, $details, $stdout );
710 } elseif ( 'json' === $format ) {
711 $details = wp_json_encode( $sessions );
712 $this->line( $details, $details, $stdout );
713 } else {
714 \WP_CLI\Utils\format_items( $format, $sessions, $detail );
715 }
716 break;
717 case 'kill':
718 if ( '' === $id ) {
719 \WP_CLI::confirm( 'Are you sure you want to kill all sessions for all users?', $assoc_args );
720 $cnt = Session::delete_all_sessions();
721 } else {
722 \WP_CLI::confirm( 'Are you sure you want to kill all sessions for this user?', $assoc_args );
723 $cnt = Session::delete_all_sessions( $id );
724 }
725 if ( false === $cnt ) {
726 $this->error( 255, $stdout );
727 } else {
728 if ( 0 === (int) $cnt ) {
729 $this->success( 'no session to kill.', 0, $stdout );
730 } else {
731 $this->success( $cnt . ' session(s) killed.', $cnt, $stdout );
732 }
733 }
734 break;
735 }
736 }
737
738 }
739
740 add_shortcode( 'pose-wpcli', [ 'POSessions\Plugin\Feature\Wpcli', 'sc_get_helpfile' ] );
741
742 if ( defined( 'WP_CLI' ) && WP_CLI ) {
743 \WP_CLI::add_command( 'sessions', 'POSessions\Plugin\Feature\Wpcli' );
744 }