うーん、困った 2019-08-14 (水) 14:37:23+09:00

ソフトウェア

rnotepad を管理者画面に組み込んだのは良かったが、問題が起きた。

「動作設定」を実現させているプラグイン config.php 内で cookie を使用しているのだが、 setcookie() 関数が動作しなくなってしまった。

理由を調べて分かったが、「setcookie」によると setcookie() は、

ほかのヘッダ情報と同様に、 クッキーは、スクリプトによる他のあらゆる出力よりも前に 送信される必要があります(これはHTTPプロトコルの制約です)。 や タグはもちろん 空白も含め、あらゆる出力よりも前にこの関数をコールするようにしなければなりません。

ということだが、 rnotepad.php では、 javascript を使用している。

それのどこがいけないかというと、 rnoteadmin.php の動作として、管理画面用のプラグインを順にファイルから require_once() で読み込む。そのとき読み込んだプラグイン内に javascript のコードが含まれていると、その場で

<script type="text/javascript"> 〜 </script>

が出力されてしまうのだ。その結果、 setcookie() は失敗する。

動作設定の画面で「この内容で設定する」ボタンを押すと、 config.php が呼ばれ、毎回上のような動作になるので、必ず setcookie() は失敗してしまう。

これを回避するには、先日実装したコールバックプラグインの機能を使い、新たに「 rnoteadmin.php が読み込まれ、管理画面用プラグインが読み込まれる前に実行するコールバック」を追加し実装するしかないが、そうすると、 config.php の処理が2つのファイルに分かれてしまい、見通しが非常に悪くなるのでやりたくない。

いっそ、 config.php の今の実装を見直し、「携帯用ページをテスト」のフラグを他の項目同様 cookie ではなく config.ini を用いるように変更してしまえば cookie を使わないので、とりあえず問題は回避されるが、 cookie を使わずに特定のブラウザからのみ携帯用ページを表示させてテストするという動作を実現させる方法が分からない。それに、 cookie の使用をやめて回避したのでは、今後 cookie を使用したくなったときに困るので、これは単なる逃げであり解決ではない。

う〜ん、これは困った・・・。どうすべきか。

この記事のリンク元 | 10 | 8 |

この記事のリンク用URL&トラックバックURL : https://red-souls.jp/ichounoki/rnote/software/20190814_143723512439.htm


ずいぶん前に一度、この機能を実装した記憶があるのだが、今の rNote を見る限り機能が付いていなかったので、改めて実装した。

今回は、プラグイン機能の拡張から行った。

rNote のプラグイン機能は、基本的に、 PHP で1つのクラスを作ることで行われる。そのクラスには、 exec() というメソッドを実装しておき、クラス名と同名の主ファイル名の php ファイルを plugins/ ディレクトリの中に入れておく。

そして、スキンファイルの中で、 <%=plugin func="呼び出し関数名" opt="呼び出し関数に渡すパラメータ"> タグを書き込んでおくと、その部分が表示されるときに、プラグインが呼ばれる、という作りだ。( func パラメータは無くてもいいが、その場合 exec() メソッドが呼ばれる。)

ただ、このプラグイン形式だと、スキンファイルに記述しておき、そのスキンファイルが表示されるタイミングでしか呼び出すことができない。

今回の場合、「コメントが送信された」というタイミングで、そのコメントに関する情報を管理者にメールする必要があるので、特定の動作をトリガーにして、パラメータを受け取って起動するようなプラグインである必要がある。なので、現状の「スキンに書かれ、スキンが呼ばれるタイミングで実行される」形式では要件を満たせない。

そこで、今回は、 rNote.php 本体に手を入れ、「『コメントが送信された』タイミングで呼び出されるプラグイン」というものを実装した。このように、「ある動作をトリガーとして、その動作が起きた時に呼び出されるプラグイン」のことを、「コールバックプラグイン」と呼ぶことにした。

そして、コールバックプラグインの実装方法は、 rnote_config.php の中に、

$g_strPlugin = array();

array_push($g_strPlugin, array('name' => 'cmntemail', 'instance' => null, 'func' => 'callback', 'type' => 'wbsave'));

のように、呼ばれるプラグインに関する情報をひとまとめにした要素をもつ配列 $g_strPlugin を用意し、その1要素として、 name, instance, func, type を定義し配列 g_strPlugin に追加する。ここで、 name はプラグインのクラス名、 instance は初期値 null 、 func は呼び出されるメソッド名、 type はコールバックプラグインの種類と定義した。現在は、 type は 'wbsave' (コメントが送信され保存されたタイミング)のみが実装されている。

この形式で、 email を送信する cmntemail クラスを記述し、 plugins/ ディレクトリに用意することで実現した。

何度かテストし、問題なく動作することを確認している。

