トップページに戻る

Piwik 日本語(マルチバイト)パッチ(2.6.0 ~ 2.16.2)

Piwik はなるべく新しいバージョンを使ってください。 今までずっと引き継いできた問題でも発見したバージョン以降で修正しています。遡っての修正はしていません。 例えば Piwik >= 2.14.3 で解決できる問題があります。

ダウンロード

Piwik 2.16.2

piwik-japan-2.16.2.patch

Piwik 2.15.0

piwik-japan-2.15.0.patch

Piwik 2.14.3 (恐らく 2.14.x 全て OK です)

piwik-japan-2.14.3_3.patch

Piwik 2.14.1

piwik-japan-2.14.1.patch

Piwik 2.12.1

piwik-japan-2.12.1.patch

Piwik 2.11.2

piwik-japan-2.11.2.patch

Piwik 2.11.1

piwik-japan-2.11.1.patch

Piwik 2.10.0

piwik-japan-2.10.0.patch

Piwik 2.9.0 - 2.9.1

piwik-japan-2.9.0-2.9.1.patch

Piwik 2.8.1 - 2.8.3

piwik-japan-2.8.1-2.8.3.patch

Piwik 2.6.0 - 2.8.0

piwik-japan.2.6.1-2.8.0.patch

このパッチで Piwik の次の日本語(マルチバイト)問題を解決します

  1. 検索エンジンからの着地時のキーワード検出でキーワードの文字コードが Shift_JIS あるいは EUC-JP である場合、文字化けする。
  2. 自サイトの検索(Piwik の表記では"サイト内検索")キーワードの抽出で、キーワードの文字コードが Shift_JIS あるいは EUC-JP である場合、文字化けする。
  3. 上記キーワードが、255 バイトを超えるときは、256 バイト以上が切り捨てられる。256 バイト目がマルチバイト文字コード途中であれば、キーワードの最後が文字化けする(Piwik 2.16.0 で本家にマージ)。

文字化けは UTF-8 のカラムで、UTF-8 ではない文字列を INSERT することにより起こりますが、MySQL のデフォルトの仕様でカラムに入るように自動変換され、文字化けはするもののエラーは起きません。

しかし、my.cnf の設定で

[mysql]
sql_mode = "STRICT_ALL_TABLES"

または

[mysql]
sql_mode = "TRADITIONAL"

として自動変換をお断りするすると、General error: 1366 で MySQL がクラッシュします。Tracker で追跡しているときは、一アクセスだけ犠牲になりますが import_logs.py でログを取り込んでいるときは処理が止まるので、--skip を指定して、問題の起きているログを飛ばして再取り込みを行う必要があります。

パッチの当て方

Piwik 2.16.2

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.16.2.patch を置きます。
  3. patch -p1 < piwik-japan-2.16.2.patch

Piwik 2.15.0

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.15.0.patch を置きます。
  3. patch -p1 < piwik-japan-2.15.0.patch

Piwik 2.14.3

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.14.3_3.patch を置きます。
  3. patch -p1 < piwik-japan-2.14.3_3.patch

Piwik 2.14.1

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.14.1.patch を置きます。
  3. patch -p1 < piwik-japan-2.14.1.patch

Piwik 2.11.2

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.12.1.patch を置きます。
  3. patch -p1 < piwik-japan-2.12.1.patch

Piwik 2.11.2

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.11.2.patch を置きます。
  3. patch -p1 < piwik-japan-2.11.2.patch

Piwik 2.10.0

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.10.0.patch を置きます。
  3. patch -p1 < piwik-japan-2.10.0.patch

Piwik 2.11.1

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.11.1.patch を置きます。
  3. patch -p1 < piwik-japan-2.11.1.patch

Piwik 2.9.0 - 2.9.1

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.9.0-2.9.1.patch を置きます。
  3. patch -p1 < piwik-japan-2.9.0-2.9.1.patch

Piwik 2.8.1 - 2.8.3

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan-2.8.1-2.8.3.patch を置きます。
  3. patch -p1 < piwik-japan-2.8.1-2.8.3.patch

