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

发布于 2024-09-28 11:30:13 字数 4771 浏览 7 评论 0原文

我正在尝试创建一个多字节安全标题=> 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 标题。

“第一个博客!” => “The-Very-First-Blog”

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

I'm trying to create a multibyte safe title => url string converter, however I've run into the problem of not knowing how to allow legal asian (and other) characters in the url when removing others. This is the function set at the moment.

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;
}

Please bear in mind that there is some CMS related functionality in there and that the functions are actually part of a class. The main function call would be

convertToUrlsafe($string);

And I'm pretty sure the problem lies with the regex replaces in that function itself but I'm not quite sure what to change without breaking some existing functionality.

I want to be able to take the following titles and have them return urlsafe titles.

"The Very First Blog!" => "The-Very-First-Blog"

"スーザンは本日、グラスゴーのベラヒューストン・パークでローマ法王の" (no idea what this says) but it needs to be converted to urlsafe and at the moment it just returns an empty string.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

沉睡月亮 2024-10-05 11:30:13

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

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

背景:网址中的 Unicode 字符

There are no "legal asian" characters in URLs: URLs can contain only ASCII characters.

Western characters you can normalize using your method (or e.g. iconv(); here is another alternative). For everything else, use percent encoding (i.e. urlencode). Modern browsers will automatically display the proper characters instead where appropriate.

Background: Unicode characters in URLs

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文