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じゃない
それぞれの条件に沿って、アップデートか新規登録か決められます。
いずれにも当てはまらない、つまりエラーがある場合は何も起きません。
これで、今回の変更は以上です。
あとは前回までのソースコードと変わりません。
次回は、ログイン機能について、進めていきます。