佐伯のメモ書き

やったことの覚え書きとか

投票を考える

昨日ちょっと時間食ったけど分かってれば別にそんな苦労しなかったんじゃ?
最終的なデバッグも実は大分適当にしたのでエラーが出るかもしれない。

前提条件

  • 名簿用のデータベースがある(MySQL
  • 名簿に登録されている人しか投票出来ない
  • 二重投票は不可能
  • 択一投票

投票結果はCSVに出して後々集計しやすいようにしたい。

先に結論

データベースに登録された名前と入力された名前で重複チェック

→重複があればオーケー

集計CSVに書き込まれている名前と入力された名前で重複チェック

→重複があるとNG

を全部if文で繋いだ。絶対もっといい方法あると思う。

投票画面

択一投票なので一個だけ選択出来るように(他の選択肢を選んだ時にチェックアウトする)ようにしておく。

checkboxで二個以上選択の時にエラーだしてもいいけど面倒臭いややこしいのでradioを採用。

HTML

<form action="" method="POST">
    <!--投票先選択-->
    <label>
        <input type="radio" name="vote" value="A">
        <span class="check">投票</span>
    </label>
    <label>
        <input type="radio" name="vote" value="B">
        <span class="check">投票</span>
    </label>
    <label>
        <input type="radio" name="vote" value="C">
        <span class="check">投票</span>
    </label>
    <!--記名-->
    <input type="text" name="name" placeholder="名前">
    <!--送信ボタン-->
    <input type="submit" name="send" value="送信"> 
</form>

CSS

input[type="radio"]{
    display:none;
}
.check{
    display: block;
    width:5em;
    margin:10px auto;
    text-align: center;
    font-size:13px;
    background-color: #aaaaaa;
    letter-spacing: .1em;
}
input[type="radio"]:checked + .check{
    background-color: #000000;
    color:#fff;
    font-weight: bold;
}

ラジオボタンそのままは味気ないので display:none で隠し
<label>~</label> で括って <span class="check">投票</span> の部分と連動させています。
input[type="radio"]:checked + .check の部分でチェックが入った時に <span>投票</span>の色とかが変わるようになっています。
<input type="radio">はname属性に同じものを設定することで択一選択が可能になります。
checkboxは複数選択になるのでその辺はまあ使い方次第で。

集計プログラム

ここからはPHPで書くので、レンタルサーバーのPHP使えるプランとかじゃないと意味ないです。
レンタルスペース(XRIEとかナノとか)って手軽だけどこういうことが出来たりするのはやっぱりレンタルサーバーが楽しいなと思う次第。
CSSはレンタルスペースでも使えると思うのでもしよかったらなんかに使って下さい。

<?php
$path = 'vote.csv'; //出力先ファイルのパス
$title = ["day","name","A","B","C"]; //ヘッダー
$date = date('m/d'); //日付
$error = '' //エラーメッセージの初期化

if(isset($_POST['send'])){ //name="send"が押された時
    //エラーチェック
    if(empty($_POST['name'])){ //name="name"が空白の時
        $error = '<span class="error">無記名投票です。やり直してください</span><br>';
    }elseif(empty($_POST['vote'])){ //name="vote"が空白の時
        $error = '<span class="error">投票先を選択してください</span><br>';
    }elseif(!in_array($_POST['name'],$name)){ //名簿との重複チェック。後述
        $error = '<span class="error">名前が存在しません</span><br>';
    }elseif(in_array($_POST['name'],$list)){ //集計との重複チェック。後述
        $error = '<span class="error">投票が重複しています</span><br>';
    }else{
    //エラーがない時の処理
    //集計しやすいように数字での置き換え
        if($_POST['vote'] == 'A'){
            $vote=array($date,$_POST['name'],'1','0','0');
        }else if($_POST['vote'] == 'B'){
            $vote=array($date,$_POST['name'],'0','1','0');
        }else{
            $vote=array($date,$_POST['name'],'0','0','1');
        }
        //出力先ファイルの存在チェック
        if(!file_exists($path)){ //ファイルがないとき
            $file = new SplFileObject($path,"w");
            $file -> fputcsv($title); //ヘッダーを記入
            $file = new SplFileObject($path,"a");
            $file -> fputcsv($vote); //データを追記
        }else{ //ファイルがあるとき
            $file = new SplFileObject($path,"a");
            $file -> fputcsv($vote); //データを追記
        }
        $error = '<span class="clear">投票が完了しました!</span><br>';
    }
}
?>

重複チェック

名簿データと集計データにそれぞれ重複チェックをかけます。
これしとかないと何回でも投票できるようになってしまうので公平性に欠ける。
名簿データは取り敢えずこんな感じ。

id name
1 あいうえお
2 かきくけこ
3 さしすせそ
4 たちつてと

テーブル名:user

データベース編

<?php
//データベース接続メソッド
function PDOconnect(){
	try {
        $dbh = new PDO ('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',DB_USER,DB_PASS);
        $id = 1;
	} catch (PDOException $e) {
        $dbh->rollback();
		var_dump($e);
		exit;
	}
	return $dbh;
}

//SQLでDB検索
$dbh = PDOconnect();
$sql = ('SELECT name FROM user');
$stmt = $dbh->prepare($sql);
$stmt->execute();
foreach ($stmt as $row){
    //繰り返し処理で名前だけを配列に格納
    $name[] = $row['name'];
}
?>

集計リスト編

<?php
$path = 'vote.csv'; //出力先ファイルのパス

//そも論ファイルが無いと意味ないのでファイルがある時の処理から書く
if(file_exists($path)){
    $csv = file($path); //ファイルの中身を配列に格納
    $csv_header = $csv[0]; //ヘッダーを削除
    $csv_body = array_splice($csv, 1);
    
    foreach ($csv_body as $row) { //繰り返し処理で名前を配列に格納
        $row_array = explode(',', $row);
        $list[] = $row_array[1];
    }
}else{
    $list = ""; //ファイルが無い時に配列を初期化(しないとエラーが出る)
}
?>

これで$nameデータベースの登録名$list投票済の名前が格納されていることになる。
間違ってなかったら、なんですけどね。少なくとも私は出来た。

in_array指定した配列の中に指定したワードが含まれていないかどうかを判断しています。
PHPは!in_arrayなどびっくりマークから始まると否定の意味になります。
なので!in_arrayは『配列に含まれない』だし!==は『等しくない』なんですよね。慣れないとややこしいかもしれない。

全体コード

<?php
$path = 'vote.csv'; //出力先ファイルのパス
$title = ["day","name","A","B","C"]; //ヘッダー
$date = date('m/d'); //日付
$error = '' //エラーメッセージの初期化

//データベース接続メソッド
function PDOconnect(){
	try {
        $dbh = new PDO ('mysql:host='.DB_HOST.';dbname='.DB_NAME.';charset=utf8',DB_USER,DB_PASS);
        $id = 1;
	} catch (PDOException $e) {
        $dbh->rollback();
		var_dump($e);
		exit;
	}
	return $dbh;
}

//SQLでDB検索
$dbh = PDOconnect();
$sql = ('SELECT name FROM user');
$stmt = $dbh->prepare($sql);
$stmt->execute();
foreach ($stmt as $row){
    //繰り返し処理で名前だけを配列に格納
    $name[] = $row['name'];
}

//そも論ファイルが無いと意味ないのでファイルがある時の処理から書く
if(file_exists($path)){
    $csv = file($path); //ファイルの中身を配列に格納
    $csv_header = $csv[0]; //ヘッダーを削除
    $csv_body = array_splice($csv, 1);
    
    foreach ($csv_body as $row) { //繰り返し処理で名前を配列に格納
        $row_array = explode(',', $row);
        $list[] = $row_array[1];
    }
}else{
    $list = ""; //ファイルが無い時に配列を初期化(しないとエラーが出る)
}

if(isset($_POST['send'])){ //name="send"が押された時
    //エラーチェック
    if(empty($_POST['name'])){ //name="name"が空白の時
        $error = '<span class="error">無記名投票です。やり直してください</span><br>';
    }elseif(empty($_POST['vote'])){ //name="vote"が空白の時
        $error = '<span class="error">投票先を選択してください</span><br>';
    }elseif(!in_array($_POST['name'],$name)){ //名簿との重複チェック。後述
        $error = '<span class="error">名前が存在しません</span><br>';
    }elseif(in_array($_POST['name'],$list)){ //集計との重複チェック。後述
        $error = '<span class="error">投票が重複しています</span><br>';
    }else{
    //エラーがない時の処理
    //集計しやすいように数字での置き換え
        if($_POST['vote'] == 'A'){
            $vote=array($date,$_POST['name'],'1','0','0');
        }else if($_POST['vote'] == 'B'){
            $vote=array($date,$_POST['name'],'0','1','0');
        }else{
            $vote=array($date,$_POST['name'],'0','0','1');
        }
        //出力先ファイルの存在チェック
        if(!file_exists($path)){ //ファイルがないとき
            $file = new SplFileObject($path,"w");
            $file -> fputcsv($title); //ヘッダーを記入
            $file = new SplFileObject($path,"a");
            $file -> fputcsv($vote); //データを追記
        }else{ //ファイルがあるとき
            $file = new SplFileObject($path,"a");
            $file -> fputcsv($vote); //データを追記
        }
        $error = '<span class="clear">投票が完了しました!</span><br>';
    }
}
 ?>
<html>
    <head>
        <link rel="stylesheet" href="vote.css">
    </head>
    <?php echo $error ?>
    <body>
        <form action="" method="POST">
            <!--投票先選択-->
            <label>
                <input type="radio" name="vote" value="A">
                <span class="check">投票</span>
            </label>
            <label>
                <input type="radio" name="vote" value="B">
                <span class="check">投票</span>
            </label>
            <label>
                <input type="radio" name="vote" value="C">
                <span class="check">投票</span>
            </label>
            <!--記名-->
            <input type="text" name="name" placeholder="名前">
            <!--送信ボタン-->
            <input type="submit" name="send" value="送信"> 
        </form>
    </body>
</html>

大体こんな感じかな。こんな感じだわ、多分。
ていうかこのシンタックスハイライトの色なんとかならんか??