PageRenderTime 52ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-admin/setup-config.php

https://github.com/markjaquith/WordPress
PHP | 486 lines | 377 code | 43 blank | 66 comment | 43 complexity | ca52f6d857061a05dca224f710fc2ad1 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. /**
  3. * Retrieves and creates the wp-config.php file.
  4. *
  5. * The permissions for the base directory must allow for writing files in order
  6. * for the wp-config.php to be created using this page.
  7. *
  8. * @package WordPress
  9. * @subpackage Administration
  10. */
  11. /**
  12. * We are installing.
  13. */
  14. define( 'WP_INSTALLING', true );
  15. /**
  16. * We are blissfully unaware of anything.
  17. */
  18. define( 'WP_SETUP_CONFIG', true );
  19. /**
  20. * Disable error reporting
  21. *
  22. * Set this to error_reporting( -1 ) for debugging
  23. */
  24. error_reporting( 0 );
  25. if ( ! defined( 'ABSPATH' ) ) {
  26. define( 'ABSPATH', dirname( __DIR__ ) . '/' );
  27. }
  28. require ABSPATH . 'wp-settings.php';
  29. /** Load WordPress Administration Upgrade API */
  30. require_once ABSPATH . 'wp-admin/includes/upgrade.php';
  31. /** Load WordPress Translation Installation API */
  32. require_once ABSPATH . 'wp-admin/includes/translation-install.php';
  33. nocache_headers();
  34. // Support wp-config-sample.php one level up, for the develop repo.
  35. if ( file_exists( ABSPATH . 'wp-config-sample.php' ) ) {
  36. $config_file = file( ABSPATH . 'wp-config-sample.php' );
  37. } elseif ( file_exists( dirname( ABSPATH ) . '/wp-config-sample.php' ) ) {
  38. $config_file = file( dirname( ABSPATH ) . '/wp-config-sample.php' );
  39. } else {
  40. wp_die(
  41. sprintf(
  42. /* translators: %s: wp-config-sample.php */
  43. __( 'Sorry, I need a %s file to work from. Please re-upload this file to your WordPress installation.' ),
  44. '<code>wp-config-sample.php</code>'
  45. )
  46. );
  47. }
  48. // Check if wp-config.php has been created.
  49. if ( file_exists( ABSPATH . 'wp-config.php' ) ) {
  50. wp_die(
  51. '<p>' . sprintf(
  52. /* translators: 1: wp-config.php, 2: install.php */
  53. __( 'The file %1$s already exists. If you need to reset any of the configuration items in this file, please delete it first. You may try <a href="%2$s">installing now</a>.' ),
  54. '<code>wp-config.php</code>',
  55. 'install.php'
  56. ) . '</p>',
  57. 409
  58. );
  59. }
  60. // Check if wp-config.php exists above the root directory but is not part of another installation.
  61. if ( @file_exists( ABSPATH . '../wp-config.php' ) && ! @file_exists( ABSPATH . '../wp-settings.php' ) ) {
  62. wp_die(
  63. '<p>' . sprintf(
  64. /* translators: 1: wp-config.php, 2: install.php */
  65. __( 'The file %1$s already exists one level above your WordPress installation. If you need to reset any of the configuration items in this file, please delete it first. You may try <a href="%2$s">installing now</a>.' ),
  66. '<code>wp-config.php</code>',
  67. 'install.php'
  68. ) . '</p>',
  69. 409
  70. );
  71. }
  72. $step = isset( $_GET['step'] ) ? (int) $_GET['step'] : -1;
  73. /**
  74. * Display setup wp-config.php file header.
  75. *
  76. * @ignore
  77. * @since 2.3.0
  78. *
  79. * @param string|string[] $body_classes Class attribute values for the body tag.
  80. */
  81. function setup_config_display_header( $body_classes = array() ) {
  82. $body_classes = (array) $body_classes;
  83. $body_classes[] = 'wp-core-ui';
  84. $dir_attr = '';
  85. if ( is_rtl() ) {
  86. $body_classes[] = 'rtl';
  87. $dir_attr = ' dir="rtl"';
  88. }
  89. header( 'Content-Type: text/html; charset=utf-8' );
  90. ?>
  91. <!DOCTYPE html>
  92. <html<?php echo $dir_attr; ?>>
  93. <head>
  94. <meta name="viewport" content="width=device-width" />
  95. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  96. <meta name="robots" content="noindex,nofollow" />
  97. <title><?php _e( 'WordPress &rsaquo; Setup Configuration File' ); ?></title>
  98. <?php wp_admin_css( 'install', true ); ?>
  99. </head>
  100. <body class="<?php echo implode( ' ', $body_classes ); ?>">
  101. <p id="logo"><?php _e( 'WordPress' ); ?></p>
  102. <?php
  103. } // End function setup_config_display_header();
  104. $language = '';
  105. if ( ! empty( $_REQUEST['language'] ) ) {
  106. $language = preg_replace( '/[^a-zA-Z0-9_]/', '', $_REQUEST['language'] );
  107. } elseif ( isset( $GLOBALS['wp_local_package'] ) ) {
  108. $language = $GLOBALS['wp_local_package'];
  109. }
  110. switch ( $step ) {
  111. case -1:
  112. if ( wp_can_install_language_pack() && empty( $language ) ) {
  113. $languages = wp_get_available_translations();
  114. if ( $languages ) {
  115. setup_config_display_header( 'language-chooser' );
  116. echo '<h1 class="screen-reader-text">Select a default language</h1>';
  117. echo '<form id="setup" method="post" action="?step=0">';
  118. wp_install_language_form( $languages );
  119. echo '</form>';
  120. break;
  121. }
  122. }
  123. // Deliberately fall through if we can't reach the translations API.
  124. case 0:
  125. if ( ! empty( $language ) ) {
  126. $loaded_language = wp_download_language_pack( $language );
  127. if ( $loaded_language ) {
  128. load_default_textdomain( $loaded_language );
  129. $GLOBALS['wp_locale'] = new WP_Locale();
  130. }
  131. }
  132. setup_config_display_header();
  133. $step_1 = 'setup-config.php?step=1';
  134. if ( isset( $_REQUEST['noapi'] ) ) {
  135. $step_1 .= '&amp;noapi';
  136. }
  137. if ( ! empty( $loaded_language ) ) {
  138. $step_1 .= '&amp;language=' . $loaded_language;
  139. }
  140. ?>
  141. <h1 class="screen-reader-text"><?php _e( 'Before getting started' ); ?></h1>
  142. <p><?php _e( 'Welcome to WordPress. Before getting started, we need some information on the database. You will need to know the following items before proceeding.' ); ?></p>
  143. <ol>
  144. <li><?php _e( 'Database name' ); ?></li>
  145. <li><?php _e( 'Database username' ); ?></li>
  146. <li><?php _e( 'Database password' ); ?></li>
  147. <li><?php _e( 'Database host' ); ?></li>
  148. <li><?php _e( 'Table prefix (if you want to run more than one WordPress in a single database)' ); ?></li>
  149. </ol>
  150. <p>
  151. <?php
  152. printf(
  153. /* translators: %s: wp-config.php */
  154. __( 'We&#8217;re going to use this information to create a %s file.' ),
  155. '<code>wp-config.php</code>'
  156. );
  157. ?>
  158. <strong>
  159. <?php
  160. printf(
  161. /* translators: 1: wp-config-sample.php, 2: wp-config.php */
  162. __( 'If for any reason this automatic file creation doesn&#8217;t work, don&#8217;t worry. All this does is fill in the database information to a configuration file. You may also simply open %1$s in a text editor, fill in your information, and save it as %2$s.' ),
  163. '<code>wp-config-sample.php</code>',
  164. '<code>wp-config.php</code>'
  165. );
  166. ?>
  167. </strong>
  168. <?php
  169. printf(
  170. /* translators: %s: Documentation URL. */
  171. __( 'Need more help? <a href="%s">We got it</a>.' ),
  172. __( 'https://wordpress.org/support/article/editing-wp-config-php/' )
  173. );
  174. ?>
  175. </p>
  176. <p><?php _e( 'In all likelihood, these items were supplied to you by your web host. If you don&#8217;t have this information, then you will need to contact them before you can continue. If you&#8217;re all ready&hellip;' ); ?></p>
  177. <p class="step"><a href="<?php echo $step_1; ?>" class="button button-large"><?php _e( 'Let&#8217;s go!' ); ?></a></p>
  178. <?php
  179. break;
  180. case 1:
  181. load_default_textdomain( $language );
  182. $GLOBALS['wp_locale'] = new WP_Locale();
  183. setup_config_display_header();
  184. $autofocus = wp_is_mobile() ? '' : ' autofocus';
  185. ?>
  186. <h1 class="screen-reader-text"><?php _e( 'Set up your database connection' ); ?></h1>
  187. <form method="post" action="setup-config.php?step=2">
  188. <p><?php _e( 'Below you should enter your database connection details. If you&#8217;re not sure about these, contact your host.' ); ?></p>
  189. <table class="form-table" role="presentation">
  190. <tr>
  191. <th scope="row"><label for="dbname"><?php _e( 'Database Name' ); ?></label></th>
  192. <td><input name="dbname" id="dbname" type="text" aria-describedby="dbname-desc" size="25" value="wordpress"<?php echo $autofocus; ?>/></td>
  193. <td id="dbname-desc"><?php _e( 'The name of the database you want to use with WordPress.' ); ?></td>
  194. </tr>
  195. <tr>
  196. <th scope="row"><label for="uname"><?php _e( 'Username' ); ?></label></th>
  197. <td><input name="uname" id="uname" type="text" aria-describedby="uname-desc" size="25" value="<?php echo htmlspecialchars( _x( 'username', 'example username' ), ENT_QUOTES ); ?>" /></td>
  198. <td id="uname-desc"><?php _e( 'Your database username.' ); ?></td>
  199. </tr>
  200. <tr>
  201. <th scope="row"><label for="pwd"><?php _e( 'Password' ); ?></label></th>
  202. <td><input name="pwd" id="pwd" type="text" aria-describedby="pwd-desc" size="25" value="<?php echo htmlspecialchars( _x( 'password', 'example password' ), ENT_QUOTES ); ?>" autocomplete="off" /></td>
  203. <td id="pwd-desc"><?php _e( 'Your database password.' ); ?></td>
  204. </tr>
  205. <tr>
  206. <th scope="row"><label for="dbhost"><?php _e( 'Database Host' ); ?></label></th>
  207. <td><input name="dbhost" id="dbhost" type="text" aria-describedby="dbhost-desc" size="25" value="localhost" /></td>
  208. <td id="dbhost-desc">
  209. <?php
  210. /* translators: %s: localhost */
  211. printf( __( 'You should be able to get this info from your web host, if %s doesn&#8217;t work.' ), '<code>localhost</code>' );
  212. ?>
  213. </td>
  214. </tr>
  215. <tr>
  216. <th scope="row"><label for="prefix"><?php _e( 'Table Prefix' ); ?></label></th>
  217. <td><input name="prefix" id="prefix" type="text" aria-describedby="prefix-desc" value="wp_" size="25" /></td>
  218. <td id="prefix-desc"><?php _e( 'If you want to run multiple WordPress installations in a single database, change this.' ); ?></td>
  219. </tr>
  220. </table>
  221. <?php
  222. if ( isset( $_GET['noapi'] ) ) {
  223. ?>
  224. <input name="noapi" type="hidden" value="1" /><?php } ?>
  225. <input type="hidden" name="language" value="<?php echo esc_attr( $language ); ?>" />
  226. <p class="step"><input name="submit" type="submit" value="<?php echo htmlspecialchars( __( 'Submit' ), ENT_QUOTES ); ?>" class="button button-large" /></p>
  227. </form>
  228. <?php
  229. break;
  230. case 2:
  231. load_default_textdomain( $language );
  232. $GLOBALS['wp_locale'] = new WP_Locale();
  233. $dbname = trim( wp_unslash( $_POST['dbname'] ) );
  234. $uname = trim( wp_unslash( $_POST['uname'] ) );
  235. $pwd = trim( wp_unslash( $_POST['pwd'] ) );
  236. $dbhost = trim( wp_unslash( $_POST['dbhost'] ) );
  237. $prefix = trim( wp_unslash( $_POST['prefix'] ) );
  238. $step_1 = 'setup-config.php?step=1';
  239. $install = 'install.php';
  240. if ( isset( $_REQUEST['noapi'] ) ) {
  241. $step_1 .= '&amp;noapi';
  242. }
  243. if ( ! empty( $language ) ) {
  244. $step_1 .= '&amp;language=' . $language;
  245. $install .= '?language=' . $language;
  246. } else {
  247. $install .= '?language=en_US';
  248. }
  249. $tryagain_link = '</p><p class="step"><a href="' . $step_1 . '" onclick="javascript:history.go(-1);return false;" class="button button-large">' . __( 'Try Again' ) . '</a>';
  250. if ( empty( $prefix ) ) {
  251. wp_die( __( '<strong>Error</strong>: "Table Prefix" must not be empty.' ) . $tryagain_link );
  252. }
  253. // Validate $prefix: it can only contain letters, numbers and underscores.
  254. if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) {
  255. wp_die( __( '<strong>Error</strong>: "Table Prefix" can only contain numbers, letters, and underscores.' ) . $tryagain_link );
  256. }
  257. // Test the DB connection.
  258. /**#@+
  259. *
  260. * @ignore
  261. */
  262. define( 'DB_NAME', $dbname );
  263. define( 'DB_USER', $uname );
  264. define( 'DB_PASSWORD', $pwd );
  265. define( 'DB_HOST', $dbhost );
  266. /**#@-*/
  267. // Re-construct $wpdb with these new values.
  268. unset( $wpdb );
  269. require_wp_db();
  270. /*
  271. * The wpdb constructor bails when WP_SETUP_CONFIG is set, so we must
  272. * fire this manually. We'll fail here if the values are no good.
  273. */
  274. $wpdb->db_connect();
  275. if ( ! empty( $wpdb->error ) ) {
  276. wp_die( $wpdb->error->get_error_message() . $tryagain_link );
  277. }
  278. $errors = $wpdb->hide_errors();
  279. $wpdb->query( "SELECT $prefix" );
  280. $wpdb->show_errors( $errors );
  281. if ( ! $wpdb->last_error ) {
  282. // MySQL was able to parse the prefix as a value, which we don't want. Bail.
  283. wp_die( __( '<strong>Error</strong>: "Table Prefix" is invalid.' ) );
  284. }
  285. // Generate keys and salts using secure CSPRNG; fallback to API if enabled; further fallback to original wp_generate_password().
  286. try {
  287. $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()-_ []{}<>~`+=,.;:/?|';
  288. $max = strlen( $chars ) - 1;
  289. for ( $i = 0; $i < 8; $i++ ) {
  290. $key = '';
  291. for ( $j = 0; $j < 64; $j++ ) {
  292. $key .= substr( $chars, random_int( 0, $max ), 1 );
  293. }
  294. $secret_keys[] = $key;
  295. }
  296. } catch ( Exception $ex ) {
  297. $no_api = isset( $_POST['noapi'] );
  298. if ( ! $no_api ) {
  299. $secret_keys = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' );
  300. }
  301. if ( $no_api || is_wp_error( $secret_keys ) ) {
  302. $secret_keys = array();
  303. for ( $i = 0; $i < 8; $i++ ) {
  304. $secret_keys[] = wp_generate_password( 64, true, true );
  305. }
  306. } else {
  307. $secret_keys = explode( "\n", wp_remote_retrieve_body( $secret_keys ) );
  308. foreach ( $secret_keys as $k => $v ) {
  309. $secret_keys[ $k ] = substr( $v, 28, 64 );
  310. }
  311. }
  312. }
  313. $key = 0;
  314. foreach ( $config_file as $line_num => $line ) {
  315. if ( '$table_prefix =' === substr( $line, 0, 15 ) ) {
  316. $config_file[ $line_num ] = '$table_prefix = \'' . addcslashes( $prefix, "\\'" ) . "';\r\n";
  317. continue;
  318. }
  319. if ( ! preg_match( '/^define\(\s*\'([A-Z_]+)\',([ ]+)/', $line, $match ) ) {
  320. continue;
  321. }
  322. $constant = $match[1];
  323. $padding = $match[2];
  324. switch ( $constant ) {
  325. case 'DB_NAME':
  326. case 'DB_USER':
  327. case 'DB_PASSWORD':
  328. case 'DB_HOST':
  329. $config_file[ $line_num ] = "define( '" . $constant . "'," . $padding . "'" . addcslashes( constant( $constant ), "\\'" ) . "' );\r\n";
  330. break;
  331. case 'DB_CHARSET':
  332. if ( 'utf8mb4' === $wpdb->charset || ( ! $wpdb->charset && $wpdb->has_cap( 'utf8mb4' ) ) ) {
  333. $config_file[ $line_num ] = "define( '" . $constant . "'," . $padding . "'utf8mb4' );\r\n";
  334. }
  335. break;
  336. case 'AUTH_KEY':
  337. case 'SECURE_AUTH_KEY':
  338. case 'LOGGED_IN_KEY':
  339. case 'NONCE_KEY':
  340. case 'AUTH_SALT':
  341. case 'SECURE_AUTH_SALT':
  342. case 'LOGGED_IN_SALT':
  343. case 'NONCE_SALT':
  344. $config_file[ $line_num ] = "define( '" . $constant . "'," . $padding . "'" . $secret_keys[ $key++ ] . "' );\r\n";
  345. break;
  346. }
  347. }
  348. unset( $line );
  349. if ( ! is_writable( ABSPATH ) ) :
  350. setup_config_display_header();
  351. ?>
  352. <p>
  353. <?php
  354. /* translators: %s: wp-config.php */
  355. printf( __( 'Unable to write to %s file.' ), '<code>wp-config.php</code>' );
  356. ?>
  357. </p>
  358. <p>
  359. <?php
  360. /* translators: %s: wp-config.php */
  361. printf( __( 'You can create the %s file manually and paste the following text into it.' ), '<code>wp-config.php</code>' );
  362. $config_text = '';
  363. foreach ( $config_file as $line ) {
  364. $config_text .= htmlentities( $line, ENT_COMPAT, 'UTF-8' );
  365. }
  366. ?>
  367. </p>
  368. <textarea id="wp-config" cols="98" rows="15" class="code" readonly="readonly"><?php echo $config_text; ?></textarea>
  369. <p><?php _e( 'After you&#8217;ve done that, click &#8220;Run the installation&#8221;.' ); ?></p>
  370. <p class="step"><a href="<?php echo $install; ?>" class="button button-large"><?php _e( 'Run the installation' ); ?></a></p>
  371. <script>
  372. (function(){
  373. if ( ! /iPad|iPod|iPhone/.test( navigator.userAgent ) ) {
  374. var el = document.getElementById('wp-config');
  375. el.focus();
  376. el.select();
  377. }
  378. })();
  379. </script>
  380. <?php
  381. else :
  382. /*
  383. * If this file doesn't exist, then we are using the wp-config-sample.php
  384. * file one level up, which is for the develop repo.
  385. */
  386. if ( file_exists( ABSPATH . 'wp-config-sample.php' ) ) {
  387. $path_to_wp_config = ABSPATH . 'wp-config.php';
  388. } else {
  389. $path_to_wp_config = dirname( ABSPATH ) . '/wp-config.php';
  390. }
  391. $error_message = '';
  392. $handle = fopen( $path_to_wp_config, 'w' );
  393. /*
  394. * Why check for the absence of false instead of checking for resource with is_resource()?
  395. * To future-proof the check for when fopen returns object instead of resource, i.e. a known
  396. * change coming in PHP.
  397. */
  398. if ( false !== $handle ) {
  399. foreach ( $config_file as $line ) {
  400. fwrite( $handle, $line );
  401. }
  402. fclose( $handle );
  403. } else {
  404. $wp_config_perms = fileperms( $path_to_wp_config );
  405. if ( ! empty( $wp_config_perms ) && ! is_writable( $path_to_wp_config ) ) {
  406. $error_message = sprintf(
  407. /* translators: 1: wp-config.php, 2: Documentation URL. */
  408. __( 'You need to make the file %1$s writable before you can save your changes. See <a href="%2$s">Changing File Permissions</a> for more information.' ),
  409. '<code>wp-config.php</code>',
  410. __( 'https://wordpress.org/support/article/changing-file-permissions/' )
  411. );
  412. } else {
  413. $error_message = sprintf(
  414. /* translators: %s: wp-config.php */
  415. __( 'Unable to write to %s file.' ),
  416. '<code>wp-config.php</code>'
  417. );
  418. }
  419. }
  420. chmod( $path_to_wp_config, 0666 );
  421. setup_config_display_header();
  422. if ( false !== $handle ) :
  423. ?>
  424. <h1 class="screen-reader-text"><?php _e( 'Successful database connection' ); ?></h1>
  425. <p><?php _e( 'All right, sparky! You&#8217;ve made it through this part of the installation. WordPress can now communicate with your database. If you are ready, time now to&hellip;' ); ?></p>
  426. <p class="step"><a href="<?php echo $install; ?>" class="button button-large"><?php _e( 'Run the installation' ); ?></a></p>
  427. <?php
  428. else :
  429. printf( '<p>%s</p>', $error_message );
  430. endif;
  431. endif;
  432. break;
  433. } // End of the steps switch.
  434. ?>
  435. <?php wp_print_scripts( 'language-chooser' ); ?>
  436. </body>
  437. </html>