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

PHP. Является ли htmlentities() достаточным для создания xml-безопасных значений?

Я создаю XML файл с нуля и должен знать, преобразует ли htmlentities() каждый символ, который может потенциально разорвать файл XML (и, возможно, данные UTF-8)? Значения будут взяты из твиттера /flickr, поэтому я должен быть уверен!

4b9b3361

Ответ 1

htmlentities() не гарантированный способ создания легального XML.

Используйте htmlspecialchars() вместо htmlentities(), если это все, о чем вы беспокоитесь. Если у вас есть несоответствия в кодировании между представлением ваших данных и кодировкой вашего XML-документа, htmlentities() может работать, чтобы обойти/закрыть их (при этом он будет раздувать ваш размер XML). Я считаю, что лучше кодировать кодировки и использовать htmlspecialchars().

Кроме того, имейте в виду, что если вы набрасываете возвращаемое значение htmlspecialchars() внутри атрибутов XML, разделенных одинарными кавычками, вам нужно будет передать флаг ENT_QUOTES, чтобы все кавычки в исходной строке были правильно закодированы также. Я предлагаю сделать это в любом случае, так как это делает ваш код невосприимчивым к ошибкам, возникающим у кого-то, использующего одинарные кавычки для атрибутов XML в будущем.

Изменить: Чтобы уточнить:

htmlentities() преобразует несколько символов, отличных от ANSI (я предполагаю, что это то, что вы подразумеваете под данными UTF-8), для сущностей (которые представлены только символами ANSI). Однако он не может сделать это для любых символов, у которых нет соответствующего объекта, и поэтому не может гарантировать, что его возвращаемое значение состоит только из символов ANSI. Вот почему я предлагаю не использовать его.

Если кодировка является возможной проблемой, обработайте ее явно (например, с помощью iconv()).

Изменить 2. Улучшенный ответ с учетом комментария Джоша Дэвиса ниже.

Ответ 2

Dom::createTextNode() автоматически удалит ваш контент.

Пример:

$dom = new DOMDocument;
$element = $dom->createElement('Element');
$element->appendChild(
    $dom->createTextNode('I am text with Ünicödé & HTML €ntities ©'));

$dom->appendChild($element);
echo $dom->saveXml();

Вывод:

<?xml version="1.0"?>
<Element>I am text with &#xDC;nic&#xF6;d&#xE9; &amp; HTML &#x20AC;ntities &#xA9;</Element>

Когда вы устанавливаете внутреннюю кодировку в utf-8, например

$dom->encoding = 'utf-8';

вы все равно получите

<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé &amp; HTML €ntities ©</Element>

Обратите внимание, что приведенное выше не то же самое, что установка второго аргумента $value в Dom::createElement(). Метод будет только убедиться, что имена ваших элементов действительны. См. Примечания на странице руководства, например

$dom = new DOMDocument;
$element = $dom->createElement('Element', 'I am text with Ünicödé & HTML €ntities ©');
$dom->appendChild($element);
$dom->encoding = 'utf-8';
echo $dom->saveXml();

приведет к предупреждению

Warning: DOMDocument::createElement(): unterminated entity reference  HTML €ntities ©

и следующий вывод:

<?xml version="1.0" encoding="utf-8"?>
<Element>I am text with Ünicödé </Element>

Ответ 3

Ответ Gordon хорош и объясняет проблемы с кодировкой XML, но не показывает простую функцию (или то, что делает черный ящик). Джон отвечает хорошо, предлагая рекомендацию функции "htmlspecialchars", но он и другие делают какую-то ошибку, затем я буду настойчивее.

Хороший программист ДОЛЖЕН иметь контроль над использованием или отсутствием UTF-8 в ваших строках и XML-данных: UTF-8 (или другой не-ASCII-код) IS SAFE в согласованном алгоритме.