この記事のリンク元 | 9 | 8 |

この記事のリンク用URL&トラックバックURL : https://red-souls.jp/ichounoki/rnote/works/software/20190813_165038581371.htm


rNote は、記事にコメントが付いた場合、有無を言わさず即時公開される。

これでいい場合は構わないのだが、公開して良いコメントかどうかを確認してからOKなら公開するようにした方がよいと思う管理者もいると思う。自分もその一人だ。コメントスパム対策にもなると思う。(コメントスパムがつくこと自体を回避はできないが、スパムだらけの記事にならないように管理することはできる。)

そこで、管理者画面に追加するタイプのプラグインとして一つ、「コメント承認」プラグインを追加した。

このプラグインの実装のために、まず rNote 本体に手を入れ、コメントの内容を保存したログファイルのフォーマットを拡張した。このログファイルは、コメントのつく先の記事1つにつき1ファイル作成され、1つのコメントが1行になるようになっている。1行の形式は、

投稿者名 [tab] mail/url [tab] 本文 [tab] 投稿日時 [\n]

となっていたので、1項目追加し、下のような形式にした。

投稿者名 [tab] mail/url [tab] 本文 [tab] 投稿日時 [tab] コメント承認フラグ[\n]

コメント承認フラグは「0:未承認, 1:承認済み」というフラグとした。

rNote に手を入れた場所はもう1箇所あって、管理者画面用の「動作設定」プラグイン ( config.php )

だ。ここに、「コメントを承認制にするかどうか」のラジオボタンを追加し、状態を保存するため、他の項目と同様に、グローバル変数の配列 $g_config[] に 'confirm_comment' というキーで値を保存するようにした。このフラグの設定状態を見て、 rNote.php 本体でコメントが送信されたときの処理に、コメント承認制であれば先程のコメント承認フラグを 0 にセットし、承認制でなければコメント承認フラグに 1 をセットしてログファイルを書き込むように動作を修正した。

ここまでの準備ができたので、いよいよコメント承認プラグインを書いた。ぷにゅさんが公開されている「Entries List Plug-in v1.01 & rNote LogViewer lot.041025」を参考に実装した。

ぷにゅさんのプラグインでは、コメントのログファイルを一覧表示し、中身を編集したり、ログファイルを削除したりできるようになっているが、自分のプラグインでは、ログファイルの一覧ではなく、コメントの一覧を表示し、コメントごとに「承認・未承認」の状態を切り替えられるリンクをつける形にした。1ページ分の表示件数は、ぷにゅさんと同じ30件にしたが、この30件はログファイルの件数なので、コメントの多く付いた記事があった場合、実際に1ページに表示される項目数は30を超える。

とりあえずこれで安心してコメント管理ができる。

この記事のリンク元 | 9 | 8 |

この記事のリンク用URL&トラックバックURL : https://red-souls.jp/ichounoki/rnote/works/software/20190813_165002332041.htm


カレントディレクトリから再帰的に下位の全てのディレクトリをたどって、検索したいことがないだろうか。

これって、ぼくは頻繁に使いたくなるのだが、なぜか解説しているサイトがほとんど見つからなかった。

Grep で特定の拡張子のファイルのみ対象・除外する」の説明を見て、

$ grep -r 検索パターン --include='*.foo'

とすると、拡張子 "foo" のファイルのみ検索対象として、パターンを検索できるのが分かった。

それでも普段ついつい、

$ grep -r 検索パターン *.foo

としてしまう。

他のコマンドでは、指定ファイルのみ対象にしたいとき、このように指定するからだ。

例えば ls の場合、

$ ls *.c

とすると、拡張子が ".c" のファイルのみの一覧を返してくれるのだ。

どうしてこの形式で統一して、 grep でも指定拡張子のみからの検索ができるようにならないのだろう。面倒だ。

・・・と思ったのだが、多分これって、上の "*.c" という指定の結果が展開されるのが、「指定した1つのディレクトリのファイルだけ」だからではないか。

つまり、動作としては、シェル上でコマンドを入力し、その中に、ワイルドカードを使ったファイル名の指定があった場合、そのパターンにマッチするファイル名がシェルによって全て展開され、コマンドに渡される。ただし、当然だが、それは指定した1つのディレクトリのみが対象であり、複数のディレクトリを1つのワイルドカードで指定する方法はない、と。

例えば、 grep -r "foo" ~/bar/baz/*.sh は、 ~/bar/baz/ ディレクトリにある "*.sh" というパターンにマッチするファイルを対象として検索してくれる。ただし、 -r を指定していることの意味はなくなってしまい、 ~/bar/baz/ の下にディレクトリがあっても、それらは検索対象とならない。なぜなら、シェルが ~/bar/baz/*.sh を展開しファイルの一覧をコマンドに渡す結果、対象がそのファイルのあるディレクトリのみに限定されてしまうからだ。

また、 grep -r "foo" ~/bar/*/*.sh などとしてみても、それは ~/bar/ とその下の全てのディレクトリを対象とする、という意味にはならない。

