home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / PEAR / PackageFile.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  15.4 KB  |  436 lines

  1. <?php
  2. /**
  3.  * PEAR_PackageFile, package.xml parsing utility class
  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.  * @copyright  1997-2005 The PHP Group
  17.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18.  * @version    CVS: $Id: PackageFile.php,v 1.31 2005/09/15 20:42:25 cellog Exp $
  19.  * @link       http://pear.php.net/package/PEAR
  20.  * @since      File available since Release 1.4.0a1
  21.  */
  22.  
  23. /**
  24.  * needed for PEAR_VALIDATE_* constants
  25.  */
  26. require_once 'PEAR/Validate.php';
  27. /**
  28.  * Error code if the package.xml <package> tag does not contain a valid version
  29.  */
  30. define('PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION', 1);
  31. /**
  32.  * Error code if the package.xml <package> tag version is not supported (version 1.0 and 1.1 are the only supported versions,
  33.  * currently
  34.  */
  35. define('PEAR_PACKAGEFILE_ERROR_INVALID_PACKAGEVERSION', 2);
  36. /**
  37.  * Abstraction for the package.xml package description file
  38.  *
  39.  * @category   pear
  40.  * @package    PEAR
  41.  * @author     Greg Beaver <cellog@php.net>
  42.  * @copyright  1997-2005 The PHP Group
  43.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  44.  * @version    Release: 1.4.5
  45.  * @link       http://pear.php.net/package/PEAR
  46.  * @since      Class available since Release 1.4.0a1
  47.  */
  48. class PEAR_PackageFile
  49. {
  50.     /**
  51.      * @var PEAR_Config
  52.      */
  53.     var $_config;
  54.     var $_debug;
  55.     /**
  56.      * Temp directory for uncompressing tgz files.
  57.      * @var string|false
  58.      */
  59.     var $_tmpdir;
  60.     var $_logger = false;
  61.     /**
  62.      * @var boolean
  63.      */
  64.     var $_rawReturn = false;
  65.  
  66.     /**
  67.      *
  68.      * @param   PEAR_Config $config
  69.      * @param   ?   $debug
  70.      * @param   string @tmpdir Optional temporary directory for uncompressing
  71.      *          files
  72.      */
  73.     function PEAR_PackageFile(&$config, $debug = false, $tmpdir = false)
  74.     {
  75.         $this->_config = $config;
  76.         $this->_debug = $debug;
  77.         $this->_tmpdir = $tmpdir;
  78.     }
  79.  
  80.     /**
  81.      * Turn off validation - return a parsed package.xml without checking it
  82.      *
  83.      * This is used by the package-validate command
  84.      */
  85.     function rawReturn()
  86.     {
  87.         $this->_rawReturn = true;
  88.     }
  89.  
  90.     function setLogger(&$l)
  91.     {
  92.         $this->_logger = &$l;
  93.     }
  94.  
  95.     /**
  96.      * Create a PEAR_PackageFile_Parser_v* of a given version.
  97.      * @param   int $version
  98.      * @return  PEAR_PackageFile_Parser_v1|PEAR_PackageFile_Parser_v1
  99.      */
  100.     function &parserFactory($version)
  101.     {
  102.         if (!in_array($version{0}, array('1', '2'))) {
  103.             $a = false;
  104.             return $a;
  105.         }
  106.         include_once 'PEAR/PackageFile/Parser/v' . $version{0} . '.php';
  107.         $version = $version{0};
  108.         $class = "PEAR_PackageFile_Parser_v$version";
  109.         $a = new $class;
  110.         return $a;
  111.     }
  112.  
  113.     /**
  114.      * For simpler unit-testing
  115.      * @return string
  116.      */
  117.     function getClassPrefix()
  118.     {
  119.         return 'PEAR_PackageFile_v';
  120.     }
  121.  
  122.     /**
  123.      * Create a PEAR_PackageFile_v* of a given version.
  124.      * @param   int $version
  125.      * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v1
  126.      */
  127.     function &factory($version)
  128.     {
  129.         if (!in_array($version{0}, array('1', '2'))) {
  130.             $a = false;
  131.             return $a;
  132.         }
  133.         include_once 'PEAR/PackageFile/v' . $version{0} . '.php';
  134.         $version = $version{0};
  135.         $class = $this->getClassPrefix() . $version;
  136.         $a = new $class;
  137.         return $a;
  138.     }
  139.  
  140.     /**
  141.      * Create a PEAR_PackageFile_v* from its toArray() method
  142.      *
  143.      * WARNING: no validation is performed, the array is assumed to be valid,
  144.      * always parse from xml if you want validation.
  145.      * @param   array $arr
  146.      * @return PEAR_PackageFileManager_v1|PEAR_PackageFileManager_v2
  147.      * @uses    factory() to construct the returned object.
  148.      */
  149.     function &fromArray($arr)
  150.     {
  151.         if (isset($arr['xsdversion'])) {
  152.             $obj = &$this->factory($arr['xsdversion']);
  153.             if ($this->_logger) {
  154.                 $obj->setLogger($this->_logger);
  155.             }
  156.             $obj->setConfig($this->_config);
  157.             $obj->fromArray($arr);
  158.             return $obj;
  159.         } else {
  160.             if (isset($arr['package']['attribs']['version'])) {
  161.                 $obj = &$this->factory($arr['package']['attribs']['version']);
  162.             } else {
  163.                 $obj = &$this->factory('1.0');
  164.             }
  165.             if ($this->_logger) {
  166.                 $obj->setLogger($this->_logger);
  167.             }
  168.             $obj->setConfig($this->_config);
  169.             $obj->fromArray($arr);
  170.             return $obj;
  171.         }
  172.     }
  173.  
  174.     /**
  175.      * Create a PEAR_PackageFile_v* from an XML string.
  176.      * @access  public
  177.      * @param   string $data contents of package.xml file
  178.      * @param   int $state package state (one of PEAR_VALIDATE_* constants)
  179.      * @param   string $file full path to the package.xml file (and the files
  180.      *          it references)
  181.      * @param   string $archive optional name of the archive that the XML was
  182.      *          extracted from, if any
  183.      * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
  184.      * @uses    parserFactory() to construct a parser to load the package.
  185.      */
  186.     function &fromXmlString($data, $state, $file, $archive = false)
  187.     {
  188.         if (preg_match('/<package[^>]+version="([0-9]+\.[0-9]+)"/', $data, $packageversion)) {
  189.             if (!in_array($packageversion[1], array('1.0', '2.0'))) {
  190.                 return PEAR::raiseError('package.xml version "' . $packageversion[1] .
  191.                     '" is not supported, only 1.0 and 2.0 are supported.');
  192.             }
  193.             $object = &$this->parserFactory($packageversion[1]);
  194.             if ($this->_logger) {
  195.                 $object->setLogger($this->_logger);
  196.             }
  197.             $object->setConfig($this->_config);
  198.             $pf = $object->parse($data, $file, $archive);
  199.             if (PEAR::isError($pf)) {
  200.                 return $pf;
  201.             }
  202.             if ($this->_rawReturn) {
  203.                 return $pf;
  204.             }
  205.             if ($pf->validate($state)) {
  206.                 if ($this->_logger) {
  207.                     if ($pf->getValidationWarnings(false)) {
  208.                         foreach ($pf->getValidationWarnings() as $warning) {
  209.                             $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  210.                         }
  211.                     }
  212.                 }
  213.                 if (method_exists($pf, 'flattenFilelist')) {
  214.                     $pf->flattenFilelist(); // for v2
  215.                 }
  216.                 return $pf;
  217.             } else {
  218.                 if ($this->_config->get('verbose') > 0) {
  219.                     if ($this->_logger) {
  220.                         if ($pf->getValidationWarnings(false)) {
  221.                             foreach ($pf->getValidationWarnings(false) as $warning) {
  222.                                 $this->_logger->log(0, 'ERROR: ' . $warning['message']);
  223.                             }
  224.                         }
  225.                     }
  226.                 }
  227.                 $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  228.                     2, null, null, $pf->getValidationWarnings());
  229.                 return $a;
  230.             }
  231.         } elseif (preg_match('/<package[^>]+version="([^"]+)"/', $data, $packageversion)) {
  232.             $a = PEAR::raiseError('package.xml file "' . $file .
  233.                 '" has unsupported package.xml <package> version "' . $packageversion[1] . '"');
  234.             return $a;
  235.         } else {
  236.             if (!class_exists('PEAR_ErrorStack')) {
  237.                 require_once 'PEAR/ErrorStack.php';
  238.             }
  239.             PEAR_ErrorStack::staticPush('PEAR_PackageFile',
  240.                 PEAR_PACKAGEFILE_ERROR_NO_PACKAGEVERSION,
  241.                 'warning', array('xml' => $data), 'package.xml "' . $file .
  242.                     '" has no package.xml <package> version');
  243.             $object = &$this->parserFactory('1.0');
  244.             $object->setConfig($this->_config);
  245.             $pf = $object->parse($data, $file, $archive);
  246.             if (PEAR::isError($pf)) {
  247.                 return $pf;
  248.             }
  249.             if ($this->_rawReturn) {
  250.                 return $pf;
  251.             }
  252.             if ($pf->validate($state)) {
  253.                 if ($this->_logger) {
  254.                     if ($pf->getValidationWarnings(false)) {
  255.                         foreach ($pf->getValidationWarnings() as $warning) {
  256.                             $this->_logger->log(0, 'WARNING: ' . $warning['message']);
  257.                         }
  258.                     }
  259.                 }
  260.                 if (method_exists($pf, 'flattenFilelist')) {
  261.                     $pf->flattenFilelist(); // for v2
  262.                 }
  263.                 return $pf;
  264.             } else {
  265.                 $a = PEAR::raiseError('Parsing of package.xml from file "' . $file . '" failed',
  266.                     2, null, null, $pf->getValidationWarnings());
  267.                 return $a;
  268.             }
  269.         }
  270.     }
  271.  
  272.     /**
  273.      * Register a temporary file or directory.  When the destructor is
  274.      * executed, all registered temporary files and directories are
  275.      * removed.
  276.      *
  277.      * @param string  $file  name of file or directory
  278.      * @return  void
  279.      */
  280.     function addTempFile($file)
  281.     {
  282.         $GLOBALS['_PEAR_Common_tempfiles'][] = $file;
  283.     }
  284.  
  285.     /**
  286.      * Create a PEAR_PackageFile_v* from a compresed Tar or Tgz file.
  287.      * @access  public
  288.      * @param string contents of package.xml file
  289.      * @param int package state (one of PEAR_VALIDATE_* constants)
  290.      * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
  291.      * @using   Archive_Tar to extract the files
  292.      * @using   fromPackageFile() to load the package after the package.xml
  293.      *          file is extracted.
  294.      */
  295.     function &fromTgzFile($file, $state)
  296.     {
  297.         if (!class_exists('Archive_Tar')) {
  298.             require_once 'Archive/Tar.php';
  299.         }
  300.         $tar = new Archive_Tar($file);
  301.         if ($this->_debug <= 1) {
  302.             $tar->pushErrorHandling(PEAR_ERROR_RETURN);
  303.         }
  304.         $content = $tar->listContent();
  305.         if ($this->_debug <= 1) {
  306.             $tar->popErrorHandling();
  307.         }
  308.         if (!is_array($content)) {
  309.             if (is_string($file) && strlen($file < 255) && !@is_file($file)) {
  310.                 $ret = PEAR::raiseError("could not open file \"$file\"");
  311.                 return $ret;
  312.             }
  313.             $file = realpath($file);
  314.             $ret = PEAR::raiseError("Could not get contents of package \"$file\"".
  315.                                      '. Invalid tgz file.');
  316.             return $ret;
  317.         } else {
  318.             if (!count($content) && !@is_file($file)) {
  319.                 $ret = PEAR::raiseError("could not open file \"$file\"");
  320.                 return $ret;
  321.             }
  322.         }
  323.         $xml = null;
  324.         $origfile = $file;
  325.         foreach ($content as $file) {
  326.             $name = $file['filename'];
  327.             if ($name == 'package2.xml') { // allow a .tgz to distribute both versions
  328.                 $xml = $name;
  329.                 break;
  330.             }
  331.             if ($name == 'package.xml') {
  332.                 $xml = $name;
  333.                 break;
  334.             } elseif (ereg('package.xml$', $name, $match)) {
  335.                 $xml = $match[0];
  336.                 break;
  337.             }
  338.         }
  339.         if ($this->_tmpdir) {
  340.             $tmpdir = $this->_tmpdir;
  341.         } else {
  342.             $tmpdir = System::mkTemp(array('-d', 'pear'));
  343.             PEAR_PackageFile::addTempFile($tmpdir);
  344.         }
  345.         if (!$xml || !$tar->extractList(array($xml), $tmpdir)) {
  346.             $ret = PEAR::raiseError('could not extract the package.xml file from "' .
  347.                 $origfile . '"');
  348.             return $ret;
  349.         }
  350.         $ret = &PEAR_PackageFile::fromPackageFile("$tmpdir/$xml", $state, $origfile);
  351.         return $ret;
  352.     }
  353.  
  354.     /**
  355.      * Create a PEAR_PackageFile_v* from a package.xml file.
  356.      *
  357.      * @access public
  358.      * @param   string  $descfile  name of package xml file
  359.      * @param   int     $state package state (one of PEAR_VALIDATE_* constants)
  360.      * @param   string|false $archive name of the archive this package.xml came
  361.      *          from, if any
  362.      * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
  363.      * @uses    PEAR_PackageFile::fromXmlString to create the oject after the
  364.      *          XML is loaded from the package.xml file.
  365.      */
  366.     function &fromPackageFile($descfile, $state, $archive = false)
  367.     {
  368.         if (is_string($descfile) && strlen($descfile) < 255 &&
  369.              !@is_file($descfile) || !is_readable($descfile) ||
  370.              (!$fp = @fopen($descfile, 'r'))) {
  371.             $a = PEAR::raiseError("Unable to open $descfile");
  372.             return $a;
  373.         }
  374.  
  375.         // read the whole thing so we only get one cdata callback
  376.         // for each block of cdata
  377.         if (function_exists('file_get_contents')) {
  378.             @fclose($fp);
  379.             $data = file_get_contents($descfile);
  380.         } else {
  381.             $data = '';
  382.             while (!feof($fp)) {
  383.                 $data .= @fread($fp, 8192);
  384.             }
  385.             fclose($fp);
  386.         }
  387.         $ret = &PEAR_PackageFile::fromXmlString($data, $state, $descfile, $archive);
  388.         return $ret;
  389.     }
  390.  
  391.  
  392.     /**
  393.      * Create a PEAR_PackageFile_v* from a .tgz archive or package.xml file.
  394.      *
  395.      * This method is able to extract information about a package from a .tgz
  396.      * archive or from a XML package definition file.
  397.      *
  398.      * @access public
  399.      * @param   string  $info file name
  400.      * @param   int     $state package state (one of PEAR_VALIDATE_* constants)
  401.      * @return  PEAR_PackageFile_v1|PEAR_PackageFile_v2
  402.      * @uses    fromPackageFile() if the file appears to be XML
  403.      * @uses    fromTgzFile() to load all non-XML files
  404.      */
  405.     function &fromAnyFile($info, $state)
  406.     {
  407.         $fp = false;
  408.         if (is_string($info) && strlen($info) < 255 &&
  409.              (file_exists($info) || ($fp = @fopen($info, 'r')))) {
  410.             if ($fp) {
  411.                 fclose($fp);
  412.             }
  413.             $tmp = substr($info, -4);
  414.             if ($tmp == '.xml') {
  415.                 $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  416.             } elseif ($tmp == '.tar' || $tmp == '.tgz') {
  417.                 $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  418.             } else {
  419.                 $fp = fopen($info, "r");
  420.                 $test = fread($fp, 5);
  421.                 fclose($fp);
  422.                 if ($test == "<?xml") {
  423.                     $info = &PEAR_PackageFile::fromPackageFile($info, $state);
  424.                 } else {
  425.                     $info = &PEAR_PackageFile::fromTgzFile($info, $state);
  426.                 }
  427.             }
  428.         } else {
  429.             $info = PEAR::raiseError("Cannot open '$info' for parsing");
  430.             return $info;
  431.         }
  432.         return $info;
  433.     }
  434. }
  435.  
  436. ?>