プログラミングの最近のブログ記事

続き。

MTベースの開発案件の時に「DBのスキーマはどうなりますか? ウチの方でPHPでMySQL叩いて開発とか後でできるでしょうか?」みたいな話が出るので。静的に動的なページを吐き出す(??)サンプル書いてみました。

エントリーを20件リストで表示する、ただそれだけ。直に書いてしまうとせっかくのテンプレートとロジックの分離のメリットが活かされないのですが、部分的に動的な処理を入れたいといった時にはまぁこんなやりかたも出来るということを覚えておいても良いと思います。

インデックス・テンプレートを作成し、「公開→スタティック」「出力ファイル名→foo.php」として保存・再構築。ブログ記事のリストの部分は動的に都度処理されます。それだけですが...

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=<$MTPublishCharset$>" />
    <title>DPAPI Example - <MTBlogName escape="html"></title>
</head>
<body>
<?php
    include('<$MTCGIServerPath$>/php/mt.php');
    $mt = MT::get_instance(<MTBlogID>, '<$MTCGIServerPath$>/mt-config.cgi');
    require_once("MTUtil.php");
    $args['class'] = 'entry';
    $args['blog_id'] = <MTBlogID>;
    $args['offset']=0;
    $args['limit']=20;
    $entries = $mt->db()->fetch_entries($args);
    $max = count($entries);
    $i = 0;
    foreach ($entries as $entry) {
        if ($i==0) {
            echo '<ul>';
        }
        echo '<li>' . encode_html($entry->title) . '</li>';
        $i++;
        if ($i==$max) {
            echo '</ul>';
        }
    }
?>
</body>
</html>

スタッフの仕事の進捗がヤバげだったので急遽phpを担当することになってブロックタグの大物をMT5対応するためにガンダムBrand new APIと格闘してみたメモ書き。

# Power CMS for MTにはPHPプラグインが189もあるんだよ...

Twitter / Junnama Noda: MTのPHP API使ってアプリ開発してるのって日本でhoge人くらいなんだからこんなに力入れてガラッと変えなくても(泣)

さて、ブロックタグの中でのオブジェクトのロードや利用についてのメモを中心に。

エントリーをロード

$args['class'] = 'entry';
$args['blog_id'] = $blog_id;
$args['offset']=n;
$args['limit']=n;
$entries = $ctx->mt->db()->fetch_entries($args);

範囲指定をしてsqlでエントリー(や他のオブジェクト)を読み込む

$entries = $ctx->mt->db()->SelectLimit( $sql, $limit, $offset );

(範囲の指定無し)sqlを実行

$entries = $ctx->mt->db()->Execute( $sql );

読み込んだオブジェクト数の取得

$entries->RecordCount();

個々のレコードの取得

$entries->Move($counter);
$entry = $entries->FetchRow();

エントリーのオブジェクト化(但しcategoryやカスタムフィールドの読み込みはSQL側で調整する必要あり)

$e; 
while(list ($key, $val) = each($entry)) {
    if (preg_match('/^entry_/',$key)) {
        $e->$key = $val;
    }
}
# $ctx->stash('entry', $e);

特定のブログ記事オブジェクトの読み込み

$e = $ctx->mt->db()->fetch_entry($id);

特定のウェブページオブジェクトの読み込み

$e = $ctx->mt->db()->fetch_page($id);

Findでオブジェクトを読み込み

require_once 'class.mt_entry.php'; #entry
$_entry = new Entry;
$where = $where_statment;
$extra = array(
    'limit' => $limit,
    'offset' => $offset,
); 
$results = $_entry->Find($where, false, false, $extra);

続きがあります...

参考

続きです(当日のデモで関連付けがうまくいかなかったのが余程悔しかったのだろう...)。

この方法で出来ないのは、エントリーに対するタグの重み付けなんですね。例えば上記エントリーには「MTDDC」というタグが最も重みが付けられるべきで、そうなれば確実に当日も失敗? しなかったわけです。ところが現状の方法では単語の出現回数なんかでの重み付けがなされないのです。

これについてはMT::ObjectTagオブジェクトを拡張してタグの重み付けを付けるという方法なんかが考えられますが(出現回数なんかでスコアを付ける)、興味のある方はトライしてみても面白いんじゃないでしょうか。

