記事一覧

ファイル入出力改良版

排他ロックを利用しつつ、どのタイミングでプログラムが強制終了しても、ファイルがクリアされないようにしてみた。

/* ファイルの先頭に追加 */
$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);

$no   = 0;
$data = '';

while ($line = fgets($fp)) {
  if (intval($line) > $no) {
    $no = intval($line);
  }
  $data .= $line;
}

$no++;

rewind($fp);
fwrite($fp, "$no\t" . date('H:i:s') . "\n$data");

flock($fp, LOCK_UN);
fclose($fp);
/* ファイルの末尾に追加 */
$fp = fopen('data.txt', 'a+') or exit('error!');
flock($fp, LOCK_EX);

$no = 0;

while ($line = fgets($fp)) {
  if (intval($line) > $no) {
    $no = intval($line);
  }
}

$no++;

fwrite($fp, "$no\t" . date('H:i:s') . "\n");

flock($fp, LOCK_UN);
fclose($fp);
/* 任意の行を編集 */
$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);

$no   = 3;  //No.3のデータを編集
$data = '';

while ($line = fgets($fp)) {
  if (intval($line) == $no) {
    $data .= "$no\t" . date('H:i:s') . "\n";
  } else {
    $data .= $line;
  }
}

rewind($fp);
fwrite($fp, $data);
ftruncate($fp, ftell($fp));

flock($fp, LOCK_UN);
fclose($fp);
/* 任意の行を削除 */
$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);

$no   = 3;  //No.3のデータを削除
$data = '';

while ($line = fgets($fp)) {
  if (intval($line) != $no) {
    $data .= $line;
  }
}

rewind($fp);
fwrite($fp, $data);
ftruncate($fp, ftell($fp));

flock($fp, LOCK_UN);
fclose($fp);

デフォルメの練習

シャナ

顔をもっとデフォルメした方が良かったかも…と思いつつも、描いてるとよく判らなくなってきたので、一応完成としておきます。

手に持っているのはメロンパンです。念のため。(^^;

ファイル入出力試行錯誤中

色々読んでみて、'r+' モードは「ファイルの内容が減る可能性がある」という場合には使えないのかと思ったけど、どうやらそうでもないっぽい。

そんな訳で改良版。↓

/* 任意の行を編集 */
$no   = 3;  //No.3のデータを編集
$data = '';

$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);

while ($line = fgets($fp)) {
  if (intval($line) == $no) {
    $data .= "$no\t" . date('H:i:s') . "\n";
  } else {
    $data .= $line;
  }
}

rewind($fp);
fwrite($fp, $data);
ftruncate($fp, ftell($fp));

flock($fp, LOCK_UN);
fclose($fp);

rewind() とか ftell() とか ftruncate() でファイルポインタを操作してやれば、編集によってファイルサイズが減る場合でも対応できるみたい。
これなら素直に排他処理ができるし、どのタイミングでプログラムが強制終了してもデータが吹っ飛ぶことは無いみたいです。

また近々詳しく検証してみるとします。

PHPでファイル入出力(続き)

この記事の続き。ファイル入出力の具体的なコード。

/* ファイルの先頭に追加 */
$no   = 0;
$data = '';

$fp = fopen('data.txt', 'r') or exit('error!');
while ($line = fgets($fp)) {
  if (intval($line) > $no) {
    $no = intval($line);
  }
  $data .= $line;
}
fclose($fp);

$no++;

$fp = fopen('data.txt', 'w') or exit('error!');
fwrite($fp, "$no\t" . date('H:i:s') . "\n$data");
fclose($fp);
/* ファイルの末尾に追加 */
$no   = 0;
$data = '';

$fp = fopen('data.txt', 'r') or exit('error!');
while ($line = fgets($fp)) {
  if (intval($line) > $no) {
    $no = intval($line);
  }
  $data .= $line;
}
fclose($fp);

$no++;

$fp = fopen('data.txt', 'w') or exit('error!');
fwrite($fp, "$data$no\t" . date('H:i:s') . "\n");
fclose($fp);
/* 任意の行を編集 */
$no   = 3;  //No.3のデータを編集
$data = '';

