PageRenderTime 53ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/common/libraries/plugin/pear/PEAR/PackageFile/Generator/v2.php

https://bitbucket.org/chamilo/chamilo/
PHP | 1531 lines | 883 code | 92 blank | 556 comment | 226 complexity | 18414fdcc81a421a427c3431dc974ad6 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT

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

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