PHP SimpleXML - 无法使用 UTF8 将 SteamID64 正确转换为 Steam 名称


PHP SimpleXML - Unable to correctly convert SteamID64 to Steam Name with UTF8

我一直在获取此函数检索的名称的 UTF8 版本,但由于某种原因它没有用正确的字母输出它。

示例输出:

ѕqÃ…ιÑÂтℓє

预期输出:

ѕqυιятℓє 

我已经对文件、字符串(从file_get_contents中提取字符串)以及源 XML 文件进行了字符集检查。MySQL也没有获得正确的版本。

此外,SimpleXML 确实支持 UTF-8。

sudo 文件 -i 调试.txt

debug.txt: txt/plain; charset=utf-8

MySQL 排序规则

utf8_general_ci

源 XML 文件头

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

这(在代码中两次)-

  $enc = mb_detect_encoding($xml, 'UTF-8', true);
  echo 'Detected encoding '.$enc;

输出:

Detected encoding UTF-8
Detected encoding UTF-8

不确定还有什么地方可以检查 UTF-8 字符集,或者这是否是我首先需要做的。我希望这里有人知道如何获得该名称的预期版本。提前谢谢。

文本文件(日志)输出功能:

function log_output($message){
  $file = 'debug.txt';
  $current = file_get_contents($file);
  $current .= $message."'n"; 
  file_put_contents($file, $current);  
}

源代码:

// Converts SteamID(64) to the users current name on Steam.
        function steamid64_to_name($steamid64) {
          // Get User Profile Data
          $xml = file_get_contents('http://steamcommunity.com/profiles/'.$steamid64.'/?xml=1');
          $enc = mb_detect_encoding($xml, 'UTF-8', true);
          echo 'Detected encoding '.$enc;
          $xml = simplexml_load_string($xml, null, LIBXML_NOCDATA);
          if(!empty($xml)) {
            if(isset($xml->steamID)) {
               $username = $xml->steamID;// Example: steamcommunity.com/profiles/76561198077095013/?xml=1
            } else { 
              $username = "Username Not Found";
            } 
          } else {
            $username = "User XML Not Found"; // Example: steamcommunity.com/profiles/0/?xml=1
          }
          $enc = mb_detect_encoding($xml, 'UTF-8', true);
          echo 'Detected encoding '.$enc;
          return $username;
        }

你问的不是关于SimpleXML,而是关于你的输出编码。输出编码是您发送到浏览器的数据以及有关与该数据一起使用的编码的信息(数据 + 元)。

您还称赞,使用 Apache HTTPD':

AddDefaultCharset utf-8

为您修复了此问题。也就是说,告诉浏览器您要发送到它的数据是 UTF-8 编码的。以前你告诉浏览器它会是一些拉丁语-n的东西,因此你得到了这些看起来错误的字符。只需考虑您需要在字母旁边命名语言,以便接收它的人理解要阅读的字母的语言。

除此之外,您应该考虑一些一般的经验法则,以更快地发现问题并且不要编写太多代码:

  • 如果您从SimpleXMLElement读取字符串,它将为您提供 UTF-8 编码的数据。无论您从中创建它的原始文件的编码是什么。
  • SimpleXML自行处理大部分重新编码,您所需要的只是一个适当的iconv安装,这通常是这种情况(否则推荐)。
  • 对自己要严格,永远不要像你在这里用mb_detect_encoding那样猜测编码。这在技术上是不可能的,相反 - 如果编码未知 - 从源而不是从数据中获取该信息(从技术上讲不可能从数据中获取它,这始终是一个猜测)。
  • 最后但并非最不重要的一点是,对于远程服务,您应该始终在此处添加间接层。我想,您在这里要介绍的最重要的小事情是远程请求的缓存,因此将其包装到类中是第一步。

您的 Steam API 访问的一些示例:

<?php
/**
 * PHP SimpleXML - Unable to correctly convert SteamID64 to Steam
 * Name with UTF8
 *
 * @link http://stackoverflow.com/q/19507614/367456
 */
$profile = new SteamProfile('76561198027590831');
echo $profile->getUsername(), "'n";
var_dump((string)$profile);
/**
 * Class SteamProfile
 *
 * Converts SteamID(64) to the users current name on Steam.
 */
class SteamProfile
{
    const STEAMAPI_URL_MASK = 'http://steamcommunity.com/profiles/%s/?xml=1';
    const UNKONWN_NAME_MASK = 'User #%s (Username Not Found)';
    private $steamId;
    private $xml;
    public function __construct($steamId)
    {
        $this->steamId = $steamId;
    }
    public function getUsername()
    {
        $xml = $this->getXml($this->steamId);
        return $xml->steamID
            ? (string)$xml->steamID
            : sprintf(self::UNKONWN_NAME_MASK, $this->steamId)
            ;
    }
    private function getXml($steamId)
    {
        if ($this->xml) {
            return $this->xml;
        }
        $url = sprintf(self::STEAMAPI_URL_MASK, $steamId);
        if (!$xml = simplexml_load_file($url)) {
            throw new UnexpectedValueException(sprintf('Unable to load XML from "%s"', $url));
        }
        return $this->xml = $xml;
    }
    public function __toString()
    {
        return sprintf("%s (SteamID: %s)", $this->getUsername(), $this->steamId);
    }
}

示例输出(UTF-8 编码):

ѕqυιятℓє | [A]
string(51) "ѕqυιятℓє | [A] (SteamID: 76561198027590831)"

如示例和输出所示,只要 Steam 提供有效的 XML,并且 Simplexml 是为有效的 XML 制作的,就不需要太在意编码。在您的网站上使用 UTF-8 作为编码,或者您需要先将 UTF-8 中的数据重新编码为目标编码。

此外,通过使用 SteamProfile 对象,您可以稍后将其替换为不同的实现。 例如,使用将远程请求委托给不同层的。