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

时间:2013-10-22 01:36:14

标签: php utf-8 simplexml steam

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

示例输出:

ѕqÃ…ιÑÂтℓє

预期输出:

ѕqυιятℓє 

我对文件进行了字符集检查,从file_get_contents中提取字符串,并将其作为函数的输出,以及源XML文件。 MySQL也没有得到正确的版本。

此外,SimpleXML支持UTF-8。

sudo file -i debug.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字符集,或者如果这是我首先需要做的事情。我希望这里有人知道如何获得该名称的预期版本。提前谢谢。

TextFile(日志)输出功能:

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

1 个答案:

答案 0 :(得分:0)

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

您还提到了使用Apache HTTPDs':

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对象,您可以稍后使用其他实现替换它。例如。有一个将远程请求委托给另一个层。