【问题标题】:PHP: Writing non-english characters to XML - encoding problemPHP:将非英语字符写入 XML - 编码问题
【发布时间】:2011-05-29 07:01:04
【问题描述】:

我编写了一个小的 PHP 脚本来编辑站点新闻 XML 文件。 我使用 DOM 来操作 XML(加载、编写、编辑)。

写英文字符时可以正常工作,但是写非英文字符时,PHP在尝试加载文件时会抛出错误。

如果我在文件中手动输入非英文字符 - 它加载得非常好,但如果 PHP 写入非英文字符,编码就会出错,尽管我指定了 utf-8 编码。

感谢任何帮助。

更新:有了有用的答案,问题就解决了(阅读下文)。

错误:

警告:DOMDocument::load() [domdocument.load]:实体'次'不是 在文件路径中定义

警告:DOMDocument::load() [domdocument.load]:输入不是 正确的UTF-8,表示编码! 字节:文件路径中的 0x91 0x26 0x74 0x69

以下是负责加载和保存文件的函数(不言自明):

function get_tags_from_xml(){
// Load news entries from XML file for display
    $errors = Array();

    if(!$xml_file = load_news_file()){
    // Load file
        // String indicates error presence
        $errors = "file not found";
        return $errors;
    }
    $taglist = $xml_file->getElementsByTagName("text");
    return $taglist;
}
function set_news_lang(){
// Sets the news language
    global $news_lang;

    if($_POST["news-lang"]){
        $news_lang = htmlentities($_POST["news-lang"]);
    }
    elseif($_GET["news-lang"]){
        $news_lang = htmlentities($_GET["news-lang"]);
    }
    else{
        $news_lang = "he";
    }
}
function load_news_file(){
// Load XML news file for proccessing, depending on language 
    global $news_lang;

    $doc = new DOMDocument('1.0','utf-8');
    // Create new XML document
    $doc->load("news_{$news_lang}.xml");
    // Load news file by language
    $doc->formatOutput = true;
    // Nicely format the file

    return $doc;
}
function save_news_file($doc){
// Save XML news file, depending on language 
    global $news_lang;

    $doc->saveXML($doc->documentElement);
    $doc->save("news_{$news_lang}.xml");
}

以下是写入 XML 的代码(添加新闻):

<?php ob_start()?>
<?php include("include/xml_functions.php")?>
<?php include("../include/functions.php")?>
<?php get_lang();?>
<?php
//TODO: ADD USER AUTHENTICATION!
if(isset($_POST["news"]) && isset($_POST["news-lang"])){
    set_news_lang();

    $news = htmlentities($_POST["news"]);

    $xml_doc = load_news_file();
    $news_list = $xml_doc->getElementsByTagName("text");
    // Get all existing news from file

    $doc_root_element = $xml_doc->getElementsByTagName("news")->item(0);
    // Get the root element of the new XML document
    $new_news_entry = $xml_doc->createElement("text",$news);
    // Create the submited news entry

    $doc_root_element->appendChild($new_news_entry);
    // Append submited news entry
    $xml_doc->appendChild($doc_root_element);

    save_news_file($xml_doc);

    header("Location: /cpanel/index.php?lang={$lang}&news-lang={$news_lang}");
}
else{
    header("Location: /cpanel/index.php?lang={$lang}&news-lang={$news_lang}");
}
?>
<?php ob_end_flush()?>

更新:使用您提供的有用答案,它已解决: 表单提交的值是非英文的,并且包含一些HTML实体, 我在 POST 上使用了htmlentities(),这使得非英文字符串无法读取。 将htmlentities() 替换为htmlspecialchars(),效果就像魔术一样。

结论:htmlentities() 可以破坏非英文字符串。

【问题讨论】:

  • 小心htmlspecialchars() - 我发现除了修复你的主要实体之外,它还可以稍微打击一些非Unicode字符(即ASCII/1252等价物)。 str_replace() 通常更安全 :)

标签: php xml encoding


【解决方案1】:

字符编码总是很麻烦。确保包含表单的页面、加载到 $dom 中的 xml 以及 php 文件本身也是 utf-8 编码的,或者进行相应的翻译。否则你的所有字符串都不会,并且将它们作为 utf-8 处理是行不通的。

