目次

5. HTML ウィジェットクラス

5.1 Sql_Query

Sql_Query は簡単なテーブルへのクエリーに関するクエリーフォームを次のように 生成します。 フィールド名のリスト、比較演算子、入力フィールドが表示されます。 ユーザーは、SQL 標準の演算子を用いて表示された任意の列について任意の値を 検索できます。 複数の検索条件も指定可能で、検索条件はANDやOR演算子を用いて結合することが できます。

クエリー条件の個数は可変にできます。この場合、ユーザーは適当なボタンを 用いてクエリーウィジェットを絞ったり拡大したりできます。

全てのボタンラベルやインターフェース上の他のメッセージは変更可能であり、 言語辞書に格納されています。現時点では de(独語)と en (英語)に関する辞書が提供されています。

インスタンス変数


classname
シリアル化ヘルパ: このクラスの名前。
persistent_slotsシリアル化ヘルパ: 全ての持続的スロットの名前
conditions クエリ条件の個数
input_size 入力フィールドで見える最大文字数
input_max入力フィールドの最大入力文字数
methodフォーム送信手順(GETまたはPOST)
lang使用する言語辞書
translateカラム名を変換するかどうかのフラグ
containerマスターコンテナを作成するかどうかのフラグ
variableリサイズボタンを作成するかどうかのフラグ
アクセス可能なインスタンス変数

dictGUI言語辞書
compareSQL比較関数辞書
内部インスタンス変数

インスタンスメソッド

公開インスタンスメソッド

start()

初期化関数。現時点では内容がありません。

form($base, $option, $class, $target)

この関数は、SQLクエリー選択フォーム用にHTMLを生成して返します。 フォーム内の全ての変数は、$baseというプレフィックスで始まり、 下線文字の後に数字のインデックス番号が付加されます。異なる base 文字を 使用することにより一つのページに複数の Sql_Query インスタンスを持つことができます。

この関数は、クエリーを行うSQLテーブルのフィールド名を知る必要があります。 $optionにこれらのフィールド名の配列 ($translateは空となります)もしくはフィールド名から 長い名前へのハッシュ($translateonに設定されます) のいずれかを指定することが可能です。

$classにCSSクラス名が指定されている場合、 生成されるフォームの全てのタグはCSSスタイルシートクラスによってタグ付けされます。 $class はオプションであり、空の場合にはクラス属性は生成されません。 $targetはSQLクエリーフォームのターゲットのURLです。 これはオプションであり、空の場合は自分自身を参照するフォームが生成されます(推奨)。

この関数は、SQLクエリ選択フォームを描画するHTMLを有する文字列を返します。

where($base, $incr)

form() によって生成されたページが送信された際には、 多くのパラメータを評価し、ユーザーの選択に応じたSQLのwhere句の 検索条件に変換する必要があります。 where()関数はこれらの全ての面倒を見ます。 この関数は、form()をコールする際に使用したプレフィックス$base を必要とします。

$incrパラメータはオプションであり、"More"もしくは"Fewer"ボタンが 使用された際に追加あるいは削除するクエリ条件の行数を定義します。デフォルト値は1です。

この関数は、SQLクエリにおいて "where"句としてエラーなく使用された文字列を返します。

内部インスタンスメソッド

plain_where($base)

この関数は、where()の全ての動作を行いますが、クエリ条件ウィンドウの サイズを変えません。

Sql_Queryクラスは直接使用することが可能です。 持続化するとより便利となりますので、prepend.php3ファイル の適当な場所にrequire("sqlquery.inc")を追加することを お勧めします。

検索結果を表示し整形する優れた方法についてはこの章のTableクラスを 参照下さい。データベースに接続する優れた方法については、DB_Sql クラス (コアクラスの一つです)を参照下さい。

以下のコードサンプルはかなり長いですが、 Sql_Query, DB_Sql,Tableクラスを用いてデータベースのテーブルにクエリを行う 完全に動作する例となっています。


<?php
  // この例を動作させるためには、preprend.incでsqlquery.incと
  // table.incをrequire()することが必要!
  page_open(array("sess" => "Example_Session"));

  $db = new DB_Example;   // これはDB_Sqlのサブクラス
  $t  = new Table;        // 結果整形用
  $t->heading = "on";     // 見出しが必要だ
