PageRenderTime 57ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/inc/app/siteinvoice/lib/PEAR/PEAR/PackageFile/Generator/v2.php

https://github.com/cbrunet/sitellite
PHP | 1518 lines | 879 code | 91 blank | 548 comment | 228 complexity | 81d44c83b7e85cb9c74a0bd07975c6ea MD5 | raw file
Possible License(s): Apache-2.0, GPL-2.0, GPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * package.xml generation class, package.xml version 2.0
  4. *
  5. * PHP versions 4 and 5
  6. *
  7. * LICENSE: This source file is subject to version 3.0 of the PHP license
  8. * that is available through the world-wide-web at the following URI:
  9. * http://www.php.net/license/3_0.txt. If you did not receive a copy of
  10. * the PHP License and are unable to obtain it through the web, please
  11. * send a note to license@php.net so we can mail you a copy immediately.
  12. *
  13. * @category pear
  14. * @package PEAR
  15. * @author Greg Beaver <cellog@php.net>
  16. * @author Stephan Schmidt (original XML_Serializer code)
  17. * @copyright 1997-2005 The PHP Group
  18. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  19. * @version CVS: $Id: v2.php,v 1.1 2005/07/02 21:12:31 lux Exp $
  20. * @link http://pear.php.net/package/PEAR
  21. * @since File available since Release 1.4.0a1
  22. */
  23. /**
  24. * file/dir manipulation routines
  25. */
  26. require_once 'System.php';
  27. /**
  28. * This class converts a PEAR_PackageFile_v2 object into any output format.
  29. *
  30. * Supported output formats include array, XML string (using S. Schmidt's
  31. * XML_Serializer, slightly customized)
  32. * @category pear
  33. * @package PEAR
  34. * @author Greg Beaver <cellog@php.net>
  35. * @author Stephan Schmidt (original XML_Serializer code)
  36. * @copyright 1997-2005 The PHP Group
  37. * @license http://www.php.net/license/3_0.txt PHP License 3.0
  38. * @version Release: 1.4.0a12
  39. * @link http://pear.php.net/package/PEAR
  40. * @since Class available since Release 1.4.0a1
  41. */
  42. class PEAR_PackageFile_Generator_v2
  43. {
  44. /**
  45. * default options for the serialization
  46. * @access private
  47. * @var array $_defaultOptions
  48. */
  49. var $_defaultOptions = array(
  50. 'indent' => ' ', // string used for indentation
  51. 'linebreak' => "\n", // string used for newlines
  52. 'typeHints' => false, // automatically add type hin attributes
  53. 'addDecl' => true, // add an XML declaration
  54. 'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
  55. 'classAsTagName' => false, // use classname for objects in indexed arrays
  56. 'keyAttribute' => '_originalKey', // attribute where original key is stored
  57. 'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
  58. 'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
  59. 'scalarAsAttributes' => false, // scalar values (strings, ints,..) will be serialized as attribute
  60. 'prependAttributes' => '', // prepend string for attributes
  61. 'indentAttributes' => false, // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
  62. 'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
  63. 'addDoctype' => false, // add a doctype declaration
  64. 'doctype' => null, // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
  65. 'rootName' => 'package', // name of the root tag
  66. 'rootAttributes' => array(
  67. 'version' => '2.0',
  68. 'xmlns' => 'http://pear.php.net/dtd/package-2.0',
  69. 'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
  70. 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
  71. 'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
  72. http://pear.php.net/dtd/tasks-1.0.xsd
  73. http://pear.php.net/dtd/package-2.0
  74. http://pear.php.net/dtd/package-2.0.xsd',
  75. ), // attributes of the root tag
  76. 'attributesArray' => 'attribs', // all values in this key will be treated as attributes
  77. 'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
  78. 'beautifyFilelist' => false,
  79. );
  80. /**
  81. * options for the serialization
  82. * @access private
  83. * @var array $options
  84. */
  85. var $options = array();
  86. /**
  87. * current tag depth
  88. * @var integer $_tagDepth
  89. */
  90. var $_tagDepth = 0;
  91. /**
  92. * serilialized representation of the data
  93. * @var string $_serializedData
  94. */
  95. var $_serializedData = null;
  96. /**
  97. * @var PEAR_PackageFile_v2
  98. */
  99. var $_packagefile;
  100. /**
  101. * @param PEAR_PackageFile_v2
  102. */
  103. function PEAR_PackageFile_Generator_v2(&$packagefile)
  104. {
  105. $this->_packagefile = &$packagefile;
  106. }
  107. /**
  108. * @return string
  109. */
  110. function getPackagerVersion()
  111. {
  112. return '1.4.0a12';
  113. }
  114. /**
  115. * @param PEAR_Packager
  116. * @param bool generate a .tgz or a .tar
  117. * @param string|null temporary directory to package in
  118. */
  119. function toTgz(&$packager, $compress = true, $where = null)
  120. {
  121. $a = null;
  122. return $this->toTgz2($packager, $a, $compress, $where);
  123. }
  124. /**
  125. * Package up both a package.xml and package2.xml for the same release
  126. * @param PEAR_Packager
  127. * @param PEAR_PackageFile_v1
  128. * @param bool generate a .tgz or a .tar
  129. * @param string|null temporary directory to package in
  130. */
  131. function toTgz2(&$packager, &$pf1, $compress = true, $where = null)
  132. {
  133. require_once 'Archive/Tar.php';
  134. if (!$this->_packagefile->isEquivalent($pf1)) {
  135. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' .
  136. basename($pf1->getPackageFile()) .
  137. '" is not equivalent to "' . basename($this->_packagefile->getPackageFile())
  138. . '"');
  139. }
  140. if ($where === null) {
  141. if (!($where = System::mktemp(array('-d')))) {
  142. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: mktemp failed');
  143. }
  144. } elseif (!@System::mkDir(array('-p', $where))) {
  145. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
  146. ' not be created');
  147. }
  148. if (file_exists($where . DIRECTORY_SEPARATOR . 'package.xml') &&
  149. !is_file($where . DIRECTORY_SEPARATOR . 'package.xml')) {
  150. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
  151. ' "' . $where . DIRECTORY_SEPARATOR . 'package.xml"');
  152. }
  153. if (!$this->_packagefile->validate(PEAR_VALIDATE_PACKAGING)) {
  154. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
  155. }
  156. $ext = $compress ? '.tgz' : '.tar';
  157. $pkgver = $this->_packagefile->getPackage() . '-' . $this->_packagefile->getVersion();
  158. $dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
  159. if (file_exists(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext) &&
  160. !is_file(getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext)) {
  161. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
  162. getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext . '"');
  163. }
  164. if ($pkgfile = $this->_packagefile->getPackageFile()) {
  165. $pkgdir = dirname(realpath($pkgfile));
  166. $pkgfile = basename($pkgfile);
  167. } else {
  168. return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
  169. 'be created from a real file');
  170. }
  171. // {{{ Create the package file list
  172. $filelist = array();
  173. $i = 0;
  174. $this->_packagefile->flattenFilelist();
  175. $contents = $this->_packagefile->getContents();
  176. if (isset($contents['bundledpackage'])) { // bundles of packages
  177. $contents = $contents['bundledpackage'];
  178. if (!isset($contents[0])) {
  179. $contents = array($contents);
  180. }
  181. $packageDir = $where;
  182. foreach ($contents as $i => $package) {
  183. $fname = $package;
  184. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  185. if (!file_exists($file)) {
  186. return $packager->raiseError("File does not exist: $fname");
  187. }
  188. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  189. System::mkdir(array('-p', dirname($tfile)));
  190. copy($file, $tfile);
  191. $filelist[$i++] = $tfile;
  192. $packager->log(2, "Adding package $fname");
  193. }
  194. } else { // normal packages
  195. $contents = $contents['dir']['file'];
  196. if (!isset($contents[0])) {
  197. $contents = array($contents);
  198. }
  199. $packageDir = $where;
  200. foreach ($contents as $i => $file) {
  201. $fname = $file['attribs']['name'];
  202. $atts = $file['attribs'];
  203. $orig = $file;
  204. $file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
  205. if (!file_exists($file)) {
  206. return $packager->raiseError("File does not exist: $fname");
  207. } else {
  208. $tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
  209. unset($orig['attribs']);
  210. if (count($orig)) { // file with tasks
  211. // run any package-time tasks
  212. $fp = fopen($file, "r");
  213. $contents = fread($fp, filesize($file));
  214. fclose($fp);
  215. foreach ($orig as $tag => $raw) {
  216. $tag = str_replace($this->_packagefile->getTasksNs() . ':', '', $tag);
  217. $task = "PEAR_Task_$tag";
  218. $task = &new $task($this->_packagefile->_config,
  219. $this->_packagefile->_logger,
  220. PEAR_TASK_PACKAGE);
  221. $task->init($raw, $atts, null);
  222. $res = $task->startSession($this->_packagefile, $contents, $tfile);
  223. if (!$res) {
  224. continue; // skip this task
  225. }
  226. if (PEAR::isError($res)) {
  227. return $res;
  228. }
  229. $contents = $res; // save changes
  230. System::mkdir(array('-p', dirname($tfile)));
  231. $wp = fopen($tfile, "wb");
  232. fwrite($wp, $contents);
  233. fclose($wp);
  234. }
  235. }
  236. if (!file_exists($tfile)) {
  237. System::mkdir(array('-p', dirname($tfile)));
  238. copy($file, $tfile);
  239. }
  240. $filelist[$i++] = $tfile;
  241. $this->_packagefile->setFileAttribute($fname, 'md5sum', md5_file($tfile), $i - 1);
  242. $packager->log(2, "Adding file $fname");
  243. }
  244. }
  245. }
  246. // }}}
  247. if ($pf1 !== null) {
  248. $name = 'package2.xml';
  249. } else {
  250. $name = 'package.xml';
  251. }
  252. $packagexml = $this->toPackageFile($where, PEAR_VALIDATE_PACKAGING, $name);
  253. if ($packagexml) {
  254. $tar =& new Archive_Tar($dest_package, $compress);
  255. $tar->setErrorHandling(PEAR_ERROR_RETURN); // XXX Don't print errors
  256. // ----- Creates with the package.xml file
  257. $ok = $tar->createModify(array($packagexml), '', $where);
  258. if (PEAR::isError($ok)) {
  259. return $packager->raiseError($ok);
  260. } elseif (!$ok) {
  261. return $packager->raiseError('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
  262. ' failed');
  263. }
  264. // ----- Add the content of the package
  265. if (!$tar->addModify($filelist, $pkgver, $where)) {
  266. return $packager->raiseError(
  267. 'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
  268. }
  269. // add the package.xml version 1.0
  270. if ($pf1 !== null) {
  271. $pfgen = &$pf1->getDefaultGenerator();
  272. $packagexml1 = $pfgen->toPackageFile($where, PEAR_VALIDATE_PACKAGING,
  273. 'package.xml', true);
  274. if (!$tar->addModify(array($packagexml1), '', $where)) {
  275. return $packager->raiseError(
  276. 'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
  277. }
  278. }
  279. return $dest_package;
  280. }
  281. }
  282. function toPackageFile($where = null, $state = PEAR_VALIDATE_NORMAL, $name = 'package.xml')
  283. {
  284. if (!$this->_packagefile->validate($state)) {
  285. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
  286. null, null, null, $this->_packagefile->getValidationWarnings());
  287. }
  288. if ($where === null) {
  289. if (!($where = System::mktemp(array('-d')))) {
  290. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
  291. }
  292. } elseif (!@System::mkDir(array('-p', $where))) {
  293. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
  294. ' not be created');
  295. }
  296. $newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
  297. $np = @fopen($newpkgfile, 'wb');
  298. if (!$np) {
  299. return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
  300. "$name as $newpkgfile");
  301. }
  302. fwrite($np, $this->toXml($state));
  303. fclose($np);
  304. return $newpkgfile;
  305. }
  306. function &toV2()
  307. {
  308. return $this->_packagefile;
  309. }
  310. /**
  311. * Return an XML document based on the package info (as returned
  312. * by the PEAR_Common::infoFrom* methods).
  313. *
  314. * @return string XML data
  315. */
  316. function toXml($state = PEAR_VALIDATE_NORMAL, $options = array())
  317. {
  318. $this->_packagefile->setDate(date('Y-m-d'));
  319. $this->_packagefile->setTime(date('H:i:s'));
  320. if (!$this->_packagefile->validate($state)) {
  321. return false;
  322. }
  323. if (is_array($options)) {
  324. $this->options = array_merge($this->_defaultOptions, $options);
  325. } else {
  326. $this->options = $this->_defaultOptions;
  327. }
  328. $arr = $this->_packagefile->getArray();
  329. if (isset($arr['filelist'])) {
  330. unset($arr['filelist']);
  331. }
  332. if (isset($arr['_lastversion'])) {
  333. unset($arr['_lastversion']);
  334. }
  335. if ($state ^ PEAR_VALIDATE_PACKAGING && !isset($arr['bundle'])) {
  336. $use = $this->_recursiveXmlFilelist($arr['contents']['dir']['file']);
  337. unset($arr['contents']['dir']['file']);
  338. if (isset($use['dir'])) {
  339. $arr['contents']['dir']['dir'] = $use['dir'];
  340. }
  341. if (isset($use['file'])) {
  342. $arr['contents']['dir']['file'] = $use['file'];
  343. }
  344. $this->options['beautifyFilelist'] = true;
  345. }
  346. $arr['attribs']['packagerversion'] = '1.4.0a12';
  347. if ($this->serialize($arr, $options)) {
  348. return $this->_serializedData . "\n";
  349. }
  350. return false;
  351. }
  352. function _recursiveXmlFilelist($list)
  353. {
  354. $dirs = array();
  355. if (isset($list['attribs'])) {
  356. $file = $list['attribs']['name'];
  357. unset($list['attribs']['name']);
  358. $attributes = $list['attribs'];
  359. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes);
  360. } else {
  361. foreach ($list as $a) {
  362. $file = $a['attribs']['name'];
  363. unset($a['attribs']['name']);
  364. $attributes = $a['attribs'];
  365. if (isset($a[$this->_packagefile->getTasksNs() . ':replace'])) {
  366. $repl = $a[$this->_packagefile->getTasksNs() . ':replace'];
  367. } else {
  368. $repl = null;
  369. }
  370. $this->_addDir($dirs, explode('/', dirname($file)), $file, $attributes, $repl);
  371. }
  372. }
  373. $this->_formatDir($dirs);
  374. $this->_deFormat($dirs);
  375. return $dirs;
  376. }
  377. function _addDir(&$dirs, $dir, $file = null, $attributes = null, $replacements = null)
  378. {
  379. if ($dir == array() || $dir == array('.')) {
  380. $attributes['name'] = basename($file);
  381. $dirs['file'][basename($file)]['attribs'] = $attributes;
  382. if (isset($replacements)) {
  383. $dirs['file'][basename($file)][$this->_packagefile->getTasksNs() . ':replace']
  384. = $replacements;
  385. }
  386. return;
  387. }
  388. $curdir = array_shift($dir);
  389. if (!isset($dirs['dir'][$curdir])) {
  390. $dirs['dir'][$curdir] = array();
  391. }
  392. $this->_addDir($dirs['dir'][$curdir], $dir, $file, $attributes, $replacements);
  393. }
  394. function _formatDir(&$dirs)
  395. {
  396. if (!count($dirs)) {
  397. return array();
  398. }
  399. $newdirs = array();
  400. if (isset($dirs['dir'])) {
  401. $newdirs['dir'] = $dirs['dir'];
  402. }
  403. if (isset($dirs['file'])) {
  404. $newdirs['file'] = $dirs['file'];
  405. }
  406. $dirs = $newdirs;
  407. if (isset($dirs['dir'])) {
  408. uksort($dirs['dir'], 'strnatcasecmp');
  409. foreach ($dirs['dir'] as $dir => $contents) {
  410. $this->_formatDir($dirs['dir'][$dir]);
  411. }
  412. }
  413. if (isset($dirs['file'])) {
  414. uksort($dirs['file'], 'strnatcasecmp');
  415. };
  416. }
  417. function _deFormat(&$dirs)
  418. {
  419. if (!count($dirs)) {
  420. return array();
  421. }
  422. $newdirs = array();
  423. if (isset($dirs['dir'])) {
  424. foreach ($dirs['dir'] as $dir => $contents) {
  425. $newdir = array();
  426. $newdir['attribs']['name'] = $dir;
  427. $this->_deFormat($contents);
  428. foreach ($contents as $tag => $val) {
  429. $newdir[$tag] = $val;
  430. }
  431. $newdirs['dir'][] = $newdir;
  432. }
  433. if (count($newdirs['dir']) == 1) {
  434. $newdirs['dir'] = $newdirs['dir'][0];
  435. }
  436. }
  437. if (isset($dirs['file'])) {
  438. foreach ($dirs['file'] as $name => $file) {
  439. $newdirs['file'][] = $file;
  440. }
  441. if (count($newdirs['file']) == 1) {
  442. $newdirs['file'] = $newdirs['file'][0];
  443. }
  444. }
  445. $dirs = $newdirs;
  446. }
  447. /**
  448. * reset all options to default options
  449. *
  450. * @access public
  451. * @see setOption(), XML_Unserializer()
  452. */
  453. function resetOptions()
  454. {
  455. $this->options = $this->_defaultOptions;
  456. }
  457. /**
  458. * set an option
  459. *
  460. * You can use this method if you do not want to set all options in the constructor
  461. *
  462. * @access public
  463. * @see resetOption(), XML_Serializer()
  464. */
  465. function setOption($name, $value)
  466. {
  467. $this->options[$name] = $value;
  468. }
  469. /**
  470. * sets several options at once
  471. *
  472. * You can use this method if you do not want to set all options in the constructor
  473. *
  474. * @access public
  475. * @see resetOption(), XML_Unserializer(), setOption()
  476. */
  477. function setOptions($options)
  478. {
  479. $this->options = array_merge($this->options, $options);
  480. }
  481. /**
  482. * serialize data
  483. *
  484. * @access public
  485. * @param mixed $data data to serialize
  486. * @return boolean true on success, pear error on failure
  487. */
  488. function serialize($data, $options = null)
  489. {
  490. // if options have been specified, use them instead
  491. // of the previously defined ones
  492. if (is_array($options)) {
  493. $optionsBak = $this->options;
  494. if (isset($options['overrideOptions']) && $options['overrideOptions'] == true) {
  495. $this->options = array_merge($this->_defaultOptions, $options);
  496. } else {
  497. $this->options = array_merge($this->options, $options);
  498. }
  499. }
  500. else {
  501. $optionsBak = null;
  502. }
  503. // start depth is zero
  504. $this->_tagDepth = 0;
  505. $this->_serializedData = '';
  506. // serialize an array
  507. if (is_array($data)) {
  508. if (isset($this->options['rootName'])) {
  509. $tagName = $this->options['rootName'];
  510. } else {
  511. $tagName = 'array';
  512. }
  513. $this->_serializedData .= $this->_serializeArray($data, $tagName, $this->options['rootAttributes']);
  514. }
  515. // add doctype declaration
  516. if ($this->options['addDoctype'] === true) {
  517. $this->_serializedData = XML_Util::getDoctypeDeclaration($tagName, $this->options['doctype'])
  518. . $this->options['linebreak']
  519. . $this->_serializedData;
  520. }
  521. // build xml declaration
  522. if ($this->options['addDecl']) {
  523. $atts = array();
  524. if (isset($this->options['encoding']) ) {
  525. $encoding = $this->options['encoding'];
  526. } else {
  527. $encoding = null;
  528. }
  529. $this->_serializedData = XML_Util::getXMLDeclaration('1.0', $encoding)
  530. . $this->options['linebreak']
  531. . $this->_serializedData;
  532. }
  533. if ($optionsBak !== null) {
  534. $this->options = $optionsBak;
  535. }
  536. return true;
  537. }
  538. /**
  539. * get the result of the serialization
  540. *
  541. * @access public
  542. * @return string serialized XML
  543. */
  544. function getSerializedData()
  545. {
  546. if ($this->_serializedData == null ) {
  547. return $this->raiseError('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION);
  548. }
  549. return $this->_serializedData;
  550. }
  551. /**
  552. * serialize any value
  553. *
  554. * This method checks for the type of the value and calls the appropriate method
  555. *
  556. * @access private
  557. * @param mixed $value
  558. * @param string $tagName
  559. * @param array $attributes
  560. * @return string
  561. */
  562. function _serializeValue($value, $tagName = null, $attributes = array())
  563. {
  564. if (is_array($value)) {
  565. $xml = $this->_serializeArray($value, $tagName, $attributes);
  566. } elseif (is_object($value)) {
  567. $xml = $this->_serializeObject($value, $tagName);
  568. } else {
  569. $tag = array(
  570. 'qname' => $tagName,
  571. 'attributes' => $attributes,
  572. 'content' => $value
  573. );
  574. $xml = $this->_createXMLTag($tag);
  575. }
  576. return $xml;
  577. }
  578. /**
  579. * serialize an array
  580. *
  581. * @access private
  582. * @param array $array array to serialize
  583. * @param string $tagName name of the root tag
  584. * @param array $attributes attributes for the root tag
  585. * @return string $string serialized data
  586. * @uses XML_Util::isValidName() to check, whether key has to be substituted
  587. */
  588. function _serializeArray(&$array, $tagName = null, $attributes = array())
  589. {
  590. $_content = null;
  591. /**
  592. * check for special attributes
  593. */
  594. if ($this->options['attributesArray'] !== null) {
  595. if (isset($array[$this->options['attributesArray']])) {
  596. $attributes = $array[$this->options['attributesArray']];
  597. unset($array[$this->options['attributesArray']]);
  598. }
  599. /**
  600. * check for special content
  601. */
  602. if ($this->options['contentName'] !== null) {
  603. if (isset($array[$this->options['contentName']])) {
  604. $_content = $array[$this->options['contentName']];
  605. unset($array[$this->options['contentName']]);
  606. }
  607. }
  608. }
  609. /*
  610. * if mode is set to simpleXML, check whether
  611. * the array is associative or indexed
  612. */
  613. if (is_array($array) && $this->options['mode'] == 'simplexml') {
  614. $indexed = true;
  615. if (!count($array)) {
  616. $indexed = false;
  617. }
  618. foreach ($array as $key => $val) {
  619. if (!is_int($key)) {
  620. $indexed = false;
  621. break;
  622. }
  623. }
  624. if ($indexed && $this->options['mode'] == 'simplexml') {
  625. $string = '';
  626. foreach ($array as $key => $val) {
  627. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  628. if (!isset($this->_curdir)) {
  629. $this->_curdir = '';
  630. }
  631. $savedir = $this->_curdir;
  632. if (isset($val['attribs'])) {
  633. if ($val['attribs']['name'] == '/') {
  634. $this->_curdir = '/';
  635. } else {
  636. if ($this->_curdir == '/') {
  637. $this->_curdir = '';
  638. }
  639. $this->_curdir .= '/' . $val['attribs']['name'];
  640. }
  641. }
  642. }
  643. $string .= $this->_serializeValue( $val, $tagName, $attributes);
  644. if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
  645. $string .= ' <!-- ' . $this->_curdir . ' -->';
  646. if (empty($savedir)) {
  647. unset($this->_curdir);
  648. } else {
  649. $this->_curdir = $savedir;
  650. }
  651. }
  652. $string .= $this->options['linebreak'];
  653. // do indentation
  654. if ($this->options['indent']!==null && $this->_tagDepth>0) {
  655. $string .= str_repeat($this->options['indent'], $this->_tagDepth);
  656. }
  657. }
  658. return rtrim($string);
  659. }
  660. }
  661. if ($this->options['scalarAsAttributes'] === true) {
  662. foreach ($array as $key => $value) {
  663. if (is_scalar($value) && (XML_Util::isValidName($key) === true)) {
  664. unset($array[$key]);
  665. $attributes[$this->options['prependAttributes'].$key] = $value;
  666. }
  667. }
  668. }
  669. // check for empty array => create empty tag
  670. if (empty($array)) {
  671. $tag = array(
  672. 'qname' => $tagName,
  673. 'content' => $_content,
  674. 'attributes' => $attributes
  675. );
  676. } else {
  677. $this->_tagDepth++;
  678. $tmp = $this->options['linebreak'];
  679. foreach ($array as $key => $value) {
  680. // do indentation
  681. if ($this->options['indent']!==null && $this->_tagDepth>0) {
  682. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  683. }
  684. // copy key
  685. $origKey = $key;
  686. // key cannot be used as tagname => use default tag
  687. $valid = XML_Util::isValidName($key);
  688. if (PEAR::isError($valid)) {
  689. if ($this->options['classAsTagName'] && is_object($value)) {
  690. $key = get_class($value);
  691. } else {
  692. $key = $this->options['defaultTagName'];
  693. }
  694. }
  695. $atts = array();
  696. if ($this->options['typeHints'] === true) {
  697. $atts[$this->options['typeAttribute']] = gettype($value);
  698. if ($key !== $origKey) {
  699. $atts[$this->options['keyAttribute']] = (string)$origKey;
  700. }
  701. }
  702. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  703. if (!isset($this->_curdir)) {
  704. $this->_curdir = '';
  705. }
  706. $savedir = $this->_curdir;
  707. if (isset($value['attribs'])) {
  708. if ($value['attribs']['name'] == '/') {
  709. $this->_curdir = '/';
  710. } else {
  711. $this->_curdir .= '/' . $value['attribs']['name'];
  712. }
  713. }
  714. }
  715. if (is_string($value) && $value && ($value{strlen($value) - 1} == "\n")) {
  716. $value .= str_repeat($this->options['indent'], $this->_tagDepth);
  717. }
  718. $tmp .= $this->_createXMLTag(array(
  719. 'qname' => $key,
  720. 'attributes' => $atts,
  721. 'content' => $value )
  722. );
  723. if ($this->options['beautifyFilelist'] && $key == 'dir') {
  724. if (isset($value['attribs'])) {
  725. $tmp .= ' <!-- ' . $this->_curdir . ' -->';
  726. if (empty($savedir)) {
  727. unset($this->_curdir);
  728. } else {
  729. $this->_curdir = $savedir;
  730. }
  731. }
  732. }
  733. $tmp .= $this->options['linebreak'];
  734. }
  735. $this->_tagDepth--;
  736. if ($this->options['indent']!==null && $this->_tagDepth>0) {
  737. $tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
  738. }
  739. if (trim($tmp) === '') {
  740. $tmp = null;
  741. }
  742. $tag = array(
  743. 'qname' => $tagName,
  744. 'content' => $tmp,
  745. 'attributes' => $attributes
  746. );
  747. }
  748. if ($this->options['typeHints'] === true) {
  749. if (!isset($tag['attributes'][$this->options['typeAttribute']])) {
  750. $tag['attributes'][$this->options['typeAttribute']] = 'array';
  751. }
  752. }
  753. $string = $this->_createXMLTag($tag, false);
  754. return $string;
  755. }
  756. /**
  757. * create a tag from an array
  758. * this method awaits an array in the following format
  759. * array(
  760. * 'qname' => $tagName,
  761. * 'attributes' => array(),
  762. * 'content' => $content, // optional
  763. * 'namespace' => $namespace // optional
  764. * 'namespaceUri' => $namespaceUri // optional
  765. * )
  766. *
  767. * @access private
  768. * @param array $tag tag definition
  769. * @param boolean $replaceEntities whether to replace XML entities in content or not
  770. * @return string $string XML tag
  771. */
  772. function _createXMLTag( $tag, $replaceEntities = true )
  773. {
  774. if ($this->options['indentAttributes'] !== false) {
  775. $multiline = true;
  776. $indent = str_repeat($this->options['indent'], $this->_tagDepth);
  777. if ($this->options['indentAttributes'] == '_auto') {
  778. $indent .= str_repeat(' ', (strlen($tag['qname'])+2));
  779. } else {
  780. $indent .= $this->options['indentAttributes'];
  781. }
  782. } else {
  783. $multiline = false;
  784. $indent = false;
  785. }
  786. if (is_array($tag['content'])) {
  787. if (empty($tag['content'])) {
  788. $tag['content'] = '';
  789. }
  790. } elseif(is_scalar($tag['content']) && (string)$tag['content'] == '') {
  791. $tag['content'] = '';
  792. }
  793. if (is_scalar($tag['content']) || is_null($tag['content'])) {
  794. $tag = XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']);
  795. } elseif (is_array($tag['content'])) {
  796. $tag = $this->_serializeArray($tag['content'], $tag['qname'], $tag['attributes']);
  797. } elseif (is_object($tag['content'])) {
  798. $tag = $this->_serializeObject($tag['content'], $tag['qname'], $tag['attributes']);
  799. } elseif (is_resource($tag['content'])) {
  800. settype($tag['content'], 'string');
  801. $tag = XML_Util::createTagFromArray($tag, $replaceEntities);
  802. }
  803. return $tag;
  804. }
  805. }
  806. foreach (explode(PATH_SEPARATOR, ini_get('include_path')) as $path) {
  807. $t = $path . DIRECTORY_SEPARATOR . 'XML' . DIRECTORY_SEPARATOR .
  808. 'Util';
  809. if (file_exists($t) && is_readable($t)) {
  810. include_once 'XML/Util';
  811. }
  812. }
  813. if (!class_exists('XML_Util')) {
  814. // well, it's one way to do things without extra deps ...
  815. /* vim: set expandtab tabstop=4 shiftwidth=4: */
  816. // +----------------------------------------------------------------------+
  817. // | PHP Version 4 |
  818. // +----------------------------------------------------------------------+
  819. // | Copyright (c) 1997-2002 The PHP Group |
  820. // +----------------------------------------------------------------------+
  821. // | This source file is subject to version 2.0 of the PHP license, |
  822. // | that is bundled with this package in the file LICENSE, and is |
  823. // | available at through the world-wide-web at |
  824. // | http://www.php.net/license/2_02.txt. |
  825. // | If you did not receive a copy of the PHP license and are unable to |
  826. // | obtain it through the world-wide-web, please send a note to |
  827. // | license@php.net so we can mail you a copy immediately. |
  828. // +----------------------------------------------------------------------+
  829. // | Authors: Stephan Schmidt <schst@php-tools.net> |
  830. // +----------------------------------------------------------------------+
  831. //
  832. // $Id: v2.php,v 1.1 2005/07/02 21:12:31 lux Exp $
  833. /**
  834. * error code for invalid chars in XML name
  835. */
  836. define("XML_UTIL_ERROR_INVALID_CHARS", 51);
  837. /**
  838. * error code for invalid chars in XML name
  839. */
  840. define("XML_UTIL_ERROR_INVALID_START", 52);
  841. /**
  842. * error code for non-scalar tag content
  843. */
  844. define("XML_UTIL_ERROR_NON_SCALAR_CONTENT", 60);
  845. /**
  846. * error code for missing tag name
  847. */
  848. define("XML_UTIL_ERROR_NO_TAG_NAME", 61);
  849. /**
  850. * replace XML entities
  851. */
  852. define("XML_UTIL_REPLACE_ENTITIES", 1);
  853. /**
  854. * embedd content in a CData Section
  855. */
  856. define("XML_UTIL_CDATA_SECTION", 2);
  857. /**
  858. * do not replace entitites
  859. */
  860. define("XML_UTIL_ENTITIES_NONE", 0);
  861. /**
  862. * replace all XML entitites
  863. * This setting will replace <, >, ", ' and &
  864. */
  865. define("XML_UTIL_ENTITIES_XML", 1);
  866. /**
  867. * replace only required XML entitites
  868. * This setting will replace <, " and &
  869. */
  870. define("XML_UTIL_ENTITIES_XML_REQUIRED", 2);
  871. /**
  872. * replace HTML entitites
  873. * @link http://www.php.net/htmlentities
  874. */
  875. define("XML_UTIL_ENTITIES_HTML", 3);
  876. /**
  877. * utility class for working with XML documents
  878. *
  879. * @category XML
  880. * @package XML_Util
  881. * @version 0.6.0
  882. * @author Stephan Schmidt <schst@php.net>
  883. */
  884. class XML_Util {
  885. /**
  886. * return API version
  887. *
  888. * @access public
  889. * @static
  890. * @return string $version API version
  891. */
  892. function apiVersion()
  893. {
  894. return "0.6";
  895. }
  896. /**
  897. * replace XML entities
  898. *
  899. * With the optional second parameter, you may select, which
  900. * entities should be replaced.
  901. *
  902. * <code>
  903. * require_once 'XML/Util.php';
  904. *
  905. * // replace XML entites:
  906. * $string = XML_Util::replaceEntities("This string contains < & >.");
  907. * </code>
  908. *
  909. * @access public
  910. * @static
  911. * @param string string where XML special chars should be replaced
  912. * @param integer setting for entities in attribute values (one of XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  913. * @return string string with replaced chars
  914. */
  915. function replaceEntities($string, $replaceEntities = XML_UTIL_ENTITIES_XML)
  916. {
  917. switch ($replaceEntities) {
  918. case XML_UTIL_ENTITIES_XML:
  919. return strtr($string,array(
  920. '&' => '&amp;',
  921. '>' => '&gt;',
  922. '<' => '&lt;',
  923. '"' => '&quot;',
  924. '\'' => '&apos;' ));
  925. break;
  926. case XML_UTIL_ENTITIES_XML_REQUIRED:
  927. return strtr($string,array(
  928. '&' => '&amp;',
  929. '<' => '&lt;',
  930. '"' => '&quot;' ));
  931. break;
  932. case XML_UTIL_ENTITIES_HTML:
  933. return htmlspecialchars($string);
  934. break;
  935. }
  936. return $string;
  937. }
  938. /**
  939. * build an xml declaration
  940. *
  941. * <code>
  942. * require_once 'XML/Util.php';
  943. *
  944. * // get an XML declaration:
  945. * $xmlDecl = XML_Util::getXMLDeclaration("1.0", "UTF-8", true);
  946. * </code>
  947. *
  948. * @access public
  949. * @static
  950. * @param string $version xml version
  951. * @param string $encoding character encoding
  952. * @param boolean $standAlone document is standalone (or not)
  953. * @return string $decl xml declaration
  954. * @uses XML_Util::attributesToString() to serialize the attributes of the XML declaration
  955. */
  956. function getXMLDeclaration($version = "1.0", $encoding = null, $standalone = null)
  957. {
  958. $attributes = array(
  959. "version" => $version,
  960. );
  961. // add encoding
  962. if ($encoding !== null) {
  963. $attributes["encoding"] = $encoding;
  964. }
  965. // add standalone, if specified
  966. if ($standalone !== null) {
  967. $attributes["standalone"] = $standalone ? "yes" : "no";
  968. }
  969. return sprintf("<?xml%s?>", XML_Util::attributesToString($attributes, false));
  970. }
  971. /**
  972. * build a document type declaration
  973. *
  974. * <code>
  975. * require_once 'XML/Util.php';
  976. *
  977. * // get a doctype declaration:
  978. * $xmlDecl = XML_Util::getDocTypeDeclaration("rootTag","myDocType.dtd");
  979. * </code>
  980. *
  981. * @access public
  982. * @static
  983. * @param string $root name of the root tag
  984. * @param string $uri uri of the doctype definition (or array with uri and public id)
  985. * @param string $internalDtd internal dtd entries
  986. * @return string $decl doctype declaration
  987. * @since 0.2
  988. */
  989. function getDocTypeDeclaration($root, $uri = null, $internalDtd = null)
  990. {
  991. if (is_array($uri)) {
  992. $ref = sprintf( ' PUBLIC "%s" "%s"', $uri["id"], $uri["uri"] );
  993. } elseif (!empty($uri)) {
  994. $ref = sprintf( ' SYSTEM "%s"', $uri );
  995. } else {
  996. $ref = "";
  997. }
  998. if (empty($internalDtd)) {
  999. return sprintf("<!DOCTYPE %s%s>", $root, $ref);
  1000. } else {
  1001. return sprintf("<!DOCTYPE %s%s [\n%s\n]>", $root, $ref, $internalDtd);
  1002. }
  1003. }
  1004. /**
  1005. * create string representation of an attribute list
  1006. *
  1007. * <code>
  1008. * require_once 'XML/Util.php';
  1009. *
  1010. * // build an attribute string
  1011. * $att = array(
  1012. * "foo" => "bar",
  1013. * "argh" => "tomato"
  1014. * );
  1015. *
  1016. * $attList = XML_Util::attributesToString($att);
  1017. * </code>
  1018. *
  1019. * @access public
  1020. * @static
  1021. * @param array $attributes attribute array
  1022. * @param boolean|array $sort sort attribute list alphabetically, may also be an assoc array containing the keys 'sort', 'multiline', 'indent', 'linebreak' and 'entities'
  1023. * @param boolean $multiline use linebreaks, if more than one attribute is given
  1024. * @param string $indent string used for indentation of multiline attributes
  1025. * @param string $linebreak string used for linebreaks of multiline attributes
  1026. * @param integer $entities setting for entities in attribute values (one of XML_UTIL_ENTITIES_NONE, XML_UTIL_ENTITIES_XML, XML_UTIL_ENTITIES_XML_REQUIRED, XML_UTIL_ENTITIES_HTML)
  1027. * @return string string representation of the attributes
  1028. * @uses XML_Util::replaceEntities() to replace XML entities in attribute values
  1029. * @todo allow sort also to be an options array
  1030. */
  1031. function attributesToString($attributes, $sort = true, $multiline = false, $indent = ' ', $linebreak = "\n", $entities = XML_UTIL_ENTITIES_XML)
  1032. {
  1033. /**
  1034. * second parameter may be an array
  1035. */
  1036. if (is_array($sort)) {
  1037. if (isset($sort['multiline'])) {
  1038. $multiline = $sort['multiline'];
  1039. }
  1040. if (isset($sort['indent'])) {
  1041. $indent = $sort['indent'];
  1042. }
  1043. if (isset($sort['linebreak'])) {
  1044. $multiline = $sort['linebreak'];
  1045. }
  1046. if (isset($sort['entities'])) {
  1047. $entities = $sort['entities'];
  1048. }
  1049. if (isset($sort['sort'])) {
  1050. $sort = $sort['sort'];
  1051. } else {
  1052. $sort = true;
  1053. }
  1054. }
  1055. $string = '';
  1056. if (is_array($attributes) && !empty($attributes)) {
  1057. if ($sort) {
  1058. ksort($attributes);
  1059. }
  1060. if( !$multiline || count($attributes) == 1) {
  1061. foreach ($attributes as $key => $value) {
  1062. if ($entities != XML_UTIL_ENTITIES_NONE) {
  1063. $value = XML_Util::replaceEntities($value, $entities);
  1064. }
  1065. $string .= ' '.$key.'="'.$value.'"';
  1066. }
  1067. } else {
  1068. $first = true;
  1069. foreach ($attributes as $key => $value) {
  1070. if ($entities != XML_UTIL_ENTITIES_NONE) {
  1071. $value = XML_Util::replaceEntities($value, $entities);
  1072. }
  1073. if ($first) {
  1074. $string .= " ".$key.'="'.$value.'"';
  1075. $first = false;
  1076. } else {
  1077. $string .= $linebreak.$indent.$key.'="'.$value.'"';
  1078. }
  1079. }
  1080. }
  1081. }
  1082. return $string;
  1083. }
  1084. /**
  1085. * create a tag
  1086. *
  1087. * This method will call XML_Util::createTagFromArray(), which
  1088. * is more flexible.
  1089. *
  1090. * <code>
  1091. * require_once 'XML/Util.php';
  1092. *
  1093. * // create an XML tag:
  1094. * $tag = XML_Util::createTag("myNs:myTag", array("foo" => "bar"), "This is inside the tag", "http://www.w3c.org/myNs#");
  1095. * </code>
  1096. *
  1097. * @access public
  1098. * @static
  1099. * @param string $qname qualified tagname (including namespace)
  1100. * @param array $attributes array containg attributes
  1101. * @param mixed $content
  1102. * @param string $namespaceUri URI of the namespace
  1103. * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
  1104. * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
  1105. * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
  1106. * @param string $linebreak string used for linebreaks
  1107. * @return string $string XML tag
  1108. * @see XML_Util::createTagFromArray()
  1109. * @uses XML_Util::createTagFromArray() to create the tag
  1110. */
  1111. function createTag($qname, $attributes = array(), $content = null, $namespaceUri = null, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n")
  1112. {
  1113. $tag = array(
  1114. "qname" => $qname,
  1115. "attributes" => $attributes
  1116. );
  1117. // add tag content
  1118. if ($content !== null) {
  1119. $tag["content"] = $content;
  1120. }
  1121. // add namespace Uri
  1122. if ($namespaceUri !== null) {
  1123. $tag["namespaceUri"] = $namespaceUri;
  1124. }
  1125. return XML_Util::createTagFromArray($tag, $replaceEntities, $multiline, $indent, $linebreak);
  1126. }
  1127. /**
  1128. * create a tag from an array
  1129. * this method awaits an array in the following format
  1130. * <pre>
  1131. * array(
  1132. * "qname" => $qname // qualified name of the tag
  1133. * "namespace" => $namespace // namespace prefix (optional, if qname is specified or no namespace)
  1134. * "localpart" => $localpart, // local part of the tagname (optional, if qname is specified)
  1135. * "attributes" => array(), // array containing all attributes (optional)
  1136. * "content" => $content, // tag content (optional)
  1137. * "namespaceUri" => $namespaceUri // namespaceUri for the given namespace (optional)
  1138. * )
  1139. * </pre>
  1140. *
  1141. * <code>
  1142. * require_once 'XML/Util.php';
  1143. *
  1144. * $tag = array(
  1145. * "qname" => "foo:bar",
  1146. * "namespaceUri" => "http://foo.com",
  1147. * "attributes" => array( "key" => "value", "argh" => "fruit&vegetable" ),
  1148. * "content" => "I'm inside the tag",
  1149. * );
  1150. * // creating a tag with qualified name and namespaceUri
  1151. * $string = XML_Util::createTagFromArray($tag);
  1152. * </code>
  1153. *
  1154. * @access public
  1155. * @static
  1156. * @param array $tag tag definition
  1157. * @param integer $replaceEntities whether to replace XML special chars in content, embedd it in a CData section or none of both
  1158. * @param boolean $multiline whether to create a multiline tag where each attribute gets written to a single line
  1159. * @param string $indent string used to indent attributes (_auto indents attributes so they start at the same column)
  1160. * @param string $linebreak string used for linebreaks
  1161. * @return string $string XML tag
  1162. * @see XML_Util::createTag()
  1163. * @uses XML_Util::attributesToString() to serialize the attributes of the tag
  1164. * @uses XML_Util::splitQualifiedName() to get local part and namespace of a qualified name
  1165. */
  1166. function createTagFromArray($tag, $replaceEntities = XML_UTIL_REPLACE_ENTITIES, $multiline = false, $indent = "_auto", $linebreak = "\n" )
  1167. {
  1168. if (isset($tag["content"]) && !is_scalar($tag["content"])) {
  1169. return XML_Util::raiseError( "Supplied non-scalar value as tag content", XML_UTIL_ERROR_NON_SCALAR_CONTENT );
  1170. }
  1171. if (!isset($tag['qname']) && !isset($tag['localPart'])) {
  1172. return XML_Util::raiseError( 'You must either supply a qualified name (qname) or local tag name (localPart).', XML_UTIL_ERROR_NO_TAG_NAME );
  1173. }
  1174. // if no attributes hav been set, use empty attributes
  1175. if (!isset($tag["attributes"]) || !is_array($tag["attributes"])) {
  1176. $tag["attributes"] = array();
  1177. }
  1178. // qualified name is not given
  1179. if (!isset($tag["qname"])) {
  1180. // check for namespace
  1181. if (isset($tag["namespace"]) && !empty($tag["namespace"])) {
  1182. $tag["qname"] = $tag["n…

Large files files are truncated, but you can click here to view the full file