見出し画像

自由研究でSNSをつくろう! ログイン編

ミニマムSNSを作る企画の3回目! 今回は、作成したアカウントを使ってログインする仕組みを作りますよ~。

ゲーム制作でも役立つ

こういったログインの仕組みを作れるようになると、SNSに限らずアカウントを使用するタイプのゲーム、古い言い方をすれば「ソシャゲ」みたいなものを作ることにも役立ちます。

このミニマムSNSは"最低限"の機能にすると決めていることですし、一度基礎のシステムを作ってしまえば拡張は比較的簡単なので、いずれはそういう拡張もありかな~と思って地味なSNS制作にうるおいを与えていきたいところです。

「ホーム画面」として作る

今回作るのは「ログインの仕組み」ですが、ログイン前だけでなくログイン後にも表示する「ホーム画面」(home.php)として作成します。

なぜそんなことをするかというと、「ログイン前後で、表示内容を切り替える」のはSNS作りではかなり重要なポイントだからです。例えば、"ログイン後に表示できるページ"を独立した別ファイル(別URL)にしてしまうと、ブラウザのブックマークなどから直接URLを指定して開かれときに"未ログイン"だとややこしいことになるからです。

なので、home.phpは
①ログイン前「ログインするためのフォーム」
②ログイン後「基礎的な情報が表示されるホーム画面」
として作成します。

以下のリンク『自由研究SNS(仮)』から[ホーム画面(ログイン)]を開くと、今回作成したhome.phpで実際にログイン処理を実行できるようになっています(※アカウントを作成しておく必要があります)。

ログイン処理自体は超カンタン

"①ログイン前「フォーム」"はとても簡単で、IDとパスワードを記入するフォームを作り、それらを前回保存したアカウント情報と一致するか確認するだけです。

これは特に悩みもせずにサクッと作りました。

(ログイン画面はシンプル)

[ログイン]を押すと再びhome.phpを開くことになるので、PHP上でIDとパスワードを確認し、一致する場合は"②ログイン後…ホーム画面"の内容を表示します。

問題はログイン状態の保持

今回の本題は、ログイン状態の保持にあります。

SNSなどの会員制的なサイトでは、検索したり、プロフィールを見たり、設定変更を行なったり、と表示する内容が変化してページが"遷移"していきます。もちろんそのたびにログインし直すわけにはいきませんので、「このユーザーはログイン済みだよ!」という情報をどこかに持っておくようにして、ログイン済みなら表示する、未ログインなら表示せずログインを促す、といった場合分けをしなくてはなりません。

ただし、「ログイン済みだよ!」という情報を偽装されるとセキュリティ的にダメダメなので、うまく隠す必要があります。

今回は、ログインした際にIPアドレスとトークン(ランダム文字列)をアカウント情報の一部としてサーバー上に保存し、ページ遷移の際にそれらが一致するかを確認するようにしてみました。表示しているページの方には、非表示で現在のアカウントIDとトークンを埋め込んであります。

アカウントIDとトークンは、クッキー(ブラウザーに情報を保存する仕組み)にも保持するようにしたので、一度ログインすると以後は同じ環境からなら自動ログインできるようになっています(100日間またはIPが変わるまで)。ただしクッキーはブラウザ側でブロックすることも可能なので、クッキーに依存することはないようにしています。

ページ遷移のテスト

ログインに成功すると表示されるログイン情報のページには[遷移テスト]というボタンがあり、これを押すとホーム画面を再度開き直します。このとき下にあるデバッグ情報の"refresh_count"の数値が変化するので、ログイン状態を保持したまま、機能を実行してページの内容を遷移させられることを確認できるようになっています(ただしこの部分は一時的なもので、今後デザインを整えるときに消すことになります)。

(ログイン状態保持しながら表示内容が変化する様子をテスト可能)

あとは、ついでといってはなんですが[ログアウト]機能も作っておきました。これを実行すると、サーバー上に保存されていたトークン情報を削除し、それによってログイン状態が保持されなくなるため以後はhome.phpを開いても最初のログイン用フォームに戻されます。

