エントリー

カテゴリー「プログラム」の検索結果は以下のとおりです。

MySQL&SQLite用のデータベース管理ツール(改良版)

以前に作成したデータベース管理ツールを改良しました。

PHP Labo のプログラムをPHP5用に書き換えるにあたり、簡易な管理ツールが欲しくなったので作成。以前作成したものを使えば大丈夫…と思いきや、PDOを使わないとSQLite3には接続できないので…。

そんな訳で、実行にはPHP5+PDOが必要です。また、以前は断念したデータのインポート機能も実装。なかなか便利。

詳細とダウンロードは以下のページから行えます。

http://www.php-labo.net/download/tool/admin/

PHP4→PHP5へ移行中

PHP Labo のプログラムを地道に書き換え中。PDO関連の修正が、単純な置換では対処できないので面倒。プラグインも含めると結構なファイル数になるなぁ…。

PHPと言えば、ロリポップがPHP5に対応するので大喜び…と思っていたけど、どうも色々問題があるようです。特に、PHPの設定を .htaccess でも ini_set() でも変更できないのは痛すぎる。

公式サイトには

現在、当該事項の対応・検証を行っております。

とか書かれているので、変更できるようになることを期待。というか、変更できなかったら使い勝手が悪すぎるので、サーバー引越しも検討しなければ…。

他の格安サーバーでは、何か問題は出ていないのかな…。

PDOの不具合

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句に値を渡すときだけ直接指定する」という書き方は極力避けたいのだけど。

PDOお試し中

概要だけは知っていたけど、実際に使うのは多分初めて。PEAR::DB と同じような感覚で使えて良い感じです。

PDO でのエラー処理は trycatch で捕捉するのが定番みたいですが、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";
}

?>

コンストラクタのエラーは trycatch でしか補足できなかった。他に方法が無いか、後でもう少し調べてみます。でもやっぱり、データベースのエラーは全部 trycatch で処理した方がスッキリ書けるかなぁ…。
今のところ使っていないけど、トランザクションを使う場合は特に便利だし。

また、SQLite2を使うかSQLite3を使うかで、コンストラクタに渡す値が微妙に異なります。うーん、設定ファイルでSQLite2、SQLite3、MySQLを切り替えるようにするかな。

PHP4→PHP5への移行

このサイトはロリポップを使用しているのですが、とうとう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) を使用する。
  • XMLの解析には SimpleXML が便利。
  • 初期設定ではMySQLではなくSQLiteを使用するようにしておく。

思いついたら追加します。
あと、PHP5への移行と同時に、ちょっとだけ機能強化もする予定。

ようやく仕事が直接関係しないプログラミングができると思うと、何だかテンションが上がるぞ。

PHPでツリー表示プログラム

これも必要になったのでメモ。

<?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]えええええ

ツリー生成手順は、以下の書籍を参考にしています。プログラミングをはじめた頃によく読んでいた本なので、久しぶりに読んで懐かしい…。

CGI&SSIを使うとホームページ作成にこんなに差が出る

PHPで2ch互換トリップ生成

必要になったので自分用にメモ。トリップ生成時の文字コードは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;

?>

トリップの概要とコードは以下のページを参考にしました。(参考というか、ほぼそのまま。)

トリップ (2ちゃんねる) - Wikipedia

script.aculo.us

いまからはじめるScript.aculo.us

主に上のページを参考に、一通りの機能をざっと試してみた。本当にざっとだけど。

script.aculo.us は prototype.js をベースにしたライブラリで、多彩なエフェクト機能が利用できるようになります。ちょっとしたアニメーション処理とか、要素のドラッグ&ドロップとか、Google Suggest みたいな入力候補機能とか、とても簡単に実装できます。これまた便利。

Webアプリケーションの管理画面などで、使えそうな機能は導入していきたいと思います。

prototype.js

prototype.js v1.5.0 の使い方
prototype.js 1.4rc4

主に上のページを参考に、一通りの機能をざっと試してみた。
かなり膨大な量なので全機能を把握し切れていないけど、凄く便利なのは分かった。

利用頻度の高いもので、自力でコードを書くと面倒そうな処理は、大抵実装されているっぽい。その分、ファイルサイズもそれなりに大きいけど…。

JavaScriptでクラス定義

書き方が色々あるけど、自分では以下のように書くとします。

/* クラスを定義 */
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 親クラス { ~ }

の書き方が(言語を問わなければ)一番見慣れているので、近い書き方にしてみた。

今後変えていくかもしれないけど。

ページ移動

ユーティリティ

カテゴリー

検索

エントリー検索フォーム
キーワード

過去ログ

過去ログ表示フォーム
キーワード

Feed