Helperの日本語対応

Symfonyで実際に開発を始めてみると時折、文字化けなど予期せぬことが発生しました。

原因を調べてみると文字列を扱うHelperにあるようです。それもそのはず、日本語はマルチバイト文字なので通常のString関数を使用していれば不具合が起こる可能性はあります。 ということで文字列を扱う関数をマルチバイトに対応する関数に置き換えたHelperが必要だと思いました。

今回はその対処について幾つか上げて行きます。

EscapingHelper

EscapingHelper.phpに関しては以前も取り上げています。

 function esc_entities($value)
 {
   return htmlentities($value, ENT_QUOTES);
 }

第3引数であるcharsetの指定がないため文字が化けます。
※このバグに関しては次期バージョン0.6.3では修正済みのはずです。

アルファベッドを使うことに関しては問題ないのですが日本語のようなマルチバイトの文字を扱う場合には文字化けなどを引き起こすことがあります。

TextHelper.php

TextHelperに関しても問題があり、日本語のマルチバイトの文字列を引数にすると文字化けが発生します。

truncate_textを例にとってみます。

function truncate_text($text, $length = 30, $truncate_string = '...', $truncate_lastspace = false)
{
  if ($text == '') return '';
  if (strlen($text) > $length)
  {
    $truncate_text = substr($text, 0, $length - strlen($truncate_string));
    if($truncate_lastspace)
    {
      $truncate_text = preg_replace('/\s+?(\S+)?$/', '', $truncate_text);
    } 
 
    return $truncate_text.$truncate_string;
  }
  else
  {
    return $text;
  }
}

文字列の分割にsubstrを使用しています。マルチバイトの文字の場合中途半端な位置で分割される可能性があります。 置き換えに関してもpreg_replaceが使われています。

日本語の対策として内部で使用されている関数をマルチバイト対応の関数に置き換えたMbTextHelper.phpを作成しました。 使い方に関してはTextHelperを参考にして頂ければと思います。

<?php
/**
 * MbTextHelper.
 *
 * @package    symfony
 * @subpackage helper
 */
 
/*
    TextHelper::truncate_textのマルチバイト対応
*/
function mb_truncate_text($text, $length = 30, $truncate_string = '...', $truncate_lastspace = false)
{
  mb_internal_encoding("UTF-8");
 
  if ($text == '') return '';
  if (mb_strlen($text) > $length)
  {
    $truncate_text = mb_substr($text, 0, $length - strlen($truncate_string));
    if($truncate_lastspace)
    {
      $truncate_text = mb_preg_replace('/\s+?(\S+)?$/', '', $truncate_text);
    } 
 
    return $truncate_text.$truncate_string;
  }
  else
  {
    return $text;
  }
}
 
/*
    TextHelper::highlight_textのマルチバイト対応
*/
function mb_highlight_text($text, $phrase, $highlighter = '<strong class="highlight">\\1</strong>')
{
  mb_internal_encoding("UTF-8");
 
  if ($text == '')
  {
    return '';
  }
  else if ($phrase != '')
  {
    return mb_preg_replace('/('.preg_quote($phrase).')/i', $highlighter, $text);
  }
  else
  {
    return $text;
  }
}
 
/*
    TextHelper::excerpt_textのマルチバイト対応
*/
function mb_excerpt_text($text, $phrase, $radius = 100, $excerpt_string = '...')
{
  mb_internal_encoding("UTF-8");
 
  if ($text == '')
  {
    return '';
  }
  else if ($phrase != '')
  {
    $phrase = preg_quote($phrase);
 
    $found_pos = strpos(strtolower($text), strtolower($phrase));
    if ($found_pos !== false)
    {
      $start_pos = max($found_pos - $radius, 0);
      $end_pos = min($found_pos + mb_strlen($phrase) + $radius, mb_strlen($text));
 
      $prefix = ($start_pos > 0) ? $excerpt_string : '';
      $postfix = $end_pos < mb_strlen($text) ? $excerpt_string : '';
 
      return $prefix.mb_substr($text, $start_pos, $end_pos - $start_pos).$postfix;
    }
  }
  else
  {
    return '';
  }
}
 
/*
    TextHelper::auto_link_textのマルチバイト対応
*/
function mb_auto_link_text($text, $link = 'all')
{
  if ($link == 'all')
  {
    return _auto_link_urls(_auto_link_email_addresses($text));
  }
  else if ($link == 'email_addresses')
  {
    return _mb_auto_link_email_addresses($text);
  }
  else if ($link == 'urls')
  {
    return _auto_link_urls($text);
  }
}
 
/*
      # Turns all urls into clickable links.
*/
function _auto_link_urls($text)
{
  return preg_replace_callback(
    '/(<\w+.*?>|[^=!:\'"\/]|^)((?:http[s]?:\/\/)|(?:www\.))([^\s<]+\/?)([[:punct:]]|\s|<|$)/',
    create_function('$matches', '
      if (preg_match("/<a\s/i", $matches[1]))
      {
        return $matches[0];
      }
      else
      {
        return $matches[1].\'<a href="\'.($matches[2] == "www." ? "http://www." : $matches[2]).$matches[3].\'">\'.$matches[2].$matches[3].\'</a>\'.$matches[4];
      }
    ')
  , $text);
}
 
/*
      # Turns all email addresses into clickable links.
*/
function _mb_auto_link_email_addresses($text)
{
  return mb_preg_replace('/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/', '<a href="mailto:\\1">\\1</a>', $text);
}
 
/*
    TextHelper::strip_links_textのマルチバイト対応
*/
function mb_strip_links_text($text)
{
  mb_internal_encoding("UTF-8");
  return mb_preg_replace('/<a.*>(.*)<\/a>/m', '\\1', $text);
}
 
?>

One Response to “Helperの日本語対応”

1
takuya_1st - 09/02/07

mb_internal_encoding やpreg_mactch はphp.iniのmb_string 関連をちゃんと設定すればいけるのでは?

Leave a Reply

Name (required)
Mail (will not be published) (required)

Your Comments:

Spam Protection by WP-SpamFree