Source for file v2.php
Documentation is available at v2.php
* package.xml generation class, package.xml version 2.0
* @author Greg Beaver <cellog@php.net>
* @author Stephan Schmidt (original XML_Serializer code)
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version CVS: $Id: v2.php 313023 2011-07-06 19:17:11Z dufuz $
* @link http://pear.php.net/package/PEAR
* @since File available since Release 1.4.0a1
* file/dir manipulation routines
require_once 'System.php';
require_once 'XML/Util.php';
* This class converts a PEAR_PackageFile_v2 object into any output format.
* Supported output formats include array, XML string (using S. Schmidt's
* XML_Serializer, slightly customized)
* @author Greg Beaver <cellog@php.net>
* @author Stephan Schmidt (original XML_Serializer code)
* @copyright 1997-2009 The Authors
* @license http://opensource.org/licenses/bsd-license.php New BSD License
* @version Release: 1.9.4
* @link http://pear.php.net/package/PEAR
* @since Class available since Release 1.4.0a1
* default options for the serialization
* @var array $_defaultOptions
var $_defaultOptions = array (
'indent' => ' ', // string used for indentation
'linebreak' => "\n", // string used for newlines
'typeHints' => false , // automatically add type hin attributes
'addDecl' => true , // add an XML declaration
'defaultTagName' => 'XML_Serializer_Tag', // tag used for indexed arrays or invalid names
'classAsTagName' => false , // use classname for objects in indexed arrays
'keyAttribute' => '_originalKey', // attribute where original key is stored
'typeAttribute' => '_type', // attribute for type (only if typeHints => true)
'classAttribute' => '_class', // attribute for class of objects (only if typeHints => true)
'scalarAsAttributes' => false , // scalar values (strings, ints,..) will be serialized as attribute
'prependAttributes' => '', // prepend string for attributes
'indentAttributes' => false , // indent the attributes, if set to '_auto', it will indent attributes so they all start at the same column
'mode' => 'simplexml', // use 'simplexml' to use parent name as tagname if transforming an indexed array
'addDoctype' => false , // add a doctype declaration
'doctype' => null , // supply a string or an array with id and uri ({@see XML_Util::getDoctypeDeclaration()}
'rootName' => 'package', // name of the root tag
'rootAttributes' => array (
'xmlns' => 'http://pear.php.net/dtd/package-2.0',
'xmlns:tasks' => 'http://pear.php.net/dtd/tasks-1.0',
'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance',
'xsi:schemaLocation' => 'http://pear.php.net/dtd/tasks-1.0
http://pear.php.net/dtd/tasks-1.0.xsd
http://pear.php.net/dtd/package-2.0
http://pear.php.net/dtd/package-2.0.xsd',
), // attributes of the root tag
'attributesArray' => 'attribs', // all values in this key will be treated as attributes
'contentName' => '_content', // this value will be used directly as content, instead of creating a new tag, may only be used in conjuction with attributesArray
'beautifyFilelist' => false ,
* options for the serialization
* @var integer $_tagDepth
* serilialized representation of the data
* @var string $_serializedData
var $_serializedData = null;
* @var PEAR_PackageFile_v2
* @param PEAR_PackageFile_v2
$this->_packagefile = &$packagefile;
if (isset ($this->_packagefile->encoding)) {
$this->_defaultOptions['encoding'] = $this->_packagefile->encoding;
* @param bool generate a .tgz or a .tar
* @param string|nulltemporary directory to package in
function toTgz(&$packager, $compress = true , $where = null )
return $this->toTgz2($packager, $a, $compress, $where);
* Package up both a package.xml and package2.xml for the same release
* @param PEAR_PackageFile_v1
* @param bool generate a .tgz or a .tar
* @param string|nulltemporary directory to package in
function toTgz2(&$packager, &$pf1, $compress = true , $where = null )
require_once 'Archive/Tar.php';
return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: "' . $where . '" could' .
$file = $where . DIRECTORY_SEPARATOR . 'package.xml';
return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: unable to save package.xml as' .
return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: invalid package.xml');
$ext = $compress ? '.tgz' : '.tar';
$dest_package = getcwd() . DIRECTORY_SEPARATOR . $pkgver . $ext;
return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: cannot create tgz file "' .
return PEAR::raiseError('PEAR_Packagefile_v2::toTgz: package file object must ' .
'be created from a real file');
// {{{ Create the package file list
if (isset ($contents['bundledpackage'])) { // bundles of packages
$contents = $contents['bundledpackage'];
if (!isset ($contents[0 ])) {
$contents = array ($contents);
foreach ($contents as $i => $package) {
$file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
return $packager->raiseError (" File does not exist: $fname" );
$tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
$filelist[$i++ ] = $tfile;
$packager->log (2 , " Adding package $fname" );
} else { // normal packages
$contents = $contents['dir']['file'];
if (!isset ($contents[0 ])) {
$contents = array ($contents);
foreach ($contents as $i => $file) {
$fname = $file['attribs']['name'];
$atts = $file['attribs'];
$file = $pkgdir . DIRECTORY_SEPARATOR . $fname;
return $packager->raiseError (" File does not exist: $fname" );
$tfile = $packageDir . DIRECTORY_SEPARATOR . $fname;
if (count($orig)) { // file with tasks
// run any package-time tasks
foreach ($orig as $tag => $raw) {
array ($this->_packagefile->getTasksNs() . ':', '-'),
$task = " PEAR_Task_$tag";
$task = &new $task($this->_packagefile->_config,
$task->init ($raw, $atts, null );
$res = $task->startSession ($this->_packagefile, $contents, $tfile);
continue; // skip this task
$contents = $res; // save changes
$wp = fopen($tfile, "wb");
chmod($tfile, $origperms);
$filelist[$i++ ] = $tfile;
$packager->log (2 , " Adding file $fname" );
$name = $pf1 !== null ? 'package2.xml' : 'package.xml';
$tar = & new Archive_Tar ($dest_package, $compress);
// ----- Creates with the package.xml file
$ok = $tar->createModify (array ($packagexml), '', $where);
return $packager->raiseError ($ok);
return $packager->raiseError ('PEAR_Packagefile_v2::toTgz(): adding ' . $name .
// ----- Add the content of the package
if (!$tar->addModify ($filelist, $pkgver, $where)) {
return $packager->raiseError (
'PEAR_Packagefile_v2::toTgz(): tarball creation failed');
// add the package.xml version 1.0
$pfgen = &$pf1->getDefaultGenerator ();
if (!$tar->addModify (array ($packagexml1), '', $where)) {
return $packager->raiseError (
'PEAR_Packagefile_v2::toTgz(): adding package.xml failed');
function toPackageFile($where = null , $state = PEAR_VALIDATE_NORMAL , $name = 'package.xml')
if (!$this->_packagefile->validate($state)) {
return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: invalid package.xml',
return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: mktemp failed');
return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: "' . $where . '" could' .
$newpkgfile = $where . DIRECTORY_SEPARATOR . $name;
$np = @fopen($newpkgfile, 'wb');
return PEAR::raiseError('PEAR_Packagefile_v2::toPackageFile: unable to save ' .
return $this->_packagefile;
* Return an XML document based on the package info (as returned
* by the PEAR_Common::infoFrom* methods).
* @return string XML data
function toXml($state = PEAR_VALIDATE_NORMAL , $options = array ())
if (!$this->_packagefile->validate($state)) {
$this->options = array_merge($this->_defaultOptions, $options);
$this->options = $this->_defaultOptions;
if (isset ($arr['filelist'])) {
if (isset ($arr['_lastversion'])) {
unset ($arr['_lastversion']);
// Fix the notes a little bit
if (isset ($arr['notes'])) {
// This trims out the indenting, needs fixing
$arr['notes'] = "\n" . trim($arr['notes']) . "\n";
if (isset ($arr['changelog']) && !empty ($arr['changelog'])) {
// Fix for inconsistency how the array is filled depending on the changelog release amount
if (!isset ($arr['changelog']['release'][0 ])) {
$release = $arr['changelog']['release'];
unset ($arr['changelog']['release']);
$arr['changelog']['release'] = array ();
$arr['changelog']['release'][0 ] = $release;
foreach (array_keys($arr['changelog']['release']) as $key) {
$c = & $arr['changelog']['release'][$key];
if (isset ($c['notes'])) {
// This trims out the indenting, needs fixing
$c['notes'] = "\n" . trim($c['notes']) . "\n";
$use = $this->_recursiveXmlFilelist ($arr['contents']['dir']['file']);
unset ($arr['contents']['dir']['file']);
if (isset ($use['dir'])) {
$arr['contents']['dir']['dir'] = $use['dir'];
if (isset ($use['file'])) {
$arr['contents']['dir']['file'] = $use['file'];
$this->options['beautifyFilelist'] = true;
$arr['attribs']['packagerversion'] = '1.9.4';
return $this->_serializedData . "\n";
function _recursiveXmlFilelist ($list)
if (isset ($list['attribs'])) {
$file = $list['attribs']['name'];
unset ($list['attribs']['name']);
$attributes = $list['attribs'];
$this->_addDir ($dirs, explode('/', dirname($file)), $file, $attributes);
$file = $a['attribs']['name'];
$attributes = $a['attribs'];
$this->_addDir ($dirs, explode('/', dirname($file)), $file, $attributes, $a);
$this->_formatDir ($dirs);
function _addDir (&$dirs, $dir, $file = null , $attributes = null , $tasks = null )
if ($dir == array () || $dir == array ('.')) {
$dirs['file'][basename($file)] = $tasks;
$dirs['file'][basename($file)]['attribs'] = $attributes;
if (!isset ($dirs['dir'][$curdir])) {
$dirs['dir'][$curdir] = array ();
$this->_addDir ($dirs['dir'][$curdir], $dir, $file, $attributes, $tasks);
function _formatDir (&$dirs)
if (isset ($dirs['dir'])) {
$newdirs['dir'] = $dirs['dir'];
if (isset ($dirs['file'])) {
$newdirs['file'] = $dirs['file'];
if (isset ($dirs['dir'])) {
uksort($dirs['dir'], 'strnatcasecmp');
foreach ($dirs['dir'] as $dir => $contents) {
$this->_formatDir ($dirs['dir'][$dir]);
if (isset ($dirs['file'])) {
uksort($dirs['file'], 'strnatcasecmp');
function _deFormat (&$dirs)
if (isset ($dirs['dir'])) {
foreach ($dirs['dir'] as $dir => $contents) {
$newdir['attribs']['name'] = $dir;
$this->_deFormat ($contents);
foreach ($contents as $tag => $val) {
$newdirs['dir'][] = $newdir;
if (count($newdirs['dir']) == 1 ) {
$newdirs['dir'] = $newdirs['dir'][0 ];
if (isset ($dirs['file'])) {
foreach ($dirs['file'] as $name => $file) {
$newdirs['file'][] = $file;
if (count($newdirs['file']) == 1 ) {
$newdirs['file'] = $newdirs['file'][0 ];
* reset all options to default options
* @see setOption(), XML_Unserializer()
$this->options = $this->_defaultOptions;
* You can use this method if you do not want to set all options in the constructor
* @see resetOption(), XML_Serializer()
$this->options[$name] = $value;
* sets several options at once
* You can use this method if you do not want to set all options in the constructor
* @see resetOption(), XML_Unserializer(), setOption()
$this->options = array_merge($this->options, $options);
* @param mixed $data data to serialize
* @return boolean true on success, pear error on failure
// if options have been specified, use them instead
// of the previously defined ones
$optionsBak = $this->options;
if (isset ($options['overrideOptions']) && $options['overrideOptions'] == true ) {
$this->options = array_merge($this->_defaultOptions, $options);
$this->options = array_merge($this->options, $options);
$this->_serializedData = '';
$tagName = isset ($this->options['rootName']) ? $this->options['rootName'] : 'array';
$this->_serializedData .= $this->_serializeArray ($data, $tagName, $this->options['rootAttributes']);
// add doctype declaration
if ($this->options['addDoctype'] === true ) {
$this->_serializedData = XML_Util ::getDoctypeDeclaration ($tagName, $this->options['doctype'])
. $this->options['linebreak']
. $this->_serializedData;
if ($this->options['addDecl']) {
$encoding = isset ($this->options['encoding']) ? $this->options['encoding'] : null;
$this->_serializedData = XML_Util ::getXMLDeclaration ('1.0', $encoding)
. $this->options['linebreak']
. $this->_serializedData;
if ($optionsBak !== null ) {
$this->options = $optionsBak;
* get the result of the serialization
* @return string serialized XML
if ($this->_serializedData === null ) {
return $this->raiseError ('No serialized data available. Use XML_Serializer::serialize() first.', XML_SERIALIZER_ERROR_NO_SERIALIZATION );
return $this->_serializedData;
* This method checks for the type of the value and calls the appropriate method
* @param array $attributes
function _serializeValue ($value, $tagName = null , $attributes = array ())
$xml = $this->_serializeArray ($value, $tagName, $attributes);
$xml = $this->_serializeObject ($value, $tagName);
'attributes' => $attributes,
$xml = $this->_createXMLTag ($tag);
* @param array $array array to serialize
* @param string $tagName name of the root tag
* @param array $attributes attributes for the root tag
* @return string $string serialized data
* @uses XML_Util::isValidName() to check, whether key has to be substituted
function _serializeArray (&$array, $tagName = null , $attributes = array ())
* check for special attributes
if ($this->options['attributesArray'] !== null ) {
if (isset ($array[$this->options['attributesArray']])) {
$attributes = $array[$this->options['attributesArray']];
unset ($array[$this->options['attributesArray']]);
* check for special content
if ($this->options['contentName'] !== null ) {
if (isset ($array[$this->options['contentName']])) {
$_content = $array[$this->options['contentName']];
unset ($array[$this->options['contentName']]);
* if mode is set to simpleXML, check whether
* the array is associative or indexed
if (is_array($array) && $this->options['mode'] == 'simplexml') {
foreach ($array as $key => $val) {
if ($indexed && $this->options['mode'] == 'simplexml') {
foreach ($array as $key => $val) {
if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
if (!isset ($this->_curdir)) {
$savedir = $this->_curdir;
if (isset ($val['attribs'])) {
if ($val['attribs']['name'] == '/') {
if ($this->_curdir == '/') {
$this->_curdir .= '/' . $val['attribs']['name'];
$string .= $this->_serializeValue ( $val, $tagName, $attributes);
if ($this->options['beautifyFilelist'] && $tagName == 'dir') {
$string .= ' <!-- ' . $this->_curdir . ' -->';
$this->_curdir = $savedir;
$string .= $this->options['linebreak'];
if ($this->options['indent'] !== null && $this->_tagDepth > 0 ) {
$string .= str_repeat($this->options['indent'], $this->_tagDepth);
if ($this->options['scalarAsAttributes'] === true ) {
foreach ($array as $key => $value) {
if (is_scalar($value) && (XML_Util ::isValidName ($key) === true )) {
$attributes[$this->options['prependAttributes']. $key] = $value;
// check for empty array => create empty tag
'attributes' => $attributes
$tmp = $this->options['linebreak'];
foreach ($array as $key => $value) {
if ($this->options['indent'] !== null && $this->_tagDepth > 0 ) {
$tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
// key cannot be used as tagname => use default tag
$valid = XML_Util ::isValidName ($key);
if ($this->options['classAsTagName'] && is_object($value)) {
$key = $this->options['defaultTagName'];
if ($this->options['typeHints'] === true ) {
$atts[$this->options['typeAttribute']] = gettype($value);
$atts[$this->options['keyAttribute']] = (string) $origKey;
if ($this->options['beautifyFilelist'] && $key == 'dir') {
if (!isset ($this->_curdir)) {
$savedir = $this->_curdir;
if (isset ($value['attribs'])) {
if ($value['attribs']['name'] == '/') {
$this->_curdir .= '/' . $value['attribs']['name'];
$value .= str_repeat($this->options['indent'], $this->_tagDepth);
$tmp .= $this->_createXMLTag (array (
if ($this->options['beautifyFilelist'] && $key == 'dir') {
if (isset ($value['attribs'])) {
$tmp .= ' <!-- ' . $this->_curdir . ' -->';
$this->_curdir = $savedir;
$tmp .= $this->options['linebreak'];
if ($this->options['indent']!==null && $this->_tagDepth>0 ) {
$tmp .= str_repeat($this->options['indent'], $this->_tagDepth);
'attributes' => $attributes
if ($this->options['typeHints'] === true ) {
if (!isset ($tag['attributes'][$this->options['typeAttribute']])) {
$tag['attributes'][$this->options['typeAttribute']] = 'array';
$string = $this->_createXMLTag ($tag, false );
* create a tag from an array
* this method awaits an array in the following format
* 'attributes' => array(),
* 'content' => $content, // optional
* 'namespace' => $namespace // optional
* 'namespaceUri' => $namespaceUri // optional
* @param array $tag tag definition
* @param boolean $replaceEntities whether to replace XML entities in content or not
* @return string $string XML tag
function _createXMLTag ($tag, $replaceEntities = true )
if ($this->options['indentAttributes'] !== false ) {
$indent = str_repeat($this->options['indent'], $this->_tagDepth);
if ($this->options['indentAttributes'] == '_auto') {
$indent .= $this->options['indentAttributes'];
$indent = $multiline = false;
if (empty ($tag['content'])) {
} elseif (is_scalar($tag['content']) && (string) $tag['content'] == '') {
if ($this->options['encoding'] == 'UTF-8' &&
if ($replaceEntities === true ) {
$replaceEntities = XML_UTIL_ENTITIES_XML;
$tag = XML_Util ::createTagFromArray ($tag, $replaceEntities, $multiline, $indent, $this->options['linebreak']);
$tag = $this->_serializeArray ($tag['content'], $tag['qname'], $tag['attributes']);
$tag = $this->_serializeObject ($tag['content'], $tag['qname'], $tag['attributes']);
settype($tag['content'], 'string');
$tag = XML_Util ::createTagFromArray ($tag, $replaceEntities);
Documentation generated on Wed, 06 Jul 2011 23:31:34 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.
|