## Entité externe

Cet exemple exploite les références externes de XML : il est possible d'utiliser un gestionnaire d'entité externe pour inclure et analyser les documents, tout comme les instructions exécutables peuvent servir à inclure et analyser d'autres documents, et aussi fournir une indication de confiance (voir plus bas).

Le document XML qui est utilisé dans cet exemple est fourni plus loin dans l'exemple (xmltest.xml et xmltest2.xml).

Exemple #1 Entité externe

    <?php
    $file = "xmltest.xml";

    function trustedFile($file)
    {
        // faites seulement confiance aux fichiers locaux dont vous êtes le propriétaire
        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;
                // si le document analysé est de confiance, nous déclarons qu'il est sûr
                // d'exécuter le code PHP qu'il contient. Si ce n'est pas le cas, le code est affiché
                // à la place.
                if (trustedFile($parser_file[$parser])) {
                    eval($data);
                } else {
                    printf("Untrusted PHP code: <i>%s</i>",
                            htmlspecialchars($data));
                }
                break;
        }
    }

    function defaultHandler($parser, $data)
    {
        if (substr($data, 0, 1) == "&" && substr($data, -1, 1) == ";") {
            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("Could not open entity %s at %s\n", $openEntityNames,
                       $systemId);
                return false;
            }
            while ($data = fread($fp, 4096)) {
                if (!xml_parse($parser, $data, feof($fp))) {
                    printf("XML error: %s at line %d while parsing entity %s\n",
                           xml_error_string(xml_get_error_code($parser)),
                           xml_get_current_line_number($parser), $openEntityNames);
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    function new_xml_parser($file)
    {
        global $parser_file;

        $xml_parser = xml_parser_create();
        xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 1);
        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("could not open XML input");
    }

    echo "<pre>";
    while ($data = fread($fp, 4096)) {
        if (!xml_parse($xml_parser, $data, feof($fp))) {
            die(sprintf("XML error: %s at line %d\n",
                        xml_error_string(xml_get_error_code($xml_parser)),
                        xml_get_current_line_number($xml_parser)));
        }
    }
    echo "</pre>";
    echo "parse complete\n";

    ?>

Exemple #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>

Ce fichier est inclus depuis xmltest.xml :

Exemple #3 xmltest2.xml

    <?xml version="1.0"?>
    <!DOCTYPE foo [
    <!ENTITY testEnt "test entity">
    ]>
    <foo>
       <element attrib="value"/>
       &testEnt;
       <?php echo "Ceci est du code PHP qui est exécuté."; ?>
    </foo>

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open