error_reporting=E_ALL のススメ

初歩ではありますが、error_reporting = E_ALL ^ E_PHP_NOTICE な環境に慣れている人のためのコーディングルールを探してもすぐに見つけられなかったため、書いておきます。
 
□変数は代入してから使うこと
定義済みの(値が入っている)変数のみ参照するべきです。
もしもグローバル変数など、値が入っているかわからない場合は isset() や empty() で存在を確認しましょう。接頭文字 @ を使ってもいいですが、 isset() や empty() のほうが望ましいです。
なお、null を代入した変数も定義済みの変数です。

<?php
// —————–
// 未定義の変数参照
// —————–
// NG
echo $foo; // PHP Notice: Undefined variable: foo
// ——–
// OK
$foo = “abc”;
echo $foo;

 
□配列、連想配列の要素も存在するもののみ参照すること
配列の要素の一つ一つについても、変数同様に定義済みのもののみ参照しましょう。
リクエスト値など、値が入っているかわからない場合は isset() や empty() で存在を確認しましょう。

<?php
// —————–
// 未定義の配列要素/連想配列要素の参照
// —————–
// NG
$id = $_GET[‘id’]; // PHP Notice: Undefined index: id (引数省略リクエストの場合)
// ——–
// OK ※省略不可能なパラメータの場合
if(empty($_GET[‘id’])){ // または if( !isset($_GET[‘id’]) )
// エラー処理
exit;
}
$id = $_GET[‘id’];
// ——–
// OK-2 ※省略可能なパラメータの場合
$id = isset($_GET[‘id’])? $_GET[‘id’]: null;

 
□定数の定義方法に注意しましょう。
定数の定義関数は

define(定数名文字列, 値)

です。
第一引数はシンボルではなく文字列です。’〜’ や “〜” で括ることを忘れないようにしましょう。

<?php
// —————–
// 未定義の定数参照(定義時)
// —————–
// NG
define(FOO, 123); // PHP Notice: Use of undefined constant FOO – assumed ‘FOO’
// ——–
// OK
define(“FOO”, 123);

 
□文字列中の連想配列のキー指定時もクォーテーションにも注意

“{$assoc[key]}”

は key が定数値とみなされます。
連想配列のキーをダブルクォーテーションまたはシングルクォーテーションで囲むようにしましょう。

<?php
// —————–
// 未定義の定数参照(文字列内での連想配列参照)
// —————–
// NG
$foo=array();
$foo[“name”] = ”John”;
echo “{$foo[name]}\n”; // Use of undefined constant name – assumed ‘name’
// ——–
// OK
$foo=array();
$foo[“name”] = ”John”;
echo “{$foo[‘name’]}\n”;

ブラウザで見ているページを編集可能にする

javascript:document.body.contentEditable=’true’; document.designMode=’on’; void 0

をアドレスバーで実行すれば、ブラウザで開いているページの画像やテキストを自由に書き換えることができます(IE6, Firefox3 で確認)。
 
編集をやめたいときは↓の一行を実行します。

javascript:document.body.contentEditable=’false’; document.designMode=’off’; void 0

 
参考:
Cut and paste one line of code to make any website editable

Firefox 3 用アドオン/テーマ

本日 Firefox 3.0 公開、ということで、おいておきますね。
それぞれ公式サイトのものを改造した非公式版なので、正式版が対応するまでの間に合わせに自己責任でご利用ください。
 
All In One Gesture Version 0.1.8 for Firefox 3.0
 
フォクすけテーマ 1.0 for Firefox 3.0
 ※タブだけテーマが適用されない不具合あり。

PostgreSQL テーブル LOCK MODE 関係図

テーブルロックモードの関係を把握しやすいように図で表してみました。
PostgreSQL LOCK MODE 関係図
() 内はそのロックを自動的に獲得するクエリです。
 
■ロックとトランザクション
SQL における排他制御の方法として、トランザクションとロックが挙げられます。
複数のクエリをトランザクションでひとつにまとめることで、(デフォルトのトランザクションレベル READ COMMITTED の場合)コミット済みの結果のみ参照されるようになり、トランザクション中の内容を外部からは見えなくなるため一見アトミック性が守られるように見えます。
 
しかし、複数の接続で同時に既存の同じレコードに対して参照と更新を分けて実行する場合などはトランザクションだけでは限界があるのも事実です。
 
たとえば以下のテーブルを考えてみましょう。

