自宅サーバー・Apche・PHP・PDO・SQLite環境でのメモ帳アプリの活用

  • メモ帳アプリはすべてが入っている教材でもあるが、実際そのまま使える道具でもある。これをサーバーに置いて本文にHTMLやXMLを書けば、それらの文はそのままWEBページに表示できるでしょ。
  • 極端な話、WEBページのすべての文をデータベースからデータとして拾ってきて構成することもできる。
  • そこまでやることはないが、例えば新着情報や、日替わりメニューや、リンクや、RSSや、その他頻繁に更新する部分はデータベースのデータとしておけば何時でもどこでもブラウザさえ開ければメモ帳アプリにアクセスして編集できるのだ。極端な話、携帯からでもできるだろう。FTPサーバーもFTPソフト必要ない。
  • 僕は自宅のWindowsパソコン1台をWEBサーバーにしているが、メールはもちろんFTPもやっていない。ポートを開けると、何かと面倒なので。更新は直接書きかえるか、@WikiのFTPにHTML文などを入れて、それを参照している部分はそのファイルを書きかえている。データベースにホームページの内容が入っていれば、そうした不便から開放される。サーバーはWEBサーバーだけでよい。

メモ帳アプリの具体的な使い方

  • 公開しているディレクトリにメモ帳アプリを置かないと「いつでも、どこでも」更新できないので意味がない。公開ディレクトリに置くためには自分(または管理者)しか操作できないように一応の対策をする。国家機密じゃあるまいしそんなに大そうには考えず、PHPによるベーシック認証ですませる。レッツPHP!の小物の中の-パスワード制限-のプログラムを使わせていただく。レッツPHP!というサイトは本当に好感が持てる。シンプルなのによーく考えられている。メモ帳アプリのプログラムの先頭にinclude_once("auth.php");と書くだけでベーシック認証しないとプログラムが走らないようになるのだ。無論パスワードを書いたテキストファイルは公開ディレクトリ以外に置いてフルパスで指定。こうすればかなり悪意がない限りデータを書きかえられることはない。なお、SQLiteのデータベースファイルはこれも公開ディレクトリより上に置けばダウンロードされることもない。かなりセキュア。
  • メモ帳アプリで「新着情報」、「お知らせ」などのHTMLやRSSのXMLを登録し、実際にそれらを表示するページに次のようなPHPを挿入すればちゃんと表示される。これによって、「いつでもどこでも」手軽に内容を更新できるというわけ。FTPサーバーも、FTPソフトもいらない。ブラウザさえ開くことができる環境なら世界中どこからでも自宅サーバーの更新ができる。
  • メモ帳アプリに習ってプリペアでやるなら、
<?php
// データベースに接続
$conn = new PDO("sqlite:memo.sqlite");
$sql = "SELECT * FROM memo WHERE id = 5";
$stmt = $conn->prepare($sql);
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
echo $row["contents"];
$conn = null; 
?>
  • まあ、でも普通はクエリにSQL文を書くでしょ。
<?php
$conn = new PDO("sqlite:memo.sqlite");// データベースに接続
$stmt = $conn->query('SELECT * FROM memo WHERE id = 5');//検索
$row = $stmt->fetch(PDO::FETCH_ASSOC);//行全体を連想配列として取得
$conn = null;//接続を切る
echo $row["contents"];//本文を表示
?>
  • この例ではidで検索しているが、titleで「新着情報」とか「お知らせ」とかで検索したほうがわかりやすいと思う。
<?php
$conn = new PDO("sqlite:相対指定パス/memo.sqlite");// データベースに接続
$stmt = $conn->query('SELECT contents FROM memo WHERE title = "新着情報"');//検索
$row = $stmt->fetch(PDO::FETCH_ASSOC);//行全体を連想配列として取得
$conn = null;//接続を切る
echo $row["contents"];//本文を表示?>
  • 普通に表示すると、なぜか「"」だとか漢字の「定」の文字だとかの前にやたらとバックスラッシュが入る。PHPでは普通にあることなのか、それを取り除く関数があるのだ。stripslashesというやつです。これを使えば解決。
  • だけど根本はフォームでPOSTする度にセキュリティーの関係でこうなるらしい。それで、フォームからのPOSTを受ける$_POSTという連想配列のようそについて、stripslashesを施してやれば、全て解決する。メモ帳アプリであれば、