试试这个:将原始新闻 XML 回显到空白页面上。然后在浏览器中切换页面编码,看看哪一种能正确显示字符。从表单中检索输入后,对 $news 重复此操作。这通常会提供有关编码出错的线索。

【讨论】:

  • 谢谢!我回应了新闻,结果是一堆乱七八糟的东西。添加新条目的过程在没有任何 HTML 的单独文件上执行,只有 PHP。我猜我需要以某种方式在该文件上设置编码。或者它也可能在 POST 中出错。
  • 好的,我还尝试在代码中为 $news 分配一个非英语字符串值,它的回声很好,我猜它没有通过 POST 正确传输。
  • Dean,为了保留字符编码,你所有的 php 文件也必须是 utf-8 格式,即 php 文件的编码必须相应设置。为 dom 和/或 xml 文件设置 utf-8 是不够的!
【解决方案2】:

如果不将应用程序拆开一点,就很难诊断出确切的问题,但这是一个很好的线索:

警告:DOMDocument::load() [domdocument.load]: 实体 'times' 未在文件路径中定义

XML 通常不喜欢像&amp;times; 这样的HTML 实体。唯一保证工作的实体是&amp;lt;&amp;gt;&amp;amp;&amp;quot;

改用数字实体。所以对于×,使用&amp;#xD7;等等。

您可以在致电html_entities 后添加一个快速而肮脏的技巧:

