WEBサービスを開発するのであれば「会員登録機能」は、ほぼ必須です。
今回は、シンプルな会員登録機能を作ってみます。
メールアドレスとパスワードを入力して登録するだけです。
会員登録システムには、基本中の基本となる3つの機能があります。
登録機能とログイン、そしてユーザー情報の編集です。
この3つを習得すると、応用で色々作れるようになります。
ぜひ、理解できるまで「繰り返して」みてください。
今回のポイントとなるのは2つ。
入力エラーがないか確認する「バリデーションチェック」。
そして「パスワードの暗号化」です。
セキュリティ上、パスワードは誰にも知られてはいけません。
それが、管理者であってもです。
データベースにも、本物が分からないように暗号化して保存する必要があります。
とは言っても、難しいことではありません。
phpには暗号化の処理も存在しているのです。
今回も、前回までのファイルに機能を加える形で作っていきます。
前回までのファイルを持っている方は、そのままカスタマイズして進めてください。
ミッションの内容
下記のファイルを再現してみてください。
基本的には、前回のファイルのアップデートです。
特に気をつけるポイントは、入力内容のバリデーションチェック。
そして、パスワードの暗号化です。
まず、ソースコードの解説を読み、自分自信で実装してみてください。
どうしても分からない場合は解答ファイルを参考にしましょう。
ソースコードの説明を下記に記載します。
まず一通り目を通して、同時に自分のエディタで試してみてください。
ソースコードの解説
まず、全体のソースコードをみていきましょう。
<?php //データベース呼び出し require_once "functions/db.php"; //URLパラメータ取得 $editId = $_GET["edit"]; //URLパラメータからidを受け取り、該当のユーザーを検索 $userdataEdit = "select * from userdata where id = '".$editId."' order by id DESC"; $userdataEdit = mysqli_query($mysqli,$userdataEdit); while ($userdataEditArray = mysqli_fetch_assoc($userdataEdit)) { $name = $userdataEditArray["name"]; $age = $userdataEditArray["age"]; $skill = $userdataEditArray["skill"]; //新しく会員登録やログインに必要なメールとパスワードが追加。 $mail = $userdataEditArray["mail"]; //$hashpassは暗号化されたパスワードという意味。 $hashpass = $userdataEditArray["password"]; }; //存在したユーザー数カウント。 $userCount = $userdataEdit->num_rows; if ($_SERVER['REQUEST_METHOD'] === 'POST') { //ポストされたデータをキャッチします。 $name = htmlspecialchars($_POST['name'], ENT_QUOTES); $age = htmlspecialchars($_POST['age'], ENT_QUOTES); $skill = htmlspecialchars($_POST['skill'], ENT_QUOTES); //メールアドレスとパスワードをキャッチします。 $mail = htmlspecialchars($_POST['mail'], ENT_QUOTES); $password = htmlspecialchars($_POST['password'], ENT_QUOTES); //メールアドレスが正しいメールアドレスかどうかを確認する関数です。 function mailcheck($mail){ //こちらの記号は正規表現と言います。 //今回は、メールアドレスの形を表しています。 //正規表現で$mail内に入っているデータがメールアドレスの形じゃなければfalseを返します。 if(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $mail)){ return 'true'; }else{ return 'false'; } }; //$mailが空じゃなければバリデーションチェック呼び出します。 //空の場合は$mailresultにfalseを返します。 if(!empty($mail)){ $mailresult = mailcheck($mail); }else{ $mailresult = "false"; }; //パスワード暗号化と空欄チェックを行います。 if(!empty($password)){ //パスワードは、管理者にも知られてはいけません。 //必ず、受けとったパスワードのデータを暗号化します。 //$passwordに文字列が入っていれば、それが暗暗号化され$hashpassに入ります。 $hashpass = password_hash($password, PASSWORD_BCRYPT); }; //もし暗号化されたパスワードが$hashpassになければ$passresultがfalseに。 if(empty($hashpass)){ $passresult = "false"; }; //すでにユーザーが存在していた場合はアップデート。 //メールアドレスとパスワードが入力されていた場合に実行。 if($userCount !== 0&&$mailresult!=="false"&&$passresult!=="false"){ $result = mysqli_query($mysqli,"update userdata set name = '".$name."',age = '".$age."',skill = '".$skill."',mail = '".$mail."',password = '".$hashpass."' where id = '".$editId."'"); echo "アップデート完了"; } if($userCount == 0&&$mailresult!=="false"&&$passresult!=="false"){ //$userCountが0だった場合は新規で登録。 //メールアドレスとハッシュパスがあれば登録可能。 $result = mysqli_query($mysqli,"insert into userdata(name,age,skill,mail,password) VALUES('$name','$age','$skill','$mail','$hashpass')"); echo "新規登録完了"; }; }; ?> <div style="padding-bottom:15px;"> <a href="https://base91.net/mission/php/9/">新規追加</a> </div> <h1>登録フォーム</h1> <form method="post" action=""> <input type="text" name="mail" placeholder="メールアドレス" value="<?php echo $mail; ?>" /><br/> <!--もし$mailresultがfalseの場合はエラー表示。--> <?php if($mailresult == "false"){echo "メールアドレスにエラーがあります。<br/>";}; ?> <input type="password" name="password" placeholder="パスワード" value="" /><br/> <!--もし$passresultがfalseの場合はエラー表示。--> <?php if($passresult == "false"){echo "パスワードにエラーがあります。<br/>";}; ?> <input type="text" name="name" placeholder="お名前" value="<?php echo $name; ?>" /><br/> <input type="text" name="age" placeholder="年齢" value="<?php echo $age; ?>" /><br/> <input type="text" name="skill" placeholder="スキル" value="<?php echo $skill; ?>" /><br/> <?php if($userCount == 0): ?> <input type="submit" name="submitBtn" value="登録" /> <?php else: ?> <input type="submit" name="submitBtn" value="更新" /> <?php endif; ?> </form> <?php //投稿データ一覧 $userdata = "select * from userdata order by id DESC"; $userdata = mysqli_query($mysqli,$userdata); while ($userdataArray = mysqli_fetch_assoc($userdata)) { echo $id = $userdataArray["id"]; echo ","; echo $name = $userdataArray["name"]; echo ","; echo $age = $userdataArray["age"]; echo ","; echo $skill = $userdataArray["skill"]; echo "|"; echo "<button class='deleteBtn' data-id='".$id."'>削除する</button>"; echo "|"; echo "<button class='editBtn' data-id='".$id."'>編集する</button>"; echo "<br>"; }; ?>
<script> //削除ボタン押された時 $(".deleteBtn").click(function(){ var btnid = $(this).data("id"); deleteData(btnid); }); //編集ボタン押された時 $(".editBtn").click(function(){ var btnid = $(this).data("id"); window.location.href = "./?edit="+btnid; }); //削除ボタン押された時に呼び出される関数 function deleteData(btnid){ $.ajax({ type: 'POST', dataType:'json', url:'functions/delete_func.php', data:{ btnid:btnid, }, success:function(data) { window.location.href = "./"; }, error:function(XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); }; </script>
以上が全体のソースコードになります。
まずは、HTMLから見ていきましょう。
<div style="padding-bottom:15px;"> <a href="https://base91.net/mission/php/9/">新規追加</a> </div> <h1>登録フォーム</h1> <form method="post" action=""> <input type="text" name="mail" placeholder="メールアドレス" value="<?php echo $mail; ?>" /><br/> <!--もし$mailresultがfalseの場合はエラー表示。--> <?php if($mailresult == "false"){echo "メールアドレスにエラーがあります。<br/>";}; ?> <input type="password" name="password" placeholder="パスワード" value="" /><br/> <!--もし$passresultがfalseの場合はエラー表示。--> <?php if($passresult == "false"){echo "パスワードにエラーがあります。<br/>";}; ?> <input type="text" name="name" placeholder="お名前" value="<?php echo $name; ?>" /><br/> <input type="text" name="age" placeholder="年齢" value="<?php echo $age; ?>" /><br/> <input type="text" name="skill" placeholder="スキル" value="<?php echo $skill; ?>" /><br/> <?php if($userCount == 0): ?> <input type="submit" name="submitBtn" value="登録" /> <?php else: ?> <input type="submit" name="submitBtn" value="更新" /> <?php endif; ?> </form>
前回と比べて、メールアドレスと、パスワードの入力欄が増えているのがおわかりでしょうか。
また、メールアドレスとパスワードは、入力必須です。
未入力や間違っていればエラーが出るようになっています。
こうした入力内容のエラーチェックをバリデーションチェックと言います。
エラーの出し方については、また後ほどご説明させて頂きます。
次にphpを見ていきましょう。
まずは、最初の設定からです。
//データベース呼び出し require_once "functions/db.php"; //URLパラメータ取得 $editId = $_GET["edit"]; //URLパラメータからidを受け取れとり、該当のユーザーを検索 $userdataEdit = "select * from userdata where id = '".$editId."' order by id DESC"; $userdataEdit = mysqli_query($mysqli,$userdataEdit); while ($userdataEditArray = mysqli_fetch_assoc($userdataEdit)) { $name = $userdataEditArray["name"]; $age = $userdataEditArray["age"]; $skill = $userdataEditArray["skill"]; //新しく会員登録やログインに必要なメールとパスワードが追加。 $mail = $userdataEditArray["mail"]; //$hashpassは暗号化されたパスワードという意味。 $hashpass = $userdataEditArray["password"]; }; //存在したユーザー数カウント。 $userCount = $userdataEdit->num_rows;
URLパラメータを元にデータベースからユーザーデータを呼び出しています。
ユーザーデータの更新に使う時の処理です。
前回からの継続して使う処理ですね。
前回から変わったのは、$mailと$hashpassが加わっているところです。
$mailにメールアドレスを呼び出します。
$hashpassに暗号化済みのパスワードを呼び出します。
今回、会員登録で上記のデータも登録させます。
なお、データベースに登録されているパスワードは、すべて暗号化済みのパスワードです。
暗号化をハッシュ化と呼びます。
暗号化されているので、開発者にもわかりません。
次は、フォームに内容を入力し、登録ボタンが押された後の機能です。
登録ボタンが押されると、同じページが再読み込みされます。
その際、フォームに入力されたデータも再読み込みされたページに渡されます。
渡されたデータを受け取って、登録していきます。
if ($_SERVER['REQUEST_METHOD'] === 'POST') { //ポストされたデータを受け取ります。 $name = htmlspecialchars($_POST['name'], ENT_QUOTES); $age = htmlspecialchars($_POST['age'], ENT_QUOTES); $skill = htmlspecialchars($_POST['skill'], ENT_QUOTES); //メールアドレスとパスワードを受け取ります。 $mail = htmlspecialchars($_POST['mail'], ENT_QUOTES); $password = htmlspecialchars($_POST['password'], ENT_QUOTES); //メールアドレスが正しいメールアドレスかどうかを確認する関数です。 function mailcheck($mail){ //下記の記号は正規表現と言います。 //今回は、文字がメールアドレスの形式になっているかの確認です。 //正規表現で$mail内に入っているデータがメールアドレスの形じゃなければfalseを返します。 if(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $mail)){ return 'true'; }else{ return 'false'; } }; //$mailが空じゃないかの確認です。 //空じゃなければバリデーションチェック呼び出します。 //空の場合は$mailresultにfalseを返します。 if(!empty($mail)){ $mailresult = mailcheck($mail); }else{ $mailresult = "false"; }; //パスワード暗号化と入力チェックを行います。 //!empty(空じゃない)場合、if文の中の処理を実行します。 if(!empty($password)){ //パスワードは、管理者にも知られてはいけません。 //必ず、受けとったパスワードのデータを暗号化します。 //$passwordに文字列が入っていれば、それが暗号化され$hashpassに入ります。 $hashpass = password_hash($password, PASSWORD_BCRYPT); }else{ $passresult = "false"; }; //すでにユーザーが存在していた場合は更新処理。 //メールアドレスとパスワードが入力されていた場合に実行。 if($userCount !== 0&&$mailresult!=="false"&&$passresult!=="false"){ $result = mysqli_query($mysqli,"update userdata set name = '".$name."',age = '".$age."',skill = '".$skill."',mail = '".$mail."',password = '".$hashpass."' where id = '".$editId."'"); echo "アップデート完了"; } if($userCount == 0&&$mailresult!=="false"&&$passresult!=="false"){ //$userCountが0だった場合は新規で登録。 //メールアドレスとハッシュパスがあれば登録可能。 $result = mysqli_query($mysqli,"insert into userdata(name,age,skill,mail,password) VALUES('$name','$age','$skill','$mail','$hashpass')"); echo "新規登録完了"; }; };
色々、前回から増えているので、順番に見ていきましょう。
まず「ポストされたデータ」を受け取ります。
最初に前回と同じデータをキャッチしています。
続けて「メールアドレスとパスワード」を受け取っています。
入力項目は増えたので、もちろん受け取る項目も増えます。
ここで気をつけて欲しいのが、パスワードの変数が2つあること。
フォームから素のパスワードを受け取る変数。
データベースから暗号化されたパスワードを呼び出して受け取る変数。
それぞれ別になっています。
$hashpassが暗号化されたパスワードを受け取る変数。
$passwordが暗号化されていないパスワードを受け取る変数です。
次に「メールアドレスのバリデーションチェックの関数」を作ります。
バリデーションとは入力エラーがないか確かめるための処理ですね。
例えばフォームはからじゃないか。
メールアドレスであれば、@マークが入っているか。
半角英数字か、形式に沿っているか。
決まりに倣って入力されているかどうかです。
下記のソースコードに注目してください。
if(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $mail))
preg_matchの次に、謎のソースコードがあるのが分かると思います。
これを正規表現と言いまして、文字列のルールを表すものです。
preg_matchで正規表現で書かれたルールと変数$mailに入っている文字列を比較します。
そして、文字列がメールアドレスのルールに沿っているかどうかを判断します。
if文で、もしルールに沿っていたら、returnでtrueかfalseを返します。
//メールアドレスバリデーションチェックの関数 function mailcheck($mail){ if(preg_match('/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD', $mail)){ return 'true'; }else{ return 'false'; } };
なお最初のうちはreturnでtrueかfalseが返される、と言っても「どこに」返されるのか迷う方も多いかと思います。
それは、関数を実行する下記のソースコードを見れば分かります。
if(!empty($mail)){ $mailresult = mailcheck($mail); }else{ $mailresult = "false"; };
メールが空でなければ、上の処理を実行。
空であれば下の処理を実行します。
$mailresult = mailcheck($mail); が関数を呼び出す処理です。
変数が関数と「=」でつながっているのが、おわかりでしょうか。
returnで返されたtrueやfalseは、その文字が$mailresultの中に入るのです。
呼び出す時に$mailresultにreturnで返された答えを受け取れるように書いているんですね。
なお、もし$mailが空であれば、バリデーションをチェックすることなく、直接falseが入ります。
$mailresultにfalseが入っていたら、エラーが表示されるという仕組みです。
さて、次はパスワードの暗号化についてご説明しましょう。
//パスワード暗号化と空欄チェックを行います。 if(!empty($password)){ //パスワードは、管理者にも知られてはいけません。 //必ず、受けとったパスワードのデータを暗号化します。 //$passwordに文字列が入っていれば、それが暗暗号化され$hashpassに入ります。 $hashpass = password_hash($password, PASSWORD_BCRYPT); }else{ $passresult = "false"; };
もし受け取ったパスワードが空であれば、そのまま$passresultにfalseが返されます。
パスワードが存在していたら、パスワードを暗号化し、trueを返します。
暗号化しているのは、下記のソースコードです。
$hashpass = password_hash($password, PASSWORD_BCRYPT);
変数$passwordをpassword_hashで暗号化します。
その後、$hashpassに返します。
暗号化の処理はこれだけです。
では、入力されたデータをデータベースに保存していきましょう。
//すでにユーザーが存在していた場合はアップデート。 //メールアドレスとパスワードが入力されていた場合に実行。 if($userCount !== 0&&$mailresult!=="false"&&$passresult!=="false"){ $result = mysqli_query($mysqli,"update userdata set name = '".$name."',age = '".$age."',skill = '".$skill."',mail = '".$mail."',password = '".$hashpass."' where id = '".$editId."'"); echo "アップデート完了"; } if($userCount == 0&&$mailresult!=="false"&&$passresult!=="false"){ //$userCountが0だった場合は新規で登録。 //メールアドレスとハッシュパスがあれば登録可能。 $result = mysqli_query($mysqli,"insert into userdata(name,age,skill,mail,password) VALUES('$name','$age','$skill','$mail','$hashpass')"); echo "新規登録完了"; };
基本的には、前のソースコードと同じです。
ただ、条件が少し異なっています。
アップデートする条件は下記の2つ。
- 該当IDのユーザーが存在する
- $mailresultと$passwordがfalseじゃない
そして新規登録の条件は下記。
- 該当IDのユーザーが存在しない
- $mailresultと$passwordがfalseじゃない
それぞれの条件に沿って、アップデートか新規登録か決められます。
いずれにも当てはまらない、つまりエラーがある場合は何も起きません。
これで、今回の変更は以上です。
あとは前回までのソースコードと変わりません。
次回は、ログイン機能について、進めていきます。