ここまで検証してみて思ったのだが、 find コマンドの場合、

$ find /home/ -name "*.c"

のようにしてやると、指定のディレクトリ /home/ とその下の全てのディレクトリを対象として、 "*.c" というパターンにマッチするファイル名を全て検索してくれる。

grep の場合も、同様に第1オプションで検索を開始するディレクトリを指定するという方法であれば、現在の「 -r 指定により下位のディレクトリも検索できるが、『カレントディレクトリから下位』としか指定できない」という問題も解決できるのだが、どうだろうか。

他の方法としては、

$ sudo cat `sudo find /home/ -name *.c` | grep "foo"

のようにすることで、指定のディレクトリ以下にある指定の拡張子のファイルのみを対象として grep で検索ができる。

さらに他の方法として、

コマンド find ファイル名・タイムスタンプ・ファイルサイズなどを元に、ファイル・ディレクトリを検索する。」によると、

$ grep "foo" `find /home/ -name "*.c"`

のようにすることでも、指定のディレクトリ以下にある指定の拡張子のファイルのみを対象として grep で検索ができる。


ベーシック認証の設置方法 2019-08-10 (土) 11:13:52+09:00

メモ

ネットで検索すると .htaccess と .htpasswd というファイルを作るという説明が多数あった。

まず .htaccess について。

いきなり、認証をかけたい url に .htaccess を用意して、

    AuthType Basic

AuthName "Input your ID and Password."

AuthUserFile /url/.htpasswd

require valid-user

のように書けばよい、と書いてあるサイトがあるが、間違いだ。

ベーシック認証を許可するには、ベーシック認証を実行したい url で AuthType, AutoName, Require, AuthUserFile などの認証処理に必要なディレクティブが許可されていなければいけないのだ。

その方法は2つある。

1つ目は、上記の通り .htaccess を用意する方法だが、その url でベーシック認証に必要なディレクトリ群を使用許可していなければいけないので、 httpd.conf (以前書いた通り ubuntu の apace2 では apache2.conf)にて、

<Directory "/設定したい url /">

AllowOverride AuthConfig

</Directory>

のようにして、ベーシック認証に必要なディレクティブの実行を許可しておく必要がある。

<Directory "/設定したい url /">

AllowOverride None

</Directory>

などとなっている場合もあるので、 httpd.conf ( apache2.conf ) をよく見て修正する必要がある。

2つ目は、 httpd.conf ( apache2.conf ) に直接、

<Directory /ベーシック認証したいurl/>

AuthType Basic

AuthName "Auth"

AuthUserFile .htpasswd

Require valid-user

</Directory>

のように記述する方法だ。

これらの方法で、ベーシック認証を行いたい url での認証許可や認証に使うファイルを指定しておく。

次は .htpasswd についてだ。

多くのサイトでの .htpasswd の作り方の紹介内容が問題だ。多くのサイトが、自分のページに、「暗号化されたパスワード文字列を生成するツール」を用意していて、それを使って作るように書いてある。

それは、あぶなくて使えない。

ネットのセキュリティを構築するためのパスワードなのに、どこの誰かも分からないサイトに、大事なユーザ名とパスワードを渡してしまえば、暗号化されたパスワードまで知られてしまう。

セキュリティはゼロになる。

暗号化されたパスワードは、自分で作れる。

apache2 のパッケージの中に htpasswd というコマンドがあるので、それで作るとよい。

ubuntu の場合、htpasswd コマンドは apache2-utils パッケージの中に含まれていて、 /usr/bin/ にインストールされる。

使い方は、「ApacheでBasic認証をするhtpasswdのコマンド」にも書かれているが、こちらの解説はユーザ名を指定して .htpasswd ファイルを作るとしか書かれていないので不十分である。

参考サイトに書かれているように

htpasswd -c ファイル名 ユーザ名

と入力したらどうなるかというと、そのユーザ名のためのパスワードを聞かれる。そして、決めたパスワードを入力すると、指定したファイル名でベーシック認証用のファイル(通常は .htpasswd )が作成される。

htpasswd -bc ファイル名 ユーザ名 パスワード

とすると、パスワードまで指定してコマンドを実行し、指定のファイル名でベーシック認証用のファイルを作成できる。

より詳しい使い方は htpasswd --help で自分で確かめてほしい。

おまけ:

アクセス制限ベーシック認証 ~パスワードでページを守ろう~」では、 perl のスクリプトでパスワードの暗号化を行う例が示されている。