Bug(バグ) #3134
完了
- 3.8 で発生するか を Yes (はい) にセット
- 対象バージョン を OpenPNE 3.8.2 にセット
- 対象バージョン を OpenPNE 3.8.2 から OpenPNE 3.9.0-old に変更
対策としては 2通り考えられるが,先に結論を述べておくと 後者を選択する
- 4byte 文字をサポートできる仕様にする
- 4byte 文字を受け付けない仕様にする
前者の場合,データベース自体(この場合 MySQL)が 4byte 文字に対応していないということになり,この MySQL のバージョンアップなりの対応で対応できるが,すでに動いている SNS などを考慮すると MySQL のバージョンを上げることが難しい場合もあるため今回はこの方法を取らない.次期 OpenPNE バージョンなどで対応できるように検討することが適切であるとおもわれる.
基本的に本チケット(本バージョン)では後者の場合を取りうるが,この場合での検討事項は どのタイミングで 4byte 文字を切り落とすかとなる.
この問題はおそらく MySQL のバージョンや使用する文字コードなどが影響しているため Doctrine 以下で行いたいところが,データ格納時などに切り落とす処理を行うと影響範囲が大きく,Symfony で提供されているバリデーションがうまく働かなくなる可能性なども十分にありえるためあまり得策ではないといえる.
OpenPNE では似たような問題として ヌルバイト文字にも対応していて,これはリクエスト時にヌルバイトを切り落とすかどうかを指定して,切り落とした文字列を用いている.本チケットの問題も同様の対処により解決できるのではとかんがえられる.
つまりリクエストから文字列を取得してくる際に 4byte 文字を削除するような対策を取る.
この対策を施した OpenPNE では 4byte 文字を扱えないという仕様になり, 4byte 文字を削除した文字列を入力値として扱う.
こうすることで,空文字列が許容されないフォームに対しても 4byte 文字のみで構成された場合に空文字列として扱わせることで Symfony の Validator をそのまま用いることができる.
4byte 文字がすでに存在する場合があるかどうかを調査する必要がある.
すでに投稿された 4byte 文字に関係するものはDBに入っていないため考慮する必要はないが,アクティビティ通知のテンプレート部分が不正な場合のアクティビティのを削除するなどの対処を行う必要がある可能性がある.
+----+-----------+-------------------------+----------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+-------------------------+---------------------+---------------------+
| id | member_id | in_reply_to_activity_id | body | uri | public_flag | is_pc | is_mobile | source | source_uri | foreign_table | foreign_id | template | template_param | created_at | updated_at |
+----+-----------+-------------------------+----------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+-------------------------+---------------------+---------------------+
| 3 | 1 | NULL | [Diary] | @diary_show?id=45 | 1 | 1 | 1 | Diary | NULL | NULL | NULL | diary | a:1:{s:3:"%1%";s:1514:" | 2012-09-12 13:24:11 | 2012-09-12 13:24:11 |
+----+-----------+-------------------------+----------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+-------------------------+---------------------+---------------------+
正しそうなデータは以下のとおり.
+----+-----------+-------------------------+----------------------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+--------------------------------------+---------------------+---------------------+
| id | member_id | in_reply_to_activity_id | body | uri | public_flag | is_pc | is_mobile | source | source_uri | foreign_table | foreign_id | template | template_param | created_at | updated_at |
+----+-----------+-------------------------+----------------------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+--------------------------------------+---------------------+---------------------+
| 4 | 1 | NULL | [Diary] タイトル | @diary_show?id=46 | 1 | 1 | 1 | Diary | NULL | NULL | NULL | diary | a:1:{s:3:"%1%";s:12:"タイトル";} | 2012-09-12 13:28:29 | 2012-09-12 13:28:29 |
+----+-----------+-------------------------+----------------------+-------------------+-------------+-------+-----------+--------+------------+---------------+------------+----------+--------------------------------------+---------------------+---------------------+
- Web サーバの外側から入ってくる任意の文字列で対応する必要がある
- OpenPNE の PHP では UTF-8 を用いており,4byte UTF8 についての考慮はなされていない
- 携帯電話のメールは Shift-JIS であり,4byte UTF8 について(おそらく)考慮する必要はない
外からの入力が必ず通る Request あたりで OpenPNE で変更出来る部分として opWebRequest のパラメータ取得を修正しようとした.
pc_frontend アプリケーションの場合ではうまくいくが api アプリケーションではうまくいかない.リクエストのオブジェクトとして opWebRequest を用いていないためである.
sfWebRequest であるならば request.filter_parameters のようなイベントを用いることができるが,これは初期化の時点で発行されるためにこのイベント発行時点での Request の中身を書き換えてしまう必要がある.
正しそうな修正としては api アプリケーションでも opWebRequest を用いることが考えられるが,本チケットの修正を対象とする修正としては少々大きいため,他の動作に影響がないか調査する必要がある.
- 担当者 を Yuya Watanabe から Kousuke Ebihara に変更
- ステータス を New(新規) から Pending Review(レビュー待ち) に変更
- 進捗率 を 0 から 50 に変更
opDoctrineRecord のセッター経由で値を設定する際、カラムが非バイナリ文字列をストアするものである場合で、 DBMS として MySQL を使用している場合は、文字列中に含まれる 4 バイト UTF-8 の文字を U+FFFD に置換するように変更しました。
ただし、 MySQL を使用している場合でも 4 バイト UTF-8 に対応可能な環境についてこの挙動を回避できるよう、 Doctrine の接続設定として ATTR_4BYTES_UTF8_READY (999) を受け入れられるようにしました。以下のように設定することで U+FFFD の置換がおこなわれなくなります。
all:
doctrine:
class: sfDoctrineDatabase
param:
dsn: 'mysql:dbname=example;host=localhost'
username: root
encoding: utf8
attributes: { 164: true, 999: true } # 999: true を追加
- ステータス を Pending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
- 進捗率 を 50 から 70 に変更
- ステータス を Pending Testing(テスト待ち) から Won't fix(対応せず) に変更
- 進捗率 を 70 から 0 に変更
OpenPNE 3.8.4 にて対応済みであったため、対応せずとします。
他の形式にエクスポート: Atom
PDF