foreach(array('quot'=>34,'amp'=>38,'lt'=>60,'gt'=>62,'OElig'=>338,'oelig'=>339,
'Scaron'=>352,'scaron'=>353,'Yuml'=>376,'circ'=>710,'tilde'=>732,'ensp'=>8194,
'emsp'=>8195,'thinsp'=>8201,'zwnj'=>8204,'zwj'=>8205,'lrm'=>8206,'rlm'=>8207,
'ndash'=>8211,'mdash'=>8212,'lsquo'=>8216,'rsquo'=>8217,'sbquo'=>8218,'ldquo'=>8220,
'rdquo'=>8221,'bdquo'=>8222,'dagger'=>8224,'Dagger'=>8225,'permil'=>8240,'lsaquo'=>8249,
'rsaquo'=>8250,'euro'=>8364,'fnof'=>402,'Alpha'=>913,'Beta'=>914,'Gamma'=>915,
'Delta'=>916,'Epsilon'=>917,'Zeta'=>918,'Eta'=>919,'Theta'=>920,'Iota'=>921,
'Kappa'=>922,'Lambda'=>923,'Mu'=>924,'Nu'=>925,'Xi'=>926,'Omicron'=>927,
'Pi'=>928,'Rho'=>929,'Sigma'=>931,'Tau'=>932,'Upsilon'=>933,'Phi'=>934,
'Chi'=>935,'Psi'=>936,'Omega'=>937,'alpha'=>945,'beta'=>946,'gamma'=>947,
'delta'=>948,'epsilon'=>949,'zeta'=>950,'eta'=>951,'theta'=>952,'iota'=>953,
'kappa'=>954,'lambda'=>955,'mu'=>956,'nu'=>957,'xi'=>958,'omicron'=>959,
'pi'=>960,'rho'=>961,'sigmaf'=>962,'sigma'=>963,'tau'=>964,'upsilon'=>965,
'phi'=>966,'chi'=>967,'psi'=>968,'omega'=>969,'thetasym'=>977,'upsih'=>978,
'piv'=>982,'bull'=>8226,'hellip'=>8230,'prime'=>8242,'Prime'=>8243,'oline'=>8254,
'frasl'=>8260,'weierp'=>8472,'image'=>8465,'real'=>8476,'trade'=>8482,'alefsym'=>8501,
'larr'=>8592,'uarr'=>8593,'rarr'=>8594,'darr'=>8595,'harr'=>8596,'crarr'=>8629,
'lArr'=>8656,'uArr'=>8657,'rArr'=>8658,'dArr'=>8659,'hArr'=>8660,'forall'=>8704,
'part'=>8706,'exist'=>8707,'empty'=>8709,'nabla'=>8711,'isin'=>8712,'notin'=>8713,
'ni'=>8715,'prod'=>8719,'sum'=>8721,'minus'=>8722,'lowast'=>8727,'radic'=>8730,
'prop'=>8733,'infin'=>8734,'ang'=>8736,'and'=>8743,'or'=>8744,'cap'=>8745,
'cup'=>8746,'int'=>8747,'there4'=>8756,'sim'=>8764,'cong'=>8773,'asymp'=>8776,
'ne'=>8800,'equiv'=>8801,'le'=>8804,'ge'=>8805,'sub'=>8834,'sup'=>8835,
'nsub'=>8836,'sube'=>8838,'supe'=>8839,'oplus'=>8853,'otimes'=>8855,'perp'=>8869,
'sdot'=>8901,'lceil'=>8968,'rceil'=>8969,'lfloor'=>8970,'rfloor'=>8971,'lang'=>9001,
'rang'=>9002,'loz'=>9674,'spades'=>9824,'clubs'=>9827,'hearts'=>9829,'diams'=>9830,
'nbsp'=>160,'iexcl'=>161,'cent'=>162,'pound'=>163,'curren'=>164,'yen'=>165,
'brvbar'=>166,'sect'=>167,'uml'=>168,'copy'=>169,'ordf'=>170,'laquo'=>171,
'not'=>172,'shy'=>173,'reg'=>174,'macr'=>175,'deg'=>176,'plusmn'=>177,
'sup2'=>178,'sup3'=>179,'acute'=>180,'micro'=>181,'para'=>182,'middot'=>183,
'cedil'=>184,'sup1'=>185,'ordm'=>186,'raquo'=>187,'frac14'=>188,'frac12'=>189,
'frac34'=>190,'iquest'=>191,'Agrave'=>192,'Aacute'=>193,'Acirc'=>194,'Atilde'=>195,
'Auml'=>196,'Aring'=>197,'AElig'=>198,'Ccedil'=>199,'Egrave'=>200,'Eacute'=>201,
'Ecirc'=>202,'Euml'=>203,'Igrave'=>204,'Iacute'=>205,'Icirc'=>206,'Iuml'=>207,
'ETH'=>208,'Ntilde'=>209,'Ograve'=>210,'Oacute'=>211,'Ocirc'=>212,'Otilde'=>213,
'Ouml'=>214,'times'=>215,'Oslash'=>216,'Ugrave'=>217,'Uacute'=>218,'Ucirc'=>219,
'Uuml'=>220,'Yacute'=>221,'THORN'=>222,'szlig'=>223,'agrave'=>224,'aacute'=>225,
'acirc'=>226,'atilde'=>227,'auml'=>228,'aring'=>229,'aelig'=>230,'ccedil'=>231,
'egrave'=>232,'eacute'=>233,'ecirc'=>234,'euml'=>235,'igrave'=>236,'iacute'=>237,
'icirc'=>238,'iuml'=>239,'eth'=>240,'ntilde'=>241,'ograve'=>242,'oacute'=>243,
'ocirc'=>244,'otilde'=>245,'ouml'=>246,'divide'=>247,'oslash'=>248,'ugrave'=>249,
'uacute'=>250,'ucirc'=>251,'uuml'=>252,'yacute'=>253,'thorn'=>254,'yuml'=>255
) as $alpha=>$num)
$news=str_replace("&$alpha;", "&#$num;", $news);

您可以使用 preg_replacearray_map 做更有趣的事情,但这是您需要的数据。

或者,如果性能对您来说是个问题,您可以进行一些花哨的多字节字符检测并完全绕过命名实体步骤。 PHP网站上有很多例子。

严格来说,如果您已将 XML 文档标记为 utf8 编码,则可以完全放弃实体编码,只对四个主要部分进行编码:

$table = array('&' => '&amp;', '<' => '&lt;', '>' => '&gt;', '"' => '&quot;');
$news = str_replace(array_keys($table), array_values($table), $_POST["news"]);

n.

【讨论】:

  • 感谢您的提示。我的问题是,非英文字符从一开始就被写成实体,而我正在尝试编写文本。
  • 您可以使用我的答案中的数据将命名实体替换为数字实体,或者如果您对数学感到满意,则可以使用 UTF8 编码的 unicode。您必须与什么样的实体合作?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 2010-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
相关资源
最近更新 更多