PHP – 複数のsubmitで処理を分ける

概要

複数のsubmitから異なるターゲットに遷移するには、formタグでaction属性を設定せず、それぞれのinputでformacion属性を設定する。

一つのターゲットで異なるsubmitごとの処理を分けたいときは、それぞれのinputにname属性を設定し、PHP側のissetでそれぞれが定義されているかどうかによって処理を分けるとよい。

以下のHTMLでは3つのsubmit(送信1、送信2、その他の送信)を配置し、前者2つにはname属性の値として”submit1″、”submit2″を設定し、その他の送信にはname属性を設定していない。

以下はこれを受け取るPHPコードで、isset()によって$_POST['submit1']$_POST['submit2']が定義されていればそれぞれに対応した処理をし、それ以外の場合には「その他の送信」としている。

実行すると3つの送信ボタンが表示され、それぞれを押すとボタンに対応したメッセージが表示される。

 

PHP – 雛形 – 現在日付・時刻

現在の日時の取得

date()関数は引数で指定したフォーマットで日付・時刻の文字列を返す。たとえば現在の日付・時刻の文字列は以下で得られる。

date('Y-m-d H:i:s')

フォーマット文字列の詳細はPHP-manualを参照。

現在のUNIXタイムスタンプ

time()関数はUnix エポック (1970 年 1 月 1 日 00:00:00 GMT)からの通算秒をintで返す。PHP-manual

 

 

PHP – ドキュメントルート外のファイル

スタイルファイル(css)

HTMLのスタイルを別のcssファイルにするとき、ファイルの位置がドキュメントルートの外にあるとlinkタグからは読み込めない。

このようなとき、style定義であればstyle要素の内容としてphpでそのファイルをincludeするとHTML内に展開される。

 

PHP – PDO プリペアードステートメント

基本形

  • $pdo = new PDO()PDOオブジェクトを得る
  • $stmt = $pdo->prepare()でプレースホルダー入りのSQLを準備する
  • $stmt->bindValue()$stmt->bindParam()でプレースホルダーを埋める
  • $stmt->execute()でバインドを有効化する

bindValueによる値の設定

'?'によるプレースホルダー

以下の例では、prepare()のSQL中2つの'?'がプレースホルダーになる。

bindValue()の第1引数は何番目のプレースホルダー'?'かを指定し、第2引数にそのプレースホルダーにセットする値を指定する。第3引数は省略するとPDO::PARAM_STRになる。

この結果、データベースのnum_datastr_dataにそれぞれ10, 'ABC'が追加される。

名前によるプレースホルダー

以下の例では、prepare()のSQL中':num'':str'の2つがプレースホルダーになる。

bindValue()の第1引数でそれぞれのプレースホルダーを指定し、第2引数にそのプレースホルダーにセットする値を指定する。第3引数は省略するとPDO::PARAM_STRになる。

この結果、データベースのnum_datastr_dataにそれぞれ20, 'DEF'が追加される。

bindParamによる変数の設定

bindValue()はプレースホルダーに値を設定したが、bindParam()は変数を設定する。

変数がバインドされた時点ではSQLの内容は決定されていない。変数に値をセットし、execute()を実行した段階でSQLの値が確定する。

この例では2つのプレースホルダーに変数をバインドし、その変数に値を与えてからexecute()を実行している。プレースホルダーに'?'を用いてもよい。

この結果、データベースのnum_datastr_dataにそれぞれ30, 'GHI'が追加される。

 

PHP – 雛形 – ファイルアップロード

概要

HTML側でアップロードされたファイルをPHP側で受け取り、妥当性のチェック、所定の場所への保存などを行う最低限の手順。

HTML側でのファイル選択

  • FORM要素でenctype="multipart/form-data"を指定する
  • INPUT要素でtype="file"を指定し、サーバー側で参照するためのname属性を設定する
  • 複数ファイルを送る場合はINPUT要素にmultiple="multiple"を指定する

HTML表示の際、デフォルトで”ファイルを選択”ボタンが表示され、これをクリックするとダイアログによるファイル選択が可能となる。

PHPで受け取る値