Piwik 2.6.0 - 2.8.0

  1. cd "piwik をインストールしたディレクトリ"
  2. piwik-japan.2.6.1-2.8.0.patch を置きます。
  3. patch -p1 < piwik-japan.2.6.1-2.8.0.patch

増える機能

  1. (Piwik <= 2.15.0)piwik/core/DataFiles/SearchEngines.php に default 検索エンジンを追加します。(Piwik >= 2.16.2) piwik/vendor/piwik/searchengine-and-social-list/SearchEngines.yml の search.yahoo.co.jp に文字コードを追加し default 検索エンジンとして使用。
  2. default 検索エンジンの設定は外からの検索エンジン(SearchEngines.php または SearchEngines.yml で定義される検索エンジンに文字コード指定がされていない)または、サイト内検索キーワードの文字コードの特定に使われます。
  3. (Piwik <= 2.15.0)default 検索エンジンの定義がないときは、UTF-8、EUC-JP、MS932 の順で文字コードを特定しようとします。特定失敗時は UTF-8 として取り扱います。(Piwik >= 2.16.2)search.yahoo.co.jp 検索エンジン文字コードの指定に従います。定義が存在しない場合 UTF-8、文字コード特定敗時は一番目に定義した文字コード、つまり UTF-8、として解釈します。
  4. google カスタムサーチで検索キーワードが取れるケースがあるので追加しています(Piwik >= 2.16.2 キーワードはとれなくなったので加えていません)。

詳細

(Piwik <= 2.15.0)検索エンジンからの着地時のキーワード検出でキーワードの文字コードが Shift_JIS あるいは EUC-JP である場合、文字化けする。

まず検索エンジンの定義ですが、
piwik/core/DataFiles/SearchEngines.php (もしくは piwik をインストールしたディレクトリ/core/DataFiles/SearchEngines.php 、以下同じ)にあります。ここの array 第 4 引数でキーワードの文字コードが複数指定できるよう考慮されており、UTF-8 以外では各国文字コードを指定しなければならないのですが、日本語検索エンジンで文字コードの指定があるのは

        'www.excite.co.jp'               => array('Excite', 'search', 'search.gw?search={k}', 'SHIFT_JIS'),

だけで(しかもこの設定だと UTF-8、EUC-JP の検索キーワードは文字化けとなります。指定文字コードが mb_detect_encoding で検出できない場合、キーワードは最初に指定する文字コード -- つまり上の例では SHIFT_JIS -- とみなされるからです)、そのほか肝心の yahoo などには設定がありません。

キーワード抽出は piwik/core/UrlHelper.php 中の extractSearchEngineInformationFromUrl で行っているのですが、文字コードの指定がないと、何も処理しません。この場合、MySQL の検索キーワード格納カラムが UTF-8 なので、結果的に UTF-8 として扱われます。

対策

  1. SearchEngines.php にある日本語と思える検索エンジンに UTF-8、EUC-JP あるいは MS932 の文字コードであることを加えます。
  2. SearchEngines.php に default 検索エンジンを追加し、SearchEngines.php 検索エンジン定義に文字コードの指定がないときは、default で指定する文字コードとします。
  3. default 検索エンジンの設定を忘れたときは UTF-8、EUC-JP、MS932 の順に文字コード検出を試みます。

参考 SearchEngines.php について:
検索エンジンは、ウェブサイトのリファラーとしてカウントされます。 Piwik に検索エンジンを追加する方法は?
A search engine is counted as a website referer. How can I add the search engine to Piwik?

(Piwik >= 2.16.2)検索エンジンからの着地時のキーワード検出でキーワードの文字コードが Shift_JIS あるいは EUC-JP である場合、文字化けする。