と書いてみたものの...というか「興味のある方=俺」なので取り敢えずMT::ObjectTagに「score」というカラムを追加して出現回数を保存するようにしてみた。

scoreを追加したobjecttagテーブル

今回はここまででRelatedEntryを取り出すほうはまだなんだけどね。

よくMovable Type (に限らないけど) のどこが面倒って話で画像とかファイルのアップロードがブラウザベースで1つずつってのは面倒だよねって話になるのだけど。

で、結局作っちゃえばいいじゃん、っていう話になるんですけど何でもかんでもJavaScriptとかAjaxとかでやるんじゃなくて、Adobe AIRでやるとか色々考えられるんだけど (それでもブラウザ上にこだわるならAdobe - Flexでやるとか)、ちょっと思い立ってREALbasic落としてきて触ってみた。昔結構使い込んでいたツールだし、手っ取り早いかなって(iPod touch / iPhoneのアプリ吐けるようにならないかなぁ...)。

1時間ほど使いながらリファレンスとか使い方をググってみたりしたけど(メーリングリストの過去ログとかでサンプル探したり)、一時は結構日本のコミュニティも勢いあったんだけどなぁ、という感想。特に日本語で新しい情報がない。

HTTPSocketまわりは昔使っていた頃からかなり変わっていて(もちろん充実していて)、とりあえずサーバーのcgiにユーザー名とパスワードをポストするだけのスクリプトを書いたらちゃんと動いた。

ウィンドウにURLFieldって名前でテキストフィールド作り、Movable Typeのcgiのパスを入力。プッシュボタンに以下のスクリプトを書いてクリック。


Dim form as Dictionary

form = New Dictionary
form.value("username") = "test"
form.value("password") = "test"
  
MTSocket.setFormData form
MTSocket.post URLField.text

ただそれだけ。ちゃんとMTにログインできた。別にMTでなくともXML-RPCクライアントくらいなら簡単に作れそうな気がする。

で、Assetにアイテム放り込むには添付ファイル? を付ける必要があるわけだが、情報としてはこのあたりか。何とかなりそうか?

受け取る側はプラグイン書くかBootstrapでアプリ作って受け取るとか、ファイルブラウザとかも定義してxmlでAssetのデータリストを返してREALbasic側でインターフェイス作るとか...半分くらいやる気になった。とりあえずライセンスアップグレードしておこうか。

Mac OS X Leopard のAppleScriptが密かに面白い。
単なるOS Xネイティブなアプリケーションだけでなく例えば Movable Type 4.1 のようなソフトウェアを扱えるようになっているようだ(用語辞書、誰が書いたんだろう?)。

エントリーをブログに登録して再構築するスクリプトの例


tell application "Movable Type 4.1"
    activate
    set obj to new entry with property
        { title : "Welcome to Movable Type4!",
          text : "New design launched using Movable Type.",
          status : 2,
          author : 1 }
    set blog to item 1 of mt_blog
    set result to save obj in blog
    rebuild result without index archive
end tell

まぁ、ここまでなら素直にPerlで書けよ! ってなことになるけれど、以下の例なんかどうだ?

Excelと連携させる


tell application "Movable Type 4.1"
    activate
    set blog to item 1 of mt_blog
    set entries to get entries of blog
    set i to 1
    repeat with entry in entries
        tell application "Microsoft Excel"
            tell document 1
                set cell1 to "A" & i
                set cell2 to "B" & i
                set text of range cell1 to (title of entry)
                set text of range cell2 to (permalink of entry)
                set i to i + 1
            end tell
        end tell
    end repeat
end tell

エントリーのタイトルとURLをExcelにそのまま渡してセルにセットしている。Excelからエントリーをインポートの方がニーズはありそうだけど。





嘘! 嘘です。すいません、もうしませんって言ったのに...一年に一度だし...また書いてしまいました。あんまり覚えてないや、AppleScript。(てかLeopardのマシンないし!)

それでも、


do shell script "./tools/run-periodic-tasks"

ってのは普通に使えるかもね。Excelから値をひっぱってシェル経由でPerlスクリプトに渡せばいいわけか。いや、できんことないよな。意味があるかどうかわからんけど。