HTML側からの結果が受信されたとき、スーパーグローバル変数$_FILESに連想配列としてアップロードされたファイルの情報が格納される。以下、'name値'はINPUT要素で指定されたname属性の値。

$_FILES['name値']['error']
エラーコード。PHPで定義された定数でエラーステータスを確認可能。(PHP-manual)
$_FILES['name値']['name']
アップロードファイル名。
$_FILES['name値']['tmp_name']
アップロードされたファイルのフルパス。
$_FILES['name値']['type']
アップロードファイルのMIMEタイプを取得。たとえばimage/jpeg、image/pngなど。
$_FILES['name値']['size']
アップロードされたファイルのサイズ

PHP側の処理

INPUT要素を受け取ったPHP側での最低限の処理の流れは以下のとおり。

  1. $_FILES['name値']['error'] === UPLOAD_ERR_OKでアップロード時のエラーをチェック
  2. 以下の変数を設定
    • $image_file_name = $_FILES['name値']['name'];
    • $tmp_name = $_FILES['name値']['tmp_name'];
    • $type = $_FILES['name値']['type'];
  3. is_uploaded_file($tmp_name)でアップロードファイルの妥当性をチェック
  4. $type === 'image/jpeg' && $type !== 'image/png'でファイルタイプをチェック
  5. move_uploaded_file($tmp_name, IMAGE_DIR . $image_file_name);でアップロードされたファイルを任意のディレクトリー(この場合IMAGE_DIR)に移動
    • この実行結果のtrue/falseに応じてファイル名のデータベースへの登録などの処理を実行

$_FILES['name値']['type']ユーザーから送信されたものなので、偽装・改竄に対する完璧な防御にはならないが、上記は最低限の流れ。

 

PHP – GETの流れ

概要

GETメソッドの挙動・手順を確認した。

  • 普通にHTML/PHPファイルが呼ばれると、GETメソッドになる
  • なので初回起動時の処理はGETメソッド前提で、$_GET変数は定義済み、要素数0をチェック
  • $_GETの要素数が0より大きければ初回以降のGETメソッド処理
  • 初回以降の$_GETの要素チェックは''との比較でok

確認コード

以下のHTMLとPHPで動作を確認する。

HTML

  • フォームからGETメソッドで送信する
  • 送信するのはテキストボックスの内容のみ
  • PHP側で処理された$msgを出力する

PHP本体

  • 全体の処理開始以降、節目の経過を$msgに累積記録し、HTMLでの出力に備える

結果

初期起動時

HTMLの表示は以下の通り。

  • 起動時にGETで始まっている
  • そのため$_GET変数も定義済みになっている
  • ここには書いていないがvar_dumpで確認すると'Array  ()'となっている
  • ただし$_GETの要素数は0

このときブラウザーでのURL表示は以下のとおり。

起動後のGET時

テキストボックスに’abc’と入れて送信した結果が以下の通り。

このときブラウザーでのURL表示は以下のとおり。ファイル位置の後ろに?でパラメーターが加えられている。

なお、上記の実行後にはテキストボックスの内容は空になっている。

再度GETの実行時

このときのブラウザーでのURL表示は以下のとおり。

リロード時

ブラウザーのリロードで再読み込みをすると、最後に表示されていたURLのままでリロードされ、同じ結果が表示される。

?以降のパラメーター部分を消してリロードしても、元のパラメーターが付加されたURLに戻ってしまう。

パラメーター部分を消してENTER、つまり直接URLを入力すれば初期状態からスタートする。

改竄に対して

上記コードで、Chromeの検証ツールでinput要素のname属性を改竄した場合、元のisset($_GET['get_input'])が存在しなくなるのでチェックが必要。

まとめ

処理の流れ

初回起動時

  • ファイルを最初に実行する場合はGETメソッド
  • 初期起動時の$_GETは要素数0の配列

フォームからのGETメソッド

  • その後フォームからGETメソッドが実行されると、INPUT要素の内容がURLのパラメーターに付加されてページの最初から実行される

リロード時

  • ブラウザー機能でリロードしただけではURLはリフレッシュされず、直前のパラメーターで再実行される

GETのみの場合

処理全体を通してGETメソッドのみの場合、$_SERVERによるチェックは不要になる。