$fp = fopen('data.txt', 'r') or exit('error!');
while ($line = fgets($fp)) {
  if (intval($line) == $no) {
    $data .= "$no\t" . date('H:i:s') . "\n";
  } else {
    $data .= $line;
  }
}
fclose($fp);

$fp = fopen('data.txt', 'w') or exit('error!');
fwrite($fp, $data);
fclose($fp);
/* 任意の行を削除 */
$no   = 3;  //No.3のデータを削除
$data = '';

$fp = fopen('data.txt', 'r') or exit('error!');
while ($line = fgets($fp)) {
  if (intval($line) != $no) {
    $data .= $line;
  }
}
fclose($fp);

$fp = fopen('data.txt', 'w') or exit('error!');
fwrite($fp, $data);
fclose($fp);

でも、単にファイルの末尾にデータを追加し続ける場合は、'a+'を使って、ロックも自前で行ったほうが圧倒的に効率が良さそう。(この場合は、一時的にデータを保存する変数のために、無駄に巨大なメモリを消費する必要は無いので。)

/* ファイルの末尾に追加 */
$fp = fopen('data.txt', 'a+') or exit('error!');
flock($fp, LOCK_EX);

$no = 0;
while ($line = fgets($fp)) {
  if (intval($line) > $no) {
    $no = intval($line);
  }
}
$no++;

fwrite($fp, "$no\t" . date('H:i:s') . "\n");

flock($fp, LOCK_UN);
fclose($fp);

今のところ、こんな感じで。

PHPでファイル入出力

ファイル入出力と排他処理のメモ。

主にこのあたりを読んでみて、結局のところどうやってロックするか。すごく今更ですが、PHPからはデータベースばかり使っていたので自分用にメモしておきます。
あくまでもメモであって、上の内容のまとめとかでは無いです。ツッコミは歓迎。

data.txt に、1行を1件として処理番号と処理時間を記録していくとする。具体的には以下のようなデータファイルを扱うとする。(<tab> の部分はタブが入る。)

4<tab>17:02:08
3<tab>16:53:20
2<tab>16:43:03
1<tab>16:42:02

データの破損を避けるために、ファイル入出力の際はロック処理を行う。

$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);  //有効なロック
fwrite($fp, '追記したいデータ');
flock($fp, LOCK_UN);
fclose($fp);

ただし、'r+' だとファイルの内容がクリアされないので、文章を編集したり一行削除したりする場合には利用できない(以前の内容がファイル内に残ってしまう可能性がある。)つまり「ファイルサイズが増えることがあっても減ることはない」という場合は 'r+' でのロックは有効だが、「ファイルの内容が減る可能性がある」という場合には使えない。

このような場合には 'w' でオープンすると、以前の内容がクリアされる。ただし、ロック方法に注意する。

$fp = fopen('data.txt', 'w') or exit('error!');
flock($fp, LOCK_EX);  //fopenの時点でファイルがクリアされるので、このロックは無意味
fwrite($fp, '書き込みたいデータ');
flock($fp, LOCK_UN);
fclose($fp);

この処理はロックができていないけど、ロック処理の例としてこのコードが紹介されていることは多い気がする…。

で、'w' を使う場合の、定番のロック方法は無いっぽい。
処理方法を色々変えるのもヤヤコシイので、入出力を行うファイル自体にはロックを行わず、ロック専用ファイルを用意した方が良さそう。

以下の自作関数で、ファイルロックを行う。

function file_lock()
{
  $fp = fopen('lock.txt', 'w') or exit('error!');
  flock($fp, LOCK_EX);

  return $fp;
}

function file_unlock($fp)
{
  flock($fp, LOCK_UN);
  fclose($fp);
}

file_lock() でロックを行い、file_unlock() でロックを解除する。つまり、ファイルロック用に lock.txt を用意し、このファイルに排他処理を行う。実際に読み書きするファイルにはロックを行わない。(排他ロック中は他のプロセスが割り込めないので、ロックは1つかければ十分。)

具体的には以下のような流れで処理する。

$lp = file_lock();

~ここでファイルの読み書き~

file_unlock($lp);

