Подтвердить что ты не робот

Создание XML-документа в PHP (escape-символы)

Я создаю XML-документ из PHP скрипт, и мне нужно избежать специальных символов XML. Я знаю список символов, которые должны быть экранированы; но каков правильный способ сделать это?

Если символы будут экранированы только с помощью обратного слэша (\) или правильного пути? Есть ли встроенная функция PHP, которая может справиться с этим для меня?

4b9b3361

Ответ 1

Используйте классы DOM, чтобы сгенерировать весь XML-документ. Он будет обрабатывать кодировки и декодирования, о которых мы даже не хотим заботиться.


Изменить: Это критиковали @Tchalvak:

Объект DOM создает полный XML-документ, он не просто поддается просто кодировке собственной строки.

Что не так, DOMDocument может корректно выводить только фрагмент, а не весь документ:

$doc->saveXML($fragment);

который дает:

Test &amp; <b> and encode </b> :)
Test &amp;amp; &lt;b&gt; and encode &lt;/b&gt; :)

как в:

$doc = new DOMDocument();
$fragment = $doc->createDocumentFragment();

// adding XML verbatim:
$xml = "Test &amp; <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(
            "<" => "&lt;",
            ">" => "&gt;",
            '"' => "&quot;",
            "'" => "&apos;",
            "&" => "&amp;",
        )
    );
}

Пример использования Демо:

$text = "Test &amp; <b> and encode </b> :)";
echo xml_entities($text);

Вывод:

Test &amp;amp; &lt;b&gt; and encode &lt;/b&gt; :)

Аналогичный эффект может быть достигнут при использовании str_replace, но он хрупкий из-за двойной замены (непроверенный, не рекомендуется):

function xml_entities($string) {
    return str_replace(
        array("&",     "<",    ">",    '"',      "'"),
        array("&amp;", "&lt;", "&gt;", "&quot;", "&apos;"), 
        $string
    );
}

Ответ 3

Как насчет функции htmlspecialchars()?

htmlspecialchars($input, ENT_QUOTES | ENT_XML1, $encoding);

Примечание. флаг ENT_XML1 доступен только в том случае, если у вас есть PHP 5.4.0 или выше.

htmlspecialchars() с этими параметрами заменяет следующие символы:

  • & (амперсанд) становится &amp;
  • " (двойная кавычка) становится &quot;
  • ' (одинарная кавычка) становится &apos;
  • < (меньше) становится &lt;
  • > (больше) становится &gt;

Вы можете получить таблицу переводов с помощью функции get_html_translation_table().

Ответ 4

С трудом справлялся с проблемой XML-сущности, решив таким образом:

htmlspecialchars($value, ENT_QUOTES, 'UTF-8')

Ответ 5

Чтобы иметь действительный окончательный текст XML, вам нужно избежать всех объектов XML и иметь текст, написанный в той же кодировке, что и инструкция обработки документа XML, заявляет об этом ( "кодирование" в строке <?xml), Акцентированные символы не должны быть экранированы, если они закодированы как документ.

Однако во многих ситуациях простое экранирование ввода с помощью htmlspecialchars может привести к двойным кодированным объектам (например, &eacute; станет &amp;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;
}

Ответ 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('>','&gt', $arr1); 
  $arr[]=preg_replace('<','&lt', $arr1);
  $arr[]=preg_replace('"','&quot', $arr1);
  $arr[]=preg_replace('\'','&apos', $arr1);
  $arr[]=preg_replace('&','&amp', $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('/&/','&amp;', $arr1); // do this first
    }

    // just encode the
    if (strpos ($arr1,'>')!== FALSE) {
        $arr1=preg_replace('/>/','&gt;', $arr1);
    }
    if (strpos ($arr1,'<')!== FALSE) {
        $arr1=preg_replace('/</','&lt;', $arr1);
    }

    if (strpos ($arr1,'"')!== FALSE) {
        $arr1=preg_replace('/"/','&quot;', $arr1);
    }

    if (strpos ($arr1,'\'')!== FALSE) {
        $arr1=preg_replace('/\'/','&apos;', $arr1);
    }

    return $arr1;
}