今回も記事の末尾にPHPのソースコードを掲載しておきますので、細かい説明は省略します。詳しく知りたい人は、コードを読んでみてください。なお、今回のコードも関数などの共通処理は別ファイルにわかれていてそのままコピペしても動きませんし、お行儀の良いコードにはなっていないので、あくまで参考ということでよろしくお願いします。

なお、次回はコード作成はちょっとお休みして、SNS用のアイコンをどうにかしようと思います。あまり、おじいちゃんばかりを酷使するわけにはいきませんからね。

老兵「わしゃ、もうつかれたわい」

(つづく)

参考PHPコード

<?php

    include './common.php'; //共通設定読み込み

    //サブタイトル
    $sub_title='ホーム';

?>
<?php
//変数初期設定
    $form_command=''; 
        //before=ログイン前
        //login=ログイン
        //home=ホーム
    $auto_aid=$account_id; //自動入力するID(再入力省略用)
    $auto_password=''; //自動入力するパスワード
    $login_password=''; //ログイン時に入力されたパスワード

    $safe=true; //チェック初期化(有効判定)
    $short_error=''; //エラーの理由
?>
<?php
//引数を取得

    if(isset($_POST['form_command'])) { 
        $form_command = $_POST['form_command'];
    }
    if(isset($_POST['login_password'])) {
        $login_password = $_POST['login_password'];
    }
    $refresh_count=0;
    if(isset($_POST['refresh'])) { //[再表示テスト]
        if(isset($_POST['refresh_count'])) {
            $refresh_count=$_POST['refresh_count'];
        }
        $refresh_count=$refresh_count+1; //+1
    }
    if(isset($_POST['logout'])) { //[ログアウト]
        $go_logout=1;
    }

    //command引数を受けてのID,password設定に対応zzz

//変数準備

    //本登録データのpath準備
    $reg_file=$account_id.'.txt';
    $reg_path=$folder_u_reg.$reg_file;
    //保管フォルダのpath準備
    $dat_folder=$folder_u_dat.'user_'.$account_id;

?>
<?php //--------共通処理:ログイン/復帰判定準備--------

    $need_relogin_check=1; //要復帰判定ON

    if($form_command==''){
    //コマンド指定なし(=直接home.phpを開いた場合)
        if($cookie_aid=='' and $cookie_token==''){
        //(cookieなし)
            //ログイン前へ
            $form_command='before';
            //要復帰判定OFF
            $need_relogin_check=0;
        }else{
        //(cookieあり)
            //復帰判定へ
            $form_command='home';
        }
    }

    //ログアウト実行時
    if($go_logout==1){ 
        //要復帰判定OFF
        $need_relogin_check=0;
        //token削除
        unlink($user_token_path);
        //cookie消去
        $cookie_aid='';
        $cookie_token='';
        utCookieUpdate($cookie_aid,$cookie_token);
        //自動入力ID指定を解除
        $auto_aid='';
        //※そのままhome表示判定へ進む(beforeに移行する)
    }

    //復帰判定+ログイン判定用情報取得
    if($need_relogin_check==1){
    //(要復帰判定ONなら)
        //アカウント存在チェック
        if(file_exists($reg_path)==false){
            $safe=false;
            $short_error='アカウント('.$account_id.')は存在しません。';
        }
        //アカウント情報ロード(login用)
        if($safe==true){
            $reg_password='';
            //ロード
            $info_lines=0;
            $fp = fopen($reg_path, "r");
            while ($line = fgets($fp)) {
                $info_lines=$info_lines+1;
                if($info_lines==1){$reg_password=trim($line);}
            }
            fclose($fp);
        }
        //トークン判定(relogin用)
        if($form_token<>''){
            //ファイルからトークンの内容を読み込む
            $saved_ip=utTokenRead($user_token_path,1);
            $saved_token=utTokenRead($user_token_path,2);
            //比較
            if($form_token==$saved_token){
                $login=1; //ログイン済み
                $form_command='home';
                $token=$form_token;
            }else{
                $short_error='再ログインの必要があります。';
            }
        }
    }
