PHP 複数選択可能なフォーム要素の$_POSTでの受け取り方

PHPでは

で送信されたフォーム要素を$POST['name属性']で取得できるが、 チェックボックスのように複数選択可能なフォーム要素の場合、単純に$POST['']で受け取っても選択された値のうち一つしか取得できない。

回答を複数持つフォーム要素には、送信元のformタグでも複数選択であることを[](ブラケットという)で明示する。これによって、ポストされた要素の値が配列でPHPに渡されることになる。

以下は好きな果物を選択するチェックボックスの例。

f:id:daily-coding:20181023182750p:plainf:id:daily-coding:20181023182758p:plain

form.php(送信元)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Check Box</title>
</head>
<body>
  <form action="check2.php" method="POST">
    <input  id="fruits" type="checkbox" name="fruits[]" value="りんご"> //fruitsに[]をつける
    <label for="fruits">りんご</label>
    <input  id="fruits" type="checkbox" name="fruits[]" value="みかん"> //fruitsに[]をつける
    <label for="fruits">みかん</label>
    <input  id="fruits" type="checkbox" name="fruits[]" value="ぶどう"> //fruitsに[]をつける
    <label for="fruits">ぶどう</label>
    <input type="submit" name="" value="送信">
  </form>
</body>
</html>

answer.php(送信先)

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>Answer</title>
</head>
<body>
  <p>選択されたのは <?= implode(',', $_POST['fruits']); ?> です。</p>
</body>
</html>

便宜上エスケープ処理の記述は省いています。

Javascript 同じクラス名がついた複数要素から、特定の要素を取得する方法

例として親要素Boxesの中に3つのboxがあり、個々のboxにimage画像とtextを記述したhtmlを見てみる。

img属性はBoxクラスの最初の子要素であるため、children[0]で取得できる。(要素は0からカウント)

さらにその下のdiv要素は、Boxクラスの2番目の要素であるため、children[1]で取得できる。

index.html

<body>
  <div class="Boxes">
    <div class="Box">  //Boxes[0]で取得できる
      <img src="box0.png">  //Boxes[0].children[0]で取得できる
      <div class="box0">Box0</div>  //Boxes[0].children[1]で取得できる
    </div>
    <div class="Box">  //Boxes[1]で取得できる
      <img src="box1.png">  //Boxes[1].children[0]で取得できる
      <div class="box1">Box1</div>  //Boxes[1].children[1]で取得できる
    </div>
    <div class="Box">  //Boxes[2]で取得できる
      <img src="box2.png">  //Boxes[2].children[0]で取得できる
      <div class="box2">Box2</div>  //Boxes[2].children[1]で取得できる
    </div>
  </div>
</body>
<script src="main.js"></script>
</html>

javascriptのオブジェクトの定義方法

javascriptのオブジェクトの定義方法についてめも。

例:

var user = {
    name: "yamada", //プロパティ
    email: "yamada@gmail.com",
    greet: function(name) { // メソッド
        console.log("hello, " + name + " from " + this.email);
    }
};

//値へのアクセス方法
console.log(user[name]); //結果 yamada
console.log(user.name);  //結果 yamada
//値の書き換え方法
user.name = "tanaka";
console.log(user.name); //結果 tanaka
//メソッドの呼び出し方法
user.greet("matuda"); //結果 hello, matuda from yamada.email

name: "yamada"のようなキーとバリューのセットのことを「プロパティ」と呼ぶ。 greet: function()~のように、関数を定義している部分は「メソッド」と呼ぶ。

thisは今自分がいるオブジェクト自信を指す。ここではuserのこと。

URLパラメーターとは。

URLパラメーターとは?

サーバーに情報を送るためにURLの末尾に付け加える変数のこと。 指定した値によって遷移先のページの内容が変化。

例) http://example.com/?name=Charie

「?パラメーター=値」の形式で送る。

PHPでのパラメーターの取得方法

$_GETの定義済み変数でパラメーター部分を取得できる。

例)

<?php
echo 'Hello ' . htmlspecialchars($_GET["name"]) . '!';
?>

ユーザーが http://example.com/?name=Charie と入力したとすると、結果は

Hello Charie !

となる。

参考: http://php.net/manual/ja/reserved.variables.get.php

PHP エラー Notice: Undifined offsetの意味

Notice: Undifined offset 

配列に対して存在しない要素を表示させようとした時にでる。

例)

<? php
$animals = [ 'dog', 'cat', 'monkey' ];
echo $animals [ 3 ]  // 結果 エラー

上の配列は、0~2までの要素しかないのに対して、存在しない3の要素を表示させようとしているので、Undifined offsetのエラーがでる。

CSRF対策としてのPHPでのトークン発行方法

トークンの発行方法を勉強する機会があったのでメモ。

CSRFとは?

CSRF:Cross-site Request Forgery(クロスサイト リクエスト フォージェリ)の略。 日本語にすると「リクエスト強要」ということらしい。

悪意のある第三者Webサービスの利用者に意図しないHTTPリクエストを送信させ、サービス提供側が意図しない処理を実行させること。

forjeryは「偽造」という意味。

対策方法としてのトークン発行

CSRF対策方法の一つとして、トークンを利用するやり方がある。

Webサービスに何らかのフォームを設置する場合、

① あらかじめセッション(通信の一連の処理)に推測されにくい文字列(トークン)を格納しておき、

② ユーザーがフォーム送信する際に、フォームからもセッションに格納されたトークンを引っぱってきて送信

③ サーバー側でセッションの中のトークンとフォームから送られてきたトークンが一致するかをチェックする

これによってフォームから変なデータを受け取らないようにする。

PHPでのトークン発行方法

index.php  フォーム側のコード例

<?php

session_start(); //セッションを開始

require_once(__DIR__ . '/Hoge.php');

?>
<!DOCTYPE html>
<html lang="ja">
<body>
  <div id="container">
    <h1>Sample Site</h1>
    <form action="">
      <input type="text">
      <input type="hidden" id="token" value="<?= h($_SESSION['token']); ?>"> //hiddenでセッションからとったトークンを一緒に送信
      <input type="submit" value="送信">
    </form>
  </div>
</body>
</html>

Hoge.php  サーバー側の処理例

<?php

class Hoge {

  public function __construct() {
    $this->createToken(); //トークン発行のメソッドを呼び出し
  }

  //トークン発行(メソッドとしてまとめておく)
  private function createToken() {
    if (!isset($_SESSION['token'])) { //トークンがセットされていなかったら
      $_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(16));
    } //32桁のトークンを発行
  }

  //フォームが送信されたら
  if ($_SERVER['REQUEST_METHOD']==='POST') {
    $this->validateToken(); 
  }

  //トークンの照合
  private function validateToken() {
    if (
      !isset($_SESSION['token']) ||  //トークンがセットされていない場合
      !isset($_POST['token']) || //トークンが送信されていない場合
      $_SESSION['token'] !== $_POST['token']  // 両者が一致しない場合
    ) {
      throw new \Exception("invalid token!"); //バリデーションエラーとする
    }
  }

}