ファイル入出力を行う際は「ファイルの内容を読み込みモードで開き、一旦変数に読み出す。その後ファイルを書き込みモードで開き、一気に書き込む」に統一してみる。

続く

MySQL&SQLite用のデータベース管理ツール

この記事の続き。数日前から自作のデータベース管理ツールを使っています。
基本的には phpminiadmin 以上 SQLiteManager 未満くらいの機能ですが、なかなか便利に使えています。(自分用に作ったから当然か。)

スクリーンショットはこんな感じ。↓

スクリーンショット

phpMyAdmin や SQLiteManager を使い慣れている方には役不足なツールですが、「データを少し編集したい」という場合には便利かもしれません。
一応さらしておきますので、よければどうぞ。

DB Admin ダウンロード (最終更新2008/03/23 Ver 1.01)

以下、簡単に特徴を記載しておきます。

  • MySQLとSQLiteに対応したデータベース管理ツール
  • SQLの文法がある程度解る人向け
  • 基本的にはphpminiadminのようなインターフェイス
  • データの一覧表示やテーブルの削除など、よく利用するコマンドはSQLを入力しなくても実行可能
  • データの登録&編集はフォームから可能
  • SQLite利用時、VACUUM*1を実行可能
  • データのエクスポートが可能
  • プログラムファイルは1つで、サイズは約40KB

