ここのAtomをRailsのAtomFeedHelper#atom_feedで出力してたんですが、基本全て数値文字参照で出る。

エンコーディングに関係無く表示されるので正しくはあるんだろうけど、クロールされてるところ(Planet PHP Japanなど)ではもう一度エスケープがかかって数値の羅列になってしまう。

フィードクライアントとしては数値文字参照をHTMLとして解釈した上でエスケープする必要があるだろう。しかし、自分がクロールする側になったら正直、

「面倒だから数値文字参照などにせんでくれ・・・」

と思うだろう。

しかもそういったクライアントを通して見る第三者の人にとってはそんなサーバークライアント間のやり取りなどどうでもいいことで、単に

「文字化けうぜぇえええ」

である。

atom_feedメソッドでのHTMLのエスケープはたくさんのクラスを遡って、最終的にはここ(String#to_xs)でやってるらしい。

/activesupport-2.2.2/lib/active_support/vendor/builder-2.1.2/builder/xchar.rb:

class Fixnum
  XChar = Builder::XChar if ! defined?(XChar)

  # XML escaped version of chr
  def xchr
    n = XChar::CP1252[self] || self
    case n when *XChar::VALID
      XChar::PREDEFINED[n] or (n<128 ? n.chr : "&##{n};")
    else
      '*'
    end
  end
end

(...snip...)

class String
  # XML escaped version of to_s
  def to_xs
    unpack('U*').map {|n| n.xchr}.join # ASCII, UTF-8
  rescue
    unpack('C*').map {|n| n.xchr}.join # ISO-8859-1, WIN-1252
  end
end

コメントを見ると、そもそもコレ自体XCharライブラリーというのを拝借しているものらしい。

Wikipediaによると、西欧22言語をサポートするISO-8859-1もCP1252も共にLatin1と呼ばれますが、IBM由来のMicrosoft Codepage(CP)では0×80から0×9Fの範囲の文字が拡張されています。(ユーロ、ダガーとか)

要はShift_JISとCP932みたいな問題がLatin1とCP1252にもあるんですな。

何のためのライブラリかというと、多言語化の時に問題になりそうなそのCP1252の拡張部分を適当な文字にマッピングするためのものらしい。(自動的にCP932で書いたら問題が起きそうなことが予想できる)

とりあえずUnicodeをUTF-8で使ってれば問題無いだろうということで下記の様に対処した。

config/initializers/rails_ext.rb:

class String
  def to_xs
    ERB::Util.html_escape(self)
  end
end

大丈夫かな?

CakePHPガイドブック
  • CakePHPガイドブック
  • 毎日コミュニケーションズ(2007-10-25)
  • 毎日コミュニケーションズ
  • 定価:¥ 3,360
  • 新品価格:¥ 3,360
  • 中古価格:¥ 2,860
  • ASIN:4839924317

これからCakePHP使うので借りて読みました。分かりやすかったです。1.2が出そうなのだとしたら読むタイミング悪かったかな?

仕事でOpenPNEのソースを読む必要があったんですが、想像してたのとは違って全然読み易い。

「なんだー、読み易いじゃんー」

などと言いながらホクホク読みました。

オープンソースプロジェクトはソースの読み易さを気にするためか、読み易いものが多いようです。しかし、社内ツールやレガシーシステムなど、世の中にはまるで夏の目黒川の如く近づくことさえためらわれるようなPHPアプリケーションが多数存在します。

そんなPHPアプリケーションの異臭を嗅ぎ分けるための7つのポイント。

  1. テンプレートシステム(PHP自身を含む)が無い。
    これさえあればコードを理解するのはかなり容易になるでしょう。さもないと・・・。
  2. register_globalsがOn。
    そのアプリは臨終前の患者です。大きな手術は諦めて延命治療に勤めましょう。
  3. magic_quotes_gpcがOn。
    フォームから保存するたびにバックスラッシュが増えるアプリを見るのはとても悲しいことです。
  4. IIS
    至急PHPとWindows Serverのベテランを探しましょう。
  5. 設定ファイルがXML 。
    最大で深さが2しかないデータ構造にまでXMLが使われている場合、プログラマは設計者の強い信念と独創性に苛まれるでしょう。(特にPHP4では茨の道。)
  6. eval, extract, create_function
    grep殺し。
  7. mbstring.encoding_translationがOn。
    素人にはオススメできない。

これらの特徴はデスマーチの周囲でしばしば目撃されることが知られています。

ある研究者(俺)によれば、php.iniやソースコード管理システムを上記のキーワードで検索するだけでPHPプログラマーのデスマーチ回避率は32%向上すると言われています。

もちろん上記を上手く使っているアプリケーションも多くあり、使っていること自体を非難することはできません。

・・・。

と無難にまとめようと思いましたが、あきらかに使うべきでないものも世の中にはあるんです!

参照: PHPで知っておきたいcreate_function5つのトリビア

現状、「OpenPNE(1)」と「OpenPNEの会員データと連動したWebデータベースアプリ(2)」が動いているコンシューマ向けサイトがあります。

ここに、私が別の「Webデータベースアプリ(3)」を、yoshukiさんが別の「携帯対応フォーラムアプリ(4)」を追加で作る予定があります。

  • (1)、(2)は前担当会社のシステム(PHP)でありこれからサーバー毎引き継ぐ。
  • 1年前から周辺システムはRailsで統一されつつある。
  • サイト全体を今後、継続的に開発していく予定にある。
  • お客さんの優先順位の第一位は(3)を期間内に立ち上げる事
  • (1)はクローズしてもかまわない事。
  • とは言え出来ることなら既存会員データは残したい。(俺の思惑)
  • 工期に余裕はない。(まっさらから3を作る分しかない)

みなさんなら会員データ周りをどのように設計しますか?

俺が考えた選択肢:

  1. (1)、(2)の会員テーブルを見るようにして(3)、(4)を作る。
  2. (3)、(4)ともに新規に作る(データ連携無し)
  3. (3)と(4)は同一会員データで作る(1、2との連携は無し)
  4. (3)、(4)を作った後で(1)、(2)をそれにあわせるように改修する。
  5. (3)、(4)を作った後で(1)はクローズ、(2)は改修する。
  6. 認証サーバ的なものを作る。

俺の中のSIer人格:

「お客さんから必要十分条件は提示されている。当然2だ。どんなシステムも段階的改修が可能である。ストアドプロシージャ、変換スクリプト、バッチ等で次フェーズ以降でのシステム統合を目指せばよい。」

俺の中の楽観主義者:

「5でしょ!きょうびほとんど使われて無いOpenPNE維持してもコストかさむだけでしょ!(2)をRailsで作り直して新機能を作ろう!」

俺の中の潔癖主義者:

「6が正しい。OpenIDサーバーを作り、全てのサービスを対応させる。authorizeとauthenticateは別である。」

俺の中の事無かれ主義者:

「前の会社がOpenPNEに合わせたんだから僕らも1だよ。PHPで作れば環境も合わせられるし」

まあ、おまいら(俺ら)の言い分もわかるが・・・。

DNSBLクライアントのライブラリdnsbl_clientをGithubに置きました。

komagata’s dnsbl_client at master ? GitHub

Install:

% sudo gem install komagata-dnsbl_client -s http://gems.github.com

Usage:

require 'dnsbl_client'
DNSBL::Client.new('list.dsbl.org', 'niku.2ch.net').listed? '61.211.32.39' # safe ip
=&gt; false
DNSBL::Client.new('list.dsbl.org', 'niku.2ch.net').listed? '78.157.143.202' # spam ip
=&gt; true

2chのDNSBL、BBQ用のライブラリも同梱してます。

require 'dnsbl_client'
DNSBL::BBQ.listed? '61.211.32.39' # safe ip
=&gt; false
DNSBL::BBQ.listed? '78.157.143.202' # spam ip
=&gt; true

何で作ったのか

人への嫌がらせ方法も進化したのか、「玄関前に猫の死体」から「ピザの大量注文」になり、最近では「お墓の資料の大量注文」というのもあるようです。

仕事で霊園(お墓)のサイトをやっています。そこでは、お墓を買う予定のある方が興味のある霊園(を運営する石材店)にフォームから資料請求できるようになっています。

この資料請求はお墓の購入にほとんど直結するといってもいいような確度を持つ大事なものです。(お墓は高いすからね)

普通は特定の市、区全体にカラーの広告を配布してやっと1件、2件獲得できる。それがお墓の資料請求なのです。

で、やられました。お墓の資料の大量注文。オープンプロクシ経由でゲイバーに。

そのプロクシ:

% nmap xxx.xxx.xxx.xxx
Starting Nmap 4.11 ( http://www.insecure.org/nmap/ ) at 2008-09-20 20:41 JST
Interesting ports on xxx.xxx.xxx.xxx:
Not shown: 1655 closed ports
PORT     STATE    SERVICE
21/tcp   open     ftp
53/tcp   open     domain
80/tcp   open     http
88/tcp   open     kerberos-sec
135/tcp  open     msrpc
139/tcp  open     netbios-ssn
157/tcp  open     knet-cmp
179/tcp  filtered bgp
389/tcp  open     ldap
445/tcp  open     microsoft-ds
464/tcp  open     kpasswd5
554/tcp  filtered rtsp
593/tcp  open     http-rpc-epmap
636/tcp  open     ldapssl
1026/tcp open     LSA-or-nterm
1027/tcp open     IIS
1050/tcp open     java-or-OTGfileshare
1720/tcp filtered H.323/Q.931
1723/tcp open     pptp
1755/tcp filtered wms
3268/tcp open     globalcatLDAP
3269/tcp open     globalcatLDAPssl
7070/tcp filtered realserver
8080/tcp open     http-proxy
8443/tcp open     https-alt
Nmap finished: 1 IP address (1 host up) scanned in 65.058 seconds

Windowsなのでスパムメールより主にプロクシとして日本から便利に活用されてるホストみたいです。

追跡を断念して今後の予防策を調べてみたところ、知ったのが2chで使っているDNS BlacklistのBBQです。

DNSBLはスパムメール対策としてよく使われるみたいですが、スパムメール対策としては効果は微妙なようです。ですが、BBSやコメントスパム対策にはかなり効果がありそうです。

荒らしの総本山といえる2chのデータを元にメンテナンスされているBBQのブラックリストは日本で使うには一番の品質なんじゃないでしょうか。実際、上記のプロクシのIPも登録されています。

実装の方は、Apacheで直接DNSBLを使えるモジュールもありますが、完全に弾くだけでなく、どこかに退避させたりしたいのでアプリの中から使いたいところです。PHPではPEARにNet_DNSBLというライブラリがあるみたいです。Rubyで見当たらなかったので作ってみたというわけです。

まだテストもなくしょぼいコードなので何かあったらご指摘(もしくはpush)いただければと思います。

参照:

freenodeにrails-tokyoチャネルを作りました

ということで、irc.freenode.netに#rails-tokyoチャネルを作ってみました。

ッザース!

早速JOINして下らない質問をしてみたところ、すぐ回答してもらえました。良い人だー!

質問:「sessionって普通どう消してますか?」

答え:「DBの場合はcronとかで普通に消すとのこと。」

14日前までのは消して、ついでにOPTIMIZEというのを用意してこれをcronで回すことにします。

script/dbmaintenance:

#!/usr/bin/env ruby
RAILS_ENV ||= "production" 
require File.dirname(__FILE__) + '/../config/boot'
require RAILS_ROOT + '/config/environment'

con = ActiveRecord::Base.connection
con.execute "DELETE FROM sessions WHERE updated_at &lt; '#{14.days.ago.to_s(:db)}'" 
con.tables.each do |table|
  con.execute "OPTIMIZE TABLE #{table}" 
end

現行アプリだとショッピングカートみたいのがあるので結構溜まってました。

PHPだと言語自体にsession gcがあるからそういうのがあるのかと勘違いしてました。でもPHPのDebianパッケージ版はsession gc切ってcronで消してたから特に違和感は無いですね。

restful_authenticationだとsessionが使わないから不要?キャッシュ用途だとDBじゃ遅いから意味ないのかな。

ウノウラボのcoco1さんの記事を見てIRCを入れてみようと思いました。

UlimaOnline廃人時代以来あんまり使ってなかったのでいったいどこに入ればいいのか・・・。haltさんの教えもあって#PHPStudyと#CakePHPに入れました。

今日びのIRCライフはtiarraというIRC Proxyを立てて、そこからtwitterやらlingrやらを取りに行って一括して扱うのが普通だそうです。ポートが必要な常駐ソフトを使ってるってことはみんなサーバー持ってるってこと?ワープアショックです。

よく考えたら、前に使ってた糞VAIOが**ny専用機+プリンタサーバー+NASって感じで放置されてるのに気付きました。

糞の中のcoLinuxをブリッジ接続にして外からはdynamicDNSを振りました。これでtiarraライフが。

しかし、家だとLAN内アドレス、外だとdDNSのアドレス、切り替えるのが面倒臭い。家にDNS立てればいいのかな?だりー。

フリーになるとオープンソースをちょっとカスタマイズとか出来ると楽できていいですよね。

そうなるとPHPは外せないわけで、ちょこちょこPHPで出来たオープンソースソフトウェアを弄るわけですが、大規模開発とかSIer向けとかとは違った、OSSのWebアプリに向いた設計があることに気が付きました。

具体的にはWordPressの作者の人(?)がもっと設計を洗練させて作ったというbbPressというフォーラムのソフトがあるんですが、これのソースを見たとき、

「うは、なるほど。やられた。この人はわかっちょる。」

とちょっとショックを受けました。

とりあえずタイトルに対する結論から列挙しますと、(bbPressですが)

  1. 言語はPHPしかありえない
  2. インストールに黒い画面(ターミナル)を使う必要があってはいけない
  3. FrontControllerを使わない。(URL見たまんまのファイルがあること)
  4. クラスを使わない。functions.phpとかにbb_xxxxとかいう関数を列挙する。
  5. テンプレート言語はPHP。theme/default/以下とかに置いて、前述のURL見たまんまファイルと同名にする。(register.phpとか)
  6. ディレクトリ構造はフラットに近くする
  7. gettextを使っておくと自然と翻訳してくれる人が現れる

作者はとにかく「サードパーティー開発者」と「ユーザー」に奉仕して、DRYに反していても誰にでもわかりやすいまま頑張ってスパゲッティにならないようにします。

より多くの「サードパーティー開発者」に気に入ってもらえるようにすることがひいてはプラグインの増加、ソフト自身の価値向上につながるんですね。

この構造の明快さだけでこのアプリのファンになってしまいました。

ただ、裾野が広すぎると、実際に何度も起こっているようにプラグインでSQL Injectionを作りこんでしまう可能性が高いのは何とかしないとまずいですね。プラグインの中でプレースフォルダ使ってない部分があったら警告表示するとか、できないかな?

MTOS4.1を使ってみて、もはやカスタマイズ方法を勉強するコストが俺のモチベーションを遥かに上まわる程、テンプレートが細かく構造化されており、ウェブページ(ブログ記事以外)を含めたテーマ(StyleCatcherを使ったStyle?)も殆ど見つからない状態。(だから今、このブログはデフォルトの鶏なんです・・・)

あと、今記事1580個なんですが、再構築はホント萎えます・・・。

フリーとして小さい要望をちゃっちゃと終わらせるためにはWordPressも知っとかなきゃなあということもあって大東亜戦争従軍記をWordPress2.5.1に移行始めました。(もっと和風っぽくする予定です・・・)

これが、何かわかりやすい!テンプレというかテーマもPHPまんまだし。

結構お馴染みっぽいvicunaというところのテーマを使わせてもらってます。ただ、おじいちゃん達が読むサイトなのでフォントでかくしたり、激しく日本語表記をわかり易くしたりカスタマイズしています。

多言語化にはgettextを使っているようで、

__(msgid, domain);

こんな感じの記述がテンプレ中に見られます。あー書き方ちょっと面倒いけどわかりやすいっすねー。

wp-content/themes/wp.vicuna/languages/ja.po

をちょっと弄ってって、

% msgfmt -o ja.mo ja.po

で完成。でも”“トラックバック”“とかいってもわかんないよなあ。

PHPマニュアルや以前書いたエントリーへのコメントで教えて頂いたcreate_functionトリビアのまとめ。(下記全部PHP4です)

1. create_functionで作った関数は無名じゃないし、どっからでも呼べる。

% cat lambda_1.php
&lt;?php
create_function('', 'echo "foo\n";');
call_user_func(chr(0)."lambda_1");
% php lambda_1.php
foo

2. しかし、定義済み関数には出てこない。

% cat lambda_2.php
&lt;?php
create_function('', 'echo "foo\n";');
print_r(get_defined_functions());
% php lambda_2.php | grep lambda
%

3. でもやっぱり存在するらしい。

% cat lambda_3.php
&lt;?php
create_function('', 'echo "foo\n";');
var_dump(function_exists(chr(0)."lambda_1"));
% php lambda_3.php
bool(true)

4. create_functionで作った関数は参照が返せない。こんなのを作っておくと便利かも。

% cat lambda_4.php
&lt;?php
function create_ref_function($args, $code) {
  static $n = 0;
  $name = "ref_lambda_".++$n;
  eval("function &".$name."(".$args.")"."{".$code."}");
  return $name;
}
$func = create_ref_function('', 'echo "foo\n";');
call_user_func($func);
% php lambda_4.php
foo

5. create_function内での関数名は一律__lambda_func。

% cat lambda_5.php
&lt;?php
create_function('', 'echo __FUNCTION__;');
call_user_func(chr(0)."lambda_1");
% php lambda_5.php
__lambda_func

Have a good create_function life!

参考:1byte 参考:PHP: create_function – Manual

(Life Hack系みたいにキャッチーなタイトルを付けたかっただけなんです。知っても何の生産性も上がりません。すみません・・・。)