【问题标题】:Language redirect works on desktop but not mobile browser语言重定向适用于桌面,但不适用于移动浏览器
【发布时间】:2015-09-15 10:22:10
【问题描述】:

我用 PHP 编写了一个小脚本,用于检查浏览器的语言设置并将它们重定向到网站的语言版本(WP 多站点),

function redirect() {
  $language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );
  switch( $language ) {
    case 'sv':
      header( 'Location: http://www.example.com/sv/' );
      break;
    case 'no':
      header( 'Location: http://www.example.com/no/' );
      break;
    case 'da':
      header( 'Location: http://www.example.com/da/' );
      break;
    default:
      header( 'Location: http://www.example.com/' );
      break;
  }
}
if ( strlen($url) < 4 ) {
  session_start();
  if ( empty($_SESSION[ 'language' ]) ) {
    $_SESSION[ 'language' ] = true;
    redirect();
  }
}

使用 Mobile Safari 或 Mobile Chrome 进行测试时,重定向似乎不起作用。我需要考虑移动浏览器的接受语言的任何特殊输出吗?

更新:经过更多调试后,我发现了这一点:

  • Mobile Safari 在回显 HTTP_ACCEPT_LANGUAGE 但不重定向时显示正确的语言。
  • 移动版 Chrome(仅限 iOS,适用于 Android)无法显示正确的语言(默认为“en”)。
  • iOS 以不同的顺序解析 http 标头数据,比较 iOS Chrome (en-US,en;q=0.8,sv;q=0.6) 和 OSX Chrome (sv,en-US;q=0.8,en; q=0.6)。

【问题讨论】:

  • 在您的移动设备上回显HTTP_ACCEPT_LANGUAGE 是否存在?
  • 抱歉,忘了提及 - 回显这给我“en”作为 Mobile Safar 和 Mobile Chrome (iOS 8) 的结果。
  • 看来HTTP_ACCEPT_LANGUAGE 不能在移动设备上工作。当 UA 移动时,您可以询问用户他们的语言或尝试其他方法。
  • 如果您“回显”您的HTTP_ACCEPT_LANGUAGE 值然后尝试重定向,它将不起作用,因为您已经将输出发送到浏览器。如果您不想通过虚假输出潜在地破坏应用程序逻辑,请使用适当的基于日志的调试技术。此外,除了浏览器发送的 Accept-Language 字符串为您提供的内容外,您真的无事可做。您的 iOS Chrome 示例应该导致 en-USen 作为选择语言,因为 sv 具有较低的 q 值。他们在这里一点也不坏。您可能只是在这些设备上具有不同的本地化设置。
  • 你能把$url的值贴出来,你为什么要检查它的长度是否小于4个字符?谢谢

标签: php redirect url-redirection http-accept-language


【解决方案1】:

试试这个并告诉我们输出结果

function redirect() {
  $language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );

  switch( $language ) {
    case 'sv':
      header( 'Location: http://www.example.com/sv/' );
      break;
    case 'no':
      header( 'Location: http://www.example.com/no/' );
      break;
    case 'da':
      header( 'Location: http://www.example.com/da/' );
      break;
    default:
      die('Default location');
   /* if you get this message on mobile devices, then this line  

          $language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );

      is faulty. Perhaps as @chris85 mentioned, HTTP_ACCEPT_LANGUAGE is
      not populated so mobile behaves as a default by not redirecting to
      other languages. If this is the case, fix that line
      and remove the die();*/
      header( 'Location: http://www.example.com/' );
      break;
  }
  die(); // leave this one in. It forces the server to flush data to the browser
}

【讨论】:

  • 好的。输出什么都没有(相同的浏览器,iOS8)。
  • 仅供参考,我可以在 Android 上正确获取输出(使用移动 Chrome 或原生 Android 浏览器)。
  • 语法错误die('Default location) 缺少结束引号。
【解决方案2】:

这在我的桌面浏览器和移动设备上运行良好。我也只是在设备上遇到了会话问题,而且大多数情况下,我依靠一个为空的会话变量来满足我的条件的要求,而实际上该变量仍然存在,或者根本没有实例化 session_id()。

?reset 将清除会话。

如果语言发生变化,它也会运行重定向。

<?php
    session_start();

    if (isset($_REQUEST['reset'])) {
      unset($_SESSION);
      $_SESSION['PREVIOUS_SESSION'] = '&cleared=1';
    }

    function redirect($loc) {
        $_SESSION[ 'language' ] = true;
        $_SESSION['last_language'] = $language;
        header( 'Location: ?r='.$loc.$_SESSION['PREVIOUS_SESSION']);
    }

    $language = substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 );

    if (( empty($_SESSION[ 'language' ]) ) || ($_SESSION['last_language'] != $language)) {
        redirect($language);
    }

    echo '<pre>';
    print_r($_SESSION);
    echo '</pre>';

    if (!empty($_SESSION['PREVIOUS_SESSION'])) {
        unset($_SESSION['PREVIOUS_SESSION']);
    }
?>

【讨论】:

  • substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 ) 与 OP 使用的代码完全相同,但不适用于他的手机壳。
  • 这不是重定向的问题,而是问题所在。在 OP 情况下,如果设备无法返回 substr( $_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2 ),则变量 $language 被分配为 'example.com'。删除这个没有意义。
【解决方案3】:

