Allowed memory size of **** bytes exhausted in /usr/*/pear/DB/

使用メモリがphp.iniの設定値を超えた場合に出る表題エラーですが、
出現箇所が、pear/DBやMDBといったDBライブラリの中で出る場合があります。
このような場合は、DBアクセスしている箇所といった特定しかできず、複雑な処理であれば突き止めるのは困難。


ただ問題としては、使用しているDBインスタンス変数のどれかが膨らんだと思われる。
怪しいのは、クエリを実行するたびに蓄積されていく以下3つ

  • $db->prepare_types
  • $db->prepare_tokens
  • $db->prepared_queries

プリペアドステートメント系のものですね。
大抵、ループ処理の中で、1つのDBインスタンスを使いまわして溜まり過ぎるパターンです。


というわけで、単純に$db->free();を入れて結果セットを解放するだけでは不十分なケースが多く、

<?php
	function freePrep()
	{
		unset($this->db->prepare_types);
		unset($this->db->prepare_tokens);
		unset($this->db->prepared_queries);
	}

みたいなメソッドを、pear::DBを呼び出すベースクラスに仕込んで、
ループ一回ごとにメソッド呼び出し、変数を解放してあげるのがよいかと。
※後ほどこれらの変数を使わない前提


 

 

MDB2でlast_query()が取得できない

本当は取得できると思うんですが、原因がわからず、調べてもよくわからなかったので、
無理やり自作しました。

$sql:プリペアされるクエリ
$pa:プレースホルダーに入るパラメータ
<?
	while(!empty($pa)){
		$e = array_shift($pa);
		$q = "'". $e. "'";
		$rep = array($e, $q);
		$pat = array('/\!/', '/\?/');
		$sql = preg_replace($pat, $rep, $sql, 1);
	}

これをDB用基底クラスに書き込んで、

<?
$this->last_query = $sql;

とかして、メンバ変数として全方位から呼び出せるように。

※当然、Fetchの後に入れないとSQLが改変されてしまいます

 

チェックボックスの全選択/解除

jquery1.6以降、.attr()の仕様が変更になったため

	$(function(){
		$('#all').click(function(){
			$('.chklist').attr('checked', $(this).attr('checked'));
		});
	});

上記では、全選択解除が動かなくなってました。
.attr('checked')が FALSE=>undefined になったようです。

全選択解除時の挙動を追加

	$(function(){
		$('#all').click(function(){
			if($(this).attr('checked')===undefined){
				$('.chklist').attr('checked', false);
			}else{
				$('.chklist').attr('checked', $(this).attr('checked'));
			}
		});
	});

若干、不恰好になってしまいましたが、これで動きます。


 

&&かandか(論理演算子の優先順位について)

かorかも含め、「どっちでもいいや」って声も耳にします。

まぁ大半はどっちでもいいケースでしょうけど、違いを分かっていないとドハマりすることもあるでしょうから整理

http://www.php.net/manual/ja/language.operators.precedence.php

要は、優先順位の話です。
もしくは()をちゃんと書け、という話です。
それだけなのに偉そうですみません。


参考
http://screw-axis.com/2009/05/20/php-%E8%AB%96%E7%90%86%E6%BC%94%E7%AE%97%E5%AD%90%E3%80%8Cand-or%E3%80%8D%E3%81%A8%E3%80%8C-%E3%80%8D%E3%81%AE%E9%81%95%E3%81%84/

input type="file"使うときのformプロパティ追加(健忘注意!)

ちょっとなんべんも忘れすぎるので、あえて記事にして備忘。

<!-- データのエンコード方式である enctype は、必ず以下のようにしなければなりません -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
    <!-- MAX_FILE_SIZE は、必ず "file" input フィールドより前になければなりません -->
    <input type="hidden" name="MAX_FILE_SIZE" value="30000" />
    <!-- input 要素の名前が $_FILES 配列での名前となります -->
    このファイルをアップロード: <input name="userfile" type="file" />
    <input type="submit" value="ファイルを送信" />
</form>

しつこいようですが、もう一度

<!-- データのエンコード方式である enctype は、必ず以下のようにしなければなりません -->
<form enctype="multipart/form-data" action="__URL__" method="POST">

POST メソッドによるアップロード
お恥ずかしい限りです。

というか、タグはPHPじゃなくてHTMLですね。

Syntax Errorを秀丸でファイル保存時に自動検出

エディタはvimテキストエディタIDEのもを色々使い回してますが、いまだに固まってマセン。
それぞれに良さがあり、欠点もある。けどせめて構文チェックくらいはどれでも使えるようにしておきたいとこです。

IDEはもちろん、vimもvimrcに設定すれば問題ないので、あと秀丸で出来ないかとずっと思ってましたが、
こちらPHPの構文チェックしてくれる秀丸マクロを自作してくれていたので、早速使わせていただきました。ありがとうございます。


しかし欲張りなもので、自分的には、上書き保存時にチェックを自動でしてほしい
(保存前のひと手間すらめんどくさがり)

というわけで、ちょこっと改造させていただきました(勝手にすみあせん)

// SaveWithPHPSyntaxCheck.mac

// 保存
save;

$type = filetype;
$header = "\<?php";
beginclipboardread;
#i = 0;
$orgclip[#i] = getclipboard;
while( $orgclip[#i] != "" ) {
    #i = #i + 1;
    $orgclip[#i] = getclipboard;
}

gofiletop;
copyline;
prevpos;
$buf = getclipboard;
clearcliphist;
// PHPファイルでなければ終了(.php以外も必要であれば追加)
if ( leftstr($buf, strlen($header)) != $header && $type != ".php") {
setclipboard $orgclip[0];
#i = 1;
	while( $orgclip[#i] != "" ) {
	    addclipboard $orgclip[#i];
	    #i = #i + 1;
	}
endmacro;
}
// PHPの構文チェックを行う
$TempFile = "c:\\php\\temp\\php_syntax.txt";
$SyntaxOk = "No syntax errors detected";

run "c:\\php\\php.exe -l %f > " + $TempFile;
if ( !result ) {
message "PHP Syntax Check Failed.";
setclipboard $orgclip[0];
#i = 1;
	while( $orgclip[#i] != "" ) {
	    addclipboard $orgclip[#i];
	    #i = #i + 1;
	}
endmacro;
}
if (! existfile($TempFile) ) {
message "うまく構文チェックできなかったみたい。";
setclipboard $orgclip[0];
#i = 1;
	while( $orgclip[#i] != "" ) {
	    addclipboard $orgclip[#i];
	    #i = #i + 1;
	}
endmacro;
}

// 元のウィンドウのウィンドウハンドルを取得
#org_w = hidemaruhandle(0);

openfile "/h" $TempFile;
// ステルスウィンドウ
#stl_w = hidemaruhandle(0);

replaceall "^\\n", "", regular;
selectall;
copy;

// 元のウィンドウに戻る
setactivehidemaru #org_w;
// ステルスウィンドウを閉じる
closehidemaruforced #stl_w;

beginclipboardread;
$buf = getclipboard;
clearcliphist;
setclipboard $orgclip[0];
#i = 1;
	while( $orgclip[#i] != "" ) {
	    addclipboard $orgclip[#i];
	    #i = #i + 1;
	}

if ( leftstr($buf, strlen($SyntaxOk)) == $SyntaxOk ) {
endmacro;
//quit;
}
message $buf;
endmacro;

このSaveWithPHPSyntaxCheck.macをマクロ登録して、この際Ctrl+sにキー割り当てしちゃう。
今まで通りの保存で、同時にチェックが働きます。(※当然ながらWinのみ)

追加で、

・Syntax Error検出したときはダイアログで出すようにしました。
・PHPファイルでなかったらスルー
・tmpファイルをステルス表示してすぐ閉じるように。

問題点

・ステルスでも一瞬tmpファイルの開閉が起きるのが気持ち悪いですが、これはしょうがない。
・「保存前にチェックして、エラーなら保存しない」風にはできない。
・エラー行番号が出ない下記、追記にて解決

何かいい解決方法があれば教えて下さい。

追記

「エラー行番号が出ない」と書きましたが、単にローカルのphp.iniの設定不足でした。

error_reporting = E_PARSE

と、Parseエラーだけ出せば、とりあえず行番号も含めたエラーメッセージを拾ってくれます。
ただ複数行に渡るので、マクロに改行トリミング

replaceall "^\\n", "", regular;

を入れてあげないと、ダイアログではうまく出ません。

さらに追記

クリップボードにコピーが残ってしまうのが気持ち悪かったので、元のを保持しといて最後上書きするようにしました。

ディレクトリ内のファイルリストを取得する

glob()関数を使うのが便利です。
パターンマッチ使えるので。

※file_exists()はファイル名が判ってないと使えない

つまり、ディレクトリ内にファイルが存在するかどうかの判定にも使えます。

<?
	if(is_dir($dir) && !glob($dir.'/*.*')){
		rmdir($dir);
	}

とか処理を入れないと、ファイルが存在するときrmdir()しようとするとWarningが出ますので。