ネイティブなPHPでselectタグやradioボタンの選択状態をどう表現するか
WordPress等のCMSやそれに伴うプラグイン(ないしアドオン)というものは実に便利なもので、一つ一つのタグを書かずともテンプレート関数やテンプレート文字列などを使えば、すぐさまselectタグやradioボタンを設置し、リクエストされたフォームのデータを処理して表示を反映できる。
そのため、いざネイティブなPHPのレベルでこの処理を作成して反映する際に、単純なPOST・GET・SESSIONの通信データを、件のタグに選択状態として表現するということができない人が増えていると近今感じている。
特にこれはデザイナーさんや静的ページ主体のコーダーさん等、業務の中でなんとな~くWordPress等を触り始めた人によくよくありがちなパターンで、インターネット黎明期からの昔ながらのWeb屋からしてみればちょっと由々しき事態。
分業化が進んだ現場中においてはある程度仕方のない部分であるにしても、今回はそういった人向けの記事として書き残しておくことにする。
さて、まずはselectタグやradioボタン以前にフォームの送信の処理というもの。
実は、PHPを教材として学生が習得する中においては、かなり初期の段階で触れられる最も基本的なカリキュラムである。
カリキュラム中のタイミングとしては、PHP上の変数の仕組みやechoやprint等の出力・取得系の最も初歩的な段階が終わったその次に必ず触れられる。
習作で何らかのPOST・GETの送信プログラムを作るにしても、データベースを介さずにSESSIONを利用したログイン画面を作るにしても、絶対に必要となるもの。
なんにしても、これを確実に処理できなければ、CMSでもテンプレート範囲外のちょっとしたデータのやり取りが発生したときに処理ができないし、CMSの限界に気付いていざネイティブなところに行こうとしたときに初っ端から挫折・頓挫することになる。
そのことを念頭において、まずは基本から書いていこうと思う。
まず、selectタグやradioボタンに行く前に、そもそもフォームから送信されるデータの基本としてテキストフィールドでの単純なHTMLを書いてみる。
<!-- GETの場合 --> <form method="get" action="xxx.php"> <!-- POSTの場合 --> <form method="post" action="yyy.php"> <input name="data" type="text" value="" /> <!-- ここには「TEST」を入力するものとする --> <input name="send" type="submit" value="送信" /> </form>
このとき、name=”data”のテキストフィールドに「TEST」を入力して、これを送信した際にPHP上ではどう扱われるか。
GETで送信したデータはこのように扱われる。
<?php // 送信されるデータはグローバル変数$_GETに入る // 加えて、URL欄の表記上は「http://ドメイン/xxx.php?data=テスト」 var_dump( $_GET['data'] ); // この結果は「TEST」 ?>
また、POSTで送信したデータはこのように扱われる。
<?php // 送信されるデータはグローバル変数$_POSTに入る var_dump( $_POST['data'] ); // この結果は「TEST」 ?>
これらをinputタグに戻す場合は、当該のname=”data”を以下のように書く。
<!-- GETの場合 --> <input type="text" name="data" value="<?php $_GET['data']; ?>" /> <!-- POSTの場合 --> <input type="text" name="data" value="<?php $_POST['data']; ?>" />
・・・ここまでがテキストフィールドでのフォームの基本知識。
基本知識を踏まえたところで、これを問題のselectタグやradioボタンに焼き直す場合、どのようにしたらいいだろうか。
HTMLだけの知識だけならば、以下のように書けば結果を得られるだろうと恐らく誰しもが考える。
<!-- selectタグの場合 --> <select name="data"> <option value="">未選択</option> <option value="TEST">テスト</option> </select> <!-- radioボタンの場合 --> <label><input type="radio" name="data" value="" /> 未選択</label> <label><input type="radio" name="data" value="TEST" /> テスト</label>
上記でselectタグやradioボタンで「テスト」の項目を選択して送信すれば、value値の「TEST」の送信自体は行われる。
送信されたデータそのものとしては、確かに「TEST」となるが、これだけでは目的の結果は得られない。
フォーム送信後の画面では、いずれも「未選択」の状態になる。
CMS的思考であれば、inputタグにname=”data”を入れてるんだから、自動的にvalue値はHTMLに戻ってくるのでは!?PHP本体のバグやんけ!プンプン!
・・・と思うだろうけれど、それは間違いなくありえません。
フォームで投げ込まれたデータを処理するのは全て*あなた*です。
これはCMSがどーとかってとこに関わらず、PHPを触り始めたときでもよくありがちな間違いだったりする。
自分も未だに稀に設定を忘れていて、見返してみたときに「あれ?」ってなるパターンもあるし。
基本知識のテキストフィールドを振り返るところで、value=”<?php $_GET[‘data’]; ?>”とかvalue=”<?php $_POST[‘data’]; ?>”とかしていたのはこのため。
$_GETや$_POSTと言うのはグローバル変数とは言え、ただの変数。
フォームの項目の情報や表示のデータを保持してHTMLで指定のnameが設定されているところに自動でセットしてくれる・・・な~んて便利機能は、変数である以上は当然ないわけです。
ただし、どのデータで何を飛ばしたかの情報はきちんと保持されており、
<?php var_dump( $_GET ); // array(1) { ['data']=> 'TEST' } var_dump( $_POST); // array(1) { ['data']=> 'TEST' } ?>
送信されたデータを覗いてみると、このようになっていることは確認できると思う。
そのため上記で、正確な結果を単純に得ようとする場合、以下のように書けばいい。
<!-- selectタグの場合 --> <select name="data"> <option value="" <?php echo '' === $_GET['data'] ? 'selected="selected"' : ''; ?>>未選択</option> <option value="TEST" <?php echo 'TEST' === $_GET['data'] ? 'selected="selected"' : ''; ?>>テスト</option> </select> <!-- radioボタンの場合 --> <label><input type="radio" name="data" value="" <?php echo 'TEST' === $_GET['data'] ? 'checked="checked"' : ''; ?> /> 未選択</label> <label><input type="radio" name="data" value="TEST" <?php echo 'TEST' === $_GET['data'] ? 'checked="checked"' : ''; ?> /> テスト</label>
または、これらの出力をテキトーに効率化したい場合は、
// $_POSTで行うものとした場合 $data = isset( $_POST['data'] ) ? $_POST['data'] : ''; // 選択肢のリストは今回は単純に配列で $data_array = array( 'none' => '未選択', 'TEST' => 'テスト', 'TEST1' => 'テスト1', 'TEST2' => 'テスト2', 'TEST3' => 'テスト3', ); // selectタグ $select = ''; $select .= '<select name="data">'; foreach ( $data_array as $key => $val ) { $ckey = 'none' === $key ?_'' : $key; $select .= '<option value="' . $ckey . '"'; $select .= $ckey === $data ? ' selected="selected"' : ''; $select .= '>' . $val . '</option>'; } $select .= '</select>'; echo $select; // radioボタン $radio = ''; foreach ( $data_array as $key => $val ) { $ckey = 'none' === $key ?_'' : $key; $radio .= '<label><input type="radio" name="data" value="' . $ckey . '"'; $radio .= $ckey === $data ? ' checked="checked"' : ''; $radio .= ' />' . $val . '</label>'; } echo $radio;
みたいな感じにもできたりする。
ちなみに今回の記事の主体は択一選択のselectタグとradioボタンだけど、同じような感覚でcheckbox選択とかの項目が複数に及ぶ場合でも考え方の使い回しは利く。
そこについては割愛するが、その場合はname=”data[]”を設定してみて、あとはこれをPHPのin_array()関数などで照合して適宜checkedすればいい。
直近でこちらの記事のコメントで少しやり取りさせていただいたのもあったので、今回の記事を書いた次第。
自分も初心に戻って色々得られたので、感謝(´・ω・`)
さて、いつもどおりここから少しだけ雑談。
しばらく記事の投稿が滞っていたのは、全国緊急事態宣言で話題の新型コロナウイルスにかかっていたとかではないです。(風邪一つなくピンピンしており、平常運行です。)
じゃあ何故、音沙汰がなかったのかと言うと・・・
PHPでの小数計算のロジック組んでました。
Xserverあたりじゃねーとレンサバのスペック的にシステム動かすには物足りないかなと思っていたけど、やっぱり他社2サーバーくらいは持ち回り使えるようにするべきだよなと思って、さくらのレンタルサーバーでも使えるようにしようと思ったら・・・
BC Math拡張が使えへん!!(怒)
BC Mathってさくらレンタルやとサポートされてないんかいwww
カンマ以下有り単価集計とか消費税小数点第二位以下表記とか、どうやって計算なり桁丸めなりするんじゃあぁぁ!!
・・・ってなわけで、両サーバー共に使えるGMP拡張で小数を計算するロジック組んでた。
入れる値は小数文字列だとか、整数bitにしてから再度小数に戻すとか、各種演算だとか、端数処理だとか色々やってたら、それなりに結構な時間が経っていた模様。
まさか、この歳になって数学的なことをやるだなんてよもや夢にも思わんかった・・・。