// データの取得
$act = (isset($_POST["act"])) ? $_POST["act"] : "";
$id = (isset($_REQUEST["id"])) ? intval($_REQUEST["id"]) : "";
$contents = (isset($_POST["contents"])) ? stripslashes($_POST["contents"]) : "";
$title = (isset($_POST["title"])) ? stripslashes($_POST["title"]) : "(無題)";
$dt = date("Y-m-d H:i:s");
  • ここのところでやれば他のところは何もしないほうがいい。いろんなところでやると、5C問題にぶち当たる。「ソ」や「表」が文字化け。これは、\を取り除きすぎなんだよ。めったやたらととっぱらっちゃ駄目です。
  • stripslashesは$_POSTで使えば次のfgetcsvであろうが、shift-jisでも問題なく使える。

メモ帳アプリを改造してCSVファイルをインポート

  • CSVのインポートはGUIやコマンドラインツールに用意されているが、実際やったら文字化けで無理。調べると、SQLiteはUTF-8でないと駄目で、HTMLもUTF-8にしろっていうこと。今更そんなのやってられない。そういう流れだったら逆らえないし、いずれやることになるだろうが、率先してやることはない。SHIFT-JISでいいじゃないか。ふつうにSQLite使えていると思うんだがね。要するにはじめから用意されているやつでやったら、文字化けでお手上げ。この辺のことに悩み出したら、どれだけ時間がかかるかわからない。アミーゴで作ったDBのファイルはCSVにできるので、ともかくこれをさっさとインポートしないと話が始まらない。
  • というわけで、不器用でも力ずくで、インポートする。PHPのfgetcsvで1行ずつ読み込み、メモ帳アプリのadd_dataファンクションで書き込んでいけばよいだけのこと。文字化けに悩む時間のことを思えば手間はましというもの。
  • 9個ぐらいのフィールドで、ためしにやってみたが110行ほどのCSVをインポートするのに5秒ぐらいかかるかな。1万行じゃあるまいし。この時間は問題にならない。
  • ポイントは、fgetcsvでCSVデータを1行ずつ読み込んでファイルが終わるまで配列に入れるという原始的方法。
  • POSTで、読み込むCSVファイルのファイル名のみを取得している。これは当てずっぽうがたまたま当たっているような感じで、邪道かもしれない。普通はフォームで、enctype="multipart/form-data"を指定してPOSTすれば$_FILES['file']['name']にファイル名が返るはずだが、どうもそれがうまくいかない。 enctype="multipart/form-data"をしなかったら$_POST["file"]にファイル名が入るのだ。事実として。それでいいじゃないか。できるんだから。
<html>
<!-- 
1.このプログラムは生成したいデータベースファイルを置く場所(ディレクトリ)と同じ場所に置く。
2.さらに、インポートするcsvファイルを同じ場所に置く。
3.生成するデータベースファイル名確認(69行目:menu.sqlite)。
4.生成するテーブル名確認(72,90,115行目:menu)。
5.このプログラムをブラウザで実行する。
6.インポートするcsvファイルを参照して指定。
7.インポートボタンを押す。
 -->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>メニューアプリケーション(PDO関数)CSVファイルインポート用</title>
<meta http-equiv="content-style-type" content="text/css">
<style type="text/css">
<!--
.sfont{
        font-size : 12px
}
-->
</style>
</head>
<body class="sfont">
<h4>メニューアプリケーション(PDO関数)CSVファイルインポート用</h4>

<?php


// データの取得
$act = (isset($_POST["act"])) ? $_POST["act"] : "";
$impfn = (isset($_POST["impfn"])) ? stripslashes($_POST["impfn"]) : "";//インポートするcsvファイル名
//$dt = date("Y-m-d H:i:s");//インポートファイルの最終更新日時を採用するときはこの行コメントアウト※54行目を使う

// データベースの初期設定
$conn = init();

//処理
if ($act == "インポート" and $impfn<>"") {
//CSVファイルを開く
//$fnで指定するファイルを読み取りモードで開く
$fn=$impfn;
$fp = fopen($fn, "r"); //CSVファイルのパスとファイル名
//CSVデータを1行ずつ読み込んでファイルが終わるまで配列に入れる。
$counter = 1;
while ($data = fgetcsv($fp, 10000)) {
        //変数に代入
                //$id=$data[0];
                $name=$data[1];
                $comment=$data[2];
                $hyou=$data[3];
                $kakaku=$data[4];
                $kakaku2=$data[5];
                $bunrui=$data[6];
                $aji=$data[7];
                $dt=$data[8];//インポート時の最終更新日時を採用するときはこの行コメントアウト※31行目を使う
                add_data($conn, $name, $comment, $hyou, $kakaku, $kakaku2, $bunrui, $aji, $dt);
//Wile文の終端
$counter++ ;
}
//ファイルを閉じる
fclose($fp);
//if文の終端
echo $impfn."をインポートしました。";
}

