【CakePHP】namedパラメータのセパレータについて皆さんにお聞きしたいこと

cake-logoはい、恥ずかしい文章でCakePHPのバグチケットを投げたのは私です(^^:::::::。
現在形と過去形が入り乱れ、しかも後で読み返したら凄い文章になっていました。フォーラムの投稿と違って、一度書いたら消せないので、超恥ずかしい… 全然ダメダメですね(;^;)。

さて本題なのですが…
namedパラメータでsession.use_trans_sidが動作をしない件は、前回の記事で書いたとおりなのですが、それを回避するKtai Libraryでの実装方法について大変に悩んでいます。実は、先日生け贄になっていただいた方にもご相談し、Router::named[‘separator’]を別の文字にすることで回避しようと決めたのですが、それが実は半分しかうまくいっていないことに気がつき、また迷宮入りしているところです。

実装に関する今までの経緯を簡単に説明すると、session.use_trans_sidを有効とするところまではうまくいったのですが、テストで制作するサイトに載せるとセッションキーを更新しないため、あれこれやっていました。iMODE端末を持っていないため、とりあえずブラウザのセキュリティをいじり、クッキーを用いない設定でアクセスすると、セッションは一向に保存されません。

このとき、制作しているサイトの関係でnamedパラメータ付きのURLで試していたのですが、このパラメータを取ってみたところ問題なく動作し、さらにnamedパラメータのセパレータを「:」から「~」に変更したところ、正しい動きをするようになりました。そこで RFC を確認したところ、「:」は予約されたキャラクターと書かれていたため、これが原因ではないかと確信した次第です。

router.phpを眺めてみたところ、urlを作成している部分はstartup処理内で行っているようなので、それより前の処理として、componentのinitializeで設定すれば間に合うんじゃないかと思い、ktai.php内で書いてみたところ、URLが正しく処理され、想定していたsid付きのURLとなりました。

この方向で実装をしようと方針を決め、リリース寸前まで来ていたのですが、新たに問題が発生! 確かにURLは作られ、一見動作しているように感じたのですが、そのURLが次のレスポンスでnamedパラメータとしてパースされないことが分かりました。何故かというと、argsを取り出しているのがdispatcher内部で、initializeより前にnamedを取り出す処理が完了してしまっていたからです。いろいろ模索をしてみたのですが、タイミング的にrouter.php内のソースを変更する以外に方法は見あたらず、ライブラリとしてこの値をどうにかする方法が採れないことが分かったのです。

ここで問題になるのは2つの事柄です。
まず一つは「namedセパレータを変えることがそもそも受け入れられるのか?」ということです。おそらく以前のバージョンからずっとこのルールの筈ですから、もう世界中に浸透してしまっているURLです。それを「Ktai Libraryでは変えてください」というルールがまかり通るか、ということなのです。
もう一つは「router.phpを直接変更する作業が必要」ということで、ライブラリ化できない部分(つまりインストールするだけでは済まなくなった)点についてどう思われるか、ということです。私的には、この繁雑な作業はバグを生み出す元となる可能性があるため、出来れば避けたいのです。

じゃあ、そもそもnamedセパレータを変えずに、さらにsession.use_trans_sidすらも使わない方法で、手動でsidを埋め込めば? という話になるのですが、それも大変に困難です。何故ならpaginateで必ずHtmlHelper::link()を使っていて、ここに及ばせる方法がないのです。この問題さえなければ、Ktai::link()を必ず使ってもらう方向で進められるのですが、paginateに対応できないとなると、魅力が薄れてしまいます。また、完全対応するためにはHtmlHelperもしくはPaginateにパッチを当てたものをcakeディレクトリにコピーしてもらうことになりかねないため、Cakeのバージョンが上がった場合に不具合を生みかねないという問題もあります。

一応、もう1つの逃げ道は考えられ、app/config/dispatcher.phpで設定してしまう、という方法もアルにはあります。しかしこの段階でRouterはロードされていないため、importする必要が出てきます。つまり、Dispatcher内でRouteは二重に読み込まれることになり、ただでさえ悪名高いimportを重複して使いたくないという思いもあります。でも、今のところライブラリ化出来る唯一の方法かもしれません。

まあ早い話、CakePHPの方でセパレータ文字を別の文字にしてくれれば、何も考えずにsession.use_trans_sidを有効にするだけでセッション問題は解決できるため、これが一番スマートなので、とりあえずチケットを投げたのですが、たぶん無理でしょう。今まで制作したサイトで不具合が出るでしょうから。「RFCの予約文字」と言う点だけが唯一の頼みの綱なのですが…

というわけで、皆さんはどうやったら一番良い方法で解決できると思われるか、是非ご意見を聞きたいです。よろしくお願いいたします。


“【CakePHP】namedパラメータのセパレータについて皆さんにお聞きしたいこと” への8件の返信

  1. 今日はまりました。参考にさせてもらいました。ありがとうございます。
    CakePHP 1.2.2.8120では、以下の方法で「:」を「-」に変更して試したところ、うまくいっているようです。携帯(F-01A)と http://firemobilesimulator.org/ で確認。

    -app/config/routes.php
    Router::connectNamed(array(),array(‘argSeparator’=>’-‘));

  2. paginatorのみの話であれば、paginatorヘルパーのoptionsで

    $options = array(\’url\’=>array(\’?\’=> session_name().\"=\".session_id()));

    のように配列を強制的に追加するようにしてみてはどうでしょうか?

    これならhelperのみいじくればどうにかなりそうですし、paginatorで
    パラメータを設定する際は、$paginator->options() を使うかと思いますので。

  3. 書いた後に気がつきましたが、

    >HtmlHelperもしくはPaginateにパッチを当てたものをcakeディレクトリにコピーしてもらうことになりかねないため、Cakeのバージョンが上がった場合に不具合を生みかねないという問題もあります。

    と書かれていましたね、失礼しました。

  4. kenji0302さん、DEXさん、ご意見や対応方法ありがとうございます。

    DEXさんの手法が今のところ理想的ですね。
    試してみたところ、ちゃんとnamed配列の中に値が入りましたので、一番問題がなさそうです。
    ソースも追ってみたのですが、dispatcherの直後のインクルードのため、実行する順番がparseよりも先ですので正しく動作がされます。Routerのソースを直接いじるということも回避できるため、実装としては理想的です。

    ただ、本文中にも指摘したとおり、この一文を加えなければならないという煩雑性が追加されることになり、「ライブラリ」としてこれを主流とすることが果たして正しいことなのかと考えます。

    ちなみに、バージョン0.0.2までは機種判別をroutes.php内に持ってくることは不可能だったのですが、新バージョンではlib3gkをここまで持ってくることが(たぶん)可能になりました。この件を含めて待望されていた「携帯固有のrouteを設定する」ということが晴れて出来るようになりましたので、routes.php内にKtai Library固有の設定を加えることについて、それほど神経質にならなくても良いような気も一応はしています。

  5. こんにちは。
    もしかしたら、もう解決されているかもしれないんですが、私はこのように対処しています(kenji0302さんの方法と似ていますが)。

    適当なヘルパーを作成し、$helpersにPaginatorを含め、beforeRender内で、

    if (ini_get(\’session.use_trans_sid\’)) {
    $this->Paginator->options = array(\’url\’ => array(\’?\’ => session_name() . \"=\" . session_id()));
    }

    として、そのヘルパーをAppControllerで読み込みます。この方法ならコアに手を入れる必要がないし、ヘルパーで処理が完結するので、問題はないと思いますがどうでしょうか。

  6. アイデアをいただきましてありがとうございます。

    この方法ですと、Paginatorを使用している場合は有効なのですが、Paginatorを使用せずにnamedパラメータを使用したい場合に対処が出来なくなります。なので、やはり根本解決をするためにはnamedセパレータを直接変更するのが一番良さそうです。
    現在は、DEXさんの方法で上手く動作をしていますので、この方式で実装させていただいています。routes.phpに1行加えることになりますが、たぶん他の方法よりも一番手数が少なくて安全ではないかと思います。

    また、この問題は本家のTracにて報告しておりますので、もし大元で修正がされれば全てが解決するはずです。残念ながら最新バージョンには反映されませんでしたが、却下もされていませんので、先方で検討されていると期待はしております。ただし、以前のバージョンからのバージョンアップで動かなくなる可能性もあるため、慎重に議論されなければならない問題でもあるかと思いますので、仮に却下されてもいたしかたないとは思っています。

  7. これ、どちらかというとPHPのsession.use_trans_sidバグのような気がします。(今更ですが)

    RFCには以下のBNFで定義されているので、セパレータとして「:」を使うのはOKです。

    ; HTTP

    httpurl = “http://” hostport [ “/” hpath [ “?” search ]]
    hpath = hsegment *[ “/” hsegment ]
    hsegment = *[ uchar | “;” | “:” | “@” | “&” | “=” ]
    search = *[ uchar | “;” | “:” | “@” | “&” | “=” ]

    むしろ、「~」を使うほうが厳密にみればRFC違反になるようです。

  8. ご指摘ありがとうございます。
    完全に私の勘違いでした。BNFを再確認してみたのですが、確かに「:」はOKで「~」はまずいですね(^^;
    PHP側で「:はucharではないから」ということで蹴られているのでしょうかね?

    今は別作業で忙しいのでできないのですが、作業が終わったらちょっと使える文字を研究してみます。

コメントは受け付けていません。