昨年から PHP7で動作するよう rNote を修正して使用していたが、PHPマニュアルサイトの flock() の説明によると、 PHP 5.3.2 以降は、 flock($fp, LOCK_EX); などでロックしたファイルは、 fclose($fp); の直前で明示的に flock($fp, LOCK_UN); を呼んでアンロックしてやらないといけないことに気づいたので grep で検索してみたら、結構あちこちでアンロックを明示的に呼んでいなかった。

そこで、 flock($fp, LOCK_UN); を明示的に呼びだすように修正した。(修正しなくても特に問題なく動作していたが、 PHP の仕様上正しくロックしなくなっていたはず。)

特に気を付けたいのが rnote.php で下のように定義されている _fopen_wb() 。


function _fopen_wb($fname){
    $fp = @fopen($fname, "wb");
    if(! $fp) error("$fname : File write error");
    set_file_buffer($fp, 0);
    flock($fp, LOCK_EX);
    rewind($fp);
    return $fp;
}

この関数の中では $fp = fopen() が呼ばれ、開かれたファイルをロックしているのだが、アンロックしないまま fclose($fp); も呼ばず、そのまま $fp を返り値として返しているので、_fopen_wb() を呼び出した側で、受け取った $fp を使用した後に fclose($fp) する直前で明示的に flock($fp, LOCK_UN); を呼ばなければいけない。コードとしてはかなり見通しが悪くなり汚いコードになるが仕方がないのでそのように修正した。

[コメントの受付は終了しています ]
この記事のリンク元 | 1 |

キーワード: rNote php flock


CMake を使ってみた 2019-01-17 (木) 21:33:20+09:00

ソフトウェア

timidity のプロジェクトの一つ、 osdn にある timidity++ 41版 というプロジェクトをローカルでビルドしようといろいろ試していて、やり方が分かった。

プロジェクトのルートフォルダごとに CMakeList.txt というファイルがあるので検索して見つけた CMake というツールを使うことで一発でビルド出来た。

最初 CMakeList.txt の中身を覗いてみたときに思ったのは、冬星の知っている Makefile の記述とはかけ離れてるなあ、ということだった。どちらかと言うと何かのスクリプト言語みたいな感じがした。

ビルドの仕方も、冬星の知っている make とは全然違っていた。 make の場合は、 make –f Makefile などとして Makefile を読み込ませればそのまま gcc なりのコンパイラが呼ばれビルドが始まったが、 CMake の場合はそうではなく、プロジェクトのルートフォルダに CMakeLise.txt があっても、そのフォルダで CMake CMakeList.txt などとしても何も起こらなかったが、「CMakeの使い方(その1)」を見て手順が分かった。

CMake でのビルドは:

  1. プロジェクトのルートフォルダ(プロジェクト用の CMakeList.txt が用意されている)で mkdir build などとして、ビルド用のフォルダを作る。
  2. 作ったフォルダに移動する。
  3. そのフォルダから cmake .. とする。

という不思議な手順で行う。こうすることでビルドが行われるかというと、実はそうではなくビルドは始まらない。 timdiity41 の場合、 Visual C++ 用のソリューションとプロジェクトが自動生成された。

そこで、 Visual C++ 用のソリューションをダブルクリックして Visual Studio を起動しソリューションを開いてやることで、ようやくビルドを開始することが出来た。

ここまで書いてから書くのもなんだが、つまり CMake は Visual Studio に対応しているということだ。(でなければこんなことができるはずがない。)また、 gcc にも対応しているらしい。 gcc の場合、上の手順の3まで行ったら make 用の Makefile が自動生成されるようだ。一言で言うと、 CMake は make の一種「ではなく」 Makefile などを自動生成するためのツール、ということだ。

キーワード: CMake timidity


rNote のオリジナルコードでは、単一記事モードで記事を閲覧したとき、

function RefererCheck()

の中で、有効なリファラか判定するために、

if(!ereg("^https?://.{6,}",$HTTP_REFERER)) return;

となっている。 ’//’ のあとに、任意の6文字以上があれば有効と見做している。

しかし、「ドメイン名の文字数と使える文字の制限」に書いたように、 http://a.cn/ など、1文字ドメインからのアクセスを考えると、これではまずい。

その部分を、

if (!preg_match("/^https?:\/\/([[:alnum:]-&#;%\.\\\\]+\.|)[[:alnum:]-&#;%\\\\]+\.[[:alnum:]-&#;%\\\\]+([\/]?|\/[[:alnum:]-_&=%#!?;~:@\/\$\.\"\']+|\.|)$/", $HTTP_REFERER)) return;

と変更する。

これで、少なくとも第2レベルドメインまで存在し、

http://foo.jp
http://foo.jp.
http://foo.jp/
http://www.foo.jp/
http://www.foo.bar.jp/
http://foo.jp/bar
http://foo.jp/bar.php
http://foo.jp/bar.php?u=sample
http://foo.jp/bar.php?u=sample&date=2018-12

などの形式の場合に有効なリファラと判断するようになる。

数値参照でエンコードされてきた場合などを考えて、ラベルには「%&#;\」などを追加してあるが、必要ないかもしれない。

キーワード: rNote リファラ referer


html_body.skin の中で、

<script src="lightbox2/js/lightbox.js"></script>

などと記述した場合、 HOME で記事一覧を表示中は問題ないが、サブカテゴリの記事を表示中には、ディレクトリ位置が変わるのでスクリプトを正しく読み込めないのが分かった。そこで、 rnote.php が存在する場所を / からの相対ディレクトリで返す、

<%=$site_dir%>

を追加した。これを使って、



<script src="<%=$site_dir%>lightbox2/js/lightbox.js"></script>

と記述することで、読み込まれたファイルのディレクトリが変わっても問題なくスクリプトを読み込める。

キーワード: rNote 置換命令 <%=site_dir%>


CGI 版 php での制限 2018-12-21 (金) 13:52:50+09:00

ソフトウェア

最近、いつまでたってもブログのカウンタが増えないなあと思っていたが、原因が分かった。

リファラが取得できなかった場合はページ内移動かどうかの判定が出来ないため、カウントアップをしないようにしていたのだが、なぜかその部分のコードを通っていたのでカウントアップされていなかった。

どうしてなのか調べてみると、「さくらサーバでのfilter_input(INPUT_SERVERの挙動が・・」のコメントによると、どうやら、 CGI 版の php では、

filter_input(INPUT_SERVER,'HTTP_REFERER')

などの INPUT_SERVER を引数に取るもの( $_SERVER の値)が全滅するらしい。

$_SERVER['HTTP_REFERER']

に戻したら、以前のようにカウントアップするようになった。

ちなみに、「PHP filter_input(INPUT_SERVER, 'REQUEST_METHOD') returns null?」によると、 CGI 版では filter_input() を用いた場合 INPUT_SERVER, INPUT_ENV の値は取得できなくて、INPUT_GET, INPUT_POST, INPUT_COOKIE の値は取得できるそうだ。

キーワード: php CGI filter_input INPUT_SERVER bug