?>
<?php //--------ログイン判定処理(login)--------
if($form_command=='login'){

    if($safe==true){
        //password判定
        if($reg_password==$login_password){
        //(一致)
            //トークン作成
            $token='t'.rand(100000000000,999999999999);
            //トークン保存
            $fp = fopen($user_token_path, "w");
            fwrite($fp, $ip."\n");//1行目:ip
            fwrite($fp, $token."\n");//2行目:token
            fclose($fp);
        }else{
        //(不一致)
            $safe=false;
            $short_error='パスワードが一致しません。';
        }
    }
    if($safe==true){
    //ログイン成功
        $login=1; //ログイン済み
        //cookie記憶
        $cookie_aid=$account_id;
        $cookie_token=$token;
        utCookieUpdate($cookie_aid,$cookie_token);
    }else{
    //ログイン失敗
        //※そのままhome表示判定へ進む(beforeに移行する)
    }
}
?>
<?php //--------共通処理:ページ開始--------
    //head
    echo "<head>";
    $pagetitle=$main_title.'/'.$sub_title;
    $pageurl=$url_index;
    //基礎設定
    utHeadBasic($pagetitle,$pageicon,480);
    //OGP設定
    utHeadOgp($main_title,$main_title,$pagetitle,$pageurl,$ogppicture);
    echo "</head>";
    //body冒頭
    echo '<body>';
    echo '<b><a href="'.$url_index.'">'.$main_title.'</a></b><br>';
    echo '<br>';
    echo '<b>'.$sub_title.'</b><br>';
    echo '<br>';
?>

<?php //--------home表示判定--------
if($login==1){
    //ログイン済みの場合
    echo '<b>ログイン情報(仮)</b><br>';
    echo '・ID: '.$account_id.'<br>';
    echo '・IP: '.$ip.'<br>';
    echo '・Token: '.$token.'<br>';
    //フォーム表示
    echo '<form action="'.$url_home.'" method="post">';
    echo '<input type="hidden" name="form_command" value="home">'; //home
    echo '<input type="hidden" name="account_id" value="'.$account_id.'"'; //account_id
    echo '<input type="hidden" name="token" value="'.$token.'">'; //token
    echo '<input type="hidden" name="refresh_count" value="'.$refresh_count.'">'; //再表示回数
    echo '<br>';
    echo '<input type="submit" name="refresh" value="遷移テスト"> ';
    echo '<input type="submit" name="logout" value="ログアウト">';
    echo '</form>';
}else{
    //未ログインの場合
    $form_command='before'; //ログイン前/受付へ戻す
}
?>

<?php //--------ログイン前/受付(before)--------
if($form_command=='before'){
    //フォーム表示
    if($short_error<>''){
        echo '・ログイン失敗: '.$short_error.'<br>';
    }
    echo '・ログインするアカウントのIDと、パスワードを記入して[ログイン]してください。<br>';
    echo '<br>';
    echo '<form action="'.$url_home.'" method="post">';
    echo '<input type="hidden" name="form_command" value="login">';
    echo 'ID(半角英数字)<br>';
    echo '<input type="text" name="account_id" size="30" required placeholder="半角英数字でIDを記入" value="'.$auto_aid.'"></p>';
    echo 'パスワード(半角英数字)<br>';
    echo '<input type="text" name="login_password" size="30" required placeholder="半角英数字でパスワードを記入" value="'.$auto_password.'"></p>';
    echo '<input type="submit" name="send" value="ログイン">';
    echo '</form>';
}
?>

<?php //共通処理:締め
    echo '<b>デバッグ情報</b><br>';
    echo '*refresh_count: '.$refresh_count.'<br>';
    echo '*cookie_aid: '.$cookie_aid.'<br>';
    echo '*cookie_token: '.$cookie_token.'<br>';
    echo '</body>';
?>

この記事が参加している募集

この記事が気に入ったらサポートをしてみませんか?