Пример использования внешних сущностей XML


Этот пример подсвечивает код XML. Он иллюстрирует то, как необходимо использовать обработчик ссылки на внешнюю сущность для подключения и разбора содержимого внешних файлов, так же как может быть обработан PI, и путь для определения "доверия" к коду, содержащемуся в PI.

XML документы, которые используются в примере расположены под самим примером (xmltest.xml и xmltest2.xml.)

Пример #1 Пример использования внешней сущности

<?php
$file 
"xmltest.xml";

function 
trustedFile($file
{
    
// доверять только нашим собственным локальным файлам
    
if (!preg_match("@^([a-z][a-z0-9+.-]*)\:\/\/@i"$file
        && 
fileowner($file) == getmyuid()) {
            return 
true;
    }
    return 
false;
}

function 
startElement($parser$name$attribs
{
    echo 
"&lt;<font color=\"#0000cc\">$name</font>";
    if (
count($attribs)) {
        foreach (
$attribs as $k => $v) {
            echo 
" <font color=\"#009900\">$k</font>=\"<font 
                   color=\"#990000\">
$v</font>\"";
        }
    }
    echo 
"&gt;";
}

function 
endElement($parser$name
{
    echo 
"&lt;/<font color=\"#0000cc\">$name</font>&gt;";
}

function 
characterData($parser$data
{
    echo 
"<b>$data</b>";
}

function 
PIHandler($parser$target$data
{
    switch (
strtolower($target)) {
        case 
"php":
            global 
$parser_file;
            
// Если обработанный документ является "доверенным", то можно сказать,
            // что запуск расположенного в нем кода является безопасным. Если нет,
            // то вместо запуска отобразить сам код.
            
if (trustedFile($parser_file[$parser])) {
                eval(
$data);
            } else {
                
printf("Небезопасный код PHP: <i>%s</i>"
                        
htmlspecialchars($data));
            }
            break;
    }
}

function 
defaultHandler($parser$data
{
    if (
substr($data01) == "&" && substr($data, -11) == ";") {
        
printf('<font color="#aa00aa">%s</font>'
                
htmlspecialchars($data));
    } else {
        
printf('<font size="-1">%s</font>'
                
htmlspecialchars($data));
    }
}

function 
externalEntityRefHandler($parser$openEntityNames$base$systemId,
                                  
$publicId) {
    if (
$systemId) {
        if (!list(
$parser$fp) = new_xml_parser($systemId)) {
            
printf("Невозможно открыть сущность %s в %s\n"$openEntityNames,
                   
$systemId);
            return 
false;
        }
        while (
$data fread($fp4096)) {
            if (!
xml_parse($parser$datafeof($fp))) {
                
printf("Ошибка XML: %s в строке %d в процессе разбора сущности %s\n",
                       
xml_error_string(xml_get_error_code($parser)),
                       
xml_get_current_line_number($parser), $openEntityNames);
                
xml_parser_free($parser);
                return 
false;
            }
        }
        
xml_parser_free($parser);
        return 
true;
    }
    return 
false;
}

function 
new_xml_parser($file
{
    global 
$parser_file;

    
$xml_parser xml_parser_create();
    
xml_parser_set_option($xml_parserXML_OPTION_CASE_FOLDING1);
    
xml_set_element_handler($xml_parser"startElement""endElement");
    
xml_set_character_data_handler($xml_parser"characterData");
    
xml_set_processing_instruction_handler($xml_parser"PIHandler");
    
xml_set_default_handler($xml_parser"defaultHandler");
    
xml_set_external_entity_ref_handler($xml_parser"externalEntityRefHandler");
    
    if (!(
$fp = @fopen($file"r"))) {
        return 
false;
    }
    if (!
is_array($parser_file)) {
        
settype($parser_file"array");
    }
    
$parser_file[$xml_parser] = $file;
    return array(
$xml_parser$fp);
}

if (!(list(
$xml_parser$fp) = new_xml_parser($file))) {
    die(
"Чтение XML-файла невозможно");
}

echo 
"<pre>";
while (
$data fread($fp4096)) {
    if (!
xml_parse($xml_parser$datafeof($fp))) {
        die(
sprintf("Ошибка XML: %s в строке %d\n",
                    
xml_error_string(xml_get_error_code($xml_parser)),
                    
xml_get_current_line_number($xml_parser)));
    }
}
echo 
"</pre>";
echo 
"разбор завершен\n";
xml_parser_free($xml_parser);

?>

Пример #2 xmltest.xml

<?xml version='1.0'?> <!DOCTYPE chapter SYSTEM "/just/a/test.dtd" [ <!ENTITY plainEntity "FOO entity"> <!ENTITY systemEntity SYSTEM "xmltest2.xml"> ]> <chapter>  <TITLE>Title &plainEntity;</TITLE>  <para>   <informaltable>    <tgroup cols="3">     <tbody>      <row><entry>a1</entry><entry morerows="1">b1</entry><entry>c1</entry></row>      <row><entry>a2</entry><entry>c2</entry></row>      <row><entry>a3</entry><entry>b3</entry><entry>c3</entry></row>     </tbody>    </tgroup>   </informaltable>  </para>  &systemEntity;  <section id="about">   <title>About this Document</title>   <para>    <!-- this is a comment -->    <?php echo 'Hi!  This is PHP version ' . phpversion(); ?>   </para>  </section> </chapter>

Этот файл подключен из xmltest.xml:

Пример #3 xmltest2.xml

<?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY testEnt "test entity"> ]> <foo>    <element attrib="value"/>    &testEnt;    <?php echo "Здесь запущен некий код PHP"; ?> </foo>