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

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

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

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

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

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

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

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

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

Dom::createTextNode() автоматически 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> 

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

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

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

Только три или четыре символа должны быть экранированы в строке содержимого XML: > , < , & и необязательно " . Пожалуйста, прочтите http://www.w3.org/TR/REC-xml/ " 2.4. Данные символов и разметка »и« 4.6 Предопределенные объекты ». ТОГДА ВЫ можете использовать« 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.

Таким образом, ваш вопрос: «Результат htmlentities () гарантирован как совместимый с XML и UTF-8?» Ответ – нет, это не так.

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

Думаю, я добавлю это для тех, кто нуждается в дезинфекции и не потеряет атрибуты 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>