CREATE TABLE foo (
  id int NOT NULL, — 商品の識別番号
  price int NOT NULL — 値段
);
INSERT INTO foo (id, price) VALUES(1, 100); — id:1 は 100 円
INSERT INTO foo (id, price) VALUES(2, 500); — id:2 は 500 円

このテーブルに対して、以下の処理を行うものとします。

BEGIN;
SELECT id FROM foo WHERE price < 500; -- 500円未満の id:1 を得る
UPDATE foo SET price = price + 500 WHERE id = 1; — 500円未満だった id:1 を 500円増し
COMMIT;

READ COMMITED レベルで同時に同じのクエリが実行されると、id:1 が 1100 円になる可能性があります。
 
トランザクションのみでこれを防ぐには衝突する可能性のある全てのクエリのトランザクションレベルを最も厳密な SERIALIZABLE にする必要があります。

— 衝突回避版
BEGIN;
SET TRANSACTION SERIALIZABLE; — この接続のトランザクションレベルを SERIALIZABLE に。
SELECT id FROM foo WHERE price < 500; -- 500円未満の id:1 を得る
UPDATE foo SET price = price + 500 WHERE id = 1; — 500円未満だった id:1 を 500円増し
COMMIT;

ただし、 SERIALIZABLE 隔離レベルのトランザクションの実行中に他の接続で COMMIT された場合、直列性を守るためにエラーになり処理が続行できなくなります。このため、衝突した場合は ROLLBACK の後再処理を行う必要があるなど, 欠点もあります。トランザクションのみでは、参照を完全にブロックすることができないのが原因のひとつです。
 
そこで、読み込みも制御できるロックの出番というわけです。
 
■ロックの獲得方法
多くのクエリは暗黙にクエリ単位で行レベルロックを獲得しています。
ロックの種類と影響する範囲については図を参照してください。
 
複数のクエリでロックを獲得するには LOCK 構文を用います。
LOCK 構文で取得できるロックはテーブルに対するロックのみです。

BEGIN;
LOCK foo_table IN EXCLUSIVE MODE; — EXCLUSIVE ロック獲得。
SELECT * FROM foo_table;
UPDATE foo_table SET …
— その他何か色々なクエリ…
COMMIT;

たとえば EXCLUSIVE モードでロックを獲得すると、他の接続では SELECT, ANALYZE 文以外の全てのクエリ、および ACCESS_SHARE 以外の全てのロックを明示的に獲得しようとするとロック待ちになります。
※具体的には UPDATE, DELETE, INSERT 文および SELECT … FROM table FOR …, CREATE INDEX, ALTER TABLE, DROP TABLE, REINDEX, CLUSTER, VACUUM, VACUUM FULL 文の実行を防ぎます。
また、ACCESS EXCLUSIVE, EXCLUSIVE, ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE ROW EXCLUSIVE, SHARE の明示ロック獲得を防ぎます。
 
■ロックの解放方法
ロックはトランザクションの終了時(COMMIT, ROLLBACK実行時)に自動で解放されます。
トランザクションの途中でロックだけを解放する方法はありません。
 
参考:
トランザクションの隔離(PostgreSQL 8.3.1 マニュアル)
LOCK 構文(同上)
トランザクションと隔離レベルとロック(ファイヤープロジェクト)

複数ファイルの中身を一括置換するには

複数のファイルをまとめて置き換えたいときは sed を使うと便利です。
 
たとえばこのようにすると指定したディレクトリの中のすべての .html ファイルの内容を 2007年 から 2008 年に書き換えることができます。

for i in `find /var/www/html -type f -iregex ‘.*\.html’`; do
  mv $i $i.bak
  sed -e ‘s/2007年/2008年/g’ $i.bak > $i
done

影響があったファイルの一覧を得るには次のようにします

for i in `find /var/www/html -type f -iregex ‘.*\.html’`; do
  diff -q $i.bak $i
done

影響があったファイルの内容を比較する場合も diff を使います。

for i in `find /var/www/html -type f -iregex ‘.*\.html’`; do
  echo $i
  diff $i.bak $i
done

問題に気づいて元に戻したいときは *.bak を移動させれば元に戻ります。

for i in `find /var/www/html -type f -iregex ‘.*\.html’`; do
  mv $i.bak $i
done

変更が問題なければ .bak ファイルを削除して置換完了です。

for i in `find /var/www/html -type f -iregex ‘.*\.html’`; do
  rm $i.bak
done

参考:
sed の使い方

sed の使い方

書式:

sed -e ‘コマンド1’ [-e ‘コマンド2’ […]] [‘ファイル名’]

