wp-load.phpで、WordPressが未インストール状態の場合(wp-config.phpがない状態)に、wp-config.phpを生成するためのボタンをクリックすると、動くのが、wp-admin/setup-config.phpです。
僕としての注目ポイントは、サーバに無いファイルを作るための方法がこの中に書かれているのが興味深いです。
index.phpからここまでの流れ
- https://nskw-style.com/にアクセスがある。
- そこにindex.php/があり、wp-blog-header.phpを呼びこむ。
- wp-blog-header.phpは、wp-load.phpを呼びこむ。
- wp-load.phpは、wp-config.phpを呼びこむ。ただし、ない場合には、setup-config.phpへご案内して、wp-config.phpを作る。
- (wp-config.phpは、wp-setting.phpを呼び込みます。)
今、4番目のconfig.phpを作るところです。
config.phpは、データベースとの接続のための情報などが書かれているものです。
実際の処理としては、wp-config.phpを作り、DBのユーザ名、パスワード名などを書き込み、ファイル名をに書き換える、ということをやっていますが、その前に色々条件を整えたりチェックしたりしています。。
あと、$_POSTを使ってこのファイル内でいくつかの段階の処理をしているのもポイントです。
コード
長いので、少しずつ。
冒頭のコメントと土台の整え
/** * Retrieves and creates the wp-config.php file. * * The permissions for the base directory must allow for writing files in order * for the wp-config.php to be created using this page. */ /** * We are installing. */ define('WP_INSTALLING', true); /** * We are blissfully unaware of anything. */ define('WP_SETUP_CONFIG', true); /** * Disable error reporting * Set this to error_reporting( E_ALL ) or error_reporting( E_ALL | E_STRICT ) for debugging */ error_reporting(0);
コメント
wp-config.phpを作ったり、復元(回復)したりします。
書き込み権限必要です。
- インストールしてます宣言、セットアップしてます宣言
- 色々PHPエラーは起こるけど、いちいち教えてくれなくていいです。
色々呼び込んでます。
これらがないとインストール出来ないということでしょう。
/**#@+ * These three defines are required to allow us to use require_wp_db() to load * the database class while being wp-content/db.php aware. * @ignore */ define('ABSPATH', dirname(dirname(__FILE__)).'/'); define('WPINC', 'wp-includes'); define('WP_CONTENT_DIR', ABSPATH . 'wp-content'); define('WP_DEBUG', false); /**#@-*/ require_once(ABSPATH . WPINC . '/load.php'); require_once(ABSPATH . WPINC . '/compat.php'); require_once(ABSPATH . WPINC . '/functions.php'); require_once(ABSPATH . WPINC . '/classes.php'); require_once(ABSPATH . WPINC . '/version.php');
色々チェックする
if (!file_exists(ABSPATH . 'wp-config-sample.php')) wp_die('wp-config-sample.php が見つかりません。WordPress インストールファイルから再アップロードしてください。'); $configFile = file(ABSPATH . 'wp-config-sample.php'); // Check if wp-config.php has been created if (file_exists(ABSPATH . 'wp-config.php')) wp_die("<p>ファイル 'wp-config.php' は既に作成済みです。このファイル内の設定項目をリセットする必要があるのなら、まずこのファイルを削除してください。その後で <a href='install.php'>インストールを実行してください</a>。</p>"); // Check if wp-config.php exists above the root directory but is not part of another install if (file_exists(ABSPATH . '../wp-config.php') && ! file_exists(ABSPATH . '../wp-settings.php')) wp_die("<p>WordPress をインストールしたひとつ上のディレクトリにファイル 'wp-config.php' が既に存在しています。このファイル内の設定項目をリセットする必要があるのなら、まずこのファイルを削除してください。その後で <a href='install.php'>インストールを実行してください</a>。</p>"); if ( version_compare( $required_php_version, phpversion(), '>' ) ) wp_die( sprintf( /*WP_I18N_OLD_PHP*/'サーバーの PHP のバージョンは %1$s です。WordPress は %2$s 以上でご利用になれます。'/*/WP_I18N_OLD_PHP*/, phpversion(), $required_php_version ) ); if ( !extension_loaded('mysql') && !file_exists(ABSPATH . 'wp-content/db.php') ) wp_die( /*WP_I18N_OLD_MYSQL*/'お使いのサーバーの PHP では WordPress に必要な MySQL 拡張を利用できないようです。'/*/WP_I18N_OLD_MYSQL*/ );
上から順に、
- wp-config-sample.phpがないとだめです
- $configFileにwp-config-sample.phpの存在そのものを代入
- 既にconfig.phpがある場合、削除を促す
- 一個上の階層に既にconfig.phpがある場合、削除を促す
- PHPのバージョンが足りない場合、お知らせ
- MySQLを拡張できないサーバなら、お知らせ
$_GETの配列をチェック
if (isset($_GET['step'])) $step = $_GET['step']; else $step = 0;
$_GETに何か入っていれば、$stepに代入。
何もなければ、$stepに0を代入。
display_header()とう関数を定義する
/** * Display setup wp-config.php file header. */ function display_header() { header( 'Content-Type: text/html; charset=utf-8' ); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>WordPress › セットアップ設定ファイル</title> <link rel="stylesheet" href="css/install.css" type="text/css" /> </head> <body> <h1 id="logo"><img alt="WordPress" src="images/wordpress-logo.png" /></h1> <?php }//end function display_header();
以後、display_header()とこのファイル内で書いたときには、直下に書いておいたHTMLソースが出力される。
switch文で分岐する
switch($step) { case 0: display_header(); ?>
ここから、$stepの値が、0なのか1,2,3とかなのかによって処理を分岐させる。
$step = 0の場合
switch($step) { case 0: display_header(); ?> <p>WordPress へようこそ。あらかじめデータベースに関する若干の情報を用意してください。作業を進める前に以下のデータベース情報を知っている必要があります。</p> <ol> <li>データベース名</li> <li>データベースのユーザー名</li> <li>データベースのパスワード</li> <li>データベースのホスト名</li> <li>テーブル接頭辞 (1つのデータベースに複数の WordPress を構築する場合)</li> </ol> <p><strong>もし何かが原因で自動ファイル生成が動作しなくても心配しないでください。この機能は設定ファイルにデータベース情報を記入するだけです。テキストエディタで <code>wp-config-sample.php</code> を開き、データベース接続の詳細を記入してこのファイルの名前を <code>wp-config.php</code> として保存してもかまいません。</strong></p> <p>これらのデータベース情報はホスティング先から提供されます。データベース情報がわからない場合、作業を続行する前にホスティング先と連絡を取ってください。すべての準備が整っているなら…</p> <p class="step"><a href="setup-config.php?step=1<?php if ( isset( $_GET['noapi'] ) ) echo '&noapi'; ?>" class="button">次に進みましょう !</a></p> <?php break;
ヘッダー部分を出して、htmlを出して、
<a href="setup-config.php?step=1<?php if ( isset( $_GET['noapi'] ) ) echo '&noapi'; ?>" class="button">次に進みましょう !</a>
で、 $_GET[]に1を入れて、$step=1になるようにする。
ここでは、DB情報整えておいてね、とユーザに伝える。
$step = 1の場合
case 1: display_header(); ?> <form method="post" action="setup-config.php?step=2"> <p>以下にデータベース接続のための詳細を入力してください。これらのデータについて分からない点があれば、ホストに連絡を取ってください。</p> <table class="form-table"> <tr> <th scope="row"><label for="dbname">データベース名</label></th> <td><input name="dbname" id="dbname" type="text" size="25" value="wordpress" /></td> <td>WP を稼動させたいデータベースの名前。</td> </tr> <tr> <th scope="row"><label for="uname">ユーザー名</label></th> <td><input name="uname" id="uname" type="text" size="25" value="username" /></td> <td>MySQL のユーザー名</td> </tr> <tr> <th scope="row"><label for="pwd">パスワード</label></th> <td><input name="pwd" id="pwd" type="text" size="25" value="password" /></td> <td>MySQL のパスワード</td> </tr> <tr> <th scope="row"><label for="dbhost">データベースのホスト名</label></th> <td><input name="dbhost" id="dbhost" type="text" size="25" value="localhost" /></td> <td><code>localhost</code> のままで動かない場合、ウェブホストからこの情報を得る必要があります。</td> </tr> <tr> <th scope="row"><label for="prefix">テーブル接頭辞</label></th> <td><input name="prefix" id="prefix" type="text" id="prefix" value="wp_" size="25" /></td> <td>1つのデータベースで複数の WordPress を動かすときに変更します。</td> </tr> </table> <?php if ( isset( $_GET['noapi'] ) ) { ?><input name="noapi" type="hidden" value="true" /><?php } ?> <p class="step"><input name="submit" type="submit" value="作成する" class="button" /></p> </form> <?php break;
フォームのactionに、setup-config.php?step=2を入れているので、次にsetup-config.phpが読み込まれるときには、$step=2になる。
$step = 2の場合
case 2: $dbname = trim($_POST['dbname']); $uname = trim($_POST['uname']); $passwrd = trim($_POST['pwd']); $dbhost = trim($_POST['dbhost']); $prefix = trim($_POST['prefix']); if ( empty($prefix) ) $prefix = 'wp_'; // Validate $prefix: it can only contain letters, numbers and underscores if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) wp_die( /*WP_I18N_BAD_PREFIX*/'<strong>エラー</strong>: "Table_Prefix" には半角英数字と下線のみしか使えません。'/*/WP_I18N_BAD_PREFIX*/ ); // Test the db connection. /**#@+ * @ignore */ define('DB_NAME', $dbname); define('DB_USER', $uname); define('DB_PASSWORD', $passwrd); define('DB_HOST', $dbhost); /**#@-*/ // We'll fail here if the values are no good. require_wp_db(); if ( !empty($wpdb->error) ) wp_die($wpdb->error->get_error_message()); // Fetch or generate keys and salts. $no_api = isset( $_POST['noapi'] ); require_once( ABSPATH . WPINC . '/plugin.php' ); require_once( ABSPATH . WPINC . '/l10n.php' ); require_once( ABSPATH . WPINC . '/pomo/translations.php' ); if ( ! $no_api ) { require_once( ABSPATH . WPINC . '/class-http.php' ); require_once( ABSPATH . WPINC . '/http.php' ); wp_fix_server_vars(); /**#@+ * @ignore */ function get_bloginfo() { return ( ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . str_replace( $_SERVER['PHP_SELF'], '/wp-admin/setup-config.php', '' ) ); } /**#@-*/ $secret_keys = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' ); } if ( $no_api || is_wp_error( $secret_keys ) ) { $secret_keys = array(); require_once( ABSPATH . WPINC . '/pluggable.php' ); for ( $i = 0; $i < 8; $i++ ) { $secret_keys[] = wp_generate_password( 64, true, true ); } } else { $secret_keys = explode( "\n", wp_remote_retrieve_body( $secret_keys ) ); foreach ( $secret_keys as $k => $v ) { $secret_keys[$k] = substr( $v, 28, 64 ); } } $key = 0; foreach ($configFile as $line_num => $line) { switch (substr($line,0,16)) { case "define('DB_NAME'": $configFile[$line_num] = str_replace("database_name_here", $dbname, $line); break; case "define('DB_USER'": $configFile[$line_num] = str_replace("'username_here'", "'$uname'", $line); break; case "define('DB_PASSW": $configFile[$line_num] = str_replace("'password_here'", "'$passwrd'", $line); break; case "define('DB_HOST'": $configFile[$line_num] = str_replace("localhost", $dbhost, $line); break; case '$table_prefix =': $configFile[$line_num] = str_replace('wp_', $prefix, $line); break; case "define('AUTH_KEY": case "define('SECURE_A": case "define('LOGGED_I": case "define('NONCE_KE": case "define('AUTH_SAL": case "define('SECURE_A": case "define('LOGGED_I": case "define('NONCE_SA": $configFile[$line_num] = str_replace('put your unique phrase here', $secret_keys[$key++], $line ); break; } } if ( ! is_writable(ABSPATH) ) : display_header(); ?> <p><code>wp-config.php</code> ファイルへの書き込みができません。</p> <p><code>wp-config.php</code> を手動で作成して、次のテキストをそこに貼り付けてください。</p> <textarea cols="98" rows="15" class="code"><?php foreach( $configFile as $line ) { echo htmlentities($line, ENT_COMPAT, 'UTF-8'); } ?></textarea> <p>それが済んだら、「インストール実行」をクリックしてください。</p> <p class="step"><a href="install.php" class="button">インストール実行</a></p> <?php else : $handle = fopen(ABSPATH . 'wp-config.php', 'w'); foreach( $configFile as $line ) { fwrite($handle, $line); } fclose($handle); chmod(ABSPATH . 'wp-config.php', 0666); display_header(); ?> <p>この部分のインストールは無事完了しました。WordPress は現在データベースと通信できる状態にあります。準備ができているなら…</p> <p class="step"><a href="install.php" class="button">インストール実行</a></p> <?php endif; break;
長い。。。。以下、$step = 2のcasブツ切りにしつつ。
$_POSTを受け取る
$dbname = trim($_POST['dbname']); $uname = trim($_POST['uname']); $passwrd = trim($_POST['pwd']); $dbhost = trim($_POST['dbhost']); $prefix = trim($_POST['prefix']); if ( empty($prefix) ) $prefix = 'wp_'; // Validate $prefix: it can only contain letters, numbers and underscores if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) wp_die( /*WP_I18N_BAD_PREFIX*/'<strong>エラー</strong>: "Table_Prefix" には半角英数字と下線のみしか使えません。'/*/WP_I18N_BAD_PREFIX*/ );
trim()
は、文字列の両端にあるスペースを削除する。
接頭辞が設定されてない場合は、wp_にする。で、半角英数字と下線以外がないかどうかをチェック。
設定した情報でDBにアクセス出来ているかをチェック
// Test the db connection. /**#@+ * @ignore */ define('DB_NAME', $dbname); define('DB_USER', $uname); define('DB_PASSWORD', $passwrd); define('DB_HOST', $dbhost); /**#@-*/ // We'll fail here if the values are no good. require_wp_db(); if ( !empty($wpdb->error) ) wp_die($wpdb->error->get_error_message());
まず、DB関連の定数の定義。
次に、エラーがないかどうかを確かめる。もしあれば、メッセージを出して停止。
require_wp_db();
は、
function require_wp_db() { global $wpdb; if ( file_exists( WP_CONTENT_DIR . '/db.php' ) ) require_once( WP_CONTENT_DIR . '/db.php' ); else require_once( ABSPATH . WPINC . '/wp-db.php' ); }
という定義。db.phpはデフォルトでは存在しないファイルなので(カスタマイズに使う)、wp-db.phpが読み込まれる。データベースに接続するときに使う関数やクラスが定義されている。
アクセス出来ていたら
// Fetch or generate keys and salts. $no_api = isset( $_POST['noapi'] ); require_once( ABSPATH . WPINC . '/plugin.php' ); require_once( ABSPATH . WPINC . '/l10n.php' ); require_once( ABSPATH . WPINC . '/pomo/translations.php' );
$no_api に、ポストにnoapiが入っているかどうかの真偽値を代入。
プラグイン、文字コードの何か、翻訳ファイルを読み込み。
これで準備ができたので、認証キーの取得と適用に移ります。
$no_apiがfalseの場合→認証キーを取得
if ( ! $no_api ) { require_once( ABSPATH . WPINC . '/class-http.php' ); require_once( ABSPATH . WPINC . '/http.php' ); wp_fix_server_vars(); function get_bloginfo() { return ( ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . str_replace( $_SERVER['PHP_SELF'], '/wp-admin/setup-config.php', '' ) ); } $secret_keys = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' ); }
まず、class-http.phpなどでサーバまわりを整えて、get_bloginfo()を定義しておく。
最後に、認証キーを取得しに行く。
wp_remote_get(’url’)は、指定のURLの内容の取得。
認証キーを配列に格納する
if ( $no_api || is_wp_error( $secret_keys ) ) { $secret_keys = array(); require_once( ABSPATH . WPINC . '/pluggable.php' ); for ( $i = 0; $i < 8; $i++ ) { $secret_keys[] = wp_generate_password( 64, true, true ); } } else { $secret_keys = explode( "\n", wp_remote_retrieve_body( $secret_keys ) ); foreach ( $secret_keys as $k => $v ) { $secret_keys[$k] = substr( $v, 28, 64 ); } } $key = 0;
前半:$no_apiがtrueなのに、認証キーの取得がエラーの時→自分たちで作る
pluggable.phpで定義されているwp_generate_password()関数で認証キーを作る。
8個作って、$secret_keys[]配列に格納。
後半:取得が出来ていた
https://api.wordpress.org/secret-key/1.1/salt/で取得した内容を、\n改行で分割して、$secret_keys[]配列に格納。
関数explode(a,b)は、aでbを分割する。
関数substr(文字列、スタート位置、長さ)は文字列をスタート位置から長さ分を返す。今回の場合、(28+1)文字目以降の64文字を変数$vに代入して、配列$secret_keys[]に格納する。
最後のこの後すぐに使うので、$key = 0をしておく。
DB情報や認証キーを連想配列に格納
foreach ($configFile as $line_num => $line) { switch (substr($line,0,16)) { case "define('DB_NAME'": $configFile[$line_num] = str_replace("database_name_here", $dbname, $line); break; case "define('DB_USER'": $configFile[$line_num] = str_replace("'username_here'", "'$uname'", $line); break; case "define('DB_PASSW": $configFile[$line_num] = str_replace("'password_here'", "'$passwrd'", $line); break; case "define('DB_HOST'": $configFile[$line_num] = str_replace("localhost", $dbhost, $line); break; case '$table_prefix =': $configFile[$line_num] = str_replace('wp_', $prefix, $line); break; case "define('AUTH_KEY": case "define('SECURE_A": case "define('LOGGED_I": case "define('NONCE_KE": case "define('AUTH_SAL": case "define('SECURE_A": case "define('LOGGED_I": case "define('NONCE_SA": $configFile[$line_num] = str_replace('put your unique phrase here', $secret_keys[$key++], $line ); break; } }
これまでにユーザに入力させたDB情報や認証キーを、$configFile[]という連想配列に格納していく。
<h5>foreach文部分</h5> foreach ($configFile as $line_num => $line) {}
の部分は、
foreach(変数名 as キー => 値) {
繰り返し内容
}
で、繰り返し内容のところでは、
$configFile[$line_num] = 値;という格納をし続けているので、
最終的には、
$configFile = array(【キー1】=>【内容1】,【キー2】=>【内容2】,【キー3】=>【内容3】…)という連想配列が出来上がる。
switch文部分
switch (substr($line,0,16)) { case 〇〇: 処理 break; case □□: 処理 break; }
まず、
substr($line,0,16)
が「$lineの0番目の文字から16文字を取り出した値」、という意味なので、
その値が、何であるかによってcase分岐処理される、ということ。
たとえば、
case "define('DB_NAME'": $configFile[$line_num] = str_replace("database_name_here", $dbname, $line); break;
では、substr関数で返ってきた値が、define(‘DB_NAME’の時には、直下の処理をしてbreak;する、ということになる。
次の、
str_replace("database_name_here", $dbname, $line);
は、「$lineの中のdatabase_name_hereを$dbnameに置換する」の意味なので、それを連想配列$configFileに格納することになる。
いよいよ、wp-config-sample.phpを書き換える!
まずは、書き込み権限がなかった場合。
if ( ! is_writable(ABSPATH) ) : display_header(); ?> <p><code>wp-config.php</code> ファイルへの書き込みができません。</p> <p><code>wp-config.php</code> を手動で作成して、次のテキストをそこに貼り付けてください。</p> <textarea cols="98" rows="15" class="code"><?php foreach( $configFile as $line ) { echo htmlentities($line, ENT_COMPAT, 'UTF-8'); } ?></textarea> <p>それが済んだら、「インストール実行」をクリックしてください。</p> <p class="step"><a href="install.php" class="button">インストール実行</a></p> <?php else :
htmlentities()は、htmlエンティティ(&を&
って書いたり)を作る関数。
書き込み権限があれば、書き換える
else : $handle = fopen(ABSPATH . 'wp-config.php', 'w'); foreach( $configFile as $line ) { fwrite($handle, $line); } fclose($handle); chmod(ABSPATH . 'wp-config.php', 0666); display_header(); ?> <p>この部分のインストールは無事完了しました。WordPress は現在データベースと通信できる状態にあります。準備ができているなら…</p> <p class="step"><a href="install.php" class="button">インストール実行</a></p> <?php endif;
fopen(URL , 開くモード)
は、URLを指定モードで開く関数で、ここでは、wp-config.phpを書き出しのみモード開くとなる。
で、それを$handleに保存しています。
次にfwrite(場所 , 内容)
は、内容を場所に書き込む関数なので、$lineを$handleに書き込みます。
次に、fclose関数でファイルを閉じます。
最後に、今できたwp-config.phpの権限を666(誰でも読み書き可能)に変更して、install.phpにリンクして終了。
まとめ
wp-config-sample.phpを書き換えているのではなく、wp-config.phpを新たに作っているのでした。しかも、ここで完成するファイルは、コメントもないし、wp-config-sample.phpの最後にある
define ('WPLANG', 'ja'); if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); require_once(ABSPATH . 'wp-settings.php');
が書き込まれていないものになるようです。
次回は、install.phpの勉強になるのかな。
コメント