Charset编码Windows上strftime()的解决方法?

时间:2016-02-12 08:39:54

标签: php windows character-encoding locale strftime

我认为我在Windows上提出了针对PHP strftime()的解决方法的最佳解决方案,然后用户报告了问题。

Windows对strftime()有一些限制,而且它不支持UTF-8。所以我为这两个问题写了一个解决方法,但偶然发现了charset问题。

这就是我的代码:

function strftimefixed($format, $timestamp=null) {

  if ($timestamp === null) $timestamp = time();

  if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
    $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\1%#d', $format); // Don't mind this line
  }

  return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'auto'); // Charset is the problem
}

错误消息

  

警告:mb_convert_encoding():无法检测字符编码

你可以看到&#39; auto&#39;无法识别编码。用户正在安装捷克语,但我无法将其硬编码到ISO-8859-2&#39;因为这只会帮助捷克用户,而不是其他最终用户,他们对Windows区域设置或者哪种字符集没有任何了解。

那么制作一些通用的优秀解决方案的最佳解决方案是什么?

注意:这里的格式不是问题。它可以是任何东西,例如%b%e%Y%H:%M。字符集识别是问题所在。

2 个答案:

答案 0 :(得分:0)

根据the manual,strftime()在Windows上遇到的问题包括:

  

您的C库可能不支持所有转换说明符   在哪种情况下,PHP的strftime()不支持它们。   此外,并非所有平台都支持负时间戳,因此您的   日期范围可能不会早于Unix纪元。这个   表示%e,%T,%R和%D(可能还有其他) - 以及日期   在1970年1月1日之前 - 在Windows上,某些Linux上不起作用   发行版和其他一些操作系统。

您的代码使用未公开的参数($format$timestamp),所以您担心的是相当不清楚的。

但是,您收到的错误消息与文本编码有关,而与日期处理本身无关。对于未知编码,无法正确处理文本,但您可以通过选择合适的区域设置选择 strftime()生成的编码:

  

strftime - 根据区域设置格式化本地时间/日期

     

根据区域设置格式化时间和/或日期。月份和工作日名称以及其他依赖于语言的字符串遵循使用setlocale()设置的当前区域设置。

请注意,在某些平台(例如Windows上的线程安全版本)中,区域设置处理是不可靠的。如果是这种情况,您可能需要完全转储strftime()并选择正确的本地化工具。

当然,您可以始终保留默认语言环境,只是尝试从中猜测编码,但您可能需要维护数据库。

答案 1 :(得分:0)

我能想出的最佳解决方案是检测Windows区域设置字符集并从那里开始工作。

function strftimefixed($format, $timestamp=null) {

  if ($timestamp === null) $timestamp = time();

  if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
    $format = preg_replace('#(?<!%)((?:%%)*)%e#', '\1%#d', $format);

    $locale = setlocale(LC_TIME, 0);

    switch(true) {
      case (preg_match('#\.(874|1256)$#', $locale, $matches)):
        return iconv('UTF-8', "$locale_charset", strftime($format, $timestamp));

      case (preg_match('#\.1250$#', $locale)):
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'ISO-8859-2');

      case (preg_match('#\.(1251|1252|1254)$#', $locale, $matches)):
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'Windows-'.$matches[1]);

      case (preg_match('#\.(1255|1256)$#', $locale, $matches)):
        return iconv('UTF-8', "Windows-{$matches[1]}", strftime($format, $timestamp));

      case (preg_match('#\.1257$#', $locale)):
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'ISO-8859-13');

      case (preg_match('#\.(932|936|950)$#', $locale)):
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'CP'.$matches[1]);

      case (preg_match('#\.(949)$#', $locale)):
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'EUC-KR');

      default:
        trigger_error("Unknown charset for system locale ($locale)", E_USER_NOTICE);
        return mb_convert_encoding(strftime($format, $timestamp), 'UTF-8', 'auto');
    }
  }

  return strftime($format, $timestamp);
}