GET処理とPOST処理を併用する場合は、GET処理を切り分ける必要がある。

action属性

form要素のaction属性をaction="./get.php"と設定しても、リロード時には元のパラメーターが復活する。この属性はGETメソッドを指定したそのフォームからの送信でないと効果がない。

 

PHP/MySQL – トランザクション確認(PDO)

概要

PHPのオブジェクト型(PDO)でMySQLのトランザクションを確認。

トランザクション中の動作はデータベースステートメントには設定されるが、トランザクション終了後のコミット/ロールバックによって設定結果がデータベースに反映されるかどうかが決まる。

確認コード

  1. 5行目でトランザクションでコミットフラグをtrueにセット
  2. 通常モードで’one’を書き込み
  3. 14行目でトランザクション開始
  4. ‘two’, ‘three’を書き込み
  5. 25行目でコミット、トランザクション確定
    • 通常モードへは自動的に復帰

確認結果

以下、出力を見ながらトランザクションの動作を確認。

  • 通常モードでは普通に書き込み
  • トランザクション開始後、データベースステートメントの内容は指示通り設定
  • トランザクション終了後、データベース内容の変更が確認できる
  • 通常モード復帰後も普通に書き込み

以下は出力結果で、終了後のデータベースの内容は’one’, ‘two’, ‘three’, ‘four’となる。

次にコミットフラグを$commit=falseにすると、commit()メソッドではなくrollback()メソッドが実行され、実行結果は以下のようになる。

  • 通常モードで普通に’one’が書き込まれる
  • トランザクションに入り、データベースステートメントには’two’, ‘three’が設定される
  • トランザクション終了後にロールバックされると、データベースステートメントがデータベースに反映されてもトランザクション中の’two’, ‘three’は書き込まれない
  • 通常モードに復帰後’four’が書き込まれる

 

PHP/MySQL – トランザクション確認(mysqli)

概要

PHPの手続き型(mysqli)でMySQLのトランザクションを確認。

トランザクション中の動作はデータベースリンクには設定されるが、トランザクション終了後のコミット/ロールバックによって設定結果がデータベースに反映されるかどうかが決まる。

確認コード

  1. 7行目でトランザクションでコミットフラグをtrueにセット
  2. 通常モードで’one’を書き込み
  3. 20行目でトランザクション開始
  4. ‘two’, ‘three’を書き込み
  5. 33行目でコミット、トランザクション確定
  6. 41行目で通常モードに復帰

確認結果

以下、出力を見ながらトランザクションの動作を確認。

  • 通常モードでは普通に書き込み
  • トランザクション開始後、データベースリンクの内容は指示通り設定
  • トランザクション終了後、データベース内容の変更が確認できる
  • 通常モード復帰後も普通に書き込み

以下は出力結果で、終了後のデータベースの内容は’one’, ‘two’, ‘three’, ‘four’となる。

次にコミットフラグを$commit=falseにすると、msqli_commit()ではなくmsqli_rollback()が実行され、実行結果は以下のようになる。

  • 通常モードで普通に’one’が書き込まれる
  • トランザクションに入り、データベースリンクには’two’, ‘three’が設定される
  • トランザクション終了後にロールバックされると、データベースリンクがデータベースに反映されてもトランザクション中の’two’, ‘three’は書き込まれない
  • 通常モードに復帰後’four’が書き込まれる

 

PHP – PDOによるデータベース操作

概要

PDO(PHP Database Object)によるデータベース操作は、手続き型に比べて、異なるDBMS間の際を隠蔽・吸収してくれるほか、セキュリティー対策も組み込まれている。

基本の流れ

PDOの最も基本的な流れは以下の通り。

  1. ユーザー情報やデータベース情報からPDOオブジェクトを生成する
  2. PDO::query()メソッドにSQLクエリーを渡してPDOStatementオブジェクトを得る
  3. PDOStatementオブジェクトからデータをフェッチする

例外処理などを無視した骨格は以下の通り。

メソッド

PDO::__constructor

PDOのコンストラクター

public PDO::__construct ( string $dsn , string $username = ? , string $passwd = ? , array $options = ? )