最近、MacのみならずiPod touchとかiPhoneとかApple製品が面白いんだが、昔僕が良く使い捨てアプリを作っていたREALbasicとか、最近どうなんだろう。iPod touch / iPhoneのアプリが作れるとかなったら再び注目を浴びるんじゃないかなと思っていて、久しぶりに触ってみようかと。

で、本格的なデスクトップアプリを作るほどの暇は年度末のこの次期にはないし、ちょっと以前から思っていたアイデアを少し。

WordPressのプラグインをDrag & Dropすると、Movable Typeのプラグインに変換してくれます。β版。

Drag & Drop すると表示されるウィザードに従って必要な情報を入力していくと変換されます。

やっぱり何でも間でもウェブアプリではなくてたまにはこういうデスクトップアプリとかも作ってみたいよね。



















ごめんなさいごめんなさい。忙しかったのでネタをブラッシュアップする暇がなかったんです!

来年こそはもう少しゆとりを持って面白いネタ考えます。

MTOSの姿はまだ見えませんが...そろそろ直前になってきましたので、内容について触れておきます。

日時:11月10日土曜日 16:00〜 (50分) [会場: 南港ATC ITM棟 9F-H6]

内容について

これまでは割とWeb屋さん向けの場所で話すことが多かったのですが、今回はOSS関係のイベントなので、これまでしゃべって来たことやこのブログに書いて来たものも含めて、方向性としては「Webアプリの開発にMTが便利!」という面を中心に話そうと思います。

  • Inside MT (MTの構成)
  • MT Perl APIの基礎
  • データベースアクセスとMT::Objectのサブクラス作成
  • MTのテンプレートエンジン
  • Perlプラグインによる拡張
  • Bootstrap.pmを利用したアプリ開発
  • PHPによるダイナミックパブリッシング
  • オープンソースならではの活用方法を考えよう

*内容は変更になる可能性があります。

特に、テンプレートエンジンについては、MT4になってMTにCMSテンプレートがMTのテンプレートエンジンを使うようになっていることもあり(3.3まではHTML::Template)、管理画面の拡張やWebアプリ開発でも多いに活用できることから、今回はその辺も強調してみたいと思います。

関西で行われる数少ないOSS系のイベントですから、他のセッションもチェックしていただいて、面白そうなものがあれば是非覗いてみてください。

それでは当日、会場でお会いしましょう。

まだやってるし...もうちょっと続くかもしれないけど、皆さんもう飽きました?

ブログ内検索




  

実は検索だけじゃないのだ

ブログにおけるエントリーの関連性や体系付けを行うしくみとして、カテゴリーやタグというものがある。一方、読者が欲しい情報を探す一つの手段として「検索」がある。

カテゴリーもタグも発信者の主観で付けられるものだ。ソーシャルブックマーク等のタグはそうではないけれども。

高速なタグ・アーカイブが欲しい

発信者が主観で付けられるものゆえ、検索語の選択が無限であるのに対してカテゴリーやタグは有限だ。であるならばこれらのアーカイブは静的アーカイブにすることが可能で、MTのカテゴリーアーカイブが静的生成できるのは良いとして、タグ・アーカイブも静的生成できるのが望ましいのではないかと思う。

できないのか? と思ってググってみると、同じようなことを考えて既に行っている方がいらっしゃるわけですね(静的生成ではないけど)...

現在作成中のダイナミックパブリッシングを利用した検索ページではタグ検索ができるようになっている。MT4のデフォルトテンプレートでは、タグ検索はmt-searchに渡される動的ページだから、mt-searchが高速動作できる環境でないと遅い(その仕組み上キーワード検索程遅くはないが)。また、CGIによって動的生成されるページへのリンクには nofollowを付けたいところ。でないとGooglebotが (に限らずロボットが) mt-searchを叩くのだ。MTインストール済みレンタルサーバーとかで、ロボットが多くのmt-search を叩いている状況ってのは何だか恐い。ただでさえスパマーがtrackbackやcommentのCGIを叩きまくっているのだし。

モジュール版PHPで動作しているサーバーの場合、CGI(Not FastCGI)の起動よりも早くレスポンスを返せるからこの(PHP)ダイナミック版タグ検索は一つの選択肢になると思う。但し、MTのダイナミックパブリッシングではパラメータ付きのページをキャッシュしてくれない。ここが何とかなるといんだけど。もう少しダイナミック版のソースを追いかけてみよう。

