前々回から取り組んでいるwp-login.phpの後半戦です。
このファイルの役割は、
- ユーザ認証。ログインさせる。
- 新規ユーザ登録
- パスワードのリセット
- パスワードを忘れてしまった人に教える
です。
ここまでは、これらの処理をするための下準備でした。
主に、
- 環境設定
- ログイン画面のを作る
- パスワード取得のための関数を定義
- パスワードリセットのための関数を定義
- 新規ユーザ登録のための関数を定義
でした。ワードプレスはしっかり動いているし、色んな変数に色々代入されてもいます。
ここからは、上記の関数を使いながら、$actionの値によって、switch構文で条件分岐して、処理が進みます。
最初に、どんなcaseがあるのかを確認し、全体の構造を抑えたいと思います。
全体の構造
switch ($action) { case 'logout' : //ログアウト時の処理 break; case 'lostpassword' : case 'retrievepassword' : //パスワード紛失時及び取得時の処理 break; case 'resetpass' : case 'rp' : //パスワードリセットのための処理 break; case 'register' : //新規登録のための処理 break; case 'login' : //ログイン時の処理 break;
ということで、以下順番に見ていきたいと思います。
まだまだ下準備
スイッチ構文に入る前に、まだ少し準備があるようです。
$actionの初期設定
// // Main // $action = isset($_REQUEST['action']) ? $_REQUEST['action'] : 'login'; $errors = new WP_Error(); if ( isset($_GET['key']) ) $action = 'resetpass';
$actionの値について、
もし$_REQUEST[‘action’]が設定されていればそれを代入し、
何もなければ、loginを代入しています。
さらにもし、$_GET[‘key’]に何かが入っていた場合には、resetpassで上書きしています。
何か別のものが$_REQUESTに入ってしまったら
// validate action so as to default to the login screen if ( !in_array($action, array('logout', 'lostpassword', 'retrievepassword', 'resetpass', 'rp', 'register', 'login'), true) && false === has_filter('login_form_' . $action) ) $action = 'login';
指定以外のものは全部、$action = login で行きましょう。
nocache_headers(); header('Content-Type: '.get_bloginfo('html_type').'; charset='.get_bloginfo('charset')); if ( defined('RELOCATE') ) { // Move flag is set if ( isset( $_SERVER['PATH_INFO'] ) && ($_SERVER['PATH_INFO'] != $_SERVER['PHP_SELF']) ) $_SERVER['PHP_SELF'] = str_replace( $_SERVER['PATH_INFO'], '', $_SERVER['PHP_SELF'] ); $schema = is_ssl() ? 'https://' : 'http://'; if ( dirname($schema . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']) != get_option('siteurl') ) update_option('siteurl', dirname($schema . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']) ); }
- nocache_headers();
- ブラウザによって、ヘッダー情報はキャッシュされる情報が異なるらしいので、全部クリアしてしまいます。
- str_replace(検索対象文字列, 新しく入る文字列, 検索範囲)
- もっとも単純な置換に使われます。
- get_option()
- optionsデータベーステーブルから、指定したオプションの値を取得する安全な関数
- update_option
- optionsデータベーステーブルを変更する関数
必要があれば、URLの何かを書き換えるようだ。
クッキーをセットする
//Set a cookie now to see if they are supported by the browser. setcookie(TEST_COOKIE, 'WP Cookie check', 0, COOKIEPATH, COOKIE_DOMAIN); if ( SITECOOKIEPATH != COOKIEPATH ) setcookie(TEST_COOKIE, 'WP Cookie check', 0, SITECOOKIEPATH, COOKIE_DOMAIN);
クッキーをセットします。
以後、$_COOKIE や $HTTP_COOKIE_VARS 配列、$_REQUEST 配列からアクセスできるようになります。
フックとPOST,GET判別
// allow plugins to override the default actions, and to add extra actions if they want do_action('login_form_' . $action); $http_post = ('POST' == $_SERVER['REQUEST_METHOD']);
プラグインによるヘッダー情報の上書きを許可するフックと、POST/GETの判別をして、変数に代入しています。
ここまでで、下準備は終わりです。
以下スイッチしていきます。
ログアウト処理
URLがwp-login.php?action=logout になっていれば、ログアウトさせます。
switch ($action) { case 'logout' : check_admin_referer('log-out'); wp_logout(); $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?loggedout=true'; wp_safe_redirect( $redirect_to ); exit(); break;
check_admin_referer()関数は、アドミンページから来たのかなんなのかを確かめています。いたずら防止です。
wp_logout()関数は、文字通りユーザをログアウトさせるもの。セッションを終了させています。
その後、リダイレクトさせるわけですが$_REQUEST[]配列にredirect_toで行き先が示されていればその行き先へ、示されていなければwp-login.php?loggedout=trueへリダイレクトです。
exit()は処理の終了です。
パスワード紛失時、取得時の処理
case 'lostpassword' : case 'retrievepassword' :
長いの分割します。
ユーザ名とメールアドレスが正しい場合
if ( $http_post ) { $errors = retrieve_password(); if ( !is_wp_error($errors) ) { $redirect_to = !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : 'wp-login.php?checkemail=confirm'; wp_safe_redirect( $redirect_to ); exit(); } }
もし、$http_postがtrueならば、前回定義したretrieve_password()を実行して$errorsに代入。
この時、retrieve_password()関数から、$errorsが返ってきていますので、その次の入れ子になっているif文では、これを使います。
もし、エラーがなければ、しかるべきところ(メールを確認してねの画面)にリダイレクトさせて、exit()して処理終了です。
ちなみに、ここでの$errorsであり得るのは、ユーザ名やメールアドレスの不正、空、そもそも存在しないなどなので、ここでやっていることをまとめると、
「ユーザ名やメールアドレスのチェックが通っていれば、パスワードを取得して、メール送信、メール送ったよの画面にリダイレクトして処理終了」です。
ログイン画面でパスワードが間違っていた人
普通にログインしようとしていた人が、間違ったパスワードを入力していた場合は以下を表示します。
if ( isset($_GET['error']) && 'invalidkey' == $_GET['error'] ) $errors->add('invalidkey', __('Sorry, that key does not appear to be valid.')); $redirect_to = apply_filters( 'lostpassword_redirect', !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '' );
パスワードが間違ってますよ、と伝えつつ再度同じ画面表示です。
フックと$user_login
do_action('lost_password'); login_header(__('Lost Password'), '<p class="message">' . __('Please enter your username or e-mail address. You will receive a new password via e-mail.') . '</p>', $errors); $user_login = isset($_POST['user_login']) ? stripslashes($_POST['user_login']) : ''; ?>
フックをセッティングして、$user_loginをちゃんとしておきます。
以下のフォームで使うからです。
パスワード紛失者フォーム
ユーザ名入力欄だけです。
<form name="lostpasswordform" id="lostpasswordform" action="<?php echo site_url('wp-login.php?action=lostpassword', 'login_post') ?>" method="post"> <p> <label><?php _e('Username or E-mail:') ?><br /> <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" tabindex="10" /></label> </p> <?php do_action('lostpassword_form'); ?> <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" /> <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button-primary" value="<?php esc_attr_e('Get New Password'); ?>" tabindex="100" /></p> </form>
formのactionが、wp-login.php?action=lostpasswordになっているので、送信ボタンを押すと、またこのファイルに戻ってきて、case ‘lostpassword’;に舞い戻ってきます。
ただ、この時には、エラーがでないはずなので、retriev_password関数が正常に動いて、exitするのでこのフォームは出ません。
登録&ログインへのリンクを
<p id="nav"> <?php if (get_option('users_can_register')) : ?> <a href="<?php echo site_url('wp-login.php', 'login') ?>"><?php _e('Log in') ?></a> | <a href="<?php echo site_url('wp-login.php?action=register', 'login') ?>"><?php _e('Register') ?></a> <?php else : ?> <a href="<?php echo site_url('wp-login.php', 'login') ?>"><?php _e('Log in') ?></a> <?php endif; ?> </p> </div>
会員登録を受け付けているサイトでは、「ログイン」「登録」へのリンクを、受け付けてなければ「ログイン」のみのリンクを。
ブログのトップページへ戻る
<p id="backtoblog"><a href="<?php bloginfo('url'); ?>/" title="<?php _e('Are you lost?') ?>"><?php printf(__('← Back to %s'), get_bloginfo('title', 'display' )); ?></a></p> <script type="text/javascript"> try{document.getElementById('user_login').focus();}catch(e){} if(typeof wpOnload=='function')wpOnload(); </script> </body> </html> <?php break;
トップヘ戻るためのリンク。JSは、ユーザ名を入力するところに入力カーソルを置いておく指示。
パスワードをリセットする場合
case 'resetpass' : case 'rp' : $errors = reset_password($_GET['key'], $_GET['login']); if ( ! is_wp_error($errors) ) { wp_redirect('wp-login.php?checkemail=newpass'); exit(); } wp_redirect('wp-login.php?action=lostpassword&error=invalidkey'); exit(); break;
パスワードリセットのための関数を呼び出し。
エラーがなければ、リダイレクトして終了。
登録の処理
case 'register' :
action=registerの二回目とか
if ( is_multisite() ) { // Multisite uses wp-signup.php wp_redirect( apply_filters( 'wp_signup_location', get_bloginfo('wpurl') . '/wp-signup.php' ) ); exit; } if ( !get_option('users_can_register') ) { wp_redirect('wp-login.php?registration=disabled'); exit(); } $user_login = ''; $user_email = ''; if ( $http_post ) { require_once( ABSPATH . WPINC . '/registration.php'); $user_login = $_POST['user_login']; $user_email = $_POST['user_email']; $errors = register_new_user($user_login, $user_email); if ( !is_wp_error($errors) ) { $redirect_to = !empty( $_POST['redirect_to'] ) ? $_POST['redirect_to'] : 'wp-login.php?checkemail=registered'; wp_safe_redirect( $redirect_to ); exit(); } } $redirect_to = apply_filters( 'registration_redirect', !empty( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '' ); login_header(__('Registration Form'), '<p class="message register">' . __('Register For This Site') . '</p>', $errors); ?>
マルチサイトの場合は、wp-signup.phpでやってくれ。
会員登録を受け付けない設定の場合はさようなら。
フォーム入力が済んでいれば、register_new_user()で実行してメールチェックを促して終了、まだならば以下のフォームの出力。
<form name="registerform" id="registerform" action="<?php echo site_url('wp-login.php?action=register', 'login_post') ?>" method="post"> <p> <label><?php _e('Username') ?><br /> <input type="text" name="user_login" id="user_login" class="input" value="<?php echo esc_attr(stripslashes($user_login)); ?>" size="20" tabindex="10" /></label> </p> <p> <label><?php _e('E-mail') ?><br /> <input type="text" name="user_email" id="user_email" class="input" value="<?php echo esc_attr(stripslashes($user_email)); ?>" size="25" tabindex="20" /></label> </p> <?php do_action('register_form'); ?> <p id="reg_passmail"><?php _e('A password will be e-mailed to you.') ?></p> <br class="clear" /> <input type="hidden" name="redirect_to" value="<?php echo esc_attr( $redirect_to ); ?>" /> <p class="submit"><input type="submit" name="wp-submit" id="wp-submit" class="button-primary" value="<?php esc_attr_e('Register'); ?>" tabindex="100" /></p> </form> //いろいろ break;
ユーザ名とメールアドレスの入力を促して送信してもらうフォーム。
このときパスワードは自動発行されてユーザに送信されます。
この下に、「ログイン」や「忘れました」のリンクもある。
ログイン
case 'login' : default:
以下、ログインの処理です。
default:は、if文のelseにあたるcase “なにか”;がなかった場合、これをするの意味。
2つの変数
$secure_cookie = ''; $interim_login = isset($_REQUEST['interim-login']);
SSLの人はSSLへどうぞ
// If the user wants ssl but the session is not ssl, force a secure cookie. if ( !empty($_POST['log']) && !force_ssl_admin() ) { $user_name = sanitize_user($_POST['log']); if ( $user = get_userdatabylogin($user_name) ) { if ( get_user_option('use_ssl', $user->ID) ) { $secure_cookie = true; force_ssl_admin(true); } } }
force_ssl_admin()は管理画面、ログイン系画面でのアクセスをSSLに限定する関数。
リダイレクト先を決めておく
if ( isset( $_REQUEST['redirect_to'] ) ) { $redirect_to = $_REQUEST['redirect_to']; // Redirect to https if user wants ssl if ( $secure_cookie && false !== strpos($redirect_to, 'wp-admin') ) $redirect_to = preg_replace('|^http://|', 'https://', $redirect_to); } else { $redirect_to = admin_url(); }
あとで使う
$reauth = empty($_REQUEST['reauth']) ? false : true;
再認証とかの意味だと思うので、reauthが入ってればもういらないからfalseにして、もし空だったらtrueにしておくのだと思う。
SSL関連再び
// If the user was redirected to a secure login form from a non-secure admin page, and secure login is required but secure admin is not, then don't use a secure // cookie and redirect back to the referring non-secure admin page. This allows logins to always be POSTed over SSL while allowing the user to choose visiting // the admin via http or https. if ( !$secure_cookie && is_ssl() && force_ssl_login() && !force_ssl_admin() && ( 0 !== strpos($redirect_to, 'https') ) && ( 0 === strpos($redirect_to, 'http') ) ) $secure_cookie = false;
もし、ユーザがノンセキュアな管理系ページからセキュアなログインフォームへ飛んできたのなら、かつセキュアログインが要求されているのにも関わらず今違うのなら、セキュアクッキーは発行せず、ノンセキュアな管理系ページへリダイレクトし返します。
サインインできた?リダイレクト
$user = wp_signon('', $secure_cookie); $redirect_to = apply_filters('login_redirect', $redirect_to, isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '', $user);
wp_signon()は、セキュアにサインオンできてるのか、エラーなのかを返してきます。
リダイレクト先が書いてなかったら、ユーザページ?へ。
成功!
if ( !is_wp_error($user) && !$reauth ) { if ( $interim_login ) { $message = '<p class="message">' . __('You have logged in successfully.') . '</p>'; login_header( '', $message ); ?> <script type="text/javascript">setTimeout( function(){window.close()}, 8000);</script> <p class="alignright"> <input type="button" class="button-primary" value="<?php esc_attr_e('Close'); ?>" onclick="window.close()" /></p> </div></body></html> <?php exit; } // If the user can't edit posts, send them to their profile. if ( !$user->has_cap('edit_posts') && ( empty( $redirect_to ) || $redirect_to == 'wp-admin/' || $redirect_to == admin_url() ) ) $redirect_to = admin_url('profile.php'); wp_safe_redirect($redirect_to); exit(); }
大外のif文は、「もしセキュアなサインオンがOK=エラーがないで、$reauthがfalseのとき」の意味でつまりログイン成功の場合のこと。
その中に、2つのif文が入っていて、一つ目は仮ログインだったらの場合、ログイン成功のメッセージを出しつつ閉じるボタンも表示。
二つ目は、編集権限が無い場合はプロフィールページに飛ばす。
どちらの場合も、処理終了があるので、以下は無視される。
以下は、ログインが成功しなかった場合の処理ということになる。
ログアウト印、再確認印、クッキーが使えない
$errors = $user; // Clear errors if loggedout is set. if ( !empty($_GET['loggedout']) || $reauth ) $errors = new WP_Error(); // If cookies are disabled we can't log in even with a valid user+pass if ( isset($_POST['testcookie']) && empty($_COOKIE[TEST_COOKIE]) ) $errors->add('test_cookie', __("<strong>ERROR</strong>: Cookies are blocked or not supported by your browser. You must <a href='http://www.google.com/cookies.html'>enable cookies</a> to use WordPress."));
$_GET[‘loggedout’]がある場合、または再認証の必要がある場合は、$errorsのインスタンスを再設定してしまう。
クッキーが使えない場合は、とにかくダメです。
エラーメッセージを用意しよう
// Some parts of this script use the main login form to display a message if ( isset($_GET['loggedout']) && TRUE == $_GET['loggedout'] ) $errors->add('loggedout', __('You are now logged out.'), 'message'); elseif ( isset($_GET['registration']) && 'disabled' == $_GET['registration'] ) $errors->add('registerdisabled', __('User registration is currently not allowed.')); elseif ( isset($_GET['checkemail']) && 'confirm' == $_GET['checkemail'] ) $errors->add('confirm', __('Check your e-mail for the confirmation link.'), 'message'); elseif ( isset($_GET['checkemail']) && 'newpass' == $_GET['checkemail'] ) $errors->add('newpass', __('Check your e-mail for your new password.'), 'message'); elseif ( isset($_GET['checkemail']) && 'registered' == $_GET['checkemail'] ) $errors->add('registered', __('Registration complete. Please check your e-mail.'), 'message'); elseif ( $interim_login ) $errors->add('expired', __('Your session has expired. Please log-in again.'), 'message');
ゲットに何が渡されてきているかによって、$errorsに色々格納されてないといけないようです。
マインのログインフォームの中で使われます。
再確認印が付いているなら、クッキー消去
// Clear any stale cookies. if ( $reauth ) wp_clear_auth_cookie();
関数login_header()が活躍してる。
login_header(__('Log In'), '', $errors);
さっき値を足された$errorsが使われています。
$_POST[‘log’]を狭める?
if ( isset($_POST['log']) ) $user_login = ( 'incorrect_password' == $errors->get_error_code() || 'empty_password' == $errors->get_error_code() ) ? esc_attr(stripslashes($_POST['log'])) : '';
パスワード関連のミスの時は、あとのメインフォームで入力されていた文字列を$user_loginに代入、そうじゃなかったらカラにしておく。
logはメインフォームのユーザ名入力欄のname属性です。
リメンバー・ミーがポストされてたら
$rememberme = ! empty( $_POST['rememberme'] );
メインフォーム
?> <form name="loginform" id="loginform" action="<?php echo site_url('wp-login.php', 'login_post') ?>" method="post"> <p> <label><?php _e('Username') ?><br /> <input type="text" name="log" id="user_login" class="input" value="<?php echo esc_attr($user_login); ?>" size="20" tabindex="10" /></label> </p> <p> <label><?php _e('Password') ?><br /> <input type="password" name="pwd" id="user_pass" class="input" value="" size="20" tabindex="20" /></label> </p> <?php do_action('login_form'); ?> <p class="forgetmenot"><label><input name="rememberme" type="checkbox" id="rememberme" value="forever" tabindex="90"<?php checked( $rememberme ); ?> /> <?php esc_attr_e('Remember Me'); ?></label></p> <p class="submit"> <input type="submit" name="wp-submit" id="wp-submit" class="button-primary" value="<?php esc_attr_e('Log In'); ?>" tabindex="100" /> <?php if ( $interim_login ) { ?> <input type="hidden" name="interim-login" value="1" /> <?php } else { ?> <input type="hidden" name="redirect_to" value="<?php echo esc_attr($redirect_to); ?>" /> <?php } ?> <input type="hidden" name="testcookie" value="1" /> </p> </form>
input type=”hidden”で色々渡しているのが効いてきます。
仮ログイン状態ではないとして、いろんなリンクボタンを出す
<?php if ( !$interim_login ) { ?> <p id="nav"> <?php if ( isset($_GET['checkemail']) && in_array( $_GET['checkemail'], array('confirm', 'newpass') ) ) : ?> <?php elseif ( get_option('users_can_register') ) : ?> <a href="<?php echo site_url('wp-login.php?action=register', 'login') ?>"><?php _e('Register') ?></a> | <a href="<?php echo site_url('wp-login.php?action=lostpassword', 'login') ?>" title="<?php _e('Password Lost and Found') ?>"><?php _e('Lost your password?') ?></a> <?php else : ?> <a href="<?php echo site_url('wp-login.php?action=lostpassword', 'login') ?>" title="<?php _e('Password Lost and Found') ?>"><?php _e('Lost your password?') ?></a> <?php endif; ?> </p> </div> <p id="backtoblog"><a href="<?php bloginfo('url'); ?>/" title="<?php _e('Are you lost?') ?>"><?php printf(__('← Back to %s'), get_bloginfo('title', 'display' )); ?></a></p> <?php } else { ?> </div> <?php } ?>
フォームの選択
<script type="text/javascript"> function wp_attempt_focus(){ setTimeout( function(){ try{ <?php if ( $user_login || $interim_login ) { ?> d = document.getElementById('user_pass'); <?php } else { ?> d = document.getElementById('user_login'); <?php } ?> d.value = ''; d.focus(); } catch(e){} }, 200); } <?php if ( !$error ) { ?> wp_attempt_focus(); <?php } ?> if(typeof wpOnload=='function')wpOnload(); </script>
どこのフォームをアクティブにしておくかをjsで制御。
やっと終わった
</body> </html> <?php break; } // end action switch ?>
スイッチが終了して、このファイル終了。
コメント