まず検索エンジンの定義ですが、従来と違い
piwik/vendor/piwik/searchengine-and-social-list/SearchEngines.yml で yml ファイル管理に大きく変更されています。文字コードは、yml ファイルの charsets 以下で複数定義可能で、並び順に文字コードを推測しますが、Piwik 2.16.2 では、Shift_JIS と EUC-JP も受け付ける検索エンジンにおいても何も定義がされていないので  piwik-japan-2.16.2.patch で charsets を追加しています(Piwik > 2.16.2 で本家にマージされることが決まっています)。 以下は search.yahoo.co.jp の例です。また日本以外の例えばロシアの検索エンジンなどは、 charsets を追加していませんが、文字コードの指定がない場合は search.yahoo.co.jp の定義で、検索文字コードを推測します。判定できなければ最初に定義されている UTF-8 を採用します。

Yahoo! Japan:
  -
    urls:
      - search.yahoo.co.jp
    params:
      - p
      - vp
    backlink: 'search?p={k}'
    charsets:
      - utf-8
      - euc-jp
      - ms932

キーワード抽出は piwik/plugins/Referrers/SearchEngine.php 中の extractInformationFromUrl で行っているのですが、文字コードの指定がないと、何も処理しません。この場合、MySQL の検索キーワード格納カラムが UTF-8 なので、結果的に UTF-8 として扱われます。

対策

  1. SearchEngines.yml にある日本語と思える検索エンジンに UTF-8、EUC-JP あるいは MS932 の文字コードであることを加えます。
  2. SearchEngines.yml 検索エンジン定義に文字コードの指定がないときは search.yahoo.co.jp で指定する文字コードとします。

(Piwik <= 2.15.0)自サイトの検索(Piwik の表記では"サイト内検索")キーワードの抽出で、キーワードの文字コードが Shift_JIS あるいは EUC-JP である場合、文字化けする(2.10.0 以降は空白文字列)。

サイト内検索設定は、システムの構成→ウェブサイト→Tracking Internal Site Search です。さらに各サイトごとに、 "サイト内検索" の項目で設定できます。これで自サイトの検索エンジンの検索キーワードを抽出でき、 "サイト検索ウィジット" で結果を見ることができます。

しかしながら、サイト内検索は、 SearchEngines.php のように文字コードの指定がなく、MySQL のサイト内検索キーワード格納カラムが UTF-8 なので、結果的に UTF-8 として扱われます。 最近は UTF-8 でサイト作るので問題ないのねと思われるかもしれませんが、CMS によっては裏でスマホページを UTF-8 出力、携帯ページを Shift_JIS 出力なんてこともできるので、そうとも限りません。

2.10.0 以降

2.10.0 でさすがに、自サイトの検索で UTF-8 以外の文字列がきた場合に上記の TRADITIONAL 時にデータベースエラー回避の手段が何もないのはまずいとと思ったのか、自サイト検索 文字列全体 が UTF-8 か否かを判定し、UTF-8 以外だと空白文字列にしてしまうというなんともやっつけな変更が加えられています。iconv で ignore 設定をかけて、なるべく拾ってみるという丁寧さもございません。

このような仕様は 邪魔なだけ です。 piwik-japan-2.10.0.patch 以降では以前と同様、 UTF-8、EUC-JP、MS932 の順(ただし、指定がないとき)で文字コードを特定させます。

対策

  1. piwik/core/DataFiles/SearchEngines.php に default 検索エンジンを追加し、サイト内検索はここで指定する文字コードとします。
  2. default 検索エンジンの設定を忘れたときは UTF-8、EUC-JP、MS932 の順に文字コード検出を試みます。

(Piwik >= 2.16.2)自サイトの検索(Piwik の表記では"サイト内検索")キーワードの抽出で、キーワードの文字コードが Shift_JIS あるいは EUC-JP である場合空白文字列)。

サイト内検索は、 SearchEngines.php のように文字コードの指定がなく、Controller::sanitizeString で UTF-8 でハードコーディングされています。 外部検索とは違い柔軟性はありません。

関数は次の順序でよばれます: ActionSiteSearch::shouldHandle $request->getParam('url') -> detectSiteSearch -> detectSiteSearchFromUrl

また、$request->getParam('url') は次の順序でよばれます: Controller::getParam -> Common::getRequestVar -> sanitizeInputValues -> sanitizeString

