[ホーム] -> [Aache + PHP + PostgreSQL 実験室]

PHP の知っておきたいこと

スカラー配列・連想配列

前でも説明をしましたが、他の言語と同じように、PHP には配列が用意されています。これは変数の一種ですが、非常に便利に使用することができます。PHP の配列には、見た目において、大きくスカラー配列と、連想配列の二つがあります。

スカラー配列

まず最初に、スカラー配列についてのメリットを説明します。これは、ほとんどの言語にある配列で、配列の後ろに数値の添字をつけることにより、各要素にアクセスできます。これは、どんなときに使うかというと、例えば、10人の名前を変数に格納したいとします。これをするには、二つの方法があります。一つは、10個の別の変数の名前をつける方法。

$name1 = "Hashiya";
$name2 = "Atsuzaki";
$name3 = "Nakano";
(省略)

もうひとつの方法が、スカラー配列を使う方法です。

$name[0] = "Hashiya";
$name[1] = "Atsuzaki";
$name[2] = "Nakano";
(省略)

この二つの例を見る限り、あまり大きな違いがありません。ところが、この変数にアクセスする場合、大きく違ってきます。例えば、すべての名前を表示したくなったとします。

// 配列を使わない場合
echo("$name1");
echo("$name2");
echo("$name3");
(省略)
// スカラー配列の場合
for ($i = 0; $i < count($name); $i++) {
  echo("$name[$i]");
}

配列を使わない場合、すべての変数を並べなければなりません。それに対して、スカラー配列の場合は、添字(括弧の中の数値)の部分を、他の変数を使って表現することができます。上記の例では、i がそれに当たります。i0 から count の戻値、つまり 変数 name の配列の数の直前までアップし、それに伴って、表示する変数 name の添字も変わってくるのです。この方法を使えば、たとえ name に格納する名前の数が変化しても、変数の中身を表示させる部分を変える必要がなくなります。

また、PHP には、配列専用の便利な関数が備わっています。例えば、sort と言う関数は、配列の中の値を並び替えてくれいます。変数の中が数値であれば、小さい順に、文字列であれば辞書順に並び替えてくれます。

また、PHP では、スカラー変数に値を入れるとき、添字を使わない方法もあります。

$name[] = "Bill";

という風にすると、変数 name の最後に新しい値を代入してくれます。変数 name に、すでに10個の値が格納されていた場合、上記のように使うと、11番目に格納されるようになります。もし、一度もスカラー配列として使われていない変数に、添字を使わずに代入した場合は、添字 0 を指定したのと等価となります。

配列にあらかじめ値を入れる必要がある場合は、次の array 関数を利用します。

$name = array("Seigo", "Atsuzaki", "Nakano", "Bill");

これにより、$name[0]"Seigo"$name[1]"Atsuzaki"... と言う風に格納されます。

連想配列

次に、連想配列についてです。連想配列は、Perl などでも使うことができる便利な変数の一種です。連想配列のことを、ハッシュテーブルと呼んだりもします。先ほどのスカラー配列は、添字が数値でしたが、連想配列の添字は、文字列です。この文字列をキーと呼んだりします。これは、例えば、人の名前に対する年齢を格納する変数を作るときに便利です。

$age["Seigo"] = 23;
$age["Atsuzaki"] = 26;
$age["Nakano"] = 21;

この様に、名前をキーにして、年齢を格納しておくことができます。先ほどと同じように、変数 age の値をすべて表示したいときは、次のようにします。

連想配列にあらかじめ値を入れる必要がある場合も、array 関数を利用しますが、書式は次のようになります。

$age = array("Seigo" => 23, "Atsuzaki" => 26, "Nakano" => 21);

変数 age の値をすべて表示したいときは、次のようにします。

$age = array("Seigo" => 23, "Atsuzaki" => 26, "Nakano" => 21);
while (list($key, $val) = each($age)) {
  echo("$key さんは $val 歳です。");
}

