@wp-playground/wordpress 3.1.20 → 3.1.22
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/boot.d.ts +7 -0
- package/database-prerequisites.d.ts +9 -0
- package/index.cjs +1651 -193
- package/index.cjs.map +1 -1
- package/index.d.ts +7 -2
- package/index.js +2719 -441
- package/index.js.map +1 -1
- package/legacy-wp/legacy-boot.d.ts +39 -0
- package/legacy-wp/legacy-fixes.d.ts +86 -0
- package/legacy-wp/legacy-mu-plugins.d.ts +21 -0
- package/legacy-wp/legacy-sqlite-preload.d.ts +13 -0
- package/legacy-wp/mysql-shims.d.ts +18 -0
- package/package.json +8 -7
- package/platform-mu-plugins.d.ts +11 -0
- package/sqlite-preload-loader.d.ts +8 -0
package/index.js
CHANGED
|
@@ -1,8 +1,2253 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
1
|
+
import { isLegacyPHPVersion as w, setPhpIniEntries as P, withPHPIniValues as N, sandboxedSpawnHandlerFactory as F, PHPRequestHandler as C, PHP as q, writeFiles as b } from "@php-wasm/universal";
|
|
2
|
+
import { joinPaths as _, phpVar as $, phpVars as A, dirname as W, basename as G } from "@php-wasm/util";
|
|
3
|
+
import { unzipFile as m, createMemoizedFetch as M } from "@wp-playground/common";
|
|
4
|
+
import { logger as h } from "@php-wasm/logger";
|
|
5
|
+
async function S(e) {
|
|
6
|
+
await e.writeFile(
|
|
7
|
+
"/internal/shared/mu-plugins/0-playground.php",
|
|
8
|
+
`<?php
|
|
9
|
+
|
|
10
|
+
// Save WordPress environment information to a file.
|
|
11
|
+
// Named function (not a closure) so this file parses on PHP 5.2.
|
|
12
|
+
function playground_save_wp_env_info() {
|
|
13
|
+
if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
|
|
14
|
+
$db_info = array(
|
|
15
|
+
'type' => 'sqlite',
|
|
16
|
+
'path' => FQDB,
|
|
17
|
+
'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
|
|
18
|
+
? WP_MYSQL_ON_SQLITE_LOADER_PATH
|
|
19
|
+
: dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
|
|
20
|
+
);
|
|
21
|
+
} else {
|
|
22
|
+
$db_info = array(
|
|
23
|
+
'type' => 'mysql',
|
|
24
|
+
// TODO: Save MySQL connection config.
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
$wp_env = array('db' => $db_info);
|
|
28
|
+
$wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
|
|
29
|
+
$wp_env_file = '/internal/shared/wp-env.php';
|
|
30
|
+
if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
|
|
31
|
+
file_put_contents($wp_env_file, $wp_env_php);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
add_action('wp_loaded', 'playground_save_wp_env_info');
|
|
35
|
+
|
|
36
|
+
// Needed because gethostbyname( 'wordpress.org' ) returns
|
|
37
|
+
// a private network IP address for some reason.
|
|
38
|
+
function playground_allowed_redirect_hosts( $deprecated = '' ) {
|
|
39
|
+
return array(
|
|
40
|
+
'wordpress.org',
|
|
41
|
+
'api.wordpress.org',
|
|
42
|
+
'downloads.wordpress.org',
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
add_filter( 'allowed_redirect_hosts', 'playground_allowed_redirect_hosts' );
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Prevents wp_http_validate_url() from universally failing.
|
|
49
|
+
*
|
|
50
|
+
* wp_http_validate_url() calls gethostbyname() to verify whether the host
|
|
51
|
+
* is external. If it is internal, the URL validation fails and WordPress
|
|
52
|
+
* refuses to make a request.
|
|
53
|
+
*
|
|
54
|
+
* However, in EMscripten, gethostbyname() returns a private network IP address.
|
|
55
|
+
* This causes wp_http_validate_url() to return false for all URLs.
|
|
56
|
+
*
|
|
57
|
+
* This filter ensures that all URLs are considered external. In production
|
|
58
|
+
* environments, this would be considered a security risk. However, Playground
|
|
59
|
+
* already provides multiple code execution vectors as features (e.g. Blueprints).
|
|
60
|
+
*
|
|
61
|
+
* If someone wants to poke around local IP addresses, they already have multiple
|
|
62
|
+
* tools at their disposal. Therefore, this is not a real security risk in context
|
|
63
|
+
* of WordPress Playground or Playground CLI.
|
|
64
|
+
*/
|
|
65
|
+
add_filter('http_request_host_is_external', '__return_true');
|
|
66
|
+
|
|
67
|
+
// Support pretty permalinks
|
|
68
|
+
add_filter( 'got_url_rewrite', '__return_true' );
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Flush rewrite rules on the first real WordPress request.
|
|
72
|
+
*
|
|
73
|
+
* During boot, we set permalink_structure in the database
|
|
74
|
+
* but can't flush rewrite rules at that point because WordPress
|
|
75
|
+
* isn't fully bootstrapped — post types and taxonomies haven't
|
|
76
|
+
* been registered yet, so the generated rules are incomplete.
|
|
77
|
+
*
|
|
78
|
+
* This hook fires on 'init' at a very late priority, after all
|
|
79
|
+
* post types and taxonomies are registered. It checks if the
|
|
80
|
+
* rewrite_rules option is empty (meaning rules were never
|
|
81
|
+
* flushed) and if permalink_structure is set, then flushes once.
|
|
82
|
+
* A flag file prevents repeated flushes on subsequent requests.
|
|
83
|
+
*/
|
|
84
|
+
function playground_maybe_flush_rewrite_rules() {
|
|
85
|
+
$flag = '/internal/shared/.rewrite-rules-flushed';
|
|
86
|
+
if (file_exists($flag)) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (!function_exists('get_option')) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
$structure = get_option('permalink_structure');
|
|
93
|
+
if (empty($structure)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
$rules = get_option('rewrite_rules');
|
|
97
|
+
if (!empty($rules)) {
|
|
98
|
+
@file_put_contents($flag, '1');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
global $wp_rewrite;
|
|
102
|
+
if (!isset($wp_rewrite) && class_exists('WP_Rewrite')) {
|
|
103
|
+
$wp_rewrite = new WP_Rewrite();
|
|
104
|
+
}
|
|
105
|
+
if (isset($wp_rewrite) && method_exists($wp_rewrite, 'flush_rules')) {
|
|
106
|
+
$wp_rewrite->flush_rules();
|
|
107
|
+
}
|
|
108
|
+
@file_put_contents($flag, '1');
|
|
109
|
+
}
|
|
110
|
+
add_action('init', 'playground_maybe_flush_rewrite_rules', 99999);
|
|
111
|
+
|
|
112
|
+
// Create the fonts directory if missing
|
|
113
|
+
if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
|
|
114
|
+
mkdir(WP_CONTENT_DIR . '/fonts');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
$log_file = WP_CONTENT_DIR . '/debug.log';
|
|
118
|
+
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
|
|
119
|
+
if ( is_string( WP_DEBUG_LOG ) ) {
|
|
120
|
+
$log_file = WP_DEBUG_LOG;
|
|
121
|
+
}
|
|
122
|
+
ini_set('error_log', $log_file);
|
|
123
|
+
} else {
|
|
124
|
+
ini_set('log_errors', '0');
|
|
125
|
+
}
|
|
126
|
+
define('ERROR_LOG_FILE', $log_file);
|
|
127
|
+
?>`
|
|
128
|
+
), await e.writeFile(
|
|
129
|
+
"/internal/shared/mu-plugins/sitemap-redirect.php",
|
|
130
|
+
`<?php
|
|
131
|
+
/**
|
|
132
|
+
* Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
|
|
133
|
+
*
|
|
134
|
+
* WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
|
|
135
|
+
* rule when installed at the domain root. This mu-plugin handles the
|
|
136
|
+
* redirect for non-root installations.
|
|
137
|
+
*/
|
|
138
|
+
if (isset($_SERVER['REQUEST_URI'])) {
|
|
139
|
+
$site_url = site_url();
|
|
140
|
+
$parsed = parse_url($site_url);
|
|
141
|
+
$base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
|
|
142
|
+
|
|
143
|
+
$request_uri = $_SERVER['REQUEST_URI'];
|
|
144
|
+
if (
|
|
145
|
+
$request_uri === $base_path . '/sitemap.xml' ||
|
|
146
|
+
strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
|
|
147
|
+
strpos($request_uri, $base_path . '/sitemap.xml/') === 0
|
|
148
|
+
) {
|
|
149
|
+
$query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
|
|
150
|
+
header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
|
|
151
|
+
exit;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
`
|
|
155
|
+
), await e.writeFile(
|
|
156
|
+
"/internal/shared/mu-plugins/inline-tinymce-content-css.php",
|
|
157
|
+
`<?php
|
|
158
|
+
function playground_inline_tinymce_content_css($settings) {
|
|
159
|
+
if (empty($settings['content_css'])) return $settings;
|
|
160
|
+
$css_urls = explode(',', $settings['content_css']);
|
|
161
|
+
$inline_css = '';
|
|
162
|
+
$doc_root = isset($_SERVER['DOCUMENT_ROOT'])
|
|
163
|
+
? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
|
|
164
|
+
foreach ($css_urls as $url) {
|
|
165
|
+
$url = trim($url);
|
|
166
|
+
if (!$url) continue;
|
|
167
|
+
$parsed = parse_url($url);
|
|
168
|
+
if (!isset($parsed['path'])) continue;
|
|
169
|
+
$path = preg_replace('#^/scope:[^/]+#', '', $parsed['path']);
|
|
170
|
+
$file = $doc_root . $path;
|
|
171
|
+
if (file_exists($file)) {
|
|
172
|
+
$inline_css .= @file_get_contents($file) . "\\n";
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if ($inline_css !== '') {
|
|
176
|
+
if (!empty($settings['content_style'])) {
|
|
177
|
+
$inline_css = $settings['content_style'] . "\\n" . $inline_css;
|
|
178
|
+
}
|
|
179
|
+
$settings['content_style'] = $inline_css;
|
|
180
|
+
$settings['content_css'] = '';
|
|
181
|
+
}
|
|
182
|
+
return $settings;
|
|
183
|
+
}
|
|
184
|
+
add_filter('tiny_mce_before_init', 'playground_inline_tinymce_content_css');
|
|
185
|
+
`
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
function v(e) {
|
|
189
|
+
return `
|
|
190
|
+
/**
|
|
191
|
+
* Loads the SQLite integration plugin before WordPress is loaded
|
|
192
|
+
* and without creating a drop-in "db.php" file.
|
|
193
|
+
*
|
|
194
|
+
* Technically, it creates a global $wpdb object whose only two
|
|
195
|
+
* purposes are to:
|
|
196
|
+
*
|
|
197
|
+
* * Exist – because the require_wp_db() WordPress function won't
|
|
198
|
+
* connect to MySQL if $wpdb is already set.
|
|
199
|
+
* * Load the SQLite integration plugin the first time it's used
|
|
200
|
+
* and replace the global $wpdb reference with the SQLite one.
|
|
201
|
+
*
|
|
202
|
+
* This lets Playground keep the WordPress installation clean and
|
|
203
|
+
* solves dillemas like:
|
|
204
|
+
*
|
|
205
|
+
* * Should we include db.php in Playground exports?
|
|
206
|
+
* * Should we remove db.php from Playground imports?
|
|
207
|
+
* * How should we treat stale db.php from long-lived OPFS sites?
|
|
208
|
+
*
|
|
209
|
+
* @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
|
|
210
|
+
* more context.
|
|
211
|
+
*/
|
|
212
|
+
class Playground_SQLite_Integration_Loader {
|
|
213
|
+
public function __call($name, $arguments) {
|
|
214
|
+
$this->load_sqlite_integration();
|
|
215
|
+
if($GLOBALS['wpdb'] === $this) {
|
|
216
|
+
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
217
|
+
}
|
|
218
|
+
return call_user_func_array(
|
|
219
|
+
array($GLOBALS['wpdb'], $name),
|
|
220
|
+
$arguments
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
public function __get($name) {
|
|
224
|
+
$this->load_sqlite_integration();
|
|
225
|
+
if($GLOBALS['wpdb'] === $this) {
|
|
226
|
+
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
227
|
+
}
|
|
228
|
+
return $GLOBALS['wpdb']->$name;
|
|
229
|
+
}
|
|
230
|
+
public function __set($name, $value) {
|
|
231
|
+
$this->load_sqlite_integration();
|
|
232
|
+
if($GLOBALS['wpdb'] === $this) {
|
|
233
|
+
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
234
|
+
}
|
|
235
|
+
$GLOBALS['wpdb']->$name = $value;
|
|
236
|
+
}
|
|
237
|
+
protected function load_sqlite_integration() {
|
|
238
|
+
${e}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
|
|
243
|
+
* the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
|
|
244
|
+
* detection.
|
|
245
|
+
*
|
|
246
|
+
* @see https://github.com/WordPress/sqlite-database-integration/pull/212
|
|
247
|
+
* @see https://github.com/WordPress/sqlite-database-integration/pull/215
|
|
248
|
+
*/
|
|
249
|
+
define('QM_TESTS', true);
|
|
250
|
+
$wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* WordPress is capable of using a preloaded global $wpdb. However, if
|
|
254
|
+
* it cannot find the drop-in db.php plugin it still checks whether
|
|
255
|
+
* the mysqli_connect() function exists even though it's not used.
|
|
256
|
+
*
|
|
257
|
+
* What WordPress demands, Playground shall provide.
|
|
258
|
+
*/
|
|
259
|
+
`;
|
|
260
|
+
}
|
|
261
|
+
const H = `
|
|
262
|
+
if (function_exists('is_user_logged_in') && is_user_logged_in()) {
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (headers_sent()) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Legacy auto-login never redirects; it populates $_COOKIE
|
|
270
|
+
// in-process for the current request and relies on
|
|
271
|
+
// setcookie() / wp_set_auth_cookie() to persist across
|
|
272
|
+
// requests via HttpCookieStore.
|
|
273
|
+
|
|
274
|
+
// WP 2.5+
|
|
275
|
+
if (function_exists('wp_set_current_user') && function_exists('wp_set_auth_cookie')) {
|
|
276
|
+
$user = function_exists('get_user_by')
|
|
277
|
+
? get_user_by('login', $user_name)
|
|
278
|
+
: (function_exists('get_userdatabylogin')
|
|
279
|
+
? get_userdatabylogin($user_name) : null);
|
|
280
|
+
if (!$user) return;
|
|
281
|
+
|
|
282
|
+
wp_set_current_user($user->ID, $user->user_login);
|
|
283
|
+
// Populate $_COOKIE in-process so auth_redirect() and
|
|
284
|
+
// wp_verify_nonce() see the session for the remainder
|
|
285
|
+
// of this request; wp_set_auth_cookie() also emits
|
|
286
|
+
// Set-Cookie for subsequent requests.
|
|
287
|
+
wp_set_auth_cookie($user->ID);
|
|
288
|
+
if (function_exists('wp_generate_auth_cookie')) {
|
|
289
|
+
$_pg_exp = time() + 172800;
|
|
290
|
+
if (defined('AUTH_COOKIE'))
|
|
291
|
+
$_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'auth');
|
|
292
|
+
if (defined('SECURE_AUTH_COOKIE'))
|
|
293
|
+
$_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'secure_auth');
|
|
294
|
+
if (defined('LOGGED_IN_COOKIE'))
|
|
295
|
+
$_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($user->ID, $_pg_exp, 'logged_in');
|
|
296
|
+
}
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// WP 1.5–2.4
|
|
301
|
+
if (defined('USER_COOKIE') && defined('PASS_COOKIE')) {
|
|
302
|
+
$_pg_pass_cookie = md5(md5('password'));
|
|
303
|
+
$_COOKIE[USER_COOKIE] = $user_name;
|
|
304
|
+
$_COOKIE[PASS_COOKIE] = $_pg_pass_cookie;
|
|
305
|
+
if (!headers_sent()) {
|
|
306
|
+
$_pg_exp = time() + 172800;
|
|
307
|
+
setcookie(USER_COOKIE, $user_name, $_pg_exp, '/');
|
|
308
|
+
setcookie(PASS_COOKIE, $_pg_pass_cookie, $_pg_exp, '/');
|
|
309
|
+
}
|
|
310
|
+
$GLOBALS['current_user'] = null;
|
|
311
|
+
if (function_exists('get_currentuserinfo')) {
|
|
312
|
+
get_currentuserinfo();
|
|
313
|
+
}
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// WP 1.0–1.2: cookies are usually already set by
|
|
318
|
+
// playground_legacy_set_auth_cookies_early() in env.php,
|
|
319
|
+
// but WP 1.0–1.2 reads its user state from globals (no
|
|
320
|
+
// WP_User), so populate those explicitly here.
|
|
321
|
+
$cookiehash = defined('COOKIEHASH')
|
|
322
|
+
? COOKIEHASH
|
|
323
|
+
: (isset($GLOBALS['cookiehash']) && $GLOBALS['cookiehash']
|
|
324
|
+
? $GLOBALS['cookiehash']
|
|
325
|
+
: (function_exists('get_settings')
|
|
326
|
+
? md5(get_settings('siteurl'))
|
|
327
|
+
: ''));
|
|
328
|
+
if ($cookiehash) {
|
|
329
|
+
$_pg_user_cookie_name = 'wordpressuser_' . $cookiehash;
|
|
330
|
+
$_pg_pass_cookie_name = 'wordpresspass_' . $cookiehash;
|
|
331
|
+
$_pg_pass_cookie_value = md5(md5('password'));
|
|
332
|
+
$_COOKIE[$_pg_user_cookie_name] = $user_name;
|
|
333
|
+
$_COOKIE[$_pg_pass_cookie_name] = $_pg_pass_cookie_value;
|
|
334
|
+
if (!headers_sent()) {
|
|
335
|
+
$_pg_exp = time() + 172800;
|
|
336
|
+
setcookie($_pg_user_cookie_name, $user_name, $_pg_exp, '/');
|
|
337
|
+
setcookie($_pg_pass_cookie_name, $_pg_pass_cookie_value, $_pg_exp, '/');
|
|
338
|
+
}
|
|
339
|
+
if (function_exists('get_userdatabylogin')) {
|
|
340
|
+
$userdata = get_userdatabylogin($user_name);
|
|
341
|
+
if ($userdata) {
|
|
342
|
+
$GLOBALS['user_login'] = $user_name;
|
|
343
|
+
$GLOBALS['userdata'] = $userdata;
|
|
344
|
+
$GLOBALS['user_level'] = isset($userdata->user_level) ? (int) $userdata->user_level : 10;
|
|
345
|
+
$GLOBALS['user_ID'] = $userdata->ID;
|
|
346
|
+
$GLOBALS['user_email'] = isset($userdata->user_email) ? $userdata->user_email : '';
|
|
347
|
+
$GLOBALS['user_url'] = isset($userdata->user_url) ? $userdata->user_url : '';
|
|
348
|
+
$GLOBALS['user_nickname'] = isset($userdata->user_nickname) ? $userdata->user_nickname : $user_name;
|
|
349
|
+
$GLOBALS['user_pass_md5'] = md5(isset($userdata->user_pass) ? $userdata->user_pass : '');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
`;
|
|
355
|
+
async function B(e) {
|
|
356
|
+
await e.mkdir("/internal/shared/mu-plugins"), await e.writeFile(
|
|
357
|
+
"/internal/shared/auto_prepend_file.php",
|
|
358
|
+
`<?php
|
|
359
|
+
// Polyfill the PHP 4 superglobals WP 1.0–2.5 still reads (removed
|
|
360
|
+
// in PHP 5.4). Bind by reference so later writes to $_COOKIE
|
|
361
|
+
// reach $HTTP_COOKIE_VARS, which WP 1.0's get_currentuserinfo()
|
|
362
|
+
// consults.
|
|
363
|
+
$GLOBALS['HTTP_GET_VARS'] = &$_GET;
|
|
364
|
+
$GLOBALS['HTTP_POST_VARS'] = &$_POST;
|
|
365
|
+
$GLOBALS['HTTP_COOKIE_VARS'] = &$_COOKIE;
|
|
366
|
+
$GLOBALS['HTTP_SERVER_VARS'] = &$_SERVER;
|
|
367
|
+
if (isset($_FILES)) $GLOBALS['HTTP_POST_FILES'] = &$_FILES;
|
|
368
|
+
if (isset($_ENV)) $GLOBALS['HTTP_ENV_VARS'] = &$_ENV;
|
|
369
|
+
if (isset($_SESSION)) $GLOBALS['HTTP_SESSION_VARS'] = &$_SESSION;
|
|
370
|
+
// Top-level names register_globals=On used to expose. WP 1.0
|
|
371
|
+
// reads $PHP_SELF / $REMOTE_ADDR directly instead of $_SERVER.
|
|
372
|
+
if (isset($_SERVER['PHP_SELF'])) $GLOBALS['PHP_SELF'] = $_SERVER['PHP_SELF'];
|
|
373
|
+
if (isset($_SERVER['REMOTE_ADDR'])) $GLOBALS['REMOTE_ADDR'] = $_SERVER['REMOTE_ADDR'];
|
|
374
|
+
if (isset($_SERVER['REQUEST_URI'])) $GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
|
|
375
|
+
// Default SERVER_PROTOCOL for scripts invoked outside an HTTP
|
|
376
|
+
// request (e.g. php.run() during boot/fixups) — legacy WP reads
|
|
377
|
+
// it unconditionally in places like wp_redirect().
|
|
378
|
+
if (!isset($_SERVER['SERVER_PROTOCOL'])) {
|
|
379
|
+
$_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
|
|
380
|
+
}
|
|
381
|
+
if(file_exists('/internal/shared/consts.json')) {
|
|
382
|
+
$consts = json_decode(file_get_contents('/internal/shared/consts.json'), true);
|
|
383
|
+
if ($consts) {
|
|
384
|
+
foreach ($consts as $const => $value) {
|
|
385
|
+
if (!defined($const) && is_scalar($value)) {
|
|
386
|
+
define($const, $value);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
foreach (glob('/internal/shared/preload/*.php') as $file) {
|
|
392
|
+
require_once $file;
|
|
393
|
+
}
|
|
394
|
+
// Buffer early output so a stray PHP notice doesn't commit the
|
|
395
|
+
// response headers before the auto-login mu-plugin gets a chance
|
|
396
|
+
// to call wp_set_auth_cookie() / setcookie() on the init hook —
|
|
397
|
+
// otherwise nonce validation breaks on POST requests. PHP flushes
|
|
398
|
+
// the buffer at script end so output still reaches the browser.
|
|
399
|
+
ob_start();
|
|
400
|
+
`
|
|
401
|
+
), await e.writeFile(
|
|
402
|
+
"/internal/shared/preload/env.php",
|
|
403
|
+
`<?php
|
|
404
|
+
// Reads $wp_version from the WordPress install on disk. Falls back
|
|
405
|
+
// to '1.0' so callers can use version_compare() unconditionally.
|
|
406
|
+
function _playground_detect_wp_version() {
|
|
407
|
+
static $version = null;
|
|
408
|
+
if ($version !== null) return $version;
|
|
409
|
+
$doc_root = isset($_SERVER['DOCUMENT_ROOT'])
|
|
410
|
+
? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
|
|
411
|
+
$version_path = $doc_root . '/wp-includes/version.php';
|
|
412
|
+
$wp_version = '1.0';
|
|
413
|
+
if (file_exists($version_path)) {
|
|
414
|
+
include $version_path;
|
|
415
|
+
}
|
|
416
|
+
$version = $wp_version;
|
|
417
|
+
return $version;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Returns 'wp10', 'wp12', or 'wp15' based on the WP version on
|
|
421
|
+
// disk — the three $wp_filter shapes apply_filters() understands.
|
|
422
|
+
function _playground_detect_wp_hook_format() {
|
|
423
|
+
static $format = null;
|
|
424
|
+
if ($format !== null) return $format;
|
|
425
|
+
$wp_version = _playground_detect_wp_version();
|
|
426
|
+
if (version_compare($wp_version, '1.5', '>=')) {
|
|
427
|
+
$format = 'wp15';
|
|
428
|
+
} elseif (version_compare($wp_version, '1.2', '>=')) {
|
|
429
|
+
$format = 'wp12';
|
|
430
|
+
} else {
|
|
431
|
+
$format = 'wp10';
|
|
432
|
+
}
|
|
433
|
+
return $format;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
// Adds filters/actions before WordPress is loaded by writing the
|
|
437
|
+
// $wp_filter shape the target version expects. $function_to_add
|
|
438
|
+
// MUST be a string (no closures).
|
|
439
|
+
function playground_add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
|
440
|
+
global $wp_filter;
|
|
441
|
+
$fmt = _playground_detect_wp_hook_format();
|
|
442
|
+
if ($fmt === 'wp10') {
|
|
443
|
+
$wp_filter[$tag][] = $function_to_add;
|
|
444
|
+
} elseif ($fmt === 'wp12') {
|
|
445
|
+
$wp_filter[$tag][$priority][] = $function_to_add;
|
|
446
|
+
} else {
|
|
447
|
+
$wp_filter[$tag][$priority][$function_to_add] = array(
|
|
448
|
+
'function' => $function_to_add,
|
|
449
|
+
'accepted_args' => $accepted_args
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
function playground_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
|
|
454
|
+
playground_add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Set WP 1.0–2.4 auth cookies before WordPress loads — by the time
|
|
458
|
+
// the init hook fires (and on WP 1.0–1.2 it may not fire at all on
|
|
459
|
+
// the front page) WordPress has already read $_COOKIE. setcookie()
|
|
460
|
+
// also persists them across requests via HttpCookieStore.
|
|
461
|
+
// WP 2.5+ uses the HMAC auth cookie scheme and doesn't read these
|
|
462
|
+
// wordpressuser_/wordpresspass_ cookies at all — bail there so we
|
|
463
|
+
// don't write inert cookies the runtime would have to clean up.
|
|
464
|
+
function playground_legacy_set_auth_cookies_early() {
|
|
465
|
+
if (!defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) return;
|
|
466
|
+
if (isset($_COOKIE['playground_auto_login_already_logged_out'])) return;
|
|
467
|
+
if (version_compare(_playground_detect_wp_version(), '2.5', '>=')) return;
|
|
468
|
+
|
|
469
|
+
foreach ($_COOKIE as $name => $_) {
|
|
470
|
+
if (strncmp($name, 'wordpressuser_', 14) === 0) return;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
$user_name = PLAYGROUND_AUTO_LOGIN_AS_USER;
|
|
474
|
+
$pass_md5 = md5(md5('password'));
|
|
475
|
+
|
|
476
|
+
// Read siteurl from SQLite so the cookie hash matches what
|
|
477
|
+
// WP 1.0–2.4 derives from get_settings('siteurl').
|
|
478
|
+
$siteurl = null;
|
|
479
|
+
$db_path = defined('DB_DIR') ? DB_DIR . '.ht.sqlite' : '';
|
|
480
|
+
if ($db_path && class_exists('PDO') && file_exists($db_path)) {
|
|
481
|
+
try {
|
|
482
|
+
$pdo = new PDO('sqlite:' . $db_path);
|
|
483
|
+
$stmt = $pdo->query("SELECT option_value FROM wp_options WHERE option_name = 'siteurl' LIMIT 1");
|
|
484
|
+
if ($stmt) $siteurl = $stmt->fetchColumn();
|
|
485
|
+
$pdo = null;
|
|
486
|
+
} catch (Exception $e) {}
|
|
487
|
+
}
|
|
488
|
+
if (!$siteurl && defined('WP_SITEURL')) $siteurl = WP_SITEURL;
|
|
489
|
+
if (!$siteurl) return;
|
|
490
|
+
|
|
491
|
+
$cookiehash = md5($siteurl);
|
|
492
|
+
$user_cookie_name = 'wordpressuser_' . $cookiehash;
|
|
493
|
+
$pass_cookie_name = 'wordpresspass_' . $cookiehash;
|
|
494
|
+
$_COOKIE[$user_cookie_name] = $user_name;
|
|
495
|
+
$_COOKIE[$pass_cookie_name] = $pass_md5;
|
|
496
|
+
|
|
497
|
+
if (!headers_sent()) {
|
|
498
|
+
$exp = time() + 172800;
|
|
499
|
+
setcookie($user_cookie_name, $user_name, $exp, '/');
|
|
500
|
+
setcookie($pass_cookie_name, $pass_md5, $exp, '/');
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
playground_legacy_set_auth_cookies_early();
|
|
504
|
+
|
|
505
|
+
// WP < 4.0 emits YEAR(post_date)='2026' AND MONTH(post_date)='4'
|
|
506
|
+
// against MySQL's loose type coercion. The SQLite driver's UDFs
|
|
507
|
+
// return integers and SQLite is strictly typed (4 != '4'), so
|
|
508
|
+
// strip quotes around numeric RHS values to keep both sides ints.
|
|
509
|
+
function playground_fix_sqlite_date_comparisons($query) {
|
|
510
|
+
if (
|
|
511
|
+
stripos($query, 'YEAR') === false &&
|
|
512
|
+
stripos($query, 'MONTH') === false &&
|
|
513
|
+
stripos($query, 'DAY') === false
|
|
514
|
+
) {
|
|
515
|
+
return $query;
|
|
516
|
+
}
|
|
517
|
+
return preg_replace(
|
|
518
|
+
'/\\b(YEAR|MONTH|DAYOFMONTH|DAY)\\s*\\(([^)]+)\\)\\s*=\\s*\\'(\\d+)\\'/i',
|
|
519
|
+
'$1($2) = $3',
|
|
520
|
+
$query
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
playground_add_filter( 'query', 'playground_fix_sqlite_date_comparisons' );
|
|
524
|
+
|
|
525
|
+
// WP 2.2+ checks WP_SITEURL/WP_HOME inside get_option(); WP <2.2
|
|
526
|
+
// doesn't, so backfill the same behaviour via the option filters
|
|
527
|
+
// to keep admin links on the Playground-scoped URL.
|
|
528
|
+
function playground_override_siteurl($value) {
|
|
529
|
+
if (defined('WP_SITEURL')) {
|
|
530
|
+
return WP_SITEURL;
|
|
531
|
+
}
|
|
532
|
+
return $value;
|
|
533
|
+
}
|
|
534
|
+
function playground_override_home($value) {
|
|
535
|
+
if (defined('WP_HOME')) {
|
|
536
|
+
return WP_HOME;
|
|
537
|
+
}
|
|
538
|
+
return $value;
|
|
539
|
+
}
|
|
540
|
+
playground_add_filter( 'option_siteurl', 'playground_override_siteurl' );
|
|
541
|
+
playground_add_filter( 'option_home', 'playground_override_home' );
|
|
542
|
+
|
|
543
|
+
// Load mu-plugins last so customer mu-plugins win — and so they
|
|
544
|
+
// can't depend on muplugins_loaded. WP < 2.8 doesn't fire that
|
|
545
|
+
// action at all, so init -1000 acts as a fallback (the $loaded
|
|
546
|
+
// flag keeps it idempotent).
|
|
547
|
+
playground_add_action( 'muplugins_loaded', 'playground_load_mu_plugins', 0 );
|
|
548
|
+
playground_add_action( 'init', 'playground_load_mu_plugins', -1000 );
|
|
549
|
+
function playground_load_mu_plugins() {
|
|
550
|
+
static $loaded = false;
|
|
551
|
+
if ($loaded) return;
|
|
552
|
+
$loaded = true;
|
|
553
|
+
$mu_plugins_dir = '/internal/shared/mu-plugins';
|
|
554
|
+
if(!is_dir($mu_plugins_dir)){
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
$mu_plugins = glob( $mu_plugins_dir . '/*.php' );
|
|
558
|
+
sort( $mu_plugins );
|
|
559
|
+
global $wp_version;
|
|
560
|
+
$is_legacy_wp = isset($wp_version) && version_compare($wp_version, '2.8', '<');
|
|
561
|
+
foreach ( $mu_plugins as $mu_plugin ) {
|
|
562
|
+
// Loaded separately by the preload lazy loader or db.php.
|
|
563
|
+
if (strpos($mu_plugin, 'sqlite-database-integration') !== false) {
|
|
564
|
+
continue;
|
|
565
|
+
}
|
|
566
|
+
// WP < 2.8 crashes on closures in hooks and lacks
|
|
567
|
+
// site_url() (added 2.6). 1-auto-login.php is written
|
|
568
|
+
// without either, so it's the only mu-plugin we load
|
|
569
|
+
// on legacy WP.
|
|
570
|
+
if ($is_legacy_wp) {
|
|
571
|
+
if (strpos($mu_plugin, '1-auto-login.php') === false) {
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
require_once $mu_plugin;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// PHP 5.x's foreach over $wp_filter['init'] iterates a copy,
|
|
579
|
+
// so add_action() calls made by the mu-plugin we just loaded
|
|
580
|
+
// won't fire on this same init run. Call them directly.
|
|
581
|
+
if ($is_legacy_wp) {
|
|
582
|
+
if (function_exists('playground_auto_login_redirect_target')) {
|
|
583
|
+
playground_auto_login_redirect_target();
|
|
584
|
+
}
|
|
585
|
+
if (function_exists('playground_auto_login')) {
|
|
586
|
+
playground_auto_login();
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
`
|
|
591
|
+
), await e.writeFile(
|
|
592
|
+
"/internal/shared/mu-plugins/1-auto-login.php",
|
|
593
|
+
`<?php
|
|
594
|
+
/**
|
|
595
|
+
* Returns the username to auto-login as, if any.
|
|
596
|
+
* @return string|false
|
|
597
|
+
*/
|
|
598
|
+
function playground_get_username_for_auto_login() {
|
|
599
|
+
if ( defined('PLAYGROUND_AUTO_LOGIN_AS_USER') && !isset($_COOKIE['playground_auto_login_already_happened']) ) {
|
|
600
|
+
return PLAYGROUND_AUTO_LOGIN_AS_USER;
|
|
601
|
+
}
|
|
602
|
+
if ( defined('PLAYGROUND_FORCE_AUTO_LOGIN_ENABLED') && isset($_GET['playground_force_auto_login_as_user']) ) {
|
|
603
|
+
return $_GET['playground_force_auto_login_as_user'];
|
|
604
|
+
}
|
|
605
|
+
return false;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function playground_auto_login() {
|
|
609
|
+
if (empty($_SERVER['REQUEST_URI'])) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
$user_name = playground_get_username_for_auto_login();
|
|
613
|
+
if ( false === $user_name ) {
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
if ((function_exists('wp_doing_ajax') && wp_doing_ajax()) || defined('REST_REQUEST')) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
${H}
|
|
620
|
+
}
|
|
621
|
+
add_action('init', 'playground_auto_login', 1);
|
|
622
|
+
|
|
623
|
+
function playground_auto_login_redirect_target() {
|
|
624
|
+
if(strpos($_SERVER['REQUEST_URI'], '?playground-redirection-handler') !== false) {
|
|
625
|
+
$next = $_GET['next'];
|
|
626
|
+
header('Location: ' . $next, true, 302);
|
|
627
|
+
exit;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
add_action('init', 'playground_auto_login_redirect_target', 1);
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* Disable the Site Admin Email Verification Screen for any session started
|
|
634
|
+
* via autologin.
|
|
635
|
+
*/
|
|
636
|
+
if (function_exists('add_filter')) {
|
|
637
|
+
add_filter('admin_email_check_interval', 'playground_disable_admin_email_check');
|
|
638
|
+
}
|
|
639
|
+
function playground_disable_admin_email_check($interval) {
|
|
640
|
+
if(false === playground_get_username_for_auto_login()) {
|
|
641
|
+
return 0;
|
|
642
|
+
}
|
|
643
|
+
return $interval;
|
|
644
|
+
}
|
|
645
|
+
`
|
|
646
|
+
), await S(e), await e.writeFile(
|
|
647
|
+
"/internal/shared/preload/error-handler.php",
|
|
648
|
+
`<?php
|
|
649
|
+
$GLOBALS['_playground_consts'] = array();
|
|
650
|
+
if (file_exists('/internal/shared/consts.json')) {
|
|
651
|
+
$GLOBALS['_playground_consts'] = @json_decode(file_get_contents('/internal/shared/consts.json'), true);
|
|
652
|
+
if (!is_array($GLOBALS['_playground_consts'])) { $GLOBALS['_playground_consts'] = array(); }
|
|
653
|
+
$GLOBALS['_playground_consts'] = array_keys($GLOBALS['_playground_consts']);
|
|
654
|
+
}
|
|
655
|
+
function _playground_error_handler($severity, $message, $file, $line) {
|
|
656
|
+
$playground_consts = $GLOBALS['_playground_consts'];
|
|
657
|
+
${V}
|
|
658
|
+
return false;
|
|
659
|
+
}
|
|
660
|
+
set_error_handler('_playground_error_handler');`
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
const V = `
|
|
664
|
+
// http_api_transports is deprecated since 6.4.0 but Playground's
|
|
665
|
+
// networking layer still registers it for wp_http_supports().
|
|
666
|
+
// @see https://core.trac.wordpress.org/ticket/37708
|
|
667
|
+
if (
|
|
668
|
+
strpos($message, "http_api_transports") !== false &&
|
|
669
|
+
strpos($message, "since version 6.4.0 with no alternative available") !== false
|
|
670
|
+
) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
// Playground predefines constants (SITE_URL, WP_DEBUG, …) that
|
|
674
|
+
// wp-config.php is allowed to redefine; ours take precedence.
|
|
675
|
+
if (strpos($message, "already defined") !== false) {
|
|
676
|
+
foreach($playground_consts as $const) {
|
|
677
|
+
if(strpos($message, "Constant $const already defined") !== false) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
// Legacy WP (2.0–3.5) assigns props on uninitialised vars,
|
|
683
|
+
// valid in PHP 4 but E_WARNING since 5.x. Unfixable in core —
|
|
684
|
+
// Playground ships unmodified WordPress releases.
|
|
685
|
+
if (strpos($message, "Creating default object from empty value") !== false) {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
// WP 2.8's dashboard widget calls get_error_string() on a
|
|
689
|
+
// null SimplePie when feed HTTP requests fail in WASM.
|
|
690
|
+
if (strpos($message, "get_error_string() on null") !== false ||
|
|
691
|
+
strpos($message, "get_error_string() on a non-object") !== false) {
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
// Don't complain about WordPress.org connection errors when
|
|
695
|
+
// the runtime isn't using fetch().
|
|
696
|
+
if (
|
|
697
|
+
(
|
|
698
|
+
! defined('USE_FETCH_FOR_REQUESTS') ||
|
|
699
|
+
! USE_FETCH_FOR_REQUESTS
|
|
700
|
+
) &&
|
|
701
|
+
strpos($message, "WordPress could not establish a secure connection to WordPress.org") !== false)
|
|
702
|
+
{
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
`;
|
|
706
|
+
async function X(e, t) {
|
|
707
|
+
const i = T(e, t);
|
|
708
|
+
if (i === null) return;
|
|
709
|
+
const n = parseFloat(i);
|
|
710
|
+
if (!Number.isFinite(n) || n < 5 || n >= 6.2)
|
|
711
|
+
return;
|
|
712
|
+
const s = _(t, "wp-includes/load.php");
|
|
713
|
+
if (!e.fileExists(s)) return;
|
|
714
|
+
const r = e.readFileAsText(s), a = r.replace(
|
|
715
|
+
"extension_loaded( 'mysqli' )",
|
|
716
|
+
"function_exists( 'mysqli_connect' )"
|
|
717
|
+
);
|
|
718
|
+
a !== r && await e.writeFile(s, a);
|
|
719
|
+
}
|
|
720
|
+
function T(e, t) {
|
|
721
|
+
const i = _(t, "wp-includes/version.php");
|
|
722
|
+
if (!e.fileExists(i)) return null;
|
|
723
|
+
const s = e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
|
|
724
|
+
return s ? s[1] : null;
|
|
725
|
+
}
|
|
726
|
+
const Y = 22527, L = "E_ALL & ~8192 & ~2048";
|
|
727
|
+
async function K(e, t) {
|
|
728
|
+
await se(e, t), await ae(e, t), await oe(e, t), await ue(e, t), await de(e, t), await Le(e, t), await fe(e, t), await we(e, t), await Z(e, t), await z(e, t);
|
|
729
|
+
const i = T(e, t);
|
|
730
|
+
if (i === null) return;
|
|
731
|
+
const n = parseFloat(i);
|
|
732
|
+
Number.isFinite(n) && (n < 1.2 && (await re(e, t), await ie(e, t)), n < 1.5 && await J(e, t), 1.5 <= n && n < 2 && await ge(e, t), n < 2 && (await ee(e, t), await ce(e, t)), 2.1 <= n && n < 2.3 && await ne(e, t), n < 2.5 && await $e(e, t), n < 2.8 && (await Ee(e, t), await Te(e, t)), 2.9 <= n && n < 3.6 && await j(e, t), 3.3 <= n && n < 3.4 && await te(e, t), n >= 4.7 && await Q(e, t));
|
|
733
|
+
}
|
|
734
|
+
async function Q(e, t) {
|
|
735
|
+
const i = _(t, "wp-content/themes");
|
|
736
|
+
if (e.isDir(i))
|
|
737
|
+
for (const n of e.listFiles(i)) {
|
|
738
|
+
const s = _(i, n, "searchform.php");
|
|
739
|
+
e.fileExists(s) && e.unlink(s);
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
async function j(e, t) {
|
|
743
|
+
const i = _(t, "wp-admin/includes/dashboard.php");
|
|
744
|
+
if (e.fileExists(i)) {
|
|
745
|
+
let r = e.readFileAsText(i);
|
|
746
|
+
if (r.includes("function wp_dashboard_primary()") && !r.includes("/* pg_no_rss */")) {
|
|
747
|
+
for (const a of [
|
|
748
|
+
"wp_dashboard_primary",
|
|
749
|
+
"wp_dashboard_secondary",
|
|
750
|
+
"wp_dashboard_plugins"
|
|
751
|
+
])
|
|
752
|
+
r = r.replace(
|
|
753
|
+
new RegExp(`function ${a}\\(\\)\\s*\\{`),
|
|
754
|
+
`function ${a}() { /* pg_no_rss */ return;`
|
|
755
|
+
);
|
|
756
|
+
await e.writeFile(i, r);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
const n = _(t, "wp-admin/admin.php");
|
|
760
|
+
if (e.fileExists(n)) {
|
|
761
|
+
let r = e.readFileAsText(n);
|
|
762
|
+
r.includes("do_action('admin_init');") && !r.includes("/* pg_admin_init_cleanup */") && (r = r.replace(
|
|
763
|
+
"do_action('admin_init');",
|
|
764
|
+
`/* pg_admin_init_cleanup */
|
|
765
|
+
if (function_exists('remove_action')) {
|
|
766
|
+
@remove_action('admin_init', '_maybe_update_plugins');
|
|
767
|
+
@remove_action('admin_init', '_maybe_update_themes');
|
|
768
|
+
@remove_action('admin_init', '_maybe_update_core');
|
|
769
|
+
@remove_action('admin_init', 'wp_version_check');
|
|
770
|
+
@remove_action('admin_init', 'wp_update_plugins');
|
|
771
|
+
@remove_action('admin_init', 'wp_update_themes');
|
|
772
|
+
}
|
|
773
|
+
do_action('admin_init');`
|
|
774
|
+
), await e.writeFile(n, r));
|
|
775
|
+
}
|
|
776
|
+
const s = _(
|
|
777
|
+
t,
|
|
778
|
+
"wp-admin/includes/update.php"
|
|
779
|
+
);
|
|
780
|
+
if (e.fileExists(s)) {
|
|
781
|
+
let r = e.readFileAsText(s);
|
|
782
|
+
if (!r.includes("/* pg_admin_no_updates */")) {
|
|
783
|
+
for (const a of [
|
|
784
|
+
"wp_plugin_update_rows",
|
|
785
|
+
"wp_plugin_update_row",
|
|
786
|
+
"wp_theme_update_rows",
|
|
787
|
+
"wp_theme_update_row",
|
|
788
|
+
"wp_update_plugins",
|
|
789
|
+
"wp_update_themes"
|
|
790
|
+
]) {
|
|
791
|
+
const o = new RegExp(
|
|
792
|
+
`function ${a}\\s*\\([^)]*\\)\\s*\\{`
|
|
793
|
+
);
|
|
794
|
+
o.test(r) && (r = r.replace(
|
|
795
|
+
o,
|
|
796
|
+
(l) => l + " /* pg_admin_no_updates */ return;"
|
|
797
|
+
));
|
|
798
|
+
}
|
|
799
|
+
await e.writeFile(s, r);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
for (const r of [
|
|
803
|
+
_(t, "wp-includes/SimplePie/File.php"),
|
|
804
|
+
_(t, "wp-includes/class-simplepie.php")
|
|
805
|
+
]) {
|
|
806
|
+
if (!e.fileExists(r)) continue;
|
|
807
|
+
let a = e.readFileAsText(r);
|
|
808
|
+
a.includes("function SimplePie_File(") && !a.includes("/* pg_no_fetch */") && (a = a.replace(
|
|
809
|
+
/function SimplePie_File\([^)]*\)\s*\{/,
|
|
810
|
+
(o) => o + `
|
|
811
|
+
/* pg_no_fetch */
|
|
812
|
+
$this->error = 'Network requests disabled in Playground';
|
|
813
|
+
$this->success = false;
|
|
814
|
+
return;`
|
|
815
|
+
), await e.writeFile(r, a));
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
async function z(e, t) {
|
|
819
|
+
const i = [
|
|
820
|
+
["function wp_new_blog_notification", "pg_no_blog_notification"],
|
|
821
|
+
[
|
|
822
|
+
"function wp_install_maybe_enable_pretty_permalinks",
|
|
823
|
+
"pg_no_permalink_check"
|
|
824
|
+
]
|
|
825
|
+
], n = [
|
|
826
|
+
_(t, "wp-admin/includes/upgrade.php"),
|
|
827
|
+
_(t, "wp-admin/upgrade-functions.php")
|
|
828
|
+
];
|
|
829
|
+
for (const s of n) {
|
|
830
|
+
if (!e.fileExists(s)) continue;
|
|
831
|
+
let r = e.readFileAsText(s), a = !1;
|
|
832
|
+
for (const [o, l] of i) {
|
|
833
|
+
if (r.includes(`/* ${l} */`)) continue;
|
|
834
|
+
const c = r.indexOf(o);
|
|
835
|
+
if (c === -1) continue;
|
|
836
|
+
const u = r.indexOf("{", c);
|
|
837
|
+
u !== -1 && (r = r.substring(0, u + 1) + ` /* ${l} */ return;` + r.substring(u + 1), a = !0);
|
|
838
|
+
}
|
|
839
|
+
a && await e.writeFile(s, r);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
async function Z(e, t) {
|
|
843
|
+
const i = _(t, "wp-load.php");
|
|
844
|
+
if (!e.fileExists(i)) return;
|
|
845
|
+
const n = e.readFileAsText(i);
|
|
846
|
+
if (!n.includes("error_reporting(") || n.includes("~8192") && n.includes("~2048")) return;
|
|
847
|
+
const s = n.replace(
|
|
848
|
+
/error_reporting\(([^)]+)\)/g,
|
|
849
|
+
(r, a) => `error_reporting((${a}) & ~8192 & ~2048)`
|
|
850
|
+
);
|
|
851
|
+
await e.writeFile(i, s);
|
|
852
|
+
}
|
|
853
|
+
async function J(e, t) {
|
|
854
|
+
const i = _(t, "wp-admin/menu.php");
|
|
855
|
+
if (e.fileExists(i)) {
|
|
856
|
+
const r = e.readFileAsText(i);
|
|
857
|
+
if (!r.includes("/* pg_wp10_logo_link */")) {
|
|
858
|
+
const a = '<h1 id="wphead"><a href="http://wordpress.org" rel="external">WordPress</a></h1>';
|
|
859
|
+
if (r.includes(a)) {
|
|
860
|
+
const o = r.replace(
|
|
861
|
+
a,
|
|
862
|
+
'<h1 id="wphead"><a href="#" rel="external">WordPress</a></h1> <!-- pg_wp10_logo_link -->'
|
|
863
|
+
);
|
|
864
|
+
o !== r && await e.writeFile(i, o);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
const n = _(
|
|
869
|
+
t,
|
|
870
|
+
"wp-admin/admin-header.php"
|
|
871
|
+
);
|
|
872
|
+
if (e.fileExists(n)) {
|
|
873
|
+
const r = e.readFileAsText(n);
|
|
874
|
+
if (!r.includes("/* pg_wp12_logo_link */")) {
|
|
875
|
+
const a = '<a href="http://wordpress.org" rel="external"', o = "</a>", l = r.indexOf(a);
|
|
876
|
+
if (l !== -1) {
|
|
877
|
+
const c = r.indexOf(o, l);
|
|
878
|
+
if (c !== -1) {
|
|
879
|
+
const u = r.substring(0, l) + '<a href="#">WordPress</a><!-- pg_wp12_logo_link -->' + r.substring(c + o.length);
|
|
880
|
+
u !== r && await e.writeFile(n, u);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
const s = _(
|
|
886
|
+
t,
|
|
887
|
+
"wp-admin/admin-footer.php"
|
|
888
|
+
);
|
|
889
|
+
if (e.fileExists(s)) {
|
|
890
|
+
const r = e.readFileAsText(s);
|
|
891
|
+
if (!r.includes("/* pg_wp10_footer_link */")) {
|
|
892
|
+
const a = r.replace(
|
|
893
|
+
'<a href="http://wordpress.org">WordPress</a>',
|
|
894
|
+
"WordPress<!-- pg_wp10_footer_link -->"
|
|
895
|
+
).replace(
|
|
896
|
+
'<a href="http://wordpress.org/">WordPress</a>',
|
|
897
|
+
"WordPress<!-- pg_wp10_footer_link -->"
|
|
898
|
+
);
|
|
899
|
+
a !== r && await e.writeFile(s, a);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
async function ee(e, t) {
|
|
904
|
+
const i = _(t, "wp-admin/edit.php");
|
|
905
|
+
if (!e.fileExists(i)) return;
|
|
906
|
+
const n = e.readFileAsText(i);
|
|
907
|
+
if (n.includes("/* pg_wp10_post_title_edit */")) return;
|
|
908
|
+
let s = n;
|
|
909
|
+
const r = '<strong><a href="<?php permalink_link(); ?>" rel="permalink"><?php the_title() ?></a></strong>';
|
|
910
|
+
s.includes(r) && (s = s.replace(
|
|
911
|
+
r,
|
|
912
|
+
'<strong><a href="post.php?action=edit&post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a></strong>'
|
|
913
|
+
));
|
|
914
|
+
const a = '<td><a href="<?php the_permalink(); ?>" rel="permalink">';
|
|
915
|
+
s.includes(a) && (s = s.replace(
|
|
916
|
+
a,
|
|
917
|
+
'<td><a href="post.php?action=edit&post=<?php echo $id /* pg_wp10_post_title_edit */ ?>">'
|
|
918
|
+
));
|
|
919
|
+
const o = `<td><?php the_title() ?>
|
|
920
|
+
<?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`;
|
|
921
|
+
s.includes(o) && (s = s.replace(
|
|
922
|
+
o,
|
|
923
|
+
`<td><a href="post.php?action=edit&post=<?php echo $id /* pg_wp10_post_title_edit */ ?>"><?php the_title() ?></a>
|
|
924
|
+
<?php if ('private' == $post->post_status) _e(' - <strong>Private</strong>'); ?></td>`
|
|
925
|
+
)), s !== n && await e.writeFile(i, s);
|
|
926
|
+
}
|
|
927
|
+
async function te(e, t) {
|
|
928
|
+
const i = _(t, "wp-admin/includes/screen.php");
|
|
929
|
+
if (!e.fileExists(i)) return;
|
|
930
|
+
const n = e.readFileAsText(i);
|
|
931
|
+
if (!n.includes("self::$this->_help_sidebar")) return;
|
|
932
|
+
const s = n.replace(
|
|
933
|
+
/self::\$this->_help_sidebar/g,
|
|
934
|
+
"$this->_help_sidebar"
|
|
935
|
+
);
|
|
936
|
+
s !== n && await e.writeFile(i, s);
|
|
937
|
+
}
|
|
938
|
+
async function ne(e, t) {
|
|
939
|
+
const i = _(t, "wp-admin/plugins.php");
|
|
940
|
+
if (!e.fileExists(i)) return;
|
|
941
|
+
const n = e.readFileAsText(i);
|
|
942
|
+
if (n.includes("/* pg_wp21_active_plugins_array */")) return;
|
|
943
|
+
const s = "$current = get_option('active_plugins');";
|
|
944
|
+
if (!n.includes(s)) return;
|
|
945
|
+
const r = n.replace(
|
|
946
|
+
s,
|
|
947
|
+
s + `
|
|
948
|
+
if (!is_array($current)) $current = array(); /* pg_wp21_active_plugins_array */`
|
|
949
|
+
);
|
|
950
|
+
r !== n && await e.writeFile(i, r);
|
|
951
|
+
}
|
|
952
|
+
async function ie(e, t) {
|
|
953
|
+
const i = _(t, "wp-login.php");
|
|
954
|
+
if (!e.fileExists(i)) return;
|
|
955
|
+
const n = e.readFileAsText(i), s = "AND user_pass = '$password'";
|
|
956
|
+
if (!n.includes(s) || n.includes("pg_wp10_plain_or_md5")) return;
|
|
957
|
+
let r = n.replace(
|
|
958
|
+
s,
|
|
959
|
+
"AND (user_pass = '$password' OR user_pass = MD5('$password')) /* pg_wp10_plain_or_md5 */"
|
|
960
|
+
);
|
|
961
|
+
r = r.replace(
|
|
962
|
+
"$login->user_pass == $password",
|
|
963
|
+
"($login->user_pass == $password || $login->user_pass == md5($password))"
|
|
964
|
+
), r !== n && await e.writeFile(i, r);
|
|
965
|
+
}
|
|
966
|
+
async function se(e, t) {
|
|
967
|
+
const i = _(t, "wp-includes");
|
|
968
|
+
if (!e.isDir(i)) return;
|
|
969
|
+
const n = _(i, "version.php");
|
|
970
|
+
e.fileExists(n) || await e.writeFile(n, "<?php $wp_version = '1.0';");
|
|
971
|
+
}
|
|
972
|
+
async function re(e, t) {
|
|
973
|
+
const i = _(t, "wp-blog-header.php");
|
|
974
|
+
if (e.fileExists(i)) {
|
|
975
|
+
const s = e.readFileAsText(i), r = `$where .= ' AND (post_status = "publish"';`;
|
|
976
|
+
s.includes(r) && await e.writeFile(
|
|
977
|
+
i,
|
|
978
|
+
s.replace(
|
|
979
|
+
r,
|
|
980
|
+
`$where .= " AND (post_status = 'publish'";`
|
|
981
|
+
)
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
const n = _(t, "wp-includes/vars.php");
|
|
985
|
+
if (e.fileExists(n)) {
|
|
986
|
+
const s = e.readFileAsText(n), r = "add_filter('all', 'wptexturize');";
|
|
987
|
+
s.includes(r) && await e.writeFile(
|
|
988
|
+
n,
|
|
989
|
+
s.replace(
|
|
990
|
+
r,
|
|
991
|
+
`// ${r} // Disabled by Playground: mangles SQL literals.`
|
|
992
|
+
)
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
async function ae(e, t) {
|
|
997
|
+
const i = _(t, "wp-load.php");
|
|
998
|
+
e.fileExists(i) || await e.writeFile(
|
|
999
|
+
i,
|
|
1000
|
+
`<?php
|
|
1001
|
+
if ( !defined('ABSPATH') ) {
|
|
1002
|
+
define('ABSPATH', dirname(__FILE__) . '/');
|
|
1003
|
+
}
|
|
1004
|
+
require_once(ABSPATH . 'wp-config.php');
|
|
1005
|
+
`
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
async function oe(e, t) {
|
|
1009
|
+
const i = _(t, "wp-settings.php");
|
|
1010
|
+
if (!e.fileExists(i)) return;
|
|
1011
|
+
const n = e.readFileAsText(i);
|
|
1012
|
+
let s = n;
|
|
1013
|
+
s = s.replace(
|
|
1014
|
+
/if\s*\(\s*!extension_loaded\('mysql'\)\s*\)\s*\n\s*die/,
|
|
1015
|
+
`if ( false ) // Patched for SQLite
|
|
1016
|
+
die`
|
|
1017
|
+
), s = s.replace(
|
|
1018
|
+
/error_reporting\(([^)]+)\)/g,
|
|
1019
|
+
(r, a) => a.includes("~8192") && a.includes("~2048") ? r : `error_reporting((${a}) & ~8192 & ~2048)`
|
|
1020
|
+
), s = s.replace(
|
|
1021
|
+
/set_magic_quotes_runtime\(\s*0\s*\)\s*;/g,
|
|
1022
|
+
"// set_magic_quotes_runtime(0); // Removed"
|
|
1023
|
+
), s.includes("function_exists('get_magic_quotes_gpc')") || (s = s.replace(
|
|
1024
|
+
/get_magic_quotes_gpc\(\)/g,
|
|
1025
|
+
"(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())"
|
|
1026
|
+
)), s = s.replace(/=\s*&\s*new\b/g, "= new"), s = s.replace(/\$HTTP_SERVER_VARS/g, "$_SERVER"), !s.includes("WP_CONTENT_DIR") && s.includes("define('WPINC'") && (s = s.replace(
|
|
1027
|
+
/define\('WPINC',\s*'wp-includes'\);/,
|
|
1028
|
+
`define('WPINC', 'wp-includes');
|
|
1029
|
+
if (!defined('WP_CONTENT_DIR')) define('WP_CONTENT_DIR', ABSPATH . 'wp-content');`
|
|
1030
|
+
)), s = s.replace(/unset\(\s*\$wp_filter\s*,/, "unset("), s = _e(s), s = le(s), s !== n && await e.writeFile(i, s);
|
|
1031
|
+
}
|
|
1032
|
+
function _e(e) {
|
|
1033
|
+
const t = e.indexOf("installed WP");
|
|
1034
|
+
if (t === -1) return e;
|
|
1035
|
+
const i = e.lastIndexOf("die(", t);
|
|
1036
|
+
if (i === -1) return e;
|
|
1037
|
+
let n = 0;
|
|
1038
|
+
for (let s = i + 3; s < e.length; s++)
|
|
1039
|
+
if (e[s] === "(") n++;
|
|
1040
|
+
else if (e[s] === ")" && (n--, n === 0)) {
|
|
1041
|
+
let r = s + 1;
|
|
1042
|
+
return e[r] === ";" && r++, e.substring(0, i) + "true; /* die removed by Playground */" + e.substring(r);
|
|
1043
|
+
}
|
|
1044
|
+
return e;
|
|
1045
|
+
}
|
|
1046
|
+
function le(e) {
|
|
1047
|
+
return e.replace(
|
|
1048
|
+
"do_action('init');",
|
|
1049
|
+
`// Remove hooks that make outbound HTTP requests (crash WASM).
|
|
1050
|
+
if (function_exists('remove_action')) {
|
|
1051
|
+
@remove_action('init', 'wp_cron');
|
|
1052
|
+
@remove_action('init', 'wp_version_check');
|
|
1053
|
+
@remove_action('init', 'wp_update_plugins');
|
|
1054
|
+
@remove_action('init', 'wp_update_themes');
|
|
1055
|
+
@remove_action('admin_init', '_maybe_update_plugins');
|
|
1056
|
+
@remove_action('admin_init', '_maybe_update_themes');
|
|
1057
|
+
@remove_action('admin_init', 'wp_version_check');
|
|
1058
|
+
@remove_action('admin_init', 'wp_update_plugins');
|
|
1059
|
+
@remove_action('admin_init', 'wp_update_themes');
|
|
1060
|
+
@remove_action('load-plugins.php', 'wp_update_plugins');
|
|
1061
|
+
@remove_action('load-update.php', 'wp_update_plugins');
|
|
1062
|
+
@remove_action('load-update.php', 'wp_update_themes');
|
|
1063
|
+
@remove_action('load-themes.php', 'wp_update_themes');
|
|
1064
|
+
@remove_action('wp_update_plugins', 'wp_update_plugins');
|
|
1065
|
+
@remove_action('wp_version_check', 'wp_version_check');
|
|
1066
|
+
}
|
|
1067
|
+
if (function_exists('add_filter')) {
|
|
1068
|
+
function _pg_disable_curl() { return false; }
|
|
1069
|
+
function _pg_disable_streams() { return false; }
|
|
1070
|
+
@add_filter('use_curl_transport', '_pg_disable_curl');
|
|
1071
|
+
@add_filter('use_streams_transport', '_pg_disable_streams');
|
|
1072
|
+
@add_filter('use_ftp_transport', '_pg_disable_curl');
|
|
1073
|
+
@add_filter('use_fsockopen_transport', '_pg_disable_streams');
|
|
1074
|
+
}
|
|
1075
|
+
do_action('init');`
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
async function ce(e, t) {
|
|
1079
|
+
const i = _(
|
|
1080
|
+
t,
|
|
1081
|
+
"wp-includes/functions.php"
|
|
1082
|
+
);
|
|
1083
|
+
if (!e.fileExists(i)) return;
|
|
1084
|
+
let n = e.readFileAsText(i), s = !1;
|
|
1085
|
+
n.includes("$all_options->{$option->option_name}") && !n.includes("$all_options = new stdClass") && (n = n.replace(
|
|
1086
|
+
"foreach ($options as $option) {",
|
|
1087
|
+
`$all_options = new stdClass;
|
|
1088
|
+
foreach ($options as $option) {`
|
|
1089
|
+
), s = !0), s && await e.writeFile(i, n);
|
|
1090
|
+
}
|
|
1091
|
+
async function ue(e, t) {
|
|
1092
|
+
const i = _(t, "wp-admin/install.php");
|
|
1093
|
+
if (!e.fileExists(i)) return;
|
|
1094
|
+
const n = e.readFileAsText(i);
|
|
1095
|
+
let s = n;
|
|
1096
|
+
const r = _(t, "wp-admin");
|
|
1097
|
+
s = s.replace(/'\.\.\/(wp-config\.php)'/g, `'${t}/$1'`).replace(/'\.\.\/(wp-load\.php)'/g, `'${t}/$1'`).replace(/'\.\/(upgrade-functions\.php)'/g, `'${r}/$1'`).replace(/'(upgrade-functions\.php)'/g, `'${r}/$1'`).replace(/'\.\/(includes\/upgrade\.php)'/g, `'${r}/$1'`).replace(/'\.\.\/(wp-includes\/[^']+)'/g, `'${t}/$1'`), s = s.replace(/\$HTTP_GET_VARS/g, "$_GET").replace(/\$HTTP_POST_VARS/g, "$_POST"), s !== n && await e.writeFile(i, s);
|
|
1098
|
+
}
|
|
1099
|
+
async function de(e, t) {
|
|
1100
|
+
const i = _(t, "wp-includes/wp-db.php");
|
|
1101
|
+
if (!e.fileExists(i)) return;
|
|
1102
|
+
const n = e.readFileAsText(i);
|
|
1103
|
+
let s = n;
|
|
1104
|
+
s.includes("isset($wpdb)") || (s = s.replace(
|
|
1105
|
+
"$wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST);",
|
|
1106
|
+
"if ( !isset($wpdb) ) { $wpdb = new wpdb(DB_USER, DB_PASSWORD, DB_NAME, DB_HOST); }"
|
|
1107
|
+
)), s.includes("db_connect") || (s = s.replace(
|
|
1108
|
+
/\$this->dbh\s*=\s*@mysql_connect\(\$dbhost\s*,\s*\$dbuser\s*,\s*\$dbpassword(?:\s*,\s*true)?\);/,
|
|
1109
|
+
'if (method_exists($this, "db_connect")) { $this->dbname = $dbname; $this->db_connect(); } else { $this->dbh = @mysql_connect($dbhost, $dbuser, $dbpassword); }'
|
|
1110
|
+
)), s = pe(s), s !== n && await e.writeFile(i, s);
|
|
1111
|
+
}
|
|
1112
|
+
function pe(e) {
|
|
1113
|
+
const t = [];
|
|
1114
|
+
if (e.includes("function set_prefix") || t.push(`
|
|
1115
|
+
function set_prefix($prefix) {
|
|
1116
|
+
$this->prefix = $prefix;
|
|
1117
|
+
$tables = array('posts', 'users', 'categories', 'post2cat', 'comments', 'link2cat', 'links', 'options', 'postmeta', 'usermeta', 'terms', 'term_taxonomy', 'term_relationships');
|
|
1118
|
+
foreach ($tables as $t) {
|
|
1119
|
+
$this->$t = $prefix . $t;
|
|
1120
|
+
}
|
|
1121
|
+
return $prefix;
|
|
1122
|
+
}`), e.includes("function timer_start") || t.push(`
|
|
1123
|
+
function timer_start() {
|
|
1124
|
+
$this->time_start = microtime(true);
|
|
1125
|
+
return true;
|
|
1126
|
+
}`), e.includes("function timer_stop") || t.push(`
|
|
1127
|
+
function timer_stop() {
|
|
1128
|
+
return microtime(true) - $this->time_start;
|
|
1129
|
+
}`), e.includes("function init_charset") || t.push(`
|
|
1130
|
+
function init_charset() {
|
|
1131
|
+
if (defined('DB_CHARSET')) $this->charset = DB_CHARSET;
|
|
1132
|
+
if (defined('DB_COLLATE')) $this->collate = DB_COLLATE;
|
|
1133
|
+
}`), e.includes("function bail") || t.push(`
|
|
1134
|
+
function bail($message, $error_code = '500') {
|
|
1135
|
+
die($message);
|
|
1136
|
+
}`), e.includes("function check_connection") || t.push(`
|
|
1137
|
+
function check_connection($allow_bail = true) {
|
|
1138
|
+
return true;
|
|
1139
|
+
}`), t.length === 0) return e;
|
|
1140
|
+
const i = e.match(
|
|
1141
|
+
/^(\s*})\s*\n+(\$wpdb|\?>\s*$|if\s*\(\s*!\s*isset\(\s*\$wpdb\s*\))/m
|
|
1142
|
+
);
|
|
1143
|
+
if (!i || i.index === void 0) return e;
|
|
1144
|
+
const n = `
|
|
1145
|
+
// Polyfills added by WordPress Playground.
|
|
1146
|
+
` + t.join(`
|
|
1147
|
+
`) + `
|
|
1148
|
+
|
|
1149
|
+
`;
|
|
1150
|
+
return e.substring(0, i.index) + n + e.substring(i.index);
|
|
1151
|
+
}
|
|
1152
|
+
async function fe(e, t) {
|
|
1153
|
+
const i = (a) => {
|
|
1154
|
+
let o = a, l = 0;
|
|
1155
|
+
for (; o.startsWith("../"); )
|
|
1156
|
+
l++, o = o.slice(3);
|
|
1157
|
+
for (; o.startsWith("./"); )
|
|
1158
|
+
o = o.slice(2);
|
|
1159
|
+
let c = "dirname(__FILE__)";
|
|
1160
|
+
for (let u = 0; u < l; u++)
|
|
1161
|
+
c = `dirname(${c})`;
|
|
1162
|
+
return `${c} . '/${o}'`;
|
|
1163
|
+
}, n = _(t, "wp-admin");
|
|
1164
|
+
if (e.isDir(n))
|
|
1165
|
+
for (const a of e.listFiles(n)) {
|
|
1166
|
+
if (!a.endsWith(".php")) continue;
|
|
1167
|
+
const o = _(n, a), l = e.readFileAsText(o), c = l.replace(
|
|
1168
|
+
/((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\.\/[^'"]+)\2\s*\)/g,
|
|
1169
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1170
|
+
).replace(
|
|
1171
|
+
/((?:require|include)(?:_once)?)\s*\(\s*(['"])(\.\/[^'"]+)\2\s*\)/g,
|
|
1172
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1173
|
+
).replace(
|
|
1174
|
+
/((?:require|include)(?:_once)?)\s*\(\s*(['"])([a-z][\w-]*\.php)\2\s*\)/g,
|
|
1175
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1176
|
+
).replace(
|
|
1177
|
+
/((?:require|include)(?:_once)?)\s+(['"])(\.\.\/[^'"]+)\2/g,
|
|
1178
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1179
|
+
).replace(
|
|
1180
|
+
/((?:require|include)(?:_once)?)\s+(['"])(\.\/[^'"]+)\2/g,
|
|
1181
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1182
|
+
).replace(
|
|
1183
|
+
/((?:require|include)(?:_once)?)\s+(['"])([a-z][\w-]*\.php)\2/g,
|
|
1184
|
+
(u, d, f, p) => `${d}(${i(p)})`
|
|
1185
|
+
).replace(/ABSPATH\s*\.\s*'\/wp-/g, "ABSPATH . 'wp-");
|
|
1186
|
+
c !== l && await e.writeFile(o, c);
|
|
1187
|
+
}
|
|
1188
|
+
const s = _(t, "wp-admin/index.php");
|
|
1189
|
+
if (e.fileExists(s)) {
|
|
1190
|
+
let a = e.readFileAsText(s);
|
|
1191
|
+
a.includes("get_settings('siteurl')") && (a = a.replace(
|
|
1192
|
+
/get_settings\('siteurl'\)\s*\.\s*'\/wp-admin\//g,
|
|
1193
|
+
"'"
|
|
1194
|
+
), await e.writeFile(s, a));
|
|
1195
|
+
}
|
|
1196
|
+
const r = _(t, "wp-admin/menu.php");
|
|
1197
|
+
if (e.fileExists(r)) {
|
|
1198
|
+
const a = e.readFileAsText(r), o = "file('./menu.txt')";
|
|
1199
|
+
a.includes(o) && await e.writeFile(
|
|
1200
|
+
r,
|
|
1201
|
+
a.replace(o, "file(dirname(__FILE__) . '/menu.txt')")
|
|
1202
|
+
);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
async function $e(e, t) {
|
|
1206
|
+
const i = _(
|
|
1207
|
+
t,
|
|
1208
|
+
"wp-admin/admin-functions.php"
|
|
1209
|
+
);
|
|
1210
|
+
if (!e.fileExists(i)) return;
|
|
1211
|
+
const n = e.readFileAsText(i);
|
|
1212
|
+
if (!n.includes("function check_admin_referer()") || !n.includes("$_SERVER['HTTP_REFERER']"))
|
|
1213
|
+
return;
|
|
1214
|
+
const s = he(
|
|
1215
|
+
n,
|
|
1216
|
+
"check_admin_referer",
|
|
1217
|
+
`
|
|
1218
|
+
do_action('check_admin_referer', '');
|
|
1219
|
+
`
|
|
1220
|
+
);
|
|
1221
|
+
s !== n && await e.writeFile(i, s);
|
|
1222
|
+
}
|
|
1223
|
+
function he(e, t, i) {
|
|
1224
|
+
const n = `function ${t}()`, s = e.indexOf(n);
|
|
1225
|
+
if (s === -1) return e;
|
|
1226
|
+
const r = e.indexOf("{", s + n.length);
|
|
1227
|
+
if (r === -1) return e;
|
|
1228
|
+
let a = 1;
|
|
1229
|
+
for (let o = r + 1; o < e.length; o++) {
|
|
1230
|
+
const l = e[o];
|
|
1231
|
+
if (l === "{") a++;
|
|
1232
|
+
else if (l === "}" && (a--, a === 0))
|
|
1233
|
+
return e.substring(0, r + 1) + i + e.substring(o);
|
|
1234
|
+
}
|
|
1235
|
+
return e;
|
|
1236
|
+
}
|
|
1237
|
+
async function ge(e, t) {
|
|
1238
|
+
const i = _(t, "wp-admin/index.php");
|
|
1239
|
+
if (e.fileExists(i)) {
|
|
1240
|
+
const n = e.readFileAsText(i), s = n.replace(/AND post_date_gmt < '\$today'/, "");
|
|
1241
|
+
s !== n && await e.writeFile(i, s);
|
|
1242
|
+
}
|
|
1243
|
+
await me(e, t);
|
|
1244
|
+
}
|
|
1245
|
+
async function me(e, t) {
|
|
1246
|
+
const i = _(t, "wp-includes/rss-functions.php");
|
|
1247
|
+
if (!e.fileExists(i)) return;
|
|
1248
|
+
let n = e.readFileAsText(i);
|
|
1249
|
+
!/^\s*error\s*\(/m.test(n) || /^function\s+error\s*\(/m.test(n) || (n = n.replace(
|
|
1250
|
+
/^(<\?php\s*)/,
|
|
1251
|
+
`$1
|
|
1252
|
+
if (!function_exists('error')) {
|
|
1253
|
+
function error($msg = '', $lvl = E_USER_WARNING) {
|
|
1254
|
+
if (defined('MAGPIE_DEBUG') && MAGPIE_DEBUG) {
|
|
1255
|
+
trigger_error($msg, $lvl);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
`
|
|
1260
|
+
), await e.writeFile(i, n));
|
|
1261
|
+
}
|
|
1262
|
+
async function we(e, t) {
|
|
1263
|
+
const i = _(t, "wp-login.php");
|
|
1264
|
+
if (!e.fileExists(i)) return;
|
|
1265
|
+
let n = e.readFileAsText(i), s = !1;
|
|
1266
|
+
for (const r of ["log", "pwd"]) {
|
|
1267
|
+
const a = new RegExp(
|
|
1268
|
+
`(\\bname=(['"])${r}\\2)(?![^>]*data-1p-ignore)`
|
|
1269
|
+
);
|
|
1270
|
+
a.test(n) && (n = n.replace(a, "$1 data-1p-ignore"), s = !0);
|
|
1271
|
+
}
|
|
1272
|
+
s && await e.writeFile(i, n);
|
|
1273
|
+
}
|
|
1274
|
+
async function Ee(e, t) {
|
|
1275
|
+
const i = _(t, "wp-admin/admin.php");
|
|
1276
|
+
if (e.fileExists(i)) {
|
|
1277
|
+
const s = e.readFileAsText(i);
|
|
1278
|
+
if (s.includes("auth_redirect()")) {
|
|
1279
|
+
const r = `
|
|
1280
|
+
// Playground: populate auth cookies and force admin user before auth_redirect.
|
|
1281
|
+
if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
|
|
1282
|
+
if (function_exists('is_user_logged_in') && is_user_logged_in()) {
|
|
1283
|
+
// On WP < 4.0, wp_set_auth_cookie() does not update $_COOKIE
|
|
1284
|
+
// in-process — auth_redirect() reads $_COOKIE, so re-emit.
|
|
1285
|
+
if (function_exists('wp_generate_auth_cookie') && defined('LOGGED_IN_COOKIE') && empty($_COOKIE[LOGGED_IN_COOKIE])) {
|
|
1286
|
+
$_pg_uid = wp_get_current_user()->ID;
|
|
1287
|
+
$_pg_exp = time() + 172800;
|
|
1288
|
+
$_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'auth');
|
|
1289
|
+
if (defined('SECURE_AUTH_COOKIE'))
|
|
1290
|
+
$_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'secure_auth');
|
|
1291
|
+
$_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_uid, $_pg_exp, 'logged_in');
|
|
1292
|
+
}
|
|
1293
|
+
} else {
|
|
1294
|
+
${x("PLAYGROUND_AUTO_LOGIN_AS_USER")}
|
|
1295
|
+
// WP 2.0-2.4: kses_init() runs during do_action('init') inside
|
|
1296
|
+
// wp-settings.php and caches $current_user as WP_User(0) when
|
|
1297
|
+
// no cookies were set yet. Reset and re-evaluate so capability
|
|
1298
|
+
// checks see the user we just authenticated.
|
|
1299
|
+
if (!function_exists('wp_generate_auth_cookie')) {
|
|
1300
|
+
$GLOBALS['current_user'] = null;
|
|
1301
|
+
if (function_exists('get_currentuserinfo')) {
|
|
1302
|
+
get_currentuserinfo();
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
// Force admin caps in-memory: if populate_roles() never ran
|
|
1307
|
+
// (e.g. WP 2.0, or WP 2.5 installs that crashed before writing
|
|
1308
|
+
// roles), the user has no caps and every current_user_can() fails.
|
|
1309
|
+
$_pg_cu = isset($GLOBALS['current_user']) ? $GLOBALS['current_user'] : null;
|
|
1310
|
+
if ($_pg_cu && isset($_pg_cu->ID) && $_pg_cu->ID > 0 && empty($_pg_cu->allcaps['read'])) {
|
|
1311
|
+
// Respect a DB-stored user_level so a blueprint that auto-logs
|
|
1312
|
+
// in as a lower-privilege user doesn't silently get level 10.
|
|
1313
|
+
$_pg_db_level = isset($_pg_cu->user_level)
|
|
1314
|
+
? (int) $_pg_cu->user_level
|
|
1315
|
+
: null;
|
|
1316
|
+
if ($_pg_db_level === null && isset($_pg_user) && $_pg_user) {
|
|
1317
|
+
$_pg_db_level = isset($_pg_user->user_level)
|
|
1318
|
+
? (int) $_pg_user->user_level
|
|
1319
|
+
: null;
|
|
1320
|
+
}
|
|
1321
|
+
$_pg_cu->user_level = $_pg_db_level !== null ? $_pg_db_level : 10;
|
|
1322
|
+
$_pg_effective_level = $_pg_cu->user_level;
|
|
1323
|
+
$_pg_caps = array('read');
|
|
1324
|
+
for ($_pg_i = 0; $_pg_i <= $_pg_effective_level; $_pg_i++) {
|
|
1325
|
+
$_pg_caps[] = 'level_' . $_pg_i;
|
|
1326
|
+
}
|
|
1327
|
+
if ($_pg_effective_level >= 10) {
|
|
1328
|
+
$_pg_caps = array_merge($_pg_caps, array(
|
|
1329
|
+
'switch_themes','edit_themes','activate_plugins',
|
|
1330
|
+
'edit_plugins','edit_users','edit_files','manage_options',
|
|
1331
|
+
'moderate_comments','manage_categories','manage_links',
|
|
1332
|
+
'upload_files','import','unfiltered_html','edit_posts',
|
|
1333
|
+
'edit_others_posts','edit_published_posts','publish_posts',
|
|
1334
|
+
'edit_pages'));
|
|
1335
|
+
}
|
|
1336
|
+
foreach ($_pg_caps as $_pg_c) {
|
|
1337
|
+
$_pg_cu->allcaps[$_pg_c] = true;
|
|
1338
|
+
}
|
|
1339
|
+
if ($_pg_effective_level >= 10) {
|
|
1340
|
+
$_pg_cu->caps = array('administrator' => true);
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
`, a = s.replace(
|
|
1345
|
+
"auth_redirect();",
|
|
1346
|
+
r + "auth_redirect();"
|
|
1347
|
+
);
|
|
1348
|
+
a !== s && await e.writeFile(i, a);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
const n = _(t, "wp-admin/auth.php");
|
|
1352
|
+
if (e.fileExists(n)) {
|
|
1353
|
+
const s = e.readFileAsText(n);
|
|
1354
|
+
if (s.includes("$cookiehash") && !s.includes("Playground: bypass auth")) {
|
|
1355
|
+
const r = `<?php
|
|
1356
|
+
require_once(ABSPATH . 'wp-config.php');
|
|
1357
|
+
// Playground: bypass auth and manually populate user globals.
|
|
1358
|
+
global $user_login, $userdata, $user_level, $user_ID,
|
|
1359
|
+
$user_nickname, $user_email, $user_url, $user_pass_md5, $cookiehash;
|
|
1360
|
+
$__pg_user_login = defined('PLAYGROUND_AUTO_LOGIN_AS_USER')
|
|
1361
|
+
? PLAYGROUND_AUTO_LOGIN_AS_USER
|
|
1362
|
+
: 'admin';
|
|
1363
|
+
$__pg_cookiehash = defined('COOKIEHASH')
|
|
1364
|
+
? COOKIEHASH
|
|
1365
|
+
: (isset($cookiehash) && $cookiehash
|
|
1366
|
+
? $cookiehash
|
|
1367
|
+
: md5(function_exists('get_settings') ? get_settings('siteurl') : ''));
|
|
1368
|
+
if ($__pg_cookiehash) {
|
|
1369
|
+
$_COOKIE['wordpressuser_' . $__pg_cookiehash] = $__pg_user_login;
|
|
1370
|
+
}
|
|
1371
|
+
if (function_exists('get_userdatabylogin')) {
|
|
1372
|
+
$__pg_userdata = get_userdatabylogin($__pg_user_login);
|
|
1373
|
+
if ($__pg_userdata) {
|
|
1374
|
+
$user_login = $__pg_user_login;
|
|
1375
|
+
$userdata = $__pg_userdata;
|
|
1376
|
+
$user_level = isset($__pg_userdata->user_level)
|
|
1377
|
+
? (int) $__pg_userdata->user_level
|
|
1378
|
+
: 10;
|
|
1379
|
+
$user_ID = $__pg_userdata->ID;
|
|
1380
|
+
$user_nickname = isset($__pg_userdata->user_nickname)
|
|
1381
|
+
? $__pg_userdata->user_nickname
|
|
1382
|
+
: $__pg_user_login;
|
|
1383
|
+
$user_email = isset($__pg_userdata->user_email)
|
|
1384
|
+
? $__pg_userdata->user_email
|
|
1385
|
+
: '';
|
|
1386
|
+
$user_url = isset($__pg_userdata->user_url)
|
|
1387
|
+
? $__pg_userdata->user_url
|
|
1388
|
+
: '';
|
|
1389
|
+
$user_pass_md5 = md5(
|
|
1390
|
+
isset($__pg_userdata->user_pass) ? $__pg_userdata->user_pass : ''
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
?>`;
|
|
1395
|
+
r !== s && await e.writeFile(n, r);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
async function Te(e, t) {
|
|
1400
|
+
const i = _(t, "wp-admin/admin-ajax.php");
|
|
1401
|
+
if (!e.fileExists(i)) return;
|
|
1402
|
+
let n = e.readFileAsText(i);
|
|
1403
|
+
if (!n.includes("is_user_logged_in")) return;
|
|
1404
|
+
const s = `
|
|
1405
|
+
// Playground: authenticate admin user for AJAX requests on WP < 2.8.
|
|
1406
|
+
if (defined('PLAYGROUND_AUTO_LOGIN_AS_USER')) {
|
|
1407
|
+
${x("PLAYGROUND_AUTO_LOGIN_AS_USER")}
|
|
1408
|
+
}
|
|
1409
|
+
`;
|
|
1410
|
+
n = n.replace(
|
|
1411
|
+
/if\s*\(\s*!\s*is_user_logged_in\(\)\s*\)/,
|
|
1412
|
+
s + "if ( !is_user_logged_in() )"
|
|
1413
|
+
), await e.writeFile(i, n);
|
|
1414
|
+
}
|
|
1415
|
+
function x(e) {
|
|
1416
|
+
return `
|
|
1417
|
+
$_pg_user = null;
|
|
1418
|
+
if (function_exists('wp_generate_auth_cookie')) {
|
|
1419
|
+
$_pg_user = function_exists('get_user_by')
|
|
1420
|
+
? get_user_by('login', ${e})
|
|
1421
|
+
: (function_exists('get_userdatabylogin')
|
|
1422
|
+
? get_userdatabylogin(${e}) : null);
|
|
1423
|
+
if ($_pg_user) {
|
|
1424
|
+
wp_set_current_user($_pg_user->ID, $_pg_user->user_login);
|
|
1425
|
+
$_pg_exp = time() + 172800;
|
|
1426
|
+
if (defined('AUTH_COOKIE'))
|
|
1427
|
+
$_COOKIE[AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'auth');
|
|
1428
|
+
if (defined('SECURE_AUTH_COOKIE'))
|
|
1429
|
+
$_COOKIE[SECURE_AUTH_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'secure_auth');
|
|
1430
|
+
if (defined('LOGGED_IN_COOKIE'))
|
|
1431
|
+
$_COOKIE[LOGGED_IN_COOKIE] = wp_generate_auth_cookie($_pg_user->ID, $_pg_exp, 'logged_in');
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
`;
|
|
1435
|
+
}
|
|
1436
|
+
async function Le(e, t) {
|
|
1437
|
+
const i = T(e, t);
|
|
1438
|
+
if (i === null) return;
|
|
1439
|
+
const n = parseFloat(i);
|
|
1440
|
+
if (!Number.isFinite(n) || n >= 3.3) return;
|
|
1441
|
+
const s = _(
|
|
1442
|
+
t,
|
|
1443
|
+
"wp-admin/includes/schema.php"
|
|
1444
|
+
);
|
|
1445
|
+
if (!e.fileExists(s)) return;
|
|
1446
|
+
const r = e.readFileAsText(s);
|
|
1447
|
+
/\$wp_queries\s*=\s*"CREATE TABLE/.test(r) && !r.includes("function wp_get_db_schema") && await ye(e, t, s, r);
|
|
1448
|
+
}
|
|
1449
|
+
async function ye(e, t, i, n) {
|
|
1450
|
+
const s = n.match(/\$wp_queries\s*=\s*"CREATE TABLE/);
|
|
1451
|
+
if (!s || s.index === void 0)
|
|
1452
|
+
return;
|
|
1453
|
+
const r = s.index, a = '";', o = n.indexOf(a, r);
|
|
1454
|
+
if (o === -1)
|
|
1455
|
+
return;
|
|
1456
|
+
const l = o + a.length, u = `function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
|
|
1457
|
+
global $wpdb, $wp_queries, $charset_collate;
|
|
1458
|
+
$charset_collate = '';
|
|
1459
|
+
if ( ! empty($wpdb->charset) )
|
|
1460
|
+
$charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
|
|
1461
|
+
if ( ! empty($wpdb->collate) )
|
|
1462
|
+
$charset_collate .= " COLLATE $wpdb->collate";
|
|
1463
|
+
${n.substring(r, l)}
|
|
1464
|
+
return $wp_queries;
|
|
1465
|
+
}`, d = n.substring(0, r) + u + n.substring(l);
|
|
1466
|
+
await e.writeFile(i, d);
|
|
1467
|
+
const f = _(
|
|
1468
|
+
t,
|
|
1469
|
+
"wp-admin/includes/upgrade.php"
|
|
1470
|
+
);
|
|
1471
|
+
if (e.fileExists(f)) {
|
|
1472
|
+
const p = e.readFileAsText(f), y = p.replace(
|
|
1473
|
+
/(\$alterations\s*=\s*dbDelta\(\s*\$wp_queries\s*\))/g,
|
|
1474
|
+
"if ( function_exists('wp_get_db_schema') ) { $wp_queries = wp_get_db_schema(); } $1"
|
|
1475
|
+
);
|
|
1476
|
+
y !== p && await e.writeFile(f, y);
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
function be() {
|
|
1480
|
+
return `<?php
|
|
1481
|
+
// @playground-managed — Playground-generated db.php.
|
|
1482
|
+
// WP < 3.0 loads only db.php and skips wp-db.php, so we pull
|
|
1483
|
+
// in the wpdb class definition explicitly.
|
|
1484
|
+
if (defined('ABSPATH') && defined('WPINC') && !class_exists('wpdb', false)) {
|
|
1485
|
+
require_once(ABSPATH . WPINC . '/wp-db.php');
|
|
1486
|
+
}
|
|
1487
|
+
// Old wpdb (WP < 3.0) has no db_connect() and calls mysql_connect()
|
|
1488
|
+
// inline, so the SQLite driver never gets a chance to attach. Load
|
|
1489
|
+
// the integration here and reinitialise to swap the dbh in place.
|
|
1490
|
+
if (
|
|
1491
|
+
class_exists('wpdb', false) &&
|
|
1492
|
+
isset($GLOBALS['wpdb']) &&
|
|
1493
|
+
!($GLOBALS['wpdb'] instanceof wpdb) &&
|
|
1494
|
+
!method_exists('wpdb', 'db_connect') &&
|
|
1495
|
+
file_exists('/internal/shared/mu-plugins/sqlite-database-integration.php')
|
|
1496
|
+
) {
|
|
1497
|
+
require_once '/internal/shared/mu-plugins/sqlite-database-integration.php';
|
|
1498
|
+
if (
|
|
1499
|
+
isset($GLOBALS['wpdb']) &&
|
|
1500
|
+
$GLOBALS['wpdb'] instanceof wpdb &&
|
|
1501
|
+
method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
|
|
1502
|
+
) {
|
|
1503
|
+
$GLOBALS['wpdb']->reinitialize_sqlite();
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
// Remaining mysqli_* stubs not covered by the 0-sqlite.php preload.
|
|
1507
|
+
// WP 4.x's extension_loaded('mysqli') check expects these to exist.
|
|
1508
|
+
if (!function_exists('mysqli_real_connect')) {
|
|
1509
|
+
function mysqli_real_connect() { return true; }
|
|
1510
|
+
}
|
|
1511
|
+
if (!function_exists('mysqli_error')) {
|
|
1512
|
+
function mysqli_error() { return ''; }
|
|
1513
|
+
}
|
|
1514
|
+
if (!function_exists('mysqli_errno')) {
|
|
1515
|
+
function mysqli_errno() { return 0; }
|
|
1516
|
+
}
|
|
1517
|
+
if (!function_exists('mysqli_query')) {
|
|
1518
|
+
function mysqli_query() { return false; }
|
|
1519
|
+
}
|
|
1520
|
+
if (!function_exists('mysqli_set_charset')) {
|
|
1521
|
+
function mysqli_set_charset() { return true; }
|
|
1522
|
+
}
|
|
1523
|
+
if (!function_exists('mysqli_select_db')) {
|
|
1524
|
+
function mysqli_select_db() { return true; }
|
|
1525
|
+
}
|
|
1526
|
+
if (!function_exists('mysqli_close')) {
|
|
1527
|
+
function mysqli_close() { return true; }
|
|
1528
|
+
}
|
|
1529
|
+
`;
|
|
1530
|
+
}
|
|
1531
|
+
async function Oe(e, t) {
|
|
1532
|
+
let i = null;
|
|
1533
|
+
const n = _(e.documentRoot, "wp-includes/version.php");
|
|
1534
|
+
if (e.fileExists(n)) {
|
|
1535
|
+
const r = e.readFileAsText(n).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
|
|
1536
|
+
r && (i = r[1]);
|
|
1537
|
+
}
|
|
1538
|
+
const s = i !== null && parseFloat(i) < 3.5;
|
|
1539
|
+
try {
|
|
1540
|
+
await e.run({
|
|
1541
|
+
code: `<?php
|
|
1542
|
+
// WP_INSTALLING bypasses WP 1.x's "not installed" die() in wp-settings.php.
|
|
1543
|
+
define('WP_INSTALLING', true);
|
|
1544
|
+
error_reporting(${L});
|
|
1545
|
+
ini_set('display_errors', '0');
|
|
1546
|
+
ob_start();
|
|
1547
|
+
$_pg_db_path = getenv('DOCUMENT_ROOT') . '/wp-content/database/.ht.sqlite';
|
|
1548
|
+
if (!file_exists($_pg_db_path)) { exit; }
|
|
1549
|
+
$_pg_pdo = new PDO('sqlite:' . $_pg_db_path);
|
|
1550
|
+
$_pg_check = $_pg_pdo->query("SELECT count(*) FROM sqlite_master WHERE type='table' AND name='wp_users'")->fetchColumn();
|
|
1551
|
+
$_pg_pdo = null;
|
|
1552
|
+
if (!$_pg_check) { exit; }
|
|
1553
|
+
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
1554
|
+
if (!file_exists($wp_load)) { exit; }
|
|
1555
|
+
require $wp_load;
|
|
1556
|
+
ob_clean();
|
|
1557
|
+
global $wpdb;
|
|
1558
|
+
if (!isset($wpdb) || !method_exists($wpdb, 'query')) { exit; }
|
|
1559
|
+
|
|
1560
|
+
// Persist the scoped siteurl/home to the DB so parse_request()
|
|
1561
|
+
// strips the scope prefix from REQUEST_URI. Filters alone
|
|
1562
|
+
// (env.php) aren't enough on WP < 2.2.
|
|
1563
|
+
$_pg_opts = !empty($wpdb->options) ? $wpdb->options : $GLOBALS['table_prefix'] . 'options';
|
|
1564
|
+
try {
|
|
1565
|
+
$_pg_url = getenv('PLAYGROUND_SITE_URL');
|
|
1566
|
+
if ($_pg_url) {
|
|
1567
|
+
$_pg_current = $wpdb->get_var("SELECT option_value FROM {$_pg_opts} WHERE option_name = 'siteurl'");
|
|
1568
|
+
if ($_pg_current !== $_pg_url) {
|
|
1569
|
+
$wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'siteurl'");
|
|
1570
|
+
$wpdb->query("UPDATE {$_pg_opts} SET option_value = '{$_pg_url}' WHERE option_name = 'home'");
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
} catch (Exception $e) {}
|
|
1574
|
+
|
|
1575
|
+
// $wpdb->users exists on WP 1.5+; older WP needs the prefix.
|
|
1576
|
+
$users_table = !empty($wpdb->users) ? $wpdb->users : $GLOBALS['table_prefix'] . 'users';
|
|
1577
|
+
|
|
1578
|
+
// WP 1.0/1.2 installers often leave the users table or admin row missing.
|
|
1579
|
+
$wpdb->query("CREATE TABLE IF NOT EXISTS {$users_table} (
|
|
1580
|
+
ID int(10) unsigned NOT NULL auto_increment,
|
|
1581
|
+
user_login varchar(20) NOT NULL default '',
|
|
1582
|
+
user_pass varchar(64) NOT NULL default '',
|
|
1583
|
+
user_firstname varchar(50) NOT NULL default '',
|
|
1584
|
+
user_lastname varchar(50) NOT NULL default '',
|
|
1585
|
+
user_nickname varchar(50) NOT NULL default '',
|
|
1586
|
+
user_icq int(10) unsigned NOT NULL default '0',
|
|
1587
|
+
user_email varchar(100) NOT NULL default '',
|
|
1588
|
+
user_url varchar(100) NOT NULL default '',
|
|
1589
|
+
user_ip varchar(15) NOT NULL default '',
|
|
1590
|
+
user_domain varchar(200) NOT NULL default '',
|
|
1591
|
+
user_browser varchar(200) NOT NULL default '',
|
|
1592
|
+
dateYMDhour datetime NOT NULL default '0000-00-00 00:00:00',
|
|
1593
|
+
user_level int(2) unsigned NOT NULL default '0',
|
|
1594
|
+
user_aim varchar(50) NOT NULL default '',
|
|
1595
|
+
user_msn varchar(100) NOT NULL default '',
|
|
1596
|
+
user_yim varchar(50) NOT NULL default '',
|
|
1597
|
+
user_idmode varchar(20) NOT NULL default '',
|
|
1598
|
+
PRIMARY KEY (ID),
|
|
1599
|
+
UNIQUE KEY user_login (user_login)
|
|
1600
|
+
)");
|
|
1601
|
+
if (!$wpdb->get_var("SELECT COUNT(*) FROM {$users_table}")) {
|
|
1602
|
+
$now = date('Y-m-d H:i:s');
|
|
1603
|
+
$wpdb->query(
|
|
1604
|
+
"INSERT INTO {$users_table} (ID, user_login, user_pass, user_email, user_level, dateYMDhour, user_nickname) " .
|
|
1605
|
+
"VALUES (1, 'admin', MD5('password'), 'admin@localhost.com', 10, '{$now}', 'admin')"
|
|
1606
|
+
);
|
|
1607
|
+
}
|
|
1608
|
+
$wpdb->query(
|
|
1609
|
+
"UPDATE {$users_table} SET user_pass = MD5('password') WHERE user_login = 'admin'"
|
|
1610
|
+
);
|
|
1611
|
+
|
|
1612
|
+
// populate_roles() can fail on SQLite; seed the admin role and caps directly.
|
|
1613
|
+
$p = $GLOBALS['table_prefix'];
|
|
1614
|
+
$roles_key = $p . 'user_roles';
|
|
1615
|
+
try {
|
|
1616
|
+
$has_roles = $wpdb->get_var(
|
|
1617
|
+
"SELECT COUNT(*) FROM {$p}options WHERE option_name = '{$roles_key}'"
|
|
1618
|
+
);
|
|
1619
|
+
} catch (Exception $e) {
|
|
1620
|
+
$has_roles = 0;
|
|
1621
|
+
}
|
|
1622
|
+
if (!$has_roles) {
|
|
1623
|
+
$roles = array('administrator' => array(
|
|
1624
|
+
'name' => 'Administrator',
|
|
1625
|
+
'capabilities' => array(
|
|
1626
|
+
'switch_themes'=>true, 'edit_themes'=>true,
|
|
1627
|
+
'activate_plugins'=>true, 'edit_plugins'=>true,
|
|
1628
|
+
'edit_users'=>true, 'edit_files'=>true,
|
|
1629
|
+
'manage_options'=>true, 'moderate_comments'=>true,
|
|
1630
|
+
'manage_categories'=>true, 'manage_links'=>true,
|
|
1631
|
+
'upload_files'=>true, 'import'=>true,
|
|
1632
|
+
'unfiltered_html'=>true, 'edit_posts'=>true,
|
|
1633
|
+
'edit_others_posts'=>true, 'edit_published_posts'=>true,
|
|
1634
|
+
'publish_posts'=>true, 'edit_pages'=>true,
|
|
1635
|
+
'read'=>true, 'level_10'=>true, 'level_9'=>true,
|
|
1636
|
+
'level_8'=>true, 'level_7'=>true, 'level_6'=>true,
|
|
1637
|
+
'level_5'=>true, 'level_4'=>true, 'level_3'=>true,
|
|
1638
|
+
'level_2'=>true, 'level_1'=>true, 'level_0'=>true,
|
|
1639
|
+
'edit_others_pages'=>true, 'edit_published_pages'=>true,
|
|
1640
|
+
'publish_pages'=>true, 'delete_pages'=>true,
|
|
1641
|
+
'delete_others_pages'=>true, 'delete_published_pages'=>true,
|
|
1642
|
+
'delete_posts'=>true, 'delete_others_posts'=>true,
|
|
1643
|
+
'delete_published_posts'=>true, 'delete_private_posts'=>true,
|
|
1644
|
+
'edit_private_posts'=>true, 'read_private_posts'=>true,
|
|
1645
|
+
'delete_private_pages'=>true, 'edit_private_pages'=>true,
|
|
1646
|
+
'read_private_pages'=>true,
|
|
1647
|
+
)
|
|
1648
|
+
));
|
|
1649
|
+
$wpdb->query("INSERT INTO {$p}options (option_name, option_value, autoload) VALUES ('{$roles_key}', '" . addslashes(serialize($roles)) . "', 'yes')");
|
|
1650
|
+
}
|
|
1651
|
+
$um = isset($wpdb->usermeta) ? $wpdb->usermeta : $p . 'usermeta';
|
|
1652
|
+
try {
|
|
1653
|
+
$has_cap = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}capabilities'");
|
|
1654
|
+
if (!$has_cap) {
|
|
1655
|
+
$cap_val = addslashes(serialize(array('administrator' => true)));
|
|
1656
|
+
$wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}capabilities', '{$cap_val}')");
|
|
1657
|
+
}
|
|
1658
|
+
$has_level = $wpdb->get_var("SELECT COUNT(*) FROM {$um} WHERE user_id=1 AND meta_key='{$p}user_level'");
|
|
1659
|
+
if (!$has_level) {
|
|
1660
|
+
$wpdb->query("INSERT INTO {$um} (user_id, meta_key, meta_value) VALUES (1, '{$p}user_level', '10')");
|
|
1661
|
+
}
|
|
1662
|
+
} catch (Exception $e) {}
|
|
1663
|
+
|
|
1664
|
+
// Seed default content when the install left the posts table empty.
|
|
1665
|
+
$posts_table = !empty($wpdb->posts) ? $wpdb->posts : $GLOBALS['table_prefix'] . 'posts';
|
|
1666
|
+
$has_posts = false;
|
|
1667
|
+
try { $has_posts = (bool)$wpdb->get_var("SELECT COUNT(*) FROM {$posts_table}"); } catch (Exception $e) {}
|
|
1668
|
+
if (!$has_posts) {
|
|
1669
|
+
$now = date('Y-m-d H:i:s');
|
|
1670
|
+
$now_gmt = gmdate('Y-m-d H:i:s');
|
|
1671
|
+
if (isset($wpdb->categories)) {
|
|
1672
|
+
$wpdb->query("INSERT INTO {$wpdb->categories} (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
|
|
1673
|
+
}
|
|
1674
|
+
// Columns common to WP 1.0+.
|
|
1675
|
+
$wpdb->query("INSERT INTO {$posts_table} (ID, post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping, pinged, post_modified, post_modified_gmt, post_content_filtered) VALUES (1, 1, '{$now}', '{$now_gmt}', 'Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!', 'Hello world!', '', 'publish', 'open', 'open', '', 'hello-world', '', '', '{$now}', '{$now_gmt}', '')");
|
|
1676
|
+
if (isset($wpdb->comments)) {
|
|
1677
|
+
$wpdb->query("INSERT INTO {$wpdb->comments} (comment_post_ID, comment_author, comment_author_email, comment_author_url, comment_author_IP, comment_date, comment_date_gmt, comment_content, comment_karma, comment_approved, comment_agent, comment_type, comment_parent, user_id) VALUES (1, 'Mr WordPress', '', 'http://wordpress.org', '127.0.0.1', '{$now}', '{$now_gmt}', 'Hi, this is a comment. To delete a comment, just log in and view the post comments. There you will have the option to edit or delete them.', 0, '1', '', '', 0, 0)");
|
|
1678
|
+
}
|
|
1679
|
+
if (isset($wpdb->post2cat)) {
|
|
1680
|
+
$wpdb->query("INSERT INTO {$wpdb->post2cat} (rel_id, post_id, category_id) VALUES (1, 1, 1)");
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
`,
|
|
1684
|
+
env: {
|
|
1685
|
+
DOCUMENT_ROOT: e.documentRoot,
|
|
1686
|
+
PLAYGROUND_SITE_URL: t || ""
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
} catch (r) {
|
|
1690
|
+
h.warn("Legacy WP post-install fixups failed (non-fatal):", r);
|
|
1691
|
+
}
|
|
1692
|
+
if (s)
|
|
1693
|
+
try {
|
|
1694
|
+
await e.run({
|
|
1695
|
+
code: `<?php
|
|
1696
|
+
$db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
|
|
1697
|
+
if (!is_dir($db_dir)) { @mkdir($db_dir, 0777, true); }
|
|
1698
|
+
$db_path = $db_dir . '.ht.sqlite';
|
|
1699
|
+
$pdo = new PDO('sqlite:' . $db_path);
|
|
1700
|
+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
1701
|
+
|
|
1702
|
+
$prefix = 'wp_';
|
|
1703
|
+
$table = $prefix . 'users';
|
|
1704
|
+
try {
|
|
1705
|
+
$count = $pdo->query("SELECT COUNT(*) FROM {$table}")->fetchColumn();
|
|
1706
|
+
} catch (Exception $e) {
|
|
1707
|
+
$pdo->exec("CREATE TABLE IF NOT EXISTS {$table} (
|
|
1708
|
+
ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1709
|
+
user_login TEXT NOT NULL DEFAULT '',
|
|
1710
|
+
user_pass TEXT NOT NULL DEFAULT '',
|
|
1711
|
+
user_nickname TEXT NOT NULL DEFAULT '',
|
|
1712
|
+
user_email TEXT NOT NULL DEFAULT '',
|
|
1713
|
+
user_url TEXT NOT NULL DEFAULT '',
|
|
1714
|
+
user_ip TEXT NOT NULL DEFAULT '',
|
|
1715
|
+
user_domain TEXT NOT NULL DEFAULT '',
|
|
1716
|
+
user_browser TEXT NOT NULL DEFAULT '',
|
|
1717
|
+
dateYMDhour TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1718
|
+
user_level INTEGER NOT NULL DEFAULT 0,
|
|
1719
|
+
user_idmode TEXT NOT NULL DEFAULT '',
|
|
1720
|
+
user_firstname TEXT NOT NULL DEFAULT '',
|
|
1721
|
+
user_lastname TEXT NOT NULL DEFAULT '',
|
|
1722
|
+
user_icq INTEGER NOT NULL DEFAULT 0,
|
|
1723
|
+
user_aim TEXT NOT NULL DEFAULT '',
|
|
1724
|
+
user_msn TEXT NOT NULL DEFAULT '',
|
|
1725
|
+
user_yim TEXT NOT NULL DEFAULT ''
|
|
1726
|
+
)");
|
|
1727
|
+
$count = 0;
|
|
1728
|
+
}
|
|
1729
|
+
if ($count == 0) {
|
|
1730
|
+
$now = date('Y-m-d H:i:s');
|
|
1731
|
+
// SECURITY: md5('password') matches WP 1.0-1.2's single-md5
|
|
1732
|
+
// scheme so auto-login works without a blueprint password.
|
|
1733
|
+
// Safe only inside the Playground WASM sandbox.
|
|
1734
|
+
$pass = md5('password');
|
|
1735
|
+
try {
|
|
1736
|
+
$col_info = $pdo->query("PRAGMA table_info({$table})")->fetchAll(PDO::FETCH_ASSOC);
|
|
1737
|
+
$known = array(
|
|
1738
|
+
'ID' => '1', 'user_login' => "'admin'",
|
|
1739
|
+
'user_pass' => "'{$pass}'", 'user_email' => "'admin@localhost.com'",
|
|
1740
|
+
'user_level' => '10', 'dateYMDhour' => "'{$now}'",
|
|
1741
|
+
'user_nickname' => "'admin'", 'user_nicename' => "'admin'",
|
|
1742
|
+
'user_registered' => "'{$now}'", 'user_status' => '0',
|
|
1743
|
+
);
|
|
1744
|
+
$ins_cols = array(); $ins_vals = array();
|
|
1745
|
+
foreach ($col_info as $ci) {
|
|
1746
|
+
$cn = $ci['name'];
|
|
1747
|
+
$ins_cols[] = $cn;
|
|
1748
|
+
if (isset($known[$cn])) {
|
|
1749
|
+
$ins_vals[] = $known[$cn];
|
|
1750
|
+
} elseif ($ci['dflt_value'] !== null) {
|
|
1751
|
+
$ins_vals[] = $ci['dflt_value'];
|
|
1752
|
+
} elseif (stripos($ci['type'], 'int') !== false) {
|
|
1753
|
+
$ins_vals[] = '0';
|
|
1754
|
+
} else {
|
|
1755
|
+
$ins_vals[] = "''";
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
$pdo->exec("INSERT INTO {$table} (" . implode(',', $ins_cols) . ") VALUES (" . implode(',', $ins_vals) . ")");
|
|
1759
|
+
} catch (Exception $e) {}
|
|
1760
|
+
} else {
|
|
1761
|
+
// See SECURITY note above.
|
|
1762
|
+
$pass = md5('password');
|
|
1763
|
+
try { $pdo->exec("UPDATE {$table} SET user_pass = '{$pass}' WHERE user_login = 'admin'"); } catch (Exception $e) {}
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
// WP 1.0-1.2 install often leaves these tables missing because
|
|
1767
|
+
// the SQLite driver can't translate the old-style CREATE TABLEs.
|
|
1768
|
+
$now = date('Y-m-d H:i:s');
|
|
1769
|
+
$now_gmt = gmdate('Y-m-d H:i:s');
|
|
1770
|
+
$tables_sql = array(
|
|
1771
|
+
'posts' => "CREATE TABLE IF NOT EXISTS {$prefix}posts (
|
|
1772
|
+
ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1773
|
+
post_author INTEGER NOT NULL DEFAULT 0,
|
|
1774
|
+
post_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1775
|
+
post_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1776
|
+
post_content TEXT NOT NULL DEFAULT '',
|
|
1777
|
+
post_title TEXT NOT NULL DEFAULT '',
|
|
1778
|
+
post_category INTEGER NOT NULL DEFAULT 0,
|
|
1779
|
+
post_excerpt TEXT NOT NULL DEFAULT '',
|
|
1780
|
+
post_status TEXT NOT NULL DEFAULT 'publish',
|
|
1781
|
+
comment_status TEXT NOT NULL DEFAULT 'open',
|
|
1782
|
+
ping_status TEXT NOT NULL DEFAULT 'open',
|
|
1783
|
+
post_password TEXT NOT NULL DEFAULT '',
|
|
1784
|
+
post_name TEXT NOT NULL DEFAULT '',
|
|
1785
|
+
to_ping TEXT NOT NULL DEFAULT '',
|
|
1786
|
+
pinged TEXT NOT NULL DEFAULT '',
|
|
1787
|
+
post_modified TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1788
|
+
post_modified_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1789
|
+
post_content_filtered TEXT NOT NULL DEFAULT '',
|
|
1790
|
+
post_parent INTEGER NOT NULL DEFAULT 0,
|
|
1791
|
+
menu_order INTEGER NOT NULL DEFAULT 0,
|
|
1792
|
+
post_mime_type TEXT NOT NULL DEFAULT ''
|
|
1793
|
+
)",
|
|
1794
|
+
'categories' => "CREATE TABLE IF NOT EXISTS {$prefix}categories (
|
|
1795
|
+
cat_ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1796
|
+
cat_name TEXT NOT NULL DEFAULT '',
|
|
1797
|
+
category_nicename TEXT NOT NULL DEFAULT '',
|
|
1798
|
+
category_description TEXT NOT NULL DEFAULT '',
|
|
1799
|
+
category_parent INTEGER NOT NULL DEFAULT 0
|
|
1800
|
+
)",
|
|
1801
|
+
'post2cat' => "CREATE TABLE IF NOT EXISTS {$prefix}post2cat (
|
|
1802
|
+
rel_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1803
|
+
post_id INTEGER NOT NULL DEFAULT 0,
|
|
1804
|
+
category_id INTEGER NOT NULL DEFAULT 0
|
|
1805
|
+
)",
|
|
1806
|
+
'comments' => "CREATE TABLE IF NOT EXISTS {$prefix}comments (
|
|
1807
|
+
comment_ID INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1808
|
+
comment_post_ID INTEGER NOT NULL DEFAULT 0,
|
|
1809
|
+
comment_author TEXT NOT NULL DEFAULT '',
|
|
1810
|
+
comment_author_email TEXT NOT NULL DEFAULT '',
|
|
1811
|
+
comment_author_url TEXT NOT NULL DEFAULT '',
|
|
1812
|
+
comment_author_IP TEXT NOT NULL DEFAULT '',
|
|
1813
|
+
comment_date TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1814
|
+
comment_date_gmt TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1815
|
+
comment_content TEXT NOT NULL DEFAULT '',
|
|
1816
|
+
comment_karma INTEGER NOT NULL DEFAULT 0,
|
|
1817
|
+
comment_approved TEXT NOT NULL DEFAULT '1',
|
|
1818
|
+
comment_agent TEXT NOT NULL DEFAULT '',
|
|
1819
|
+
comment_type TEXT NOT NULL DEFAULT '',
|
|
1820
|
+
comment_parent INTEGER NOT NULL DEFAULT 0,
|
|
1821
|
+
user_id INTEGER NOT NULL DEFAULT 0
|
|
1822
|
+
)",
|
|
1823
|
+
'options' => "CREATE TABLE IF NOT EXISTS {$prefix}options (
|
|
1824
|
+
option_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1825
|
+
blog_id INTEGER NOT NULL DEFAULT 0,
|
|
1826
|
+
option_name TEXT NOT NULL DEFAULT '',
|
|
1827
|
+
option_can_override TEXT NOT NULL DEFAULT 'Y',
|
|
1828
|
+
option_type INTEGER NOT NULL DEFAULT 1,
|
|
1829
|
+
option_value TEXT NOT NULL DEFAULT '',
|
|
1830
|
+
option_width INTEGER NOT NULL DEFAULT 20,
|
|
1831
|
+
option_height INTEGER NOT NULL DEFAULT 8,
|
|
1832
|
+
option_description TEXT NOT NULL DEFAULT '',
|
|
1833
|
+
option_admin_level INTEGER NOT NULL DEFAULT 1,
|
|
1834
|
+
autoload TEXT NOT NULL DEFAULT 'yes'
|
|
1835
|
+
)",
|
|
1836
|
+
'postmeta' => "CREATE TABLE IF NOT EXISTS {$prefix}postmeta (
|
|
1837
|
+
meta_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1838
|
+
post_id INTEGER NOT NULL DEFAULT 0,
|
|
1839
|
+
meta_key TEXT NOT NULL DEFAULT '',
|
|
1840
|
+
meta_value TEXT NOT NULL DEFAULT ''
|
|
1841
|
+
)",
|
|
1842
|
+
'links' => "CREATE TABLE IF NOT EXISTS {$prefix}links (
|
|
1843
|
+
link_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1844
|
+
link_url TEXT NOT NULL DEFAULT '',
|
|
1845
|
+
link_name TEXT NOT NULL DEFAULT '',
|
|
1846
|
+
link_image TEXT NOT NULL DEFAULT '',
|
|
1847
|
+
link_target TEXT NOT NULL DEFAULT '',
|
|
1848
|
+
link_category INTEGER NOT NULL DEFAULT 0,
|
|
1849
|
+
link_description TEXT NOT NULL DEFAULT '',
|
|
1850
|
+
link_visible TEXT NOT NULL DEFAULT 'Y',
|
|
1851
|
+
link_owner INTEGER NOT NULL DEFAULT 1,
|
|
1852
|
+
link_rating INTEGER NOT NULL DEFAULT 0,
|
|
1853
|
+
link_updated TEXT NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
1854
|
+
link_rel TEXT NOT NULL DEFAULT '',
|
|
1855
|
+
link_notes TEXT NOT NULL DEFAULT '',
|
|
1856
|
+
link_rss TEXT NOT NULL DEFAULT ''
|
|
1857
|
+
)",
|
|
1858
|
+
'linkcategories' => "CREATE TABLE IF NOT EXISTS {$prefix}linkcategories (
|
|
1859
|
+
cat_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1860
|
+
cat_name TEXT NOT NULL DEFAULT '',
|
|
1861
|
+
auto_toggle TEXT NOT NULL DEFAULT 'N',
|
|
1862
|
+
show_images TEXT NOT NULL DEFAULT 'Y',
|
|
1863
|
+
show_description TEXT NOT NULL DEFAULT 'N',
|
|
1864
|
+
show_rating TEXT NOT NULL DEFAULT 'Y',
|
|
1865
|
+
show_updated TEXT NOT NULL DEFAULT 'Y',
|
|
1866
|
+
sort_order TEXT NOT NULL DEFAULT 'name',
|
|
1867
|
+
sort_desc TEXT NOT NULL DEFAULT 'ASC',
|
|
1868
|
+
text_before_link TEXT NOT NULL DEFAULT '<li>',
|
|
1869
|
+
text_after_link TEXT NOT NULL DEFAULT '<br />',
|
|
1870
|
+
text_after_all TEXT NOT NULL DEFAULT '</li>',
|
|
1871
|
+
list_limit INTEGER NOT NULL DEFAULT -1
|
|
1872
|
+
)",
|
|
1873
|
+
'optiongroups' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroups (
|
|
1874
|
+
group_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1875
|
+
group_name TEXT NOT NULL DEFAULT '',
|
|
1876
|
+
group_desc TEXT DEFAULT '',
|
|
1877
|
+
group_longdesc TEXT DEFAULT ''
|
|
1878
|
+
)",
|
|
1879
|
+
'optiongroup_options' => "CREATE TABLE IF NOT EXISTS {$prefix}optiongroup_options (
|
|
1880
|
+
group_id INTEGER NOT NULL DEFAULT 0,
|
|
1881
|
+
option_id INTEGER NOT NULL DEFAULT 0,
|
|
1882
|
+
seq INTEGER NOT NULL DEFAULT 0,
|
|
1883
|
+
PRIMARY KEY (group_id, option_id)
|
|
1884
|
+
)"
|
|
1885
|
+
);
|
|
1886
|
+
foreach ($tables_sql as $t => $sql) {
|
|
1887
|
+
try { $pdo->exec($sql); } catch (Exception $e) {}
|
|
1888
|
+
}
|
|
1889
|
+
// Backfill columns that WP 1.0-1.2 installs leave off but later code paths read.
|
|
1890
|
+
$alter_cols = array(
|
|
1891
|
+
'categories' => array(
|
|
1892
|
+
'category_nicename' => "TEXT NOT NULL DEFAULT ''",
|
|
1893
|
+
'category_description' => "TEXT NOT NULL DEFAULT ''",
|
|
1894
|
+
'category_parent' => "INTEGER NOT NULL DEFAULT 0",
|
|
1895
|
+
'category_count' => "INTEGER NOT NULL DEFAULT 0",
|
|
1896
|
+
),
|
|
1897
|
+
// WP 1.5+ get_comments_number() reads comment_count off wp_posts.
|
|
1898
|
+
'posts' => array(
|
|
1899
|
+
'comment_count' => "INTEGER NOT NULL DEFAULT 0",
|
|
1900
|
+
),
|
|
1901
|
+
);
|
|
1902
|
+
foreach ($alter_cols as $t => $cols_to_add) {
|
|
1903
|
+
try {
|
|
1904
|
+
$existing = $pdo->query("PRAGMA table_info({$prefix}{$t})")->fetchAll(PDO::FETCH_COLUMN, 1);
|
|
1905
|
+
foreach ($cols_to_add as $col => $type) {
|
|
1906
|
+
if (!in_array($col, $existing)) {
|
|
1907
|
+
$pdo->exec("ALTER TABLE {$prefix}{$t} ADD COLUMN {$col} {$type}");
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
} catch (Exception $e) {}
|
|
1911
|
+
}
|
|
1912
|
+
// Dynamic column detection because the schema differs across WP 1.x.
|
|
1913
|
+
try {
|
|
1914
|
+
if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}posts")->fetchColumn()) {
|
|
1915
|
+
$post_cols = $pdo->query("PRAGMA table_info({$prefix}posts)")->fetchAll(PDO::FETCH_COLUMN, 1);
|
|
1916
|
+
$post_vals = array(
|
|
1917
|
+
'ID' => '1', 'post_author' => '1',
|
|
1918
|
+
'post_date' => "'{$now}'", 'post_date_gmt' => "'{$now_gmt}'",
|
|
1919
|
+
'post_content' => "'Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!'",
|
|
1920
|
+
'post_title' => "'Hello world!'", 'post_excerpt' => "''",
|
|
1921
|
+
'post_status' => "'publish'", 'comment_status' => "'open'",
|
|
1922
|
+
'ping_status' => "'open'", 'post_password' => "''",
|
|
1923
|
+
'post_name' => "'hello-world'", 'to_ping' => "''", 'pinged' => "''",
|
|
1924
|
+
'post_modified' => "'{$now}'", 'post_modified_gmt' => "'{$now_gmt}'",
|
|
1925
|
+
'post_content_filtered' => "''",
|
|
1926
|
+
);
|
|
1927
|
+
$ins_c = array(); $ins_v = array();
|
|
1928
|
+
foreach ($post_vals as $c => $v) {
|
|
1929
|
+
if (in_array($c, $post_cols)) { $ins_c[] = $c; $ins_v[] = $v; }
|
|
1930
|
+
}
|
|
1931
|
+
if ($ins_c) $pdo->exec("INSERT INTO {$prefix}posts (" . implode(',', $ins_c) . ") VALUES (" . implode(',', $ins_v) . ")");
|
|
1932
|
+
}
|
|
1933
|
+
} catch (Exception $e) {}
|
|
1934
|
+
try {
|
|
1935
|
+
if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}categories")->fetchColumn()) {
|
|
1936
|
+
$pdo->exec("INSERT INTO {$prefix}categories (cat_ID, cat_name, category_nicename, category_description, category_parent) VALUES (1, 'Uncategorized', 'uncategorized', '', 0)");
|
|
1937
|
+
}
|
|
1938
|
+
} catch (Exception $e) {}
|
|
1939
|
+
try {
|
|
1940
|
+
$env_site = getenv('PLAYGROUND_SITE_URL');
|
|
1941
|
+
$site = $env_site ? $env_site : 'http://localhost';
|
|
1942
|
+
if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='siteurl'")->fetchColumn()) {
|
|
1943
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('siteurl', '{$site}')");
|
|
1944
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogname', 'My WordPress Website')");
|
|
1945
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('blogdescription', 'Just another WordPress weblog')");
|
|
1946
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value) VALUES ('home', '{$site}')");
|
|
1947
|
+
}
|
|
1948
|
+
// Overwrite the placeholder 'http://localhost' with the scoped URL.
|
|
1949
|
+
if ($env_site) {
|
|
1950
|
+
$pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'siteurl'");
|
|
1951
|
+
$pdo->exec("UPDATE {$prefix}options SET option_value = '{$env_site}' WHERE option_name = 'home'");
|
|
1952
|
+
}
|
|
1953
|
+
// populate_options() sets template/stylesheet; backfill if it crashed.
|
|
1954
|
+
if (!$pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='template'")->fetchColumn()) {
|
|
1955
|
+
$themes_dir = getenv('DOCUMENT_ROOT') . '/wp-content/themes/';
|
|
1956
|
+
$tpl = 'default';
|
|
1957
|
+
if (is_dir($themes_dir)) {
|
|
1958
|
+
$entries = glob($themes_dir . '*', GLOB_ONLYDIR);
|
|
1959
|
+
if ($entries) {
|
|
1960
|
+
foreach ($entries as $e) {
|
|
1961
|
+
$name = basename($e);
|
|
1962
|
+
if ($name === '.' || $name === '..') continue;
|
|
1963
|
+
if (file_exists($e . '/style.css')) {
|
|
1964
|
+
$tpl = $name;
|
|
1965
|
+
break;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('template', '{$tpl}', 'yes')");
|
|
1971
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('stylesheet', '{$tpl}', 'yes')");
|
|
1972
|
+
}
|
|
1973
|
+
// Without a correct db_version, WP 2.0-2.5 admin redirects to upgrade.php.
|
|
1974
|
+
$version_path = getenv('DOCUMENT_ROOT') . '/wp-includes/version.php';
|
|
1975
|
+
if (file_exists($version_path)) {
|
|
1976
|
+
$wp_db_version = 0;
|
|
1977
|
+
include $version_path;
|
|
1978
|
+
if ($wp_db_version > 0) {
|
|
1979
|
+
$has_dbv = $pdo->query("SELECT COUNT(*) FROM {$prefix}options WHERE option_name='db_version'")->fetchColumn();
|
|
1980
|
+
if (!$has_dbv) {
|
|
1981
|
+
$pdo->exec("INSERT INTO {$prefix}options (option_name, option_value, autoload) VALUES ('db_version', '{$wp_db_version}', 'yes')");
|
|
1982
|
+
} else {
|
|
1983
|
+
$pdo->exec("UPDATE {$prefix}options SET option_value = '{$wp_db_version}' WHERE option_name = 'db_version'");
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
}
|
|
1987
|
+
} catch (Exception $e) {}
|
|
1988
|
+
`,
|
|
1989
|
+
env: {
|
|
1990
|
+
DOCUMENT_ROOT: e.documentRoot,
|
|
1991
|
+
PLAYGROUND_SITE_URL: t || ""
|
|
1992
|
+
}
|
|
1993
|
+
});
|
|
1994
|
+
} catch (r) {
|
|
1995
|
+
h.warn("Legacy WP PDO fallback failed (non-fatal):", r);
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
const Pe = `
|
|
1999
|
+
// Connection stubs — wpdb::__construct bails on a falsy return.
|
|
2000
|
+
if (!function_exists('mysqli_connect')) {
|
|
2001
|
+
function mysqli_connect() { return true; }
|
|
2002
|
+
}
|
|
2003
|
+
if (!function_exists('mysqli_init')) {
|
|
2004
|
+
function mysqli_init() { return true; }
|
|
2005
|
+
}
|
|
2006
|
+
if (!function_exists('mysql_connect')) {
|
|
2007
|
+
function mysql_connect() { return true; }
|
|
2008
|
+
}
|
|
2009
|
+
if (!function_exists('mysql_select_db')) {
|
|
2010
|
+
function mysql_select_db() { return true; }
|
|
2011
|
+
}
|
|
2012
|
+
// WordPress < 3.0 wpdb::__construct calls mysql_set_charset directly.
|
|
2013
|
+
if (!function_exists('mysql_set_charset')) {
|
|
2014
|
+
function mysql_set_charset() { return true; }
|
|
2015
|
+
}
|
|
2016
|
+
// Functional mysql_* stubs that delegate to $wpdb (SQLite driver).
|
|
2017
|
+
$GLOBALS['_mysql_results'] = array();
|
|
2018
|
+
$GLOBALS['_mysql_result_id'] = 0;
|
|
2019
|
+
if (!function_exists('mysql_query')) {
|
|
2020
|
+
function mysql_query($query, $link = null) {
|
|
2021
|
+
global $wpdb;
|
|
2022
|
+
if (isset($wpdb) && method_exists($wpdb, 'query')) {
|
|
2023
|
+
$wpdb->query($query);
|
|
2024
|
+
if (preg_match('/^\\s*(SELECT|SHOW|DESCRIBE|EXPLAIN)/i', $query)) {
|
|
2025
|
+
$rows = isset($wpdb->last_result) ? $wpdb->last_result : array();
|
|
2026
|
+
$id = ++$GLOBALS['_mysql_result_id'];
|
|
2027
|
+
$GLOBALS['_mysql_results'][$id] = array(
|
|
2028
|
+
'rows' => $rows,
|
|
2029
|
+
'index' => 0,
|
|
2030
|
+
);
|
|
2031
|
+
return $id;
|
|
2032
|
+
}
|
|
2033
|
+
return true;
|
|
2034
|
+
}
|
|
2035
|
+
return false;
|
|
2036
|
+
}
|
|
2037
|
+
}
|
|
2038
|
+
if (!function_exists('mysql_error')) {
|
|
2039
|
+
function mysql_error($link = null) {
|
|
2040
|
+
global $wpdb;
|
|
2041
|
+
if (isset($wpdb) && isset($wpdb->last_error)) {
|
|
2042
|
+
return $wpdb->last_error;
|
|
2043
|
+
}
|
|
2044
|
+
return '';
|
|
2045
|
+
}
|
|
2046
|
+
}
|
|
2047
|
+
if (!function_exists('mysql_list_tables')) {
|
|
2048
|
+
function mysql_list_tables($db = '', $link = null) {
|
|
2049
|
+
global $wpdb;
|
|
2050
|
+
if (isset($wpdb) && method_exists($wpdb, 'get_results')) {
|
|
2051
|
+
$tables = $wpdb->get_results(
|
|
2052
|
+
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
2053
|
+
);
|
|
2054
|
+
$rows = array();
|
|
2055
|
+
if ($tables) {
|
|
2056
|
+
foreach ($tables as $t) {
|
|
2057
|
+
$obj = new stdClass();
|
|
2058
|
+
$obj->name = is_object($t) ? $t->name : $t['name'];
|
|
2059
|
+
$rows[] = $obj;
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
$id = ++$GLOBALS['_mysql_result_id'];
|
|
2063
|
+
$GLOBALS['_mysql_results'][$id] = array(
|
|
2064
|
+
'rows' => $rows,
|
|
2065
|
+
'index' => 0,
|
|
2066
|
+
);
|
|
2067
|
+
return $id;
|
|
2068
|
+
}
|
|
2069
|
+
return false;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
if (!function_exists('mysql_fetch_row')) {
|
|
2073
|
+
function mysql_fetch_row($result) {
|
|
2074
|
+
if (!isset($GLOBALS['_mysql_results'][$result])) return null;
|
|
2075
|
+
$r = &$GLOBALS['_mysql_results'][$result];
|
|
2076
|
+
if ($r['index'] >= count($r['rows'])) return null;
|
|
2077
|
+
$row = $r['rows'][$r['index']++];
|
|
2078
|
+
return array_values((array)$row);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
if (!function_exists('mysql_fetch_object')) {
|
|
2082
|
+
function mysql_fetch_object($result) {
|
|
2083
|
+
if (!isset($GLOBALS['_mysql_results'][$result])) return null;
|
|
2084
|
+
$r = &$GLOBALS['_mysql_results'][$result];
|
|
2085
|
+
if ($r['index'] >= count($r['rows'])) return null;
|
|
2086
|
+
return (object)(array)$r['rows'][$r['index']++];
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
if (!function_exists('mysql_num_rows')) {
|
|
2090
|
+
function mysql_num_rows($result) {
|
|
2091
|
+
if (isset($GLOBALS['_mysql_results'][$result])) {
|
|
2092
|
+
return count($GLOBALS['_mysql_results'][$result]['rows']);
|
|
2093
|
+
}
|
|
2094
|
+
return 0;
|
|
2095
|
+
}
|
|
2096
|
+
}
|
|
2097
|
+
if (!function_exists('mysql_get_server_info')) {
|
|
2098
|
+
function mysql_get_server_info() { return '8.0.0'; }
|
|
2099
|
+
}
|
|
2100
|
+
if (!function_exists('mysql_affected_rows')) {
|
|
2101
|
+
function mysql_affected_rows() {
|
|
2102
|
+
global $wpdb;
|
|
2103
|
+
if (isset($wpdb) && isset($wpdb->rows_affected)) {
|
|
2104
|
+
return $wpdb->rows_affected;
|
|
2105
|
+
}
|
|
2106
|
+
return 0;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
if (!function_exists('mysql_insert_id')) {
|
|
2110
|
+
function mysql_insert_id() {
|
|
2111
|
+
global $wpdb;
|
|
2112
|
+
if (isset($wpdb) && isset($wpdb->insert_id)) {
|
|
2113
|
+
return $wpdb->insert_id;
|
|
2114
|
+
}
|
|
2115
|
+
return 0;
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
if (!function_exists('mysql_free_result')) {
|
|
2119
|
+
function mysql_free_result($result) {
|
|
2120
|
+
unset($GLOBALS['_mysql_results'][$result]);
|
|
2121
|
+
return true;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
if (!function_exists('mysql_num_fields')) {
|
|
2125
|
+
function mysql_num_fields($result) {
|
|
2126
|
+
if (isset($GLOBALS['_mysql_results'][$result])
|
|
2127
|
+
&& !empty($GLOBALS['_mysql_results'][$result]['rows'])) {
|
|
2128
|
+
return count((array)$GLOBALS['_mysql_results'][$result]['rows'][0]);
|
|
2129
|
+
}
|
|
2130
|
+
return 0;
|
|
2131
|
+
}
|
|
2132
|
+
}
|
|
2133
|
+
if (!function_exists('mysql_real_escape_string')) {
|
|
2134
|
+
function mysql_real_escape_string($s) { return addslashes($s); }
|
|
2135
|
+
}
|
|
2136
|
+
if (!function_exists('mysql_escape_string')) {
|
|
2137
|
+
function mysql_escape_string($s) { return addslashes($s); }
|
|
2138
|
+
}`;
|
|
2139
|
+
async function Ne(e, t, i = {}) {
|
|
2140
|
+
await e.isDir("/tmp/sqlite-database-integration") && await e.rmdir("/tmp/sqlite-database-integration", {
|
|
2141
|
+
recursive: !0
|
|
2142
|
+
}), await e.mkdir("/tmp/sqlite-database-integration"), await m(e, t, "/tmp/sqlite-database-integration");
|
|
2143
|
+
const n = "/internal/shared/sqlite-database-integration", s = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
|
|
2144
|
+
await e.mv(s, n), await Ae(e, n), await e.defineConstant("SQLITE_MAIN_FILE", "1");
|
|
2145
|
+
let a = (await e.readFileAsText(
|
|
2146
|
+
_(n, "db.copy")
|
|
2147
|
+
)).replace(
|
|
2148
|
+
"'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
|
|
2149
|
+
$(n)
|
|
2150
|
+
).replace(
|
|
2151
|
+
"'{SQLITE_PLUGIN}'",
|
|
2152
|
+
$(_(n, "load.php"))
|
|
2153
|
+
);
|
|
2154
|
+
a = a.replace(
|
|
2155
|
+
/^add_action\(/gm,
|
|
2156
|
+
'function_exists("add_action") && add_action('
|
|
2157
|
+
);
|
|
2158
|
+
const o = _(await e.documentRoot, "wp-content/db.php"), l = "/internal/shared/mu-plugins/sqlite-database-integration.php", c = `
|
|
2159
|
+
if(file_exists(${$(o)})) {
|
|
2160
|
+
$_pg_db_php = @file_get_contents(${$(o)});
|
|
2161
|
+
if (strpos($_pg_db_php, '@playground-managed') === false) {
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
unset($_pg_db_php);
|
|
2165
|
+
}
|
|
2166
|
+
`;
|
|
2167
|
+
await e.writeFile(l, `<?php
|
|
2168
|
+
${c}?>` + a), await e.writeFile(
|
|
2169
|
+
"/internal/shared/preload/0-sqlite.php",
|
|
2170
|
+
Se(c, l)
|
|
2171
|
+
), await e.writeFile(
|
|
2172
|
+
"/internal/shared/mu-plugins/sqlite-test.php",
|
|
2173
|
+
`<?php
|
|
2174
|
+
global $wpdb;
|
|
2175
|
+
if(!($wpdb instanceof WP_SQLite_DB)) {
|
|
2176
|
+
var_dump(isset($wpdb));
|
|
2177
|
+
die("SQLite integration not loaded " . get_class($wpdb));
|
|
2178
|
+
}
|
|
2179
|
+
`
|
|
2180
|
+
);
|
|
2181
|
+
}
|
|
2182
|
+
async function Ae(e, t) {
|
|
2183
|
+
const i = _(
|
|
2184
|
+
t,
|
|
2185
|
+
"wp-includes/database/sqlite/class-wp-pdo-mysql-on-sqlite.php"
|
|
2186
|
+
);
|
|
2187
|
+
if (!await e.fileExists(i)) return;
|
|
2188
|
+
const n = await e.readFileAsText(i), s = n.replace(
|
|
2189
|
+
/\$active_sql_modes\s*=\s*array\s*\([^)]*\)\s*;/,
|
|
2190
|
+
"$active_sql_modes = array();"
|
|
2191
|
+
);
|
|
2192
|
+
s !== n && await e.writeFile(i, s);
|
|
2193
|
+
}
|
|
2194
|
+
function Se(e, t) {
|
|
2195
|
+
return `<?php
|
|
2196
|
+
${e}?>
|
|
2197
|
+
<?php
|
|
2198
|
+
// Shim __() etc. only for WP < 1.2 (no l10n layer; the SQLite
|
|
2199
|
+
// plugin calls __() from print_error()). WP 1.2–1.4 ship
|
|
2200
|
+
// wp-l10n.php and WP 1.5+ ships l10n.php — defining the shims
|
|
2201
|
+
// then would fatal on redeclare.
|
|
2202
|
+
$_pg_doc_root = isset($_SERVER['DOCUMENT_ROOT'])
|
|
2203
|
+
? $_SERVER['DOCUMENT_ROOT'] : '/wordpress';
|
|
2204
|
+
if (
|
|
2205
|
+
!file_exists($_pg_doc_root . '/wp-includes/l10n.php')
|
|
2206
|
+
&& !file_exists($_pg_doc_root . '/wp-includes/wp-l10n.php')
|
|
2207
|
+
) {
|
|
2208
|
+
if (!function_exists('__')) {
|
|
2209
|
+
function __($text, $domain = null) { return $text; }
|
|
2210
|
+
}
|
|
2211
|
+
if (!function_exists('_e')) {
|
|
2212
|
+
function _e($text, $domain = null) { echo $text; }
|
|
2213
|
+
}
|
|
2214
|
+
if (!function_exists('esc_html__')) {
|
|
2215
|
+
function esc_html__($text, $domain = null) {
|
|
2216
|
+
return htmlspecialchars($text, ENT_QUOTES);
|
|
2217
|
+
}
|
|
2218
|
+
}
|
|
2219
|
+
if (!function_exists('esc_html_e')) {
|
|
2220
|
+
function esc_html_e($text, $domain = null) {
|
|
2221
|
+
echo htmlspecialchars($text, ENT_QUOTES);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
?>
|
|
2226
|
+
<?php
|
|
2227
|
+
${v(
|
|
2228
|
+
// WP < 3.0's wpdb does mysql_connect() inline so the SQLite
|
|
2229
|
+
// plugin's db_connect() never runs; reinitialize_sqlite()
|
|
2230
|
+
// swaps the dbh in place after the integration is loaded.
|
|
2231
|
+
`require_once ${$(t)};
|
|
2232
|
+
if (
|
|
2233
|
+
isset($GLOBALS['wpdb']) &&
|
|
2234
|
+
method_exists($GLOBALS['wpdb'], 'reinitialize_sqlite')
|
|
2235
|
+
) {
|
|
2236
|
+
$GLOBALS['wpdb']->reinitialize_sqlite();
|
|
2237
|
+
}`
|
|
2238
|
+
)}
|
|
2239
|
+
${Pe}
|
|
2240
|
+
if (PHP_MAJOR_VERSION < 7) {
|
|
2241
|
+
// E_DEPRECATED (8192) / E_STRICT (2048) are PHP 5.3+ symbols;
|
|
2242
|
+
// LEGACY_WP_ERROR_REPORTING_PHP_EXPR uses numeric literals.
|
|
2243
|
+
$level = ${L};
|
|
2244
|
+
error_reporting($level);
|
|
2245
|
+
ini_set('error_reporting', $level);
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
`;
|
|
2249
|
+
}
|
|
2250
|
+
const U = `<?php
|
|
6
2251
|
|
|
7
2252
|
/**
|
|
8
2253
|
* Transforms the "wp-config.php" file.
|
|
@@ -474,133 +2719,327 @@ class WP_Config_Transformer {
|
|
|
474
2719
|
}
|
|
475
2720
|
}
|
|
476
2721
|
`;
|
|
477
|
-
async function
|
|
478
|
-
const
|
|
479
|
-
!
|
|
480
|
-
|
|
481
|
-
await
|
|
482
|
-
|
|
2722
|
+
async function ve(e, t) {
|
|
2723
|
+
const i = _(t, "wp-config.php");
|
|
2724
|
+
!e.fileExists(i) && e.fileExists(_(t, "wp-config-sample.php")) && await e.writeFile(
|
|
2725
|
+
i,
|
|
2726
|
+
await e.readFileAsBuffer(
|
|
2727
|
+
_(t, "wp-config-sample.php")
|
|
483
2728
|
)
|
|
484
|
-
),
|
|
2729
|
+
), e.fileExists(i) && await xe(e, i, {
|
|
485
2730
|
DB_NAME: "wordpress"
|
|
486
2731
|
});
|
|
487
2732
|
}
|
|
488
|
-
async function
|
|
489
|
-
const
|
|
490
|
-
if ((await
|
|
491
|
-
code: `${
|
|
492
|
-
$wp_config_path = ${
|
|
493
|
-
$transformer = WP_Config_Transformer::from_file($wp_config_path);
|
|
494
|
-
$transformer->define_constants(${
|
|
495
|
-
$transformer->to_file($wp_config_path);
|
|
496
|
-
`
|
|
497
|
-
})).errors.length > 0)
|
|
498
|
-
throw new Error("Failed to rewrite constants in wp-config.php.");
|
|
2733
|
+
async function st(e, t, i) {
|
|
2734
|
+
const n = A({ wpConfigPath: t, constants: i });
|
|
2735
|
+
if ((await e.run({
|
|
2736
|
+
code: `${U}
|
|
2737
|
+
$wp_config_path = ${n.wpConfigPath};
|
|
2738
|
+
$transformer = WP_Config_Transformer::from_file($wp_config_path);
|
|
2739
|
+
$transformer->define_constants(${n.constants});
|
|
2740
|
+
$transformer->to_file($wp_config_path);
|
|
2741
|
+
`
|
|
2742
|
+
})).errors.length > 0)
|
|
2743
|
+
throw new Error("Failed to rewrite constants in wp-config.php.");
|
|
2744
|
+
}
|
|
2745
|
+
async function xe(e, t, i) {
|
|
2746
|
+
const n = Object.keys(i), s = A({ wpConfigPath: t, constantNames: n }), r = await e.run({
|
|
2747
|
+
code: `${U}
|
|
2748
|
+
$transformer = WP_Config_Transformer::from_file(${s.wpConfigPath});
|
|
2749
|
+
$missing = [];
|
|
2750
|
+
foreach (${s.constantNames} as $name) {
|
|
2751
|
+
if (!$transformer->constant_exists($name)) {
|
|
2752
|
+
$missing[] = $name;
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
echo json_encode($missing);
|
|
2756
|
+
`
|
|
2757
|
+
});
|
|
2758
|
+
if (r.errors.length > 0)
|
|
2759
|
+
throw new Error("Failed to check wp-config.php for constants.");
|
|
2760
|
+
let a;
|
|
2761
|
+
try {
|
|
2762
|
+
a = JSON.parse(r.text);
|
|
2763
|
+
} catch {
|
|
2764
|
+
throw new Error(
|
|
2765
|
+
`Failed to parse wp-config.php constant check output: ${r.text}`
|
|
2766
|
+
);
|
|
2767
|
+
}
|
|
2768
|
+
for (const o of a)
|
|
2769
|
+
await e.defineConstant(o, i[o]);
|
|
2770
|
+
}
|
|
2771
|
+
async function E(e, {
|
|
2772
|
+
usesSqlite: t,
|
|
2773
|
+
hasCustomDatabasePath: i
|
|
2774
|
+
}) {
|
|
2775
|
+
const n = await e.getPrimaryPhp();
|
|
2776
|
+
if (n.isFile("/internal/shared/preload/0-sqlite.php"))
|
|
2777
|
+
return;
|
|
2778
|
+
const s = _(
|
|
2779
|
+
e.documentRoot,
|
|
2780
|
+
"wp-content/mu-plugins/sqlite-database-integration"
|
|
2781
|
+
);
|
|
2782
|
+
if (!n.isDir(s) && !t && !i && !Ue(n))
|
|
2783
|
+
throw new Error("Error connecting to the MySQL database.");
|
|
2784
|
+
}
|
|
2785
|
+
function Ue(e) {
|
|
2786
|
+
const t = _(e.documentRoot, "wp-config.php");
|
|
2787
|
+
if (!e.isFile(t)) return !1;
|
|
2788
|
+
const i = e.readFileAsText(t), n = i.match(
|
|
2789
|
+
/define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/
|
|
2790
|
+
), s = i.match(
|
|
2791
|
+
/define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/
|
|
2792
|
+
);
|
|
2793
|
+
return !n || !s ? !1 : n[1] !== "database_name_here" && s[1] !== "username_here";
|
|
2794
|
+
}
|
|
2795
|
+
const R = [
|
|
2796
|
+
"fsockopen",
|
|
2797
|
+
"pfsockopen",
|
|
2798
|
+
"curl_init",
|
|
2799
|
+
"curl_exec",
|
|
2800
|
+
"curl_multi_exec",
|
|
2801
|
+
"mail"
|
|
2802
|
+
];
|
|
2803
|
+
function Re(e, t) {
|
|
2804
|
+
var r, a;
|
|
2805
|
+
if (!w(t.phpVersion)) return;
|
|
2806
|
+
const i = (((r = t.phpIniEntries) == null ? void 0 : r.disable_functions) ?? "").split(",").map((o) => o.trim()).filter((o) => o), s = {
|
|
2807
|
+
disable_functions: Array.from(
|
|
2808
|
+
/* @__PURE__ */ new Set([...i, ...R])
|
|
2809
|
+
).join(","),
|
|
2810
|
+
allow_url_fopen: "0"
|
|
2811
|
+
};
|
|
2812
|
+
(a = t.phpIniEntries) != null && a["date.timezone"] || (s["date.timezone"] = "UTC"), P(e, s);
|
|
2813
|
+
}
|
|
2814
|
+
async function ke(e, t) {
|
|
2815
|
+
var a, o;
|
|
2816
|
+
const i = await e.getPrimaryPhp();
|
|
2817
|
+
if ((a = t.hooks) != null && a.beforeWordPressFiles && await t.hooks.beforeWordPressFiles(i), t.wordPressZip && await D(i, await t.wordPressZip), t.constants)
|
|
2818
|
+
for (const l in t.constants)
|
|
2819
|
+
i.defineConstant(l, t.constants[l]);
|
|
2820
|
+
i.defineConstant("WP_HOME", t.siteUrl), i.defineConstant("WP_SITEURL", t.siteUrl), await Ie(i, e.documentRoot), await K(i, e.documentRoot), (o = t.hooks) != null && o.beforeDatabaseSetup && await t.hooks.beforeDatabaseSetup(i);
|
|
2821
|
+
let n = !1;
|
|
2822
|
+
t.sqliteIntegrationPluginZip && (n = !0, await I(
|
|
2823
|
+
i,
|
|
2824
|
+
await t.sqliteIntegrationPluginZip,
|
|
2825
|
+
{ phpVersion: t.phpVersion }
|
|
2826
|
+
), await De(i, e.documentRoot));
|
|
2827
|
+
const s = t.wordpressInstallMode ?? "download-and-install", r = !!t.dataSqlPath;
|
|
2828
|
+
return (s === "download-and-install" || s === "install-from-existing-files" || // Legacy PHP: isWordPressInstalled() can trigger a WASM trap
|
|
2829
|
+
// (not a PHP exception) on old WordPress (< 3.0) and corrupt
|
|
2830
|
+
// the runtime beyond recovery. Always run the installer; it
|
|
2831
|
+
// is idempotent and its post-install fixups short-circuit
|
|
2832
|
+
// cheaply when the schema already exists.
|
|
2833
|
+
s === "install-from-existing-files-if-needed") && (await E(e, {
|
|
2834
|
+
usesSqlite: n,
|
|
2835
|
+
hasCustomDatabasePath: r
|
|
2836
|
+
}), await Fe(i, e)), e;
|
|
2837
|
+
}
|
|
2838
|
+
async function Ie(e, t) {
|
|
2839
|
+
const i = _(t, "wp-config.php"), n = _(t, "wp-config-sample.php");
|
|
2840
|
+
!e.fileExists(i) && e.fileExists(n) && await e.writeFile(
|
|
2841
|
+
i,
|
|
2842
|
+
await e.readFileAsBuffer(n)
|
|
2843
|
+
);
|
|
499
2844
|
}
|
|
500
|
-
async function
|
|
501
|
-
const i =
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
foreach (${a.constantNames} as $name) {
|
|
506
|
-
if (!$transformer->constant_exists($name)) {
|
|
507
|
-
$missing[] = $name;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
echo json_encode($missing);
|
|
511
|
-
`
|
|
512
|
-
});
|
|
513
|
-
if (o.errors.length > 0)
|
|
514
|
-
throw new Error("Failed to check wp-config.php for constants.");
|
|
515
|
-
let l;
|
|
2845
|
+
async function De(e, t) {
|
|
2846
|
+
const i = _(t, "wp-content"), n = _(i, "db.php");
|
|
2847
|
+
e.isDir(i) && !e.fileExists(n) && await e.writeFile(n, be());
|
|
2848
|
+
}
|
|
2849
|
+
async function Fe(e, t) {
|
|
516
2850
|
try {
|
|
517
|
-
|
|
518
|
-
} catch {
|
|
2851
|
+
await Ce(e);
|
|
2852
|
+
} catch (i) {
|
|
2853
|
+
h.warn("Legacy PHP WordPress installation error:", i);
|
|
2854
|
+
}
|
|
2855
|
+
await Oe(e, t.absoluteUrl);
|
|
2856
|
+
}
|
|
2857
|
+
async function Ce(e) {
|
|
2858
|
+
var r, a, o, l, c, u;
|
|
2859
|
+
const t = Ge(e, e.documentRoot);
|
|
2860
|
+
if (t !== null) {
|
|
2861
|
+
const d = parseFloat(t);
|
|
2862
|
+
if (d < 2.1)
|
|
2863
|
+
return;
|
|
2864
|
+
if (d <= 3) {
|
|
2865
|
+
await We(e);
|
|
2866
|
+
return;
|
|
2867
|
+
}
|
|
2868
|
+
}
|
|
2869
|
+
const i = {
|
|
2870
|
+
disable_functions: R.join(","),
|
|
2871
|
+
allow_url_fopen: "0",
|
|
2872
|
+
error_reporting: String(Y)
|
|
2873
|
+
}, n = await N(
|
|
2874
|
+
e,
|
|
2875
|
+
i,
|
|
2876
|
+
async () => await e.request({
|
|
2877
|
+
url: "/wp-admin/install.php?step=2",
|
|
2878
|
+
method: "POST",
|
|
2879
|
+
body: {
|
|
2880
|
+
language: "en",
|
|
2881
|
+
prefix: "wp_",
|
|
2882
|
+
weblog_title: "My WordPress Website",
|
|
2883
|
+
user_name: "admin",
|
|
2884
|
+
admin_password: "password",
|
|
2885
|
+
admin_password2: "password",
|
|
2886
|
+
Submit: "Install WordPress",
|
|
2887
|
+
pw_weak: "1",
|
|
2888
|
+
admin_email: "admin@localhost.com"
|
|
2889
|
+
}
|
|
2890
|
+
})
|
|
2891
|
+
);
|
|
2892
|
+
if (!(((r = n.text) == null ? void 0 : r.includes("Success")) || ((a = n.text) == null ? void 0 : a.includes("successful")) || ((o = n.text) == null ? void 0 : o.includes("Finished")) || ((l = n.text) == null ? void 0 : l.includes("Already Installed")) || ((c = n.text) == null ? void 0 : c.includes("already have WordPress installed")) || !1))
|
|
519
2893
|
throw new Error(
|
|
520
|
-
`Failed to
|
|
2894
|
+
`Failed to install WordPress – installer responded with "${(u = n.text) == null ? void 0 : u.substring(
|
|
2895
|
+
0,
|
|
2896
|
+
100
|
|
2897
|
+
)}"`
|
|
2898
|
+
);
|
|
2899
|
+
await qe(e);
|
|
2900
|
+
}
|
|
2901
|
+
async function qe(e) {
|
|
2902
|
+
try {
|
|
2903
|
+
(await e.run({
|
|
2904
|
+
code: `<?php
|
|
2905
|
+
$db_dir = getenv('DOCUMENT_ROOT') . '/wp-content/database/';
|
|
2906
|
+
$db_path = $db_dir . '.ht.sqlite';
|
|
2907
|
+
if (!file_exists($db_path)) { echo '0'; exit; }
|
|
2908
|
+
$pdo = new PDO('sqlite:' . $db_path);
|
|
2909
|
+
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
|
2910
|
+
$nice_permalinks = '/%year%/%monthnum%/%day%/%postname%/';
|
|
2911
|
+
$stmt = $pdo->prepare(
|
|
2912
|
+
"UPDATE wp_options SET option_value = :val WHERE option_name = 'permalink_structure'"
|
|
2913
|
+
);
|
|
2914
|
+
$stmt->execute(array(':val' => $nice_permalinks));
|
|
2915
|
+
if ($stmt->rowCount() === 0) {
|
|
2916
|
+
$stmt = $pdo->prepare(
|
|
2917
|
+
"INSERT INTO wp_options (option_name, option_value, autoload) VALUES ('permalink_structure', :val, 'yes')"
|
|
2918
|
+
);
|
|
2919
|
+
$stmt->execute(array(':val' => $nice_permalinks));
|
|
2920
|
+
}
|
|
2921
|
+
$check = $pdo->query(
|
|
2922
|
+
"SELECT option_value FROM wp_options WHERE option_name = 'permalink_structure'"
|
|
2923
|
+
)->fetchColumn();
|
|
2924
|
+
echo $check === $nice_permalinks ? '1' : '0';
|
|
2925
|
+
`,
|
|
2926
|
+
env: { DOCUMENT_ROOT: e.documentRoot }
|
|
2927
|
+
})).text !== "1" && h.warn(
|
|
2928
|
+
"Failed to default to pretty permalinks after WP install."
|
|
2929
|
+
);
|
|
2930
|
+
} catch {
|
|
2931
|
+
h.warn(
|
|
2932
|
+
"Failed to set pretty permalinks after WP install (non-fatal)."
|
|
521
2933
|
);
|
|
522
2934
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
2935
|
+
}
|
|
2936
|
+
async function We(e) {
|
|
2937
|
+
try {
|
|
2938
|
+
await e.run({
|
|
2939
|
+
code: `<?php
|
|
2940
|
+
define('WP_INSTALLING', true);
|
|
2941
|
+
error_reporting(${L});
|
|
2942
|
+
ini_set('display_errors', '0');
|
|
2943
|
+
ob_start();
|
|
2944
|
+
require getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
2945
|
+
ob_clean();
|
|
2946
|
+
if (file_exists(ABSPATH . 'wp-admin/includes/upgrade.php')) {
|
|
2947
|
+
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
|
|
2948
|
+
} elseif (file_exists(ABSPATH . 'wp-admin/upgrade-functions.php')) {
|
|
2949
|
+
require_once ABSPATH . 'wp-admin/upgrade-functions.php';
|
|
2950
|
+
}
|
|
2951
|
+
if (function_exists('make_db_current_silent')) {
|
|
2952
|
+
make_db_current_silent();
|
|
2953
|
+
}
|
|
2954
|
+
// Seed essential options/roles when the loader exposes
|
|
2955
|
+
// them. The PDO fallback in runPostInstallLegacyFixups
|
|
2956
|
+
// backfills anything missing if either call dies.
|
|
2957
|
+
if (function_exists('populate_options')) populate_options();
|
|
2958
|
+
if (function_exists('populate_roles')) populate_roles();
|
|
2959
|
+
echo 'OK';
|
|
2960
|
+
`,
|
|
2961
|
+
env: { DOCUMENT_ROOT: e.documentRoot }
|
|
2962
|
+
});
|
|
2963
|
+
} catch (t) {
|
|
2964
|
+
h.warn("runDbDeltaOnly failed (non-fatal):", t);
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
function Ge(e, t) {
|
|
2968
|
+
const i = _(t, "wp-includes/version.php");
|
|
2969
|
+
if (!e.fileExists(i)) return null;
|
|
2970
|
+
const s = e.readFileAsText(i).match(/\$wp_version\s*=\s*['"]([^'"]+)['"]/);
|
|
2971
|
+
return s ? s[1] : null;
|
|
2972
|
+
}
|
|
2973
|
+
async function rt(e) {
|
|
2974
|
+
const t = await He(e);
|
|
2975
|
+
return await Me(t, e), t;
|
|
2976
|
+
}
|
|
2977
|
+
async function Me(e, t) {
|
|
2978
|
+
var a, o;
|
|
2979
|
+
if (w(t.phpVersion))
|
|
2980
|
+
return ke(e, t);
|
|
2981
|
+
const i = await e.getPrimaryPhp();
|
|
2982
|
+
if ((a = t.hooks) != null && a.beforeWordPressFiles && await t.hooks.beforeWordPressFiles(i), t.wordPressZip && await D(i, await t.wordPressZip), t.constants)
|
|
2983
|
+
for (const l in t.constants)
|
|
2984
|
+
i.defineConstant(l, t.constants[l]);
|
|
2985
|
+
t.dataSqlPath && (i.defineConstant("DB_DIR", W(t.dataSqlPath)), i.defineConstant("DB_FILE", G(t.dataSqlPath))), i.defineConstant("WP_HOME", t.siteUrl), i.defineConstant("WP_SITEURL", t.siteUrl), await ve(i, e.documentRoot), (o = t.hooks) != null && o.beforeDatabaseSetup && await t.hooks.beforeDatabaseSetup(i);
|
|
2986
|
+
let n = !1;
|
|
2987
|
+
t.sqliteIntegrationPluginZip && (n = !0, await I(
|
|
2988
|
+
i,
|
|
2989
|
+
await t.sqliteIntegrationPluginZip,
|
|
2990
|
+
{ phpVersion: t.phpVersion }
|
|
2991
|
+
), await X(i, e.documentRoot));
|
|
2992
|
+
const s = t.wordpressInstallMode ?? "download-and-install", r = !!t.dataSqlPath;
|
|
543
2993
|
if (["download-and-install", "install-from-existing-files"].includes(
|
|
544
|
-
|
|
2994
|
+
s
|
|
545
2995
|
)) {
|
|
546
|
-
await
|
|
547
|
-
usesSqlite:
|
|
548
|
-
hasCustomDatabasePath:
|
|
2996
|
+
await E(e, {
|
|
2997
|
+
usesSqlite: n,
|
|
2998
|
+
hasCustomDatabasePath: r
|
|
549
2999
|
});
|
|
550
3000
|
try {
|
|
551
|
-
await
|
|
552
|
-
} catch (
|
|
553
|
-
throw
|
|
3001
|
+
await O(i);
|
|
3002
|
+
} catch (l) {
|
|
3003
|
+
throw r || await g(e), l;
|
|
554
3004
|
}
|
|
555
|
-
|
|
556
|
-
} else if (
|
|
557
|
-
if (await
|
|
558
|
-
usesSqlite:
|
|
559
|
-
hasCustomDatabasePath:
|
|
560
|
-
}), !await
|
|
3005
|
+
r || await g(e);
|
|
3006
|
+
} else if (s === "install-from-existing-files-if-needed") {
|
|
3007
|
+
if (await E(e, {
|
|
3008
|
+
usesSqlite: n,
|
|
3009
|
+
hasCustomDatabasePath: r
|
|
3010
|
+
}), !await k(i))
|
|
561
3011
|
try {
|
|
562
|
-
await
|
|
563
|
-
} catch (
|
|
564
|
-
throw
|
|
3012
|
+
await O(i);
|
|
3013
|
+
} catch (l) {
|
|
3014
|
+
throw r || await g(e), l;
|
|
565
3015
|
}
|
|
566
|
-
|
|
3016
|
+
r || await g(e);
|
|
567
3017
|
}
|
|
568
|
-
return
|
|
569
|
-
}
|
|
570
|
-
async function _(t, {
|
|
571
|
-
usesSqlite: e,
|
|
572
|
-
hasCustomDatabasePath: n
|
|
573
|
-
}) {
|
|
574
|
-
const i = await t.getPrimaryPhp();
|
|
575
|
-
if (i.isFile("/internal/shared/preload/0-sqlite.php"))
|
|
576
|
-
return;
|
|
577
|
-
const a = s(
|
|
578
|
-
t.documentRoot,
|
|
579
|
-
"wp-content/mu-plugins/sqlite-database-integration"
|
|
580
|
-
);
|
|
581
|
-
if (!i.isDir(a) && !e && !n && !A(i))
|
|
582
|
-
throw new Error("Error connecting to the MySQL database.");
|
|
3018
|
+
return e;
|
|
583
3019
|
}
|
|
584
|
-
async function
|
|
585
|
-
const
|
|
586
|
-
if (await
|
|
3020
|
+
async function g(e) {
|
|
3021
|
+
const t = await e.getPrimaryPhp();
|
|
3022
|
+
if (await Ve(t))
|
|
587
3023
|
return;
|
|
588
|
-
if (
|
|
3024
|
+
if (t.isFile("/internal/shared/preload/0-sqlite.php"))
|
|
589
3025
|
throw new Error("Error connecting to the SQLite database.");
|
|
590
|
-
const
|
|
591
|
-
|
|
3026
|
+
const n = _(
|
|
3027
|
+
e.documentRoot,
|
|
592
3028
|
"wp-content/mu-plugins/sqlite-database-integration"
|
|
593
3029
|
);
|
|
594
|
-
throw
|
|
595
|
-
}
|
|
596
|
-
async function
|
|
597
|
-
const
|
|
598
|
-
async function
|
|
599
|
-
const
|
|
600
|
-
if (
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
3030
|
+
throw t.isDir(n) ? new Error("Error connecting to the SQLite database.") : new Error("Error connecting to the MySQL database.");
|
|
3031
|
+
}
|
|
3032
|
+
async function He(e) {
|
|
3033
|
+
const t = e.spawnHandler ?? F;
|
|
3034
|
+
async function i(s, r = !1) {
|
|
3035
|
+
const a = await e.createPhpRuntime(r), o = new q(a);
|
|
3036
|
+
if (e.sapiName && o.setSapiName(e.sapiName), s && (o.requestHandler = s), e.phpIniEntries && P(o, e.phpIniEntries), Re(o, {
|
|
3037
|
+
phpVersion: e.phpVersion,
|
|
3038
|
+
phpIniEntries: e.phpIniEntries
|
|
3039
|
+
}), o.defineConstant("WP_SQLITE_AST_DRIVER", !0), e.constants)
|
|
3040
|
+
for (const l in e.constants)
|
|
3041
|
+
o.defineConstant(l, e.constants[l]);
|
|
3042
|
+
return r && /**
|
|
604
3043
|
* Only the first PHP instance of the first worker created
|
|
605
3044
|
* during WordPress boot writes these files – otherwise we'll keep
|
|
606
3045
|
* overwriting them with concurrent writers living in other worker
|
|
@@ -610,45 +3049,47 @@ async function C(t) {
|
|
|
610
3049
|
* mechanism. It works, because secondary workers are only booted
|
|
611
3050
|
* once the primary worker has fully booted.
|
|
612
3051
|
*/
|
|
613
|
-
!
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
3052
|
+
!o.isFile("/internal/.boot-files-written") && (await Ke(o, {
|
|
3053
|
+
phpVersion: e.phpVersion
|
|
3054
|
+
}), await b(o, "/", e.createFiles || {}), await Qe(
|
|
3055
|
+
o,
|
|
3056
|
+
_(new URL(e.siteUrl).pathname, "phpinfo.php")
|
|
3057
|
+
), await b(o, "/internal", {
|
|
617
3058
|
".boot-files-written": ""
|
|
618
|
-
})),
|
|
619
|
-
|
|
620
|
-
|
|
3059
|
+
})), t && await o.setSpawnHandler(
|
|
3060
|
+
t(
|
|
3061
|
+
s ? () => s.instanceManager.acquirePHPInstance() : void 0
|
|
621
3062
|
)
|
|
622
|
-
),
|
|
623
|
-
recreateRuntime:
|
|
3063
|
+
), o.enableRuntimeRotation({
|
|
3064
|
+
recreateRuntime: e.createPhpRuntime,
|
|
624
3065
|
maxRequests: 400
|
|
625
|
-
}),
|
|
3066
|
+
}), e.onPHPInstanceCreated && await e.onPHPInstanceCreated(o, { isPrimary: r }), o;
|
|
626
3067
|
}
|
|
627
|
-
const
|
|
628
|
-
documentRoot:
|
|
629
|
-
absoluteUrl:
|
|
630
|
-
rewriteRules:
|
|
631
|
-
pathAliases:
|
|
632
|
-
getFileNotFoundAction:
|
|
633
|
-
cookieStore:
|
|
3068
|
+
const n = new C({
|
|
3069
|
+
documentRoot: e.documentRoot || "/wordpress",
|
|
3070
|
+
absoluteUrl: e.siteUrl,
|
|
3071
|
+
rewriteRules: Ye,
|
|
3072
|
+
pathAliases: e.pathAliases,
|
|
3073
|
+
getFileNotFoundAction: e.getFileNotFoundAction ?? Be,
|
|
3074
|
+
cookieStore: e.cookieStore,
|
|
634
3075
|
/**
|
|
635
3076
|
* If maxPhpInstances is 1, the PHPRequestHandler constructor needs
|
|
636
3077
|
* a PHP instance. Internally, it creates a SinglePHPInstanceManager
|
|
637
3078
|
* and uses the same PHP instance to handle all requests.
|
|
638
3079
|
*/
|
|
639
|
-
php:
|
|
3080
|
+
php: e.maxPhpInstances === 1 ? await i(void 0, !0) : void 0,
|
|
640
3081
|
/**
|
|
641
3082
|
* If maxPhpInstances is not 1, the PHPRequestHandler constructor needs
|
|
642
3083
|
* a PHP factory function. Internally, it creates a PHPProcessManager that
|
|
643
3084
|
* maintains a pool of reusable PHP instances.
|
|
644
3085
|
*/
|
|
645
|
-
phpFactory:
|
|
646
|
-
maxPhpInstances:
|
|
3086
|
+
phpFactory: e.maxPhpInstances !== 1 ? async ({ isPrimary: s }) => i(n, s) : void 0,
|
|
3087
|
+
maxPhpInstances: e.maxPhpInstances
|
|
647
3088
|
});
|
|
648
|
-
return
|
|
3089
|
+
return n;
|
|
649
3090
|
}
|
|
650
|
-
async function
|
|
651
|
-
return (await
|
|
3091
|
+
async function k(e) {
|
|
3092
|
+
return (await e.run({
|
|
652
3093
|
code: `<?php
|
|
653
3094
|
ob_start();
|
|
654
3095
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
@@ -662,19 +3103,19 @@ async function w(t) {
|
|
|
662
3103
|
ob_end_flush();
|
|
663
3104
|
`,
|
|
664
3105
|
env: {
|
|
665
|
-
DOCUMENT_ROOT:
|
|
3106
|
+
DOCUMENT_ROOT: e.documentRoot
|
|
666
3107
|
}
|
|
667
3108
|
})).text === "1";
|
|
668
3109
|
}
|
|
669
|
-
async function
|
|
670
|
-
var
|
|
671
|
-
const
|
|
672
|
-
|
|
3110
|
+
async function O(e) {
|
|
3111
|
+
var n;
|
|
3112
|
+
const t = await N(
|
|
3113
|
+
e,
|
|
673
3114
|
{
|
|
674
3115
|
disable_functions: "fsockopen",
|
|
675
3116
|
allow_url_fopen: "0"
|
|
676
3117
|
},
|
|
677
|
-
async () => await
|
|
3118
|
+
async () => await e.request({
|
|
678
3119
|
url: "/wp-admin/install.php?step=2",
|
|
679
3120
|
method: "POST",
|
|
680
3121
|
body: {
|
|
@@ -691,14 +3132,14 @@ async function h(t) {
|
|
|
691
3132
|
}
|
|
692
3133
|
})
|
|
693
3134
|
);
|
|
694
|
-
if (!await
|
|
3135
|
+
if (!await k(e))
|
|
695
3136
|
throw new Error(
|
|
696
|
-
`Failed to install WordPress – installer responded with "${(
|
|
3137
|
+
`Failed to install WordPress – installer responded with "${(n = t.text) == null ? void 0 : n.substring(
|
|
697
3138
|
0,
|
|
698
3139
|
100
|
|
699
3140
|
)}"`
|
|
700
3141
|
);
|
|
701
|
-
(await
|
|
3142
|
+
(await e.run({
|
|
702
3143
|
code: `<?php
|
|
703
3144
|
ob_start();
|
|
704
3145
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
@@ -721,28 +3162,18 @@ async function h(t) {
|
|
|
721
3162
|
ob_end_flush();
|
|
722
3163
|
`,
|
|
723
3164
|
env: {
|
|
724
|
-
DOCUMENT_ROOT:
|
|
3165
|
+
DOCUMENT_ROOT: e.documentRoot
|
|
725
3166
|
}
|
|
726
|
-
})).text !== "1" &&
|
|
3167
|
+
})).text !== "1" && h.warn("Failed to default to pretty permalinks after WP install.");
|
|
727
3168
|
}
|
|
728
|
-
function
|
|
3169
|
+
function Be(e) {
|
|
729
3170
|
return {
|
|
730
3171
|
type: "internal-redirect",
|
|
731
3172
|
uri: "/index.php"
|
|
732
3173
|
};
|
|
733
3174
|
}
|
|
734
|
-
function
|
|
735
|
-
|
|
736
|
-
if (!t.isFile(e)) return !1;
|
|
737
|
-
const n = t.readFileAsText(e), i = n.match(
|
|
738
|
-
/define\s*\(\s*['"]DB_NAME['"]\s*,\s*['"]([^'"]*)['"]/
|
|
739
|
-
), a = n.match(
|
|
740
|
-
/define\s*\(\s*['"]DB_USER['"]\s*,\s*['"]([^'"]*)['"]/
|
|
741
|
-
);
|
|
742
|
-
return !i || !a ? !1 : i[1] !== "database_name_here" && a[1] !== "username_here";
|
|
743
|
-
}
|
|
744
|
-
async function W(t) {
|
|
745
|
-
return (await t.run({
|
|
3175
|
+
async function Ve(e) {
|
|
3176
|
+
return (await e.run({
|
|
746
3177
|
code: `<?php
|
|
747
3178
|
ob_start();
|
|
748
3179
|
$wp_load = getenv('DOCUMENT_ROOT') . '/wp-load.php';
|
|
@@ -756,35 +3187,35 @@ async function W(t) {
|
|
|
756
3187
|
ob_end_flush();
|
|
757
3188
|
`,
|
|
758
3189
|
env: {
|
|
759
|
-
DOCUMENT_ROOT:
|
|
3190
|
+
DOCUMENT_ROOT: e.documentRoot
|
|
760
3191
|
}
|
|
761
3192
|
})).text === "1";
|
|
762
3193
|
}
|
|
763
|
-
async function
|
|
764
|
-
const { php:
|
|
3194
|
+
async function at(e) {
|
|
3195
|
+
const { php: t, reap: i } = await e.instanceManager.acquirePHPInstance();
|
|
765
3196
|
try {
|
|
766
|
-
const
|
|
3197
|
+
const s = (await t.run({
|
|
767
3198
|
code: `<?php
|
|
768
|
-
require '${
|
|
3199
|
+
require '${e.documentRoot}/wp-includes/version.php';
|
|
769
3200
|
echo $wp_version;
|
|
770
3201
|
`
|
|
771
3202
|
})).text;
|
|
772
|
-
if (!
|
|
3203
|
+
if (!s)
|
|
773
3204
|
throw new Error("Unable to read loaded WordPress version.");
|
|
774
|
-
return
|
|
3205
|
+
return Xe(s);
|
|
775
3206
|
} finally {
|
|
776
|
-
|
|
3207
|
+
i();
|
|
777
3208
|
}
|
|
778
3209
|
}
|
|
779
|
-
function
|
|
780
|
-
if (/-(alpha|beta|RC)\d*-\d+$/.test(
|
|
3210
|
+
function Xe(e) {
|
|
3211
|
+
if (/-(alpha|beta|RC)\d*-\d+$/.test(e))
|
|
781
3212
|
return "trunk";
|
|
782
|
-
if (/-(beta|RC)\d*$/.test(
|
|
3213
|
+
if (/-(beta|RC)\d*$/.test(e))
|
|
783
3214
|
return "beta";
|
|
784
|
-
const
|
|
785
|
-
return
|
|
3215
|
+
const n = e.match(/^(\d+\.\d+)(?:\.\d+)?$/);
|
|
3216
|
+
return n !== null ? n[1] : e;
|
|
786
3217
|
}
|
|
787
|
-
const
|
|
3218
|
+
const Ye = [
|
|
788
3219
|
/**
|
|
789
3220
|
* Substitutes the multisite WordPress rewrite rule:
|
|
790
3221
|
*
|
|
@@ -800,8 +3231,10 @@ const q = [
|
|
|
800
3231
|
replacement: "$2"
|
|
801
3232
|
}
|
|
802
3233
|
];
|
|
803
|
-
async function
|
|
804
|
-
|
|
3234
|
+
async function Ke(e, t = {}) {
|
|
3235
|
+
if (w(t.phpVersion))
|
|
3236
|
+
return B(e);
|
|
3237
|
+
await e.mkdir("/internal/shared/mu-plugins"), await e.writeFile(
|
|
805
3238
|
"/internal/shared/preload/env.php",
|
|
806
3239
|
`<?php
|
|
807
3240
|
|
|
@@ -831,7 +3264,7 @@ async function N(t) {
|
|
|
831
3264
|
}
|
|
832
3265
|
}
|
|
833
3266
|
`
|
|
834
|
-
), await
|
|
3267
|
+
), await e.writeFile(
|
|
835
3268
|
"/internal/shared/mu-plugins/1-auto-login.php",
|
|
836
3269
|
`<?php
|
|
837
3270
|
/**
|
|
@@ -988,111 +3421,7 @@ async function N(t) {
|
|
|
988
3421
|
return $interval;
|
|
989
3422
|
});
|
|
990
3423
|
`
|
|
991
|
-
), await
|
|
992
|
-
"/internal/shared/mu-plugins/0-playground.php",
|
|
993
|
-
`<?php
|
|
994
|
-
|
|
995
|
-
// Save WordPress environment information to a file.
|
|
996
|
-
add_action('wp_loaded', function() {
|
|
997
|
-
if (defined('DB_ENGINE') && DB_ENGINE === 'sqlite') {
|
|
998
|
-
$db_info = array(
|
|
999
|
-
'type' => 'sqlite',
|
|
1000
|
-
'path' => FQDB,
|
|
1001
|
-
'driver_path' => defined('WP_MYSQL_ON_SQLITE_LOADER_PATH')
|
|
1002
|
-
? WP_MYSQL_ON_SQLITE_LOADER_PATH
|
|
1003
|
-
: dirname(SQLITE_MAIN_FILE) . '/wp-pdo-mysql-on-sqlite.php',
|
|
1004
|
-
);
|
|
1005
|
-
} else {
|
|
1006
|
-
$db_info = array(
|
|
1007
|
-
'type' => 'mysql',
|
|
1008
|
-
// TODO: Save MySQL connection config.
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
$wp_env = array('db' => $db_info);
|
|
1012
|
-
$wp_env_php = sprintf('<?php return %s;', var_export($wp_env, true));
|
|
1013
|
-
$wp_env_file = '/internal/shared/wp-env.php';
|
|
1014
|
-
if (!file_exists($wp_env_file) || file_get_contents($wp_env_file) !== $wp_env_php ) {
|
|
1015
|
-
file_put_contents($wp_env_file, $wp_env_php);
|
|
1016
|
-
}
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
// Needed because gethostbyname( 'wordpress.org' ) returns
|
|
1020
|
-
// a private network IP address for some reason.
|
|
1021
|
-
add_filter( 'allowed_redirect_hosts', function( $deprecated = '' ) {
|
|
1022
|
-
return array(
|
|
1023
|
-
'wordpress.org',
|
|
1024
|
-
'api.wordpress.org',
|
|
1025
|
-
'downloads.wordpress.org',
|
|
1026
|
-
);
|
|
1027
|
-
} );
|
|
1028
|
-
|
|
1029
|
-
/**
|
|
1030
|
-
* Prevents wp_http_validate_url() from universally failing.
|
|
1031
|
-
*
|
|
1032
|
-
* wp_http_validate_url() calls gethostbyname() to verify whether the host
|
|
1033
|
-
* is external. If it is internal, the URL validation fails and WordPress
|
|
1034
|
-
* refuses to make a request.
|
|
1035
|
-
*
|
|
1036
|
-
* However, in EMscripten, gethostbyname() returns a private network IP address.
|
|
1037
|
-
* This causes wp_http_validate_url() to return false for all URLs.
|
|
1038
|
-
*
|
|
1039
|
-
* This filter ensures that all URLs are considered external. In production
|
|
1040
|
-
* environments, this would be considered a security risk. However, Playground
|
|
1041
|
-
* already provides multiple code execution vectors as features (e.g. Blueprints).
|
|
1042
|
-
*
|
|
1043
|
-
* If someone wants to poke around local IP addresses, they already have multiple
|
|
1044
|
-
* tools at their disposal. Therefore, this is not a real security risk in context
|
|
1045
|
-
* of WordPress Playground or Playground CLI.
|
|
1046
|
-
*/
|
|
1047
|
-
add_filter('http_request_host_is_external', '__return_true');
|
|
1048
|
-
|
|
1049
|
-
// Support pretty permalinks
|
|
1050
|
-
add_filter( 'got_url_rewrite', '__return_true' );
|
|
1051
|
-
|
|
1052
|
-
// Create the fonts directory if missing
|
|
1053
|
-
if(!file_exists(WP_CONTENT_DIR . '/fonts')) {
|
|
1054
|
-
mkdir(WP_CONTENT_DIR . '/fonts');
|
|
1055
|
-
}
|
|
1056
|
-
|
|
1057
|
-
$log_file = WP_CONTENT_DIR . '/debug.log';
|
|
1058
|
-
if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
|
|
1059
|
-
if ( is_string( WP_DEBUG_LOG ) ) {
|
|
1060
|
-
$log_file = WP_DEBUG_LOG;
|
|
1061
|
-
}
|
|
1062
|
-
ini_set('error_log', $log_file);
|
|
1063
|
-
} else {
|
|
1064
|
-
ini_set('log_errors', '0');
|
|
1065
|
-
}
|
|
1066
|
-
define('ERROR_LOG_FILE', $log_file);
|
|
1067
|
-
?>`
|
|
1068
|
-
), await t.writeFile(
|
|
1069
|
-
"/internal/shared/mu-plugins/sitemap-redirect.php",
|
|
1070
|
-
`<?php
|
|
1071
|
-
/**
|
|
1072
|
-
* Redirect sitemap.xml to wp-sitemap.xml for non-root installations.
|
|
1073
|
-
*
|
|
1074
|
-
* WordPress seems to only generate the sitemap.xml → wp-sitemap.xml rewrite
|
|
1075
|
-
* rule when installed at the domain root. This mu-plugin handles the
|
|
1076
|
-
* redirect for non-root installations.
|
|
1077
|
-
*/
|
|
1078
|
-
if (isset($_SERVER['REQUEST_URI'])) {
|
|
1079
|
-
$site_url = site_url();
|
|
1080
|
-
$parsed = parse_url($site_url);
|
|
1081
|
-
$base_path = isset($parsed['path']) ? rtrim($parsed['path'], '/') : '';
|
|
1082
|
-
|
|
1083
|
-
$request_uri = $_SERVER['REQUEST_URI'];
|
|
1084
|
-
if (
|
|
1085
|
-
$request_uri === $base_path . '/sitemap.xml' ||
|
|
1086
|
-
strpos($request_uri, $base_path . '/sitemap.xml?') === 0 ||
|
|
1087
|
-
strpos($request_uri, $base_path . '/sitemap.xml/') === 0
|
|
1088
|
-
) {
|
|
1089
|
-
$query_string = strpos($request_uri, '?') !== false ? substr($request_uri, strpos($request_uri, '?')) : '';
|
|
1090
|
-
header('Location: ' . $base_path . '/wp-sitemap.xml' . $query_string, true, 301);
|
|
1091
|
-
exit;
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
`
|
|
1095
|
-
), await t.writeFile(
|
|
3424
|
+
), await S(e), await e.writeFile(
|
|
1096
3425
|
"/internal/shared/preload/error-handler.php",
|
|
1097
3426
|
`<?php
|
|
1098
3427
|
(function() {
|
|
@@ -1145,13 +3474,13 @@ async function N(t) {
|
|
|
1145
3474
|
})();`
|
|
1146
3475
|
);
|
|
1147
3476
|
}
|
|
1148
|
-
async function
|
|
1149
|
-
await
|
|
3477
|
+
async function Qe(e, t = "/phpinfo.php") {
|
|
3478
|
+
await e.writeFile(
|
|
1150
3479
|
"/internal/shared/preload/phpinfo.php",
|
|
1151
3480
|
`<?php
|
|
1152
3481
|
// Render PHPInfo if the requested page is /phpinfo.php
|
|
1153
|
-
if ( isset($_SERVER['REQUEST_URI']) && ${
|
|
1154
|
-
|
|
3482
|
+
if ( isset($_SERVER['REQUEST_URI']) && ${$(
|
|
3483
|
+
t
|
|
1155
3484
|
)} === $_SERVER['REQUEST_URI'] ) {
|
|
1156
3485
|
phpinfo();
|
|
1157
3486
|
exit;
|
|
@@ -1159,105 +3488,44 @@ async function F(t, e = "/phpinfo.php") {
|
|
|
1159
3488
|
`
|
|
1160
3489
|
);
|
|
1161
3490
|
}
|
|
1162
|
-
async function
|
|
1163
|
-
|
|
3491
|
+
async function I(e, t, i = {}) {
|
|
3492
|
+
if (w(i.phpVersion))
|
|
3493
|
+
return Ne(e, t, i);
|
|
3494
|
+
await e.isDir("/tmp/sqlite-database-integration") && await e.rmdir("/tmp/sqlite-database-integration", {
|
|
1164
3495
|
recursive: !0
|
|
1165
|
-
}), await
|
|
1166
|
-
const n = "/internal/shared/sqlite-database-integration",
|
|
1167
|
-
await
|
|
1168
|
-
const
|
|
1169
|
-
|
|
3496
|
+
}), await e.mkdir("/tmp/sqlite-database-integration"), await m(e, t, "/tmp/sqlite-database-integration");
|
|
3497
|
+
const n = "/internal/shared/sqlite-database-integration", s = `/tmp/sqlite-database-integration/${(await e.listFiles("/tmp/sqlite-database-integration"))[0]}`;
|
|
3498
|
+
await e.mv(s, n);
|
|
3499
|
+
const r = _(
|
|
3500
|
+
n,
|
|
3501
|
+
"wp-includes/sqlite/class-wp-sqlite-db.php"
|
|
3502
|
+
);
|
|
3503
|
+
if (await e.fileExists(r)) {
|
|
3504
|
+
const d = await e.readFileAsText(r), f = d.replace(
|
|
3505
|
+
"private $allow_unsafe_unquoted_parameters",
|
|
3506
|
+
"protected $allow_unsafe_unquoted_parameters"
|
|
3507
|
+
);
|
|
3508
|
+
f !== d && await e.writeFile(r, f);
|
|
3509
|
+
}
|
|
3510
|
+
await e.defineConstant("SQLITE_MAIN_FILE", "1");
|
|
3511
|
+
const o = (await e.readFileAsText(
|
|
3512
|
+
_(n, "db.copy")
|
|
1170
3513
|
)).replace(
|
|
1171
3514
|
"'{SQLITE_IMPLEMENTATION_FOLDER_PATH}'",
|
|
1172
|
-
|
|
3515
|
+
$(n)
|
|
1173
3516
|
).replace(
|
|
1174
3517
|
"'{SQLITE_PLUGIN}'",
|
|
1175
|
-
|
|
1176
|
-
), l =
|
|
3518
|
+
$(_(n, "load.php"))
|
|
3519
|
+
), l = _(await e.documentRoot, "wp-content/db.php"), c = `<?php
|
|
1177
3520
|
// Do not preload this if WordPress comes with a custom db.php file.
|
|
1178
|
-
if(file_exists(${
|
|
3521
|
+
if(file_exists(${$(l)})) {
|
|
1179
3522
|
return;
|
|
1180
3523
|
}
|
|
1181
|
-
?>`,
|
|
1182
|
-
await
|
|
3524
|
+
?>`, u = "/internal/shared/mu-plugins/sqlite-database-integration.php";
|
|
3525
|
+
await e.writeFile(u, c + o), await e.writeFile(
|
|
1183
3526
|
"/internal/shared/preload/0-sqlite.php",
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* Loads the SQLite integration plugin before WordPress is loaded
|
|
1188
|
-
* and without creating a drop-in "db.php" file.
|
|
1189
|
-
*
|
|
1190
|
-
* Technically, it creates a global $wpdb object whose only two
|
|
1191
|
-
* purposes are to:
|
|
1192
|
-
*
|
|
1193
|
-
* * Exist – because the require_wp_db() WordPress function won't
|
|
1194
|
-
* connect to MySQL if $wpdb is already set.
|
|
1195
|
-
* * Load the SQLite integration plugin the first time it's used
|
|
1196
|
-
* and replace the global $wpdb reference with the SQLite one.
|
|
1197
|
-
*
|
|
1198
|
-
* This lets Playground keep the WordPress installation clean and
|
|
1199
|
-
* solves dillemas like:
|
|
1200
|
-
*
|
|
1201
|
-
* * Should we include db.php in Playground exports?
|
|
1202
|
-
* * Should we remove db.php from Playground imports?
|
|
1203
|
-
* * How should we treat stale db.php from long-lived OPFS sites?
|
|
1204
|
-
*
|
|
1205
|
-
* @see https://github.com/WordPress/wordpress-playground/discussions/1379 for
|
|
1206
|
-
* more context.
|
|
1207
|
-
*/
|
|
1208
|
-
class Playground_SQLite_Integration_Loader {
|
|
1209
|
-
public function __call($name, $arguments) {
|
|
1210
|
-
$this->load_sqlite_integration();
|
|
1211
|
-
if($GLOBALS['wpdb'] === $this) {
|
|
1212
|
-
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
1213
|
-
}
|
|
1214
|
-
return call_user_func_array(
|
|
1215
|
-
array($GLOBALS['wpdb'], $name),
|
|
1216
|
-
$arguments
|
|
1217
|
-
);
|
|
1218
|
-
}
|
|
1219
|
-
public function __get($name) {
|
|
1220
|
-
$this->load_sqlite_integration();
|
|
1221
|
-
if($GLOBALS['wpdb'] === $this) {
|
|
1222
|
-
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
1223
|
-
}
|
|
1224
|
-
return $GLOBALS['wpdb']->$name;
|
|
1225
|
-
}
|
|
1226
|
-
public function __set($name, $value) {
|
|
1227
|
-
$this->load_sqlite_integration();
|
|
1228
|
-
if($GLOBALS['wpdb'] === $this) {
|
|
1229
|
-
throw new Exception('Infinite loop detected in $wpdb – SQLite integration plugin could not be loaded');
|
|
1230
|
-
}
|
|
1231
|
-
$GLOBALS['wpdb']->$name = $value;
|
|
1232
|
-
}
|
|
1233
|
-
protected function load_sqlite_integration() {
|
|
1234
|
-
require_once ${d(c)};
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
/**
|
|
1238
|
-
* The Query Monitor plugin short-circuits in the CLI SAPI. However, in Playground,
|
|
1239
|
-
* the SAPI is always "cli" at the moment. Let's set a constant to disable the CLI
|
|
1240
|
-
* detection.
|
|
1241
|
-
*
|
|
1242
|
-
* @see https://github.com/WordPress/sqlite-database-integration/pull/212
|
|
1243
|
-
* @see https://github.com/WordPress/sqlite-database-integration/pull/215
|
|
1244
|
-
*/
|
|
1245
|
-
define('QM_TESTS', true);
|
|
1246
|
-
$wpdb = $GLOBALS['wpdb'] = new Playground_SQLite_Integration_Loader();
|
|
1247
|
-
|
|
1248
|
-
/**
|
|
1249
|
-
* WordPress is capable of using a preloaded global $wpdb. However, if
|
|
1250
|
-
* it cannot find the drop-in db.php plugin it still checks whether
|
|
1251
|
-
* the mysqli_connect() function exists even though it's not used.
|
|
1252
|
-
*
|
|
1253
|
-
* What WordPress demands, Playground shall provide.
|
|
1254
|
-
*/
|
|
1255
|
-
if(!function_exists('mysqli_connect')) {
|
|
1256
|
-
function mysqli_connect() {}
|
|
1257
|
-
}
|
|
1258
|
-
|
|
1259
|
-
`
|
|
1260
|
-
), await t.writeFile(
|
|
3527
|
+
je(c, u)
|
|
3528
|
+
), await e.writeFile(
|
|
1261
3529
|
"/internal/shared/mu-plugins/sqlite-test.php",
|
|
1262
3530
|
`<?php
|
|
1263
3531
|
global $wpdb;
|
|
@@ -1268,117 +3536,127 @@ if(!function_exists('mysqli_connect')) {
|
|
|
1268
3536
|
`
|
|
1269
3537
|
);
|
|
1270
3538
|
}
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
3539
|
+
function je(e, t) {
|
|
3540
|
+
return e + `<?php
|
|
3541
|
+
|
|
3542
|
+
${v(`require_once ${$(t)};`)}
|
|
3543
|
+
if(!function_exists('mysqli_connect')) {
|
|
3544
|
+
function mysqli_connect() {}
|
|
3545
|
+
}
|
|
3546
|
+
|
|
3547
|
+
`;
|
|
3548
|
+
}
|
|
3549
|
+
async function D(e, t) {
|
|
3550
|
+
e.mkdir("/tmp/unzipped-wordpress"), await m(e, t, "/tmp/unzipped-wordpress"), e.fileExists("/tmp/unzipped-wordpress/wordpress.zip") && await m(
|
|
3551
|
+
e,
|
|
1274
3552
|
"/tmp/unzipped-wordpress/wordpress.zip",
|
|
1275
3553
|
"/tmp/unzipped-wordpress"
|
|
1276
3554
|
);
|
|
1277
|
-
let
|
|
1278
|
-
if (!
|
|
1279
|
-
const
|
|
1280
|
-
if (
|
|
1281
|
-
const
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
) && (
|
|
3555
|
+
let i = e.fileExists("/tmp/unzipped-wordpress/wordpress") ? "/tmp/unzipped-wordpress/wordpress" : e.fileExists("/tmp/unzipped-wordpress/build") ? "/tmp/unzipped-wordpress/build" : "/tmp/unzipped-wordpress";
|
|
3556
|
+
if (!e.fileExists(_(i, "wp-config-sample.php"))) {
|
|
3557
|
+
const s = e.listFiles(i);
|
|
3558
|
+
if (s.length) {
|
|
3559
|
+
const r = s[0];
|
|
3560
|
+
e.fileExists(
|
|
3561
|
+
_(i, r, "wp-config-sample.php")
|
|
3562
|
+
) && (i = _(i, r));
|
|
1285
3563
|
}
|
|
1286
3564
|
}
|
|
1287
|
-
const
|
|
1288
|
-
if (
|
|
1289
|
-
for (const
|
|
1290
|
-
const
|
|
1291
|
-
|
|
3565
|
+
const n = (s, r, a) => {
|
|
3566
|
+
if (a.isDir(s) && a.isDir(r))
|
|
3567
|
+
for (const o of a.listFiles(s)) {
|
|
3568
|
+
const l = _(s, o), c = _(r, o);
|
|
3569
|
+
n(l, c, a);
|
|
1292
3570
|
}
|
|
1293
3571
|
else {
|
|
1294
|
-
if (
|
|
1295
|
-
const
|
|
3572
|
+
if (a.fileExists(r)) {
|
|
3573
|
+
const o = s.replace(
|
|
1296
3574
|
/^\/tmp\/unzipped-wordpress\//,
|
|
1297
3575
|
"/"
|
|
1298
3576
|
);
|
|
1299
|
-
|
|
1300
|
-
`Cannot unzip WordPress files at ${
|
|
3577
|
+
h.warn(
|
|
3578
|
+
`Cannot unzip WordPress files at ${r}: ${o} already exists.`
|
|
1301
3579
|
);
|
|
1302
3580
|
return;
|
|
1303
3581
|
}
|
|
1304
|
-
|
|
3582
|
+
a.mv(s, r);
|
|
1305
3583
|
}
|
|
1306
3584
|
};
|
|
1307
|
-
i
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
3585
|
+
n(i, e.documentRoot, e), e.fileExists(i) && e.rmdir(i, { recursive: !0 }), !e.fileExists(_(e.documentRoot, "wp-config.php")) && e.fileExists(_(e.documentRoot, "wp-config-sample.php")) && e.writeFile(
|
|
3586
|
+
_(e.documentRoot, "wp-config.php"),
|
|
3587
|
+
e.readFileAsText(
|
|
3588
|
+
_(e.documentRoot, "/wp-config-sample.php")
|
|
1311
3589
|
)
|
|
1312
3590
|
);
|
|
1313
3591
|
}
|
|
1314
|
-
const
|
|
1315
|
-
async function
|
|
1316
|
-
if (
|
|
1317
|
-
|
|
1318
|
-
else if (
|
|
1319
|
-
const
|
|
3592
|
+
const ze = M(fetch), Ze = "https://github.com/WordPress/WordPress/archive/refs/heads/master.zip";
|
|
3593
|
+
async function ot(e = "latest") {
|
|
3594
|
+
if (e === null)
|
|
3595
|
+
e = "latest";
|
|
3596
|
+
else if (e.startsWith("https://") || e.startsWith("http://")) {
|
|
3597
|
+
const n = await crypto.subtle.digest(
|
|
1320
3598
|
"SHA-1",
|
|
1321
|
-
new TextEncoder().encode(
|
|
1322
|
-
),
|
|
3599
|
+
new TextEncoder().encode(e)
|
|
3600
|
+
), s = Array.from(new Uint8Array(n)).map((r) => r.toString(16).padStart(2, "0")).join("");
|
|
1323
3601
|
return {
|
|
1324
|
-
releaseUrl:
|
|
1325
|
-
version: "custom-" +
|
|
3602
|
+
releaseUrl: e,
|
|
3603
|
+
version: "custom-" + s.substring(0, 8),
|
|
1326
3604
|
source: "inferred"
|
|
1327
3605
|
};
|
|
1328
|
-
} else if (
|
|
1329
|
-
const
|
|
3606
|
+
} else if (e === "trunk" || e === "nightly") {
|
|
3607
|
+
const n = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1330
3608
|
return {
|
|
1331
|
-
releaseUrl: `${
|
|
3609
|
+
releaseUrl: `${Ze}?ts=${n}`,
|
|
1332
3610
|
version: "trunk",
|
|
1333
3611
|
source: "inferred"
|
|
1334
3612
|
};
|
|
1335
3613
|
}
|
|
1336
|
-
let
|
|
3614
|
+
let i = await (await ze(
|
|
1337
3615
|
"https://api.wordpress.org/core/version-check/1.7/?channel=beta"
|
|
1338
3616
|
)).json();
|
|
1339
|
-
|
|
1340
|
-
(
|
|
3617
|
+
i = i.offers.filter(
|
|
3618
|
+
(n) => n.response === "autoupdate"
|
|
1341
3619
|
);
|
|
1342
|
-
for (const
|
|
1343
|
-
if (
|
|
3620
|
+
for (const n of i) {
|
|
3621
|
+
if (e === "beta" && (n.version.includes("beta") || n.version.includes("RC")))
|
|
1344
3622
|
return {
|
|
1345
|
-
releaseUrl:
|
|
1346
|
-
version:
|
|
3623
|
+
releaseUrl: n.download,
|
|
3624
|
+
version: n.version,
|
|
1347
3625
|
source: "api"
|
|
1348
3626
|
};
|
|
1349
|
-
if (
|
|
3627
|
+
if (e === "latest" && !n.version.includes("beta") && !n.version.includes("RC"))
|
|
1350
3628
|
return {
|
|
1351
|
-
releaseUrl:
|
|
1352
|
-
version:
|
|
3629
|
+
releaseUrl: n.download,
|
|
3630
|
+
version: n.version,
|
|
1353
3631
|
source: "api"
|
|
1354
3632
|
};
|
|
1355
|
-
if (
|
|
3633
|
+
if (n.version.substring(0, e.length) === e)
|
|
1356
3634
|
return {
|
|
1357
|
-
releaseUrl:
|
|
1358
|
-
version:
|
|
3635
|
+
releaseUrl: n.download,
|
|
3636
|
+
version: n.version,
|
|
1359
3637
|
source: "api"
|
|
1360
3638
|
};
|
|
1361
3639
|
}
|
|
1362
|
-
return
|
|
1363
|
-
releaseUrl: `https://wordpress.org/wordpress-${
|
|
1364
|
-
version:
|
|
3640
|
+
return e.match(/^\d+\.\d+\.0$/) && (e = e.split(".").slice(0, 2).join(".")), {
|
|
3641
|
+
releaseUrl: `https://wordpress.org/wordpress-${e}.zip`,
|
|
3642
|
+
version: e,
|
|
1365
3643
|
source: "inferred"
|
|
1366
3644
|
};
|
|
1367
3645
|
}
|
|
1368
3646
|
export {
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
3647
|
+
He as bootRequestHandler,
|
|
3648
|
+
Me as bootWordPress,
|
|
3649
|
+
rt as bootWordPressAndRequestHandler,
|
|
3650
|
+
st as defineWpConfigConstants,
|
|
3651
|
+
ve as ensureWpConfig,
|
|
3652
|
+
Be as getFileNotFoundActionForWordPress,
|
|
3653
|
+
at as getLoadedWordPressVersion,
|
|
3654
|
+
Qe as preloadPhpInfoRoute,
|
|
3655
|
+
I as preloadSqliteIntegration,
|
|
3656
|
+
ot as resolveWordPressRelease,
|
|
3657
|
+
Ke as setupPlatformLevelMuPlugins,
|
|
3658
|
+
D as unzipWordPress,
|
|
3659
|
+
Xe as versionStringToLoadedWordPressVersion,
|
|
3660
|
+
Ye as wordPressRewriteRules
|
|
1383
3661
|
};
|
|
1384
3662
|
//# sourceMappingURL=index.js.map
|