Bearsampp 2026.9.23
Loading...
Searching...
No Matches
Util.php
Go to the documentation of this file.
1<?php
46
50define('XML_UTIL_ERROR_INVALID_CHARS', 51);
51
55define('XML_UTIL_ERROR_INVALID_START', 52);
56
60define('XML_UTIL_ERROR_NON_SCALAR_CONTENT', 60);
61
65define('XML_UTIL_ERROR_NO_TAG_NAME', 61);
66
70define('XML_UTIL_REPLACE_ENTITIES', 1);
71
75define('XML_UTIL_CDATA_SECTION', 5);
76
80define('XML_UTIL_ENTITIES_NONE', 0);
81
86define('XML_UTIL_ENTITIES_XML', 1);
87
92define('XML_UTIL_ENTITIES_XML_REQUIRED', 2);
93
98define('XML_UTIL_ENTITIES_HTML', 3);
99
103define('XML_UTIL_COLLAPSE_NONE', 0);
104
108define('XML_UTIL_COLLAPSE_ALL', 1);
109
113define('XML_UTIL_COLLAPSE_XHTML_ONLY', 2);
114
127{
133 public static function apiVersion()
134 {
135 return '1.4';
136 }
137
176 public static function replaceEntities(
177 $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
178 ) {
179 switch ($replaceEntities) {
181 return strtr(
182 $string,
183 array(
184 '&' => '&amp;',
185 '>' => '&gt;',
186 '<' => '&lt;',
187 '"' => '&quot;',
188 '\'' => '&apos;'
189 )
190 );
191 break;
193 return strtr(
194 $string,
195 array(
196 '&' => '&amp;',
197 '<' => '&lt;',
198 '"' => '&quot;'
199 )
200 );
201 break;
203 return htmlentities($string, ENT_COMPAT, $encoding);
204 break;
205 }
206 return $string;
207 }
208
248 public static function reverseEntities(
249 $string, $replaceEntities = XML_UTIL_ENTITIES_XML, $encoding = 'ISO-8859-1'
250 ) {
251 switch ($replaceEntities) {
253 return strtr(
254 $string,
255 array(
256 '&amp;' => '&',
257 '&gt;' => '>',
258 '&lt;' => '<',
259 '&quot;' => '"',
260 '&apos;' => '\''
261 )
262 );
263 break;
265 return strtr(
266 $string,
267 array(
268 '&amp;' => '&',
269 '&lt;' => '<',
270 '&quot;' => '"'
271 )
272 );
273 break;
275 return html_entity_decode($string, ENT_COMPAT, $encoding);
276 break;
277 }
278 return $string;
279 }
280
299 public static function getXMLDeclaration(
300 $version = '1.0', $encoding = null, $standalone = null
301 ) {
302 $attributes = array(
303 'version' => $version,
304 );
305 // add encoding
306 if ($encoding !== null) {
307 $attributes['encoding'] = $encoding;
308 }
309 // add standalone, if specified
310 if ($standalone !== null) {
311 $attributes['standalone'] = $standalone ? 'yes' : 'no';
312 }
313
314 return sprintf(
315 '<?xml%s?>',
316 XML_Util::attributesToString($attributes, false)
317 );
318 }
319
338 public static function getDocTypeDeclaration(
339 $root, $uri = null, $internalDtd = null
340 ) {
341 if (is_array($uri)) {
342 $ref = sprintf(' PUBLIC "%s" "%s"', $uri['id'], $uri['uri']);
343 } elseif (!empty($uri)) {
344 $ref = sprintf(' SYSTEM "%s"', $uri);
345 } else {
346 $ref = '';
347 }
348
349 if (empty($internalDtd)) {
350 return sprintf('<!DOCTYPE %s%s>', $root, $ref);
351 } else {
352 return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
353 }
354 }
355
392 public static function attributesToString(
393 $attributes, $sort = true, $multiline = false,
394 $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML
395 ) {
396 /*
397 * second parameter may be an array
398 */
399 if (is_array($sort)) {
400 if (isset($sort['multiline'])) {
401 $multiline = $sort['multiline'];
402 }
403 if (isset($sort['indent'])) {
404 $indent = $sort['indent'];
405 }
406 if (isset($sort['linebreak'])) {
407 $multiline = $sort['linebreak'];
408 }
409 if (isset($sort['entities'])) {
410 $entities = $sort['entities'];
411 }
412 if (isset($sort['sort'])) {
413 $sort = $sort['sort'];
414 } else {
415 $sort = true;
416 }
417 }
418 $string = '';
419 if (is_array($attributes) && !empty($attributes)) {
420 if ($sort) {
421 ksort($attributes);
422 }
423 if (!$multiline || count($attributes) == 1) {
424 foreach ($attributes as $key => $value) {
425 if ($entities != XML_UTIL_ENTITIES_NONE) {
426 if ($entities === XML_UTIL_CDATA_SECTION) {
427 $entities = XML_UTIL_ENTITIES_XML;
428 }
429 $value = XML_Util::replaceEntities($value, $entities);
430 }
431 $string .= ' ' . $key . '="' . $value . '"';
432 }
433 } else {
434 $first = true;
435 foreach ($attributes as $key => $value) {
436 if ($entities != XML_UTIL_ENTITIES_NONE) {
437 $value = XML_Util::replaceEntities($value, $entities);
438 }
439 if ($first) {
440 $string .= ' ' . $key . '="' . $value . '"';
441 $first = false;
442 } else {
443 $string .= $linebreak . $indent . $key . '="' . $value . '"';
444 }
445 }
446 }
447 }
448 return $string;
449 }
450
460 public static function collapseEmptyTags($xml, $mode = XML_UTIL_COLLAPSE_ALL)
461 {
462 if (preg_match('~<([^>])+/>~s', $xml, $matches)) {
463 // it's already an empty tag
464 return $xml;
465 }
466 switch ($mode) {
468 $preg1 =
469 '~<' .
470 '(?:' .
471 '(https?://[^:\s]+:\w+)' . // <http://foo.com:bar ($1)
472 '|(\w+:\w+)' . // <foo:bar ($2)
473 '|(\w+)' . // <foo ($3)
474 ')+' .
475 '([^>]*)' . // attributes ($4)
476 '>' .
477 '<\/(\1|\2|\3)>' . // 1, 2, or 3 again ($5)
478 '~s'
479 ;
480 $preg2 =
481 '<' .
482 '${1}${2}${3}' . // tag (only one should have been populated)
483 '${4}' . // attributes
484 ' />'
485 ;
486 return (preg_replace($preg1, $preg2, $xml)?:$xml);
487 break;
489 return (
490 preg_replace(
491 '/<(area|base(?:font)?|br|col|frame|hr|img|input|isindex|link|meta|'
492 . 'param)([^>]*)><\/\\1>/s',
493 '<\\1\\2 />',
494 $xml
495 ) ?: $xml
496 );
497 break;
499 // fall thru
500 default:
501 return $xml;
502 }
503 }
504
541 public static function createTag(
542 $qname, $attributes = array(), $content = null,
543 $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
544 $multiline = false, $indent = '_auto', $linebreak = "\n",
545 $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
546 ) {
547 $tag = array(
548 'qname' => $qname,
549 'attributes' => $attributes
550 );
551
552 // add tag content
553 if ($content !== null) {
554 $tag['content'] = $content;
555 }
556
557 // add namespace Uri
558 if ($namespaceUri !== null) {
559 $tag['namespaceUri'] = $namespaceUri;
560 }
561
563 $tag, $replaceEntities, $multiline,
564 $indent, $linebreak, $sortAttributes,
565 $collapseTagMode
566 );
567 }
568
629 public static function createTagFromArray(
630 $tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES,
631 $multiline = false, $indent = '_auto', $linebreak = "\n",
632 $sortAttributes = true, $collapseTagMode = XML_UTIL_COLLAPSE_ALL
633 ) {
634 if (isset($tag['content']) && !is_scalar($tag['content'])) {
636 'Supplied non-scalar value as tag content',
638 );
639 }
640
641 if (!isset($tag['qname']) && !isset($tag['localPart'])) {
643 'You must either supply a qualified name '
644 . '(qname) or local tag name (localPart).',
646 );
647 }
648
649 // if no attributes hav been set, use empty attributes
650 if (!isset($tag['attributes']) || !is_array($tag['attributes'])) {
651 $tag['attributes'] = array();
652 }
653
654 if (isset($tag['namespaces'])) {
655 foreach ($tag['namespaces'] as $ns => $uri) {
656 $tag['attributes']['xmlns:' . $ns] = $uri;
657 }
658 }
659
660 if (!isset($tag['qname'])) {
661 // qualified name is not given
662
663 // check for namespace
664 if (isset($tag['namespace']) && !empty($tag['namespace'])) {
665 $tag['qname'] = $tag['namespace'] . ':' . $tag['localPart'];
666 } else {
667 $tag['qname'] = $tag['localPart'];
668 }
669 } elseif (isset($tag['namespaceUri']) && !isset($tag['namespace'])) {
670 // namespace URI is set, but no namespace
671
672 $parts = XML_Util::splitQualifiedName($tag['qname']);
673
674 $tag['localPart'] = $parts['localPart'];
675 if (isset($parts['namespace'])) {
676 $tag['namespace'] = $parts['namespace'];
677 }
678 }
679
680 if (isset($tag['namespaceUri']) && !empty($tag['namespaceUri'])) {
681 // is a namespace given
682 if (isset($tag['namespace']) && !empty($tag['namespace'])) {
683 $tag['attributes']['xmlns:' . $tag['namespace']]
684 = $tag['namespaceUri'];
685 } else {
686 // define this Uri as the default namespace
687 $tag['attributes']['xmlns'] = $tag['namespaceUri'];
688 }
689 }
690
691 if (!array_key_exists('content', $tag)) {
692 $tag['content'] = '';
693 }
694
695 // check for multiline attributes
696 if ($multiline === true) {
697 if ($indent === '_auto') {
698 $indent = str_repeat(' ', (strlen($tag['qname'])+2));
699 }
700 }
701
702 // create attribute list
704 $tag['attributes'],
705 $sortAttributes, $multiline, $indent, $linebreak
706 );
707
708 switch ($replaceEntities) {
710 break;
712 $tag['content'] = XML_Util::createCDataSection($tag['content']);
713 break;
714 default:
715 $tag['content'] = XML_Util::replaceEntities(
716 $tag['content'], $replaceEntities
717 );
718 break;
719 }
720 $tag = sprintf(
721 '<%s%s>%s</%s>', $tag['qname'], $attList, $tag['content'],
722 $tag['qname']
723 );
724
725 return self::collapseEmptyTags($tag, $collapseTagMode);
726 }
727
752 public static function createStartElement(
753 $qname, $attributes = array(), $namespaceUri = null,
754 $multiline = false, $indent = '_auto', $linebreak = "\n",
755 $sortAttributes = true
756 ) {
757 // if no attributes hav been set, use empty attributes
758 if (!isset($attributes) || !is_array($attributes)) {
759 $attributes = array();
760 }
761
762 if ($namespaceUri != null) {
763 $parts = XML_Util::splitQualifiedName($qname);
764 }
765
766 // check for multiline attributes
767 if ($multiline === true) {
768 if ($indent === '_auto') {
769 $indent = str_repeat(' ', (strlen($qname)+2));
770 }
771 }
772
773 if ($namespaceUri != null) {
774 // is a namespace given
775 if (isset($parts['namespace']) && !empty($parts['namespace'])) {
776 $attributes['xmlns:' . $parts['namespace']] = $namespaceUri;
777 } else {
778 // define this Uri as the default namespace
779 $attributes['xmlns'] = $namespaceUri;
780 }
781 }
782
783 // create attribute list
785 $attributes, $sortAttributes,
786 $multiline, $indent, $linebreak
787 );
788 $element = sprintf('<%s%s>', $qname, $attList);
789 return $element;
790 }
791
807 public static function createEndElement($qname)
808 {
809 $element = sprintf('</%s>', $qname);
810 return $element;
811 }
812
827 public static function createComment($content)
828 {
829 $comment = sprintf('<!-- %s -->', $content);
830 return $comment;
831 }
832
847 public static function createCDataSection($data)
848 {
849 return sprintf(
850 '<![CDATA[%s]]>',
851 preg_replace('/\‍]\‍]>/', ']]]]><![CDATA[>', strval($data))
852 );
853 }
854
877 public static function splitQualifiedName($qname, $defaultNs = null)
878 {
879 if (strstr($qname, ':')) {
880 $tmp = explode(':', $qname);
881 return array(
882 'namespace' => $tmp[0],
883 'localPart' => $tmp[1]
884 );
885 }
886 return array(
887 'namespace' => $defaultNs,
888 'localPart' => $qname
889 );
890 }
891
918 public static function isValidName($string)
919 {
920 // check for invalid chars
921 if (!is_string($string) || !strlen($string) || !preg_match('/^[[:alpha:]_]\\z/', $string[0])) {
923 'XML names may only start with letter or underscore',
925 );
926 }
927
928 // check for invalid chars
929 $match = preg_match(
930 '/^([[:alpha:]_]([[:alnum:]\-\.]*)?:)?'
931 . '[[:alpha:]_]([[:alnum:]\_\-\.]+)?\\z/',
932 $string
933 );
934 if (!$match) {
936 'XML names may only contain alphanumeric '
937 . 'chars, period, hyphen, colon and underscores',
939 );
940 }
941 // XML name is valid
942 return true;
943 }
944
957 public static function raiseError($msg, $code)
958 {
959 include_once 'PEAR.php';
960 return PEAR::raiseError($msg, $code);
961 }
962}
963?>
const XML_UTIL_COLLAPSE_NONE
Definition Util.php:103
const XML_UTIL_ERROR_NON_SCALAR_CONTENT
Definition Util.php:60
const XML_UTIL_ERROR_INVALID_CHARS
Definition Util.php:50
const XML_UTIL_ERROR_NO_TAG_NAME
Definition Util.php:65
const XML_UTIL_COLLAPSE_ALL
Definition Util.php:108
const XML_UTIL_COLLAPSE_XHTML_ONLY
Definition Util.php:113
const XML_UTIL_REPLACE_ENTITIES
Definition Util.php:70
const XML_UTIL_ENTITIES_XML
Definition Util.php:86
const XML_UTIL_ENTITIES_HTML
Definition Util.php:98
const XML_UTIL_ENTITIES_XML_REQUIRED
Definition Util.php:92
const XML_UTIL_CDATA_SECTION
Definition Util.php:75
const XML_UTIL_ERROR_INVALID_START
Definition Util.php:55
const XML_UTIL_ENTITIES_NONE
Definition Util.php:80
static raiseError($msg, $code)
Definition Util.php:957
static attributesToString( $attributes, $sort=true, $multiline=false, $indent=' ', $linebreak="\n", $entities=XML_UTIL_ENTITIES_XML)
Definition Util.php:392
static collapseEmptyTags($xml, $mode=XML_UTIL_COLLAPSE_ALL)
Definition Util.php:460
static createTag( $qname, $attributes=array(), $content=null, $namespaceUri=null, $replaceEntities=XML_UTIL_REPLACE_ENTITIES, $multiline=false, $indent='_auto', $linebreak="\n", $sortAttributes=true, $collapseTagMode=XML_UTIL_COLLAPSE_ALL)
Definition Util.php:541
static getDocTypeDeclaration( $root, $uri=null, $internalDtd=null)
Definition Util.php:338
static replaceEntities( $string, $replaceEntities=XML_UTIL_ENTITIES_XML, $encoding='ISO-8859-1')
Definition Util.php:176
static createComment($content)
Definition Util.php:827
static createStartElement( $qname, $attributes=array(), $namespaceUri=null, $multiline=false, $indent='_auto', $linebreak="\n", $sortAttributes=true)
Definition Util.php:752
static reverseEntities( $string, $replaceEntities=XML_UTIL_ENTITIES_XML, $encoding='ISO-8859-1')
Definition Util.php:248
static splitQualifiedName($qname, $defaultNs=null)
Definition Util.php:877
static getXMLDeclaration( $version='1.0', $encoding=null, $standalone=null)
Definition Util.php:299
static createCDataSection($data)
Definition Util.php:847
static createTagFromArray( $tag, $replaceEntities=XML_UTIL_REPLACE_ENTITIES, $multiline=false, $indent='_auto', $linebreak="\n", $sortAttributes=true, $collapseTagMode=XML_UTIL_COLLAPSE_ALL)
Definition Util.php:629
static isValidName($string)
Definition Util.php:918
static apiVersion()
Definition Util.php:133
static createEndElement($qname)
Definition Util.php:807