?>
<html>
<head><title>Testseite</title>
<style type="text/css"><!--
h1          { font-family: arial, helvetica, sans-serif; color: #d33e30 }
table.test  { background-color: #eeeeee }
th.test     { font-family: arial, helvetica, sans-serif  }
td.test     { font-family: arial, helvetica, sans-serif }
table.query { background-color: #cccccc }
td.query    { font-face: arial, helvetica, sans-serif }
--></style>
</head>
<body bgcolor="#ffffff">
<h1>Testpage</h1>
<?php
  // 以下のフィールドは選択可能
  $field = array(
    "username"   => "Login Name",
    "password"   => "Password",
    "perms"      => "Permissions"
  );

  // 最初にこのページを開いたときには、$q は存在しません
  if (!isset($q)) {
    $q = new Sql_Query;     // 以下のような問い合わせフォームを作る
    $q->conditions = 1;     // ... まず最初に単一の問い合わせ条件を持ち、
    $q->translate  = "on";  // ... 列名は変換され、
    $q->container  = "on";  // ... 見易いコンテナテーブルを持ち、
    $q->variable   = "on";  // ... 検索条件の個数は可変であり、
    $q->lang       = "en";  // ... 英語で、よろしく

    $sess->register("q");   // これを忘れちゃいけない!
  }

  // このページを二度目に開いたときは、$baseで指定した名前の配列が
  // 設定されており、$queryを作成する必要があります。 
  // $q が作成したSql_Query オブジェクトの場合、$baseを"q"に
  // 設定してはいけません... :-)
  if (isset($x)) {
    $query = $q->where("x", 1);
  }

  // どんな場合でもフォームを今表示しなければいけません。
  // ここでの"x"と$q->whereが一致していなければならないということに
  // 注意してください。CSS"query"クラスとして全要素にタグを付けます。
  printf($q->form("x", $field, "query"));
  printf("<hr>");

  // 適正なクエリ文字列を有しているか?
  if ($query) {
    // 検索条件を表示する
    printf("Query Condition = %s<br>\n", $query);

    // クエリ実行
    $db->query("select * from auth_user where ". $query);

    // 結果の出力 (CSS class test としてタグづけ)
    printf("Query Results = %s<br>\n", $db->num_rows());
    $t->show_result($db, "test");
  }

  page_close();
?>
</body>
</html>

5.2 Table およびCSV_Table

Tableクラスは2次元の連想配列データやデータベースクエリの結果を テーブルとして整形する優れた方法です。 Tableとそのサブクラスに配列またはクエリ結果のいずれかを指定することにより、 全ての値を含むテーブルの正しいHTMLを出力することが可能となります。 Table はそれ自体に簡単なフィルタリング能力を持っており、サブクラス化しなくても 単独で使用可能です。Tableの全ての機能を利用するには、専用のサブクラスを作成する必要があります。

checkオプションと同時に使用した際、テーブルはHTML要素FORM の一部であると仮定されます。 それぞれの表の行の前にinput type="checkbox"を作成する コードが生成されます。 このチェックボックスは行番号に対応する連番を持つ配列として構成されます。 その配列名はcheckインスタンス変数にセットされた内容が常に使われます。

表の各行を生成する際に、2種類のカラムフィルタのどちらか1つが使用されます。 fieldsインスタンス変数に値が指定されている場合、その配列中で フィールド名がキーになっているカラムだけがその配列内の順番で出力されます。 つまり、fieldsインスタンス変数にarray("a", "c", "e")を 指定した場合、a, c, eというカラムだけが 生成される表の要素になるということです。

fieldsに値を指定しない場合、全てのデータ列がeach()で 走査され、filter中の正規表現に一致する名前の全てのカラムが表に表示されます。 デフォルトでは、この正規表現はアルファベットで始まり、残りが英数字または "_" (下線) になっている全てのカラム名を通過させます。 これがデフォルトとして選ばれたのは、DB_Sqlデータベースクラスがデータベースからデータを 取得するためにmysql_fetch_array()を内部的に用いており、この関数が 数値インデックスと本当のカラム名の両方の形式で2重に全てのカラムを返すからです。 デフォルトのフィルターは正しいカラム名で全てのデータを一度だけ表示させます。

加えて、インスタンス変数map_colsによりカラム名の再マッピング が可能です。map_cols に値が定義されている場合、見つかったカラム名を 新しい名前で置き換えます。

すなわち、fnamelnamemydateというカラムを 持つテーブルを以下のコードを用いることにより名前, , 日付に対応させることができます。 (なお、ここで$tは初期化したTableクラスのオブジェクトです)


$t->map_cols = array("fname"  => "名前",
                     "lname"  => "姓",
                     "mydate" => "日付");

インスタンス変数map_colsは、これと同じテクニックを用いて異なる言語の名前に カラムを対応づけることができます。

派生クラス用にインスタンス変数add_extraが追加されています。 この変数に値が指定されている場合、関数table_heading_row_add_extra()および table_row_add_extra()がコールされます。Table クラスにおいてはこれらの関数 は何もしませんが、派生クラスでこれらの関数に必要とされるさらなる機能性を提供するよう オーバーライドすることができます。すなわち、その行の編集削除詳細表示機能を提供するハイパーリンクをこれらの関数に容易に追加することができ、 大幅なカスタマイズを行えます。

Tableのサブクラスの一つであるCSV_Tableは最小の努力であなたのデータをCSV形式で 生成することができるように提供されています。CSV(コンマ区切りのデータ)は、MySQLの LOAD DATA INFILE 文でインポートしたり、多くの表計算ソフトのインポート機能に よるインポートが可能です。

Tableクラスは、現在モジュール化により高レベル、中レベル、低レベルの関数を提供しています。 プログラマーは、シンプルな高レベル関数を使うことや、複雑さの度合いに応じて中または 低レベルの関数のパワーを用いることができます。過去の互換性を維持するためのあらゆる努力を していますが、Tableクラスを広範囲に使用するならば新しい関数に慣れ親しんでおくのもよい 考えです。通常、高レベルと中レベルのサポート関数は show_で始まりますが、 低レベル関数ではそうではありません。

インスタンス変数

classname
(クラス名)
シリアル化ヘルパ: このクラスの名前
check 設定されている場合、チェックオプションが有効になります。
filter 表示するカラムを選択する正規表現。
fields 表示するカラム名のリスト。
heading フラグ: 値が指定されている場合、見出しが生成されます。
map_cols 静的なカラム名を置換されるカラム名のリスト。
add_extra フラグ: 値が指定されている場合、見出しと行用の拡張関数が呼ばれます。
アクセス可能なインスタンス変数

インスタンス操作

高レベルインスタンスメソッド

show($ary, $class = "")

上で説明したフィルタリング則に基づき、2次元配列(またはハッシュ)$aryを テーブルとして整形し表示します。$classに値が指定されていたら、 それぞれのHTML要素はそこで名前が指定されたクラスに属するものとしてタグが生成されます。 これはカスケーディング・スタイルシートを使用する場合に有用です。

show_page($ary, $start, $num, $class = "")

show()と同じですが、startを始点としてnum個の 要素だけが表示されます。

show_result($db, $class = "")

$db の結果セットを整形し表示します。$db は、クエリー を発行したDB_Sqlのサブクラスであることが想定されています。 Tableは、$db->next_record()を繰り返しコールして クエリーの結果セットから全ての結果を取得し、テーブル形式で出力します。

show_result_page($db, $start, $num, $class = "")

show_result()と同じですが、start を始点としてnum 個の要素だけを表示します。

中レベルインスタンスメソッド

show_table_rows($ary, $class="")

指定した配列を走査し、データの各行をHTMLテーブルの行として表示します。

show_table_rows_result($db, $class="")

指定したデータベースオブジェクトを走査し、各レコードをHTML テーブルの行として表示します。

show_table_page_rows($ary, $start, $num, $class="")

指定した配列を走査し、データの各行をHTMLテーブル行として表示します。ただし、 $start要素まで表示を開始せず、$num行表示した後も表示しません。

show_table_page_rows_result($db, $start, $num, $class="")

指定したデータベースオブジェクトを指定し、各レコードをHTMLテーブル行として表示します。 ただし、$startレコードまで表示を開始せず、$num個のレコードを 表示した後も表示しません。

show_table_heading_row($ary, $class="")

HTMLヘッダー行を生成するために指定した配列を使います。

show_table_heading_row_result($db, $class="")

HTMLヘッダー行を生成するために指定したデータベースオブジェクトを使います。

show_table_heading_cells($data, $class="")

指定した配列を走査し、それぞれのアイテムをHTMLテーブルヘッダーセルの中で表示します。

show_table_cells($row, $row_key, $data, $class="")

指定した配列を走査し、それぞれのアイテムをHTMLテーブルセルの中で表示します。

低レベルインスタンスメソッド

table_open($class = "")

この関数は、Tableのサブクラスでオーバーライドすることができます。 テーブル作成の一番最初で呼び出され、テーブルを開くためのHTMLを出力します。 (例えばprintf("<table%s>\n", $class?" class=$class":"");)

table_close()

この関数は、Table のサブクラスでオーバーライドすることができます。 テーブル作成の一番最後で呼び出され、テーブルを閉じるためのHTMLを出力します。 (例えばprintf("<table>\n");/)

select_colnames($data)

テーブルの列名のリストを生成するための内部ドライバ関数。

table_heading_row($data, $class = "")

テーブルの先頭行を生成するための内部ドライバ関数。

table_heading_cell($col, $val, $class)

この関数は、Tableのサブクラスでオーバーライドすることができます。 テーブルの先頭セルが生成される度にコールされます。

$col は現在のカラム番号、$val はカラム名、$class は生成される要素のためのHTML CSSクラスです。

table_heading_cell_open($class="")

ヘッダーセルを開始します。

table_heading_cell_close($class="")

ヘッダーセルを終了します。

table_heading_row_add_extra($data, $class="")

派生クラスのための仮想関数です。この関数は全てのヘッダーセルが生成された後にコールされます。 この関数によりプログラマーはヘッダー行を閉じる前にHTMLコードを追加することができます。

table_row($data, $class = "")

テーブルの行を生成するための内部的なドライバ関数です。

table_row_open($row, $data, $class = "")

この関数は、Table のサブクラスでオーバーライドすることができます。 一番最初の行が生成されるときにコールされ、テーブルの行を開始するHTMLを出力します。

$rowは現在の行番号です。$dataはこの行のために列名/値の ペアのハッシュであり、$class は生成する全ての要素のためのHTML CSSクラスです。

table_row_close()

この関数は、Tableのサブクラスでオーバーライドすることができます。 一番最後の行が生成されるときにコールされ、テーブルの行を閉じるHTMLを出力します。

table_cell($row, $cell, $key, $val, $class)

この関数は、Tableのサブクラスでオーバーライドすることができます。 テーブルのセルが生成されるたびにコールされます。

$rowは現在の行番号、$cellは現在のセル番号、 $keyは現在のカラム名、$valはセルの値、$class は生成されているその要素のHTML CSSクラスです。

table_cell_open($class="")

セルを開始します。

table_cell_close($class="")

セルを終了します。

set_checkbox_heading($class="")

この関数は、そのカラムのチェックボックスオプションと一致する空のヘッダーセルを生成します。

table_checkbox_cell($row, $row_key, $data, $class="")

チェックボックスを表示するためのHTMLコードを出力します。この関数は、メンバー変数 $checkに値が設定されているときに実行されます。$checkには、 $data配列の中のあるキーがセットされている必要があります。 (例えば、$data["myKey"]ならば$check="myKey" をセットします)

set_checkbox($row, $row_key, $data, $class="")

インスタンス変数$checkに値がセットされているときに限り、指定したデータを 基づきHTMLチェックボックスを生成します。

Tableはそれぞれのページで自動的にインクルードされたり事前に読み込まれたりされません。 Tableクラスを使うページでTableクラスをインクルードし、Tableのインスタンスを作成してください。


<?php
  // Table のインクルード
  require("table.inc");
  
  // Table インスタンスの生成
  $t = new Table;
  
  // 表の見出しを出力する
  $t->heading = "on";

次に2次元配列を生成するかデータベースクエリーの準備をし、 それを表示する表を作成、出力します。


  // データベースオブジェクトを生成
  $db = new DB_Session;
  
  // $tab という2次元配列を生成
  $tab = $db->metadata("active_sessions");
  
  // その配列を表示
  $t->show($tab, "metadata");
  
  // データベース問い合わせを準備
  $db->query("select * from active_sessions");
  
  // 結果を表示
  $t->show_result($db, "data");

5.3 Form

Formクラス(しばしばOOH Formsと呼ばれます)はHTMLフォームを扱うための便利な ライブラリです。内容の検証のためにJavascriptとサーバー側スクリプトを用いることができ、 カスタマイズおよび拡張が可能になっています。

OOH Formsの使用法

OOH Formsライブラリは次の5つのファイルから成っています。oohforms.inc, of_checkbox.inc, of_radio.inc, of_select.inc, of_text.inc, of_textarea.inc oohforms.incは自動的に他のファイルをインクルードします。 使用するフォーム要素用にファイルを手動でインクルードするようにこれを修正することが 可能です。もしくは、複数のインクルードを行う余計な負荷を避けるために oohforms.incに要素ファイルの内容をカット&ペーストしてもかまいません。 サイトにおける適切なファイル構成を決めることは、読者の課題として残されています。 しかし、ほとんどの目的において、require("oohforms.inc") で十分でしょう。

一般的に oohforms を用いるページの構造は以下のようになっています。


require("oohforms.inc");         // ライブラリをインクルード

$f = new form;                   // フォームオブジェクトを生成

$f->add_element(...);     // フォーム要素を準備
$f->add_element(...);    
$f->add_element(...);    

if ($submitname)                 // 処理するデータはあるか?
  if ($err = $f->validate()) {   // データは適正か?
    echo $err;                   // 適正ではない; エラーを表示
    $f->load_defaults();  // 送信されたデータとともにフォームを読み出し
  else {
    /* Process data */           // データに問題なし; それについての仕事をする
  }

$f->start(...);                  // フォームの表示を開始
$f->show_element(...);    // 要素を表示
$f->show_element(...);
$f->show_element(...);
$->finish();                     // フォームの最後

明らかにこのテーマについては多くのバリエーションがありますが、これで基本的な部分を カバーしています。各メソッドについては以下に文書化されています。

start($jvsname,$method,$action, $target)

開始タグ<form>を出力し、クラスで必要とされる初期状態を セットアップします。全ての宣言はオプションですが、JavaScriptによる検査を可能に するために少なくとも一つは使いたいと思います。$jvsnameはフォーム へのJavaScriptへのリンクを持つために使われる適当な文字列です。空(デフォルト)の場合、 JavaScript検査は提供されません。$methodはフォームを送信するHTTPメソッドです。 デフォルトは"POST"です。$actionはフォームを 送信するURLです。デフォルトは$PHP_SELFです。$targetは フォームの結果を表示するフレームのターゲットです。デフォルトは_selfです。

finish($after,$before)

フォームに追加されたhiddenフィールド、終了タグ</form>、 そしてJavascript検査コードを出力します。$after及び$before はともにオプションです。いずれかが空でない文字列であれば、フォーム送信前または後に、 フォーム送信時に走る追加のJavaScriptを出力します。宣言の順番は全く洗練されて いないように見えるかもしれませんが、通常は打ちやすいと思います。 通常、あなたはJavascriptで何か高級なことをするために行われる検査が終わるまで待つでしょうから。 検査とは異なり、OOH Formsはここであなたが使っているJavascriptと同等の機能を サーバー側で与える術を持ちません。

add_element($element)

add_elementはある特定のフォーム要素の属性を定義し、それによって 他のクラスメソッドがそれを適切に用い操作することができるようにするために用いられます。 add_elementは引数を1つだけ取ります。それは連想配列であり、 そのキーになる値のペアはフォーム要素の種類とその種々の属性を定義するために用いられます。 これらの属性のうちあるものはHTML属性に対応していますが、それ以外はoohforms への機能付加を必要とします。それが受け取る属性と値の文法並びに構文は以下で文書化されています。 全ての型の要素が全ての属性を使うわけではないことに注意してください。

type

この要素の種類。"submit", "hidden", "text", "textarea", "select", "radio", "checkbox", "file" のいずれかです。

name

この要素の名前を示す文字列。この名前は他の操作への引数として用いられ、生成された HTMLの中でname="" として使われます。 (従ってPHPにおける変数名にもなります)配列値を持つ要素にしたい場合でも、名前に []を追加しないでくださいmultiple属性を 代わりに設定してください。

value

このフォーム要素のデフォルト値です。フォーム要素のmultiple属性に 値が設定されていたら、valueは配列にすることができます。これが select要素の場合、value は、文字表記 (options配列中のlabel)か、送信される値 (options配列中のvalue)のいずれかを参照することもできます。

multiple

oohformsにこの要素が配列値であるとみなすよう通知するフラグです。このフラグは select要素でよく利用されますが、textcheckbox 要素でも同様に用いることができます。このような要素をoohformsがどう扱うかについては、 show_elementに関する記述を参照してください。

extrahtml

開始タグに挿入される追加HTMLコードです。select 要素では、optionタグではなくselectタグに挿入されます。

size

text要素において、テキスト入力ボックスの文字数幅を指定するHTML size 属性に値をセットします。select要素においては、選択ボックスのサイズ (一度に見ることができるオプション数)です。select 要素では size が1にセットされている場合にのみ検査が実施されます。 これは、複数のオプションを一度に見ることができた場合には、select検査は あまり意味がないからです。file 要素においては、アップロード可能な ファイルサイズの最大値です。

pass

text要素のために値がセットされていたら、パスワード要素として、 すなわち入力内容がアスタリスク(*)として表示されるようHTML出力します。

src

submit要素のために値がセットされていたら、イメージ要素に変換され、 そのイメージのソースURLとしてsrcの値が用いられます。

maxlength

text要素でmaxlength HTML属性としてそのまま使われます。

minlength

length_eに値がセットされていたら、これはtext要素が 検査機構により許容される入力の最低限の長さを示します。

length_e

値がセットされていたら、text要素が少なくともminlength 個の文字をもっているかどうかが検査されます。length_eは検査に失敗した ときにエラー文字列として用いられます。

valid_e

値がセットされていたら、text, radioまたは select要素で検査が実施されます。text要素においては、 検査はvalid_正規表現に合致するかどうか検査されます。 radio要素は、グループ中の一つが選択されたかどうかを検査します。 select 検査はmultipleに値がなくsizeが1 であるときにしか機能しません。検査はメニューのオプションの一番目を一種の案内 (例えば「アイテムを選択してください」)とみなして受け入れません。どの場合にも、 valid_e は検査に失敗したときに用いられるエラー文字列です。

valid_regex

valid_e に値がセットされていたら、テキストフィールドへの入力を 検査するために正規表現が用いられます。もし入力内容全体に一致する正規表現が ほしいならば ^...$ を使わないといけない点に注意してください。

icase

もし値がセットされていたら、正規表現で大文字小文字を無視します。

checked

multipleが使用されていないcheckboxでのみ使用されます。 checkedが設定されている場合、その要素はチェックされた状態で表示されます。

rows

textarea要素でrows=としてそのまま使われます。

cols

textarea要素でcols=としてそのまま使われます。

wrap

textarea要素でwrap=としてそのまま使われます。

options

select要素で表示されるオプションの配列です。配列の要素が単純な値 (文字列または数値)なら単純にそのとおりに表示され、その特定のオプションの値として 用いられます。 この要素は、それ自体"label""value" をキーとする連想配列とすることも可能です。この場合、"label" が表示され、"value"の値が送信に用いられます。

例:


$f->add_element(array("type"=>"text",
                             "name"=>"foo",
                             "valid_regex"=>"^[a-z]*$",
                             "valid_e"=>"文字のみ",
                             "icase"=>1,
                             "value"=>"bar"));
$f->add_element(array("type"=>"checkbox",
                             "name"=>"compress",
                             "multiple"=>1));
$f->add_element(array("type"=>"textarea",
                             "name"=>"comment",
                             "rows"=>6,
                             "cols"=>40,
                             "value"=>""));
$o = array(array("label"=>"以下から選択してください","value"=>0),
           array("label"=>"林檎","value"=>1),
           array("label"=>"オレンジ","value"=>2),
           array("label"=>"梨","value"=>3),
           array("label"=>"葡萄","value"=>4));
$f->add_element(array("type"=>"select",
                             "name"=>"menu",
                             "options"=>$o,
                             "size"=>1,
                             "valid_e"=>"果物を選択してください",
                             "value"=>"林檎"));

show_element($name,$value)

$nameで名前の指定されたフォーム要素を出力します。通常は2番目の引数は 使いません。multiple属性がセットされたradiochekbox要素では必須です。というのも、これらの多くは同じ名前をもつからです。 submit要素で送信ボタンにラベルを定義するためにも用いられます。 value属性はsubmit要素では使われません。配列値を取りうる 他の要素(とりわけtext要素)については、show_elementを 複数回呼ぶことで逐次値が表示されます。

load_defaults($element_list)

同じ名前をもつPHP変数の値をフォーム要素のデフォルト値としてセットします。 これは送信されたのと同じ値をフォームで再表示したいときに一般的に用いられます。 引数はオプションです。要素名の配列が指定された場合、これらの要素だけが影響を受けます。

validate($result,$element_list)

フォーム送信内容を検査します。もし全ての要素が適正であれば$resultを返し、 そうでなければ関係するエラーメッセージ(フォーム要素の valid_elength_e属性)を返します。$resultは、falseが デフォルトです。2番目の引数もオプションです。これは検査する要素の名前をもつ配列です。

freeze($element_list)

引数で指定した配列に含まれる名前を持つフォーム要素を凍結します。引数がなければ、 全ての要素を凍結します。凍結された要素は、フォームウィジェットではなく静的な 通常のHTMLとして表示されます。この静的表示には、凍結されていないバージョンの要素を 用いたのと同じ効果をシミュレートするための適切なhidden要素が伴っています。

OOH Formsのカスタマイズ

OOH Formsはオブジェクト指向に基づいているので、要素の型を定義するクラスを拡張する ことで容易にカスタマイズできます。一般的に、派生クラスはコンストラクタを 持たねばならず、またof_elementのself_*関数の好きなものをオーバーライド してもよいです。既に存在する要素のソースは、上記作業を適切に行うための最良の文書ですが、 若干の注意すべき点を以下に示します。

self_show($val,$which)

凍結されていないこの要素のインスタンスを表示します。 $valは値が1つであれば、show_elementの引数$value です。$whichは、値が配列となる要素においてインデックスとして用いられます。 この数は、この要素に関してshow_elementが以前にコールされた回数と 等しいです。この関数はhiddenタグ出力の個数を返さなければなりません。

self_show_frozen($val,$which)

凍結されたこの要素のインスタンスを表示します。凍結した要素を表示するためのHTML 出力に加えて、この種類の凍結されていない要素を送信することの効果を 2重化するためにhiddenフィールド用のタグを出力する必要があります。この関数は 出力するhiddenタグの個数を返します。

self_validate($val)

この要素の$valを検証します。適正であれば、falseを返し、 そうでなければ関連するエラー文字列を返します。

self_print_js($ndx_array)

この要素を検証するためのJavascriptコードを表示します。$ndx_arrayは、 Javascriptのform.element[]配列で用いられる検証の対象になる要素のインデックスをもった 配列です。これはその要素名を名前として持つ配列中の別の[]がJavascriptを 混乱させないために必要です。

self_load_defaults($val)

この要素のデフォルト値を$valとしてセットします。$val$this->valueにコピーするだけという、この関数のデフォルトの定義で 必要な全てを満たしていますが、それ以外の何かをすることが必要な特別なケースがあるかも しれません。例としてチェックボックス要素の実装を参照してください。

5.4 tpl_form

tpl_formクラスは、HTMLフォーム展開のための一般的な枠組みとして提供される ことが意図されています。このクラスはOOH Formsライブラリにかなり 依存しているために、関係する文書を読み、理解することが必要です。

中心になるアイデアは、実際にフォームをHTMLとして出力するためにOOH Forms に何らかのHTMLコードを混ぜたものをコールすることを可能にするような、 tpl_formのサブクラスによるブラックボックスを生成する点にあります。 アプリケーションはユーザーから何らかの入力を得るためにこのブラックボックスを 使うことが可能です。アプリケーションはユーザーの入力がどう扱われるかだけでなく、 入力データの適正さをどうやって検証するかについて知っている必要はなくなります。 というのも、内部メソッドがその面倒を見てくれるからです。

このアプローチはOOH Formsにとても似ています(私はそう思います)が、 それがより高いレベルで実現されているのです。OOH Forms要素は相互に 通信する手段がありませんし、データの一貫性について"簡単な" 確認しかできませんが、tpl_formでは、複雑なデータ評価や処理のための 一連のインターフェースが追加されています。

さらに、get_default_valuesset_default_valuesメソッドは、 フィールド名と値を持つハッシュ配列を用いることで、フォーム変数(a BAD THING (tm)) のシリアル化について心配せずに、セッション間でユーザーの入力を維持する ために用いることができます。

配列がアプリケーションでデータを共有するために用いられていることに注意してください。 これは一種の無駄ではないかと異議を申し立てるかもしれません。というのも、全ての ユーザー入力データはグローバル変数かHTTP_POSTまたはHTTP_GET グローバルハッシュで見つけられるからです。これは正しいですし、一般的なケースでは 空の配列を保存したり取り出したりするだけでしょう。values変数は、 フォームの振る舞いがその前にユーザーの入力したデータに依存するような、非常に複雑な データエントリの設定に使うことが意図されています。この場合、すべてのフォームが 共同してvaluesハッシュ配列に読み書きすれば、複数のHTMLページを渡り歩いて ステップバイステップで最終的な結果を構築することができるようになります。

インスタンス変数

classname クラス名です。シリアル化、及びフォームを実際にHTML化することが必要なHTML/PHP コードを含むテンプレートのファイル名を定義するためにdisplay中で用いられます。
error validate及びvalidate_input操作で生成されたエラー メッセージを保持します。
values
(値)
これは"共有メモリエリア"の1種です; フォームとアプリケーションの間で 用いられます。initメソッドの中で読み出され、get_values メソッドの中で戻されます。
form data
(フォームデータ)
(Formオブジェクトの)フォーム情報を保持します。
has defaults
(デフォルトあり)
フラグです。フォームのデフォルト値はset_default_values操作を 経由して渡されます。ユーザーはこれを置き換えるべきではありません。
内部インスタンス変数

インスタンスメソッド

アクセス可能なインスタンスメソッド

init($values)

これはクラスのコンストラクタの1種です。$values はget_valuesメソッドにより アプリケーションへ戻されるフォーム変数を格納する連想配列です。

get_default_values()

フォームからユーザーが送信した全てのデータが入っている配列を返します。 この配列はあとでset_defaults_valuesへ渡されます。

set_default_values($fv)

get_default_valuesにより返されるのと同じ配列からデフォルト値を復元します。

display()

実際にフォームフィールドを表示します。この操作は派生クラスにより上書きしては いけません。代わりにユーザーはこの派生クラスの名前が付いており、自動的にインクルードされる ".ihtml" 拡張子を持つファイルを提供するべきです。

get_values()

このメソッドはオーバーライドするべきではありません。アプリケーションとフォームの間の 中心的なインターフェースとして想定されています。 デザイナーのニーズを満たすフォームが適切に派生された後、アプリケーションは get_valuesをコールし、配列を返します。 この配列はinitに渡され、結局process_inputメソッドにより 修正されます。ユーザの入力が不正の場合はfalseが返されます。 後者の場合は、アプリケーションは適切なデフォルト値を代入してユーザーにフォームを (再)表示するためにdisplay()をコールする必要があります。

clear()

"デストラクタ"の1種です。メモリーを多少解放する以外に このメソッドをコールする必要性はありません。アプリケーションからコールされる 可能性がありますが、それ以外では実行されません。trueを返します。

内部インスタンスメソッド

setup()

全てのフィールド情報をもったFormオブジェクトを初期化します。 hiddenフィールドform_nameが自動的にこのルーチンによって追加され、 ユーザーにより既に送信されているかどうかを確かめるために他のメソッドにより使われます。 派生クラスによりこれを上書きするべきでなく、代わりにsetup_fields を用いるべきです。true を返します。

setup_fields()

要求を満たすフォームフィールド定義を提供するためにこのメソッドをオーバーライドして ください。

validate()

ユーザーの入力を検査します。この操作は派生クラスでオーバーライドするべきでは ありません。validate_input をその代わりに参照してください。エラー発生時 にはfalseを返し、関係するerror変数に値をセットします。

validate_input()

このメソッドは複雑な確認方法(例えば、フィールド1 == "other;" ならば フィールド2は空ではいけないとか)を提供したい場合には、派生クラスでオーバーライトする 必要があります。エラーが発生した場合にはfalseを返し、状況に応じた エラーメッセージをerror変数にセットする必要があります。

process()

ユーザーデータを処理します。このメソッドは派生クラスでオーバーライドするべきでは ありません。process_input及びprocess_defaultを代わりに 参照してください。成功したらtrueを返し、そうでなければfalse を返します。

process_input()

このメソッドは派生クラスでオーバーライドするべきです。検査が終わったら実行されます。 フォームへ渡されるデータはvalues配列へ代入するために用いられることがあります。

process_default()

このメソッドは派生クラスでオーバーライドすべきです。フォームの検査が失敗したか、 最初にフォームが表示される前に実行されます。もしデータが以前のアクション、占い、 ペンギンの飛行観察や他の物から抽出されたのであれば、フォーム表示を避けるべきです。

あなたは、彼女(アハ)の名前とe-mailアドレスを入力するフォームを持っているとしましょう。 あなたは、このe-mailアドレスが適正かどうかをチェックしたいと思っています。 そうでなければあなたの盲目的データセットアップは失われます。あ・・・ええと・・・ 構文的にe-mailアドレスを検証する単純な正規表現は以下の例のコードで表現されています。


 $this->form_data->add_element(array(
  "type"=>"text",
  "name"=>"email",
  "valid_e"=>"Syntax error in E-Mail address.",
  "valid_regex"=>"^([-a-zA-Z0-9.]+@[-a-zA-Z0-9]+(\.[-a-zA-Z0-9]+)+)*$"
 ));

さて、この短いコードは役目を果たしますが、あなたの今日の気分はとってもイカレているので、 アドレスのホスト名の部分をDNSを使って検証したいと思いました。そこで、あなたは入力内容 の中のホスト名を取得し、適正なホスト名ならtrue、そうでないなら falseを返すコードをいっしょにおきます。 (ヒント: PHP Code Exchangeで、 "現在有効な"電子メールの検証のプロシージャを見つけるべきです)

素晴らしいコードが書かれたため、アドレスをチェックできます。ユーザーがフォームに入力 した後、ユーザーの入力内容を解析し、構文エラーがないのでアプリケーションから mycheckhostをコールする時になりました。 この関数がOKならばデータベースを更新し、そうでなければフォームにデフォルト値をロードし、 再び表示し、ページを閉じ、終了します。

私は同じようなことを多くのフォームで行い、その中のいくつかは大変複雑な検証手順を 持っており、そして私は駄目で読みにくいコードを生産するのは非常に簡単なことに 気づきました。(そうです、私は、データ検証手順の中のロジックを変更しなければいけないとき に実際に悟りました...)

tpl_formは、フォームを構築する強固なフレームワークを提供するもの であり、全てのコードは自己包含的でメインのアプリケーションロジックから分離される ようになります。あなたが気に入ればいいのですが。

さて、コードをいくつか見てみましょう。まず最初にtpl_formのサブクラス のクラス宣言です。


class myform extends tpl_form {
  var $classname = "myform";
  
  function setup_fields() {
    $this->form_data->add_element(array(
     "name"=>"email",
     ..., // 省略された分は以前のコードを参照
    ));
    $this->form_data->add_element(array(
     "name"=>"submit",
     "type"=>"submit",
     "value"=>"submit"
    ));
  }
  
  function validate_input() {
    global $email;
    list($uname, $hostname) = split("@", $email);
    if (! mycheckhost($hostname)) {
      $this->error = sprintf("ごめんなさい、%s は不明なホストです。やり直してください", $hostname);
      return false;
    }
    // 追加のチェックはここに...
    return true;
  }
}

フォームをHTML化するためにHTMLとPHPコードを含んだmyform.ihtmlを 提供する必要があります。最小限の例を以下に示します。


<html>
<body>
<?php
 $this->form_data->start_form($this->classname, "POST", $sess->self_url(), "");
 printf("%s<br>\n", $this->error);
 $this->form_data->show_element("email");
 printf("<br>\n");
 $this->form_data->show_element("submit");
 $this->form_data->finish();
?>
</body>
</html>

tpl_formクラスは完成し、あとは芸術家としてのちょっとした仕事を残すだけ になりました... 8-)。真新しいクラスを用いるためにクラス定義コードをアプリケーションに 組み込み、それから...


$mf = new myform;
$mf->init(array()); // 現時点では、厳密に要求されていない
                    // が、推奨されている
if ($rv = $mf->getdata()) {
  $mf->clear(); // これは厳密に要求されているわけではないが、とにかくメモリーを
                // 少しでもフリーにすべきである...
  global $email;
  // あなたのデータを望むように処理
} else {
  $mf->display();
}

この大変小さな例が、少なくともすばやい設計とコード分割の観点からtpl_form クラスの本当の力を理解する助けになることを願っています。

5.5 Tree (ツリー表示)

Treeクラスはディレクトリの階層構造やHTMLにおけるメニューの構造といった ツリー構造を表現します。この構造は適切な深さをもったネストした配列の配列として Treeに与えられなければなりません。

Treeの理念は、ツリー構造はいくつもの数学的モデルで表現することができるという 点にあります。 あるモデルは、ネストした配列かポインタ構造のようなデータ構造で、それから多次元グラフ図を 出力するとか、ツリーのある枝を刈ったり完全な枝を挿入したりといったそれ以外の巧妙な処理が できます。しかし、ツリーを、一次元の文字列か、一連の関数のコール (数学的センスにかなり近いです)としてイメージすることも可能です。

ツリー構造からHTMLコードを生成するためには、このようにします。 ブラウザに何をするかを教える、1次元の文字列を最終的に必要とします。Treeクラスは 以下の方法でこの文字列を生成する手助けをします。すなわち、ツリー全体を一巡し、 通った各ステージにおいて複数の関数をコールするという方法です。 この関数を変更するのは作成者の仕事なので、素晴らしいレイアウトを作成されることでしょう。

インスタンス変数

classname
(クラス名)
シリアル化ヘルパ: クラスの名前
delimiter
(区切り)
"path" を短縮した文字
tree
(木)
配列の配列の配列
outp 「出力内容」そのもの
prfx, sufx, flag 内部用 - outp を生成するいくつかの補助
アクセス可能なインスタンス変数

インスタンスメソッド

アクセス可能なインスタンスメソッド

build_tree()

この関数は完全にユーザー主導です!以下に記述した構造をもった配列を生成しなければ なりません。詳細は例を見てください。

build_tree() によってコールされる独自の関数を生成することに臆病に ならないでください。例えば、再帰的コール。

go_trough_tree($key="",$path="",$depth=0,$lcount=0,$pcount=0)

これはこのクラスの中でも最も重要な関数です。適正なパラメータが与えられたら、 正しい順序で出力関数を呼び出します。

全ての変数はオプションです。現在サポートされていませんが、もし部分木を表示したい のであれば、これらパラメータは有益かもしれません。

path_to_index (&$path,$key="")

この関数はほとんどの場合内部的に用いられますが、$this->tree を生成するときに有益かもしれません。この関数は、パスからPHP3の連想配列の インデックス文字列を生成します。そのパスは文字列ですが、 $this->delimiterによって区切られた文字列です。$keyが 指定された場合には$pathに追加されます。 (空のパスかそういったものを考えてください)

例:


  $t->delimiter="/";
  $path= "usr/local/lib";
  ## $pathは変数として与えられなければならない、なぜなら参照によってコールされるから!
  $bla = $t->path_to_index($path,"etc");

  ## ここで、$pathは"usr/local/lib/etc"です
  ## ここで、$blaは["usr"]["local"]["lib"]["etc"]です

path_to_parent (&$path)

この関数は内部では使われませんが、ツリー表示を出力するときに有益かもしれません。 これはパスのある深さから1段取り除きます。

例:


  $t->delimiter="/";
  $path= "usr/local/lib";
  $bla = $t->path_to_parent($path);

  ## $path は、"usr/local"です
  ## $bla は、["usr"]["local"]です

path_add ($path,$key)

この関数は、path_to_indexの「参照でコールされないバージョン」です。 この関数は、$keyをパスに追加して返します。

path_sub ($path)

この関数は、path_to_parentの「参照でコールされないバージョン」です。 この関数は、パスの親を見つけ、それを返します。

path_index ($path)

この関数は path_to_index() の「参照でコールされないバージョン」です。 これはパスにより記述されたツリーへの連想キーを返します。

starttree ()

この関数はツリー表示の出力の開始時にgo_through_tree()によりコールされます。

全ての*tree-関数はgo_trough_tree()によりコールされますが、 素晴らしいレイアウトを提供するためにあなたに順番が回ってきます。 私はこれを用いてほぼあらゆる種類のツリーのレイアウトを生成することが可能であると 考えています。変数を見てください。例えば、$depthは他の方式であらゆる "level"を扱うことが可能になります。

growtree ($key,$value,$path,$depth,$count,$pcount)

この関数はツリー表示の出力の開始時にgo_trough_tree()によりコールされます。

go_trough_tree()がそれ自身を再帰的に呼び出すたびに毎回コールされます。 これは、現在の要素がそれ以下の要素を持つ時、とも言えます。

leaftree ($key,$value,$path,$depth,$count,$pcount)

この関数は、現在の要素がそれ以下の要素を持たないときにコールされます。

shrinktree ($key,$depth)

この関数は、growtree()の"反対"です。現在の要素がこの サブリストでの最後の要素であるときに、いつもコールされます。

endtree()

ツリーを離れるときに呼ばれます。

Treeの配列

上述のようにgo_trough_tree()をコールする前にまず$tree を生成しておかないといけません。

$tree は適当な深さを持ったネストした一連の配列です。以下がその例です。


$t= new Tree;
$t->tree = array(
                "usr" => array(
                  0       => "許可",
                  "lib"   => "禁止",
                  "local" => "許可",
                  "bin"   => "禁止",
                  "etc"   => array(
                     0       => "許可",
                    "hosts"  => "禁止",
                    "mailcap"=> "許可"
                  ),
                  "var"   => "許可",
                  "tmp"   => "許可"
                ),
                "root" =>"禁止"
              );
$t->go_through_tree();
print $t->outp;

これは完全に再帰的な構造です。関数の再帰的コールによりこれを作成する 方法は明らかだと思います。明らかでないならば、以下の例を参照下さい。

ある小さな奇妙な点について説明が必要です。というのも、これは少々混乱を招くからです。 0(ゼロ)という名前の配列は親の要素の値として用いられます。例で示したように、子供 (例えば"etc")を持つ要素は属性("許可"など)を持つことができません。その代わり、 この要素の値は0という名前をもつ擬似的な子供の中に格納されます。この要素が存在しない場合、 値"Array"(おそらく変更が必要なもの)を持つでしょう。

この例の出力結果は、出力関数を変更していない場合は、以下のようになります。


/
^---- usr->'許可' : 'usr' (1) [1/2]
|    ^---- lib->'禁止' : 'usr^lib' (2) [2/7]
|    O---- local->'許可' : 'usr^local' (2) [3/7]
|    O---- bin->'禁止' : 'usr^bin' (2) [4/7]
|    O---- etc->'許可' : 'usr^etc' (2) [5/7]
|    |    ^---- hosts->'禁止' : 'usr^etc^hosts' (3) [2/3]
|    |     \--- mailcap->'許可' : 'usr^etc^mailcap' (3) [3/3]
|    O---- var->'許可' : 'usr^var' (2) [6/7]
|     \--- tmp->'許可' : 'usr^tmp' (2) [7/7]
 \--- root->'禁止' : 'root' (1) [2/2]

少し分かりにくいですね。左から右にかけてのフィールドは、それぞれ以下のように なっています。

この例はハードディスクのディレクトリ構造を一巡します。

以下のコードでそれを読むことができます。


class dir_Tree extends Tree {
     var $classname = "dir_Tree";
     var $delimiter="/";

     var $tdat;

     function build_tree ($path=".") {
         $this->tree=$this->recurs_dir($path,0);
     }

     ## この例のコードは、私のシステム (P200, 64MB) ではおよそ 20 秒で
     ## 多くのサブディレクトリを持つ 1000 のディレクトリエントリを読んで
     ## 出力できます。最大で 4 の深さを持つ 220 のエントリを 2 秒で読みます。
     ## OK ですね。

     function recurs_dir ($path,$depth) {
     GLOBAL $flap_out;
         $d=opendir($path);

         while ( $name=readdir($d) ) {
             $pathname=$path . $this->delimiter . $name;
             if (is_dir($pathname) && !ereg("\.\.?",$pathname)) {
                 if (isset($flap_out[$pathname])) {
                     $array[$name]=$this->recurs_dir($pathname,$depth+1);
                 }
                 # 注意: 配列[0]を埋めるのは、配列の残りの部分の後
		 #       にすることが重要です! 
                 $array[$name][0]=$pathname;
             } else {
                 $array[$name]=$pathname;
             }
         }
         closedir($d);
         return($array);

     }

     #################################################
     ## INとOUTを切り替えます
     ## これは見せるべき全てのサブパスを含む配列を
     ## 生成するために使います
     ## 

     function flapping ($path) {
     GLOBAL $flap_out;
         if ($path) {
             if (is_dir($path)) {
                 if (isset($flap_out[$path])) {
                     unset($flap_out[$path]);
                 } else {
                     $flap_out[$path]=$name;
                 }
             }
         }
     }
}

$t= new dir_Tree;
## $valはGETメソッドにより指定されます。*tree-関数を参照。
$t->flapping($val); 
$t->build_tree();
$t->go_through_tree();
print $t->outp;

このコードでは、ツリーの要素全体でinとoutを切り替えやすくしています。 GET メソッド経由でパスを送信し、このパスをflapping()に渡しています。 $flap_out-配列全体は(例えばsessionにより)永続化する必要があります。 おそらく、あなたは、$flap_outを見てパスが既に存在するかどうかを調べるガーベージ コレクションをプログラムするでしょうか?

既知のバグとヒント

既知のバグが一つあります。サブパスの名前が$delimiter文字列を 含んでいる場合です。これを適切に解決するのは無理であり、ツリーを生成するときに 注意しなければなりません。

同じことがサブ配列の値[0]にもあてはまります。この要素は常に親要素として扱われます。 後で[0]-索引に値を代入する必要があります。 私が何を言っているかは上の例を参照してください。これはPHP3に特有だと思います。

また全ての名前を連想インデックスフィールドに挿入しない(制御コードなど)ことも 可能ですが、これはテストしていません。

5.6 STRINGS2 関数集

これは私が頻繁に用いた一連の関数です。

これらは単純なので、私は説明することを止め、単純にコードを挿入することにしました。 おそらくこれの次のリビジョンでは私はもっとまともな説明で置き換えるつもりです。


<?php
##
## Strings2-関数集
##
## Copyright (c) 1998,1999 Alex 'SSilk' Aulbach
##
## これらの関数はとても実用的であり、もし私がもっと C で
## プログラムを書けたら PHP3 に直接組み込んだでしょう。
## でもできませんでした... :-}
##


##
## あなたはこんな文に恐れおののいたことはありませんか?
##    echo ($faxnumber) ? sprintf("Fax: %s",$faxnumber) : "";
##
## これは上記のような文を次の文で置き換え、あなたの手助けをします
##    p_iftrue($faxnumber,"Fax: %s");
## これで入力すべき文字は半分になり、より明晰に見え、もし $faxnumber が
## 未定義の場合に起きるエラーを解決します。
##
function o_iftrue ($val,$str) {
        if (isset($val) && $val) {
                return(sprintf($str,$val));
        }
}
function p_iftrue ($val,$str) {
        print o_iftrue($val,$str);
}

##
## 「一つまたはそれ以上」を出力
##
## この関数は、もし個数によって出力を変えたいときに便利です。
##  例)   o_1or2($q->num_rows(),
##               "一致するレコードは一つでした",
##               "%s 個のレコードが見つかりました");
## は、もし num_rows() が 1 ならば「一致するレコードは一つでした」
##                        200 ならば「200 個のレコードが見つかりました」
## を出力します。
##
## もし $val が空か "" であれば空白文字列が返されます!
##
function o_1or2 ($val,$str1,$str2) {
        if (isset($val) && $val) {
                if (1==$val) {
                        return(sprintf($str1,$val));
                } else {
                        return(sprintf($str2,$val));
                }
        } else {
                return(false);
        }
}
function p_1or2 ($val,$str1,$str2) {
        print o_1or2 ($val,$str1,$str2);
}


##
## これは、$valがfalseの場合に何かを出力したい場合です。例えば、
##
## p_0or1($faxnumber,"FAX 番号がありません", "Fax 番号: %s");
## 
function o_0or1 ($val,$str1,$str2) {
        if (empty($val) || !$val) {
                if (isset($val)) {
                        return(sprintf($str1,$val));
                } else {
                        return($str1);
                }
        } else {
                return(sprintf($str2,$val));
        }
}
function p_0or1 ($val,$str1,$str2) {
        print o_0or1 ($val,$str1,$str2);
}

##
## %nbsp; による全ての空白文字列を置き換えます
## この関数はブラウザがあなたの行を破壊することを好まず、非常に互換性のある
## 代替品としてタグを代わりに用いるときに用います。
##
##   はISO-Latin-1でのコード番号160を持つ本当の空白で
## 置き換えることができます
##
function o_nonbsp ($val) {
        return(ereg_replace("[[:blank:]\n\r]"," ",$val));
}
function p_nonbsp ($val) {
        print o_nonbsp($val);
}
?>


次へ 前へ 目次