アルファサード株式会社 代表取締役 野田 純生のブログ


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


公開日 : 2014-06-13 10:51:11


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フォルダとは別のフォルダにおいておくと良いです。

'; $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( '?>' . $varcompiled ); $contents = obgetcontents(); obendclean(); 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 );
    }
}
// ...

シリーズコンテンツ一覧



このブログを書いている人
野田純生の写真
野田 純生 (のだ すみお)

大阪府出身。ウェブアクセシビリティエバンジェリスト。 アルファサード株式会社の創業者であり、現役のプログラマ。経営理念は「テクノロジーによって顧客とパートナーに寄り添い、ウェブを良くする」。 プロフィール詳細へ