Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 62 |
|
0.00% |
0 / 3 |
CRAP | |
0.00% |
0 / 1 |
MWEval | |
0.00% |
0 / 62 |
|
0.00% |
0 / 3 |
462 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
2 | |||
canExecuteWithoutLocalSettings | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
execute | |
0.00% |
0 / 45 |
|
0.00% |
0 / 1 |
380 |
1 | <?php |
2 | /** |
3 | * This script lets a command-line user start up the wiki engine and then poke |
4 | * about by issuing PHP commands directly. |
5 | * |
6 | * Unlike eg Python, you need to use a 'return' statement explicitly for the |
7 | * interactive shell to print out the value of the expression. Multiple lines |
8 | * are evaluated separately, so blocks need to be input without a line break. |
9 | * Fatal errors such as use of undeclared functions can kill the shell. |
10 | * |
11 | * To get decent line editing behavior, you should compile PHP with support |
12 | * for GNU readline (pass --with-readline to configure). |
13 | * |
14 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by |
16 | * the Free Software Foundation; either version 2 of the License, or |
17 | * (at your option) any later version. |
18 | * |
19 | * This program is distributed in the hope that it will be useful, |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
22 | * GNU General Public License for more details. |
23 | * |
24 | * You should have received a copy of the GNU General Public License along |
25 | * with this program; if not, write to the Free Software Foundation, Inc., |
26 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
27 | * http://www.gnu.org/copyleft/gpl.html |
28 | * |
29 | * @file |
30 | * @ingroup Maintenance |
31 | */ |
32 | |
33 | use MediaWiki\HookContainer\HookRunner; |
34 | use MediaWiki\Logger\ConsoleSpi; |
35 | use MediaWiki\Logger\LoggerFactory; |
36 | use MediaWiki\Maintenance\Maintenance; |
37 | use MediaWiki\MediaWikiServices; |
38 | |
39 | // @codeCoverageIgnoreStart |
40 | require_once __DIR__ . '/Maintenance.php'; |
41 | // @codeCoverageIgnoreEnd |
42 | |
43 | /** |
44 | * Maintenance script providing an interactive console for evaluating php commands |
45 | * in the context of an initialized MediaWiki instance. |
46 | * |
47 | * @ingroup Maintenance |
48 | */ |
49 | // phpcs:disable MediaWiki.Files.ClassMatchesFilename.NotMatch |
50 | class MWEval extends Maintenance { |
51 | public function __construct() { |
52 | parent::__construct(); |
53 | $this->addDescription( |
54 | 'Maintenance script providing an interactive console for evaluating php' . |
55 | 'commands in the context of an initialized MediaWiki instance.' |
56 | ); |
57 | |
58 | $this->addOption( |
59 | 'd', |
60 | 'Write debug logs to stdout. Set "1" to enable all channels (aka debug log groups). ' |
61 | . 'Set "2" to also enable Rdbms debugging.', |
62 | false, |
63 | true |
64 | ); |
65 | |
66 | $this->addOption( |
67 | 'ignore-errors', |
68 | 'Ignore (some) errors' |
69 | ); |
70 | } |
71 | |
72 | public function canExecuteWithoutLocalSettings(): bool { |
73 | return true; |
74 | } |
75 | |
76 | public function execute() { |
77 | if ( $this->hasOption( 'd' ) ) { |
78 | $d = $this->getOption( 'd' ); |
79 | if ( $d > 0 ) { |
80 | LoggerFactory::registerProvider( new ConsoleSpi ); |
81 | // Some services hold Logger instances in object properties |
82 | MediaWikiServices::resetGlobalInstance(); |
83 | } |
84 | if ( $d > 1 ) { |
85 | $this->getServiceContainer()->getConnectionProvider()->getPrimaryDatabase()->setFlag( DBO_DEBUG ); |
86 | $this->getServiceContainer()->getConnectionProvider()->getReplicaDatabase()->setFlag( DBO_DEBUG ); |
87 | } |
88 | } |
89 | |
90 | // pull all globals into local scope |
91 | foreach ( $GLOBALS as $name => $unused ) { |
92 | // phpcs:disable MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix |
93 | // phpcs:disable MediaWiki.VariableAnalysis.UnusedGlobalVariables.UnusedGlobal$name |
94 | global $$name; |
95 | } |
96 | |
97 | $__ignoreErrors = $this->hasOption( 'ignore-errors' ); |
98 | |
99 | $__useReadline = function_exists( 'readline_add_history' ) |
100 | && Maintenance::posix_isatty( 0 /*STDIN*/ ); |
101 | |
102 | if ( $__useReadline ) { |
103 | $home = getenv( 'HOME' ); |
104 | $__historyFile = $home ? |
105 | "$home/.mweval_history" : ( MW_INSTALL_PATH . "/maintenance/.mweval_history" ); |
106 | readline_read_history( $__historyFile ); |
107 | } else { |
108 | $__historyFile = null; |
109 | } |
110 | |
111 | ( new HookRunner( $this->getServiceContainer()->getHookContainer() ) )->onMaintenanceShellStart(); |
112 | |
113 | $__e = null; // PHP exception |
114 | // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition |
115 | while ( ( $__line = Maintenance::readconsole() ) !== false ) { |
116 | if ( !$__ignoreErrors && $__e && !preg_match( '/^(exit|die);?$/', $__line ) ) { |
117 | // Internal state may be corrupted or fatals may occur later due |
118 | // to some object not being set. Don't drop out of eval in case |
119 | // lines were being pasted in (which would then get dumped to the shell). |
120 | // Instead, just absorb the remaining commands. Let "exit" through per DWIM. |
121 | echo "Exception was thrown before; please restart eval.php\n"; |
122 | continue; |
123 | } |
124 | if ( $__useReadline ) { |
125 | readline_add_history( $__line ); |
126 | // @phan-suppress-next-line PhanTypeMismatchArgumentNullableInternal |
127 | readline_write_history( $__historyFile ); |
128 | } |
129 | try { |
130 | // @phan-suppress-next-next-line SecurityCheck-RCE |
131 | // phpcs:ignore MediaWiki.Usage.ForbiddenFunctions.eval |
132 | $__val = eval( $__line . ";" ); |
133 | } catch ( Exception $__e ) { |
134 | fwrite( STDERR, "Caught exception " . get_class( $__e ) . |
135 | ": {$__e->getMessage()}\n" . $__e->getTraceAsString() . "\n" ); |
136 | continue; |
137 | } catch ( Throwable $__e ) { |
138 | if ( $__ignoreErrors ) { |
139 | fwrite( STDERR, "Caught " . get_class( $__e ) . |
140 | ": {$__e->getMessage()}\n" . $__e->getTraceAsString() . "\n" ); |
141 | continue; |
142 | } else { |
143 | throw $__e; |
144 | } |
145 | } |
146 | if ( $__val === null ) { |
147 | echo "\n"; |
148 | } elseif ( is_string( $__val ) || is_numeric( $__val ) ) { |
149 | echo "$__val\n"; |
150 | } else { |
151 | var_dump( $__val ); |
152 | } |
153 | } |
154 | |
155 | echo "\n"; |
156 | } |
157 | } |
158 | |
159 | // @codeCoverageIgnoreStart |
160 | $maintClass = MWEval::class; |
161 | require_once RUN_MAINTENANCE_IF_MAIN; |
162 | // @codeCoverageIgnoreEnd |