コメント以外のコードはメモ帳アプリケーション(西沢直木氏作)より引用
<html>
<!-- html文書のbodyにPHPを書く。 -->
<head>
<title>メモ帳アプリケーション(PDO関数)</title>
</head>
<body>
<h3>メモ帳アプリケーション(PDO関数)</h3>
<!-- 小見出し -->
<?php
// データの取得
//ここからPHP。データの取得というより変数の初期化。
$act = (isset($_POST["act"])) ? $_POST["act"] : "";
//$actという変数は「新規作成」とか「保存」などの行為(action)を示す値をとる。
//?は三項条件演算子(a? b : c aが真ならb,偽ならc)C言語でよく使う。IF文の方がわかりやすいけど。
//isset(変数)は変数がセットされているどうか調べてセットされていればTRUE、されていなければFALSE。
//$_POST["act"]はフォームのPOSTメソッドのinputでactという名前でブラウザから要求された値がセットされる変数。
//結局$actは$_POST["act"]に値があればその値とし、なければNULLとする、ということ。
$id = (isset($_REQUEST["id"])) ? intval($_REQUEST["id"]) : "";
//$_REQUEST["id"]は、GETメソッドかPOSTメソッドでidという名前でブラウザから要求された値がセットされる変数。
//POSTメソッドとGETメソッドの違いはhttp://nyx.pu1.net/practice/external_var/external_var2.php
//要するにフォーム以外のハイパーリンクとかのブラウザからの要求は全部GETメソッド。
//intvalは整数の数値。
//結局、結局$idは$_REQUEST["id"]に値があればその整数値とし、なければNULLとする、ということ。
$contents = (isset($_POST["contents"])) ? $_POST["contents"] : "";
//$contentsは本文。
//$_POST["contents"]はフォームのPOSTメソッドのinputでcontentsという名前でブラウザから要求された値がセットされる変数。
//結局$actは$_POST["contents"]に値があればその値とし、なければNULLとする、ということ。
$title = (isset($_POST["title"])) ? $_POST["title"] : "(無題)";
//$titleは題名。
//$_POST["title"]はフォームのPOSTメソッドのinputでtitleという名前でブラウザから要求された値がセットされる変数。
//結局$actは$_POST["title"]に値があればその値とし、なければ(無題)とする、ということ。
$dt = date("Y-m-d H:i:s");
//$dtに現在の日付と時刻をセット。
//yyyy-mm-dd hh:mm:ssという形式はSQLiteの日付、時刻関数でも認識できる形式。
// データベースの初期設定
$conn = init();
//init()はユーザー定義関数(あとで記述されるfunction init()で戻り値は$conn)。
//ユーザー定義関数というのはサブルーチンのようなもんで、一連の処理を書いたものであり、
//必要に応じてそれを呼び出す。
//引数を与えればそれに処理を加えた戻り値が返ってくる。
//引数が無くても処理後の戻り値だけある場合や、引数も戻り値も無い単なるサブルーチンという場合もある。
//function 関数名(引数) {
// 処理に必要なプログラム
// return(戻り値)
// }
//関数は上記の形で定義される。このプログラムの場合、関数名はinit()であり、これを書くことで呼び出される。
//引数は無いし、$connの値を戻すだけの関数である。
//$connが何を意味するのか?connection、つまり、接続ということで、
//具体的には$conn = new PDO("sqlite:memo.sqlite")という値がinit()でセットされる。
//ともかくここで$connにinit()というユーザー定義関数の戻り値をセットし、直後の処理分岐で使う。
if ($act == "保存" and $contents <> "") { // 保存
if (empty($id)) { // 新規保存
$id = add_data($conn, $title, $contents, $dt);
} else { // 既存データの保存
update_data($conn, $id, $title, $contents, $dt);
}
//もし$act(行為)が"保存"でかつ$contents(本文)がNULLなら保存だけど
//$idが空なら新規保存だけどユーザー定義関数add_dataを4つの引数で実行し、戻り値を$idにする。
//それ以外なら既存データの保存で、ユーザー定義関数update_dataを5つの引数($idを含む)で実行。
} elseif ($act == "選択したデータを削除") { // 削除
if (isset($_POST["c1"])) {
delete_data($conn, $_POST["c1"]);
} else {
echo "削除するデータが選択されていません";
}
//それ以外でもし$act(行為)が"選択したデータを削除"なら削除だけど、
//フォームのPOSTメソッドのinputで"c1"という名前(チェックボックス)で
//ブラウザから要求された値(具体的にはidの値)があれば、
//ユーザー定義関数delete_dataを2つの引数$connとidの値で実行する。
//それ以外なら"削除するデータが選択されていません"と表示。
} elseif ($act == "全データを削除") { // 全データ削除
delete_all_data($conn);
//それ以外でもし$act(行為)が"全データを削除"なら全データ削除つまり
//ユーザー定義関数delete_all_dataを引数$connで実行する。
} elseif ($act == "新規作成") { // 新規作成
clear_data();
//それ以外でもし$act(行為)が"新規作成"新規作成つまり
//ユーザー定義関数clear_data();を引数なしで実行する。
} elseif (!empty($id)) { // 編集
$row = get_data($conn, $id);
$title = $row["title"];
$contents = $row["contents"];
}
//!は論理演算子で否定。!aならaでないということ。それ以外でもし$idが空でなければ編集つまり
//ユーザー定義関数get_dataを$connと$idの2つの引数で実行し、戻り値を$rowにする。
//$title(題名)をtitle番目の$rowとする。え?row番目の$titleじゃないの?
//正しくは$title = $title["row"];じゃないの?
//$contents(本文)をcontents番目の$rowとする。え?え?row番目の$contentsじゃないの?
//正しくは$contents = $contents["row"];じゃないの?
//おかしいよ。でもプログラムは正常に動作している。
//僕の思う正しくはのように書き変えたら正常に動作しなかった。そりゃそうだ。
//$rowは行番号ではない!!$idに書かれているデータ(タイトルと本文)である。rowなんて名前にしないで!
//この場合の戻り値$rowは、連想配列である。連想配列というのは添字が文字の配列。
//$row["title"]は、この$idのタイトルのデータ。$row["contents"]は、この$idの本文のデータ。
//つまり、編集の時に該当$idのタイトルと本文を$titleと$contentsにセットするということ。
//ここで、$rowという変数名について考えておきたい。Excelなどでrowといえば行番号だと反射的に思ってしまったのが
//大きな間違い。リレーショナルデータベースにおいて、行というのは、複数のデータの組み合わせを格納する単位である。
//データベース全体を表として見た場合、1つの行は横長に伸びた形で表示される。
//1つの行に含まれるデータはひとかたまりとして扱われ、それぞれの行は主キー($id)によって識別される。
//例えば住所録の場合、氏名や住所・電話番号などを合わせた1人分のデータが1つの行を構成する。
//つまりRDBにおいて、ROWといえばIDによって識別される1件分のデータの塊である。
//だから列を添字とした連想配列で表す。行番号の働きは$idが担っている。
//だいぶ読めてきた。後は心臓部であるユーザー定義関数。
//ここに、具体的にどのようにPHPとSQLiteが連携するのかが書かれている。
//このプログラムは教材だけあって非常に解読しやすく書かれている。
//他人のプログラムは、とかく意味不明理解不能ということになりがちだ。
//ひどい場合には、読めるもんなら読んでみろ!
//なんてプログラムを親切そうな顔してわざわざ持ってくる人も居る。有難迷惑だ。
//しかし、このプログラムは自分で書くよりよくわかるような書き方だ。
// データベースの初期設定
function init() {
// データベースに接続
$conn = new PDO("sqlite:memo.sqlite");
// データベースの作成
$sql = "CREATE TABLE IF NOT EXISTS memo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
contents TEXT NOT NULL,
dt TEXT NOT NULL
)";
$stmt = $conn->prepare($sql);
$stmt->execute();
return $conn;
}
//いよいよPHPのPDOでSQLiteに接続する。
//$conn = new PDO("sqlite:パスとデータベースファイル名");
//接続の決まり文句。これで$connにPDOクラスのインスタンス(戻り値)がセットされて、接続される。
//$conn = NULL とすれば切断されるが、わざわざやらなくていい。
//普通、PHPはSQLiteにクエリ(query:問い合わせ)を投げかけ、
//SQLiteはその問い合わせ(クエリ)に応じて、回答するが、
//上記の場合は
//1.あらかじめSQL文を定義する($sqlにSOL文を代入する。文の意味はコマンドラインの練習でやったようなことなので略)。
//2.必要に応じて値をセットする(prepareにSQL文を引数として渡し、戻り値をプリペアドステートメントとする)。
//3.実行する(execute()でそのプリペアドステートメントを実行する)。
//$connを戻り値として保持しつつ呼び出し元に帰る。
//PDOプリペアドステートメントに対するメソッドや定義済み定数は下記URL参照。
//http://www.phpmanual.jp/ref.pdo.html
//データの追加(処理分岐では新規保存となっている)
function add_data($conn, $title, $contents, $dt) {
$sql = "INSERT INTO memo(title, contents, dt)
VALUES(:title, :contents, :dt)";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":title", $title);
$stmt->bindParam(":contents", $contents);
$stmt->bindParam(":dt", $dt);
$stmt->execute();
$id = $conn->lastInsertId();
return $id;
}
//データの追加(処理分岐では新規保存となっている)
//題名、本文、投稿日時を追加するSQL文を$sqlに代入。
//$sqlによるプリペアドステートメントをセットする。
//bindParam - プリペアドステートメントのパラメータに PHP 変数をバインドする
//なんてややこしいことがマニュアルに書いてあるが、(引数でもらっている)変数を
//プリペアドステートメントの各項目のデータとして入力するって事である。
//$stmt->execute()でプリペアドステートメントを実行。
//$conn->lastInsertId()は最後に追加した行の IDを返す。
//この値を$idとして戻り値とする。
// データの変更
function update_data($conn, $id, $title, $contents, $dt) {
$sql = "UPDATE memo SET
title = :title,
contents = :contents,
dt = :dt
WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":id", $id);
$stmt->bindParam(":title", $title);
$stmt->bindParam(":contents", $contents);
$stmt->bindParam(":dt", $dt);
$stmt->execute();
}
//データの変更(処理分岐では既存データの保存となっている)
//引数でもらったidの題名、本文、投稿日時をとりあえずセットするSQL文を$sqlに代入。
//$sqlによるプリペアドステートメントをセットする。
//bindParam - プリペアドステートメントのパラメータに PHP 変数をバインドする
//なんてややこしいことがマニュアルに書いてあるが、(引数でもらっている)変数を
//プリペアドステートメントの各項目のデータとして入力するって事。
//$stmt->execute()によりプリペアドステートメントを実行。戻り値無し。
// 指定データの削除
function delete_data($conn, $data) {
$sql = "DELETE FROM memo WHERE (id = :id)";
$stmt = $conn->prepare($sql);
for ($i = 0; $i < count($data); $i++) {
$stmt->bindParam(":id", $data[$i]);
$stmt->execute();
}
clear_data();
}
//$dataはチェックボックスの表示で何番目のチェックボックスなのかを示す値。
//未定のidの行を削除するSQL文を$sqlに代入。
//$sqlによるプリペアドステートメントをセットする。
//idを$dataの値とするが、複数チェックされている場合があるので
//それぞれの$data(配列変数)のidについて、
//$stmt->execute()によりプリペアドステートメントを実行。(削除実行。)
//$data(配列変数)をすべてNULLにする。
// 全データの削除
function delete_all_data($conn) {
$sql = "DELETE FROM memo";
$stmt = $conn->prepare($sql);
$stmt->execute();
clear_data();
}
//全データを削除するSQL文を$sqlに代入。
//$sqlによるプリペアドステートメントをセットする。
//$stmt->execute()によりプリペアドステートメントを実行。(削除実行。)
//$data(配列変数)をすべてNULLにする。
// データのクリア
function clear_data() {
global $id, $title, $contents;
$id = "";
$title = "(無題)";
$contents = "";
}
//function外でも通用するように$id, $title, $contentsをglobal宣言し、
//それぞれ消す。
// 編集データの取得
function get_data($conn, $id) {
$sql = "SELECT * FROM memo WHERE id = :id";
$stmt = $conn->prepare($sql);
$stmt->bindParam(":id", $id);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
return $row;
}
?>
//引数でもらったidの行を選択するSQL文を$sqlに代入。
//$sqlによるプリペアドステートメントをセットする。
//引数でもらっているidをプリペアドステートメントのデータとして入力する。
//$stmt->execute()によりプリペアドステートメントを実行。
//fetch(PDO::FETCH_ASSOC)は行全体を各カラムを添字とする連想配列として返す。
//行全体を各カラムを添字とする連想配列として$rowに代入する。
//$rowを戻り値として呼び出し元に帰る。
<form method="POST" action="<?php echo $_SERVER["SCRIPT_NAME"]?>">
<table>
<tr>
<td><input type="text" value="<?php echo $title?>"
size="50" name="title"></td>
</tr>
<tr>
<td>
<textarea name="contents" rows="10"
cols="60"><?php echo $contents?></textarea>
</td>
</tr>
<tr>
<td>
<table>
<tr>
<td>
<input type="hidden" value="<?php echo $id?>" name="id">
<input type="submit" value="保存" name="act">
</td>
<td>
<input type="submit" value="新規作成" name="act"
onClick="return confirm('新規作成します')">
</td>
<td>
<input type="submit" value="選択したデータを削除"
name="act"
onClick="return confirm('削除して良いですか?')">
</td>
<td>
<input type="submit" value="全データを削除" name="act"
onClick="return confirm('削除して良いですか?')">
</td>
</tr>
</table>
</td>
</tr>
</table>
//いくらなんでも読めるが、1行目
//<form method="POST" action="<?php echo $_SERVER["SCRIPT_NAME"]?>">
//<form method="postまたはget" action="URI"> ~ </form>
//フォームの送信形式postまたはgetと送信先のURIを記述。
//$_SERVER["SCRIPT_NAME"]は実行中のスクリプトのパス返す。
//$idは表示しないのでhidden
//onClick="return confirm('確認文')"はjava環境で確認文つきのボタンとなる
<tr>
<td><input type="text" value="<?php $title=stripslashes($title);echo $title?>"
size="50" name="title"></td>
</tr>
<tr>
<td>
<textarea name="contents" rows="15"cols="100"><?php $contents=stripslashes($contents);echo $contents?></textarea>
</td>
</tr>
<?php
// 全データの取得
$sql = "SELECT * FROM memo ORDER BY dt DESC";
$stmt = $conn->prepare($sql);
$stmt->execute();
// データの一覧表示
echo "<table border=\"1\">";
echo "<tr>";
echo "<td>削除</td>";
echo "<td>タイトル</td>";
echo "<td>最終更新時刻</td>";
echo "</tr>";
while ($row = $stmt->fetch()) {
echo "<tr>";
echo "<td><input type=\"checkbox\"
name=\"c1[]\" value=\"" . $row["id"] . "\"></td>";
echo "<td><a href=\"" . $_SERVER["SCRIPT_NAME"]
. "?id=" . $row["id"] . "\">". $row["title"]
. "</a></td>";
echo "<td>" . $row["dt"] . "</td>";
echo "</tr>";
}
echo "</table>";
?>
</form>
</body>
</html>
//ORDER BY dt DESC 登録日時で降順に並び替え。
//while ($row = $stmt->fetch()) {
//配列変数である行全体の内容を受け取ることが真である間ということだろう。
//この最後の表示のところのループがイマイチわからん。
//まあ、ここまで読めたら良しとしよう。
//次は改造。