home *** CD-ROM | disk | FTP | other *** search
/ Enter 2004 June / ENTER.ISO / files / xampp-win32-1.4.5-installer.exe / xampp / Util.php < prev    next >
Encoding:
PHP Script  |  2004-03-24  |  20.5 KB  |  569 lines

  1. <?PHP
  2. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2002 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stephan Schmidt <schst@php-tools.net>                       |
  17. // +----------------------------------------------------------------------+
  18. //
  19. //    $Id: Util.php,v 1.15 2003/11/22 10:41:08 schst Exp $
  20.  
  21. /**
  22.  * uses PEAR errors
  23.  */
  24.     require_once 'PEAR.php';
  25.  
  26. /**
  27.  * error code for invalid chars in XML name
  28.  */
  29. define("XML_UTIL_ERROR_INVALID_CHARS", 51);
  30.  
  31. /**
  32.  * error code for invalid chars in XML name
  33.  */
  34. define("XML_UTIL_ERROR_INVALID_START", 52);
  35.  
  36. /**
  37.  * error code for non-scalar tag content
  38.  */
  39. define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
  40.     
  41. /**
  42.  * replace XML entities
  43.  */
  44. define("XML_UTIL_REPLACE_ENTITIES", 1);
  45.  
  46. /**
  47.  * embedd content in a CData Section
  48.  */
  49. define("XML_UTIL_CDATA_SECTION", 2);
  50.     
  51. /**
  52.  * utility class for working with XML documents
  53.  *
  54.  * @category XML
  55.  * @package  XML_Util
  56.  * @version  0.5.2
  57.  * @author   Stephan Schmidt <schst@php.net>
  58.  * @todo     method to get doctype declaration
  59.  */
  60. class XML_Util {
  61.  
  62.    /**
  63.     * return API version
  64.     *
  65.     * @access   public
  66.     * @static
  67.     * @return   string  $version API version
  68.     */
  69.     function apiVersion()
  70.     {
  71.         return "0.5.2";
  72.     }
  73.  
  74.    /**
  75.     * replace XML entities
  76.     *
  77.     * chars that have to be replaced are '&' and '<',
  78.     * furthermore '>', ''' and '"' have entities that can be used. 
  79.     *
  80.     * <code>
  81.     * require_once 'XML/Util.php';
  82.     * 
  83.     * // replace XML entites:
  84.     * $string = XML_Util::replaceEntities("This string contains < & >.");
  85.     * </code>
  86.     *
  87.     * @access   public
  88.     * @static
  89.     * @param    string  $string string where XML special chars should be replaced
  90.     * @return   string  $string string with replaced chars
  91.     * @todo     optional parameter to supply additional entities
  92.     */
  93.     function replaceEntities($string)
  94.     {
  95.         return strtr($string,array(
  96.                                   '&'  => '&',
  97.                                   '>'  => '>',
  98.                                   '<'  => '<',
  99.                                   '"'  => '"',
  100.                                   '\'' => ''' ));
  101.     }
  102.  
  103.    /**
  104.     * build an xml declaration
  105.     *
  106.     * <code>
  107.     * require_once 'XML/Util.php';
  108.     * 
  109.     * // get an XML declaration:
  110.     * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
  111.     * </code>
  112.     *
  113.     * @access   public
  114.     * @static
  115.     * @param    string  $version     xml version
  116.     * @param    string  $encoding    character encoding
  117.     * @param    boolean $standAlone  document is standalone (or not)
  118.     * @return   string  $decl xml declaration
  119.     * @uses     XML_Util::attributesToString() to serialize the attributes of the XML declaration
  120.     */
  121.     function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
  122.     {
  123.         $attributes = array(
  124.                             "version" => $version,
  125.                            );
  126.         // add encoding
  127.         if ($encoding !== null) {
  128.             $attributes["encoding"] = $encoding;
  129.         }
  130.         // add standalone, if specified
  131.         if ($standalone !== null) {
  132.             $attributes["standalone"] = $standalone ? "yes" : "no";
  133.         }
  134.         
  135.         return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
  136.     }
  137.  
  138.  
  139.    /**
  140.     * build a document type declaration
  141.     *
  142.     * <code>
  143.     * require_once 'XML/Util.php';
  144.     * 
  145.     * // get a doctype declaration:
  146.     * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
  147.     * </code>
  148.     *
  149.     * @access   public
  150.     * @static
  151.     * @param    string  $root         name of the root tag
  152.     * @param    string  $uri          uri of the doctype definition (or array with uri and public id)
  153.     * @param    string  $internalDtd  internal dtd entries   
  154.     * @return   string  $decl         doctype declaration
  155.     * @since    0.2
  156.     */
  157.     function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
  158.     {
  159.         if (is_array($uri)) {
  160.             $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
  161.         } elseif (!empty($uri)) {
  162.             $ref = sprintf( ' SYSTEM "%s"', $uri );
  163.         } else {
  164.             $ref = "";
  165.         }
  166.  
  167.         if (empty($internalDtd)) {
  168.             return sprintf("<!DOCTYPE %s%s>", $root, $ref);
  169.         } else {
  170.             return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  171.         }
  172.     }
  173.  
  174.    /**
  175.     * create string representation of an attribute list
  176.     *
  177.     * <code>
  178.     * require_once 'XML/Util.php';
  179.     * 
  180.     * // build an attribute string
  181.     * $att = array(
  182.     *              "foo"   =>  "bar",
  183.     *              "argh"  =>  "tomato"
  184.     *            );
  185.     *
  186.     * $attList = XML_Util::attributesToString($att);    
  187.     * </code>
  188.     *
  189.     * @access   public
  190.     * @static
  191.     * @param    array   $attributes  attribute array
  192.     * @param    boolean $sort        sort attribute list alphabetically
  193.     * @param    boolean $multiline   use linebreaks, if more than one attribute is given
  194.     * @param    string  $indent      string used for indentation of multiline attributes
  195.     * @param    string  $linebreak   string used for linebreaks of multiline attributes
  196.     * @return   string  $string      string representation of the attributes
  197.     * @uses     XML_Util::replaceEntities() to replace XML entities in attribute values
  198.     */
  199.     function attributesToString($attributes, $sort = true, $multiline = false, $indent = '    ', $linebreak = "\n")
  200.     {
  201.         $string = "";
  202.         if (is_array($attributes) && !empty($attributes)) {
  203.             if ($sort) {
  204.                 ksort($attributes);
  205.             }
  206.             if( !$multiline || count($attributes) == 1) {
  207.                 foreach ($attributes as $key => $value) {
  208.                     $string .= " ".$key.'="'.XML_Util::replaceEntities($value).'"';
  209.                 }
  210.             } else {
  211.                 $first = true;
  212.                 foreach ($attributes as $key => $value) {
  213.                     if ($first) {
  214.                         $string .= " ".$key.'="'.XML_Util::replaceEntities($value).'"';
  215.                         $first = false;
  216.                     } else {
  217.                         $string .= $linebreak.$indent.$key.'="'.XML_Util::replaceEntities($value).'"';
  218.                     }
  219.                 }
  220.             }
  221.         }
  222.         return $string;
  223.     }
  224.  
  225.    /**
  226.     * create a tag
  227.     *
  228.     * This method will call XML_Util::createTagFromArray(), which
  229.     * is more flexible.
  230.     *
  231.     * <code>
  232.     * require_once 'XML/Util.php';
  233.     * 
  234.     * // create an XML tag:
  235.     * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
  236.     * </code>
  237.     *
  238.     * @access   public
  239.     * @static
  240.     * @param    string  $qname             qualified tagname (including namespace)
  241.     * @param    array   $attributes        array containg attributes
  242.     * @param    mixed   $content
  243.     * @param    string  $namespaceUri      URI of the namespace
  244.     * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
  245.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  246.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  247.     * @param    string  $linebreak         string used for linebreaks
  248.     * @return   string  $string            XML tag
  249.     * @see      XML_Util::createTagFromArray()
  250.     * @uses     XML_Util::createTagFromArray() to create the tag
  251.     */
  252.     function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n")
  253.     {
  254.         $tag = array(
  255.                      "qname"      => $qname,
  256.                      "attributes" => $attributes
  257.                     );
  258.  
  259.         // add tag content
  260.         if ($content !== null) {
  261.             $tag["content"] = $content;
  262.         }
  263.         
  264.         // add namespace Uri
  265.         if ($namespaceUri !== null) {
  266.             $tag["namespaceUri"] = $namespaceUri;
  267.         }
  268.  
  269.         return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak);
  270.     }
  271.  
  272.    /**
  273.     * create a tag from an array
  274.     * this method awaits an array in the following format
  275.     * <pre>
  276.     * array(
  277.     *  "qname"        => $qname         // qualified name of the tag
  278.     *  "namespace"    => $namespace     // namespace prefix (optional, if qname is specified or no namespace)
  279.     *  "localpart"    => $localpart,    // local part of the tagname (optional, if qname is specified)
  280.     *  "attributes"   => array(),       // array containing all attributes (optional)
  281.     *  "content"      => $content,      // tag content (optional)
  282.     *  "namespaceUri" => $namespaceUri  // namespaceUri for the given namespace (optional)
  283.     *   )
  284.     * </pre>
  285.     *
  286.     * <code>
  287.     * require_once 'XML/Util.php';
  288.     * 
  289.     * $tag = array(
  290.     *           "qname"        => "foo:bar",
  291.     *           "namespaceUri" => "http://foo.com",
  292.     *           "attributes"   => array( "key" => "value", "argh" => "fruit&vegetable" ),
  293.     *           "content"      => "I'm inside the tag",
  294.     *            );
  295.     * // creating a tag with qualified name and namespaceUri
  296.     * $string = XML_Util::createTagFromArray($tag);
  297.     * </code>
  298.     *
  299.     * @access   public
  300.     * @static
  301.     * @param    array   $tag               tag definition
  302.     * @param    integer $replaceEntities   whether to replace XML special chars in content, embedd it in a CData section or none of both
  303.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  304.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  305.     * @param    string  $linebreak         string used for linebreaks
  306.     * @return   string  $string            XML tag
  307.     * @see      XML_Util::createTag()
  308.     * @uses     XML_Util::attributesToString() to serialize the attributes of the tag
  309.     * @uses     XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
  310.     */
  311.     function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n" )
  312.     {
  313.         if (isset($tag["content"]) && !is_scalar($tag["content"])) {
  314.             return PEAR::raiseError( "Supplied non-scalar value as tag content", XML_UTIL_ERROR_NON_SCALAR_CONTENT );
  315.         }
  316.  
  317.         // if no attributes hav been set, use empty attributes
  318.         if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
  319.             $tag["attributes"] = array();
  320.         }
  321.         
  322.         // qualified name is not given
  323.         if (!isset($tag["qname"])) {
  324.             // check for namespace
  325.             if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  326.                 $tag["qname"] = $tag["namespace"].":".$tag["localPart"];
  327.             } else {
  328.                 $tag["qname"] = $tag["localPart"];
  329.             }
  330.         // namespace URI is set, but no namespace
  331.         } elseif (isset($tag["namespaceUri"]) && !isset($tag["namespace"])) {
  332.             $parts = XML_Util::splitQualifiedName($tag["qname"]);
  333.             $tag["localPart"] = $parts["localPart"];
  334.             if (isset($parts["namespace"])) {
  335.                 $tag["namespace"] = $parts["namespace"];
  336.             }
  337.         }
  338.  
  339.         if (isset($tag["namespaceUri"]) && !empty($tag["namespaceUri"])) {
  340.             // is a namespace given
  341.             if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  342.                 $tag["attributes"]["xmlns:".$tag["namespace"]] = $tag["namespaceUri"];
  343.             } else {
  344.                 // define this Uri as the default namespace
  345.                 $tag["attributes"]["xmlns"] = $tag["namespaceUri"];
  346.             }
  347.         }
  348.  
  349.         // check for multiline attributes
  350.         if ($multiline === true) {
  351.             if ($indent === "_auto") {
  352.                 $indent = str_repeat(" ", (strlen($tag["qname"])+2));
  353.             }
  354.         }
  355.         
  356.         // create attribute list
  357.         $attList    =   XML_Util::attributesToString($tag["attributes"], true, $multiline, $indent, $linebreak );
  358.         if (!isset($tag["content"]) || (string)$tag["content"] == '') {
  359.             $tag    =   sprintf("<%s%s />", $tag["qname"], $attList);
  360.         } else {
  361.             if ($replaceEntities == XML_UTIL_REPLACE_ENTITIES) {
  362.                 $tag["content"] = XML_Util::replaceEntities($tag["content"]);
  363.             } elseif ($replaceEntities == XML_UTIL_CDATA_SECTION) {
  364.                 $tag["content"] = XML_Util::createCDataSection($tag["content"]);
  365.             }
  366.             $tag    =   sprintf("<%s%s>%s</%s>", $tag["qname"], $attList, $tag["content"], $tag["qname"] );
  367.         }        
  368.         return  $tag;
  369.     }
  370.  
  371.    /**
  372.     * create a start element
  373.     *
  374.     * <code>
  375.     * require_once 'XML/Util.php';
  376.     * 
  377.     * // create an XML start element:
  378.     * $tag = XML_Util::createStartElement("myNs:myTag", array("foo" => "bar") ,"http://www.w3c.org/myNs#");
  379.     * </code>
  380.     *
  381.     * @access   public
  382.     * @static
  383.     * @param    string  $qname             qualified tagname (including namespace)
  384.     * @param    array   $attributes        array containg attributes
  385.     * @param    string  $namespaceUri      URI of the namespace
  386.     * @param    boolean $multiline         whether to create a multiline tag where each attribute gets written to a single line
  387.     * @param    string  $indent            string used to indent attributes (_auto indents attributes so they start at the same column)
  388.     * @param    string  $linebreak         string used for linebreaks
  389.     * @return   string  $string            XML start element
  390.     * @see      XML_Util::createEndElement(), XML_Util::createTag()
  391.     */
  392.     function createStartElement($qname, $attributes = array(), $namespaceUri = null, $multiline = false, $indent = '_auto', $linebreak = "\n")
  393.     {
  394.         // if no attributes hav been set, use empty attributes
  395.         if (!isset($attributes) || !is_array($attributes)) {
  396.             $attributes = array();
  397.         }
  398.         
  399.         if ($namespaceUri != null) {
  400.             $parts = XML_Util::splitQualifiedName($qname);
  401.         }
  402.  
  403.         // check for multiline attributes
  404.         if ($multiline === true) {
  405.             if ($indent === "_auto") {
  406.                 $indent = str_repeat(" ", (strlen($qname)+2));
  407.             }
  408.         }
  409.  
  410.         if ($namespaceUri != null) {
  411.             // is a namespace given
  412.             if (isset($parts["namespace"]) && !empty($parts["namespace"])) {
  413.                 $attributes["xmlns:".$parts["namespace"]] = $namespaceUri;
  414.             } else {
  415.                 // define this Uri as the default namespace
  416.                 $attributes["xmlns"] = $namespaceUri;
  417.             }
  418.         }
  419.  
  420.         // create attribute list
  421.         $attList    =   XML_Util::attributesToString($attributes, true, $multiline, $indent, $linebreak);
  422.         $element    =   sprintf("<%s%s>", $qname, $attList);
  423.         return  $element;
  424.     }
  425.  
  426.    /**
  427.     * create an end element
  428.     *
  429.     * <code>
  430.     * require_once 'XML/Util.php';
  431.     * 
  432.     * // create an XML start element:
  433.     * $tag = XML_Util::createEndElement("myNs:myTag");
  434.     * </code>
  435.     *
  436.     * @access   public
  437.     * @static
  438.     * @param    string  $qname             qualified tagname (including namespace)
  439.     * @return   string  $string            XML end element
  440.     * @see      XML_Util::createStartElement(), XML_Util::createTag()
  441.     */
  442.     function createEndElement($qname)
  443.     {
  444.         $element    =   sprintf("</%s>", $qname);
  445.         return  $element;
  446.     }
  447.     
  448.    /**
  449.     * create an XML comment
  450.     *
  451.     * <code>
  452.     * require_once 'XML/Util.php';
  453.     * 
  454.     * // create an XML start element:
  455.     * $tag = XML_Util::createComment("I am a comment");
  456.     * </code>
  457.     *
  458.     * @access   public
  459.     * @static
  460.     * @param    string  $content           content of the comment
  461.     * @return   string  $comment           XML comment
  462.     */
  463.     function createComment($content)
  464.     {
  465.         $comment    =   sprintf("<!-- %s -->", $content);
  466.         return  $comment;
  467.     }
  468.     
  469.    /**
  470.     * create a CData section
  471.     *
  472.     * <code>
  473.     * require_once 'XML/Util.php';
  474.     * 
  475.     * // create a CData section
  476.     * $tag = XML_Util::createCDataSection("I am content.");
  477.     * </code>
  478.     *
  479.     * @access   public
  480.     * @static
  481.     * @param    string  $data              data of the CData section
  482.     * @return   string  $string            CData section with content
  483.     */
  484.     function createCDataSection($data)
  485.     {
  486.         return  sprintf("<![CDATA[%s]]>", $data);
  487.     }
  488.  
  489.    /**
  490.     * split qualified name and return namespace and local part
  491.     *
  492.     * <code>
  493.     * require_once 'XML/Util.php';
  494.     * 
  495.     * // split qualified tag
  496.     * $parts = XML_Util::splitQualifiedName("xslt:stylesheet");
  497.     * </code>
  498.     * the returned array will contain two elements:
  499.     * <pre>
  500.     * array(
  501.     *       "namespace" => "xslt",
  502.     *       "localPart" => "stylesheet"
  503.     *      );
  504.     * </pre>
  505.     *
  506.     * @access public
  507.     * @static
  508.     * @param  string    $qname      qualified tag name
  509.     * @param  string    $defaultNs  default namespace (optional)
  510.     * @return array     $parts      array containing namespace and local part
  511.     */
  512.     function splitQualifiedName($qname, $defaultNs = null)
  513.     {
  514.         if (strstr($qname, ':')) {
  515.             $tmp = explode(":", $qname);
  516.             return array(
  517.                           "namespace" => $tmp[0],
  518.                           "localPart" => $tmp[1]
  519.                         );
  520.         }
  521.         return array(
  522.                       "namespace" => $defaultNs,
  523.                       "localPart" => $qname
  524.                     );
  525.     }
  526.  
  527.    /**
  528.     * check, whether string is valid XML name
  529.     *
  530.     * <p>XML names are used for tagname, attribute names and various
  531.     * other, lesser known entities.</p>
  532.     * <p>An XML name may only consist of alphanumeric characters,
  533.     * dashes, undescores and periods, and has to start with a letter
  534.     * or an underscore.
  535.     * </p>
  536.     *
  537.     * <code>
  538.     * require_once 'XML/Util.php';
  539.     * 
  540.     * // verify tag name
  541.     * $result = XML_Util::isValidName("invalidTag?");
  542.     * if (XML_Util::isError($result)) {
  543.     *    print "Invalid XML name: " . $result->getMessage();
  544.     * }
  545.     * </code>
  546.     *
  547.     * @access  public
  548.     * @static
  549.     * @param   string  $string string that should be checked
  550.     * @return  mixed   $valid  true, if string is a valid XML name, PEAR error otherwise
  551.     * @todo    support for other charsets
  552.     */
  553.     function isValidName($string)
  554.     {
  555.         // check for invalid chars
  556.         if (!preg_match("/^[[:alnum:]_\-.]+$/", $string)) {
  557.             return PEAR::raiseError( "XML name may only contain alphanumeric chars, period, hyphen and underscore", XML_UTIL_ERROR_INVALID_CHARS );
  558.         }
  559.  
  560.         //  check for invalid starting character
  561.         if (!preg_match("/[[:alpha:]_]/", $string{0})) {
  562.             return PEAR::raiseError( "XML name may only start with letter or underscore", XML_UTIL_ERROR_INVALID_START );
  563.         }
  564.  
  565.         // XML name is valid
  566.         return true;
  567.     }
  568. }
  569. ?>