PHPerのためのMovable Type講座(その16)

| コメント(0) | トラックバック(0)

Speed is everything! 軽量なDynamicMTMLを動かす編。

PHPerのためのMovable Type講座

DynamicMTMLは、元来はhtmlファイル内のMTタグを動的処理するために作られました。平たく言えば、静的生成されたページの一部をMTタグで動的に処理するためのものです。但し、DynamicMTMLはこれにとどまらず、タスクやワーカーを処理したり、config.php形式でプラグインを完結に(まとめて)書けたりといった様々な機能を持っています。

今回は、そのあたりの機能は必要とせず、とにかく軽量、速く処理したいということで、ファイル中のMTタグのみを実行するだけ、しかも不要なプラグインは初期化そのものをスキップしてしまうことで、とにかく高速に動かすことを目的とした.mtview.phpを紹介します。

以下のソースをインデックステンプレートにします。

方針:必要なプラグインのみ初期化する。ブログや記事の情報が不要なら、$blog_idをNULLとして、クエリを一回でも省略する。

前提:必要なphpプラグインを一カ所(以下の例ではCustomHandlers/php)以下に纏めてしまう(もしくは配列で必要なプラグインを複数指定する)。通常の処理の際にファイルの重複があるとエラーになってしまうので、plugins以下ではない場所に設置するか、plugins/CustomHandlers/phplib など、phpフォルダとは別のフォルダにおいておくと良いです。

<?php
$base = '<$MTCGIServerPath encode_php="q"$>';
$plugins = array( 'CustomHandlers/php' );
$blog_id = NULL;
$directry_index = 'index.html';
$tmpl = $_SERVER[ 'DOCUMENT_ROOT' ] . $_SERVER[ 'REQUEST_URI' ];
if ( strpos( $tmpl, '?' ) != FALSE ) {
    $split_path = explode( '?', $tmpl );
    $tmpl = $split_path[ 0 ];
}
$tmpl = urldecode( $tmpl );
if ( is_dir( $tmpl ) ) {
    $tmpl .= $directry_index;
}
$tmpl = str_replace( '../', '', $tmpl );
if ( file_exists( $tmpl ) ) {
    $php_dir = $base . DIRECTORY_SEPARATOR . 'php' . DIRECTORY_SEPARATOR;
    $mt_cfg = $base . DIRECTORY_SEPARATOR . 'mt-config.cgi';
    $php_lib = $php_dir . 'mt.php';
    include( $php_lib );
    $mt = MT::get_instance( $blog_id, $mt_cfg );
    $ctx =& $mt->context();
    if ( $blog_id ) {
        $blog = $mt->db()->fetch_blog( $blog_id );
        $ctx->stash( 'blog', $blog );
        $ctx->stash( 'blog_id', $blog->id );
        $ctx->stash( 'local_blog_id', $blog->id );
    }
    require_once( $php_dir . 'lib' .  DIRECTORY_SEPARATOR . 'MTUtil.php' );
    $include_paths = ini_get( 'include_path' );
    if ( strtoupper( substr( PHP_OS, 0, 3 ) == 'WIN' ) ) {
        $path_sep = ';';
    } else {
        $path_sep = ':';
    }
    // $mt->init_plugins();
    foreach ( $plugins as $plugin ) {
        $require_plugin = $base . DIRECTORY_SEPARATOR . $plugin;
        $include_paths .= $path_sep . $require_plugin;
        ini_set( 'include_path', $include_paths );
        $mt->load_plugin( $require_plugin );
        $ctx->add_plugin_dir( $require_plugin );
    }
    $_var_compiled = '';
    $ctx->_compile_source( 'evaluated template', file_get_contents( $tmpl ), $_var_compiled );
    ob_start();
    $ctx->_eval( '?>' . $_var_compiled );
    $_contents = ob_get_contents();
    ob_end_clean();
    echo $_contents;
    exit();
}

ファイルが存在しない時に通常のダイナミックパブリッシングに処理を渡す場合は、以下の処理を末尾に追加する。ダイナミックパブリッシングの場合は $blog_id は NULLでは駄目で、ブログのIDを指定する必要があります。