この例は、配列を使った少し複雑なテクニックを使っています。each 関数は、引数の配列(例だと $age)のキーと値のペアである配列を返します。このペアは、スカラー配列として参照した場合は 0 番目にキーを、1 番目には値を取得できます。連想配列として参照した場合は、key でキーを、value で値を取得できます。

$age = array("Seigo" => 23, "Atsuzaki" => 26, "Nakano" => 21);
$pair = each($age);
echo("$pair[0]\n");
echo("$pair[1]\n");
echo("$pair[key]\n");
echo("$pair[value]\n");

この結果は、実行してみると分かりますが、「seigo 23 seigo 23」となります。このことから、スカラー配列と連想配列は、同じ変数にそれぞれ別のものをもてるのが分かりますね。また、同じ変数に対して each を繰り返すと、前回返した次のペアを返すのです。

$age = array("Seigo" => 23, "Atsuzaki" => 26, "Nakano" => 21);
$pair = each($age);
echo("$pair[0] = $pair[1]\n");
$pair = each($age);
echo("$pair[0] = $pair[1]\n");
$pair = each($age);
echo("$pair[0] = $pair[1]\n");
$pair = each($age);
echo("$pair[0] = $pair[1]\n");

これに対して、list 関数(実際は関数ではないですが)は、代入の左辺に置き、右辺の配列をそれぞれ別の変数に代入してくれます。

$fullname = array("Atsuzaki", "Hizuya");
list($firstname, $familyname) = $fullname;
echo("first name is $firstname\n");
echo("first name is $familyname\n");

これの二つを組み合わせて、each 関数でキーと値のペアを順番に取り出し、それを list でキーと値をそれぞれ別の変数で受け取る、という処理を行ったのです。

配列に対して、ソート(並び替え)なども行うことができます。キーに対してソートをしたい場合は、ksort, krsort、格納されている値に対してソートしたい場合は asort, arsort を使います。また、ファイル名を並び替えるのに便利な natsort, natcasesort などがあります。

スカラー配列は、可変個の値を格納できるので、プログラムが実行されるときに、格納する値の個数が分からないときに使用します。連想配列は、キーの値が重複しないように注意する必要がありますが、使い方次第では非常に強力です。実際にプログラムを作る際は、これら二つの変数と、普通の変数を、うまく使い分けてください。これらが使いこなせるようになると、プログラムを作るの非常に楽になります。

GET と POST の補足

GETPOST で値を渡すと、それが PHP の変数として使用できることは前に説明しました。補足ですが、変数を配列とすることもできます。配列としたい場合、呼び出し側で、変数の後ろに括弧「[]」を付けます。

<form action="var.php" method="POST">
  住所1:<input type="text" name="address[]">
  住所2:<input type="text" name="address[]">
</form>

この例では、$_POST['address'][0] に「住所1」が、$_POST['address'][1] に「住所2」が入ってきます(文字列中でこの変数を使うときは、"{$_POST[address][1]}" として、中カッコで囲む必要があります)。もちろん、次のようにすれば、連想配列としても使えます。

<form action="var.php" method="POST">
  名前:<input type="text" name="personal[name]">
  住所:<input type="text" name="personal[address]">
  電話:<input type="text" name="personal[telephone]">
</form>

名前は、$_POST['personal']['name'] に入ってくるわけですね。これらを使用することで、入力項目の多い画面から、たくさんの変数の名前を受け取らなくて済むようになります。まあ、これも好みの問題ですね。

また、GETPOST や クッキー(次で説明します)で値を受け取ったとき、ダブルクォーテーション「"」が、「\"」となっているのに気付いたかもしれません。これは、magic_quotes_gpc という設定のせいで、この設定が On(デフォルト値は On)になっていると、シングルクォーテーション「'」、ダブルクォーテーション「"」、バックスラッシュ「\」がエスケープされます。

