PluginProbe
WPTerm / 1.1.9
WPTerm v1.1.9
1.3 trunk 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 1.1.9 1.2
wpterm / wpterm.php

wpterm.php in WPTerm 1.1.9, at wpterm.php

1,196 lines 45.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: WPTerm
4 Plugin URI: https://nintechnet.com/bruandet/
5 Description: An xterm-like plugin to run non-interactive shell commands.
6 Author: Jerome Bruandet
7 Version: 1.1.9
8 Author URI: https://nintechnet.com/
9 Text Domain: wpterm
10 Domain Path: /languages
11 License: GPLv3 or later
12 Network: true
13 *
14 +=====================================================================+
15 | __ ______ _____ |
16 | \ \ / / _ \_ _|__ _ __ _ __ ___ |
17 | \ \ /\ / /| |_) || |/ _ \ '__| '_ ` _ \ |
18 | \ V V / | __/ | | __/ | | | | | | | |
19 | \_/\_/ |_| |_|\___|_| |_| |_| |_| |
20 | |
21 | (c) Jerome Bruandet ~ https://nintechnet.com/ |
22 +=====================================================================+
23 */
24 define( 'WPTERM_VERSION', '1.1.9' );
25
26 /* ================================================================== */
27
28 if (! defined( 'ABSPATH' ) ) { die( 'Forbidden' ); }
29
30 /* ================================================================== */
31
32 $null = __('An xterm-like plugin to run non-interactive shell commands.', 'wpterm');
33
34 /* ================================================================== */
35 // Force WP to load our translation files.
36
37 $wpterm_locale = array( 'fr_FR' );
38 $this_locale = get_locale();
39 if ( in_array( $this_locale, $wpterm_locale ) ) {
40 if ( file_exists( __DIR__ . "/languages/wpterm-{$this_locale}.mo" ) ) {
41 unload_textdomain( 'wpterm' );
42 load_textdomain( 'wpterm', __DIR__ . "/languages/wpterm-{$this_locale}.mo" );
43 }
44 }
45
46 /* ================================================================== */
47 // Start a session if the user is an admin and WPTerm password
48 // protection is enabled.
49
50 function wpterm_session() {
51
52 if ( current_user_can( 'install_plugins' ) && defined( 'WPTERM_PASSWORD' ) &&
53 is_main_site() ) {
54
55 if (! headers_sent() ) {
56 if (! function_exists('session_status') ) {
57 if (! session_id() ) {
58 session_start();
59 }
60 } else {
61 if ( session_status() !== PHP_SESSION_ACTIVE ) {
62 session_start();
63 }
64 }
65 }
66 }
67 }
68
69 add_action( 'admin_init', 'wpterm_session' );
70
71 /* ================================================================== */
72
73 function wpterm_activate() {
74
75 // Make sure the user meets the requirements to run WPTerm:
76
77 if ( PATH_SEPARATOR == ';' ) {
78 exit( __( 'WPTerm is not compatible with Microsoft Windows.', 'wpterm' ) );
79 }
80
81 global $wp_version;
82 if ( version_compare( $wp_version, '3.3', '<' ) ) {
83 exit( sprintf( __( 'WPTerm requires WordPress 3.3 or greater but your current version is %s.', 'wpterm' ), htmlspecialchars( $wp_version ) ) );
84 }
85
86 if ( version_compare( PHP_VERSION, '5.3.0', '<' ) ) {
87 exit( sprintf( __( 'WPTerm requires PHP 5.3 or greater but your current version is %s.', 'wpterm' ), PHP_VERSION ) );
88 }
89
90 }
91
92 register_activation_hook( __FILE__, 'wpterm_activate' );
93
94 /* ================================================================== */
95
96 function wpterm_settings_link( $links ) {
97
98 // Display the link in the "Plugins" page:
99 if (! current_user_can( 'install_plugins' ) || ! is_main_site() ) {
100 return $links;
101 }
102
103 $links[] = '<a href="'. get_admin_url( null, 'tools.php?page=wpterm' ) .
104 '">' . __( 'Terminal', 'wpterm' ) . '</a>';
105 return $links;
106 }
107
108 add_filter( 'plugin_action_links_' . plugin_basename(__FILE__), 'wpterm_settings_link' );
109
110 /* ================================================================== */
111
112 function wpterm_js_insert() {
113
114 // Insert our JS and CSS files in the footer for the admin...
115 if (! current_user_can( 'install_plugins' ) || ! is_main_site() ) {
116 return;
117 }
118 // ...when viewing WPTerm pages only:
119 if (! empty( $_GET['page'] ) && $_GET['page'] == 'wpterm' ) {
120
121 // Load terminal JS code only if we are requesting the terminal tab:
122 if (! empty( $_GET['wptermtab'] ) && $_GET['wptermtab'] == 'terminal' ) {
123 wp_enqueue_script(
124 'wpterm_script2',
125 plugin_dir_url( __FILE__ ) . 'wpterm-terminal.js',
126 array( 'jquery' )
127 );
128
129 } else {
130 wp_enqueue_script(
131 'wpterm_script',
132 plugin_dir_url( __FILE__ ) . 'wpterm.js',
133 array( 'jquery' )
134 );
135 }
136
137 wp_enqueue_style(
138 'wpterm_style',
139 plugin_dir_url( __FILE__ ) . 'wpterm.css'
140 );
141 }
142 }
143
144 add_action( 'admin_footer', 'wpterm_js_insert' );
145
146 /* ================================================================== */
147
148 function wpterm_admin_menu() {
149
150 // Append WPTerm menu to the "Tools" menu:
151 if (! is_main_site() ) { return;}
152
153 global $menu_hook;
154
155 require_once( plugin_dir_path(__FILE__) . 'wpterm-help.php' );
156
157 $menu_hook = add_submenu_page(
158 'tools.php',
159 'WPTerm',
160 'WPTerm',
161 // In a multisite environment, only the
162 // superadmin will be able to access WPTerm:
163 'install_plugins',
164 'wpterm',
165 'wpterm_main_menu'
166 );
167
168 // Load contextual help:
169 add_action( 'load-' . $menu_hook, 'wpterm_help' );
170
171 }
172
173 add_action( 'admin_menu', 'wpterm_admin_menu' );
174
175 /* ================================================================== */
176
177 function wpterm_main_menu() {
178
179 // Show the selected tab and page:
180
181 // If the terminal is password protected,
182 // check if the user is authenticated:
183 if (! wpterm_is_allowed() ) { return; }
184
185 $tab = array ( 'terminal', 'settings', 'about', 'donate' );
186 // Make sure $_GET['wptermtab']'s value is okay,
187 // otherwise set it to its default 'terminal' value:
188 if (! isset( $_GET['wptermtab'] ) || ! in_array( $_GET['wptermtab'], $tab ) ) {
189 $_GET['wptermtab'] = 'terminal';
190 }
191 $wpterm_menu = "wpterm_menu_{$_GET['wptermtab']}";
192 $wpterm_menu();
193
194 }
195
196 /* ================================================================== */
197
198 function wpterm_get_blogtimezone() {
199
200 // Get the timezone:
201
202 // From WordPress...
203 $tzstring = get_option( 'timezone_string' );
204 if (! $tzstring ) {
205 // ...or PHP?
206 $tzstring = ini_get( 'date.timezone' );
207 if (! $tzstring ) {
208 // Set it to UTC if we cannot find it:
209 $tzstring = 'UTC';
210 }
211 }
212 date_default_timezone_set( $tzstring );
213 }
214
215 /* ================================================================== */
216
217 function wpterm_menu_terminal() {
218
219 // Display the terminal:
220
221 // Fetch our options:
222 $wpterm_options = wpterm_menu_get_settings();
223
224 // Retrieve the current user info (name, home dir etc):
225 $userinfo = posix_getpwuid( posix_getuid() );
226
227 // Get current working directory:
228 if ( $wpterm_options['user-home'] == 'abspath' ) {
229 // WP current dir (a.k.a. ABSPATH):
230 $cwd = htmlspecialchars( rtrim( ABSPATH, '/' ) );
231 } else {
232 // Linux home dir:
233 $cwd = htmlspecialchars( rtrim( $userinfo['dir'], '/' ) );
234 }
235
236 // Get the blog timezone:
237 wpterm_get_blogtimezone();
238
239 $last_login = '';
240 $kernel_info = '';
241
242 // Get/set last login:
243 if (! empty( $wpterm_options['last_login'] ) ) {
244 list ( $time, $user, $ip ) = explode( ':', $wpterm_options['last_login'], 3 );
245 // Try to get hostname from its IP:
246 if (! $host = gethostbyaddr( $ip ) ) {
247 $host = $ip;
248 }
249 $date = date_i18n( 'D M d H:i:s Y', $time );
250 // We'll display this along the "welcome" message:
251 $last_login = sprintf(
252 __( 'Last login: %s, %s from %s', 'wpterm' ),
253 htmlspecialchars( $user ),
254 $date,
255 htmlspecialchars( $host ) . '\n'
256 );
257 }
258
259 // Get the current user (system and WordPress) + his/her IP:
260 $current_user = wp_get_current_user();
261 $wpuser = htmlspecialchars( $current_user->user_login );
262 $user = htmlspecialchars( $userinfo['name'] );
263 $ip = htmlspecialchars( $_SERVER['REMOTE_ADDR'] );
264 $time = time();
265
266 // We refuse to run if we're root (unless stated otherwise):
267 if ( $user == 'root' && ! defined( 'THOU_SHALT_NOT_RUN_AS_ROOT' ) ) {
268 ?>
269 <div class="error notice is-dismissible"><p><?php _e( 'Sorry, but I refuse to run as the <code>root</code> user.', 'wpterm' ) ?></p></div>
270 <div class="wrap"><h1>WPTerm</h1></div>
271 <?php
272 return;
273 }
274
275 // Display a one-time notice if we just installed WPTerm
276 // (this notice can be displayed again by entering `notice`
277 // at the terminal prompt):
278 $notice = __( "Thanks for using WPTerm!", "wpterm") . " ";
279 $notice.= __( "This is a one-time notice, please read it carefully:", "wpterm") . "<br />";
280 $notice.= "<ol>";
281 $notice.= "<li>" . __( "Just like a terminal, WPTerm lets you do almost everything you want (e.g., changing file permissions, viewing network connections or current processes etc). That's great, but if you aren't familiar with Unix shell commands, you can also damage your blog.", "wpterm") . "<br />" . __( "Therefore, each time you use WPTerm, please follow this rule of thumb: <strong>if you don't know what you're doing, don't do it!</strong>", "wpterm") . "</li>";
282 $notice.= "<li>" . __( 'Take the time to password protect the access to WPTerm. Click on the contextual "Help" menu tab located in the upper right corner to get more details about how to enable this feature.', "wpterm" ) . "</li>";
283 $notice.= "<li>" . __( "Do not try to run interactive commands, you can't (most would not run anyway because the TERM environment variable is not set). If you run one by mistake and are stuck at the prompt, press CTRL-C.", "wpterm" ) . "</li>";
284 $notice.= "</ol>";
285 $notice.= __( "If you want to read this notice again, type <code>notice</code> from WPTerm prompt.", "wpterm" );
286 if ( empty( $wpterm_options['version'] ) ) {
287 $style = '';
288 } else {
289 $style = 'style="display:none" ';
290 }
291 // Display notice:
292 ?>
293 <div <?php echo $style; ?>id="wpterm-warning" class="error notice"><?php echo $notice ?><p style="text-align:center"><a onclick="jQuery('#wpterm-warning').slideUp();"><?php _e( "Click to hide", "wpterm" ) ?></a></p></div>
294 <?php
295
296 // Save options to the database:
297 $wpterm_options['last_login'] = "$time:$wpuser:$ip";
298 $wpterm_options['version'] = WPTERM_VERSION;
299 update_option( 'wpterm_options', $wpterm_options );
300
301 // Greeting + help command (in english only, no i18n):
302 $greeting['cowsay'] = ' _________________________________\n/ ';
303 $greeting['cowsay'].= " Welcome and thank you for using" . ' \x5c\n| ';
304 $greeting['cowsay'].= " WPTerm :)" . ' |\n\x5c ';
305 $greeting['cowsay'].= " If you need help, type 'help'. " . ' /\n';
306 $greeting['cowsay'].= ' ---------------------------------\n \x5c';
307 $greeting['cowsay'].= ' ^__^ v' . WPTERM_VERSION . '\n';
308 $greeting['cowsay'].= ' \x5c (oo)\x5c_______\n';
309 $greeting['cowsay'].= ' (__)\x5c )\x5c/\x5c\n';
310 $greeting['cowsay'].= ' ||----w |\n';
311 $greeting['cowsay'].= ' || ||\n';
312 $greeting['wpterm'] = ' __ ______ _____\n';
313 $greeting['wpterm'].= ' \x5c \x5c / / _ \x5c_ _|__ _ __ _ __ ___\n';
314 $greeting['wpterm'].= ' \x5c \x5c /\x5c / /| |_) || |/ _ \x5c \'__| \'_ ` _ \x5c\n';
315 $greeting['wpterm'].= ' \x5c V V / | __/ | | __/ | | | | | | |\n';
316 $greeting['wpterm'].= ' \x5c_/\x5c_/ |_| |_|\x5c___|_| |_| |_| |_| v' .
317 WPTERM_VERSION . '\n';
318 $greeting['wpterm'].= ' If you need help, type \'help\'.\n\n';
319 $greeting['tux'] = ' .--. [------------------------------]\n';
320 $greeting['tux'].= ' |o_o | WPTerm v' . WPTERM_VERSION . '\n';
321 $greeting['tux'].= ' |:_/ |\n';
322 $greeting['tux'].= ' // \x5c \x5c Welcome and thank you for\n';
323 $greeting['tux'].= ' (| | ) using WPTerm :)\n';
324 $greeting['tux'].= ' /\'\x5c_ _/`\x5c If you need help, type \'help\'.\n';
325 $greeting['tux'].= ' \x5c___)-(___/ [------------------------------]\n';
326
327 // Try to get the kernel info:
328 list( $uname, $null ) = @run_command( 'uname -a', $wpterm_options['php-function'] );
329 if (! empty( $uname ) ) {
330 $kernel_info = htmlspecialchars( trim( $uname ) ) . '\n';
331 } else {
332 // Maybe we are running on a shared hosting account that has
333 // PHP program execution functions disabled?
334 ?>
335 <div class="error notice is-dismissible"><p><?php printf( __( "I was unable to run a shell command. Make sure that you are allowed to run %sPHP program execution functions%s, otherwise WPTerm will not function.", "wpterm" ), '<a href="http://php.net/manual/en/ref.exec.php">', '</a>' ) ?></p></div>
336 <?php
337 }
338
339 // Security nonce used for the terminal (AJAX):
340 $wpterm_ajax_nonce = wp_create_nonce( 'wpterm_menu_terminal' );
341
342 ?>
343 <style>
344 .terminal-user {
345 <?php
346 if (! empty( $wpterm_options['bold-font'] ) ) {
347 echo "font-weight:bold;\n";
348 }
349 ?>
350 background-color:<?php echo $wpterm_options['background-color-val'] ?>;
351 color:<?php echo $wpterm_options['font-color-val'] ?>;
352 font-family:<?php echo $wpterm_options['font-family'] ?>;
353 font-size:<?php echo $wpterm_options['font-size'] ?>px;
354 }
355 </style>
356 <script>
357 var wpterm_ajax_nonce = "<?php echo $wpterm_ajax_nonce ?>";
358 var prompt = "<?php echo "$user:$cwd" ?> $ ";
359 var user = "<?php echo $user ?>";
360 var cwd = "<?php echo $cwd ?>";
361 var abspath = "<?php echo htmlspecialchars( rtrim( ABSPATH, '/' ) ) ?>";
362 var exec = "<?php echo htmlspecialchars( $wpterm_options['php-function'] ) ?>";
363 var last_login = "<?php echo $kernel_info . $greeting[$wpterm_options['welcome-message']] . $last_login ?>";
364 var in_progress = "<?php echo esc_js( __( 'Operations in progress, please wait.', 'wpterm' ) ) .'\n'.
365 esc_js( __( 'If you want to cancel, press CTRL+C.', 'wpterm' ) ) ?>";
366 var op_cancelled = "<?php echo esc_js( __( 'operation cancelled', 'wpterm' ) ) ?>";
367 var iptables = "<?php echo esc_js( __( 'if you want a good firewall, install NinjaFirewall (WP Edition):', 'wp-shell' ) );
368 echo '\n https://wordpress.org/plugins/ninjafirewall/'; ?>";
369 var emul_tab = <?php echo (int) $wpterm_options['tab-completion'] ?>;
370 var emul_tab_msg = "<?php echo esc_js( __( 'Tab completion is disabled. You can enable it from the Settings page', 'wpterm' ) ) ?>";
371 var logout_url = "<?php echo html_entity_decode( wp_logout_url() ); ?>";
372 var logout_msg = "<?php echo esc_js( __( 'Log out of WordPress?', 'wpterm' ) ) ?>";
373 var unknown_err = "<?php echo esc_js( __( 'WPTerm: error, no data received', 'wpterm' ) ) ?>";
374 var version = "<?php echo '\nWPTerm v' . WPTERM_VERSION ?>";
375 var scrollback = <?php echo (int) $wpterm_options['scrollback'] ?>;
376 var visual_bell = <?php echo (int) $wpterm_options['visual-bell'] ?>;
377 var audible_bell = <?php echo (int) $wpterm_options['audible-bell'] ?>;
378 var wrap_on = "<?php echo esc_js( __( "Line wrapping is enabled", "wpterm" ) ) ?>";
379 var wrap_off = "<?php echo esc_js( __( "Line wrapping is disabled", "wpterm" ) ) ?>";
380 </script>
381 <?php
382
383 // If the blog is setup to use a right-to-left language and the user runs IE/Edge browser
384 // we inform them that it is not compatible:
385 if ( is_rtl() && preg_match( '/MSIE|Trident|Edge/', $_SERVER['HTTP_USER_AGENT'] ) ) {
386 echo '<div class="notice-warning notice is-dismissible"><p>' . __('Because your current locale is RTL (Right To Left script), the terminal will not work well with your IE/Edge browser. Consider using another browser that is compatible (Firefox, Chrome, Opera or Safari).', 'wpterm') .'</p></div>';
387 }
388
389 ?>
390 <div class="wrap">
391 <h1>WPTerm</h1>
392
393 <h2 class="nav-tab-wrapper wp-clearfix">
394 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab nav-tab-active"><?php _e( 'Terminal', 'wpterm' ) ?></a>
395 <a href="?page=wpterm&wptermtab=settings" class="nav-tab"><?php _e( 'Settings', 'wpterm' ) ?></a>
396 <a href="?page=wpterm&wptermtab=about" class="nav-tab"><?php _e( 'About', 'wpterm' ) ?></a>
397 <a href="?page=wpterm&wptermtab=donate" class="nav-tab"><?php _e( 'Info', 'wpterm' ) ?></a>
398 </h2>
399
400 <table style="width:100%;padding-top:4px">
401 <tr>
402 <td width="100%">
403 <textarea dir="auto" ondragstart="return false;" id="terminal" class="terminal terminal-user" onMouseOver="this.focus();" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" wrap="soft"></textarea>
404 </td>
405 </tr>
406 </table>
407
408 <div>
409 <p class="alignleft">
410 <img id="progress_gif" style="display:none" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-progress.gif" width="51" height="13" title="<?php _e('Operations in progress, please wait.', 'wpterm') ?>">
411 </p>
412 <p class="alignright">
413 <img onClick="line_wrapping(this);" onTouchStart="line_wrapping(this);" id="wrap-line" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-wrap.png" width="20" height="20" title="<?php _e( "Line wrapping is enabled", "wpterm" ) ?>" style="cursor:pointer">
414 &nbsp;&nbsp;&nbsp;
415 <img onClick="font_size(-1);" onTouchStart="font_size(-1);" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-fontminus.png" width="21" height="20" title="<?php _e( "Decrease font size", "wpterm" ) ?>" style="cursor:pointer">
416 &nbsp;&nbsp;&nbsp;
417 <img onClick="font_size(1);" onTouchStart="font_size(1);" border="0" src="<?php echo plugins_url() ?>/wpterm/images/wpterm-fontplus.png" width="21" height="20" title="<?php _e( "Increase font size", "wpterm" ) ?>" style="cursor:pointer">
418 </p>
419 </div>
420
421 </div>
422 <?php
423 }
424
425 /* ================================================================== */
426
427 function wpterm_menu_settings() {
428
429 // Display the settings page:
430
431 // Save settings?
432 if ( isset( $_POST['save-settings'] ) ) {
433 // Verify security nonce:
434 if ( empty( $_POST['wptermnonce'] ) || ! wp_verify_nonce( $_POST['wptermnonce'], 'save_settings' ) ) {
435 wp_nonce_ays( 'save_settings' );
436 }
437 wpterm_menu_save_settings();
438 echo '<div class="updated notice is-dismissible"><p>' . __('Your changes have been saved.', 'wpterm') .'</p></div>';
439 }
440
441 // Fetch, verify and sanitize the current settings:
442 $wpterm_options = wpterm_menu_get_settings();
443
444 ?>
445 <div class="wrap">
446 <h1>WPTerm</h1>
447
448 <h2 class="nav-tab-wrapper wp-clearfix">
449 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab"><?php _e( 'Terminal', 'wpterm' ) ?></a>
450 <a href="?page=wpterm&wptermtab=settings" class="nav-tab nav-tab-active"><?php _e( 'Settings', 'wpterm' ) ?></a>
451 <a href="?page=wpterm&wptermtab=about" class="nav-tab"><?php _e( 'About', 'wpterm' ) ?></a>
452 <a href="?page=wpterm&wptermtab=donate" class="nav-tab"><?php _e( 'Info', 'wpterm' ) ?></a>
453 </h2>
454
455 <br />
456
457 <form method="post">
458
459 <h3><?php _e('Fonts and Colors', 'wpterm') ?></h3>
460
461 <table class="form-table">
462
463 <tr>
464 <th scope="row"><?php _e('Font color', 'wpterm') ?></th>
465 <td>
466 <input type="text" name="font-color" value="<?php echo htmlspecialchars( $wpterm_options['font-color'] ) ?>" oninput="wpterm_preview('color', 'color', this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
467 <p>
468 <span class="description">
469 <?php printf ( __( 'Hexadecimal value (e.g., %s) or CSS color name (e.g., <code>red</code>).', 'wpterm' ), '<code>ffffff</code>' ) ?>
470 </span>
471 </p>
472 </td>
473 </tr>
474
475 <tr>
476 <th scope="row"><?php _e('Background color', 'wpterm') ?></th>
477 <td>
478 <input type="text" name="background-color" value="<?php echo htmlspecialchars( $wpterm_options['background-color'] ) ?>" oninput="wpterm_preview('color', 'background', this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
479 <p>
480 <span class="description">
481 <?php printf ( __( 'Hexadecimal value (e.g., %s) or CSS color name (e.g., <code>red</code>).', 'wpterm' ), '<code>3465A4</code>' ) ?>
482 </span>
483 </p>
484 </td>
485 </tr>
486
487 <tr>
488 <th scope="row"><?php _e('Font size', 'wpterm') ?></th>
489 <td>
490 <input type="number" class="small-text" name="font-size" step="1" min="9" max="20" value="<?php echo (int) $wpterm_options['font-size'] ?>" oninput="wpterm_preview('fontsize', 0, this.value);" /> px
491 &nbsp;&nbsp;&nbsp;&nbsp;
492 <label><input type="checkbox" id="bold_font" onchange="wpterm_preview('fontweight', 'bold_font', this.value);" name="bold-font"<?php checked( $wpterm_options['bold-font'], 1 ) ?> /><?php _e( 'Bold fonts', 'wpterm' ) ?></label>
493 <p>
494 <span class="description">
495 <?php _e('From 9 to 20px.', 'wpterm') ?>
496 </span>
497 </p>
498 </td>
499 </tr>
500
501 <tr>
502 <th scope="row"><?php _e('Font family', 'wpterm') ?></th>
503 <td>
504 <input type="text" class="regular-text" name="font-family" value="<?php echo htmlspecialchars( $wpterm_options['font-family'] ) ?>" oninput="wpterm_preview('fontface', 0, this.value)" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
505 <p>
506 <span class="description">
507 <?php _e( 'Multiple values must be comma separated (e.g., <code>Consolas,Monaco,monospace</code>)', 'wpterm' ) ?>
508 </span>
509 </p>
510 </td>
511 </tr>
512
513 <?php
514 if (! empty( $wpterm_options['bold-font'] ) ) {
515 $font_weight = 'font-weight:bold;';
516 } else {
517 $font_weight = 'font-weight:normal;';
518 }
519 ?>
520 <tr>
521 <th scope="row"><?php _e('Test', 'wpterm') ?></th>
522 <td>
523 <textarea autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" id="textarea-test" rows="3" style="width:20em;resize:both;padding:10px;color:<?php echo htmlspecialchars( $wpterm_options['font-color-val'] ) ?>;background-color:<?php echo htmlspecialchars( $wpterm_options['background-color-val'] ) ?>;font-size:<?php echo (int) $wpterm_options['font-size'] ?>px;font-family:<?php echo htmlspecialchars( $wpterm_options['font-family'] ) ?>;<?php echo $font_weight ?>"><?php echo "ABCDEFGHIJKLMNOPQRSTUVWXYZ\nabcdefghijklmnopqrstuvwxyz\n0123456789" ?></textarea>
524 </td>
525 </tr>
526
527 </table>
528
529 <br />
530
531 <h3><?php _e('Terminal', 'wpterm') ?></h3>
532
533 <table class="form-table">
534
535 <tr>
536 <th scope="row"><?php _e('Use the following PHP function for command execution', 'wpterm') ?></th>
537 <td>
538 <p>
539 <label>
540 <input type="radio" name="php-function" value="exec"<?php checked( $wpterm_options['php-function'], 'exec' ) ?> /><code>exec</code>
541 </label>
542 </p>
543 <p>
544 <label>
545 <input type="radio" name="php-function" value="shell_exec"<?php checked( $wpterm_options['php-function'], 'shell_exec' ) ?> /><code>shell_exec</code>
546 </label>
547 </p>
548 <p>
549 <label>
550 <input type="radio" name="php-function" value="system"<?php checked( $wpterm_options['php-function'], 'system' ) ?> /><code>system</code>
551 </label>
552 </p>
553 <p>
554 <label>
555 <input type="radio" name="php-function" value="passthru"<?php checked( $wpterm_options['php-function'], 'passthru' ) ?> /><code>passthru</code>
556 </label>
557 </p>
558 <p>
559 <label>
560 <input type="radio" name="php-function" value="popen"<?php checked( $wpterm_options['php-function'], 'popen' ) ?> /><code>popen</code>
561 </label>
562 </p>
563 </td>
564 </tr>
565
566
567 <tr>
568 <th scope="row"><?php _e('Emulate pseudo-Tab completion?', 'wpterm') ?></th>
569 <td>
570 <p>
571 <label>
572 <input type="radio" name="tab-completion" value="1"<?php checked( $wpterm_options['tab-completion'], 1 ) ?> /><?php _e( 'Yes', 'wpterm' ) ?>
573 </label>
574 </p>
575 <p>
576 <label>
577 <input type="radio" name="tab-completion" value="0"<?php checked( $wpterm_options['tab-completion'], 0 ) ?> /><?php _e( 'No', 'wpterm' ) ?>
578 </label>
579 </p>
580 </td>
581 </tr>
582
583 <?php
584 // Retrieve user info:
585 $userinfo = posix_getpwuid( posix_getuid() );
586 ?>
587 <tr>
588 <th scope="row"><?php _e('Default working directory', 'wpterm') ?></th>
589 <td>
590 <p>
591 <label>
592 <input type="radio" name="user-home" value="abspath"<?php checked( $wpterm_options['user-home'], 'abspath' ) ?> /><?php printf( __( 'WordPress ABSPATH (%s)', 'wpterm' ), '<code>'. htmlspecialchars( ABSPATH ) .'</code>' ) ?>
593 </label>
594 </p>
595 <span class="description"><?php printf( __( "Tip: to go back to that directory, type %s.", "wpterm" ), '<code>cd $ABSPATH</code>' ) ?></span>
596
597 <p>
598 <label>
599 <input type="radio" name="user-home" value="homedir"<?php checked( $wpterm_options['user-home'], 'homedir' ) ?> /><?php printf( __( 'User home directory (%s)', 'wpterm' ), '<code>'. htmlspecialchars( $userinfo['dir'] ) .'</code>' ) ?>
600 </label>
601 </p>
602 </td>
603 </tr>
604
605 <tr>
606 <th scope="row"><?php _e('Scrollback', 'wpterm') ?></th>
607 <td>
608 <label><?php printf( __( "Limit scrollback to %s lines", "wpterm" ) , '<input type="number" class="small-text" name="scrollback" step="1" min="1" max="3000" value="' . (int) $wpterm_options['scrollback'] .'" />' ) ?></label>
609 <br>
610 <span class="description">
611 <?php _e('Max 3,000 lines.', 'wpterm') ?>
612 </span>
613 </td>
614 </tr>
615
616 <tr>
617 <th scope="row"><?php _e('Welcome message', 'wpterm') ?></th>
618 <td>
619 <p>
620 <label>
621 <input type="radio" name="welcome-message" value="wpterm"<?php checked( $wpterm_options['welcome-message'], 'wpterm' ) ?> />WPTerm
622 </label>
623 </p>
624 <p>
625 <label>
626 <input type="radio" name="welcome-message" value="cowsay"<?php checked( $wpterm_options['welcome-message'], 'cowsay' ) ?> />Cowsay
627 </label>
628 </p>
629 <p>
630 <label>
631 <input type="radio" name="welcome-message" value="tux"<?php checked( $wpterm_options['welcome-message'], 'tux' ) ?> />Tux
632 </label>
633 </p>
634 </td>
635 </tr>
636
637 <?php
638 // IE up to 11 isn't compatible with our 'Audible bell':
639 if ( isset( $_SERVER["HTTP_USER_AGENT"] ) && strpos( $_SERVER["HTTP_USER_AGENT"], '; rv:11' ) !== false ) {
640 $disabled = ' disabled="disabled"';
641 } else {
642 $disabled = '';
643 }
644 ?>
645 <tr>
646 <th scope="row"><?php _e('Terminal bell', 'wpterm') ?></th>
647 <td>
648 <p><label id="visual-bell">
649 <input type="checkbox" onchange="bell_preview(this, 'visual');" name="visual-bell"<?php checked( $wpterm_options['visual-bell'], 1 ) ?> /><?php _e( 'Visual bell', 'wpterm' ) ?>
650 </label></p>
651 <p><label>
652 <input type="checkbox"<?php echo $disabled ?> onchange="bell_preview(this, 'beep');" name="audible-bell"<?php checked( $wpterm_options['audible-bell'], 1 ) ?> /><?php _e( 'Audible bell', 'wpterm' ) ?>
653 </label></p>
654 </td>
655 </tr>
656
657 </table>
658
659 <br />
660 <br />
661
662 <input class="button-primary" type="submit" name="save-settings" value="<?php _e('Save Settings', 'wpterm') ?>" />
663
664 <?php wp_nonce_field('save_settings', 'wptermnonce', 0); ?>
665
666 </form>
667
668 </div>
669
670 <?php
671
672 }
673
674 /* ================================================================== */
675
676 function wpterm_menu_get_settings() {
677
678 // Retrieve the current settings:
679
680 $wpterm_options = get_option( 'wpterm_options' );
681
682 if ( empty( $wpterm_options['font-color'] ) ) {
683 $wpterm_options['font-color'] = 'ffffff';
684 } else {
685 $wpterm_options['font-color'] = preg_replace( '/\W/', '', $wpterm_options['font-color'] );
686 }
687 if ( ctype_xdigit( $wpterm_options['font-color'] ) ) {
688 $wpterm_options['font-color-val'] = '#' . $wpterm_options['font-color'];
689 } else {
690 $wpterm_options['font-color-val'] = $wpterm_options['font-color'];
691 }
692
693 if ( empty( $wpterm_options['background-color'] ) ) {
694 $wpterm_options['background-color'] = '3465A4';
695 } else {
696 $wpterm_options['background-color'] = preg_replace( '/\W/', '', $wpterm_options['background-color'] );
697 }
698 if ( ctype_xdigit( $wpterm_options['background-color'] ) ) {
699 $wpterm_options['background-color-val'] = '#' . $wpterm_options['background-color'];
700 } else {
701 $wpterm_options['background-color-val'] = $wpterm_options['background-color'];
702 }
703
704 if (! isset( $wpterm_options['font-size'] ) || ! preg_match( '/^(?:9|1[0-9]|20)$/', $wpterm_options['font-size'] ) ) {
705 $wpterm_options['font-size'] = 13;
706 }
707
708
709 if (! empty( $wpterm_options['bold-font'] ) ) {
710 $wpterm_options['bold-font'] = 1;
711 } else {
712 $wpterm_options['bold-font'] = 0;
713 }
714
715 if (! empty( $wpterm_options['font-family'] ) ) {
716 $wpterm_options['font-family'] = preg_replace( '/[^\'" ,a-zA-Z]/', '', $wpterm_options['font-family'] );
717 $wpterm_options['font-family'] = trim( $wpterm_options['font-family'], ' ,' );
718 }
719 if ( empty( $wpterm_options['font-family'] ) ) {
720 $wpterm_options['font-family'] = 'Consolas,Monaco,monospace';
721 }
722
723 if ( empty( $wpterm_options['welcome-message'] ) || ! preg_match( '/^(?:wpterm|cowsay|tux)$/', $wpterm_options['welcome-message'] ) ) {
724 $wpterm_options['welcome-message'] = 'wpterm';
725 }
726
727 if ( empty( $wpterm_options['php-function'] ) || ! preg_match( '/^(?:exec|shell_exec|system|passthru|popen)$/', $wpterm_options['php-function'] ) ) {
728 // WPTerm <1.1.2:
729 if ( @$wpterm_options['php-function'] == 'backtick' ) {
730 $wpterm_options['php-function'] = 'shell_exec';
731 } else {
732 $wpterm_options['php-function'] = 'exec';
733 }
734 }
735
736 if (! isset( $wpterm_options['tab-completion'] ) || $wpterm_options['tab-completion'] == 1 ) {
737 // Default value:
738 $wpterm_options['tab-completion'] = 1;
739 } else {
740 $wpterm_options['tab-completion'] = 0;
741 }
742
743
744 if (! isset( $wpterm_options['user-home'] ) || $wpterm_options['user-home'] == 'abspath' ) {
745 $wpterm_options['user-home'] = 'abspath';
746 } else {
747 $wpterm_options['user-home'] = 'homedir';
748 }
749
750
751 if (! empty( $wpterm_options['scrollback'] ) ) {
752 $wpterm_options['scrollback'] = (int) $wpterm_options['scrollback'];
753 if ( $wpterm_options['scrollback'] < 1 || $wpterm_options['scrollback'] > 3000 ) {
754 $wpterm_options['scrollback'] = 512;
755 }
756 } else {
757 $wpterm_options['scrollback'] = 512;
758 }
759
760
761 if (! isset( $wpterm_options['visual-bell'] ) || $wpterm_options['visual-bell'] == 1 ) {
762 $wpterm_options['visual-bell'] = 1;
763 } else {
764 $wpterm_options['visual-bell'] = 0;
765 }
766
767 if (! empty( $wpterm_options['audible-bell'] ) ) {
768 $wpterm_options['audible-bell'] = 1;
769 } else {
770 $wpterm_options['audible-bell'] = 0;
771 }
772
773
774 return $wpterm_options;
775
776 }
777
778 /* ================================================================== */
779
780 function wpterm_menu_save_settings() {
781
782 // Check and save the terminal settings:
783
784 $wpterm_options = get_option( 'wpterm_options' );
785
786
787 if ( empty( $_POST['font-color'] ) ) {
788 $wpterm_options['font-color'] = 'ffffff';
789 } else {
790 // Make sure $_POST['font-color'] contains only word characters:
791 $wpterm_options['font-color'] = preg_replace( '/\W/', '', $_POST['font-color'] );
792 }
793
794 if ( empty( $_POST['background-color'] ) ) {
795 $wpterm_options['background-color'] = '3465A4';
796 } else {
797 // Make sure $_POST['background-color'] contains only word characters:
798 $wpterm_options['background-color'] = preg_replace( '/\W/', '', $_POST['background-color'] );
799 }
800
801 // Make sure $_POST['font-size'] is an integer between 9 and 20,
802 // otherwise set it to 13, its default value:
803 if (! isset( $_POST['font-size'] ) || ! preg_match( '/^(?:9|1[0-9]|20)$/', $_POST['font-size'] ) ) {
804 $wpterm_options['font-size'] = 13;
805 } else {
806 $wpterm_options['font-size'] = (int)$_POST['font-size'];
807 }
808
809 if (! empty( $_POST['bold-font'] ) ) {
810 $wpterm_options['bold-font'] = 1;
811 } else {
812 $wpterm_options['bold-font'] = 0;
813 }
814
815 // Make sure $_POST['font-family'] contains only letters, commas, spaces, single and double quotes:
816 if (! empty( $_POST['font-family'] ) ) {
817 $wpterm_options['font-family'] = preg_replace( '/[^\'" ,a-zA-Z]/', '', $_POST['font-family'] );
818 $wpterm_options['font-family'] = trim( $wpterm_options['font-family'], ' ,' );
819 }
820 if ( empty( $_POST['font-family'] ) ) {
821 $wpterm_options['font-family'] = 'Consolas,Monaco,monospace';
822 }
823
824 // Make sure the value of $_POST['welcome-message'] is 'wpterm', 'cowsay' or 'tux',
825 // otherwise set it to 'wpterm', its default value:
826 if ( empty( $_POST['welcome-message'] ) || ! preg_match( '/^(?:wpterm|cowsay|tux)$/', $_POST['welcome-message'] ) ) {
827 $wpterm_options['welcome-message'] = 'wpterm';
828 } else {
829 $wpterm_options['welcome-message'] = htmlspecialchars( $_POST['welcome-message'] );
830 }
831
832 // Make sure the value of $_POST['php-function'] is 'exec', 'shell_exec', 'system', 'popen' or 'passthru',
833 // otherwise set it to 'exec', its default value:
834 if ( empty( $_POST['php-function'] ) || ! preg_match( '/^(?:exec|shell_exec|system|passthru|popen)$/', $_POST['php-function'] ) ) {
835 $wpterm_options['php-function'] = 'exec';
836 } else {
837 $wpterm_options['php-function'] = htmlspecialchars( $_POST['php-function'] );
838 }
839
840 if ( empty( $_POST['tab-completion'] ) || $_POST['tab-completion'] != 1 ) {
841 $wpterm_options['tab-completion'] = 0;
842 } else {
843 $wpterm_options['tab-completion'] = 1;
844 }
845
846 // Make sure the value of $_POST['user-home'] is 'abspath' or 'homedir',
847 // otherwise set it to 'abspath', its default value:
848 if ( empty( $_POST['user-home'] ) || ! preg_match( '/^(?:abspath|homedir)$/', $_POST['user-home'] ) ) {
849 $wpterm_options['user-home'] = 'abspath';
850 } else {
851 $wpterm_options['user-home'] = htmlspecialchars( $_POST['user-home'] );
852 }
853
854 // Make sure $_POST['scrollback'] is an integer between 1 and 3,000,
855 // otherwise set it to 512, its default value:
856 if (! empty( $_POST['scrollback'] ) ) {
857 $wpterm_options['scrollback'] = (int) $_POST['scrollback'];
858 if ( $wpterm_options['scrollback'] < 1 || $wpterm_options['scrollback'] > 3000 ) {
859 $wpterm_options['scrollback'] = 512;
860 }
861 } else {
862 $wpterm_options['scrollback'] = 512;
863 }
864
865
866 if (! empty( $_POST['audible-bell'] ) ) {
867 $wpterm_options['audible-bell'] = 1;
868 } else {
869 $wpterm_options['audible-bell'] = 0;
870 }
871 if (! empty( $_POST['visual-bell'] ) ) {
872 $wpterm_options['visual-bell'] = 1;
873 } else {
874 $wpterm_options['visual-bell'] = 0;
875 }
876
877
878 // Save current version too (we'll likely need it when updating the plugin):
879 $wpterm_options['version'] = WPTERM_VERSION;
880
881 update_option( 'wpterm_options', $wpterm_options );
882
883 }
884
885 /* ================================================================== */
886
887 function wpterm_menu_about() {
888
889 if ( file_exists( plugin_dir_path(__FILE__) . 'LICENSE.TXT' ) ) {
890 $gpl3 = file_get_contents( plugin_dir_path(__FILE__) . 'LICENSE.TXT' );
891 } else {
892 $gpl3 = __( 'Error: cannot open LICENSE.TXT!', 'wpterm' );
893 }
894 ?>
895 <div class="wrap">
896 <h1>WPTerm</h1>
897
898 <h2 class="nav-tab-wrapper wp-clearfix">
899 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab"><?php _e( 'Terminal', 'wpterm' ) ?></a>
900 <a href="?page=wpterm&wptermtab=settings" class="nav-tab"><?php _e( 'Settings', 'wpterm' ) ?></a>
901 <a href="?page=wpterm&wptermtab=about" class="nav-tab nav-tab-active"><?php _e( 'About', 'wpterm' ) ?></a>
902 <a href="?page=wpterm&wptermtab=donate" class="nav-tab"><?php _e( 'Info', 'wpterm' ) ?></a>
903 </h2>
904
905 <div class="card">
906 <h1>WPTerm v<?php echo WPTERM_VERSION ?></h1>
907 <h3>&copy; <?php echo date( 'Y' ) ?> Jerome Bruandet</h3>
908 <strong><?php _e('From the same author:', 'wpterm' ) ?></strong>
909 <ul>
910 <li><a href="https://wordpress.org/plugins/ninjafirewall/">NinjaFirewall (WP Edition)</a>: <?php _e('A true Web Application Firewall to protect and secure WordPress.', 'wpterm' ) ?></li>
911 <li><a href="https://wordpress.org/plugins/ninjascanner/">NinjaScanner</a>: <?php _e('A lightweight, fast and powerful antivirus scanner for WordPress.', 'wpterm' ) ?></li>
912 <li><a href="https://wordpress.org/plugins/dashboard-cleaner/">Dashboard Cleaner</a>: <?php _e('Reclaim your admin dashboard: Get rid of annoying banners, unwanted ads and other nuisances.', 'wpterm' ) ?></li>
913 </ul>
914 <br />
915 <br />
916 <textarea id="wpterm-license" class="small-text code" style="display:none" cols="60" rows="8" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"><?php echo htmlspecialchars( $gpl3 ) ?></textarea>
917 <input id="wpterm-license-button" type="button" class="button-secondary" value="<?php _e('View license', 'wpterm' ) ?>" onClick="show_license();" />
918 <br />&nbsp;
919 </div>
920 </div>
921 <?php
922 }
923
924 /* ================================================================== */
925
926 function wpterm_menu_donate() {
927
928 // Donate menu:
929
930 ?>
931 <div class="wrap">
932 <h1><?php _e('Info', 'wpterm' ) ?></h1>
933
934 <h2 class="nav-tab-wrapper wp-clearfix">
935 <a href="?page=wpterm&wptermtab=terminal" class="nav-tab"><?php _e( 'Terminal', 'wpterm' ) ?></a>
936 <a href="?page=wpterm&wptermtab=settings" class="nav-tab"><?php _e( 'Settings', 'wpterm' ) ?></a>
937 <a href="?page=wpterm&wptermtab=about" class="nav-tab"><?php _e( 'About', 'wpterm' ) ?></a>
938 <a href="?page=wpterm&wptermtab=donate" class="nav-tab nav-tab-active"><?php _e( 'Info', 'wpterm' ) ?></a>
939 </h2>
940
941 <div class="card">
942 <p><?php _e('<strong>WPTerm</strong> is open-source and free. If you like it and want to support it, you can either donate or rate it on wordpress.org.', 'wpterm' ) ?></p>
943 <hr />
944 <h3><?php _e('Bitcoin donation', 'wpterm' ) ?></h3>
945 <br />
946 <a href="bitcoin:13GH1yAU22ukKQ4AxhtBnb8eiNRtzbqsUC?message=WPTerm%20donation"><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIYAAACGCAIAAACXG2XGAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QYCCjMiGBn+rgAAAzJJREFUeNrtncFyg0AMQ6HD//9yeu10GsZG0jaGpzMhBMUSttfL/nq9NvBJOLZt2/fdft6fTL87/7tjKp9VrseF0H374l/5aYASKAEVL3Fpbldb3/lHwg8qXvXu/JVjjPeNKEG4AJSM95KuNygaWtH0yvkVD0vkGeJ9I0oQLgAlt/KSBLrP9a58ons9ifoVUYJwASjBSzz+kfCGbg3q5/Hp+hVRgnABKHm6l7g0tOsB3XzC1dtXfM5434gShAtAyXgvSdd2Ep5R8bD0mjHjfSNKEC4AJeOwLy7gdDU30c9Q/IwoQbgAlIC/vaRSI+rqeKI+1l3TtXJOxfW9zJcgXABKJuLYav0DxTOUfkbCwxRPcuVYJ+cnShAuACUjvUR5Hk9ovct7up+tXL8y21j0HqIE4QJQMtJLXNrdrWsptbVurpCeI1HWEfz6XUQJwgWgZHxe0p3PcPWxuzPwykzJyhyFKEG4AJQ8xUu6sxquPsfKWcVEbuG6BvolCBeAkuk4WxP8X/uIpHvvrvXESr5C7x3hAlDyRC9R+t5KfpDwBlddrtubIUoQLgAlT/SStF53j1F8qNsXcc2mXMhjiBKEC0DJSC9J5xldfxJn/ZblT6EcjihBuACUjM9LXPWldH9eyQkS8yuuHI4oQbgAlEzEcUFPXTpbWRuWyBVca39DfRqiBOECUDLeSxJ75VY0VJn1S7wfZfF+jkQJwgWgZLyXJJ67FY1O5A2u7+2+P5goQbgAlDzFS5TZurTmrswhVta7iBKEC0DJ3bxE0fGKx6TzDNd+J4l9Yi7U1ogShAtAyThceX9J91k+nXO45ldWvvvk5HqIEoQLQMlIL4l/h6nvvSAnaHmPklednJMoQbgAlIzDsWX23VL2gnT5h5IbuTzywnUSJQgXgJKRXpLQVkVzK9fTff9jYg8V1z6PRAnCBaDkbl6i5ASuPEZ571ZX95Uevuv3EiUIF4CSO3uJC0r/I72vopJPhOp1RAnCBaAEL7mo0a7eu6L1rvMofRSiBOECUHI3L1k5A+iaZ0zkOq4eD/0ShAtAyV1xNl+iIL1HZCIfUnzCtf6YGhfCBaBkqpdwFz4K3/F65gVuLsNPAAAAAElFTkSuQmCC"><br />13GH1yAU22ukKQ4AxhtBnb8eiNRtzbqsUC</a>
947 <br />&nbsp;
948 <hr />
949 <h3><?php _e('Rate it', 'wpterm' ) ?></h3>
950 <a href="https://wordpress.org/support/view/plugin-reviews/wpterm?rate=5#postform"><img title="<?php _e('Rate it', 'wpterm' ) ?>" border="0" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHQAAAAcCAIAAAA/XwxHAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3woMCgQevC7e8gAAActJREFUaN7tmb9LAmEYx9/XM1OLNDMCB8MLQRCHoKGprbW1pcWh/yKabHVsjIj+gKgGh1q1oMEIIoIup8Ph0lOvO7F7720QuZI6fd9q6X2+2/G+H57j88D7gxdTShHkb+IDBSAX5EJ+LJfS5p7RbHGVE4tll0sV82G383BIODZCwVgfcxsbBaPtoHah02gB+6tyqWI+HjoIIaRZj4zNFI1llNtv4+CLrZmisaxy3Tb2w9JM0ViEEEL42xsa1W3ttGc82ZZCTMW2FGLVv5iLp30h2R+SpbAshWT/9NpkPOdDgrGYVS7qEXVTuztxGFoVC+ZuookUFo5lXhYCUuI4ll7F41YKBNIXg0qisTxr7tRE6mw2uTROKX/yfDa1jMVlOTY0HJ/MXEYX5kZsiwtHscz68NIjGstzWsCLoexB0GOitBHJbkkYWL6jGKkTj3WeqI7HsGgsq1xqXRGv8ec3qwssn1ziGLeenXp5MxrA8sntEr3mApH8zMr9/EoxHIm6v6M/U2C/uj+PilN7LSO1hOqVvKHVHHfAtLWiXomqJaSW920H2OGMIde+ble3P5f5GNPWinp1p2cDOxwMr79/F3hDA7kgFwJyQe6/yDsZhxXHUCuqgQAAAABJRU5ErkJggg==" width="116" height="28"><br /><?php _e('Rate it on WordPress.org', 'wpterm' ) ?></a>
951 <br />&nbsp;
952 <hr />
953 <p><?php _e('Thanks!', 'wpterm' ) ?></p>
954 </div>
955 </div>
956 <?php
957 }
958
959
960 /* ================================================================== */
961
962 add_action( 'wp_ajax_wptermajax', 'wptermajax_callback' );
963
964 function wptermajax_callback() {
965
966 // The terminal AJAX callback function:
967
968 if (! current_user_can( 'install_plugins' ) || ! is_main_site() ) { wp_die(0); }
969
970 // Check AJAX security nonce:
971 if ( check_ajax_referer( 'wpterm_menu_terminal', 'wpterm_ajax_nonce', false ) ) {
972
973 // Path to return in case of fatal error:
974 $if_error = htmlspecialchars( rtrim( ABSPATH, '/' ) ) . '::';
975
976 // If the password protection is enabled, check the password:
977 if (! wpterm_is_allowed( 'ajax' ) ) {
978 echo $if_error . __( 'WPTerm: error, your password has expired. Reload this page to renew it.', 'wpterm');
979 wp_die();
980 }
981
982 if ( empty( $_POST['cmd'] ) || empty( $_POST['cwd'] ) || empty( $_POST['exec'] ) || empty( $_POST['abs'] ) ) {
983 echo $if_error . __( 'WPTerm error: missing command, path, function or abspath', 'wpterm' );
984 wp_die();
985 }
986 // Make sure the max number of lines to returned to WPTerm
987 // is a digit, otherwise set it to 512, its default value:
988 if ( empty( $_POST['scrollback'] ) || ! ctype_digit( $_POST['scrollback'] ) ) {
989 $scrollback = 512;
990 } else {
991 $scrollback = (int)$_POST['scrollback'];
992 }
993 // We don't want WordPress to escape strings with slashes:
994 $cmd = stripslashes( trim( $_POST['cmd'] ) );
995 $cwd = stripslashes( trim( $_POST['cwd'] ) );
996 $abs = stripslashes( trim( $_POST['abs'] ) );
997 // Set the ABSPATH variable, go to the current working directory,
998 // run the command, redirect STDERR to STDOUT and return the current
999 // working directory (it may have been changed e.g., `cd /foo/bar`):
1000 $command = sprintf( "ABSPATH=%s;cd %s;%s 2>&1;echo [-{-`pwd`-}-]", $abs, $cwd, $cmd );
1001
1002 // Run the command:
1003 list( $res, $ret_var ) = @run_command( $command, trim( $_POST['exec'] ) );
1004
1005 // Split the PWD and the data returned by the command:
1006 if ( preg_match( '`^(.+)?\[-{-(/.*?)-}-\]`s', $res, $match ) ) {
1007 // Turn the string into an array...
1008 $res_array = explode( "\n", $match[1] );
1009 // ...keep only the last $_POST['scrollback'] lines and re-create the string...
1010 $res_str = implode( "\n", array_slice( $res_array, -$_POST['scrollback'] ) );
1011 // ...and return it to WPTerm terminal:
1012 echo rtrim( $match[2] . '::' . $res_str );
1013 } else {
1014 if (! empty( $ret_var ) ) {
1015 echo $if_error . sprintf( __( 'WPTerm: error %s', 'wpterm' ), (int) $ret_var );
1016 } else {
1017 echo $if_error . __( 'WPTerm: unknown error. Are you allowed to run PHP program execution functions?', 'wpterm' );
1018 }
1019 }
1020 } else {
1021 echo '/::' . __( 'WPTerm: error, security nonces do not match. Try to reload this page to renew them.', 'wpterm');
1022 }
1023 wp_die();
1024
1025 }
1026
1027 /* ================================================================== */
1028
1029 function run_command( $command, $function ) {
1030
1031 $ret_var = '';
1032 $res = '';
1033
1034 // Select which method to use to run the command:
1035
1036 if ( $function == 'shell_exec' || $function == 'backtick' ) {
1037 $res = shell_exec( $command );
1038
1039 } elseif ( $function == 'system' ) {
1040 ob_start();
1041 system( $command, $ret_var );
1042 $res = ob_get_contents();
1043 ob_end_clean();
1044
1045 } elseif ( $function == 'passthru' ) {
1046 ob_start();
1047 passthru( $command, $ret_var );
1048 $res = ob_get_contents();
1049 ob_end_clean();
1050
1051 } elseif ( $function == 'popen' ) {
1052 if ( ( $handle = popen( $command , 'r' ) ) !== false ) {
1053 while (! feof( $handle ) ) {
1054 $res .= fgets( $handle );
1055 }
1056 pclose( $handle );
1057 }
1058
1059 } else {
1060 if ( exec( $command, $res, $ret_var ) ) {
1061 $res = implode( "\n", $res );
1062 }
1063 }
1064
1065 return array( $res, $ret_var );
1066
1067 }
1068
1069 /* ================================================================== */
1070
1071 function wpterm_is_allowed( $is_ajax = null ) {
1072
1073 // Check if a password was set:
1074 if (! defined( 'WPTERM_PASSWORD' ) ) {
1075 // No, let it go:
1076 return true;
1077 }
1078
1079 // Check if the user session exists:
1080 if ( empty( $_SESSION['wptermpwd'] ) ) {
1081 // Return if this is an AJAX call (a warning
1082 // will be displayed from the terminal prompt):
1083 if ( isset( $is_ajax ) ) { return false; }
1084 // Display the password form:
1085 if( ! wpterm_password_prompt(1) ) {
1086 return false;
1087 }
1088 }
1089 // Check if passwords match:
1090 if ( $_SESSION['wptermpwd'] != WPTERM_PASSWORD ) {
1091 // Password does not match, clear it:
1092 unset( $_SESSION['wptermpwd'] );
1093 if ( isset( $is_ajax ) ) { return false; }
1094 // Display the password form:
1095 if (! wpterm_password_prompt(2) ) {
1096 return false;
1097 }
1098 }
1099
1100 // Okay, go ahead!
1101 return true;
1102
1103 }
1104
1105 /* ================================================================== */
1106
1107 function wpterm_password_prompt( $err = 0 ) {
1108
1109 // Display the password form:
1110
1111 // Password form submitted?
1112 if ( isset( $_POST['wptermpwd'] ) ) {
1113 // Verify security nonce:
1114 if ( empty( $_POST['wptermnonce'] ) || ! wp_verify_nonce( $_POST['wptermnonce'], 'wpterm_password' ) ) {
1115 wp_nonce_ays( 'wpterm_password' );
1116 }
1117 // Verify password:
1118 if ( sha1( $_POST['wptermpwd'] ) === WPTERM_PASSWORD ) {
1119 $_SESSION['wptermpwd'] = sha1( $_POST['wptermpwd'] );
1120 return true;
1121 } else {
1122 $err = 3;
1123 }
1124 }
1125
1126 if ( $err == 3 ) {
1127 ?>
1128 <div class="error notice is-dismissible"><p><?php _e( 'Wrong password, please try again.', 'wpterm' ) ?></p></div>
1129 <?php
1130 } else {
1131 ?>
1132 <div class="notice-info notice is-dismissible"><p><?php printf( __( 'A password is required to access WPTerm (#%s).', 'wpterm' ), (int) $err ) ?></p></div>
1133 <?php
1134 }
1135 ?>
1136
1137 <div class="wrap">
1138 <h1>WPTerm</h1>
1139
1140 <h2 class="nav-tab-wrapper wp-clearfix" style="cursor:not-allowed">
1141 <a class="nav-tab"><?php _e( 'Terminal', 'wpterm' ) ?></a>
1142 <a class="nav-tab"><?php _e( 'Settings', 'wpterm' ) ?></a>
1143 <a class="nav-tab"><?php _e( 'About', 'wpterm' ) ?></a>
1144 <a class="nav-tab"><?php _e( 'Info', 'wpterm' ) ?></a>
1145 </h2>
1146
1147 <div class="card">
1148
1149 <form method="post">
1150 <h3><?php _e( 'Enter your WPTerm password:', 'wpterm' ) ?></h3>
1151 <p><input class="input" type="password" name="wptermpwd" placeholder="Password" autofocus /></p>
1152 <p><input type="submit" class="button-secondary" /></p>
1153 <?php wp_nonce_field('wpterm_password', 'wptermnonce', 0); ?>
1154 </form>
1155
1156 </div>
1157 </div>
1158 <?php
1159
1160 return false;
1161
1162 }
1163
1164 /* ================================================================== */
1165 // Write session to disk to prevent cURL time-out which may occur with
1166 // WordPress (since 4.9.2, see https://core.trac.wordpress.org/ticket/43358),
1167 // or plugins such as "Health Check".
1168
1169 add_filter( 'pre_http_request', 'wpterm_pre_http_request', 10, 3 );
1170
1171 function wpterm_pre_http_request( $preempt, $r, $url ) {
1172
1173 // NFW_DISABLE_SWC can be defined in wp-config.php (undocumented):
1174 if (! defined('NFW_DISABLE_SWC') && isset( $_SESSION ) ) {
1175 if ( function_exists( 'get_site_url' ) ) {
1176 $parse = parse_url( get_site_url() );
1177 $s_url = @$parse['scheme'] . "://{$parse['host']}";
1178 if ( strpos( $url, $s_url ) === 0 ) {
1179 @session_write_close();
1180 }
1181 }
1182 }
1183 return false;
1184 }
1185
1186 // Get rid of the Site Health php_sessions test, it returns a scary message
1187 // although everything is working as expected
1188 function wpterm_remove_php_sessions_test( $tests ) {
1189 unset( $tests['direct']['php_sessions'] );
1190 return $tests;
1191 }
1192 add_filter( 'site_status_tests', 'wpterm_remove_php_sessions_test' );
1193
1194 /* ================================================================== */
1195 // EOF
1196