Web 1
ウェブに関するテクニック

注意事項

毎回の授業の最初に出席メールを提出せよ.

前回までの出席記録課題と提出状況 を確認せよ.

7 章 ウェブに関するテクニック

php はもともとウェブで動的なページを作成するために作られた.

7.1 HTTP の基本

ユーザから見たブラウザへの入力と出力は以下のとおりである.

ブラウザへの入力

  1. サーバの名前(そのサーバを一意に識別できる完全なDNS名)
  2. アクセスしたいコンテンツのサーバ内での場所(ファイルのパス)
  3. フォームへの入力を含む場合はそのデータ

ブラウザからの出力

取得したコンテンツに ついてHTML を解析して内容を表示すること

実際にはサーバに渡されるデータは上記ブラウザへの入力だけではなく, サーバから返されるデータも上記出力だけではない. ブラウザはユーザとサーバの間にたってより多くの情報を処理している.

具体的にはブラウザへの入力にヘッダとよばれる情報を付加してサーバに送る. この通信もテキストだけで行うので,最初にヘッダ行を送信し,空行をはさんで 内容を送信する.(例は教科書p.175 下から 6 行目)

送信ヘッダの最初に書かれるのは「メソッド」と呼ばれるサーバに対するコマンドで, ほとんどの場合 GET か POST である.

出力についてもユーザに見えないデータをやり取りしている. このやりとりもテキストだけで行うのでヘッダ行の追加で行う.具体的には サーバから返されるデータは,ブラウザに表示するコンテンツの前に 数行のヘッダがついたものになっていて,ヘッダの最初の行にはステータスコード等 が含まれる.

GET メソッドは画面表示など情報を引き出すために使い,POST メドッドは ファイルのアップロードなど情報をサーバに送る目的で使う.実際には 検索語句などの単純な情報は GET で送ることが多い.

例 12 の form 要素で method ="GET" とあるのは GET メソッドでフォームに入力されたデータを 送るという意味である.GET であればデータは URL エンコードされ,ヘッダの URL 情報として送られる.そのためブラウザのアドレス入力欄に入力したデータが現れる.

7.2 変数

例 12 では $_GET['data'] で 入力されたデータにアクセスしている.このようにプログラム中でアクセスしなければ ならないデータはいろいろある.これらは以下のグローバル変数に格納されるので プログラムから直接アクセスできる.いずれもいろいろな変数に値が設定されている 形なので連想配列で記憶される.

$_ENV
環境変数の値.変数名がキー
$_GET
GET リクエストで渡されたパラメータの値.パラメータ名がキー
$_POST
POST リクエストで渡されたパラメータの値.パラメータ名がキー
$_FILES
ファイルに関する情報
$_COOKIE
リクエストで渡されたクッキーの値.キーはクッキーの名前
$_SERVER
ウェブサーバが知っている種々の情報.7.3 節参照

環境変数とはユーザがシステムを利用している間システムが保持している データで,グローバル変数のような形で利用される.例えば 現在の時刻を表示するプログラムを作成するとき,LANG という環境変数に文字列 ja が 指定されているときは日本語の形式で表示する,というようにあらかじめプログラムを 作っておく.ユーザがログインするときに環境変数 LANG が文字列 jp にセットされる ようにしておけば,そのユーザは意識することなく日本語向けの結果を得ることができる. 他のプログラムも同じ環境変数を使って出力を変えるように作っておく事でその情報を プログラム間で共有できる.環境変数はこのようにプログラム間で共有するユーザに 関する補助データとして利用される.

変数 $_SERVER['PHP_SELF'] には動作しているスクリプトのパス名が格納される. 自分のスクリプト名を直接プログラムに書いてしまうと,プログラム名を 変えたり,別の場所で動作させたりする場合に変更しなければならないが $_SERVER['PHP_SELF'] を使えば自動的に設定されるので便利である.

7.3 サーバの情報