// データベースの初期設定
function init() {
    // データベースに接続(カレントフォルダのmenu.sqliteというファイル名)
    $conn = new PDO("sqlite:menu.sqlite");

    // データベースの作成
    $sql = "CREATE TABLE IF NOT EXISTS menu (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                name TEXT NOT NULL,
                comment TEXT NOT NULL,
                hyou,
                kakaku,
                kakaku2,
                bunrui,
                aji,
                dt TEXT NOT NULL
            )";
    $stmt = $conn->prepare($sql);
    $stmt->execute();
    return $conn;
}

// データの追加
function add_data($conn, $name, $comment, $hyou, $kakaku, $kakaku2, $bunrui, $aji, $dt) {
    $sql = "INSERT INTO menu(name, comment, hyou, kakaku, kakaku2, bunrui, aji, dt)
                VALUES(:name, :comment, :hyou, :kakaku, :kakaku2, :bunrui, :aji, :dt)";
    $stmt = $conn->prepare($sql);
    $stmt->bindParam(":name", $name);
    $stmt->bindParam(":comment", $comment);
    $stmt->bindParam(":hyou", $hyou);
    $stmt->bindParam(":kakaku", $kakaku);
    $stmt->bindParam(":kakaku2", $kakaku2);
    $stmt->bindParam(":bunrui", $bunrui);
    $stmt->bindParam(":aji", $aji);
    $stmt->bindParam(":dt", $dt);
    $stmt->execute();
    $id = $conn->lastInsertId();
    return $id;
}
?>

<!-- フォーム -->
<form method="POST" action="<?php echo $_SERVER["SCRIPT_NAME"]?>">
<input type="file" name="impfn" size="30">
<input type="submit" value="インポート" name="act" onClick="return confirm('インポートします')">
</form>

<?php
// 全データの取得
$sql = "SELECT * FROM menu ORDER BY id";
$stmt = $conn->prepare($sql);
$stmt->execute();

// データの一覧表示
echo "<table  class=\"sfont\" border=\"1\">";
echo "<tr>";
echo "<td>ID</td>";
echo "<td>名称</td>";
echo "<td>得票</td>";
echo "<td>価格</td>";
echo "<td>最終更新時刻</td>";
echo "</tr>";
while ($row = $stmt->fetch()) {
    echo "<tr>";
    echo "<td>" . $row["id"] . "</td>";
    echo "<td>" . $row["name"] . "</td>";
    echo "<td>" . $row["hyou"] . "</td>";
    echo "<td>" . $row["kakaku"] . "</td>";
    echo "<td>" . $row["dt"] . "</td>";
    echo "</tr>";
}
echo "</table>";
?>
</body>
</html>

ともかくこれで、アミーゴのデータを全部SQLiteに移行した。文字化けなし。

全くなし。

SHIFT-JISであろうとfgetcsvであろうと文字化けなし。

$_POSTだけバックスラッシュ取ればいいのだ!

文字化けアレルギーにかかっていた。

stripslashesは、やたらと使うもんじゃない。これを使いすぎて、\が無くなって,逆に5C問題が発生する。基礎的な設定が正しければstripslashesはPOSTを受けた直後の$_POSTにだけ施せばよろしい。例えば、stripslashes($_POST["comment"])みたいにPOSTを受ければそれで何もかもうまくいく。下手に対処療法ばかりやってはいけない。対処療法が症状を生みさらに対処療法をするとそれがまた症状を生むという悪循環に陥る。おおもとの部分を解決しなければ永遠のいたちごっこになる。

カクテルはさすがに26種類のフィールドで、486行だから時間がPHP既定の30秒では足りず、

Fatal error: Maximum execution time of 30

となった。

プログラムの先頭に秒数を書く。120秒でどうだ。

set_time_limit(120);

結果、65秒であった。2年かけて入力したデータだからな。65秒ぐらいかかってくれたほうがうれしい。

$conn = new PDO("sqlite:パス/cocktail.db");// データベースに接続
$stmt = $conn->query("SELECT count (*) FROM cocktail where {$where}");//countで、セレクトされる行数を取得する。
$total = $stmt->fetchColumn();//カウントの結果はこれで。なお(*)は(id)などnotnullのフィールドでもいい。
$conn = null;//接続を切る
  • 検索結果の表示でページャー(ページ送り機能)を使いたかったので、検索結果件数を上のコードで取得。{$where}はWhere句の内容。
  • ページャーはレッツPHPさんのお世話になりました。よくできたプログラム。わかりやすいし。

http://php.s3.to/simple/

最終更新:2011年10月11日 16:04