您真的不应该依赖获取前两个字符。您确实需要依靠检查整个字符串并了解最佳语言选择应该是什么。这些字符串值具有特定含义,例如,在您的“问题”字符串的一种情况下,您实际上会做最合适的行为来显示en 而不是sv。您显然可以编写逻辑来分解接受语言,调查组成部分并采取适当的措施,但您也可以考虑使用类似的东西:

http_negotiate_language

为您执行此操作。可能有许多其他脚本可以从快速 google 搜索中获得,以便以更合适的方式真正使用此标头,而不仅仅是查看前两个字符。

另外,你可以在这里查看类似的问题:Using the PHP HTTP_ACCEPT_LANGUAGE server variable

【讨论】:

    【解决方案4】:

    你真的应该给我们举例说明$_SERVER["HTTP_ACCEPT_LANGUAGE"] 在这三种情况下的值是多少。

    无论如何,请注意,根据RFC2616 of HTTP/1.1,语言的选择比只取标题的前两个字符要复杂得多。

    每个语言范围都可以被赋予一个相关的质量值 表示用户对语言偏好的估计 由该范围指定。质量值默认为“q=1”。为了 例如,

       Accept-Language: da, en-gb;q=0.8, en;q=0.7
    

    意思是:“我更喜欢丹麦语,但会接受英式英语和 其他类型的英语。”

    没有说这些标题是排序的,也没有说用户的首选语言是列表中的第一个。并且语言配置也无法在浏览器或操作系统中进行配置。

    理想情况下,要选择最佳语言,您必须以这种方式解析此标头:

    • 用逗号分割字符串
    • 拆分在分号字符上找到的每个子字符串
    • 当没有给出数值时,使用默认值 1.0
    • 使用此数值对结果进行排序
    • 将此列表与您网站上可用的语言列表进行比较,然后找到最佳的。

    【讨论】:

      【解决方案5】:

      更新我之前的回答

      HTTP_ACCEPT_LANGUAGE 是通过标头设置的,将为每个人提供不同的值。 就我而言,我在南美洲的计算机设置为英语,所以我的 lang 标题有英语和西班牙语 偏向英语的设置。

      session_start();
      
      function redirectToLang($langCode){
          // use if's instead of switch so that you can
          // check exact matches and presence of a substring
          if ($langCode == 'sv'){
              $langPath = 'sv';
          }else if (strpos($langCode, 'en') !== false){ // this would match en, en-CA, en-US
              $langPath = 'en';
          }else if ($langCode == 'no'){
              $langPath = 'no';
          }else{
              $langPath = 'en';
          }
      
          // you should have no output from the server before this line!
          // that is no echoes, print_r, var_dumps, headers, etc
          header( 'Location: http://www.example.com/' . $langPath .'/' );
          die();
      }
      
      function parseLang(){
          // echo $_SERVER['HTTP_ACCEPT_LANGUAGE']; in my case
          // Chrome Mac OS:        en,es;q=0.8
          // Chrome Android 5.1:   en-US;en;q=0.8,es;q=0.6
          // IE Windows Phone 8.1: en-US,en;q=0.5
          // Safari iOS:           en-US
          // Chrome iOS:           en-US,en;q=0.8
      
          // get the lang and set a default
          $lang = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : 'en';
      
          // parse the lang code. This can be as simple or as complex as you want
      
          // Simple
          $langCode = substr($lang, 0, 2); // in my case 'en'
      
          // Semi Complex (credits to http://www.thefutureoftheweb.com/blog/use-accept-language-header)
          $languages = array();
          preg_match_all('/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $lang, $parsed);
      
          if (count($parsed[1])) {
              $languages = array_combine($parsed[1], $parsed[4]);
              foreach ($languages as $lang => $val) {
                  if ($val === '') $languages[$lang] = 1;
              }
              arsort($languages, SORT_NUMERIC);
          }
          // var_dump($languages); in my case
          // array (size=2)
          //  'en' => int 1
          //  'es' => string '0.8'
      
      
          $langCode = key($languages); // in my case 'en'
      
          return $langCode;
      }
      
      
      if (!isset($_SESSION['lang'])){
          $langCode = parseLang();
          $_SESSION['lang'] = $langCode;
          redirectToLang($langCode);
      }else{
          // we already know the language and it is in $_SESSION
          // no need to parseLang nor redirect
      }
      

      就我而言,所有设备都正确重定向。我的猜测是调用redirect() 的逻辑发生了一些事情

      // this part
      if ( strlen($url) < 4 ) {
        session_start();
        if ( empty($_SESSION[ 'language' ]) ) {
          $_SESSION[ 'language' ] = true;
          redirect();
        }
      }
      

      和会话变量 正在绕过重定向逻辑。尝试上面的代码并清除所有设备上的所有 cookie 和会话,以便您拥有 $_SESSION['language'] var 在测试期间设置不会弄乱结果。让我们知道您会发生什么。

      【讨论】:

        【解决方案6】:

        我在引用.. “更现代的方法是使用 http_negotiate_language():”

        你检查过这个吗? Using the PHP HTTP_ACCEPT_LANGUAGE server variable

        【讨论】:

        • 请将该链接中的信息添加到您的答案中。该链接将来可能会断开
        猜你喜欢
        • 2021-07-06
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 2019-10-27
        • 1970-01-01
        • 2023-03-13
        • 2014-02-18
        • 1970-01-01
        相关资源
        最近更新 更多