入力された値を、そのままデータベースに入力するときなどは便利かなと思う機能(私は、ちょっとよけいなお世話、って気もします)ですが、この機能を切ることもできます。php.ini ファイルに、次のように記述してください。

magic_quotes_gpc = Off

この設定に関係なく、データベースやテキストファイルから読み込んだ値は、エスケープされませんが、逆にこれらの値もエスケープするようにもできます。次の設定をしてみてください。

magic_quotes_runtime = On

クッキー

PHP では、クッキーがサポートされていますが、その使い方は非常に簡単です。クッキーとは何かというと・・・。普通、PHP の各プログラムは独立していて、変数の値は、一度実行されたら消えてしまい、たの PHP のページと共有することはできません。Web の BBS(掲示板)などは、一度ユーザが入力した名前やメールアドレスなどが、2回目以降自動的に表示されたりします。これは、名前やメールアドレスを、クッキーという特殊な形式でブラウザに保存しておいているのです。プログラムから、クッキーと呼ばれる値を設定すると、それはブラウザに渡され、その値がブラウザ内に保存されます。以降その値は、PHP のページにアクセスするたびに、ブラウザから PHP のページに渡されるようになります。

PHP からクッキーの値をセットするのはすごく簡単で、次のように setcookie 関数を使います。ただし、クッキーの設定は、HTML などを出力するより前に実行しなければなりません。つまり、<html> タグより、もっと前で、setcookie を呼び出さなければなりません。これは、PHP の制限ではなく、クッキーの制限です。

setcookie("name", "Hizuya");

この例では、name といクッキー変数に、Hizuya とい値を格納しています。一度格納すると、それ以降に呼び出されるプログラムは、PHP の変数 $_COOKIE['name']Hizuya という値が入っています。また、この変数には次のように配列も使用できます。

setcookie("personal[name]", "Hizuya");
setcookie("personal[age]", "23");

クッキーには、有効期限というのがあります。有効期限を設定しないと、ブラウザを終了させるまで設定したクッキーが有効ですが、有効期限を設定すると、ブラウザを終了しても有効期限が切れるまで、PHP 側はその値を使用することができます。有効期限を設定するには、setcookie 関数の3番目の引数に、時間を指定します。ここで指定できる期限は、UNIX 標準時を表す整数なので、time 関数からの差分を指定するようにすると便利です。

setcookie("name", "Hizuya", time() + 3600);

単位は秒なので、上の例では、1時間で有効期限が切れ、1時間たつと、name は送られてこなくなります。

もし、有効期限が切れる前に、クッキー変数を削除したい場合は、クッキー変数名だけを指定して呼び出されます。

setcookie("name");

これで name として設定されたクッキーは削除されます。

クッキーを扱う際に注意しなければ行けない点は、クッキーの値はユーザには見ることが可能だし、値を変更できてしまう点です。説明しておいてなんですが、パスワード等をクッキーに保存しておいてはいけません。もし、ユーザにログインさせて、その情報を保持したいのであれば、「セッション」という機能を使います。セッションについては、また後で説明します。

アップロード

HTML には、ファイルをアップロードする機能があります。これは、Netscape Navigator 3 以上、Internet Explorer 4 以上、あるいは Internet Explorer 3 にパッチを当てたものなどで使用可能です。PHP もそのアップロードの機能に対応していて、ユーザにファイルをアップロードしてもらい、そのファイルの中身にアクセスすることが可能です。まず、ファイルをアップロードするための HTML を用意します。

<form action="upload.php" method="POST" enctype="multipart/form-data">
  <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
  ファイル:<input type="file" name="sendfile"><br>
  <input type="submit" value="Send File">
</form>

<form> タグの、enctype の指定を忘れないでください。また、MAX_FILE_SIZEhidden で指定していますが、これは、受け取るファイルの最大サイズで、値をバイト数で指定します(あくまでも目安なので、この値を信頼してはいけません)。ファイルを入力するフィールドより前で指定する必要があるので、注意してください。