指定したファイル(省略した場合は標準入力)を入力テキストとして読み込み、
-e で指定したスクリプトを順番に実行して標準出力に書き出します。
 
-e で指定できる書式は次のようなものがあります。
 
■命令のみ指定するタイプ( -e 命令 ):

-e p

行バッファの内容を出力(Print)する。バッファの内容は操作しないため、-ep -ep のように複数指定すると指定回出力されます。バッファの消去には後述の d を使用します。また、全てのスクリプトを実行したあとにもバッファ内容が出力されます。

-e d

行バッファの内容を消去(Delete)する。通常、p 命令と組み合わせて利用します。
 
■正規表現パターン + 処理内容指定をするタイプ(-e /正規表現/命令):

-e /^foo/p

foo から始まる行を出力します。

-e ‘/boO$/d’

boO で終わる行をバッファから削除します。

-e ‘/[J][j]ohn/p’

John または john が含まれる行を出力します。
 
■正規表現による置換(-e s/正規表現/置換内容/オプション)

-e s/foo/boo/

各行バッファで最初に見つかった foo を boo に置換します。

-e ‘s/a/A/g’

バッファ中の全ての a を A に置換します。

-e s/john/JOHN/ig

バッファ中の全ての john(大文字小文字問わない)を大文字の JOHN に統一します。
 
例:

echo “Hallo, world” | sed -e s/a/e/

typo を訂正する(Hallo -> Hello)。

cat /var/log/httpd/access_log | sed -e ‘/GET/p’ -e ‘/^127\.0\.0\.1/p’ -ed

Apache のローカルからの GET アクセスを抽出する。

右クリック→新規作成からテキストファイルが消えた

XP の話。
検索してみると同じ症状の方が結構いたので解決方法のメモを残しておきます。
 
原因A: レジストリの HKEY_CLASSES_ROOT\.txt の ShellNew キーの内容が正しくない、もしくは不足している

HKEY_CLASSES_ROOT\.txt\ShellNew というキーがあり、NullFile という空の文字列値があるか?

ない場合は作成する。
 
原因B: レジストリの HKEY_CLASSES_ROOT\.txt の(既定)の値が正しくない
HKEY_CLASSES_ROOT\.txt の既定の値は txtfile です。
これ以外の値に書き換わっている場合(txt_auto_fileになっている、などの場合)は txtfile に変更することで解決する場合があります。
 
原因C: レジストリの HKEY_CLASSES_ROOT\.txt の PerceivedType キーの内容が正しくない、もしくは不足している

HKEY_CLASSES_ROOT\.txt\PerceivedType というキーがあり、text という文字列が設定されているか?

ない場合は作成する。
 
原因D: レジストリの HKEY_CLASSES_ROOT\Directory 以下が Windows Update で書き換わった
( http://pub.ne.jp/pchitorigoto/?entry_id=1145705 より。)

HKEY_CLASSES_ROOT\Directory\Background\shellex\ContextMenuHandlers\New\

の(既定)の値が

{D969A300-E7FF-11d0-A93B-00A0C90F2719}

以外になっていると新規作成が正しく動作しない現象が発生するようです。
 
どうしても解決しない場合:
Windows XP なら、こちらのサイトから、「TXT File Association Fix」をダウンロードして実行するとレジストリキーを修復できます。
ただし、.txt ファイル関係の設定をリセットするためテキストファイルへの関連付け等が外れてしまいます。
参考:
New command missing in Windows Explorer(Microsoft サポートオンライン:英語)
Windowss XP File Association Fixes

tips – PuTTY でコマンドライン – サーバごとに接続設定を変える

PuTTY は SSH と互換のコマンドライン引数を持っているため、以下のようにしてコマンドラインからユーザ foo, ドメイン example.com でログインできます。

putty [email protected]

環境変数 PATH に putty.exe (または puttyjp.exe)へのパスを通しておけば、Windows の「ファイル名を指定して実行(Windowsキー + Rキー)」で実行できるためかなり便利です。

GUIでのログインと同様、サーバごとに秘密鍵や文字コードの設定−保存(ストア)されたセッション−を切り替えてログインしたい場合は、

putty -load “セッション名”

とすると指定した設定(セッション)をコマンドラインから読み込んでログインすることができます。セッション名を user@hostname の書式で設定しておけば

putty -load [email protected]

のように通常のログインに -load を加えるだけでよいので管理、利用が容易になります。

参考:
PuTTY でデフォルト設定を変更する(過去記事)
ssh -R の応用例(過去記事)
ssh を任意のポート、プロトコルの proxy にする(過去記事)