dsn

データソースネーム(Data Source Name)。DBMS名やホストなどの情報を文字列で指定する。たとえばlocalhostのMySQLを文字セット・データベースまで含めて指定する場合は以下のように記述する。

'mysql:host=localhost;charset=utf8mb4;dbname=databasename'

charsetで文字コードセットをしている点に注意。

$options

PDOクラス定数と用いた連想配列で指定する。たとえばエラーを例外としてthrowさせたい場合は以下のように指定する。

array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION)

PDO::query

クエリー文字列を与えて、検索結果をPDOStatementオブジェクトとして受け取る。

PDOStatement::fetch()

検索結果を取り出す。一般的なのは、while文の条件の中でfetch()メソッドの結果を取り出して、全レコードについて処理を行うケース。以下の例では、クエリーによって抽出された都道府県と市町村を連想配列の配列として格納する。

PDO::prepare

PDO::query()による方法は、SQLステートメントがそのまま実行されるためセキュリティー上脆弱。

PDO::prepare()によるプリペアードステートメントとbindValue/bindParamによる値や変数のバインドによれば特定文字のエスケープが行われるため、こちらを使うべき。

PDO::lastInsertId

最後に登録されたレコードのIDを返す。MySQLの場合引数は不要。戻り値はstring。

雛形

PDO::query

レコード数のカウント

SQLのCOUNTの結果1行からデータを読む。以下の例では、id列をカウントした結果が1行で返されるのをfetchColumn()でカラム指定してデータを取得している。

あるいはPDO::rowCount()メソッドを使ってもよい。この場合はSELECTで何かのカラムを読み込めばよい。

列の全データの取得

検索したい列を抽出し、PDOStatement::fetchAll()で配列として取り出す。以下の例ではprefカラムの全データを取り出し、配列$pref_nameに格納している。

複数列データの連想配列への格納

以下はクエリーの結果を格納する方法の一つ。各レコードをカラム名をキーとした連想配列とし、それを1つの配列に収めている。

例外処理

PDOに例外をthrowさせるには、コンストラクターで以下のようにクラス変数で指定する。

トランザクション

3つのメソッドで簡明に処理できる(PDOによるトランザクションの確認)。

commit()メソッド、rollBack()メソッドはbeginTransaction()が成功していないと例外になるので注意。

beginTransaction()はトランザクションが開始できない場合に例外を投げる。

PDOによるトランザクションの確認はこちらを参照

 

PHP – 雛形 – 入力された内容を残す

概要

普通にHTMLのinput要素などを書くと、GETやPOSTのたびにそれらがvalueなしで描きなおされるので、内容が空になる。これに対してsubmit後に元に入力した値が残るようにする手順。

普通に書くと消える

以下のコードでは、送信ボタンを押すと入力した内容が表示されるが、テキストボックスの内容は毎回消えてしまう。

これはinput要素のvalue属性がないため、POSTのたびに再描画されるときに要素が空として描かれるため。

valueを設定すると値を残せる

input要素のvalue属性に前の入力内容を渡せば、その内容で要素が描かれるため値が残る。

  • POSTされた際にPHPコードの変数は初期状態に戻る(undefinedか初期設定値に戻る)
  • ただしHTMLのinput要素が再描画されるまでは、その要素の内容は残っている
  • そこで、正常に入力が取得された場合にはinput要素のvalue属性の値に入力された値を渡せば、描画時にその値が残される

ただし、GETやPOST後の状態によってvalueにセットする変数がundefinedだとエラーになるため、どのような状態でも変数が定義済みとなるようにしておく必要がある。

以下のコードでは、POSTされた場合はisset()がtrueかfalseかそれぞれの場合に、POSTされずに実行された場合(最初に実行された場合など)にvalueにセットする値を定義している。

エラー処理などで値を残す

GET/POSTされた値の内容によってエラーとする場合にも、エラーとなったその値を残しておける。コード実行の最初にinput要素から取得した値を変数に持っておいて、その内容のままvalue属性の値として渡せばよい(もちろん例外対応は必要)。

以下のコードは、数値入力欄が数値以外の場合エラーとしているが、その入力内容はテキストボックスに残る。