$_SERVER にはサーバが知っている情報が多く記録されている.p.178 の 一覧でキーと格納されている値を知る事ができる. 例えば echo $_SERVER['SERVER_NAME'] でサーバの名前が出力される.

例題6

アクセスしてきた端末の IP アドレスを表示するスクリプトを作れ. 他の PC からもアクセスしてもらって動作を確認せよ.

7.4 フォームの処理

$_GET や $_POST の変数にアクセスすることでフォームの処理を行う.

7.4.1

サーバにデータを送る場合,ヘッダの最初に書かれるリクエストのメソッドの種類は ほとんどの場合 GET か POST のどちらかである.どちらもフォームに入力したデータを サーバに送る.例えば 例 12 のフォームの最初の input 要素には name という変数名が関連付けられている.ここに 'abc' という文字列を入力し, 送信ボタンを押すと,「name という名前の変数に 'abc' という値がセットされている」 という情報をサーバに送る必要がある.

GET メソッドと POST メソッドでは情報の送り方が異なる. GET では入力された変数名とその値の組を URL 形式にエンコードして ヘッダの URL 情報を使って送信する.このエンコードは スクリプトのファイルの URL の後に ? を追加し"変数名=値" として すべての変数を追加する.例えば 例 12 のフォームは GET メソッド が指定されているので URL エンコードが行われる.フォームに "abc" と入力して 送信ボタンを押すとスクリプトの URL の後に "?data=abc" が追加された URL をサーバにリクエストする. ブラウザの URL 入力欄にも表示される.

POST の場合はヘッダの URL ではなくリクエストの本文として書き込む.

GET と POST の表面的な違いは GET の場合すべての送信情報が URL に 含まれることである.このため,ブラウザのアドレス欄で確認できる, 入力データごとブックマークできる,リンクを作成できる,などの特徴がある. POST ではこれらはできない.

機能としては同じように使われる GET と POST だが,設計思想としては 明確なポリシーの違いがあるのでそれを尊重して使い分けるべきである. GET はもともと情報を引き出すためのメソッドで,変数でいえば読み出しにあたる. ただし,ユーザが決めるパラメータの値によって結果を変化させたい場合にその パラメータを GET メソッドで送る.このため検索キーワードなどは GET のパラメータとして送ることが一般的である.変数の書き込みではなく 読み出しに当たるので,同じパラメータであれば何度アクセスしても同じ結果を 返すような使い方のときに GET を使うべきである.

一方,POST は変数で言えば書き込みにあたる.サーバの保持するデータに 変更を加える時に使う.例えばショッピングサイトの注文データや掲示板への 書き込み等はサーバのデータベースに変更を加えるので POST を使うべきである.

まとめると,相手サーバのデータベースに変更を加えない場合は GET, 変更を加える可能性のある場合は POST を使う,という判断基準が適当である.

7.4.2

フォームの各入力要素にはパラメータが関連づけられている.それにアクセスするには $_GET や $_POST などの配列を使う.GET メソッドのフォームで, パラメータ名が "data" であれば $_GET['data'] でパラメータの内容 にアクセスできる.フォームのほうのパラメータ名では "." が使用できるが PHP では使用できないので PHP では "_" に置き換えられる.

例16

教科書 p.180 の例 7-1 を chunkify.html として作成せよ. また,p.181 の例 7-2 を chunkify.php として作成せよ. 両方を完成させ,ブラウザから chunkify.html にアクセスし, 実行テストを行え. (この例題プログラムは日本語の入力は正しく処理できない)

chunkify.php に使われている ceil は切り上げを行う関数である.