これによって呼び出されたPHP プログラム(この例では upload.php)では、4つの変数 $HTTP_POST_FILES['sendfile']['tmp_name'], $HTTP_POST_FILES['sendfile']['name'], $HTTP_POST_FILES['sendfile']['size'], $HTTP_POST_FILES['sendfile']['type']がセットされます。それぞれ、アップロードされたファイルが保存されているテンポラリファイルの名前、送信元のオリジナルのファイル名、アップロードされたファイルのサイズ、ファイルの MIME タイプに相当します。これらの名前は、ファイルの入力する <input> タグのname に設定されている値が元になります。ちなみに、$HTTP_POST_FILES['sendfile']['type'] は、ブラウザから MIME タイプが送られてこない場合、セットされません。

注意して欲しいのは、$HTTP_POST_FILES['sendfile']['tmp_name'] はテンポラリファイルの名前である点です。つまり、PHP では、ファイルがアップロードされると、一時的にテンポラリファイルとして保存されます。テンポラリファイルは、その PHP プログラムの終了時に削除されてしまうので、このファイルを残しておきたい場合、テンポラリファイルをどこか別の場所に移動したりする必要があります。次のような感じになります。

define("SAVE_DIR", "/www/upload/");
echo("テンポラリファイル名は {$HTTP_POST_FILES[sendfile][tmp_name]} です。\n");
echo("元のファイル名は {$HTTP_POST_FILES[sendfile][name]} です。\n");
echo("ファイルのサイズは {$HTTP_POST_FILES[sendfile][size]} です。\n");
echo("ファイルのタイプは {$HTTP_POST_FILES[sendfile][type]} です。\n");
echo('<font color="red">');
if (strlen($HTTP_POST_FILES[sendfile][name]) == 0) {
  echo("ファイルを指定してください。\n");
} elseif ($HTTP_POST_FILES['sendfile']['size'] <= 0) {
  $maxsize = min(ini_get('upload_max_filesize'), $_POST[MAX_FILE_SIZE]);
  if ($maxsize == 0) {
    if (ini_get('upload_max_filesize') > 0) {
      $maxsize = ini_get('upload_max_filesize');
    } else {
      $maxsize = $_POST[MAX_FILE_SIZE];
    }
  }
  echo("ファイルのサイズが $maxsize 以下であるかを確認してください。\n");
} else {
  $savepath = SAVE_DIR . md5(uniqid(mt_rand(), TRUE));
  if (move_uploaded_file($HTTP_POST_FILES['sendfile']['tmp_name'], $savepath)) {
    echo("ファイルを $savepath として保存しました。\n");
  } else {
    echo("ファイルを保存できませんでした。\n");
  }
}
echo("</font>");

ユーザがファイルを指定しなかった場合は、$HTTP_POST_FILES['sendfile']['name']が空になります。また、ファイルサイズの制限に引っかかった場合は、$HTTP_POST_FILES['sendfile']['size']0 が設定されます。

ファイルの保存するために、何かファイル名を決定しないといけませんが、もし上書きされたくない場合は一意な名前を付けなくてはなりません($HTTP_POST_FILES['sendfile']['name'] を元にしてはいけません。不適切な文字が混ざっているかもしれないからです)。そのために、このサンプルでは md5(uniqid(mt_rand(), TRUE)) としてファイル名を決定しています。

mt_rand 関数は、ランダムな値を返す関数です(rand 関数よりこちらの方がいいようです)。その値を元に、uniqid 関数を呼び出して一な値を生成しています。そしてその値を md5 関数にかけて、ハッシュ値を求めます。この結果、ファイル名は32文字の文字列(16進数なので、0-9A-F からなる)になります。

最後に、move_uploaded_file 関数を利用して、アップロードされたテンポラリファイルを、新しい名前で保存します。この関数を使う理由は、アップロードされたファイルしか、移動しないからです(普通のファイルを移動しようとすると、エラーになる)。

ホームへ