ホームページ制作/SEO対策なら株式会社サイバーブレーンへ

 03-5961-5681 平日10:00~19:00

 2018-02-02

mb_substrが遅い

メールの送信処理で30秒以上戻らない

WEBサイトでフォームからのHTMLメールの送信でmax_execution_timeでデフォルトセットされている30秒を超えたため処理が中断される。
中断箇所は自作関数のquoted_printable_encode のループ内である。
PHPのバージョンが5.2なので、quoted_printable_encodeが存在しない為作成した関数。この関数内で中断される。
いったい?原因は?

mb_substrが犯人だった!

故あって関数内でどうしてもマルチバイト文字かシングルバイトかで処理を分けなければならなかった為、mb_substrを使って1文字ずつ取り出していた。
原因がわかったのでmb_substrを使わずにsubstrで処理するように変更して解決したが、本当にmb_substrの問題なのか明確にしたかったので、UTF-8に文字コードを限定して確認してみることに。

処理時間を確認するためのソースコード

<?php
mb_internal_encoding('UTF-8');

$aiueo = 'あ	い	う	え	お
a	i	u	e	o
か	き	く	け	こ
ka	ki	ku	ke	ko
さ	し	す	せ	そ
sa	shi	su	se	so
た	ち	つ	て	と
ta	chi	tsu	te	to
な	に	ぬ	ね	の
na	ni	nu	ne	no
は	ひ	ふ	へ	ほ
ha	hi	fu	he	ho
ま	み	む	め	も
ma	mi	mu	me	mo
や	 	ゆ	 	よ
ya	 	yu	 	yo
ら	り	る	れ	ろ
ra	ri	ru	re	ro
わ	 	を	 	ん
wa	 	o	 	n';

$str = '';
$loop = 1000;
while ($loop) {
    $str .= $aiueo;
    $loop--;
}
echo 'length: ' . strlen($str) . "\n";


$start_time = microtime(true);
$jp_str = utf8stringMB($str);
$run_time = microtime(true) - $start_time;

echo 'mb_substr: ' . $run_time . "\n";


$start_time = microtime(true);
$jp_str = utf8string($str);
$run_time = microtime(true) - $start_time;

echo 'substr: ' . $run_time . "\n";

/*
 * mb_substrを利用してマルチバイト文字だけを取り出す関数
 */
function utf8stringMB($str)
{
    $len = mb_strlen($str, 'UTF-8');
    $mbstr = '';
    for ($i = 0; $i < $len; $i++) {
        $char = mb_substr($str, $i, 1, 'UTF-8');
        $byte = strlen($char);
        if ($byte > 1) {//マルチバイト文字の取り出し
            $mbstr .= $char;
        }
    }
    return $mbstr;
}

/*
 * substrを利用してマルチバイト文字の判定をしながらマルチバイト文字だけを取り出す関数
 */
function utf8string($str)
{
    $len = strlen($str);
    $mbstr = '';
    for ($i = 0; $i < $len; $i++) {
        $char = substr($str, $i, 1);
        $ascii = ord($char);
        $byte = 1;
        if ($ascii >= 0xC2 && $ascii <= 0xDF) {
            $byte = 2;
        } else if ($ascii >= 0xE0 && $ascii <= 0xEF) {
            $byte = 3;
        } else if ($ascii >= 0xF0 && $ascii<=0xF4) {
            $byte = 4;
        }
        if ($byte > 1) {//マルチバイト文字の取り出し
            $mbstr .= substr($str, $i, $byte);
            $i += ($byte - 1);
        }
    }
    return $mbstr;
}

ターミナルで実行した結果は、こんな感じです。
mb_substrを利用している方がシンプルで見やすいのに残念。
何度か試しましたが、333k程度のデータで
mb_substrを使ったutf8stringMB関数で80秒〜100秒
substrで文字コードを判定しながら進めた場合は、0.02秒〜0.09秒
実行環境によって速度は変わると思いますが、圧倒的な差です。

[xxx@local]$ php -f Utf8TestChar.php
length: 333000
mb_substr: 102.03357696533
substr: 0.032789945602417
[xxx@local]$

~この記事の著者~

サイト制作に関するご相談はこちら

 03-5961-5681 平日10:00~19:00

メールフォーム

あなたが
サイトに
求める要素
あなたがサイトに求める0要素