ライセンスはGPL。サポート無しですが、不具合はこっそり教えてくれると嬉しいです。
「このツールを使ったらデータが全部消えた」とか言われても責任は持てませんので、使用する前にバックアップはとっておきましょう。(^^;

あとはデータのインポート機能が欲しいけど、結構複雑になりそうなので見送り。またそのうちに。

*1 : SQLiteはdeleteを実行しても表示ができなくなるだけ。VACUUMを実行するまでデータベースから消去されない。(つまり、VACUUMを実行するまでファイルサイズが減らない。)

祝日判定プログラム

2000年~2020年の祝日を判定するプログラム。

<?php

$holiday = Array(
  '2000' => '0101,0110,0211,0320,0429,0503,0504,0505,0717,0918,0923,1009,1103,1123,1223',
  '2001' => '0101,0108,0211,0212,0320,0429,0430,0503,0504,0505,0716,0917,0923,0924,1008,1103,1123,1223,1224',
  '2002' => '0101,0114,0211,0321,0429,0503,0504,0505,0506,0715,0916,0923,1014,1103,1104,1123,1223',
  '2003' => '0101,0113,0211,0321,0429,0503,0504,0505,0721,0915,0923,1013,1103,1123,1124,1223',
  '2004' => '0101,0112,0211,0320,0429,0503,0504,0505,0719,0920,0923,1011,1103,1123,1223',
  '2005' => '0101,0110,0211,0320,0321,0429,0503,0504,0505,0718,0919,0923,1010,1103,1123,1223',
  '2006' => '0101,0102,0109,0211,0321,0429,0503,0504,0505,0717,0918,0923,1009,1103,1123,1223',
  '2007' => '0101,0108,0211,0212,0321,0429,0430,0503,0504,0505,0716,0917,0923,0924,1008,1103,1123,1223,1224',
  '2008' => '0101,0114,0211,0320,0429,0503,0504,0505,0506,0721,0915,0923,1013,1103,1123,1124,1223',
  '2009' => '0101,0112,0211,0320,0429,0503,0504,0505,0506,0720,0921,0922,0923,1012,1103,1123,1223',
  '2010' => '0101,0111,0211,0321,0322,0429,0503,0504,0505,0719,0920,0923,1011,1103,1123,1223',
  '2011' => '0101,0110,0211,0321,0429,0503,0504,0505,0718,0919,0923,1010,1103,1123,1223',
  '2012' => '0101,0102,0109,0211,0320,0429,0430,0503,0504,0505,0716,0917,0922,1008,1103,1123,1223,1224',
  '2013' => '0101,0114,0211,0320,0429,0503,0504,0505,0506,0715,0916,0923,1014,1103,1104,1123,1223',
  '2014' => '0101,0113,0211,0321,0429,0503,0504,0505,0506,0721,0915,0923,1013,1103,1123,1124,1223',
  '2015' => '0101,0112,0211,0321,0429,0503,0504,0505,0506,0720,0921,0922,0923,1012,1103,1123,1223',
  '2016' => '0101,0111,0211,0320,0321,0429,0503,0504,0505,0718,0919,0922,1010,1103,1123,1223',
  '2017' => '0101,0102,0109,0211,0320,0429,0503,0504,0505,0717,0918,0923,1009,1103,1123,1223',
  '2018' => '0101,0108,0211,0212,0321,0429,0430,0503,0504,0505,0716,0917,0923,0924,1008,1103,1123,1223,1224',
  '2019' => '0101,0114,0211,0321,0429,0503,0504,0505,0506,0715,0916,0923,1014,1103,1104,1123,1223',
  '2020' => '0101,0113,0211,0320,0429,0503,0504,0505,0506,0720,0921,0922,1012,1103,1123,1223'
);

if (strpos($holiday['2008'], '0101') === false) {
  echo '祝日ではありません。';
} else {
  echo '祝日です。';
}

?>

これを実行すると2008年1月1日が祝日かどうか判定され、結果は 祝日です。 と表示されます。
処理内容は見たままです。何とも露骨な判定。
その分、独自の祝日を追加するのは簡単(のハズ)。あと、調べてないけど判定速度は多分高速。

今回はカレンダー表示の際に、日付を平日の色で表示するべきか休日の色で表示するべきかを判定できれば十分なので、これでいくかなぁ…。

ちなみに、$holiday の内容はプログラムで自動作成しました。1年分ならともかく、20年分を手書きするのはさすがに面倒です…。

祝日の設定

この記事の続き。プログラムでカレンダー表示を行う際、祝日をどうやって求めるかを考え中。

KENTさんのコードを読んで、どんな流れで祝日判定を行うかは把握できたのですが…。どうしても、それなりに複雑なコードになりそうです。しかも、法改正されるたびにアルゴリズムの勉強をやり直さなければならない可能性があります。

これならいっそ、2000年~2020年くらいの祝日を、コード内で個別に定義して使った方が良さそう。もともと大した数では無いのだし。
そうすれば祝日の追加変更も簡単だし、個人的な休日も簡単に追加できて、むしろ便利かもしれない。

もちろん「2050年のカレンダーを表示すると祝日が設定されていない」…という状態にはなるけど、特に問題は無いでしょう。そもそも、その頃にはまた法律が変わってそう。(^^;

頂の座

ヘカテー

何となく落書き。…と思ったら1時間くらい経ってる罠。

まったく描かないよりは、描くほうが上達するだろう…ということで時々描いていきます。あと、動的パレットを導入したので、簡単に着色もしてみた。

本当は、AREA最終巻を読んで登場人物の誰かを描こうとしたけど、全然描けなかったので諦めた。またいつか挑戦するとします。
アリスのプリマ昇格から、一気に話が進んでいったけど、もう少し色々見たかったなぁ…。好きな漫画が終わるのは寂しいですねぇ…。

そして代わりにヘカテー。灼眼のシャナも、アニメがもうすぐ終わってしまう…。

Amazon 商品情報&レビュー検索ツール

以前にPerlで作ったツールですが、PHP+Smartyで作り直してみた。

http://amazon.php-labo.net/

携帯からAmazonの商品情報やレビューを閲覧できるツール。公式サイトの携帯版はレビュー閲覧にログインが必要なので、ログイン無しでも見れるように作った…のですが、いつの間にかログイン無しで見れるようになってる…。

あああ、作った意味が無かった。まあ、APIを利用する練習だったと思っておこう…。

ちなみに、XMLの解析には XML Library を利用。(そのまま使うとNoticeが表示されたので、内部コードに少し手を加えた。)リンク先にも書かれているとおり、PHP5のSimpleXML関数はかなり良さ気ですが、利用サーバーはPHP4なのです。

夏ごろには、すべてのサーバーがPHP5に移行するのかなぁ…。

ナビゲーション

ユーティリティ

2008年08月

- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31 - - - - - -

ツールメニュー

メッセージ

匿名で一言送信できます。

送信フォーム
メッセージ

RSSリーダー

  • JavaScriptをONにすると、RSSリーダーが表示されます。

利用ツール