chunkify.html と cunkify.php は以下の手順で動作する.

  1. ユーザはブラウザから静的なコンテンツである chunkify.html にアクセスする.
  2. サーバはヘッダ情報と共に cunkify.html のソースを返す.
  3. ブラウザは chunkify.html のソースに 従って "word" という名前のパラメータに関連づけられたテキスト入力窓と "number" という名前のパラメータに関連づけられたテキスト入力窓, 送信ボタンをもつフォームを表示する. このフォーム全体にも情報が関連付けられている. フォームが送信されたときの動作として "chunkify.php" が指定されており, メソッドとしては POST を使用することが記述されている.
  4. ユーザがパラメータ word の窓に文字列, number の窓に数値を入力する.例えば パラメータ word に "ultrasuperlongword" number に "4" を入力し, 送信ボタンを押したとする.
  5. ブラウザは form に指定されている action="chunkify.php" の働きで, chunkify.php にアクセスする.このとき 2 つの パラメータのパラメータ名と設定された値の組も POST メソッドで送信される.
  6. サーバは chunkify.php をリクエストされたこと,word というパラメータに ultrasuperlongword, number というパラメータに 4 が設定されていることを 知る.
  7. サーバは chunkify.php のうち <?php と ?> で囲まれた部分を php スクリプトとして処理する.このときグローバル配列 $_POST には 入力されたパラメータ群がパラメータ名をキーとした連想配列として格納されている. 今回の例では $_POST['word'] には 'ultrasuperlongword' が, $_POST['number'] には '4' が格納されている.このスクリプトではそれぞれに アクセスし,改めてスクリプト内部の変数 $word, $number にコピーしている. $chunks = ceil(strlen($word)/$number); で $chunks には分割する 文字列長(パラメータ word の値の文字列長)を分割後の一個の長さ (サンプルプログラムでは「何個にの部分に分解しますか」と書かれているが誤り. パラメータ number の値) で割って切り上げを行った整数値が設定される.つまり $chunks は結果的に 何個の文字列に分解されるかという値が設定される.php スクリプトの 残りの部分でこれらの情報を用いて分割された文字列を表示する html を 出力する.
  8. サーバは上記の結果出力された html で <?php と ?> で囲まれた部分 を書き換え,html ソースとしてブラウザに返す.
  9. ブラウザは受け取ったソースに従って表示を行い,ユーザが確認する.

7.4.3

サーバでで magic_quotes_gpc が有効になっている場合は パラメータに含まれる引用符等の前には自動的にエスケープ文字 "\" が挿入される.この処理を避けるには関数 stripslashes を使う. この実習のサーバでは無効なのでこの処理は必要ない.

7.4.4

教科書 p.180,181 の例 7-1,7-2 では chunkify.html が入力用のページで, 送信ボタンを押すと form 要素の action 属性 に記述されている処理用の chunkify.php という別のページが呼び出される.

入力用と処理用のページを一つにまとめることができる.これを 自己参照するページとよぶ.この場合は form 要素の action 属性に自分自身を記述する.スクリプトに 直接ファイル名を書いても動作するが, $_SERVER['PHP_SELF'] で現在動作しているスクリプトそのものを 知ることができるのでそれを利用するほうがよい.

例17

教科書 p.183 の例 7-3 を temp.php として作成し,動作確認を 行え.

自己参照するページを作成する場合,入力欄を表示するフェーズなのか 出力結果を表示するフェーズなのかを意識することが重要である. ページの目的によってフェーズの数は異なるが,例 7-3 では入力 フェーズと出力フェーズの 2 つのフェーズに分けられる. HTTP は記憶のないプロトコルなので スクリプト内で何らかの方法でどちらのフェーズなのかを判断し, それにあった表示を選択しなければならない.

例 7-3 では $_SERVER['REQUEST_METHOD'] の値でフェーズを 判定している.この値が GET であれば入力フェーズ,POST であれば 出力フェーズと判断している.最初にこの URL にアクセスするときは GET メソッドであり,フォームの送信ボタンがおされて呼び出された時は そのフォームの method 属性が POST なので POST でリクエストされる からである.