БЕЗОПАСНЫЙ UTF-8 XML НЕ НУЖЕН ПОЛНЫЙ ENCODE ENCODE. Неизбирательное кодирование создает "второй класс, не-человеческий, кодированный/декодированный запрос, XML". И безопасный ASCII XML, также не требует кодирования сущности, когда весь ваш контент ASCII.

В строке XML-содержимого необходимо экранировать только 3 или 4 символа: >, <, & и необязательный ". Пожалуйста, прочитайте http://www.w3.org/TR/REC-xml/ "2.4 Character Data and Markup" и "4.6 Predefined Entities". ТОГДА ВЫ можете использовать htmlentities '

Для иллюстрации следующая PHP-функция сделает XML полностью безопасным:

// it is a didactic illustration, USE htmlentities($S,flag)
function xmlsafe($s,$intoQuotes=0) {
if ($intoQuotes)
    return str_replace(array('&','>','<','"'), array('&amp;','&gt;','&lt;','&quot;'), $s);
    // SAME AS htmlspecialchars($s)
else
    return str_replace(array('&','>','<'), array('&amp;','&gt;','&lt;'), $s);
    // SAME AS htmlspecialchars($s,ENT_NOQUOTES)
}

// example of SAFE XML CONSTRUCTION
function xmlTag( $element, $attribs, $contents = NULL) {
$out = '<' . $element;
foreach( $attribs as $name => $val )
   $out .= ' '.$name.'="'. xmlsafe( $val,1 ) .'"';
if ( $contents==='' || is_null($contents) )
    $out .= '/>';
else
    $out .= '>'.xmlsafe( $contents )."</$element>";
return $out;
}

В блоке CDATA вам не нужно использовать эту функцию... Но, пожалуйста, избегайте неизбирательного использования CDATA.

Ответ 4

Итак, ваш вопрос: "является ли результат htmlentities() гарантированным XML-совместимым и совместимым с UTF-8?" Ответ - нет, это не так.

htmlspecialchars() должно быть достаточно, чтобы избежать специальных символов XML, но вам придется санировать ваши строки UTF-8 в любом случае. Даже если вы создадите свой XML с помощью, скажем, SimpleXML, вам придется санировать строки. Я не знаю о других librairies, таких как XMLWriter или DOM, я думаю, что это то же самое.

Ответ 5

Думаю, я добавлю это для тех, кто нуждается в дезинфекции и не потеряет атрибуты XML.

// Returns SimpleXML Safe XML keeping the elements attributes as well
function sanitizeXML($xml_content, $xml_followdepth=true){

    if (preg_match_all('%<((\w+)\s?.*?)>(.+?)</\2>%si', $xml_content, $xmlElements, PREG_SET_ORDER)) {

        $xmlSafeContent = '';

        foreach($xmlElements as $xmlElem){
            $xmlSafeContent .= '<'.$xmlElem['1'].'>';
            if (preg_match('%<((\w+)\s?.*?)>(.+?)</\2>%si', $xmlElem['3'])) {
                $xmlSafeContent .= sanitizeXML($xmlElem['3'], false);
            }else{
                $xmlSafeContent .= htmlspecialchars($xmlElem['3'],ENT_NOQUOTES);
            }
            $xmlSafeContent .= '</'.$xmlElem['2'].'>';
        }

        if(!$xml_followdepth)
            return $xmlSafeContent;
        else
            return "<?xml version='1.0' encoding='UTF-8'?>".$xmlSafeContent;

    } else {
        return htmlspecialchars($xml_content,ENT_NOQUOTES);
    }

}

Применение:

$body = <<<EG
<?xml version='1.0' encoding='UTF-8'?>
<searchResult count="1">
   <item>
      <title>2016 & Au Rendez-Vous Des Enfoir&</title>
   </item>
</searchResult>
EG;
$newXml = sanitizeXML($body);
var_dump($newXml);

Возврат:

<?xml version='1.0' encoding='UTF-8'?>
<searchResult count="1">
    <item>
        <title>2016 &amp; Au Rendez-Vous Des Enfoir&amp;</title>
    </item>
</searchResult>