PHP中的多字节安全URL标题转换

时间:2010-10-21 15:24:17

标签: php url-rewriting multibyte

我正在尝试创建一个多字节安全标题=> url字符串转换器,但是我遇到了在删除其他人时不知道如何在URL中允许合法的亚洲(和其他)字符的问题。这是目前设定的功能。

public static function convertAccentedCharacters($string)
{                            
    $table = array(
            'Œ'=>'CE', 'œ'=>'ce', '¥'=>'Y', 'Ÿ'=>'Y', 'µ'=>'u', 'ü'=>'u', 
            'Š'=>'S', 'š'=>'s', 'Đ'=>'Dj', 'đ'=>'dj', 'Ž'=>'Z', 'ž'=>'z', 'Č'=>'C', 'č'=>'c', 'Ć'=>'C', 'ć'=>'c',
            'À'=>'A', 'Á'=>'A', 'Â'=>'A', 'Ã'=>'A', 'Ä'=>'A', 'Å'=>'A', 'Æ'=>'A', 'Ç'=>'C', 'È'=>'E', 'É'=>'E',
            'Ê'=>'E', 'Ë'=>'E', 'Ì'=>'I', 'Í'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Ñ'=>'N', 'Ò'=>'O', 'Ó'=>'O', 'Ô'=>'O',
            'Õ'=>'O', 'Ö'=>'O', 'Ø'=>'O', 'Ù'=>'U', 'Ú'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ý'=>'Y', 'Þ'=>'B', 'ß'=>'Ss',
            'à'=>'a', 'á'=>'a', 'â'=>'a', 'ã'=>'a', 'ä'=>'a', 'å'=>'a', 'æ'=>'a', 'ç'=>'c', 'è'=>'e', 'é'=>'e',
            'ê'=>'e', 'ë'=>'e', 'ì'=>'i', 'í'=>'i', 'î'=>'i', 'ï'=>'i', 'ð'=>'o', 'ñ'=>'n', 'ò'=>'o', 'ó'=>'o',
            'ô'=>'o', 'õ'=>'o', 'ö'=>'o', 'ø'=>'o', 'ù'=>'u', 'ú'=>'u', 'û'=>'u', 'ý'=>'y', 'ý'=>'y', 'þ'=>'b',
            'ÿ'=>'y', 'Ŕ'=>'R', 'ŕ'=>'r',
        );

    return str_replace(array_keys($table), array_values($table), $string); 
}

public static function convertStringToSafeCharacters($string)
{                 
    $string = self::convertAccentedCharacters($string);
    if (function_exists('mb_convert_encoding') === true)
    {
        $string = mb_convert_encoding($string, 'UTF-8', 'auto'); 
    }
    else if(function_exists('iconv') === true && ($iconvstr = @iconv('', 'UTF-8', $string)) !== false)
    {
        $string = $iconvstr;
    }
    else
    {
        $string = utf8_decode($string);
    }
    return strip_tags(trim($string));
}

public static function convertToUrlsafe($string, $options=array())
{    
    if(isset($options['separator']) === false || $options['separator'] === false)
    {
        global $_SITE;
        if(strpos($_SITE->urlsafe_format, 'underscore') !== false)
        {
            $options['separator'] = '_';
        }
        else
        {
            $options['separator'] = '-';
        }
    }
    if(isset($options['case']) === false || $options['case'] === false)
    {
        global $_SITE;
        $format = substr($_SITE->urlsafe_format, 0, 5);
        if($format === 'lower')
        {
            $options['case'] = 'lower';
        }
        else if($format === 'upper')  
        {
            $options['case'] = 'upper';
        }
        else
        {
            $options['case'] = 'mixed';
        }
    } 

    $string = self::convertStringToSafeCharacters($string);

    $separator_in_use = $options['separator'];
    $separtor_convert = $options['separator'] == '-' ? '_' : '-';
    $preg_changes = array(
//              convert other seperators into the seperator being used
        '/\\'.$separtor_convert.'/i'            => $separator_in_use, 
//              remove any none legal chars
        '/[^\-\_a-zA-Z0-9&\s]/i'                => '',
        '/\&\#\d+?\;/'                          => '', 
        '/\&\S+?\;/'                            => '',
//              replace spaces with separator
        '/\s+/'                                 => $separator_in_use,
//              replace amersands with and
        '/\&/'                                  => 'and',
//              now finally remove any last chars
        '/[^A-Za-z0-9\/'.$separator_in_use.']/' => '',
//              remove any double paddinging separators, ie ----
        '/'.$separator_in_use.'+/'              => $separator_in_use, 
//              remove separator padding from start and end of string
        '/'.$separator_in_use.'$/'              => '',
        '/^'.$separator_in_use.'/'              => ''
    );
    $string = preg_replace(array_keys($preg_changes), array_values($preg_changes), $string);
    switch($options['case'])
    {
        case 'lower' :
            $string = strtolower($string);
            break;
        case 'upper' :
            $string = strtoupper($string);
            break;
        case 'mixed' :
            // do nothing
    }
    return $string;
}

请记住,那里有一些与CMS相关的功能,而且这些功能实际上是一个类的一部分。主函数调用是

convertToUrlsafe($string);

我很确定问题在于该函数本身的正则表达式替换,但我不确定在不破坏现有功能的情况下应该更改什么。

我希望能够获得以下标题并让它们返回urlsafe标题。

“非常第一个博客!” => “该-非常入先博客”

“スーザンは本日,グラスゴーのベラヒューストン·パークでローマ法王の”(不知道这是什么意思)但它需要转换为urlsafe,目前它只返回一个空字符串。

1 个答案:

答案 0 :(得分:1)

网址中没有“合法亚洲”字符:网址只能包含ASCII字符。

您可以使用您的方法规范化的西方字符(例如iconv(); here是另一种选择)。对于其他所有内容,请使用百分比编码(即urlencode)。现代浏览器将在适当的位置自动显示正确的字符。

背景:Unicode characters in URLs