MySQL&SQLite用のデータベース管理ツール(改良版)
以前に作成したデータベース管理ツールを改良しました。
PHP Labo のプログラムをPHP5用に書き換えるにあたり、簡易な管理ツールが欲しくなったので作成。以前作成したものを使えば大丈夫…と思いきや、PDOを使わないとSQLite3には接続できないので…。
そんな訳で、実行にはPHP5+PDOが必要です。また、以前は断念したデータのインポート機能も実装。なかなか便利。
詳細とダウンロードは以下のページから行えます。
気ままな雑記帳&実験場。好き勝手に色々やっています。
カテゴリー「プログラム」の検索結果は以下のとおりです。
以前に作成したデータベース管理ツールを改良しました。
PHP Labo のプログラムをPHP5用に書き換えるにあたり、簡易な管理ツールが欲しくなったので作成。以前作成したものを使えば大丈夫…と思いきや、PDOを使わないとSQLite3には接続できないので…。
そんな訳で、実行にはPHP5+PDOが必要です。また、以前は断念したデータのインポート機能も実装。なかなか便利。
詳細とダウンロードは以下のページから行えます。
PHP Labo のプログラムを地道に書き換え中。PDO関連の修正が、単純な置換では対処できないので面倒。プラグインも含めると結構なファイル数になるなぁ…。
PHPと言えば、ロリポップがPHP5に対応するので大喜び…と思っていたけど、どうも色々問題があるようです。特に、PHPの設定を .htaccess
でも ini_set()
でも変更できないのは痛すぎる。
公式サイトには
現在、当該事項の対応・検証を行っております。
とか書かれているので、変更できるようになることを期待。というか、変更できなかったら使い勝手が悪すぎるので、サーバー引越しも検討しなければ…。
他の格安サーバーでは、何か問題は出ていないのかな…。
PDOのプレースホルダが意図したとおりに動作しません…。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT ?, ?');
$flag = $stmt->execute(array(0, 5));
こんな風に書くと、SQLの文法エラーと言われてしまいます。
プレースホルダを文字で指定しても駄目。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT :from, :to');
$flag = $stmt->execute(array(':from' => 0, ':to' => 5));
LIMIT句以外なら、普通にプレースホルダが機能するんだけどなぁ…。
ちなみに、bindValue()
で値を指定してから execute()
を実行するようにすればLIMIT句でも大丈夫だった。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT ?, ?');
$stmt->bindValue(1, 0, PDO::PARAM_INT);
$stmt->bindValue(2, 5, PDO::PARAM_INT);
$flag = $stmt->execute();
文字で指定しても当然のように動作します。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT :from, :to');
$stmt->bindValue(':from', 0, PDO::PARAM_INT);
$stmt->bindValue(':to', 5, PDO::PARAM_INT);
$flag = $stmt->execute();
なかなか原因が判らなかったけど、これはPDOの不具合らしい。
何とも厄介な…。公式サイトには
PDO::execute() errors when parameters are used in LIMIT clause
と書かれているので execute()
の問題らしいけど、bindValue()
を使えばバージョンに関わらず実行できる…と思っていいのかな…。
うっかりミスでSQLインジェクションが起こり得ないようにするためにプレースホルダを使っている(僕の場合は)ので、「LIMIT句に値を渡すときだけ直接指定する」という書き方は極力避けたいのだけど。
概要だけは知っていたけど、実際に使うのは多分初めて。PEAR::DB
と同じような感覚で使えて良い感じです。
PDO
でのエラー処理は try
~ catch
で捕捉するのが定番みたいですが、PEAR::DB
みたいに戻り値のチェックで処理することもできるのですね。
PHP Labo のプログラムは非オブジェクト指向(手続き型)で書くので、エラー処理も昔ながらの方法にしようかなぁ…。その場合、こんな感じ?
<?php
try {
$pdo = new PDO(
'mysql:dbname=phpdb;host=localhost',
'user',
'pass',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT
)
);
} catch (PDOException $e) {
exit($e->getMessage());
}
$stmt = $pdo->query('SELECT * FROM address');
if (!$stmt) {
list($state, $code, $message) = $pdo->errorInfo();
exit($state . ':' . $code . ':' . $message);
}
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $data['no'] . ':' . $data['name'] . "<br>\n";
}
?>
コンストラクタのエラーは try
~ catch
でしか補足できなかった。他に方法が無いか、後でもう少し調べてみます。でもやっぱり、データベースのエラーは全部 try
~ catch
で処理した方がスッキリ書けるかなぁ…。
今のところ使っていないけど、トランザクションを使う場合は特に便利だし。
また、SQLite2を使うかSQLite3を使うかで、コンストラクタに渡す値が微妙に異なります。うーん、設定ファイルでSQLite2、SQLite3、MySQLを切り替えるようにするかな。
このサイトはロリポップを使用しているのですが、とうとうPHP5に移行するらしいです。ちなみに Web Liberty はWADAXを使用していますが、結構前にPHP5に移行済み。
その他のサーバーもPHP4が使えなくなるのは時間の問題だと思うので、PHP Labo のプログラムをPHP4非対応に修正していきます。
代わりに、PHP5で追加された機能を色々使います。PEARが不要になるので、設置も楽になるハズ。
そんな訳で、自分用に移行メモ。「オブジェクトのコピー方法が云々」とか紹介しているのではなくて、あくまでも PHP Labo のプログラムを修正するための自分用作業メモ。ちなみに、厳密にはPHP5.1以降への移行が前提になっています。
PEAR::DB
ではなく PDO
を使用する。opendir()
ではなく scandir()
を使用する。fopen()
+ fwrite()
+ fclose()
は file_put_contents()
で処理できる。ただし、ロック方法などを後で調べる。fgetcsv()
はPHP4とは異なり日本語処理に難があるため、使い物にならなくなっている(ような気がする)。文字コードの問題っぽい?session_regenerate_id(true)
を使用する。SimpleXML
が便利。思いついたら追加します。
あと、PHP5への移行と同時に、ちょっとだけ機能強化もする予定。
ようやく仕事が直接関係しないプログラミングができると思うと、何だかテンションが上がるぞ。
これも必要になったのでメモ。
<?php
function put_tree($no, $line, $broths, $childs, $texts) {
echo '<span class="line">' . $line . '</span>';
echo '▼[' . $no . ']' . $texts[$no] . '<br>';
$line = preg_replace('/├$/', '│', $line);
$line = preg_replace('/└$/', ' ', $line);
$no = isset($childs[$no]) ? $childs[$no] : 0;
while ($no > 0) {
$tail = $broths[$no] ? '├' : '└';
put_tree($no, $line . $tail, $broths, $childs, $texts);
$no = $broths[$no];
}
}
?>
<html>
<head>
<title>ツリー表示</title>
<style>
.line {
font-family: "MS ゴシック", monospace;
}
</style>
</head>
<body>
<?php
$logs = array(
array(1, 0, 'あああああ'), //記事番号・親記事番号・記事内容
array(2, 1, 'いいいいい'),
array(3, 1, 'ううううう'),
array(4, 2, 'えええええ'),
array(5, 3, 'おおおおお'),
array(6, 3, 'かかかかか'),
array(7, 0, 'ききききき'),
array(8, 6, 'くくくくく'),
array(9, 8, 'けけけけけ'),
array(10, 7, 'こここここ')
);
$roots = array();
$broths = array();
$childs = array();
$texts = array();
foreach ($logs as $log) {
list($no, $pno, $text) = $log;
if ($pno == 0) {
$roots[] = $no;
} else {
$broths[$no] = isset($childs[$pno]) ? $childs[$pno] : 0;
$childs[$pno] = $no;
}
$texts[$no] = $text;
}
rsort($roots);
foreach ($roots as $root) {
put_tree($root, '', $broths, $childs, $texts);
}
?>
</body>
</html>
実行結果は以下のとおり。
▼[7]ききききき
└▼[10]こここここ
▼[1]あああああ
├▼[3]ううううう
│├▼[6]かかかかか
││└▼[8]くくくくく
││ └▼[9]けけけけけ
│└▼[5]おおおおお
└▼[2]いいいいい
└▼[4]えええええ
ツリー生成手順は、以下の書籍を参考にしています。プログラミングをはじめた頃によく読んでいた本なので、久しぶりに読んで懐かしい…。
必要になったので自分用にメモ。トリップ生成時の文字コードはShift-JISにしておく。
<?php
$tripkey = '#istrip';? //パスワードとする文字列(# 付き)
$tripkey = substr($tripkey, 1);
$salt = substr($tripkey . 'H.', 1, 2);
$salt = preg_replace('/[^\.-z]/', '.', $salt);
$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
$trip = crypt($tripkey, $salt);
$trip = substr($trip, -10);
$trip = '◆' . $trip;
echo $trip;
?>
トリップの概要とコードは以下のページを参考にしました。(参考というか、ほぼそのまま。)
主に上のページを参考に、一通りの機能をざっと試してみた。本当にざっとだけど。
script.aculo.us は prototype.js をベースにしたライブラリで、多彩なエフェクト機能が利用できるようになります。ちょっとしたアニメーション処理とか、要素のドラッグ&ドロップとか、Google Suggest みたいな入力候補機能とか、とても簡単に実装できます。これまた便利。
Webアプリケーションの管理画面などで、使えそうな機能は導入していきたいと思います。
prototype.js v1.5.0 の使い方
prototype.js 1.4rc4
主に上のページを参考に、一通りの機能をざっと試してみた。
かなり膨大な量なので全機能を把握し切れていないけど、凄く便利なのは分かった。
利用頻度の高いもので、自力でコードを書くと面倒そうな処理は、大抵実装されているっぽい。その分、ファイルサイズもそれなりに大きいけど…。
書き方が色々あるけど、自分では以下のように書くとします。
/* クラスを定義 */
function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
document.write(this.name + ' : ぱくぱく<br />');
};
/* クラスを継承 */
function Dog(name) {
this.name = name;
}
Dog.prototype = new Animal();
Dog.prototype.bark = function() {
document.write(this.name + ' : わんわん<br />');
};
/* クラスを利用 */
pochi = new Dog('ポチ');
pochi.eat();
pochi.bark();
以前から書いている方法。一番見慣れているのでひとまずこれで。
prototype.js
利用時は以下のように書くとします。
/* クラスを定義 */
var Animal = Class.create();
Animal.prototype = {
initialize: function(name) {
this.name = name;
},
eat: function() {
document.write(this.name + ' : ぱくぱく<br />');
}
};
/* クラスを継承 */
var Dog = Class.create();
Dog.prototype = Object.extend(new Animal, {
bark: function() {
document.write(this.name + ' : わんわん<br />');
}
});
/* クラスを利用 */
pochi = new Dog('ポチ');
pochi.eat();
pochi.bark();
クラスの継承は
子クラス.prototype = Object.extend(new 親クラス, { ~ });
としてみる。
class 子クラス extends 親クラス { ~ }
の書き方が(言語を問わなければ)一番見慣れているので、近い書き方にしてみた。
今後変えていくかもしれないけど。