@wp-playground/wordpress 3.1.1 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +480 -349
- package/index.cjs.map +1 -1
- package/index.d.ts +1 -1
- package/index.js +659 -522
- package/index.js.map +1 -1
- package/package.json +9 -7
- package/wp-config.d.ts +24 -0
- package/rewrite-wp-config.d.ts +0 -22
package/index.cjs
CHANGED
|
@@ -1,358 +1,489 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("@php-wasm/util"),p=require("@wp-playground/common"),_=require("@php-wasm/logger"),d=require("@php-wasm/universal"),$=`<?php
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* with specific values.
|
|
6
|
-
*
|
|
7
|
-
* Example:
|
|
8
|
-
*
|
|
9
|
-
* \`\`\`php
|
|
10
|
-
* <?php
|
|
11
|
-
* define('WP_DEBUG', true);
|
|
12
|
-
* // The third define() argument is also supported:
|
|
13
|
-
* define('SAVEQUERIES', false, true);
|
|
14
|
-
*
|
|
15
|
-
* // Expression
|
|
16
|
-
* define(true ? 'WP_DEBUG_LOG' : 'WP_DEBUG_LOG', 123);
|
|
17
|
-
*
|
|
18
|
-
* // Guarded expressions shouldn't be wrapped twice
|
|
19
|
-
* if(!defined(1 ? 'A' : 'B')) {
|
|
20
|
-
* define(1 ? 'A' : 'B', 0);
|
|
21
|
-
* }
|
|
22
|
-
*
|
|
23
|
-
* // More advanced expression
|
|
24
|
-
* define((function() use($x) {
|
|
25
|
-
* return [$x, 'a'];
|
|
26
|
-
* })(), 123);
|
|
27
|
-
* \`\`\`
|
|
28
|
-
*
|
|
29
|
-
* Rewritten with
|
|
30
|
-
*
|
|
31
|
-
* $constants = [
|
|
32
|
-
* 'WP_DEBUG' => false,
|
|
33
|
-
* 'WP_DEBUG_LOG' => true,
|
|
34
|
-
* 'SAVEQUERIES' => true,
|
|
35
|
-
* 'NEW_CONSTANT' => "new constant",
|
|
36
|
-
* ];
|
|
37
|
-
*
|
|
38
|
-
* \`\`\`php
|
|
39
|
-
* <?php
|
|
40
|
-
* define('WP_DEBUG_LOG',true);
|
|
41
|
-
* define('NEW_CONSTANT','new constant');
|
|
42
|
-
* ?><?php
|
|
43
|
-
* define('WP_DEBUG',false);
|
|
44
|
-
* // The third define() argument is also supported:
|
|
45
|
-
* define('SAVEQUERIES',true, true);
|
|
46
|
-
*
|
|
47
|
-
* // Expression
|
|
48
|
-
* if(!defined($const ? 'WP_DEBUG_LOG' : 'WP_DEBUG_LOG')) {
|
|
49
|
-
* define($const ? 'WP_DEBUG_LOG' : 'WP_DEBUG_LOG', 123);
|
|
50
|
-
* }
|
|
51
|
-
*
|
|
52
|
-
* // Guarded expressions shouldn't be wrapped twice
|
|
53
|
-
* if(!defined(1 ? 'A' : 'B')) {
|
|
54
|
-
* define(1 ? 'A' : 'B', 0);
|
|
55
|
-
* }
|
|
56
|
-
*
|
|
57
|
-
* // More advanced expression
|
|
58
|
-
* if(!defined((function() use($x) {
|
|
59
|
-
* return [$x, 'a'];
|
|
60
|
-
* })())) {
|
|
61
|
-
* define((function() use($x) {
|
|
62
|
-
* return [$x, 'a'];
|
|
63
|
-
* })(), 123);
|
|
64
|
-
* }
|
|
65
|
-
* \`\`\`
|
|
4
|
+
* Transforms the "wp-config.php" file.
|
|
66
5
|
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
* @param bool $when_already_defined Optional. What to do if the constant is already defined.
|
|
70
|
-
* Possible values are:
|
|
71
|
-
* 'rewrite' - Rewrite the constant, using the new value.
|
|
72
|
-
* 'skip' - Skip the definition, keeping the existing value.
|
|
73
|
-
* Default: 'rewrite'
|
|
74
|
-
* @return string
|
|
6
|
+
* This parses the "wp-config.php" file contents into a token array and provides
|
|
7
|
+
* methods to modify it and serialize it back to a string with the modifications.
|
|
75
8
|
*/
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
9
|
+
class WP_Config_Transformer {
|
|
10
|
+
/**
|
|
11
|
+
* The tokens of the wp-config.php file.
|
|
12
|
+
*
|
|
13
|
+
* @var array<array|string>
|
|
14
|
+
*/
|
|
15
|
+
private $tokens;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Constructor.
|
|
19
|
+
*
|
|
20
|
+
* @param string $content The contents of the wp-config.php file.
|
|
21
|
+
*/
|
|
22
|
+
public function __construct( string $content ) {
|
|
23
|
+
$this->tokens = token_get_all( $content );
|
|
24
|
+
|
|
25
|
+
// Check if the file is a valid PHP file.
|
|
26
|
+
$is_valid_php_file = false;
|
|
27
|
+
foreach ( $this->tokens as $token ) {
|
|
28
|
+
if ( is_array( $token ) && T_OPEN_TAG === $token[0] ) {
|
|
29
|
+
$is_valid_php_file = true;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if ( ! $is_valid_php_file ) {
|
|
34
|
+
throw new Exception( "The 'wp-config.php' file is not a valid PHP file." );
|
|
35
|
+
}
|
|
36
|
+
}
|
|
102
37
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Create a new config transformer instance from a file.
|
|
40
|
+
*
|
|
41
|
+
* @param string $path The path to the wp-config.php file.
|
|
42
|
+
* @return self The new config transformer instance.
|
|
43
|
+
*/
|
|
44
|
+
public static function from_file( string $path ): self {
|
|
45
|
+
if ( ! is_file( $path ) ) {
|
|
46
|
+
throw new Exception( sprintf( "The '%s' file does not exist.", $path ) );
|
|
47
|
+
}
|
|
48
|
+
return new self( file_get_contents( $path ) );
|
|
49
|
+
}
|
|
107
50
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
51
|
+
/**
|
|
52
|
+
* Get the transformed wp-config.php file contents.
|
|
53
|
+
*
|
|
54
|
+
* @return string The transformed wp-config.php file contents.
|
|
55
|
+
*/
|
|
56
|
+
public function to_string(): string {
|
|
57
|
+
$output = '';
|
|
58
|
+
foreach ( $this->tokens as $token ) {
|
|
59
|
+
$output .= is_array( $token ) ? $token[1] : $token;
|
|
60
|
+
}
|
|
61
|
+
return $output;
|
|
62
|
+
}
|
|
123
63
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
$defined_expression[] = $token;
|
|
136
|
-
}
|
|
64
|
+
/**
|
|
65
|
+
* Save the transformed wp-config.php file contents to a file.
|
|
66
|
+
*
|
|
67
|
+
* @param string $path The path to the wp-config.php file.
|
|
68
|
+
*/
|
|
69
|
+
public function to_file( string $path ): void {
|
|
70
|
+
$result = file_put_contents( $path, $this->to_string() );
|
|
71
|
+
if ( false === $result ) {
|
|
72
|
+
throw new Exception( sprintf( "Failed to write to the '%s' file.", $path ) );
|
|
73
|
+
}
|
|
74
|
+
}
|
|
137
75
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Check if a constant is defined in the wp-config.php file.
|
|
78
|
+
*
|
|
79
|
+
* @param string $name The name of the constant.
|
|
80
|
+
* @return bool True if the constant is defined, false otherwise.
|
|
81
|
+
*/
|
|
82
|
+
public function constant_exists( string $name ): bool {
|
|
83
|
+
foreach ( $this->tokens as $i => $token ) {
|
|
84
|
+
$is_string_token = is_array( $token ) && T_STRING === $token[0];
|
|
85
|
+
if ( $is_string_token && 'define' === strtolower( $token[1] ) ) {
|
|
86
|
+
$args = $this->collect_function_call_argument_locations( $i );
|
|
87
|
+
$const_name = $this->evaluate_constant_name(
|
|
88
|
+
array_slice( $this->tokens, $args[0][0], $args[0][1] )
|
|
89
|
+
);
|
|
90
|
+
if ( $name === $const_name ) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
141
97
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Define a constant in the wp-config.php file.
|
|
100
|
+
*
|
|
101
|
+
* @param string $name The name of the constant.
|
|
102
|
+
* @param mixed $value The value of the constant.
|
|
103
|
+
*/
|
|
104
|
+
public function define_constant( string $name, $value ): void {
|
|
105
|
+
// Tokenize the new constant value for insertion in the tokens array.
|
|
106
|
+
$definition_tokens = token_get_all(
|
|
107
|
+
sprintf(
|
|
108
|
+
"<?php define( %s, %s );\\n",
|
|
109
|
+
var_export( $name, true ),
|
|
110
|
+
var_export( $value, true )
|
|
111
|
+
)
|
|
112
|
+
);
|
|
151
113
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// Examples:
|
|
155
|
-
// define("WP_DEBUG", true);
|
|
156
|
-
// ^^^^^^^^^^^
|
|
157
|
-
//
|
|
158
|
-
// define(count([1,2]) > 2 ? 'WP_DEBUG' : 'FOO', true);
|
|
159
|
-
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
160
|
-
$open_parenthesis = 0;
|
|
161
|
-
while ($token = array_pop($tokens)) {
|
|
162
|
-
$buffer[] = $token;
|
|
163
|
-
if ($token === "(" || $token === "[" || $token === "{") {
|
|
164
|
-
++$open_parenthesis;
|
|
165
|
-
} elseif ($token === ")" || $token === "]" || $token === "}") {
|
|
166
|
-
--$open_parenthesis;
|
|
167
|
-
} elseif ($token === "," && $open_parenthesis === 0) {
|
|
168
|
-
break;
|
|
169
|
-
}
|
|
114
|
+
// Full constant definition statement, e.g.: define( 'WP_DEBUG', true );\\n
|
|
115
|
+
$define_tokens = array_slice( $definition_tokens, 1 );
|
|
170
116
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
}
|
|
117
|
+
// The value of the constant, e.g.: "my-database-name"
|
|
118
|
+
$value_tokens = array_slice( $definition_tokens, 7, -4 );
|
|
174
119
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
break;
|
|
185
|
-
} else if ($token === "(" || $token === "[" || $token === "{") {
|
|
186
|
-
++$open_parenthesis;
|
|
187
|
-
} elseif ($token === ")" || $token === "]" || $token === "}") {
|
|
188
|
-
--$open_parenthesis;
|
|
189
|
-
} elseif ($token === "," && $open_parenthesis === 0) {
|
|
190
|
-
// This define call has more than 2 arguments! The third one is the
|
|
191
|
-
// boolean value indicating $is_case_insensitive. Let's continue capturing
|
|
192
|
-
// to $third_arg_buffer.
|
|
193
|
-
$is_second_argument = false;
|
|
194
|
-
}
|
|
195
|
-
if ($is_second_argument) {
|
|
196
|
-
$value_buffer[] = $token;
|
|
197
|
-
} else {
|
|
198
|
-
$third_arg_buffer[] = $token;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
120
|
+
// Collect all locations where the constant value needs to be updated.
|
|
121
|
+
$updates = array();
|
|
122
|
+
foreach ( $this->tokens as $i => $token ) {
|
|
123
|
+
$is_string_token = is_array( $token ) && T_STRING === $token[0];
|
|
124
|
+
if ( $is_string_token && 'define' === strtolower( $token[1] ) ) {
|
|
125
|
+
$args = $this->collect_function_call_argument_locations( $i );
|
|
126
|
+
$const_name = $this->evaluate_constant_name(
|
|
127
|
+
array_slice( $this->tokens, $args[0][0], $args[0][1] )
|
|
128
|
+
);
|
|
201
129
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if ($token === ";") {
|
|
208
|
-
break;
|
|
209
|
-
}
|
|
210
|
-
}
|
|
130
|
+
if ( $name === $const_name ) {
|
|
131
|
+
$updates[] = $args[1];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
211
135
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if ($token[0] === T_WHITESPACE || $token[0] === T_COMMENT || $token[0] === T_DOC_COMMENT) {
|
|
219
|
-
continue;
|
|
220
|
-
} else if ($token[0] === T_STRING || $token[0] === T_CONSTANT_ENCAPSED_STRING) {
|
|
221
|
-
$name_token = $token;
|
|
222
|
-
$name_token_index = $k;
|
|
223
|
-
} else {
|
|
224
|
-
$name_is_literal = false;
|
|
225
|
-
break;
|
|
226
|
-
}
|
|
227
|
-
} else if ($token !== "(" && $token !== ")") {
|
|
228
|
-
$name_is_literal = false;
|
|
229
|
-
break;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
136
|
+
// Modify the token array to define the constant. Apply updates in reverse
|
|
137
|
+
// order, so splices at earlier positions don't shift indices after them.
|
|
138
|
+
for ( $i = count( $updates ) - 1; $i >= 0; $i -= 1 ) {
|
|
139
|
+
list ( $value_start, $value_length ) = $updates[ $i ];
|
|
140
|
+
array_splice( $this->tokens, $value_start, $value_length, $value_tokens );
|
|
141
|
+
}
|
|
232
142
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
// Ensure the defined expression is not already accounted for
|
|
238
|
-
foreach ($defined_expressions as $defined_expression) {
|
|
239
|
-
if ($defined_expression === stringify_tokens(skip_whitespace($name_buffer))) {
|
|
240
|
-
$output = array_merge($output, $buffer);
|
|
241
|
-
continue 2;
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
$output = array_merge(
|
|
245
|
-
$output,
|
|
246
|
-
["if(!defined("],
|
|
247
|
-
$name_buffer,
|
|
248
|
-
[")) {\\n "],
|
|
249
|
-
['define('],
|
|
250
|
-
$name_buffer,
|
|
251
|
-
[','],
|
|
252
|
-
$value_buffer,
|
|
253
|
-
$third_arg_buffer,
|
|
254
|
-
[");"],
|
|
255
|
-
["\\n}\\n"]
|
|
256
|
-
);
|
|
257
|
-
continue;
|
|
258
|
-
}
|
|
143
|
+
// If it's a new constant, inject it at the anchor location.
|
|
144
|
+
if ( 0 === count( $updates ) ) {
|
|
145
|
+
$anchor = $this->get_new_constant_location();
|
|
146
|
+
array_splice( $this->tokens, $anchor, 0, $define_tokens );
|
|
259
147
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
148
|
+
/*
|
|
149
|
+
* Ensure at least one newline (one "\\n") before the new constant.
|
|
150
|
+
* This must be done after inserting the constant definition in order
|
|
151
|
+
* to avoid shifting the anchor location when a new token is inserted.
|
|
152
|
+
*/
|
|
153
|
+
$this->ensure_newlines( $anchor - 1, 1 );
|
|
154
|
+
}
|
|
155
|
+
}
|
|
263
156
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
157
|
+
/**
|
|
158
|
+
* Define multiple constants in the wp-config.php file.
|
|
159
|
+
*
|
|
160
|
+
* @param array<string, mixed> $constants An array of name-value pairs of constants to define.
|
|
161
|
+
*/
|
|
162
|
+
public function define_constants( array $constants ): void {
|
|
163
|
+
foreach ( $constants as $name => $value ) {
|
|
164
|
+
$this->define_constant( $name, $value );
|
|
165
|
+
}
|
|
166
|
+
}
|
|
270
167
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
168
|
+
/**
|
|
169
|
+
* Inject code block into the wp-config.php file.
|
|
170
|
+
*
|
|
171
|
+
* @param string $code The code to inject.
|
|
172
|
+
*/
|
|
173
|
+
public function inject_code_block( string $code ): void {
|
|
174
|
+
// Tokenize the injected code for insertion in the token array.
|
|
175
|
+
$tokens = token_get_all( sprintf( '<?php %s', trim( $code ) ) );
|
|
176
|
+
$code_tokens = array_slice( $tokens, 1 );
|
|
177
|
+
|
|
178
|
+
// Inject the code at the anchor location.
|
|
179
|
+
$anchor = $this->get_injected_code_location();
|
|
180
|
+
array_splice( $this->tokens, $anchor, 0, $code_tokens );
|
|
181
|
+
|
|
182
|
+
/*
|
|
183
|
+
* Ensure empty line before and after the code block (at least two "\\n").
|
|
184
|
+
* This must be done after inserting the injected code, and the location
|
|
185
|
+
* AFTER must be updated prior to the location BEFORE, in order to avoid
|
|
186
|
+
* shifting the anchor location when a new token is inserted.
|
|
187
|
+
*/
|
|
188
|
+
$this->ensure_newlines( $anchor + count( $code_tokens ), 2 );
|
|
189
|
+
$this->ensure_newlines( $anchor - 1, 2 );
|
|
190
|
+
}
|
|
278
191
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
// Remove the constant from the list so we can process any remaining
|
|
292
|
-
// constants later.
|
|
293
|
-
unset($constants[$name]);
|
|
294
|
-
} while (count($tokens));
|
|
295
|
-
|
|
296
|
-
// Add any constants that weren't found in the file
|
|
297
|
-
if (count($constants)) {
|
|
298
|
-
$prepend = [
|
|
299
|
-
"<?php \\n"
|
|
300
|
-
];
|
|
301
|
-
foreach ($constants as $name => $value) {
|
|
302
|
-
$prepend = array_merge(
|
|
303
|
-
$prepend,
|
|
304
|
-
[
|
|
305
|
-
"define(",
|
|
306
|
-
var_export($name, true),
|
|
307
|
-
',',
|
|
308
|
-
var_export($value, true),
|
|
309
|
-
");\\n"
|
|
310
|
-
]
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
$prepend[] = "?>";
|
|
314
|
-
$output = array_merge(
|
|
315
|
-
$prepend,
|
|
316
|
-
$output
|
|
317
|
-
);
|
|
318
|
-
}
|
|
192
|
+
/**
|
|
193
|
+
* Remove code block defined by two comment fragments from the wp-config.php file.
|
|
194
|
+
*
|
|
195
|
+
* @param string $from_comment_fragment A comment fragment from which to remove the code.
|
|
196
|
+
* @param string $to_comment_fragment A comment fragment to which to remove the code.
|
|
197
|
+
*/
|
|
198
|
+
public function remove_code_block( string $from_comment_fragment, string $to_comment_fragment ): void {
|
|
199
|
+
$start = $this->find_first_token_location( T_COMMENT, $from_comment_fragment );
|
|
200
|
+
$end = $this->find_first_token_location( T_COMMENT, $to_comment_fragment );
|
|
201
|
+
if ( null === $start || null === $end ) {
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
319
204
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
205
|
+
// Remove the code, including the comment fragments.
|
|
206
|
+
array_splice( $this->tokens, $start, $end - $start + 1 );
|
|
207
|
+
|
|
208
|
+
// If previous and next tokens are whitespace, merge them.
|
|
209
|
+
$prev = $this->tokens[ $start - 1 ];
|
|
210
|
+
$next = $this->tokens[ $start ] ?? null;
|
|
211
|
+
if (
|
|
212
|
+
is_array( $prev ) && T_WHITESPACE === $prev[0]
|
|
213
|
+
&& is_array( $next ) && T_WHITESPACE === $next[0]
|
|
214
|
+
) {
|
|
215
|
+
$this->tokens[ $start - 1 ][1] = $prev[1] . $next[1];
|
|
216
|
+
array_splice( $this->tokens, $start, 1 );
|
|
217
|
+
}
|
|
323
218
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
219
|
+
// Remove up to two empty lines (before & after), keeping at least one.
|
|
220
|
+
$token = $this->tokens[ $start - 1 ];
|
|
221
|
+
if ( is_array( $token ) && T_WHITESPACE === $token[0] ) {
|
|
222
|
+
$newlines = substr_count( $token[1], "\\n" );
|
|
223
|
+
if ( $newlines > 2 ) {
|
|
224
|
+
$limit = min( $newlines - 2, 4 );
|
|
225
|
+
$value = $token[1];
|
|
226
|
+
for ( $i = 0; $limit > 0; $i += 1 ) {
|
|
227
|
+
if ( "\\n" === $value[ $i ] ) {
|
|
228
|
+
$value = substr_replace( $value, '', $i, 1 );
|
|
229
|
+
$limit -= 1;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
$this->tokens[ $start - 1 ][1] = $value;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
335
236
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
237
|
+
/**
|
|
238
|
+
* Parse arguments of a function call and collect their locations.
|
|
239
|
+
*
|
|
240
|
+
* @param int $start The location of the first token of the function call.
|
|
241
|
+
* @return array<array<int, int>> The arguments of the function call.
|
|
242
|
+
*/
|
|
243
|
+
private function collect_function_call_argument_locations( int $start ): array {
|
|
244
|
+
// Find location of the opening parenthesis after the function name.
|
|
245
|
+
$i = $start;
|
|
246
|
+
while ( '(' !== $this->tokens[ $i ] ) {
|
|
247
|
+
$i += 1;
|
|
248
|
+
}
|
|
249
|
+
$i += 1;
|
|
250
|
+
|
|
251
|
+
// Collect all function call argument locations.
|
|
252
|
+
$args = array();
|
|
253
|
+
$arg_start = $this->skip_whitespace_and_comments( $i );
|
|
254
|
+
$parens_level = 0;
|
|
255
|
+
for ( $i = $arg_start; $i < count( $this->tokens ); $i += 1 ) {
|
|
256
|
+
// Skip whitespace and comments, but preserve the index of the last
|
|
257
|
+
// non-whitespace token to calculate the exact argument boundaries.
|
|
258
|
+
$prev_i = $i;
|
|
259
|
+
$i = $this->skip_whitespace_and_comments( $i );
|
|
260
|
+
$token = $this->tokens[ $i ];
|
|
261
|
+
|
|
262
|
+
if ( 0 === $parens_level && ( ',' === $token || ')' === $token ) ) {
|
|
263
|
+
$args[] = array( $arg_start, $prev_i - $arg_start );
|
|
264
|
+
if ( ',' === $token ) {
|
|
265
|
+
// Start of the next argument.
|
|
266
|
+
$arg_start = $this->skip_whitespace_and_comments( $i + 1 );
|
|
267
|
+
$i = $arg_start;
|
|
268
|
+
} else {
|
|
269
|
+
// End of the argument list.
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
} elseif ( '(' === $token || '[' === $token || '{' === $token ) {
|
|
273
|
+
$parens_level += 1;
|
|
274
|
+
} elseif ( ')' === $token || ']' === $token || '}' === $token ) {
|
|
275
|
+
$parens_level -= 1;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return $args;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Evaluate the constant name value from its tokens.
|
|
283
|
+
*
|
|
284
|
+
* @param array $name_tokens The tokens containing the constant name.
|
|
285
|
+
* @return string|null The evaluated constant name.
|
|
286
|
+
*/
|
|
287
|
+
private function evaluate_constant_name( array $name_tokens ): ?string {
|
|
288
|
+
// Decide whether the array represents a constant name or an expression.
|
|
289
|
+
$name_token = null;
|
|
290
|
+
foreach ( $name_tokens as $token ) {
|
|
291
|
+
if ( $this->is_whitespace( $token ) ) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if ( is_array( $token ) ) {
|
|
295
|
+
if ( T_STRING === $token[0] || T_CONSTANT_ENCAPSED_STRING === $token[0] ) {
|
|
296
|
+
$name_token = $token;
|
|
297
|
+
} else {
|
|
298
|
+
return null;
|
|
299
|
+
}
|
|
300
|
+
} elseif ( '(' !== $token && ')' !== $token ) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if ( null === $name_token ) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Get the constant name value.
|
|
310
|
+
return eval( 'return ' . $name_token[1] . ';' );
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Skip whitespace and comment tokens and return the location of the first
|
|
315
|
+
* non-whitespace and non-comment token after the specified start location.
|
|
316
|
+
*
|
|
317
|
+
* @param int $start The start location in the token array.
|
|
318
|
+
* @return int The location of the first non-whitespace and non-comment token.
|
|
319
|
+
*/
|
|
320
|
+
private function skip_whitespace_and_comments( int $start ): int {
|
|
321
|
+
for ( $i = $start; $i < count( $this->tokens ); $i += 1 ) {
|
|
322
|
+
if ( $this->is_whitespace( $this->tokens[ $i ] ) ) {
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
return $i;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Ensure minimum number of newlines are present at the given index.
|
|
332
|
+
*
|
|
333
|
+
* @param int $index The index of the token to ensure newlines.
|
|
334
|
+
* @param int $count The number of newlines that should be present.
|
|
335
|
+
*/
|
|
336
|
+
private function ensure_newlines( int $index, int $count ): void {
|
|
337
|
+
$token = $this->tokens[ $index ] ?? null;
|
|
338
|
+
if ( is_array( $token ) && ( T_WHITESPACE === $token[0] || T_OPEN_TAG === $token[0] ) ) {
|
|
339
|
+
$newlines = substr_count( $token[1], "\\n" );
|
|
340
|
+
if ( $newlines < $count ) {
|
|
341
|
+
$this->tokens[ $index ][1] .= str_repeat( "\\n", $count - $newlines );
|
|
342
|
+
}
|
|
343
|
+
} else {
|
|
344
|
+
$new_token = array( T_WHITESPACE, str_repeat( "\\n", $count ) );
|
|
345
|
+
array_splice( $this->tokens, $index, 0, array( $new_token ) );
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Get the location to inject new constant definitions in the token array.
|
|
351
|
+
*
|
|
352
|
+
* @return int The location for new constant definitions in the token array.
|
|
353
|
+
*/
|
|
354
|
+
private function get_new_constant_location(): int {
|
|
355
|
+
// First try to find the "That's all, stop editing!" comment.
|
|
356
|
+
$anchor = $this->find_first_token_location( T_COMMENT, "That's all, stop editing!" );
|
|
357
|
+
if ( null !== $anchor ) {
|
|
358
|
+
return $anchor;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// If not found, try the "Absolute path to the WordPress directory." doc comment.
|
|
362
|
+
$anchor = $this->find_first_token_location( T_DOC_COMMENT, 'Absolute path to the WordPress directory.' );
|
|
363
|
+
if ( null !== $anchor ) {
|
|
364
|
+
return $anchor;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// If not found, try the "Sets up WordPress vars and included files." doc comment.
|
|
368
|
+
$anchor = $this->find_first_token_location( T_DOC_COMMENT, 'Sets up WordPress vars and included files.' );
|
|
369
|
+
if ( null !== $anchor ) {
|
|
370
|
+
return $anchor;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// If not found, try "require_once ABSPATH . 'wp-settings.php';".
|
|
374
|
+
$anchor = $this->find_first_token_location( T_REQUIRE_ONCE );
|
|
375
|
+
if ( null !== $anchor ) {
|
|
376
|
+
return $anchor;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// If not found, fall back to the PHP opening tag.
|
|
380
|
+
$open_tag_anchor = $this->find_first_token_location( T_OPEN_TAG );
|
|
381
|
+
if ( null !== $open_tag_anchor ) {
|
|
382
|
+
return $open_tag_anchor + 1;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// If we still don't have an anchor, the file is not a valid PHP file.
|
|
386
|
+
throw new Exception( "The 'wp-config.php' file is not a valid PHP file." );
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get the location to inject new code in the token array.
|
|
391
|
+
*
|
|
392
|
+
* @return int The location for injected code in the token array.
|
|
393
|
+
*/
|
|
394
|
+
private function get_injected_code_location(): int {
|
|
395
|
+
// First try to find the "/** Sets up WordPress vars and included files. */" comment.
|
|
396
|
+
$anchor = $this->find_first_token_location( T_DOC_COMMENT, 'Sets up WordPress vars and included files.' );
|
|
397
|
+
if ( null !== $anchor ) {
|
|
398
|
+
return $anchor;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// If not found, try "require_once ABSPATH . 'wp-settings.php';".
|
|
402
|
+
$anchor = $this->find_require_wp_settings_location();
|
|
403
|
+
if ( null !== $anchor ) {
|
|
404
|
+
return $anchor;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// If not found, fall back to the PHP opening tag.
|
|
408
|
+
$open_tag_anchor = $this->find_first_token_location( T_OPEN_TAG );
|
|
409
|
+
if ( null !== $open_tag_anchor ) {
|
|
410
|
+
return $open_tag_anchor + 1;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// If we still don't have an anchor, the file is not a valid PHP file.
|
|
414
|
+
throw new Exception( "The 'wp-config.php' file is not a valid PHP file." );
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Find location of the "wp-settings.php" require statement in the token array.
|
|
419
|
+
*
|
|
420
|
+
* This method searches for the following statement:
|
|
421
|
+
*
|
|
422
|
+
* require_once ABSPATH . 'wp-settings.php';
|
|
423
|
+
*
|
|
424
|
+
* @return int|null The location of the require statement.
|
|
425
|
+
*/
|
|
426
|
+
private function find_require_wp_settings_location(): ?int {
|
|
427
|
+
$require_anchor = $this->find_first_token_location( T_REQUIRE_ONCE );
|
|
428
|
+
if ( null === $require_anchor ) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
$abspath = $this->tokens[ $require_anchor + 2 ] ?? null;
|
|
433
|
+
$path = $this->tokens[ $require_anchor + 6 ] ?? null;
|
|
434
|
+
if (
|
|
435
|
+
( is_array( $abspath ) && 'ABSPATH' === $abspath[1] )
|
|
436
|
+
&& ( is_array( $path ) && "'wp-settings.php'" === $path[1] )
|
|
437
|
+
) {
|
|
438
|
+
return $require_anchor;
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Find location of the first token of a given type in the token array.
|
|
445
|
+
*
|
|
446
|
+
* @param int $type The type of the token.
|
|
447
|
+
* @param string $search Optional. A search string to match against the token content.
|
|
448
|
+
* @return int|null The location of the first token.
|
|
449
|
+
*/
|
|
450
|
+
private function find_first_token_location( int $type, ?string $search = null ): ?int {
|
|
451
|
+
foreach ( $this->tokens as $i => $token ) {
|
|
452
|
+
if ( is_array( $token ) && $type === $token[0] ) {
|
|
453
|
+
if ( null === $search || false !== strpos( $token[1], $search ) ) {
|
|
454
|
+
return $i;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Check if a token is whitespace or a comment.
|
|
463
|
+
*
|
|
464
|
+
* @param array|string $token The token to check.
|
|
465
|
+
* @return bool True if the token is whitespace or a comment.
|
|
466
|
+
*/
|
|
467
|
+
private function is_whitespace( $token ): bool {
|
|
468
|
+
return is_array( $token )
|
|
469
|
+
&& ( T_WHITESPACE === $token[0] || T_COMMENT === $token[0] || T_DOC_COMMENT === $token[0] );
|
|
470
|
+
}
|
|
345
471
|
}
|
|
346
|
-
`;async function g(e
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
`})).
|
|
472
|
+
`;async function g(t,e){const n=r.joinPaths(e,"wp-config.php"),i={DB_NAME:"wordpress"};if(!t.fileExists(n)&&t.fileExists(r.joinPaths(e,"wp-config-sample.php"))&&await t.writeFile(n,await t.readFileAsBuffer(r.joinPaths(e,"wp-config-sample.php"))),!t.fileExists(n))return;const a=r.phpVars({wpConfigPath:n,constants:i});if((await t.run({code:`${$}
|
|
473
|
+
$wp_config_path = ${a.wpConfigPath};
|
|
474
|
+
$transformer = WP_Config_Transformer::from_file($wp_config_path);
|
|
475
|
+
foreach ( ${a.constants} as $name => $value ) {
|
|
476
|
+
if ( ! $transformer->constant_exists( $name ) ) {
|
|
477
|
+
$transformer->define_constant($name, $value);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
$transformer->to_file($wp_config_path);
|
|
481
|
+
`})).errors.length>0)throw new Error("Failed to auto-configure wp-config.php.")}async function I(t,e,n){const i=r.phpVars({wpConfigPath:e,constants:n});if((await t.run({code:`${$}
|
|
482
|
+
$wp_config_path = ${i.wpConfigPath};
|
|
483
|
+
$transformer = WP_Config_Transformer::from_file($wp_config_path);
|
|
484
|
+
$transformer->define_constants(${i.constants});
|
|
485
|
+
$transformer->to_file($wp_config_path);
|
|
486
|
+
`})).errors.length>0)throw new Error("Failed to rewrite constants in wp-config.php.")}async function x(t){const e=await w(t);return await m(e,t),e}async function m(t,e){var c,o;const n=await t.getPrimaryPhp();if((c=e.hooks)!=null&&c.beforeWordPressFiles&&await e.hooks.beforeWordPressFiles(n),e.wordPressZip&&await R(n,await e.wordPressZip),e.constants)for(const l in e.constants)n.defineConstant(l,e.constants[l]);e.dataSqlPath&&(n.defineConstant("DB_DIR",r.dirname(e.dataSqlPath)),n.defineConstant("DB_FILE",r.basename(e.dataSqlPath))),n.defineConstant("WP_HOME",e.siteUrl),n.defineConstant("WP_SITEURL",e.siteUrl),await g(n,t.documentRoot),(o=e.hooks)!=null&&o.beforeDatabaseSetup&&await e.hooks.beforeDatabaseSetup(n);let i=!1;e.sqliteIntegrationPluginZip&&(i=!0,await E(n,await e.sqliteIntegrationPluginZip));const a=e.wordpressInstallMode??"download-and-install",s=!!e.dataSqlPath;if(["download-and-install","install-from-existing-files"].includes(a)){await h(t,{usesSqlite:i,hasCustomDatabasePath:s});try{await f(n)}catch(l){throw s||await u(t),l}s||await u(t)}else if(a==="install-from-existing-files-if-needed"){if(await h(t,{usesSqlite:i,hasCustomDatabasePath:s}),!await k(n))try{await f(n)}catch(l){throw s||await u(t),l}s||await u(t)}return t}async function h(t,{usesSqlite:e,hasCustomDatabasePath:n}){const i=await t.getPrimaryPhp();if(i.isFile("/internal/shared/preload/0-sqlite.php"))return;const a=r.joinPaths(t.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");if(!i.isDir(a)&&!e&&!n)throw new Error("Error connecting to the MySQL database.")}async function u(t){const e=await t.getPrimaryPhp();if(await C(e))return;if(e.isFile("/internal/shared/preload/0-sqlite.php"))throw new Error("Error connecting to the SQLite database.");const i=r.joinPaths(t.documentRoot,"wp-content/mu-plugins/sqlite-database-integration");throw e.isDir(i)?new Error("Error connecting to the SQLite database."):new Error("Error connecting to the MySQL database.")}async function w(t){const e=t.spawnHandler??d.sandboxedSpawnHandlerFactory;async function n(a,s=!1){const c=await t.createPhpRuntime(s),o=new d.PHP(c);if(t.sapiName&&o.setSapiName(t.sapiName),a&&(o.requestHandler=a),t.phpIniEntries&&d.setPhpIniEntries(o,t.phpIniEntries),o.defineConstant("WP_SQLITE_AST_DRIVER",!0),t.constants)for(const l in t.constants)o.defineConstant(l,t.constants[l]);return s&&!o.isFile("/internal/.boot-files-written")&&(await T(o),await d.writeFiles(o,"/",t.createFiles||{}),await v(o,r.joinPaths(new URL(t.siteUrl).pathname,"phpinfo.php")),await d.writeFiles(o,"/internal",{".boot-files-written":""})),e&&await o.setSpawnHandler(e(a?()=>a.instanceManager.acquirePHPInstance():void 0)),o.enableRuntimeRotation({recreateRuntime:t.createPhpRuntime,maxRequests:400}),t.onPHPInstanceCreated&&await t.onPHPInstanceCreated(o,{isPrimary:s}),o}const i=new d.PHPRequestHandler({documentRoot:t.documentRoot||"/wordpress",absoluteUrl:t.siteUrl,rewriteRules:b,pathAliases:t.pathAliases,getFileNotFoundAction:t.getFileNotFoundAction??P,cookieStore:t.cookieStore,php:t.maxPhpInstances===1?await n(void 0,!0):void 0,phpFactory:t.maxPhpInstances!==1?async({isPrimary:a})=>n(i,a):void 0,maxPhpInstances:t.maxPhpInstances});return i}async function k(t){return(await t.run({code:`<?php
|
|
356
487
|
ob_start();
|
|
357
488
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
358
489
|
if (!file_exists($wp_load)) {
|
|
@@ -363,7 +494,7 @@ function skip_whitespace($tokens) {
|
|
|
363
494
|
ob_clean();
|
|
364
495
|
echo is_blog_installed() ? '1' : '0';
|
|
365
496
|
ob_end_flush();
|
|
366
|
-
`,env:{DOCUMENT_ROOT:
|
|
497
|
+
`,env:{DOCUMENT_ROOT:t.documentRoot}})).text==="1"}async function f(t){var i;const e=await d.withPHPIniValues(t,{disable_functions:"fsockopen",allow_url_fopen:"0"},async()=>await t.request({url:"/wp-admin/install.php?step=2",method:"POST",body:{language:"en",prefix:"wp_",weblog_title:"My WordPress Website",user_name:"admin",admin_password:"password",admin_password2:"password",Submit:"Install WordPress",pw_weak:"1",admin_email:"admin@localhost.com"}}));if(!await k(t))throw new Error(`Failed to install WordPress – installer responded with "${(i=e.text)==null?void 0:i.substring(0,100)}"`);(await t.run({code:`<?php
|
|
367
498
|
ob_start();
|
|
368
499
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
369
500
|
if (!file_exists($wp_load)) {
|
|
@@ -383,7 +514,7 @@ function skip_whitespace($tokens) {
|
|
|
383
514
|
echo '0';
|
|
384
515
|
}
|
|
385
516
|
ob_end_flush();
|
|
386
|
-
`,env:{DOCUMENT_ROOT:
|
|
517
|
+
`,env:{DOCUMENT_ROOT:t.documentRoot}})).text!=="1"&&_.logger.warn("Failed to default to pretty permalinks after WP install.")}function P(t){return{type:"internal-redirect",uri:"/index.php"}}async function C(t){return(await t.run({code:`<?php
|
|
387
518
|
ob_start();
|
|
388
519
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
389
520
|
if (!file_exists($wp_load)) {
|
|
@@ -394,10 +525,10 @@ function skip_whitespace($tokens) {
|
|
|
394
525
|
ob_clean();
|
|
395
526
|
echo $wpdb->check_connection( false ) ? '1' : '0';
|
|
396
527
|
ob_end_flush();
|
|
397
|
-
`,env:{DOCUMENT_ROOT:
|
|
398
|
-
require '${
|
|
528
|
+
`,env:{DOCUMENT_ROOT:t.documentRoot}})).text==="1"}async function L(t){const{php:e,reap:n}=await t.instanceManager.acquirePHPInstance();try{const a=(await e.run({code:`<?php
|
|
529
|
+
require '${t.documentRoot}/wp-includes/version.php';
|
|
399
530
|
echo $wp_version;
|
|
400
|
-
`})).text;if(!
|
|
531
|
+
`})).text;if(!a)throw new Error("Unable to read loaded WordPress version.");return y(a)}finally{n()}}function y(t){if(/-(alpha|beta|RC)\d*-\d+$/.test(t))return"trunk";if(/-(beta|RC)\d*$/.test(t))return"beta";const i=t.match(/^(\d+\.\d+)(?:\.\d+)?$/);return i!==null?i[1]:t}const b=[{match:new RegExp("^(/[_0-9a-zA-Z-]+)?(/wp-(content|admin|includes)/.*)"),replacement:"$2"}];async function T(t){await t.mkdir("/internal/shared/mu-plugins"),await t.writeFile("/internal/shared/preload/env.php",`<?php
|
|
401
532
|
|
|
402
533
|
// Allow adding filters/actions prior to loading WordPress.
|
|
403
534
|
// $function_to_add MUST be a string.
|
|
@@ -424,7 +555,7 @@ function skip_whitespace($tokens) {
|
|
|
424
555
|
require_once $mu_plugin;
|
|
425
556
|
}
|
|
426
557
|
}
|
|
427
|
-
`),await
|
|
558
|
+
`),await t.writeFile("/internal/shared/mu-plugins/1-auto-login.php",`<?php
|
|
428
559
|
/**
|
|
429
560
|
* Returns the username to auto-login as, if any.
|
|
430
561
|
* @return string|false
|
|
@@ -578,7 +709,7 @@ function skip_whitespace($tokens) {
|
|
|
578
709
|
}
|
|
579
710
|
return $interval;
|
|
580
711
|
});
|
|
581
|
-
`),await
|
|
712
|
+
`),await t.writeFile("/internal/shared/mu-plugins/0-playground.php",`<?php
|
|
582
713
|
// Needed because gethostbyname( 'wordpress.org' ) returns
|
|
583
714
|
// a private network IP address for some reason.
|
|
584
715
|
add_filter( 'allowed_redirect_hosts', function( $deprecated = '' ) {
|
|
@@ -620,7 +751,7 @@ function skip_whitespace($tokens) {
|
|
|
620
751
|
$log_file = WP_CONTENT_DIR . '/debug.log';
|
|
621
752
|
define('ERROR_LOG_FILE', $log_file);
|
|
622
753
|
ini_set('error_log', $log_file);
|
|
623
|
-
?>`),await
|
|
754
|
+
?>`),await t.writeFile("/internal/shared/mu-plugins/sitemap-redirect.php",`<?php
|
|
624
755
|
/**
|
|
625
756
|
* Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
|
|
626
757
|
*
|
|
@@ -644,7 +775,7 @@ function skip_whitespace($tokens) {
|
|
|
644
775
|
exit;
|
|
645
776
|
}
|
|
646
777
|
}
|
|
647
|
-
`),await
|
|
778
|
+
`),await t.writeFile("/internal/shared/preload/error-handler.php",`<?php
|
|
648
779
|
(function() {
|
|
649
780
|
$playground_consts = [];
|
|
650
781
|
if(file_exists('/internal/shared/consts.json')) {
|
|
@@ -692,18 +823,18 @@ function skip_whitespace($tokens) {
|
|
|
692
823
|
}
|
|
693
824
|
return false;
|
|
694
825
|
});
|
|
695
|
-
})();`)}async function
|
|
826
|
+
})();`)}async function v(t,e="/phpinfo.php"){await t.writeFile("/internal/shared/preload/phpinfo.php",`<?php
|
|
696
827
|
// Render PHPInfo if the requested page is /phpinfo.php
|
|
697
|
-
if ( isset($_SERVER['REQUEST_URI']) && ${
|
|
828
|
+
if ( isset($_SERVER['REQUEST_URI']) && ${r.phpVar(e)} === $_SERVER['REQUEST_URI'] ) {
|
|
698
829
|
phpinfo();
|
|
699
830
|
exit;
|
|
700
831
|
}
|
|
701
|
-
`)}async function
|
|
832
|
+
`)}async function E(t,e){await t.isDir("/tmp/sqlite-database-integration")&&await t.rmdir("/tmp/sqlite-database-integration",{recursive:!0}),await t.mkdir("/tmp/sqlite-database-integration"),await p.unzipFile(t,e,"/tmp/sqlite-database-integration");const n="/internal/shared/sqlite-database-integration",i=`/tmp/sqlite-database-integration/${(await t.listFiles("/tmp/sqlite-database-integration"))[0]}`;await t.mv(i,n),await t.defineConstant("SQLITE_MAIN_FILE","1");const s=(await t.readFileAsText(r.joinPaths(n,"db.copy"))).replace("'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",r.phpVar(n)).replace("'{SQLITE_PLUGIN}'",r.phpVar(r.joinPaths(n,"load.php"))),c=r.joinPaths(await t.documentRoot,"wp-content/db.php"),o=`<?php
|
|
702
833
|
// Do not preload this if WordPress comes with a custom db.php file.
|
|
703
|
-
if(file_exists(${
|
|
834
|
+
if(file_exists(${r.phpVar(c)})) {
|
|
704
835
|
return;
|
|
705
836
|
}
|
|
706
|
-
?>`,l="/internal/shared/mu-plugins/sqlite-database-integration.php";await
|
|
837
|
+
?>`,l="/internal/shared/mu-plugins/sqlite-database-integration.php";await t.writeFile(l,o+s),await t.writeFile("/internal/shared/preload/0-sqlite.php",o+`<?php
|
|
707
838
|
|
|
708
839
|
/**
|
|
709
840
|
* Loads the SQLite integration plugin before WordPress is loaded
|
|
@@ -753,7 +884,7 @@ class Playground_SQLite_Integration_Loader {
|
|
|
753
884
|
$GLOBALS['wpdb']->$name = $value;
|
|
754
885
|
}
|
|
755
886
|
protected function load_sqlite_integration() {
|
|
756
|
-
require_once ${
|
|
887
|
+
require_once ${r.phpVar(l)};
|
|
757
888
|
}
|
|
758
889
|
}
|
|
759
890
|
/**
|
|
@@ -778,11 +909,11 @@ if(!function_exists('mysqli_connect')) {
|
|
|
778
909
|
function mysqli_connect() {}
|
|
779
910
|
}
|
|
780
911
|
|
|
781
|
-
`),await
|
|
912
|
+
`),await t.writeFile("/internal/shared/mu-plugins/sqlite-test.php",`<?php
|
|
782
913
|
global $wpdb;
|
|
783
914
|
if(!($wpdb instanceof WP_SQLite_DB)) {
|
|
784
915
|
var_dump(isset($wpdb));
|
|
785
916
|
die("SQLite integration not loaded " . get_class($wpdb));
|
|
786
917
|
}
|
|
787
|
-
`)}async function
|
|
918
|
+
`)}async function R(t,e){t.mkdir("/tmp/unzipped-wordpress"),await p.unzipFile(t,e,"/tmp/unzipped-wordpress"),t.fileExists("/tmp/unzipped-wordpress/wordpress.zip")&&await p.unzipFile(t,"/tmp/unzipped-wordpress/wordpress.zip","/tmp/unzipped-wordpress");let n=t.fileExists("/tmp/unzipped-wordpress/wordpress")?"/tmp/unzipped-wordpress/wordpress":t.fileExists("/tmp/unzipped-wordpress/build")?"/tmp/unzipped-wordpress/build":"/tmp/unzipped-wordpress";if(!t.fileExists(r.joinPaths(n,"wp-config-sample.php"))){const a=t.listFiles(n);if(a.length){const s=a[0];t.fileExists(r.joinPaths(n,s,"wp-config-sample.php"))&&(n=r.joinPaths(n,s))}}const i=(a,s,c)=>{if(c.isDir(a)&&c.isDir(s))for(const o of c.listFiles(a)){const l=r.joinPaths(a,o),S=r.joinPaths(s,o);i(l,S,c)}else{if(c.fileExists(s)){const o=a.replace(/^\/tmp\/unzipped-wordpress\//,"/");_.logger.warn(`Cannot unzip WordPress files at ${s}: ${o} already exists.`);return}c.mv(a,s)}};i(n,t.documentRoot,t),t.fileExists(n)&&t.rmdir(n,{recursive:!0}),!t.fileExists(r.joinPaths(t.documentRoot,"wp-config.php"))&&t.fileExists(r.joinPaths(t.documentRoot,"wp-config-sample.php"))&&t.writeFile(r.joinPaths(t.documentRoot,"wp-config.php"),t.readFileAsText(r.joinPaths(t.documentRoot,"/wp-config-sample.php")))}const W=p.createMemoizedFetch(fetch),q="https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";async function A(t="latest"){if(t===null)t="latest";else if(t.startsWith("https://")||t.startsWith("http://")){const i=await crypto.subtle.digest("SHA-1",new TextEncoder().encode(t)),a=Array.from(new Uint8Array(i)).map(s=>s.toString(16).padStart(2,"0")).join("");return{releaseUrl:t,version:"custom-"+a.substring(0,8),source:"inferred"}}else if(t==="trunk"||t==="nightly"){const i=new Date().toISOString().split("T")[0];return{releaseUrl:`${q}?ts=${i}`,version:"trunk",source:"inferred"}}let n=await(await W("https://api.wordpress.org/core/version-check/1.7/?channel=beta")).json();n=n.offers.filter(i=>i.response==="autoupdate");for(const i of n){if(t==="beta"&&(i.version.includes("beta")||i.version.includes("RC")))return{releaseUrl:i.download,version:i.version,source:"api"};if(t==="latest"&&!i.version.includes("beta")&&!i.version.includes("RC"))return{releaseUrl:i.download,version:i.version,source:"api"};if(i.version.substring(0,t.length)===t)return{releaseUrl:i.download,version:i.version,source:"api"}}return t.match(/^\d+\.\d+\.0$/)&&(t=t.split(".").slice(0,2).join(".")),{releaseUrl:`https://wordpress.org/wordpress-${t}.zip`,version:t,source:"inferred"}}exports.bootRequestHandler=w;exports.bootWordPress=m;exports.bootWordPressAndRequestHandler=x;exports.defineWpConfigConstants=I;exports.ensureWpConfig=g;exports.getFileNotFoundActionForWordPress=P;exports.getLoadedWordPressVersion=L;exports.preloadPhpInfoRoute=v;exports.preloadSqliteIntegration=E;exports.resolveWordPressRelease=A;exports.setupPlatformLevelMuPlugins=T;exports.unzipWordPress=R;exports.versionStringToLoadedWordPressVersion=y;exports.wordPressRewriteRules=b;
|
|
788
919
|
//# sourceMappingURL=index.cjs.map
|