対策

  1. Controller::sanitizeString に search.yahoo.co.jp の charsets 順にに文字コードの推測をすします。判定できなければ search.yahoo.co.jp で最初に定義されている UTF-8 を採用します。

sanitizeString にはこのようなコメントがあるが、urldecode されてない前提でこのあと urldecodeValidUtf8 を使って urldecode される場合がある。

    private static function sanitizeString($value)
    {
        // $_GET and $_REQUEST already urldecode()'d

getParam は UTF-8 前提で作っているんだけれども、 ActionSiteSearch::detectSiteSearchFromUrl 中に

        // decode values if they were sent from a client using another charset
        $pageEncoding = $this->request->getParam('cs');
        PageUrl::reencodeParameters($parameters, $pageEncoding);

としてある箇所がある。 parameter を全部 cs の文字コードから utf8 にエンコードしなおす関数になっているが getParam が UTF-8 ハードコーディングなので cs が必要になる前に文字化け。

検索キーワードが、255 バイトを超えるときは、多バイト文字を 256 バイト以上が切り捨てられる。 UTF-8 前提の多言語であるのに substr が使われている。

Piwik 2.16.0 で本家にマージされました。 キーワードは、MySQL で varchar(255) として扱われています。MySQL の自動変換をにお断りしてもクラッシュしないように制限を加えているのでしょうが、 MySQL はバイトではなくて文字数です。つまり、255 文字までです。

対策

  1. substr から mb_substr に変更します。

tracker 使用時に action_name= で送られてくる UTF-8 のページ title が文字化けしたとき、 title 文字列を空白にし、データベースに文字化けで記録することを抑止する (Piwik >= 2.14.3)

tracker から送られてくる title 文字列は Web サイトがどんな文字コードであろうと UTF-8 で送られてくるように実装されているようです。しかし中国経由でこられたときに、title 文字列が UTF-8 ... なのですが、さまざまな Proxy を介するうちに UTF-8 → Big5 → UTF-8 と変換され UTF-8 の 4 バイト(U+10000)に文字化けすることがあるようです、確認できた事象では途中から文字化けしていました。 MySQL の UTF-8 は 4 バイト以上の UTF-8 を受け付けないらしく、そのような UTF-8 文字列が来ると、上記に記述した通り MySQL のデフォルトの仕様ではカラムに入るように自動変換されますが、文字化けはします(まあこの場合はどのみち最初から文字化けですけど)。また、これも上記のとおり、MySQL にこのような文字列をエラーとして受け付けない設定としている場合は、Internal Server Error として終了します。

対策

  1. action_name= で送られてくる文字列が 4 バイト以上の UTF-8 が混じっていれば文字化けとみなし、 title 文字列を空白にします。
  2. PHP では 4 バイト以上の UTF-8 を検出する... なんてどの関数を使ってもできないので、 正規表現で 1 文字 3 バイト以下であるかをチェックします。
  3. なお、title 文字列を空白としたページは、アクション→ページタイトルで、「ページ名 は定義されていません」に集約されます。

tracker 使用時に pk_campaign= (utm_campaign=) で送られてくる UTF-8 文字列が多バイト文字を考慮せず 70 バイト以上が切り捨てられる。 UTF-8 前提の多言語であるのに substr が使われている。(Piwik >= 2.14.3)

Piwik 2.16.0 で本家にマージされました。 該当カラムは piwik_log_visit の referer_name で varchar(70) として扱われています。MySQL の自動変換をにお断りしてもクラッシュしないように制限を加えているのでしょうが、 MySQL はバイトではなくて文字数です。つまり、70 文字までです。

対策

  1. substr から mb_substr に変更します。

最後に

  • もう現在は yahoo japan からの検索キーワードを最大限拾うしかありません。 google からのキーワードは拾えなくなりました。
  • SearchEngines.yml に検索エンジンを加えるときは、必ず文字コードを指定してください。なお github のレポジトリは別で、 searchengine-and-social-list となります。