佐伯のメモ書き

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

PHPのローカル開発について考える

そもそも論的にこれを話しておかなければならないのではないか?と思った次第。
出来るだけ簡単な方法を使おうと思います。

ローカル開発ってなんやねん

自分のPC内でプログラミングを行うことです。
結論から申し上げるとPHPはHTMLやCSSのように、何もないままパッと表示することが出来ません
PHPという言語パックをPCに導入しておかなければ見れないのです。
無料DLCみたいなもんだよ、分かるだろ。
要するに外部に出さず自分のPC内のみで開発する、これをローカル開発というわけです。

レンタルサーバーも利用できるプランじゃないとPHPは使えません。
使わないひとからするとなんじゃらホイなんですけど、もしも興味がある人はPHPを使えるプランで借りてみて下さい。
ロリポップもエコノミー(100円/月)から使えるみたいですね。
私はSSDMySQLが使いたいのでスターサーバーのライト(200円/月額)を借りていますけど。

ローカルの開発環境を作っておかないと結果を見るのにいちいちサーバーにアップロードしなければならないんですよね。
当然クソ程面倒臭いので、サーバーにアップロードせずとも自分のPC内で結果を見たり出来るようにしておきます。
(解説にめちゃくちゃ齟齬があったりしますが大目に見て下さい)

XAMPPを入れる

PHPを開発するにあたり入れるものは色々あります。

  • PHPの言語パック
  • Apache(表示用のサーバー)
  • MySQL(データベース)(使わないなら要らないが)

これを全部入れてパスを通してとか正味めちゃめんどい。マジでめんどい。
一回弊社ちゃんで入れたことあるけどクソ程面倒だった。

ので
XAMPPを入れて下さい。
PHPの開発環境オールインワンって感じです。これ入れるだけで全部使える。有能オブ有能。
今言ってるのはあくまでもWindows環境なのでMacの人は独自で調べてくれ。

データベースとかも入るのでPCの容量少ない人は頑張ってバラで入れる方がいいのかもしれない。

XAMPPを動かす。

この辺とか見て欲しい。
自分のPCにXAMPP入れたの云万年前な上に必要不可欠だからこそ最早息をするように設定組んでるので覚えてないんだ。
ちな、私はいつもApacheMySQLだけ動かしてます。Tomcatとかは仕事でしか使わんすね。

余談

私は基本PHP+データベースの環境を前提で制作しています。
最初の方に挙げたロリポのエコノミーはPHPこそ使えますけど、データベースはついてないプランなので
『はいここでデータベースつかいま~~す!!』みたいなやつになると途端に使えなくなってしまいます。
ご注意あそばせ。

この辺で締め

わたしがTwitterとかで良く言うPHPについてのお話でした。
そも論、PHPというのはサーバーサイド言語というやつで、ざっくり簡単に言ってしまえば裏っ側の処理をするための言語です。
レンタルスペースのメールフォームや、名前変換機能とかもこの言語で作られています。
言い換えると、PHPを使えるようになればレンタルサーバーを使って夢小説サイトを作ることも出来るわけです。
そう考えるとちょっと楽しくないですか?わたしは楽しい。

プログラミングというと途端にハードルが高く感じるかもしれませんが、HTMLもCSSプログラミング言語です。
英語とスペイン語みたいなもんや。多分。どっちも外国語だけど英語の方がハードル低めに感じる的なね。
機会がある人はぜひ遊んでみて下さい。

限定コンテンツについて考える①

古のオタクにも昨今のオタクにも馴染み深い限定コンテンツ。
使うのは簡単だけど、いざ仕組みについてのつまりどういうことだってばよ??をざっくり感で。

ざっくりした限定コンテンツの定義

広義に捉えてパスワードを知っている人ならというアレで行こうと思います。

  • 同じジャンルの人
  • フォロワー
  • 友人
  • 教えた人だけ

そういうのもまあなんでも良いんだけど、考え方としては
入力したものが設定したものと一致するなら表示するという感じになる。
ここにデータベースを使ったりなどして作り込んでいくと『会員登録をした人のみ』とかいう話になる。

ざっくりしたソース

<?php
    $pass = 'オレ';
    if($_POST['pass'] == $pass){
        // ここに正解時の表示
    }else{
        // ここに不正解時の表示
    }
?>
<p>Q.〇〇は自分が大好きなんだ</p>
<form action="" method="POST">
    <input type="text" name="pass">
    <input type="submit" value="送信">
</form>

$passに定義した文字とinputで書き込んだ文字が一致したら表示するという至極簡単なつくりのやつ。
if~は文字の通り『もしも〇〇ならば』という関数。==というのは左右が完全に一致する場合の意。

そもそものif構文
<?php
    if(判別式A){
        // ここにAの時の出力内容
    }elseif(判別式B){
        // ここにBの時の出力内容
    }else{
        // ここにAでもBでも無いときの出力内容
    }
?>

ちな、これはめちゃどうでもいいんやけど、文頭を下げることを『インデント』といいます。
これをすることによって『どの部分が』『何の配下』かというのが分かりやすくなるわけです。
分かりやすくしておけば

  • 見返した時に分かりやすい(可読性が高い)
  • 処理漏れをしにくくなる

とか結構メリットが多いです。HTMLにありがちな所謂ところの『閉め忘れ』というのも減るし。

言い換えるとインデントをしていると当然余分な改行が増えるので大体のテンプレサイトさんで『自動改行なしで作成しとくれやす』という話になるわけ。
前にHTMLとかを全く知らないフレンズに『なんで段々にするのお~(´・ω・`)?』と聞かれたのでそういえばそうだわなと思ったのを今思い出した。案外誰も教えてくれないこういうの。

IF文があるだけで出来ることがぐっと増えるというかややこしいことが出来るようになるので私はIF文使うのすきです。

投票を考える

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

前提条件

  • 名簿用のデータベースがある(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>

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