有关网址编码的Umlaut的路线问题(使用Zend框架)

时间:2020-03-06 14:39:51  来源:igfitidea点击:

今天,我偶然发现了一个问题,该问题似乎是Zend框架中的错误。给出以下路线:

<test>
    <route>citytest/:city</route>
    <defaults>
        <controller>result</controller>
        <action>test</action>
    </defaults>
    <reqs>
        <city>.+</city>
    </reqs>
</test>

和三个Urls:

  • mysite.local / citytest /柏林
  • mysite.local / citytest /汉堡
  • mysite.local / citytest / M%FCnchen

最后一个网址不匹配,因此未调用正确的控制器。有人知道为什么吗?

Fyi,在哪里使用Zend-Framework 1.0(是的,我知道那很古老,但是我不负责更改它:-/)

编辑:据我所知,我们将很快升级到Zend 1.5.6,但是我不知道何时,所以补丁会很棒。

编辑:我已经将其跟踪到以下行(Zend / Controller / Router / Route.php:170):

$regex = $this->_regexDelimiter . '^' . 
  $part['regex'] . '$' . 
  $this->_regexDelimiter . 'iu';

如果我将其更改为

$this->_regexDelimiter . 'i';

有用。据我了解,u-修饰符用于处理亚洲字符。因为我不使用它们,所以我知道该补丁很好。谢谢阅读。

解决方案

u修饰符使regexp期望输入utf-8. 这表明ZF需要utf-8编码的输入,而不是ISO-8859-1(我对ZF不太熟悉,所以我只是在这里猜测)。

在这种情况下,我们必须先对``进行utf-8编码,然后再在URL中使用它。然后它将变为:mysite.local / citytest / M%C3%BCnchen

请注意,由于应用程序的其余部分可能使用的是ISO-8859-1(PHP <= 5的默认设置),因此在使用该变量之前,必须使用utf8_decode对其进行显式解码。

问题如下:

Using the /u pattern modifier prevents
  words from being mangled but instead
  PCRE skips strings of characters with
  code values greater than 127.
  Therefore, \w will not match a
  multibyte (non-lower ascii) word at
  all (but also won’t return portions of
  it). From the pcrepattern man page;
  
  In UTF-8 mode, characters with values
  greater than 128 never match \d, \s,
  or \w, and always match \D, \S, and
  \W. This is true even when Unicode
  character property support is
  available.

从使用PHP处理UTF-8.
因此,如果网址是ISO-8859-1编码(mysite.local / citytest / M%FCnchen)或者UTF-8编码(mysite.local / citytest / M%C3%BCnchen),则实际上是无关紧要的,默认正则表达式不会比赛。

我还对Zend Framework中URL中的变音符号进行了实验,得出的结论是,我们实际上并不需要URL中的变音符号。问题是,我们不能依赖浏览器使用的URL编码。例如,Firefox(3.0之前的版本)不对输入到地址文本框中的URL进行UTF-8编码(如果未在about:config中指定),并且IE的选项中确实有一个复选框,可在其URL的常规编码和UTF-8编码之间进行选择。但是,如果我们单击页面内的链接,则两个浏览器都会使用给定编码的URL(UTF-8页面上的UTF-8)。因此,我们无法确定将URL发送到应用程序的编码方式是什么,而检测使用的编码并不是一件容易的事。

在网址中使用音译参数可能更好(例如,将?更改为Ae等)。有一个非常简单的方法(我不知道这是否适用于每种语言,但是我将其与德语字符串一起使用,并且效果很好):

function createUrlFriendlyName($name) // $name must be an UTF-8 encoded string
{
    $name=mb_convert_encoding(trim($name), 'HTML-ENTITIES', 'UTF-8');
    $name=preg_replace(
        array('/&szlig;/', '/&(..)lig;/', '/&([aouAOU])uml;/', '/&(.)[^;]*;/', '/\W/'),
        array('ss', '', 'e', '', '-'),
        $name);
    $name=preg_replace('/-{2,}/', '-', $name);
    return trim($name, '-');
}