さすがにキーワード検索は動的生成じゃないと、ってかそれでいいと思うし

話がそれた。一方「検索」は発信者ではなく読者が自由に設定するものだ。一部の読者は発信者の意図しないカテゴリの情報を求めているかもしれない。なので基本的に動的生成で良い。問題はMTのデフォルトテンプレートで「検索結果」フィードへのリンクが表示される点だ。確かに検索結果のフィードがとれるってのは便利かと思う。

それでもやっぱり読者がRSSリーダーに mt-search が生成する動的ページのフィードを登録するってのもやっぱり勇気がいるなぁ (サーバーへの負担という点で)。パワーに余裕の無いサーバーではRSSリーダーが取得に失敗するってことも多いのではないだろうか。

ということで、高速・軽量な検索ってのは単なる検索ではなくて、タグ・アーカイブや検索結果のフィード配信の代替プログラムでもあり、カテゴリ+タグでの絞り込みとか、カテゴリ+キーワードの絞り込みとかを実現するためのものなのです。 キーワードはともかく、このあたりを柔軟に指定できて且つ静的に吐き出すことができれば、関連性, 体系付けの選択肢も広がるのではないかな?

分かち書き+MySQL FULLTEXTインデックス検索 VS LIKE検索

両方とも実装してみたのだが、400エントリー弱(実際にはテスト用ブログ等でDBにはその倍くらいが登録されている)のこのブログで、現状のサーバーでは2倍程度の差が出ている。とはいえ20件表示であれば0.08秒前後と0.16秒前後、体感速度に大して差はない。

フィードの生成はもっと高速。各々約半分くらいの時間で検索と構築が終わる。これは検索結果ページではトータルヒット件数を取得してページ送りを実現するためにSQLを2回発行しているからだ(まず全てのヒット件数をカウントしてからoffset, limitを指定して表示すべきエントリーを得ている)。フィードではページ送りが不要だからこの分のSQLが不要。

FULLTEXTインデックス検索には速度以外にもメリットがあって、関連性の高い順に表示することができることだ。また、インデックス作成の際に画像のALTを展開した上でHTMLタグを削除しているから、「タグの中」がひっかからない。
LIKE検索ではたとえば「HTML」について書かれたエントリーを検索したい場合に、アンカータグの中の foo.html とかにもマッチしてしまう。

逆にこれを逆手に取れば、特定のエントリーにリンクしているエントリーの検索とかにはLIKE検索使えるね。例えば、「音声ブラウザと相性の良いHTMLを作る(1)。」にリンクしているエントリーはページのパスをクエリーとして指定してやれば良いわけだ。

ということでね、色々活用法が考えられて 夢がひろがりんぐ でしょ?

ウチの会社で作成したサイトは全部MTで作ってんじゃねぇの? と思われているかもしれませんが、もちろんそんなこたぁありません。

但し昔っからCMS的なサイトの制作を行っていて、「よくこんな小世帯でこんだけのボリュームのサイト作ってんね!?」と言われる答えの一つは「自動化」なわけです。徹夜でガシガシHTMLコーディングってのがWeb屋のイメージなのかもしれませんが、ウチは徹夜はしません。

面接の際に意外によく聞かれるんですけど「徹夜はありますか?」って、世間のWeb屋はどんなんやねん、って思いますよ。

あ、一応答えは「年2回」って答えてます。実際は2回ないけどね。まぁ1回あるかないか。ただ、徹夜になるってことは誰かが何かミスした時しかあり得ないですが、まぁ人間だもの、ミスもあるさっ。

のっけから話それまくりですが、来月こんなイベントがあるそうなのでちょっと前フリというか、ウチでよくやる方法についてちょっと晒してみる(わりと普通なのかなぁ)。

まぁ実際はMTのAPIでもって詳細なカテゴリの関連づけとかブログの切り分けとかテンプレートのインポートとか色々やるわけですが、MT4でエクスポート/インポート形式がちょっとだけ進化したので(ファイル名なんかを引き継げるようになった)、Excelで作成したデータをもとにMTのエクスポート形式のファイルを生成して読み込むって方法が簡単なので紹介したい(もちろん、MT4のバックアップのフォーマットのXMLを気合いを入れて作るって方法もあるよ)。

