Создание XML-документа в PHP (escape-символы)
Я создаю XML-документ из PHP скрипт, и мне нужно избежать специальных символов XML.
Я знаю список символов, которые должны быть экранированы; но каков правильный способ сделать это?
Если символы будут экранированы только с помощью обратного слэша (\) или правильного пути?
Есть ли встроенная функция PHP, которая может справиться с этим для меня?
Ответы
Ответ 1
Используйте классы DOM, чтобы сгенерировать весь XML-документ. Он будет обрабатывать кодировки и декодирования, о которых мы даже не хотим заботиться.
Изменить: Это критиковали @Tchalvak:
Объект DOM создает полный XML-документ, он не просто поддается просто кодировке собственной строки.
Что не так, DOMDocument может корректно выводить только фрагмент, а не весь документ:
$doc->saveXML($fragment);
который дает:
Test & <b> and encode </b> :)
Test &amp; <b> and encode </b> :)
как в:
$doc = new DOMDocument();
$fragment = $doc->createDocumentFragment();
// adding XML verbatim:
$xml = "Test & <b> and encode </b> :)\n";
$fragment->appendXML($xml);
// adding text:
$text = $xml;
$fragment->appendChild($doc->createTextNode($text));
// output the result
echo $doc->saveXML($fragment);
Смотрите Демо
Ответ 2
Я создал простую функцию, которая ускользает от пяти "предопределенных сущностей" , которые находятся в XML:
function xml_entities($string) {
return strtr(
$string,
array(
"<" => "<",
">" => ">",
'"' => """,
"'" => "'",
"&" => "&",
)
);
}
Пример использования Демо:
$text = "Test & <b> and encode </b> :)";
echo xml_entities($text);
Вывод:
Test &amp; <b> and encode </b> :)
Аналогичный эффект может быть достигнут при использовании str_replace
, но он хрупкий из-за двойной замены (непроверенный, не рекомендуется):
function xml_entities($string) {
return str_replace(
array("&", "<", ">", '"', "'"),
array("&", "<", ">", """, "'"),
$string
);
}
Ответ 3
Как насчет функции htmlspecialchars()
?
htmlspecialchars($input, ENT_QUOTES | ENT_XML1, $encoding);
Примечание. флаг ENT_XML1
доступен только в том случае, если у вас есть PHP 5.4.0 или выше.
htmlspecialchars()
с этими параметрами заменяет следующие символы:
-
&
(амперсанд) становится &
-
"
(двойная кавычка) становится "
-
'
(одинарная кавычка) становится '
-
<
(меньше) становится <
-
>
(больше) становится >
Вы можете получить таблицу переводов с помощью функции get_html_translation_table()
.
Ответ 4
С трудом справлялся с проблемой XML-сущности, решив таким образом:
htmlspecialchars($value, ENT_QUOTES, 'UTF-8')
Ответ 5
Чтобы иметь действительный окончательный текст XML, вам нужно избежать всех объектов XML и иметь текст, написанный в той же кодировке, что и инструкция обработки документа XML, заявляет об этом ( "кодирование" в строке <?xml
), Акцентированные символы не должны быть экранированы, если они закодированы как документ.
Однако во многих ситуациях простое экранирование ввода с помощью htmlspecialchars
может привести к двойным кодированным объектам (например, é
станет &eacute;
), поэтому я предлагаю сначала декодировать html-объекты:
function xml_escape($s)
{
$s = html_entity_decode($s, ENT_QUOTES, 'UTF-8');
$s = htmlspecialchars($s, ENT_QUOTES, 'UTF-8', false);
return $s;
}
Теперь вам нужно убедиться, что все символы с акцентом действительны в кодировке XML-документа. Я настоятельно рекомендую всегда кодировать вывод XML в UTF-8, поскольку не все синтаксические анализаторы XML уважают кодировку XML-обработки документов. Если ваш ввод может быть получен из другой кодировки, попробуйте использовать utf8_encode()
.
В этом случае особый случай, который может быть получен из одного из этих кодировок: ISO-8859-1, ISO-8859-15, UTF-8, cp866, cp1251, cp1252 и KOI8-R-PHP они все равно, но в них есть небольшие различия, некоторые из которых даже iconv()
не могут справиться. Я мог решить эту проблему только путем дополнения поведения utf8_encode()
:
function encode_utf8($s)
{
$cp1252_map = array(
"\xc2\x80" => "\xe2\x82\xac",
"\xc2\x82" => "\xe2\x80\x9a",
"\xc2\x83" => "\xc6\x92",
"\xc2\x84" => "\xe2\x80\x9e",
"\xc2\x85" => "\xe2\x80\xa6",
"\xc2\x86" => "\xe2\x80\xa0",
"\xc2\x87" => "\xe2\x80\xa1",
"\xc2\x88" => "\xcb\x86",
"\xc2\x89" => "\xe2\x80\xb0",
"\xc2\x8a" => "\xc5\xa0",
"\xc2\x8b" => "\xe2\x80\xb9",
"\xc2\x8c" => "\xc5\x92",
"\xc2\x8e" => "\xc5\xbd",
"\xc2\x91" => "\xe2\x80\x98",
"\xc2\x92" => "\xe2\x80\x99",
"\xc2\x93" => "\xe2\x80\x9c",
"\xc2\x94" => "\xe2\x80\x9d",
"\xc2\x95" => "\xe2\x80\xa2",
"\xc2\x96" => "\xe2\x80\x93",
"\xc2\x97" => "\xe2\x80\x94",
"\xc2\x98" => "\xcb\x9c",
"\xc2\x99" => "\xe2\x84\xa2",
"\xc2\x9a" => "\xc5\xa1",
"\xc2\x9b" => "\xe2\x80\xba",
"\xc2\x9c" => "\xc5\x93",
"\xc2\x9e" => "\xc5\xbe",
"\xc2\x9f" => "\xc5\xb8"
);
$s=strtr(utf8_encode($s), $cp1252_map);
return $s;
}
Ответ 6
Если вам нужен правильный вывод xml, simplexml - это способ:
http://www.php.net/manual/en/simplexmlelement.asxml.php
Ответ 7
Правильное экранирование - это способ получить правильный вывод XML, но вам нужно обработать экранирование по-разному для атрибутов и элементов. (То есть ответ Томаса неверен).
Я написал/украл некоторый Java-код, который отличается от атрибута и escape-элементов элементов. Причина в том, что синтаксический анализатор XML рассматривает все специальные пробелы, особенно в атрибутах.
Это должно быть тривиально переносить это на PHP (вы можете использовать подход Томаса Янчика с вышеупомянутым соответствующим экранированием). Вам не нужно беспокоиться об экранировании расширенных объектов, если вы используете UTF-8
.
Если вы не хотите переносить мой код Java, вы можете посмотреть XMLWriter, который основан на потоке и использует libxml, поэтому он должен быть очень эффективным.
Ответ 8
Вы можете использовать следующие методы:
http://php.net/manual/en/function.htmlentities.php
Таким образом, все объекты (html/xml) экранированы, и вы можете поместить свою строку в теги XML
Ответ 9
function replace_char($arr1)
{
$arr[]=preg_replace('>','>', $arr1);
$arr[]=preg_replace('<','<', $arr1);
$arr[]=preg_replace('"','"', $arr1);
$arr[]=preg_replace('\'','&apos', $arr1);
$arr[]=preg_replace('&','&', $arr1);
return $arr;
}
Ответ 10
На основе решения sadeghj для меня работал следующий код:
/**
* @param $arr1 the single string that shall be masked
* @return the resulting string with the masked characters
*/
function replace_char($arr1)
{
if (strpos ($arr1,'&')!== FALSE) { //test if the character appears
$arr1=preg_replace('/&/','&', $arr1); // do this first
}
// just encode the
if (strpos ($arr1,'>')!== FALSE) {
$arr1=preg_replace('/>/','>', $arr1);
}
if (strpos ($arr1,'<')!== FALSE) {
$arr1=preg_replace('/</','<', $arr1);
}
if (strpos ($arr1,'"')!== FALSE) {
$arr1=preg_replace('/"/','"', $arr1);
}
if (strpos ($arr1,'\'')!== FALSE) {
$arr1=preg_replace('/\'/',''', $arr1);
}
return $arr1;
}