$php_dir = $base . DIRECTORY_SEPARATOR . 'php' . DIRECTORY_SEPARATOR;
$mt_cfg = $base . DIRECTORY_SEPARATOR . 'mt-config.cgi';
$php_lib = $php_dir . 'mt.php';
include( $php_lib );
$mt = MT::get_instance( $blog_id, $mt_cfg );
$mt->view();

カスタムフィールドの初期化を高速化する

カスタムフィールドが2000個くらいあって、でもDynamicで使っているのは一つか二つ、みたいなとき、データベースで2000フィールド取得して初期化回すわけです。明らかに無駄なんですけど。特にフロントサーバーとDBサーバーが別な環境なんかでは、この処理はバカにならない。

上記の処理では、カスタムフィールドの初期化はスキップされますが、当然利用しているカスタムフィールドが使えない。そこで、CustomHandlers/php 以下に2つのファイルをコピーします。

  • addons/Commercial.pack/php/class.mt_field.php
  • addons/Commercial.pack/php/init.CustomFields.php

init.CustomFields.phpの先頭部分をカスタマイズ

.mtview.phpの中で、利用するカスタムフィールドのベースネームを指定するか、mt-config.cgiにDynamicCustomFieldBasenames を指定して、ベースネームをカンマで区切っておきます。

global $load_custom_fields;
$load_custom_fields = array( 'cf_basename1',  'cf_basename2' );

また、カスタムフィールドをキャッシュしておきたい時、mt-config.cgiに以下をあわせて指定します。

DynamicCustomFieldCaching 1

こうすることで、カスタムフィールドオブジェクトをファイルキャッシュして、クエリを省略できるようになります。init.CustomFields.phpの先頭部分を以下のように修正します(MTのコードに手を入れることになるので、あくまでも参考例。MTにその辺りの仕組みが入ることを望むなり。Memcacheにキャッシュするとか、ね)。

<?php
$mt = MT::get_instance();
$ctx = &$mt->context();
define('CUSTOMFIELDS_ENABLED', 1);

global $customfield_types;
$customfield_types or $customfield_types = array();
init_core_customfield_types();

global $customfields_custom_handlers;
$customfields_custom_handlers = array();
$dynamic_functions = '';
require_once('class.baseobject.php');
require_once('class.mt_field.php');

$fields;
$in_operator;
global $load_custom_fields;
if (! is_array( $load_custom_fields ) ) {
    if ( $_field = $mt->config( 'DynamicCustomFieldBasenames' ) ) {
        $load_custom_fields = explode( ',', $_field );
    }
}
if ( is_array( $load_custom_fields ) ) {
    $in_operator = '(';
    foreach ( $load_custom_fields as $basename ) {
        $basename = $mt->db()->escape( $basename );
        $in_operator .= "'$basename',";
    }
    $in_operator = rtrim( $in_operator, ',' );
    $in_operator .= ')';
}
if ( $cached_customfields = $mt->config( 'DynamicCustomFieldCaching' ) ) {
    $cf_file = $mt->config( 'TempDir' ) . DIRECTORY_SEPARATOR . 'customfields-' . md5( $mt->cfg_file );
}
if ( $cf_file && file_exists( $cf_file ) ) {
    $frozen = file_get_contents( $cf_file );
    $fields = unserialize( $frozen );
} else {
    $fld = new Field();
    if ( $in_operator ) {
        $fields = $fld->Find("field_basename IN ${in_operator}");
    } else {
        $fields = $fld->Find('1 = 1');
    }
    if ( $cf_file ) {
        $frozen = serialize( $fields );
        file_put_contents( $cf_file, $frozen );
    }
}
// ...

シリーズコンテンツ一覧

トラックバック(0)

トラックバックURL: http://junnama.alfasado.net/cgi/mt/mt-tb.cgi/846

コメントする

Facebook

Twitter

このブログ記事について

このページは、Junnama Nodaが2014年6月13日 10:51に書いたブログ記事です。

ひとつ前のブログ記事は「広島に来ているので、地方のWeb制作ビジネスについて考えてみた。」です。

次のブログ記事は「Hack-A-ThonでMT Image Managerを作った。」です。

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

Powered by Movable Type 6.2.6