まず、ExcelとかOpenOfficeとか何でもいいけれどスプレッドシートを作成できるソフトウェアでマスターデータを作る。構造は何でもいいけど、この例ではページのタイトル, カテゴリ, ファイル名, テキスト, 追記なんかを各セルに入力。

Excelでマスタデータを作る

保存形式を「テキスト(タブ区切り)」にして保存。

スクリプトはこんな感じ


#!/usr/bin/perl -w

$fp = $ARGV[0];

open(FH, $fp);
while(<FH>){
    my $line = $_;
    my @datas = split(/¥t/, $line);
    my $html = &_read_tmpl($datas[0], $datas[1], $datas[2], $datas[3], $datas[3]);
    print $html;
}
close(FH);

sub _read_tmpl {
    my ($title, $cat, $basename, $excerpt, $text, $text_more) = @_;
return <<"MT_TMPL_HTML";

--------
AUTHOR: junnama
TITLE: $title
BASENAME: $basename
STATUS: Publish
ALLOW COMMENTS: 1
CONVERT BREAKS: __default__
ALLOW PINGS: 0
PRIMARY CATEGORY: $cat
CATEGORY: $cat
DATE: 08/30/2007 00:00:00 PM
-----
BODY:
$text
-----
EXTENDED BODY:
$text_more
-----
EXCERPT:

-----
KEYWORDS:

-----

MT_TMPL_HTML
}

Macだったらターミナルから引数にマスタ、出力をファイルに指定して実行。WindowsだとActivePerlを入れておく必要があるけど。


perl ./tsv2mt.pl master.tsv > mt_html.txt

生成されたテキストをMTからインポートすればOK。ね、簡単でしょ? コツ、という程じゃないけど、カテゴリは英数文字で指定しておくとカテゴリーのbasenameがこれになってくれる(インポートした後にカテゴリー名とbasenameの関連づけを行う必要があるのだけど、これこそMTのAPIを使えばチョチョイと作れる)。

つまり、ここで書いたことのひとつの具体的な事例ね。

ということで、このエントリーをよく読んでから、以下のエントリーを読むと幸せになれるかも(笑)。

Nakedがじわじわ?来てるので改めて紹介。というか何をやっているかが分かりやすいようにサンプルページを作ってみた(CSSと画像をオフにする以外特別なことをするのかな? とかいう反応もあったことだし)。オリジナル変換後を具体的にHPRとかに読ませてみて欲しい(誰か音声ファイルとか作ってくれないかな?)。読み上げ向けと他のモードの違いとかも是非試してみてください。単に画像切ってるだけじゃないので。

じわじわ...

サンプルページ

実は、このプログラムを書いた僕自身は本職のプログラマではないしどっちかと言えばマークアップとかアートディレクションとかが本来の立ち位置である人間なのでして、このエントリーに書いた(5は別にして)「正規表現」とか「Perl」とかを覚えるとこんなものが作れるのです。

でも、むしろこれを作るのに必要な知識ってのは、Perlや正規表現よりも「どんなHTMLが読み上げにくくて、音声ブラウザユーザーやスクリーンリーダー利用者はどんなところに困るのか」という部分の知識です。で、この知識に強い人たちこそウェブアクセシビリティとかに配慮してHTMLを正しく書こうと思っている人とかウェブ標準とか大切と思っている「マークアップエンジニア」の人たちなのではないかなぁ。プログラムなんて実現のための手段でしかないし。

Nakedのコンセプトというか何をやっているかは以下のエントリーに殆ど書いてます。イケてないところも沢山あると思うけれど、「ここがイケてない」と思うそこのあなた! 有用なアイデアや確かにイケてないところがあったらまだまだ改良して行こうと思うのでひとつ宜しく。

* 一応言い訳しておきますが、このブログは駄目です。汚いし、突っ込まれるところ沢山あるのでそこはまぁ大目に見ていただけると幸い。

関連エントリー

ちなみに、ウチの会社でリニューアルなんかの仕事を受けた時には、まずこんな感じで既存のコンテンツをてきるだけらくちんな方法でクリーンアップして再利用できないか考えます。あとはうまくMTに放り込む方法を探ります。

と、まぁこんなことやってる制作会社やってます。だから、ね、ヲチはこちらね。宜しく。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちプログラミングカテゴリに属しているものが含まれています。

前のカテゴリはアクセシビリティです。

次のカテゴリはモブログです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。