1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* WP PHP Console Plugin Core Class |
4
|
|
|
* |
5
|
|
|
* @link https://github.com/unfulvio/wp-php-console |
6
|
|
|
* @since 1.0.0 |
7
|
|
|
* @package WP_PHP_Console |
8
|
|
|
*/ |
9
|
|
|
namespace WP_PHP_Console; |
10
|
|
|
|
11
|
|
|
use PhpConsole; |
12
|
|
|
|
13
|
|
|
defined( 'ABSPATH' ) or exit; |
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* WP PHP Console main class. |
17
|
|
|
* |
18
|
|
|
* @since 1.0.0 |
19
|
|
|
* @package WP_PHP_Console |
20
|
|
|
*/ |
21
|
|
|
class Plugin { |
22
|
|
|
|
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* The plugin version. |
26
|
|
|
* |
27
|
|
|
* @since 1.5.0 |
28
|
|
|
* @const string |
29
|
|
|
*/ |
30
|
|
|
CONST VERSION = '1.5.0'; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* The plugin name. |
34
|
|
|
* |
35
|
|
|
* @since 1.5.0 |
36
|
|
|
* @const string |
37
|
|
|
*/ |
38
|
|
|
CONST NAME = 'WP PHP Console'; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* This plugin's settings options. |
42
|
|
|
* |
43
|
|
|
* @since 1.0.0 |
44
|
|
|
* @access protected |
45
|
|
|
* @var array $options Array of this plugin settings options. |
46
|
|
|
*/ |
47
|
|
|
protected $options = array(); |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* Instance of PHP Console connector object. |
51
|
|
|
* |
52
|
|
|
* @since 1.4.0 |
53
|
|
|
* @access public |
54
|
|
|
* @var PhpConsole\Connector $connector Instance. |
55
|
|
|
*/ |
56
|
|
|
public $connector; |
57
|
|
|
|
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Load plugin and connect to PHP Console. |
61
|
|
|
* |
62
|
|
|
* @since 1.0.0 |
63
|
|
|
*/ |
64
|
|
|
public function __construct() { |
65
|
|
|
|
66
|
|
|
// Handle translations. |
67
|
|
|
add_action( 'plugins_loaded', array( $this, 'set_locale' ) ); |
68
|
|
|
|
69
|
|
|
// Set options. |
70
|
|
|
$this->options = $this->get_options(); |
71
|
|
|
|
72
|
|
|
// Load admin. |
73
|
|
|
$this->set_admin(); |
74
|
|
|
|
75
|
|
|
// Bail out if PHP Console can't be found. |
76
|
|
|
if ( ! class_exists( 'PhpConsole\Connector' ) ) { |
77
|
|
|
return; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
// Connect to PHP Console. |
81
|
|
|
add_action( 'init', array( $this, 'connect' ), -100 ); |
82
|
|
|
|
83
|
|
|
// Delay further PHP Console initialisation |
84
|
|
|
// to have more context during Remote PHP execution. |
85
|
|
|
add_action( 'wp_loaded', array( $this, 'init' ), -100 ); |
86
|
|
|
|
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* Set plugin text domain. |
92
|
|
|
* |
93
|
|
|
* @since 1.0.0 |
94
|
|
|
*/ |
95
|
|
|
public function set_locale() { |
96
|
|
|
|
97
|
|
|
load_plugin_textdomain( |
98
|
|
|
'wp-php-console', |
99
|
|
|
false, |
100
|
|
|
dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' |
101
|
|
|
); |
102
|
|
|
|
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Load admin. |
108
|
|
|
* |
109
|
|
|
* @since 1.5.0 |
110
|
|
|
*/ |
111
|
|
|
private function set_admin() { |
112
|
|
|
|
113
|
|
|
if ( ! defined( 'DOING_AJAX' ) && is_admin() ) { |
114
|
|
|
|
115
|
|
|
// Add a settings link to the plugins admin screen. |
116
|
|
|
$plugin_name = str_replace( 'includes/class-', '', plugin_basename( __FILE__ ) ); |
117
|
|
|
add_filter( "plugin_action_links_{$plugin_name}", function( $actions ) { |
118
|
|
|
return array_merge( array( |
119
|
|
|
'<a href="' . esc_url( admin_url( 'options-general.php?page=wp-php-console' ) ) . '">' . __( 'Settings', 'wp-php-console' ) . '</a>', |
120
|
|
|
), $actions ); |
121
|
|
|
} ); |
122
|
|
|
|
123
|
|
|
// Init settings. |
124
|
|
|
require_once __DIR__ . '/class-wp-php-console-settings.php'; |
125
|
|
|
new Settings( $this->options ); |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
|
131
|
|
|
/** |
132
|
|
|
* Connect to PHP Console. |
133
|
|
|
* |
134
|
|
|
* @since 1.4.0 |
135
|
|
|
*/ |
136
|
|
|
public function connect() { |
137
|
|
|
|
138
|
|
|
session_start(); |
139
|
|
|
|
140
|
|
|
if ( ! $this->connector instanceof PhpConsole\Connector ) { |
141
|
|
|
$this->connector = PhpConsole\Connector::getInstance(); |
142
|
|
|
} |
143
|
|
|
|
144
|
|
|
// Apply PHP Console options. |
145
|
|
|
$this->apply_options(); |
146
|
|
|
|
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* Get WP PHP Console settings options. |
152
|
|
|
* |
153
|
|
|
* @since 1.4.0 |
154
|
|
|
* @return array |
155
|
|
|
*/ |
156
|
|
|
protected function get_options() { |
157
|
|
|
|
158
|
|
|
$options = get_option( 'wp_php_console', array() ); |
159
|
|
|
|
160
|
|
|
return wp_parse_args( $options, array( |
161
|
|
|
'ip' => '', |
162
|
|
|
'password' => '', |
163
|
|
|
'register' => false, |
164
|
|
|
'short' => false, |
165
|
|
|
'ssl' => false, |
166
|
|
|
'stack' => false, |
167
|
|
|
) ); |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Apply options. |
173
|
|
|
* |
174
|
|
|
* @since 1.4.0 |
175
|
|
|
*/ |
176
|
|
|
private function apply_options() { |
|
|
|
|
177
|
|
|
|
178
|
|
|
// Bail out if not connected yet to PHP Console. |
179
|
|
|
if ( ! $this->connector instanceof PhpConsole\Connector ) { |
180
|
|
|
return; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
// Apply 'register' option to PHP Console... |
184
|
|
|
if ( true === $this->options['register'] && ! class_exists( 'PC', false ) ) { |
185
|
|
|
// ...only if PC not registered yet. |
186
|
|
|
try { |
187
|
|
|
PhpConsole\Helper::register(); |
188
|
|
|
} catch( \Exception $e ) { |
189
|
|
|
$this->print_notice_exception( $e ); |
190
|
|
|
} |
191
|
|
|
} |
192
|
|
|
|
193
|
|
|
// Apply 'stack' option to PHP Console. |
194
|
|
|
if ( true === $this->options['stack'] ) { |
195
|
|
|
$this->connector->getDebugDispatcher()->detectTraceAndSource = true; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
// Apply 'short' option to PHP Console. |
199
|
|
|
if ( true === $this->options['short'] ) { |
200
|
|
|
try { |
201
|
|
|
$this->connector->setSourcesBasePath( $_SERVER['DOCUMENT_ROOT'] ); |
202
|
|
|
} catch ( \Exception $e ) { |
203
|
|
|
$this->print_notice_exception( $e ); |
204
|
|
|
} |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
} |
208
|
|
|
|
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* Initialize PHP Console. |
212
|
|
|
* |
213
|
|
|
* @since 1.0.0 |
214
|
|
|
*/ |
215
|
|
|
public function init() { |
216
|
|
|
|
217
|
|
|
// Get PHP Console extension password. |
218
|
|
|
$password = $this->options['password']; |
219
|
|
|
|
220
|
|
|
if ( ! $password ) { |
221
|
|
|
// Display admin notice and abort if no password has been set. |
222
|
|
|
add_action( 'admin_notices', array( $this, 'password_notice' ) ); |
223
|
|
|
return; |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
// Selectively remove slashes added by WordPress as expected by PhpConsole. |
227
|
|
|
if ( array_key_exists( PhpConsole\Connector::POST_VAR_NAME, $_POST ) ) { |
228
|
|
|
$_POST[ PhpConsole\Connector::POST_VAR_NAME ] = stripslashes_deep( $_POST[ PhpConsole\Connector::POST_VAR_NAME ] ); |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
// Get PHP Console instance if wasn't set yet. |
232
|
|
|
if ( ! $this->connector instanceof PhpConsole\Connector ) { |
233
|
|
|
$this->connector = PhpConsole\Connector::getInstance(); |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
// Set PHP Console password. |
237
|
|
|
try { |
238
|
|
|
$this->connector->setPassword( $password ); |
239
|
|
|
} catch ( \Exception $e ) { |
240
|
|
|
$this->print_notice_exception( $e ); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
// Get PHP Console handler instance. |
244
|
|
|
$handler = PhpConsole\Handler::getInstance(); |
245
|
|
|
|
246
|
|
|
if ( true !== PhpConsole\Handler::getInstance()->isStarted() ) { |
247
|
|
|
try { |
248
|
|
|
$handler->start(); |
249
|
|
|
} catch( \Exception $e ) { |
250
|
|
|
$this->print_notice_exception( $e ); |
251
|
|
|
} |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
// Enable SSL-only mode. |
255
|
|
|
if ( true === $this->options['ssl'] ) { |
256
|
|
|
$this->connector->enableSslOnlyMode(); |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
// Restrict IP addresses. |
260
|
|
|
$allowedIpMasks = ! empty( $this->options['ip'] ) ? explode( ',', $this->options['ip'] ) : ''; |
261
|
|
|
|
262
|
|
|
if ( is_array( $allowedIpMasks ) && count( $allowedIpMasks ) > 0 ) { |
263
|
|
|
$this->connector->setAllowedIpMasks( $allowedIpMasks ); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
$evalProvider = $this->connector->getEvalDispatcher()->getEvalProvider(); |
267
|
|
|
|
268
|
|
|
try { |
269
|
|
|
$evalProvider->addSharedVar( 'uri', $_SERVER['REQUEST_URI'] ); |
270
|
|
|
} catch ( \Exception $e ) { |
271
|
|
|
$this->print_notice_exception( $e ); |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
try { |
275
|
|
|
$evalProvider->addSharedVarReference( 'post', $_POST ); |
276
|
|
|
} catch ( \Exception $e ) { |
277
|
|
|
$this->print_notice_exception( $e ); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
$openBaseDirs = array( ABSPATH, get_template_directory() ); |
281
|
|
|
|
282
|
|
|
try { |
283
|
|
|
$evalProvider->addSharedVarReference( 'dirs', $openBaseDirs ); |
284
|
|
|
} catch ( \Exception $e ) { |
285
|
|
|
$this->print_notice_exception( $e ); |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
$evalProvider->setOpenBaseDirs( $openBaseDirs ); |
289
|
|
|
|
290
|
|
|
try { |
291
|
|
|
$this->connector->startEvalRequestsListener(); |
292
|
|
|
} catch ( \Exception $e ) { |
293
|
|
|
$this->print_notice_exception( $e ); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
|
299
|
|
|
/** |
300
|
|
|
* Prints an exception message as WordPress admin notice. |
301
|
|
|
* |
302
|
|
|
* @since 1.4.0 |
303
|
|
|
* @param \Exception $e Exception object |
304
|
|
|
*/ |
305
|
|
|
public function print_notice_exception( \Exception $e ) { |
306
|
|
|
|
307
|
|
|
add_action( 'admin_notices', function() use ( $e ) { |
308
|
|
|
|
309
|
|
|
?> |
310
|
|
|
<div class="error"> |
311
|
|
|
<p><?php printf( '%1$s: %2$s', self::NAME, $e->getMessage() ); ?></p> |
312
|
|
|
</div> |
313
|
|
|
<?php |
314
|
|
|
|
315
|
|
|
} ); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
|
319
|
|
|
|
320
|
|
|
/** |
321
|
|
|
* Admin password notice. |
322
|
|
|
* Prompts user to set a password for PHP Console upon plugin activation. |
323
|
|
|
* |
324
|
|
|
* @since 1.3.2 |
325
|
|
|
*/ |
326
|
|
|
public function password_notice() { |
327
|
|
|
|
328
|
|
|
?> |
329
|
|
|
<div class="update-nag"> |
330
|
|
|
<p><?php |
331
|
|
|
/* translators: Placeholders: %1$s - WP Php Console name, %2$s - opening HTML <a> link tag; %3$s closing HTML </a> link tag */ |
332
|
|
|
printf( __( '%1$s: Please remember to %2$sset a password%3$s if you want to enable the terminal.', 'wp-php-console' ), |
333
|
|
|
'<strong>' . self::NAME . '</strong>', |
334
|
|
|
'<a href="' . esc_url( admin_url( 'options-general.php?page=wp-php-console' ) ) .'">', |
335
|
|
|
'</a>' |
336
|
|
|
); ?> |
337
|
|
|
</p> |
338
|
|
|
</div> |
339
|
|
|
<?php |
340
|
|
|
|
341
|
|
|
} |
342
|
|
|
|
343
|
|
|
|
344
|
|
|
} |
345
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.