Issues (8)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Plugin.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * WP PHP Console
4
 *
5
 * This source file is subject to the GNU General Public License v3.0
6
 * that is bundled with this package in the file license.txt.
7
 * It is also available through the world-wide-web at this URL:
8
 * http://www.gnu.org/licenses/gpl-3.0.html
9
 *
10
 * @author    Fulvio Notarstefano <[email protected]>
11
 * @copyright Copyright (c) 2014-2020 Fulvio Notarstefano
12
 * @license   http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
13
 */
14
15
namespace WP_PHP_Console;
16
17
use PhpConsole;
18
19
defined( 'ABSPATH' ) or exit;
20
21
/**
22
 * WP PHP Console main class.
23
 *
24
 * @since 1.0.0
25
 */
26
class Plugin {
27
28
29
	/** @var string plugin version */
30
	CONST VERSION = '1.6.0';
31
32
	/** @var string plugin ID */
33
	CONST ID = 'wp-php-console';
34
35
	/** @var string plugin name */
36
	CONST NAME = 'WP PHP Console';
37
38
39
	/** @var PhpConsole\Connector instance */
40
	public $connector;
41
42
43
	/**
44
	 * Loads plugin and connects to PHP Console.
45
	 *
46
	 * @since 1.0.0
47
	 */
48
	public function __construct() {
49
50
		@error_reporting( E_ALL );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
51
52
		foreach ( [ 'WP_DEBUG',	'WP_DEBUG_LOG', 'WP_DEBUG_DISPLAY', ] as $wp_debug_constant ) {
53
			if ( ! defined( $wp_debug_constant ) ) {
54
				define ( $wp_debug_constant, true );
55
			}
56
		}
57
58
		// handle translations
59
		add_action( 'plugins_loaded', static function() {
60
			load_plugin_textdomain(
61
				'wp-php-console',
62
				false,
63
				dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/'
64
			);
65
		} );
66
67
		if ( class_exists( 'PhpConsole\Connector' ) ) {
68
			// connect to PHP Console
69
			add_action( 'init',      [ $this, 'connect' ], -1000 );
70
			// delay further PHP Console initialisation to have more context during Remote PHP execution
71
			add_action( 'wp_loaded', [ $this, 'init' ], -1000 );
72
		}
73
74
		// load admin
75
		if ( is_admin() ) {
76
			new Admin();
77
		}
78
	}
79
80
81
	/**
82
	 * Connects to PHP Console.
83
	 *
84
	 * PHP Console needs to hook in session, in WordPress we need to be in 'init':
85
	 * @link http://silvermapleweb.com/using-the-php-session-in-wordpress/
86
	 *
87
	 * @internal action hook callback
88
	 *
89
	 * @since 1.4.0
90
	 */
91
	public function connect() {
92
93
		// workaround for avoiding headers already sent warnings
94
		@error_reporting( E_ALL & ~E_WARNING );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
95
96
		if ( ! @session_id() ) {
97
			@session_start();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
98
		}
99
100
		$connected = true;
101
102
		if ( ! $this->connector instanceof PhpConsole\Connector ) {
103
			try {
104
				$this->connector = PhpConsole\Connector::getInstance();
105
			} catch ( \Exception $e ) {
106
				$connected = false;
107
			}
108
		}
109
110
		// restore error reporting
111
		@error_reporting( E_ALL );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
112
113
		// apply PHP Console options
114
		if ( $connected ) {
115
			$this->apply_options();
116
		}
117
	}
118
119
120
	/**
121
	 * Applies options.
122
	 *
123
	 * @since 1.4.0
124
	 */
125
	private function apply_options() {
126
127
		// bail out if not connected yet to PHP Console
128
		if ( ! $this->connector instanceof PhpConsole\Connector ) {
129
			return;
130
		}
131
132
		// apply 'register' option to PHP Console...
133
		if ( Settings::should_register_pc_class() && ! class_exists( 'PC', false ) ) {
134
			// ...only if PC not registered yet
135
			try {
136
				PhpConsole\Helper::register();
137
			} catch( \Exception $e ) {
138
				$this->print_notice_exception( $e );
139
			}
140
		}
141
142
		// apply 'stack' option to PHP Console
143
		if ( Settings::should_show_call_stack() ) {
144
			$this->connector->getDebugDispatcher()->detectTraceAndSource = true;
145
		}
146
147
		// apply 'short' option to PHP Console
148
		if ( Settings::should_use_short_path_names() ) {
149
			try {
150
				$this->connector->setSourcesBasePath( $_SERVER['DOCUMENT_ROOT'] );
151
			} catch ( \Exception $e ) {
152
				$this->print_notice_exception( $e );
153
			}
154
		}
155
	}
156
157
158
	/**
159
	 * Initializes PHP Console.
160
	 *
161
	 * @internal action hook callback
162
	 *
163
	 * @since 1.0.0
164
	 */
165
	public function init() {
166
167
		// bail if no password is set to connect with PHP Console
168
		if ( ! Settings::has_eval_terminal_password() ) {
169
			return;
170
		}
171
172
		// selectively remove slashes added by WordPress as expected by PHP Console
173
		if ( array_key_exists( PhpConsole\Connector::POST_VAR_NAME, $_POST ) ) {
174
			$_POST[ PhpConsole\Connector::POST_VAR_NAME ] = stripslashes_deep( $_POST[ PhpConsole\Connector::POST_VAR_NAME ] );
175
		}
176
177
		// get PHP Console instance if wasn't set yet
178
		if ( ! $this->connector instanceof PhpConsole\Connector ) {
179
180
			// workaround for avoiding headers already sent warnings
181
			@error_reporting( E_ALL & ~E_WARNING );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
182
183
			try {
184
				$this->connector = PhpConsole\Connector::getInstance();
185
				$connected       = true;
186
			} catch ( \Exception $e ) {
187
				$connected       = false;
188
			}
189
190
			// restore error reporting
191
			@error_reporting( E_ALL );
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
192
193
			if ( ! $connected ) {
194
				return;
195
			}
196
		}
197
198
		// set PHP Console password
199
		try {
200
			$this->connector->setPassword( Settings::get_eval_terminal_password() );
201
		} catch ( \Exception $e ) {
202
			$this->print_notice_exception( $e );
203
		}
204
205
		// get PHP Console handler instance
206
		$handler = PhpConsole\Handler::getInstance();
207
208
		if ( true !== PhpConsole\Handler::getInstance()->isStarted() ) {
209
			try {
210
				$handler->start();
211
			} catch( \Exception $e ) {
212
				$this->print_notice_exception( $e );
213
				return;
214
			}
215
		}
216
217
		// enable SSL-only mode
218
		if ( Settings::should_use_ssl_only() ) {
219
			$this->connector->enableSslOnlyMode();
220
		}
221
222
		// restrict IP addresses
223
		$allowedIpMasks = Settings::get_allowed_ip_masks();
224
225
		if ( count( $allowedIpMasks ) > 0 ) {
226
			$this->connector->setAllowedIpMasks( $allowedIpMasks );
227
		}
228
229
		$evalProvider = $this->connector->getEvalDispatcher()->getEvalProvider();
230
231
		try {
232
			$evalProvider->addSharedVar( 'uri', $_SERVER['REQUEST_URI'] );
233
		} catch ( \Exception $e ) {
234
			$this->print_notice_exception( $e );
235
		}
236
237
		try {
238
			$evalProvider->addSharedVarReference( 'post', $_POST );
239
		} catch ( \Exception $e ) {
240
			$this->print_notice_exception( $e );
241
		}
242
243
		$openBaseDirs = [ ABSPATH, get_template_directory() ];
244
245
		try {
246
			$evalProvider->addSharedVarReference( 'dirs', $openBaseDirs );
247
		} catch ( \Exception $e ) {
248
			$this->print_notice_exception( $e );
249
		}
250
251
		$evalProvider->setOpenBaseDirs( $openBaseDirs );
252
253
		try {
254
			$this->connector->startEvalRequestsListener();
255
		} catch ( \Exception $e ) {
256
			$this->print_notice_exception( $e );
257
		}
258
	}
259
260
261
	/**
262
	 * Prints an exception message as WordPress admin notice.
263
	 *
264
	 * @since 1.4.0
265
	 *
266
	 * @param \Exception $e Exception object
267
	 */
268
	private function print_notice_exception( \Exception $e ) {
269
270
		add_action( 'admin_notices', static function() use ( $e ) {
271
			?>
272
			<div class="error">
273
				<p><?php printf( '%1$s: %2$s', self::NAME, $e->getMessage() ); ?></p>
274
			</div>
275
			<?php
276
		} );
277
	}
278
279
280
	/**
281
	 * Gets the plugin path.
282
	 *
283
	 * @since 1.6.0
284
	 *
285
	 * @return string
286
	 */
287
	public static function get_plugin_path() {
288
289
		return untrailingslashit( dirname( __DIR__ ) );
290
	}
291
292
293
	/**
294
	 * Gets the plugin vendor path.
295
	 *
296
	 * @since 1.6.0
297
	 */
298
	public static function get_plugin_vendor_path() {
299
300
		return self::get_plugin_path() . '/vendor';
301
	}
302
303
304
	/**
305
	 * Gets the plugin page URL.
306
	 *
307
	 * @since 1.6.0
308
	 *
309
	 * @return string
310
	 */
311
	public static function get_plugin_page_url() {
312
313
		return 'https://wordpress.org/support/plugin/wp-php-console/';
314
	}
315
316
317
	/**
318
	 * Gets the plugin reviews page URL.
319
	 *
320
	 * @since 1.6.0
321
	 *
322
	 * @return string
323
	 */
324
	public static function get_reviews_page_url() {
325
326
		return 'https://wordpress.org/support/plugin/wp-php-console/reviews/';
327
	}
328
329
330
	/**
331
	 * Gets the plugin support page URL.
332
	 *
333
	 * @since 1.6.0
334
	 *
335
	 * @return string
336
	 */
337
	public static function get_support_page_url() {
338
339
		return 'https://wordpress.org/support/plugin/wp-php-console/';
340
	}
341
342
343
	/**
344
	 * Gets the GitHub repository page URL.
345
	 *
346
	 * @since 1.6.0
347
	 *
348
	 * @return string
349
	 */
350
	public static function get_wp_php_console_repository_url() {
351
352
		return 'https://github.com/unfulvio/wp-php-console';
353
	}
354
355
356
	/**
357
	 * Gets the PHP Console project page URL.
358
	 *
359
	 * @since 1.6.0
360
	 *
361
	 * @return string
362
	 */
363
	public static function get_php_console_repository_url() {
364
365
		return 'https://github.com/barbushin/php-console';
366
	}
367
368
369
	/**
370
	 * Gets the PHP Console Google Chrome extension URL.
371
	 *
372
	 * @since 1.6.0
373
	 *
374
	 * @return string
375
	 */
376
	public static function get_php_console_chrome_extension_web_store_url() {
377
378
		return 'https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef';
379
	}
380
381
382
	/**
383
	 * Gets the PHP Console Google Chrome extension repository URL.
384
	 *
385
	 * @since 1.6.0
386
	 *
387
	 * @return string
388
	 */
389
	public static function get_php_console_chrome_extension_repository_url() {
390
391
		return 'https://github.com/barbushin/php-console-extension';
392
	}
393
394
395
}
396