例 7-3 は以下の手順で動作する.

  1. ユーザが最初に temp.php にアクセスする
  2. ブラウザは GET メソッドでサーバにリクエストする
  3. サーバは GET メソッドを受け付ける.
  4. サーバは <?php と ?> で囲まれた部分を PHP スクリプトとして 処理する.このとき $_SERVER['REQUEST_METHOD'] には 'GET' が設定 されているので入力フェーズと判断する. 最初の if 分の条件のみ成立するのでそこだけが処理される. その結果フォームが出力される.このフォームの action 属性は 動作しているスクリプト自身,method 属性は POST が指定されており, パラメータ fahrenheit に関連付けられた入力欄と送信ボタンが表示される.
  5. ユーザは入力欄に数値を入力する.例えば 100 を入力し,送信ボタンを押したとする.
  6. ブラウザは action 属性 $_SERVER['PHP_SELF] すなわち temp.php 自身にリクエストを送る,今回はフォームの method 属性により POST が 指定されているので POST メソッドでパラメータの名 fahrenheit と それに設定されている値 100 とともにリクエストをサーバに送る.
  7. サーバは POST メソッドで temp.php がリクエストされたこと, fahrenheit という名前のパラメータが存在し,値が 100 であることを知る.
  8. サーバは <?php と ?> で囲まれた部分を PHP スクリプトとして 処理する.今回は $_SERVER['REQUEST_METHOD'] には 'POST' が設定 されているので出力フェーズと判断する. 2 番目の elseif 分の条件のみ成立するのでそこだけが処理される. セ氏に変換した温度を求め,それを表示する html を出力する.
  9. サーバは <?php と ?> で囲まれた部分を上記の出力結果に置き換え, html ソースとしてブラウザに返す
  10. ブラウザは受け取ったソースに従って表示を行い,ユーザが確認する.

教科書の例 7-3 ではリクエストのメソッドが GET か POST かでフェーズを判定した. 他によく使われる方法として特定のパラメータの値がセットされているかどうか を見ることでフェーズを判断する方法もある. 本サイト例 12 はこのタイプのスクリプトで, GET メソッドだけでフェーズによる切り替えのあるページを書いている. 具体的には isset($_GET['data']) でパラメータ名 data の値が セットされているかどうかがわかるのでセットされていないときは入力 のみのフェーズ,セットされているときは 次の入力と前の値の処理結果の出力両方を行うフェーズと判断し, 表示を切り替えている.

教科書の例 7-4 も値がセットされているかどうかでフェーズを判定する タイプのスクリプトである.最初に $_GET['fahrenheit'] の結果を is_null 関数を使って null かどうかを調べている.null であれば 入力フェーズと判断し,入力用の表示を行うルーチンを処理する. fahrenheit に値が設定されていれば 出力フェーズと判断し, その値を入力として計算を行った結果を表示するルーチンを処理する. このように特定のパラメータの値が設定されているかどうかでフェーズを 判断する手法はよく使用される.

7.4.5

入力欄にデフォルト値を設定するには input 要素の value 属性にその文字列を設定しておけばよい. 教科書例 7-5 は 7-4 を改良したもので, 送信ボタンを押した後も入力フォームを表示するように変更 したものである.ただし、value 属性に $_GET['fahrenheit'] の値, すなわち入力されたパラメータを初期値として表示させる.

7.4.6 節の複数選択形式の説明の前に単一選択形式の例を挙げる. これは 本サイト例 12 を選択形式に変えたものである.

例 18

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="ja">
  <head>
    <title>Sample of select</title>
  </head>

  <body>
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="GET">
      Select: <select name="data">
               <option value="apple">りんご</option>
               <option value="olange">みかん</option>
               <option value="banana">バナナ</option>
               <option value="pinapple">パイナップル</option>
              </select>       
      <input type="submit" />
    </form>
<?php
if(isset($_GET['data'])){
  $s = $_GET['data'];
  echo "Selected: $s";
} 
?>
  </body>
</html>

第 7 回課題「フォーム」 を提出せよ.


Updated in June 9, 2009, index.html, Yamamoto Hiroshi