2008-11-26 22:50:40 +00:00
< ? php
2009-01-05 00:22:54 +00:00
/**
* PEAR_PackageFile_v2 , package . xml version 2.0 , read / write version
*
* PHP versions 4 and 5
*
* LICENSE : This source file is subject to version 3.0 of the PHP license
* that is available through the world - wide - web at the following URI :
* http :// www . php . net / license / 3_0 . txt . If you did not receive a copy of
* the PHP License and are unable to obtain it through the web , please
* send a note to license @ php . net so we can mail you a copy immediately .
*
* @ category pear
* @ package PEAR
* @ author Greg Beaver < cellog @ php . net >
* @ copyright 1997 - 2008 The PHP Group
* @ license http :// www . php . net / license / 3_0 . txt PHP License 3.0
* @ version CVS : $Id : Validator . php , v 1.106 2008 / 03 / 28 22 : 23 : 41 dufuz Exp $
* @ link http :// pear . php . net / package / PEAR
* @ since File available since Release 1.4 . 0 a8
*/
2008-11-26 22:50:40 +00:00
/**
* Private validation class used by PEAR_PackageFile_v2 - do not use directly , its
* sole purpose is to split up the PEAR / PackageFile / v2 . php file to make it smaller
2009-01-05 00:22:54 +00:00
* @ category pear
* @ package PEAR
* @ author Greg Beaver < cellog @ php . net >
* @ copyright 1997 - 2008 The PHP Group
* @ license http :// www . php . net / license / 3_0 . txt PHP License 3.0
* @ version Release : 1.7 . 2
* @ link http :// pear . php . net / package / PEAR
* @ since Class available since Release 1.4 . 0 a8
2008-11-26 22:50:40 +00:00
* @ access private
*/
class PEAR_PackageFile_v2_Validator
{
/**
* @ var array
*/
var $_packageInfo ;
/**
* @ var PEAR_PackageFile_v2
*/
var $_pf ;
/**
* @ var PEAR_ErrorStack
*/
var $_stack ;
/**
* @ var int
*/
var $_isValid = 0 ;
2009-01-05 00:22:54 +00:00
/**
* @ var int
*/
var $_filesValid = 0 ;
2008-11-26 22:50:40 +00:00
/**
* @ var int
*/
var $_curState = 0 ;
/**
* @ param PEAR_PackageFile_v2
* @ param int
*/
function validate ( & $pf , $state = PEAR_VALIDATE_NORMAL )
{
$this -> _pf = & $pf ;
$this -> _curState = $state ;
$this -> _packageInfo = $this -> _pf -> getArray ();
$this -> _isValid = $this -> _pf -> _isValid ;
$this -> _filesValid = $this -> _pf -> _filesValid ;
$this -> _stack = & $pf -> _stack ;
$this -> _stack -> getErrors ( true );
if (( $this -> _isValid & $state ) == $state ) {
return true ;
}
if ( ! isset ( $this -> _packageInfo ) || ! is_array ( $this -> _packageInfo )) {
return false ;
}
if ( ! isset ( $this -> _packageInfo [ 'attribs' ][ 'version' ]) ||
2009-01-05 00:22:54 +00:00
( $this -> _packageInfo [ 'attribs' ][ 'version' ] != '2.0' &&
$this -> _packageInfo [ 'attribs' ][ 'version' ] != '2.1' )
) {
2008-11-26 22:50:40 +00:00
$this -> _noPackageVersion ();
}
$structure =
array (
'name' ,
'channel|uri' ,
'*extends' , // can't be multiple, but this works fine
'summary' ,
'description' ,
'+lead' , // these all need content checks
'*developer' ,
'*contributor' ,
'*helper' ,
'date' ,
'*time' ,
'version' ,
'stability' ,
'license->?uri->?filesource' ,
'notes' ,
'contents' , //special validation needed
'*compatible' ,
'dependencies' , //special validation needed
'*usesrole' ,
'*usestask' , // reserve these for 1.4.0a1 to implement
// this will allow a package.xml to gracefully say it
// needs a certain package installed in order to implement a role or task
'*providesextension' ,
'*srcpackage|*srcuri' ,
2009-01-05 00:22:54 +00:00
'+phprelease|+extsrcrelease|+extbinrelease|' .
'+zendextsrcrelease|+zendextbinrelease|bundle' , //special validation needed
2008-11-26 22:50:40 +00:00
'*changelog' ,
);
$test = $this -> _packageInfo ;
2009-01-05 00:22:54 +00:00
if ( isset ( $test [ 'dependencies' ]) &&
isset ( $test [ 'dependencies' ][ 'required' ]) &&
isset ( $test [ 'dependencies' ][ 'required' ][ 'pearinstaller' ]) &&
isset ( $test [ 'dependencies' ][ 'required' ][ 'pearinstaller' ][ 'min' ]) &&
version_compare ( '1.7.2' ,
$test [ 'dependencies' ][ 'required' ][ 'pearinstaller' ][ 'min' ], '<' )
) {
$this -> _pearVersionTooLow ( $test [ 'dependencies' ][ 'required' ][ 'pearinstaller' ][ 'min' ]);
return false ;
}
2008-11-26 22:50:40 +00:00
// ignore post-installation array fields
if ( array_key_exists ( 'filelist' , $test )) {
unset ( $test [ 'filelist' ]);
}
if ( array_key_exists ( '_lastmodified' , $test )) {
unset ( $test [ '_lastmodified' ]);
}
if ( array_key_exists ( '#binarypackage' , $test )) {
unset ( $test [ '#binarypackage' ]);
}
if ( array_key_exists ( 'old' , $test )) {
unset ( $test [ 'old' ]);
}
if ( array_key_exists ( '_lastversion' , $test )) {
unset ( $test [ '_lastversion' ]);
}
2009-01-05 00:22:54 +00:00
if ( ! $this -> _stupidSchemaValidate ( $structure , $test , '<package>' )) {
2008-11-26 22:50:40 +00:00
return false ;
}
if ( empty ( $this -> _packageInfo [ 'name' ])) {
$this -> _tagCannotBeEmpty ( 'name' );
}
2009-01-05 00:22:54 +00:00
$test = isset ( $this -> _packageInfo [ 'uri' ]) ? 'uri' : 'channel' ;
2008-11-26 22:50:40 +00:00
if ( empty ( $this -> _packageInfo [ $test ])) {
$this -> _tagCannotBeEmpty ( $test );
}
if ( is_array ( $this -> _packageInfo [ 'license' ]) &&
( ! isset ( $this -> _packageInfo [ 'license' ][ '_content' ]) ||
empty ( $this -> _packageInfo [ 'license' ][ '_content' ]))) {
$this -> _tagCannotBeEmpty ( 'license' );
} elseif ( empty ( $this -> _packageInfo [ 'license' ])) {
$this -> _tagCannotBeEmpty ( 'license' );
}
if ( empty ( $this -> _packageInfo [ 'summary' ])) {
$this -> _tagCannotBeEmpty ( 'summary' );
}
if ( empty ( $this -> _packageInfo [ 'description' ])) {
$this -> _tagCannotBeEmpty ( 'description' );
}
if ( empty ( $this -> _packageInfo [ 'date' ])) {
$this -> _tagCannotBeEmpty ( 'date' );
}
if ( empty ( $this -> _packageInfo [ 'notes' ])) {
$this -> _tagCannotBeEmpty ( 'notes' );
}
if ( isset ( $this -> _packageInfo [ 'time' ]) && empty ( $this -> _packageInfo [ 'time' ])) {
$this -> _tagCannotBeEmpty ( 'time' );
}
if ( isset ( $this -> _packageInfo [ 'dependencies' ])) {
$this -> _validateDependencies ();
}
if ( isset ( $this -> _packageInfo [ 'compatible' ])) {
$this -> _validateCompatible ();
}
if ( ! isset ( $this -> _packageInfo [ 'bundle' ])) {
2009-01-05 00:22:54 +00:00
if ( empty ( $this -> _packageInfo [ 'contents' ])) {
$this -> _tagCannotBeEmpty ( 'contents' );
}
2008-11-26 22:50:40 +00:00
if ( ! isset ( $this -> _packageInfo [ 'contents' ][ 'dir' ])) {
$this -> _filelistMustContainDir ( 'contents' );
return false ;
}
if ( isset ( $this -> _packageInfo [ 'contents' ][ 'file' ])) {
$this -> _filelistCannotContainFile ( 'contents' );
return false ;
}
}
$this -> _validateMaintainers ();
$this -> _validateStabilityVersion ();
$fail = false ;
if ( array_key_exists ( 'usesrole' , $this -> _packageInfo )) {
$roles = $this -> _packageInfo [ 'usesrole' ];
if ( ! is_array ( $roles ) || ! isset ( $roles [ 0 ])) {
$roles = array ( $roles );
}
foreach ( $roles as $role ) {
if ( ! isset ( $role [ 'role' ])) {
$this -> _usesroletaskMustHaveRoleTask ( 'usesrole' , 'role' );
$fail = true ;
} else {
if ( ! isset ( $role [ 'channel' ])) {
if ( ! isset ( $role [ 'uri' ])) {
$this -> _usesroletaskMustHaveChannelOrUri ( $role [ 'role' ], 'usesrole' );
$fail = true ;
}
} elseif ( ! isset ( $role [ 'package' ])) {
$this -> _usesroletaskMustHavePackage ( $role [ 'role' ], 'usesrole' );
$fail = true ;
}
}
}
}
if ( array_key_exists ( 'usestask' , $this -> _packageInfo )) {
$roles = $this -> _packageInfo [ 'usestask' ];
if ( ! is_array ( $roles ) || ! isset ( $roles [ 0 ])) {
$roles = array ( $roles );
}
foreach ( $roles as $role ) {
if ( ! isset ( $role [ 'task' ])) {
$this -> _usesroletaskMustHaveRoleTask ( 'usestask' , 'task' );
$fail = true ;
} else {
if ( ! isset ( $role [ 'channel' ])) {
if ( ! isset ( $role [ 'uri' ])) {
$this -> _usesroletaskMustHaveChannelOrUri ( $role [ 'task' ], 'usestask' );
$fail = true ;
}
} elseif ( ! isset ( $role [ 'package' ])) {
$this -> _usesroletaskMustHavePackage ( $role [ 'task' ], 'usestask' );
$fail = true ;
}
}
}
}
if ( $fail ) {
return false ;
}
2009-01-05 00:22:54 +00:00
$list = $this -> _packageInfo [ 'contents' ];
if ( isset ( $list [ 'dir' ]) && is_array ( $list [ 'dir' ]) && isset ( $list [ 'dir' ][ 0 ])) {
$this -> _multipleToplevelDirNotAllowed ();
return $this -> _isValid = 0 ;
}
2008-11-26 22:50:40 +00:00
$this -> _validateFilelist ();
$this -> _validateRelease ();
if ( ! $this -> _stack -> hasErrors ()) {
$chan = $this -> _pf -> _registry -> getChannel ( $this -> _pf -> getChannel (), true );
2009-01-05 00:22:54 +00:00
if ( PEAR :: isError ( $chan )) {
2008-11-26 22:50:40 +00:00
$this -> _unknownChannel ( $this -> _pf -> getChannel ());
} else {
$valpack = $chan -> getValidationPackage ();
// for channel validator packages, always use the default PEAR validator.
// otherwise, they can't be installed or packaged
$validator = $chan -> getValidationObject ( $this -> _pf -> getPackage ());
if ( ! $validator ) {
$this -> _stack -> push ( __FUNCTION__ , 'error' ,
array_merge (
array ( 'channel' => $chan -> getName (),
'package' => $this -> _pf -> getPackage ()),
$valpack
),
'package "%channel%/%package%" cannot be properly validated without ' .
'validation package "%channel%/%name%-%version%"' );
return $this -> _isValid = 0 ;
}
$validator -> setPackageFile ( $this -> _pf );
$validator -> validate ( $state );
$failures = $validator -> getFailures ();
foreach ( $failures [ 'errors' ] as $error ) {
$this -> _stack -> push ( __FUNCTION__ , 'error' , $error ,
'Channel validator error: field "%field%" - %reason%' );
}
foreach ( $failures [ 'warnings' ] as $warning ) {
$this -> _stack -> push ( __FUNCTION__ , 'warning' , $warning ,
'Channel validator warning: field "%field%" - %reason%' );
}
}
}
$this -> _pf -> _isValid = $this -> _isValid = ! $this -> _stack -> hasErrors ( 'error' );
if ( $this -> _isValid && $state == PEAR_VALIDATE_PACKAGING && ! $this -> _filesValid ) {
if ( $this -> _pf -> getPackageType () == 'bundle' ) {
if ( $this -> _analyzeBundledPackages ()) {
$this -> _filesValid = $this -> _pf -> _filesValid = true ;
} else {
$this -> _pf -> _isValid = $this -> _isValid = 0 ;
}
} else {
if ( ! $this -> _analyzePhpFiles ()) {
$this -> _pf -> _isValid = $this -> _isValid = 0 ;
} else {
$this -> _filesValid = $this -> _pf -> _filesValid = true ;
}
}
}
if ( $this -> _isValid ) {
return $this -> _pf -> _isValid = $this -> _isValid = $state ;
}
return $this -> _pf -> _isValid = $this -> _isValid = 0 ;
}
function _stupidSchemaValidate ( $structure , $xml , $root )
{
if ( ! is_array ( $xml )) {
$xml = array ();
}
$keys = array_keys ( $xml );
reset ( $keys );
$key = current ( $keys );
while ( $key == 'attribs' || $key == '_contents' ) {
$key = next ( $keys );
}
$unfoundtags = $optionaltags = array ();
$ret = true ;
$mismatch = false ;
foreach ( $structure as $struc ) {
if ( $key ) {
$tag = $xml [ $key ];
}
$test = $this -> _processStructure ( $struc );
if ( isset ( $test [ 'choices' ])) {
$loose = true ;
foreach ( $test [ 'choices' ] as $choice ) {
if ( $key == $choice [ 'tag' ]) {
$key = next ( $keys );
while ( $key == 'attribs' || $key == '_contents' ) {
$key = next ( $keys );
}
$unfoundtags = $optionaltags = array ();
$mismatch = false ;
if ( $key && $key != $choice [ 'tag' ] && isset ( $choice [ 'multiple' ])) {
$unfoundtags [] = $choice [ 'tag' ];
$optionaltags [] = $choice [ 'tag' ];
if ( $key ) {
$mismatch = true ;
}
}
$ret &= $this -> _processAttribs ( $choice , $tag , $root );
continue 2 ;
} else {
$unfoundtags [] = $choice [ 'tag' ];
$mismatch = true ;
}
if ( ! isset ( $choice [ 'multiple' ]) || $choice [ 'multiple' ] != '*' ) {
$loose = false ;
} else {
$optionaltags [] = $choice [ 'tag' ];
}
}
if ( ! $loose ) {
$this -> _invalidTagOrder ( $unfoundtags , $key , $root );
return false ;
}
} else {
if ( $key != $test [ 'tag' ]) {
if ( isset ( $test [ 'multiple' ]) && $test [ 'multiple' ] != '*' ) {
$unfoundtags [] = $test [ 'tag' ];
$this -> _invalidTagOrder ( $unfoundtags , $key , $root );
return false ;
} else {
if ( $key ) {
$mismatch = true ;
}
$unfoundtags [] = $test [ 'tag' ];
$optionaltags [] = $test [ 'tag' ];
}
if ( ! isset ( $test [ 'multiple' ])) {
$this -> _invalidTagOrder ( $unfoundtags , $key , $root );
return false ;
}
continue ;
} else {
$unfoundtags = $optionaltags = array ();
$mismatch = false ;
}
$key = next ( $keys );
while ( $key == 'attribs' || $key == '_contents' ) {
$key = next ( $keys );
}
if ( $key && $key != $test [ 'tag' ] && isset ( $test [ 'multiple' ])) {
$unfoundtags [] = $test [ 'tag' ];
$optionaltags [] = $test [ 'tag' ];
$mismatch = true ;
}
$ret &= $this -> _processAttribs ( $test , $tag , $root );
continue ;
}
}
if ( ! $mismatch && count ( $optionaltags )) {
// don't error out on any optional tags
$unfoundtags = array_diff ( $unfoundtags , $optionaltags );
}
if ( count ( $unfoundtags )) {
$this -> _invalidTagOrder ( $unfoundtags , $key , $root );
} elseif ( $key ) {
// unknown tags
$this -> _invalidTagOrder ( '*no tags allowed here*' , $key , $root );
while ( $key = next ( $keys )) {
$this -> _invalidTagOrder ( '*no tags allowed here*' , $key , $root );
}
}
return $ret ;
}
function _processAttribs ( $choice , $tag , $context )
{
if ( isset ( $choice [ 'attribs' ])) {
if ( ! is_array ( $tag )) {
$tag = array ( $tag );
}
$tags = $tag ;
if ( ! isset ( $tags [ 0 ])) {
$tags = array ( $tags );
}
$ret = true ;
foreach ( $tags as $i => $tag ) {
if ( ! is_array ( $tag ) || ! isset ( $tag [ 'attribs' ])) {
foreach ( $choice [ 'attribs' ] as $attrib ) {
if ( $attrib { 0 } != '?' ) {
$ret &= $this -> _tagHasNoAttribs ( $choice [ 'tag' ],
$context );
continue 2 ;
}
}
}
foreach ( $choice [ 'attribs' ] as $attrib ) {
if ( $attrib { 0 } != '?' ) {
if ( ! isset ( $tag [ 'attribs' ][ $attrib ])) {
$ret &= $this -> _tagMissingAttribute ( $choice [ 'tag' ],
$attrib , $context );
}
}
}
}
return $ret ;
}
return true ;
}
function _processStructure ( $key )
{
$ret = array ();
if ( count ( $pieces = explode ( '|' , $key )) > 1 ) {
2009-01-05 00:22:54 +00:00
$ret [ 'choices' ] = array ();
2008-11-26 22:50:40 +00:00
foreach ( $pieces as $piece ) {
$ret [ 'choices' ][] = $this -> _processStructure ( $piece );
}
return $ret ;
}
$multi = $key { 0 };
if ( $multi == '+' || $multi == '*' ) {
$ret [ 'multiple' ] = $key { 0 };
$key = substr ( $key , 1 );
}
if ( count ( $attrs = explode ( '->' , $key )) > 1 ) {
$ret [ 'tag' ] = array_shift ( $attrs );
$ret [ 'attribs' ] = $attrs ;
} else {
$ret [ 'tag' ] = $key ;
}
return $ret ;
}
function _validateStabilityVersion ()
{
$structure = array ( 'release' , 'api' );
$a = $this -> _stupidSchemaValidate ( $structure , $this -> _packageInfo [ 'version' ], '<version>' );
$a &= $this -> _stupidSchemaValidate ( $structure , $this -> _packageInfo [ 'stability' ], '<stability>' );
if ( $a ) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$this -> _packageInfo [ 'version' ][ 'release' ])) {
$this -> _invalidVersion ( 'release' , $this -> _packageInfo [ 'version' ][ 'release' ]);
}
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$this -> _packageInfo [ 'version' ][ 'api' ])) {
$this -> _invalidVersion ( 'api' , $this -> _packageInfo [ 'version' ][ 'api' ]);
}
if ( ! in_array ( $this -> _packageInfo [ 'stability' ][ 'release' ],
array ( 'snapshot' , 'devel' , 'alpha' , 'beta' , 'stable' ))) {
2009-01-05 00:22:54 +00:00
$this -> _invalidState ( 'release' , $this -> _packageInfo [ 'stability' ][ 'release' ]);
2008-11-26 22:50:40 +00:00
}
if ( ! in_array ( $this -> _packageInfo [ 'stability' ][ 'api' ],
array ( 'devel' , 'alpha' , 'beta' , 'stable' ))) {
2009-01-05 00:22:54 +00:00
$this -> _invalidState ( 'api' , $this -> _packageInfo [ 'stability' ][ 'api' ]);
2008-11-26 22:50:40 +00:00
}
}
}
function _validateMaintainers ()
{
$structure =
array (
'name' ,
'user' ,
'email' ,
'active' ,
);
foreach ( array ( 'lead' , 'developer' , 'contributor' , 'helper' ) as $type ) {
if ( ! isset ( $this -> _packageInfo [ $type ])) {
continue ;
}
if ( isset ( $this -> _packageInfo [ $type ][ 0 ])) {
foreach ( $this -> _packageInfo [ $type ] as $lead ) {
$this -> _stupidSchemaValidate ( $structure , $lead , '<' . $type . '>' );
}
} else {
$this -> _stupidSchemaValidate ( $structure , $this -> _packageInfo [ $type ],
'<' . $type . '>' );
}
}
}
function _validatePhpDep ( $dep , $installcondition = false )
{
$structure = array (
'min' ,
'*max' ,
'*exclude' ,
);
$type = $installcondition ? '<installcondition><php>' : '<dependencies><required><php>' ;
$this -> _stupidSchemaValidate ( $structure , $dep , $type );
if ( isset ( $dep [ 'min' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'min' ])) {
$this -> _invalidVersion ( $type . '<min>' , $dep [ 'min' ]);
}
}
if ( isset ( $dep [ 'max' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'max' ])) {
$this -> _invalidVersion ( $type . '<max>' , $dep [ 'max' ]);
}
}
2009-01-05 00:22:54 +00:00
if ( isset ( $dep [ 'exclude' ])) {
if ( ! is_array ( $dep [ 'exclude' ])) {
$dep [ 'exclude' ] = array ( $dep [ 'exclude' ]);
}
foreach ( $dep [ 'exclude' ] as $exclude ) {
if ( ! preg_match (
'/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?(?:-[a-zA-Z0-9]+)?\\z/' ,
$exclude )) {
$this -> _invalidVersion ( $type . '<exclude>' , $exclude );
}
}
}
2008-11-26 22:50:40 +00:00
}
function _validatePearinstallerDep ( $dep )
{
$structure = array (
'min' ,
'*max' ,
'*recommended' ,
'*exclude' ,
);
$this -> _stupidSchemaValidate ( $structure , $dep , '<dependencies><required><pearinstaller>' );
if ( isset ( $dep [ 'min' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'min' ])) {
$this -> _invalidVersion ( '<dependencies><required><pearinstaller><min>' ,
$dep [ 'min' ]);
}
}
if ( isset ( $dep [ 'max' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'max' ])) {
$this -> _invalidVersion ( '<dependencies><required><pearinstaller><max>' ,
$dep [ 'max' ]);
}
}
if ( isset ( $dep [ 'recommended' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'recommended' ])) {
$this -> _invalidVersion ( '<dependencies><required><pearinstaller><recommended>' ,
$dep [ 'recommended' ]);
}
}
if ( isset ( $dep [ 'exclude' ])) {
if ( ! is_array ( $dep [ 'exclude' ])) {
$dep [ 'exclude' ] = array ( $dep [ 'exclude' ]);
}
foreach ( $dep [ 'exclude' ] as $exclude ) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$exclude )) {
$this -> _invalidVersion ( '<dependencies><required><pearinstaller><exclude>' ,
$exclude );
}
}
}
}
function _validatePackageDep ( $dep , $group , $type = '<package>' )
{
if ( isset ( $dep [ 'uri' ])) {
if ( isset ( $dep [ 'conflicts' ])) {
$structure = array (
'name' ,
'uri' ,
'conflicts' ,
'*providesextension' ,
);
} else {
$structure = array (
'name' ,
'uri' ,
'*providesextension' ,
);
}
} else {
if ( isset ( $dep [ 'conflicts' ])) {
$structure = array (
'name' ,
'channel' ,
'*min' ,
'*max' ,
'*exclude' ,
'conflicts' ,
'*providesextension' ,
);
} else {
$structure = array (
'name' ,
'channel' ,
'*min' ,
'*max' ,
'*recommended' ,
'*exclude' ,
'*nodefault' ,
'*providesextension' ,
);
}
}
if ( isset ( $dep [ 'name' ])) {
$type .= '<name>' . $dep [ 'name' ] . '</name>' ;
}
$this -> _stupidSchemaValidate ( $structure , $dep , '<dependencies>' . $group . $type );
if ( isset ( $dep [ 'uri' ]) && ( isset ( $dep [ 'min' ]) || isset ( $dep [ 'max' ]) ||
isset ( $dep [ 'recommended' ]) || isset ( $dep [ 'exclude' ]))) {
$this -> _uriDepsCannotHaveVersioning ( '<dependencies>' . $group . $type );
}
if ( isset ( $dep [ 'channel' ]) && strtolower ( $dep [ 'channel' ]) == '__uri' ) {
$this -> _DepchannelCannotBeUri ( '<dependencies>' . $group . $type );
}
if ( isset ( $dep [ 'min' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'min' ])) {
$this -> _invalidVersion ( '<dependencies>' . $group . $type . '<min>' , $dep [ 'min' ]);
}
}
if ( isset ( $dep [ 'max' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'max' ])) {
$this -> _invalidVersion ( '<dependencies>' . $group . $type . '<max>' , $dep [ 'max' ]);
}
}
if ( isset ( $dep [ 'recommended' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'recommended' ])) {
$this -> _invalidVersion ( '<dependencies>' . $group . $type . '<recommended>' ,
$dep [ 'recommended' ]);
}
}
if ( isset ( $dep [ 'exclude' ])) {
if ( ! is_array ( $dep [ 'exclude' ])) {
$dep [ 'exclude' ] = array ( $dep [ 'exclude' ]);
}
foreach ( $dep [ 'exclude' ] as $exclude ) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$exclude )) {
$this -> _invalidVersion ( '<dependencies>' . $group . $type . '<exclude>' ,
$exclude );
}
}
}
}
function _validateSubpackageDep ( $dep , $group )
{
$this -> _validatePackageDep ( $dep , $group , '<subpackage>' );
if ( isset ( $dep [ 'providesextension' ])) {
2009-01-05 00:22:54 +00:00
$this -> _subpackageCannotProvideExtension ( isset ( $dep [ 'name' ]) ? $dep [ 'name' ] : '' );
2008-11-26 22:50:40 +00:00
}
if ( isset ( $dep [ 'conflicts' ])) {
2009-01-05 00:22:54 +00:00
$this -> _subpackagesCannotConflict ( isset ( $dep [ 'name' ]) ? $dep [ 'name' ] : '' );
2008-11-26 22:50:40 +00:00
}
}
function _validateExtensionDep ( $dep , $group = false , $installcondition = false )
{
if ( isset ( $dep [ 'conflicts' ])) {
$structure = array (
'name' ,
'*min' ,
'*max' ,
'*exclude' ,
'conflicts' ,
);
} else {
$structure = array (
'name' ,
'*min' ,
'*max' ,
'*recommended' ,
'*exclude' ,
);
}
if ( $installcondition ) {
$type = '<installcondition><extension>' ;
} else {
$type = '<dependencies>' . $group . '<extension>' ;
}
if ( isset ( $dep [ 'name' ])) {
$type .= '<name>' . $dep [ 'name' ] . '</name>' ;
}
$this -> _stupidSchemaValidate ( $structure , $dep , $type );
if ( isset ( $dep [ 'min' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'min' ])) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<min' , $dep [ 'min' ]);
}
}
if ( isset ( $dep [ 'max' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'max' ])) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<max' , $dep [ 'max' ]);
}
}
if ( isset ( $dep [ 'recommended' ])) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$dep [ 'recommended' ])) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<recommended' , $dep [ 'recommended' ]);
}
}
if ( isset ( $dep [ 'exclude' ])) {
if ( ! is_array ( $dep [ 'exclude' ])) {
$dep [ 'exclude' ] = array ( $dep [ 'exclude' ]);
}
foreach ( $dep [ 'exclude' ] as $exclude ) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$exclude )) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<exclude' , $exclude );
}
}
}
}
function _validateOsDep ( $dep , $installcondition = false )
{
$structure = array (
'name' ,
'*conflicts' ,
);
$type = $installcondition ? '<installcondition><os>' : '<dependencies><required><os>' ;
if ( $this -> _stupidSchemaValidate ( $structure , $dep , $type )) {
if ( $dep [ 'name' ] == '*' ) {
if ( array_key_exists ( 'conflicts' , $dep )) {
$this -> _cannotConflictWithAllOs ( $type );
}
}
}
}
function _validateArchDep ( $dep , $installcondition = false )
{
$structure = array (
'pattern' ,
'*conflicts' ,
);
$type = $installcondition ? '<installcondition><arch>' : '<dependencies><required><arch>' ;
$this -> _stupidSchemaValidate ( $structure , $dep , $type );
}
function _validateInstallConditions ( $cond , $release )
{
$structure = array (
'*php' ,
'*extension' ,
'*os' ,
'*arch' ,
);
if ( ! $this -> _stupidSchemaValidate ( $structure ,
$cond , $release )) {
return false ;
}
foreach ( array ( 'php' , 'extension' , 'os' , 'arch' ) as $type ) {
if ( isset ( $cond [ $type ])) {
$iter = $cond [ $type ];
if ( ! is_array ( $iter ) || ! isset ( $iter [ 0 ])) {
$iter = array ( $iter );
}
foreach ( $iter as $package ) {
if ( $type == 'extension' ) {
$this -> { " _validate { $type } Dep " }( $package , false , true );
} else {
$this -> { " _validate { $type } Dep " }( $package , true );
}
}
}
}
}
function _validateDependencies ()
{
$structure = array (
'required' ,
'*optional' ,
'*group->name->hint'
);
if ( ! $this -> _stupidSchemaValidate ( $structure ,
$this -> _packageInfo [ 'dependencies' ], '<dependencies>' )) {
return false ;
}
foreach ( array ( 'required' , 'optional' ) as $simpledep ) {
if ( isset ( $this -> _packageInfo [ 'dependencies' ][ $simpledep ])) {
if ( $simpledep == 'optional' ) {
$structure = array (
'*package' ,
'*subpackage' ,
'*extension' ,
);
} else {
$structure = array (
'php' ,
'pearinstaller' ,
'*package' ,
'*subpackage' ,
'*extension' ,
'*os' ,
'*arch' ,
);
}
if ( $this -> _stupidSchemaValidate ( $structure ,
$this -> _packageInfo [ 'dependencies' ][ $simpledep ],
" <dependencies>< $simpledep > " )) {
foreach ( array ( 'package' , 'subpackage' , 'extension' ) as $type ) {
if ( isset ( $this -> _packageInfo [ 'dependencies' ][ $simpledep ][ $type ])) {
$iter = $this -> _packageInfo [ 'dependencies' ][ $simpledep ][ $type ];
if ( ! isset ( $iter [ 0 ])) {
$iter = array ( $iter );
}
foreach ( $iter as $package ) {
if ( $type != 'extension' ) {
if ( isset ( $package [ 'uri' ])) {
if ( isset ( $package [ 'channel' ])) {
$this -> _UrlOrChannel ( $type ,
$package [ 'name' ]);
}
} else {
if ( ! isset ( $package [ 'channel' ])) {
$this -> _NoChannel ( $type , $package [ 'name' ]);
}
}
}
$this -> { " _validate { $type } Dep " }( $package , " < $simpledep > " );
}
}
}
if ( $simpledep == 'optional' ) {
continue ;
}
foreach ( array ( 'php' , 'pearinstaller' , 'os' , 'arch' ) as $type ) {
if ( isset ( $this -> _packageInfo [ 'dependencies' ][ $simpledep ][ $type ])) {
$iter = $this -> _packageInfo [ 'dependencies' ][ $simpledep ][ $type ];
if ( ! isset ( $iter [ 0 ])) {
$iter = array ( $iter );
}
foreach ( $iter as $package ) {
$this -> { " _validate { $type } Dep " }( $package );
}
}
}
}
}
}
if ( isset ( $this -> _packageInfo [ 'dependencies' ][ 'group' ])) {
$groups = $this -> _packageInfo [ 'dependencies' ][ 'group' ];
if ( ! isset ( $groups [ 0 ])) {
$groups = array ( $groups );
}
$structure = array (
'*package' ,
'*subpackage' ,
'*extension' ,
);
foreach ( $groups as $group ) {
if ( $this -> _stupidSchemaValidate ( $structure , $group , '<group>' )) {
if ( ! PEAR_Validate :: validGroupName ( $group [ 'attribs' ][ 'name' ])) {
$this -> _invalidDepGroupName ( $group [ 'attribs' ][ 'name' ]);
}
foreach ( array ( 'package' , 'subpackage' , 'extension' ) as $type ) {
if ( isset ( $group [ $type ])) {
$iter = $group [ $type ];
if ( ! isset ( $iter [ 0 ])) {
$iter = array ( $iter );
}
foreach ( $iter as $package ) {
if ( $type != 'extension' ) {
if ( isset ( $package [ 'uri' ])) {
if ( isset ( $package [ 'channel' ])) {
$this -> _UrlOrChannelGroup ( $type ,
$package [ 'name' ],
$group [ 'name' ]);
}
} else {
if ( ! isset ( $package [ 'channel' ])) {
$this -> _NoChannelGroup ( $type ,
$package [ 'name' ],
$group [ 'name' ]);
}
}
}
$this -> { " _validate { $type } Dep " }( $package , '<group name="' .
$group [ 'attribs' ][ 'name' ] . '">' );
}
}
}
}
}
}
}
function _validateCompatible ()
{
$compat = $this -> _packageInfo [ 'compatible' ];
if ( ! isset ( $compat [ 0 ])) {
$compat = array ( $compat );
}
$required = array ( 'name' , 'channel' , 'min' , 'max' , '*exclude' );
foreach ( $compat as $package ) {
$type = '<compatible>' ;
if ( is_array ( $package ) && array_key_exists ( 'name' , $package )) {
$type .= '<name>' . $package [ 'name' ] . '</name>' ;
}
$this -> _stupidSchemaValidate ( $required , $package , $type );
if ( is_array ( $package ) && array_key_exists ( 'min' , $package )) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$package [ 'min' ])) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<min' , $package [ 'min' ]);
}
}
if ( is_array ( $package ) && array_key_exists ( 'max' , $package )) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$package [ 'max' ])) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<max' , $package [ 'max' ]);
}
}
if ( is_array ( $package ) && array_key_exists ( 'exclude' , $package )) {
if ( ! is_array ( $package [ 'exclude' ])) {
$package [ 'exclude' ] = array ( $package [ 'exclude' ]);
}
foreach ( $package [ 'exclude' ] as $exclude ) {
2009-01-05 00:22:54 +00:00
if ( ! preg_match ( '/^\d+(?:\.\d+)*(?:[a-zA-Z]+\d*)?\\z/' ,
2008-11-26 22:50:40 +00:00
$exclude )) {
$this -> _invalidVersion ( substr ( $type , 1 ) . '<exclude' , $exclude );
}
}
}
}
}
function _validateBundle ( $list )
{
if ( ! is_array ( $list ) || ! isset ( $list [ 'bundledpackage' ])) {
return $this -> _NoBundledPackages ();
}
if ( ! is_array ( $list [ 'bundledpackage' ]) || ! isset ( $list [ 'bundledpackage' ][ 0 ])) {
return $this -> _AtLeast2BundledPackages ();
}
foreach ( $list [ 'bundledpackage' ] as $package ) {
if ( ! is_string ( $package )) {
$this -> _bundledPackagesMustBeFilename ();
}
}
}
function _validateFilelist ( $list = false , $allowignore = false , $dirs = '' )
{
$iscontents = false ;
if ( ! $list ) {
$iscontents = true ;
$list = $this -> _packageInfo [ 'contents' ];
if ( isset ( $this -> _packageInfo [ 'bundle' ])) {
return $this -> _validateBundle ( $list );
}
}
if ( $allowignore ) {
$struc = array (
'*install->name->as' ,
'*ignore->name'
);
} else {
$struc = array (
'*dir->name->?baseinstalldir' ,
'*file->name->role->?baseinstalldir->?md5sum'
);
if ( isset ( $list [ 'dir' ]) && isset ( $list [ 'file' ])) {
// stave off validation errors without requiring a set order.
$_old = $list ;
if ( isset ( $list [ 'attribs' ])) {
$list = array ( 'attribs' => $_old [ 'attribs' ]);
}
$list [ 'dir' ] = $_old [ 'dir' ];
$list [ 'file' ] = $_old [ 'file' ];
}
}
if ( ! isset ( $list [ 'attribs' ]) || ! isset ( $list [ 'attribs' ][ 'name' ])) {
$unknown = $allowignore ? '<filelist>' : '<dir name="*unknown*">' ;
$dirname = $iscontents ? '<contents>' : $unknown ;
} else {
$dirname = '<dir name="' . $list [ 'attribs' ][ 'name' ] . '">' ;
2009-01-05 00:22:54 +00:00
if ( preg_match ( '~/\.\.?(/|\\z)|^\.\.?/~' ,
str_replace ( '\\' , '/' , $list [ 'attribs' ][ 'name' ]))) {
// file contains .. parent directory or . cur directory
$this -> _invalidDirName ( $list [ 'attribs' ][ 'name' ]);
}
2008-11-26 22:50:40 +00:00
}
$res = $this -> _stupidSchemaValidate ( $struc , $list , $dirname );
if ( $allowignore && $res ) {
2009-01-05 00:22:54 +00:00
$ignored_or_installed = array ();
2008-11-26 22:50:40 +00:00
$this -> _pf -> getFilelist ();
$fcontents = $this -> _pf -> getContents ();
$filelist = array ();
if ( ! isset ( $fcontents [ 'dir' ][ 'file' ][ 0 ])) {
$fcontents [ 'dir' ][ 'file' ] = array ( $fcontents [ 'dir' ][ 'file' ]);
}
foreach ( $fcontents [ 'dir' ][ 'file' ] as $file ) {
$filelist [ $file [ 'attribs' ][ 'name' ]] = true ;
}
if ( isset ( $list [ 'install' ])) {
if ( ! isset ( $list [ 'install' ][ 0 ])) {
$list [ 'install' ] = array ( $list [ 'install' ]);
}
foreach ( $list [ 'install' ] as $file ) {
if ( ! isset ( $filelist [ $file [ 'attribs' ][ 'name' ]])) {
$this -> _notInContents ( $file [ 'attribs' ][ 'name' ], 'install' );
2009-01-05 00:22:54 +00:00
continue ;
}
if ( array_key_exists ( $file [ 'attribs' ][ 'name' ], $ignored_or_installed )) {
$this -> _multipleInstallAs ( $file [ 'attribs' ][ 'name' ]);
}
if ( ! isset ( $ignored_or_installed [ $file [ 'attribs' ][ 'name' ]])) {
$ignored_or_installed [ $file [ 'attribs' ][ 'name' ]] = array ();
}
$ignored_or_installed [ $file [ 'attribs' ][ 'name' ]][] = 1 ;
if ( preg_match ( '~/\.\.?(/|\\z)|^\.\.?/~' ,
str_replace ( '\\' , '/' , $file [ 'attribs' ][ 'as' ]))) {
// file contains .. parent directory or . cur directory references
$this -> _invalidFileInstallAs ( $file [ 'attribs' ][ 'name' ],
$file [ 'attribs' ][ 'as' ]);
2008-11-26 22:50:40 +00:00
}
}
}
if ( isset ( $list [ 'ignore' ])) {
if ( ! isset ( $list [ 'ignore' ][ 0 ])) {
$list [ 'ignore' ] = array ( $list [ 'ignore' ]);
}
foreach ( $list [ 'ignore' ] as $file ) {
if ( ! isset ( $filelist [ $file [ 'attribs' ][ 'name' ]])) {
$this -> _notInContents ( $file [ 'attribs' ][ 'name' ], 'ignore' );
2009-01-05 00:22:54 +00:00
continue ;
}
if ( array_key_exists ( $file [ 'attribs' ][ 'name' ], $ignored_or_installed )) {
$this -> _ignoreAndInstallAs ( $file [ 'attribs' ][ 'name' ]);
2008-11-26 22:50:40 +00:00
}
}
}
}
if ( ! $allowignore && isset ( $list [ 'file' ])) {
2009-01-05 00:22:54 +00:00
if ( is_string ( $list [ 'file' ])) {
$this -> _oldStyleFileNotAllowed ();
return false ;
}
2008-11-26 22:50:40 +00:00
if ( ! isset ( $list [ 'file' ][ 0 ])) {
// single file
$list [ 'file' ] = array ( $list [ 'file' ]);
}
foreach ( $list [ 'file' ] as $i => $file )
{
2009-01-05 00:22:54 +00:00
if ( isset ( $file [ 'attribs' ]) && isset ( $file [ 'attribs' ][ 'name' ])) {
if ( $file [ 'attribs' ][ 'name' ]{ 0 } == '.' &&
$file [ 'attribs' ][ 'name' ]{ 1 } == '/' ) {
// name is something like "./doc/whatever.txt"
$this -> _invalidFileName ( $file [ 'attribs' ][ 'name' ], $dirname );
}
if ( preg_match ( '~/\.\.?(/|\\z)|^\.\.?/~' ,
str_replace ( '\\' , '/' , $file [ 'attribs' ][ 'name' ]))) {
// file contains .. parent directory or . cur directory
$this -> _invalidFileName ( $file [ 'attribs' ][ 'name' ], $dirname );
}
2008-11-26 22:50:40 +00:00
}
if ( isset ( $file [ 'attribs' ]) && isset ( $file [ 'attribs' ][ 'role' ])) {
if ( ! $this -> _validateRole ( $file [ 'attribs' ][ 'role' ])) {
if ( isset ( $this -> _packageInfo [ 'usesrole' ])) {
$roles = $this -> _packageInfo [ 'usesrole' ];
if ( ! isset ( $roles [ 0 ])) {
$roles = array ( $roles );
}
foreach ( $roles as $role ) {
if ( $role [ 'role' ] = $file [ 'attribs' ][ 'role' ]) {
$msg = 'This package contains role "%role%" and requires ' .
'package "%package%" to be used' ;
if ( isset ( $role [ 'uri' ])) {
$params = array ( 'role' => $role [ 'role' ],
'package' => $role [ 'uri' ]);
} else {
$params = array ( 'role' => $role [ 'role' ],
'package' => $this -> _pf -> _registry ->
parsedPackageNameToString ( array ( 'package' =>
$role [ 'package' ], 'channel' => $role [ 'channel' ]),
true ));
}
$this -> _stack -> push ( '_mustInstallRole' , 'error' , $params , $msg );
}
}
}
$this -> _invalidFileRole ( $file [ 'attribs' ][ 'name' ],
$dirname , $file [ 'attribs' ][ 'role' ]);
}
}
if ( ! isset ( $file [ 'attribs' ])) {
continue ;
}
$save = $file [ 'attribs' ];
if ( $dirs ) {
$save [ 'name' ] = $dirs . '/' . $save [ 'name' ];
}
unset ( $file [ 'attribs' ]);
if ( count ( $file ) && $this -> _curState != PEAR_VALIDATE_DOWNLOADING ) { // has tasks
foreach ( $file as $task => $value ) {
if ( $tagClass = $this -> _pf -> getTask ( $task )) {
if ( ! is_array ( $value ) || ! isset ( $value [ 0 ])) {
$value = array ( $value );
}
foreach ( $value as $v ) {
$ret = call_user_func ( array ( $tagClass , 'validateXml' ),
$this -> _pf , $v , $this -> _pf -> _config , $save );
if ( is_array ( $ret )) {
2009-01-05 00:22:54 +00:00
$this -> _invalidTask ( $task , $ret , isset ( $save [ 'name' ]) ?
$save [ 'name' ] : '' );
2008-11-26 22:50:40 +00:00
}
}
} else {
if ( isset ( $this -> _packageInfo [ 'usestask' ])) {
$roles = $this -> _packageInfo [ 'usestask' ];
if ( ! isset ( $roles [ 0 ])) {
$roles = array ( $roles );
}
foreach ( $roles as $role ) {
if ( $role [ 'task' ] = $task ) {
$msg = 'This package contains task "%task%" and requires ' .
'package "%package%" to be used' ;
if ( isset ( $role [ 'uri' ])) {
$params = array ( 'task' => $role [ 'task' ],
'package' => $role [ 'uri' ]);
} else {
$params = array ( 'task' => $role [ 'task' ],
'package' => $this -> _pf -> _registry ->
parsedPackageNameToString ( array ( 'package' =>
$role [ 'package' ], 'channel' => $role [ 'channel' ]),
true ));
}
$this -> _stack -> push ( '_mustInstallTask' , 'error' ,
$params , $msg );
}
}
}
$this -> _unknownTask ( $task , $save [ 'name' ]);
}
}
}
}
}
if ( isset ( $list [ 'ignore' ])) {
if ( ! $allowignore ) {
$this -> _ignoreNotAllowed ( 'ignore' );
}
}
if ( isset ( $list [ 'install' ])) {
if ( ! $allowignore ) {
$this -> _ignoreNotAllowed ( 'install' );
}
}
if ( isset ( $list [ 'file' ])) {
if ( $allowignore ) {
$this -> _fileNotAllowed ( 'file' );
}
}
if ( isset ( $list [ 'dir' ])) {
if ( $allowignore ) {
$this -> _fileNotAllowed ( 'dir' );
} else {
if ( ! isset ( $list [ 'dir' ][ 0 ])) {
$list [ 'dir' ] = array ( $list [ 'dir' ]);
}
foreach ( $list [ 'dir' ] as $dir ) {
if ( isset ( $dir [ 'attribs' ]) && isset ( $dir [ 'attribs' ][ 'name' ])) {
if ( $dir [ 'attribs' ][ 'name' ] == '/' ||
! isset ( $this -> _packageInfo [ 'contents' ][ 'dir' ][ 'dir' ])) {
// always use nothing if the filelist has already been flattened
$newdirs = '' ;
} elseif ( $dirs == '' ) {
$newdirs = $dir [ 'attribs' ][ 'name' ];
} else {
$newdirs = $dirs . '/' . $dir [ 'attribs' ][ 'name' ];
}
} else {
$newdirs = $dirs ;
}
$this -> _validateFilelist ( $dir , $allowignore , $newdirs );
}
}
}
}
function _validateRelease ()
{
if ( isset ( $this -> _packageInfo [ 'phprelease' ])) {
$release = 'phprelease' ;
if ( isset ( $this -> _packageInfo [ 'providesextension' ])) {
$this -> _cannotProvideExtension ( $release );
}
if ( isset ( $this -> _packageInfo [ 'srcpackage' ]) || isset ( $this -> _packageInfo [ 'srcuri' ])) {
$this -> _cannotHaveSrcpackage ( $release );
}
$releases = $this -> _packageInfo [ 'phprelease' ];
if ( ! is_array ( $releases )) {
return true ;
}
if ( ! isset ( $releases [ 0 ])) {
$releases = array ( $releases );
}
foreach ( $releases as $rel ) {
$this -> _stupidSchemaValidate ( array (
'*installconditions' ,
'*filelist' ,
), $rel , '<phprelease>' );
}
}
2009-01-05 00:22:54 +00:00
foreach ( array ( '' , 'zend' ) as $prefix ) {
$releasetype = $prefix . 'extsrcrelease' ;
if ( isset ( $this -> _packageInfo [ $releasetype ])) {
$release = $releasetype ;
if ( ! isset ( $this -> _packageInfo [ 'providesextension' ])) {
$this -> _mustProvideExtension ( $release );
}
if ( isset ( $this -> _packageInfo [ 'srcpackage' ]) || isset ( $this -> _packageInfo [ 'srcuri' ])) {
$this -> _cannotHaveSrcpackage ( $release );
}
$releases = $this -> _packageInfo [ $releasetype ];
if ( ! is_array ( $releases )) {
return true ;
}
if ( ! isset ( $releases [ 0 ])) {
$releases = array ( $releases );
}
foreach ( $releases as $rel ) {
$this -> _stupidSchemaValidate ( array (
'*installconditions' ,
'*configureoption->name->prompt->?default' ,
'*binarypackage' ,
'*filelist' ,
), $rel , '<' . $releasetype . '>' );
if ( isset ( $rel [ 'binarypackage' ])) {
if ( ! is_array ( $rel [ 'binarypackage' ]) || ! isset ( $rel [ 'binarypackage' ][ 0 ])) {
$rel [ 'binarypackage' ] = array ( $rel [ 'binarypackage' ]);
}
foreach ( $rel [ 'binarypackage' ] as $bin ) {
if ( ! is_string ( $bin )) {
$this -> _binaryPackageMustBePackagename ();
}
2008-11-26 22:50:40 +00:00
}
}
}
}
2009-01-05 00:22:54 +00:00
$releasetype = 'extbinrelease' ;
if ( isset ( $this -> _packageInfo [ $releasetype ])) {
$release = $releasetype ;
if ( ! isset ( $this -> _packageInfo [ 'providesextension' ])) {
$this -> _mustProvideExtension ( $release );
}
if ( isset ( $this -> _packageInfo [ 'channel' ]) &&
! isset ( $this -> _packageInfo [ 'srcpackage' ])) {
$this -> _mustSrcPackage ( $release );
}
if ( isset ( $this -> _packageInfo [ 'uri' ]) && ! isset ( $this -> _packageInfo [ 'srcuri' ])) {
$this -> _mustSrcuri ( $release );
}
$releases = $this -> _packageInfo [ $releasetype ];
if ( ! is_array ( $releases )) {
return true ;
}
if ( ! isset ( $releases [ 0 ])) {
$releases = array ( $releases );
}
foreach ( $releases as $rel ) {
$this -> _stupidSchemaValidate ( array (
'*installconditions' ,
'*filelist' ,
), $rel , '<' . $releasetype . '>' );
}
2008-11-26 22:50:40 +00:00
}
}
if ( isset ( $this -> _packageInfo [ 'bundle' ])) {
$release = 'bundle' ;
if ( isset ( $this -> _packageInfo [ 'providesextension' ])) {
$this -> _cannotProvideExtension ( $release );
}
if ( isset ( $this -> _packageInfo [ 'srcpackage' ]) || isset ( $this -> _packageInfo [ 'srcuri' ])) {
$this -> _cannotHaveSrcpackage ( $release );
}
$releases = $this -> _packageInfo [ 'bundle' ];
if ( ! is_array ( $releases ) || ! isset ( $releases [ 0 ])) {
$releases = array ( $releases );
}
foreach ( $releases as $rel ) {
$this -> _stupidSchemaValidate ( array (
'*installconditions' ,
'*filelist' ,
), $rel , '<bundle>' );
}
}
foreach ( $releases as $rel ) {
if ( is_array ( $rel ) && array_key_exists ( 'installconditions' , $rel )) {
$this -> _validateInstallConditions ( $rel [ 'installconditions' ],
" < $release ><installconditions> " );
}
if ( is_array ( $rel ) && array_key_exists ( 'filelist' , $rel )) {
if ( $rel [ 'filelist' ]) {
2009-01-05 00:22:54 +00:00
2008-11-26 22:50:40 +00:00
$this -> _validateFilelist ( $rel [ 'filelist' ], true );
}
}
}
}
/**
* This is here to allow role extension through plugins
* @ param string
*/
function _validateRole ( $role )
{
return in_array ( $role , PEAR_Installer_Role :: getValidRoles ( $this -> _pf -> getPackageType ()));
}
2009-01-05 00:22:54 +00:00
function _pearVersionTooLow ( $version )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' ,
array ( 'version' => $version ),
'This package.xml requires PEAR version %version% to parse properly, we are ' .
'version 1.7.2' );
}
2008-11-26 22:50:40 +00:00
function _invalidTagOrder ( $oktags , $actual , $root )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' ,
array ( 'oktags' => $oktags , 'actual' => $actual , 'root' => $root ),
'Invalid tag order in %root%, found <%actual%> expected one of "%oktags%"' );
}
function _ignoreNotAllowed ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ),
'<%type%> is not allowed inside global <contents>, only inside ' .
2009-01-05 00:22:54 +00:00
'<phprelease>/<extbinrelease>/<zendextbinrelease>, use <dir> and <file> only' );
2008-11-26 22:50:40 +00:00
}
function _fileNotAllowed ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ),
'<%type%> is not allowed inside release <filelist>, only inside ' .
'<contents>, use <ignore> and <install> only' );
}
2009-01-05 00:22:54 +00:00
function _oldStyleFileNotAllowed ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'Old-style <file>name</file> is not allowed. Use' .
'<file name="name" role="role"/>' );
}
2008-11-26 22:50:40 +00:00
function _tagMissingAttribute ( $tag , $attr , $context )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $tag ,
'attribute' => $attr , 'context' => $context ),
'tag <%tag%> in context "%context%" has no attribute "%attribute%"' );
}
function _tagHasNoAttribs ( $tag , $context )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $tag ,
'context' => $context ),
'tag <%tag%> has no attributes in context "%context%"' );
}
function _invalidInternalStructure ()
{
$this -> _stack -> push ( __FUNCTION__ , 'exception' , array (),
'internal array was not generated by compatible parser, or extreme parser error, cannot continue' );
}
function _invalidFileRole ( $file , $dir , $role )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (
'file' => $file , 'dir' => $dir , 'role' => $role ,
'roles' => PEAR_Installer_Role :: getValidRoles ( $this -> _pf -> getPackageType ())),
'File "%file%" in directory "%dir%" has invalid role "%role%", should be one of %roles%' );
}
function _invalidFileName ( $file , $dir )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (
'file' => $file ),
2009-01-05 00:22:54 +00:00
'File "%file%" in directory "%dir%" cannot begin with "./" or contain ".."' );
}
function _invalidFileInstallAs ( $file , $as )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (
'file' => $file , 'as' => $as ),
'File "%file%" <install as="%as%"/> cannot contain "./" or contain ".."' );
}
function _invalidDirName ( $dir )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (
'dir' => $file ),
'Directory "%dir%" cannot begin with "./" or contain ".."' );
2008-11-26 22:50:40 +00:00
}
function _filelistCannotContainFile ( $filelist )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $filelist ),
'<%tag%> can only contain <dir>, contains <file>. Use ' .
'<dir name="/"> as the first dir element' );
}
function _filelistMustContainDir ( $filelist )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $filelist ),
'<%tag%> must contain <dir>. Use <dir name="/"> as the ' .
'first dir element' );
}
function _tagCannotBeEmpty ( $tag )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $tag ),
'<%tag%> cannot be empty (<%tag%/>)' );
}
function _UrlOrChannel ( $type , $name )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ,
'name' => $name ),
'Required dependency <%type%> "%name%" can have either url OR ' .
'channel attributes, and not both' );
}
function _NoChannel ( $type , $name )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ,
'name' => $name ),
'Required dependency <%type%> "%name%" must have either url OR ' .
'channel attributes' );
}
function _UrlOrChannelGroup ( $type , $name , $group )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ,
'name' => $name , 'group' => $group ),
'Group "%group%" dependency <%type%> "%name%" can have either url OR ' .
'channel attributes, and not both' );
}
function _NoChannelGroup ( $type , $name , $group )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ,
'name' => $name , 'group' => $group ),
'Group "%group%" dependency <%type%> "%name%" must have either url OR ' .
'channel attributes' );
}
function _unknownChannel ( $channel )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'channel' => $channel ),
'Unknown channel "%channel%"' );
}
function _noPackageVersion ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'package.xml <package> tag has no version attribute, or version is not 2.0' );
}
function _NoBundledPackages ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'No <bundledpackage> tag was found in <contents>, required for bundle packages' );
}
function _AtLeast2BundledPackages ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'At least 2 packages must be bundled in a bundle package' );
}
function _ChannelOrUri ( $name )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'name' => $name ),
'Bundled package "%name%" can have either a uri or a channel, not both' );
}
function _noChildTag ( $child , $tag )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'child' => $child , 'tag' => $tag ),
'Tag <%tag%> is missing child tag <%child%>' );
}
function _invalidVersion ( $type , $value )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type , 'value' => $value ),
'Version type <%type%> is not a valid version (%value%)' );
}
function _invalidState ( $type , $value )
{
$states = array ( 'stable' , 'beta' , 'alpha' , 'devel' );
if ( $type != 'api' ) {
$states [] = 'snapshot' ;
}
if ( strtolower ( $value ) == 'rc' ) {
$this -> _stack -> push ( __FUNCTION__ , 'error' ,
array ( 'version' => $this -> _packageInfo [ 'version' ][ 'release' ]),
'RC is not a state, it is a version postfix, try %version%RC1, stability beta' );
}
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type , 'value' => $value ,
'types' => $states ),
'Stability type <%type%> is not a valid stability (%value%), must be one of ' .
'%types%' );
}
function _invalidTask ( $task , $ret , $file )
{
switch ( $ret [ 0 ]) {
case PEAR_TASK_ERROR_MISSING_ATTRIB :
$info = array ( 'attrib' => $ret [ 1 ], 'task' => $task , 'file' => $file );
$msg = 'task <%task%> is missing attribute "%attrib%" in file %file%' ;
break ;
case PEAR_TASK_ERROR_NOATTRIBS :
$info = array ( 'task' => $task , 'file' => $file );
$msg = 'task <%task%> has no attributes in file %file%' ;
break ;
case PEAR_TASK_ERROR_WRONG_ATTRIB_VALUE :
$info = array ( 'attrib' => $ret [ 1 ], 'values' => $ret [ 3 ],
'was' => $ret [ 2 ], 'task' => $task , 'file' => $file );
$msg = 'task <%task%> attribute "%attrib%" has the wrong value "%was%" ' .
'in file %file%, expecting one of "%values%"' ;
break ;
case PEAR_TASK_ERROR_INVALID :
$info = array ( 'reason' => $ret [ 1 ], 'task' => $task , 'file' => $file );
$msg = 'task <%task%> in file %file% is invalid because of "%reason%"' ;
break ;
}
$this -> _stack -> push ( __FUNCTION__ , 'error' , $info , $msg );
}
function _unknownTask ( $task , $file )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'task' => $task , 'file' => $file ),
'Unknown task "%task%" passed in file <file name="%file%">' );
}
function _subpackageCannotProvideExtension ( $name )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'name' => $name ),
'Subpackage dependency "%name%" cannot use <providesextension>, ' .
'only package dependencies can use this tag' );
}
function _subpackagesCannotConflict ( $name )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'name' => $name ),
'Subpackage dependency "%name%" cannot use <conflicts/>, ' .
'only package dependencies can use this tag' );
}
function _cannotProvideExtension ( $release )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'release' => $release ),
2009-01-05 00:22:54 +00:00
'<%release%> packages cannot use <providesextension>, only extbinrelease, extsrcrelease, zendextsrcrelease, and zendextbinrelease can provide a PHP extension' );
2008-11-26 22:50:40 +00:00
}
function _mustProvideExtension ( $release )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'release' => $release ),
'<%release%> packages must use <providesextension> to indicate which PHP extension is provided' );
}
function _cannotHaveSrcpackage ( $release )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'release' => $release ),
'<%release%> packages cannot specify a source code package, only extension binaries may use the <srcpackage> tag' );
}
function _mustSrcPackage ( $release )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'release' => $release ),
2009-01-05 00:22:54 +00:00
'<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcpackage>' );
2008-11-26 22:50:40 +00:00
}
function _mustSrcuri ( $release )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'release' => $release ),
2009-01-05 00:22:54 +00:00
'<extbinrelease>/<zendextbinrelease> packages must specify a source code package with <srcuri>' );
2008-11-26 22:50:40 +00:00
}
function _uriDepsCannotHaveVersioning ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ),
'%type%: dependencies with a <uri> tag cannot have any versioning information' );
}
function _conflictingDepsCannotHaveVersioning ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ),
'%type%: conflicting dependencies cannot have versioning info, use <exclude> to ' .
'exclude specific versions of a dependency' );
}
function _DepchannelCannotBeUri ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'type' => $type ),
'%type%: channel cannot be __uri, this is a pseudo-channel reserved for uri ' .
'dependencies only' );
}
function _bundledPackagesMustBeFilename ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'<bundledpackage> tags must contain only the filename of a package release ' .
'in the bundle' );
}
function _binaryPackageMustBePackagename ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'<binarypackage> tags must contain the name of a package that is ' .
2009-01-05 00:22:54 +00:00
'a compiled version of this extsrc/zendextsrc package' );
2008-11-26 22:50:40 +00:00
}
function _fileNotFound ( $file )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file ),
'File "%file%" in package.xml does not exist' );
}
function _notInContents ( $file , $tag )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file , 'tag' => $tag ),
'<%tag% name="%file%"> is invalid, file is not in <contents>' );
}
function _cannotValidateNoPathSet ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'Cannot validate files, no path to package file is set (use setPackageFile())' );
}
function _usesroletaskMustHaveChannelOrUri ( $role , $tag )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'role' => $role , 'tag' => $tag ),
2009-01-05 00:22:54 +00:00
'<%tag%> for role "%role%" must contain either <uri>, or <channel> and <package>' );
2008-11-26 22:50:40 +00:00
}
function _usesroletaskMustHavePackage ( $role , $tag )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'role' => $role , 'tag' => $tag ),
2009-01-05 00:22:54 +00:00
'<%tag%> for role "%role%" must contain <package>' );
2008-11-26 22:50:40 +00:00
}
function _usesroletaskMustHaveRoleTask ( $tag , $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $tag , 'type' => $type ),
'<%tag%> must contain <%type%> defining the %type% to be used' );
}
function _cannotConflictWithAllOs ( $type )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'tag' => $tag ),
'%tag% cannot conflict with all OSes' );
}
function _invalidDepGroupName ( $name )
{
2009-01-05 00:22:54 +00:00
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'name' => $name ),
2008-11-26 22:50:40 +00:00
'Invalid dependency group name "%name%"' );
}
2009-01-05 00:22:54 +00:00
function _multipleToplevelDirNotAllowed ()
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array (),
'Multiple top-level <dir> tags are not allowed. Enclose them ' .
'in a <dir name="/">' );
}
function _multipleInstallAs ( $file )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file ),
'Only one <install> tag is allowed for file "%file%"' );
}
function _ignoreAndInstallAs ( $file )
{
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file ),
'Cannot have both <ignore> and <install> tags for file "%file%"' );
}
2008-11-26 22:50:40 +00:00
function _analyzeBundledPackages ()
{
if ( ! $this -> _isValid ) {
return false ;
}
if ( ! $this -> _pf -> getPackageType () == 'bundle' ) {
return false ;
}
if ( ! isset ( $this -> _pf -> _packageFile )) {
return false ;
}
$dir_prefix = dirname ( $this -> _pf -> _packageFile );
2009-01-05 00:22:54 +00:00
$common = new PEAR_Common ;
2008-11-26 22:50:40 +00:00
$log = isset ( $this -> _pf -> _logger ) ? array ( & $this -> _pf -> _logger , 'log' ) :
2009-01-05 00:22:54 +00:00
array ( $common , 'log' );
2008-11-26 22:50:40 +00:00
$info = $this -> _pf -> getContents ();
$info = $info [ 'bundledpackage' ];
if ( ! is_array ( $info )) {
$info = array ( $info );
}
$pkg = & new PEAR_PackageFile ( $this -> _pf -> _config );
foreach ( $info as $package ) {
if ( ! file_exists ( $dir_prefix . DIRECTORY_SEPARATOR . $package )) {
$this -> _fileNotFound ( $dir_prefix . DIRECTORY_SEPARATOR . $package );
$this -> _isValid = 0 ;
continue ;
}
call_user_func_array ( $log , array ( 1 , " Analyzing bundled package $package " ));
PEAR :: pushErrorHandling ( PEAR_ERROR_RETURN );
$ret = $pkg -> fromAnyFile ( $dir_prefix . DIRECTORY_SEPARATOR . $package ,
PEAR_VALIDATE_NORMAL );
PEAR :: popErrorHandling ();
if ( PEAR :: isError ( $ret )) {
call_user_func_array ( $log , array ( 0 , " ERROR: package $package is not a valid " .
'package' ));
$inf = $ret -> getUserInfo ();
if ( is_array ( $inf )) {
foreach ( $inf as $err ) {
call_user_func_array ( $log , array ( 1 , $err [ 'message' ]));
}
}
return false ;
}
}
return true ;
}
function _analyzePhpFiles ()
{
if ( ! $this -> _isValid ) {
return false ;
}
if ( ! isset ( $this -> _pf -> _packageFile )) {
$this -> _cannotValidateNoPathSet ();
return false ;
}
$dir_prefix = dirname ( $this -> _pf -> _packageFile );
$common = new PEAR_Common ;
$log = isset ( $this -> _pf -> _logger ) ? array ( & $this -> _pf -> _logger , 'log' ) :
array ( & $common , 'log' );
$info = $this -> _pf -> getContents ();
2009-01-05 00:22:54 +00:00
if ( ! $info || ! isset ( $info [ 'dir' ][ 'file' ])) {
$this -> _tagCannotBeEmpty ( 'contents><dir' );
return false ;
}
2008-11-26 22:50:40 +00:00
$info = $info [ 'dir' ][ 'file' ];
if ( isset ( $info [ 'attribs' ])) {
$info = array ( $info );
}
$provides = array ();
foreach ( $info as $fa ) {
$fa = $fa [ 'attribs' ];
$file = $fa [ 'name' ];
if ( ! file_exists ( $dir_prefix . DIRECTORY_SEPARATOR . $file )) {
$this -> _fileNotFound ( $dir_prefix . DIRECTORY_SEPARATOR . $file );
$this -> _isValid = 0 ;
continue ;
}
if ( in_array ( $fa [ 'role' ], PEAR_Installer_Role :: getPhpRoles ()) && $dir_prefix ) {
call_user_func_array ( $log , array ( 1 , " Analyzing $file " ));
$srcinfo = $this -> analyzeSourceCode ( $dir_prefix . DIRECTORY_SEPARATOR . $file );
if ( $srcinfo ) {
$provides = array_merge ( $provides , $this -> _buildProvidesArray ( $srcinfo ));
}
}
}
$this -> _packageName = $pn = $this -> _pf -> getPackage ();
$pnl = strlen ( $pn );
foreach ( $provides as $key => $what ) {
if ( isset ( $what [ 'explicit' ]) || ! $what ) {
// skip conformance checks if the provides entry is
// specified in the package.xml file
continue ;
}
extract ( $what );
if ( $type == 'class' ) {
if ( ! strncasecmp ( $name , $pn , $pnl )) {
continue ;
}
$this -> _stack -> push ( __FUNCTION__ , 'warning' ,
array ( 'file' => $file , 'type' => $type , 'name' => $name , 'package' => $pn ),
'in %file%: %type% "%name%" not prefixed with package name "%package%"' );
} elseif ( $type == 'function' ) {
if ( strstr ( $name , '::' ) || ! strncasecmp ( $name , $pn , $pnl )) {
continue ;
}
$this -> _stack -> push ( __FUNCTION__ , 'warning' ,
array ( 'file' => $file , 'type' => $type , 'name' => $name , 'package' => $pn ),
'in %file%: %type% "%name%" not prefixed with package name "%package%"' );
}
}
return $this -> _isValid ;
}
/**
* Analyze the source code of the given PHP file
*
* @ param string Filename of the PHP file
* @ param boolean whether to analyze $file as the file contents
* @ return mixed
*/
function analyzeSourceCode ( $file , $string = false )
{
if ( ! function_exists ( " token_get_all " )) {
2009-01-05 00:22:54 +00:00
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file ),
'Parser error: token_get_all() function must exist to analyze source code, PHP may have been compiled with --disable-tokenizer' );
2008-11-26 22:50:40 +00:00
return false ;
}
if ( ! defined ( 'T_DOC_COMMENT' )) {
define ( 'T_DOC_COMMENT' , T_COMMENT );
}
if ( ! defined ( 'T_INTERFACE' )) {
define ( 'T_INTERFACE' , - 1 );
}
if ( ! defined ( 'T_IMPLEMENTS' )) {
define ( 'T_IMPLEMENTS' , - 1 );
}
if ( $string ) {
$contents = $file ;
} else {
if ( ! $fp = @ fopen ( $file , " r " )) {
return false ;
}
2009-01-05 00:22:54 +00:00
fclose ( $fp );
$contents = file_get_contents ( $file );
}
// Silence this function so we can catch PHP Warnings and show our own custom message
$tokens = @ token_get_all ( $contents );
if ( isset ( $php_errormsg )) {
$pn = $this -> _pf -> getPackage ();
$this -> _stack -> push ( __FUNCTION__ , 'warning' ,
array ( 'file' => $file , 'package' => $pn ),
'in %file%: Could not process file for unkown reasons,' .
' possibly a PHP parse error in %file% from %package%' );
2008-11-26 22:50:40 +00:00
}
/*
for ( $i = 0 ; $i < sizeof ( $tokens ); $i ++ ) {
@ list ( $token , $data ) = $tokens [ $i ];
if ( is_string ( $token )) {
var_dump ( $token );
} else {
print token_name ( $token ) . ' ' ;
var_dump ( rtrim ( $data ));
}
}
*/
$look_for = 0 ;
$paren_level = 0 ;
$bracket_level = 0 ;
$brace_level = 0 ;
$lastphpdoc = '' ;
$current_class = '' ;
$current_interface = '' ;
$current_class_level = - 1 ;
$current_function = '' ;
$current_function_level = - 1 ;
$declared_classes = array ();
$declared_interfaces = array ();
$declared_functions = array ();
$declared_methods = array ();
$used_classes = array ();
$used_functions = array ();
$extends = array ();
$implements = array ();
$nodeps = array ();
$inquote = false ;
$interface = false ;
for ( $i = 0 ; $i < sizeof ( $tokens ); $i ++ ) {
if ( is_array ( $tokens [ $i ])) {
list ( $token , $data ) = $tokens [ $i ];
} else {
$token = $tokens [ $i ];
$data = '' ;
}
if ( $inquote ) {
if ( $token != '"' && $token != T_END_HEREDOC ) {
continue ;
} else {
$inquote = false ;
continue ;
}
}
switch ( $token ) {
case T_WHITESPACE :
continue ;
case ';' :
if ( $interface ) {
$current_function = '' ;
$current_function_level = - 1 ;
}
break ;
case '"' :
case T_START_HEREDOC :
$inquote = true ;
break ;
case T_CURLY_OPEN :
case T_DOLLAR_OPEN_CURLY_BRACES :
case '{' : $brace_level ++ ; continue 2 ;
case '}' :
$brace_level -- ;
if ( $current_class_level == $brace_level ) {
$current_class = '' ;
$current_class_level = - 1 ;
}
if ( $current_function_level == $brace_level ) {
$current_function = '' ;
$current_function_level = - 1 ;
}
continue 2 ;
case '[' : $bracket_level ++ ; continue 2 ;
case ']' : $bracket_level -- ; continue 2 ;
case '(' : $paren_level ++ ; continue 2 ;
case ')' : $paren_level -- ; continue 2 ;
case T_INTERFACE :
$interface = true ;
case T_CLASS :
if (( $current_class_level != - 1 ) || ( $current_function_level != - 1 )) {
$this -> _stack -> push ( __FUNCTION__ , 'error' , array ( 'file' => $file ),
'Parser error: invalid PHP found in file "%file%"' );
return false ;
}
case T_FUNCTION :
case T_NEW :
case T_EXTENDS :
case T_IMPLEMENTS :
$look_for = $token ;
continue 2 ;
case T_STRING :
if ( version_compare ( zend_version (), '2.0' , '<' )) {
if ( in_array ( strtolower ( $data ),
array ( 'public' , 'private' , 'protected' , 'abstract' ,
2009-01-05 00:22:54 +00:00
'interface' , 'implements' , 'throw' )
2008-11-26 22:50:40 +00:00
)) {
$this -> _stack -> push ( __FUNCTION__ , 'warning' , array (
'file' => $file ),
'Error, PHP5 token encountered in %file%,' .
' analysis should be in PHP5' );
}
}
if ( $look_for == T_CLASS ) {
$current_class = $data ;
$current_class_level = $brace_level ;
$declared_classes [] = $current_class ;
} elseif ( $look_for == T_INTERFACE ) {
$current_interface = $data ;
$current_class_level = $brace_level ;
$declared_interfaces [] = $current_interface ;
} elseif ( $look_for == T_IMPLEMENTS ) {
$implements [ $current_class ] = $data ;
} elseif ( $look_for == T_EXTENDS ) {
$extends [ $current_class ] = $data ;
} elseif ( $look_for == T_FUNCTION ) {
if ( $current_class ) {
$current_function = " $current_class :: $data " ;
$declared_methods [ $current_class ][] = $data ;
} elseif ( $current_interface ) {
$current_function = " $current_interface :: $data " ;
$declared_methods [ $current_interface ][] = $data ;
} else {
$current_function = $data ;
$declared_functions [] = $current_function ;
}
$current_function_level = $brace_level ;
$m = array ();
} elseif ( $look_for == T_NEW ) {
$used_classes [ $data ] = true ;
}
$look_for = 0 ;
continue 2 ;
case T_VARIABLE :
$look_for = 0 ;
continue 2 ;
case T_DOC_COMMENT :
case T_COMMENT :
if ( preg_match ( '!^/\*\*\s!' , $data )) {
$lastphpdoc = $data ;
if ( preg_match_all ( '/@nodep\s+(\S+)/' , $lastphpdoc , $m )) {
$nodeps = array_merge ( $nodeps , $m [ 1 ]);
}
}
continue 2 ;
case T_DOUBLE_COLON :
if ( ! ( $tokens [ $i - 1 ][ 0 ] == T_WHITESPACE || $tokens [ $i - 1 ][ 0 ] == T_STRING )) {
$this -> _stack -> push ( __FUNCTION__ , 'warning' , array ( 'file' => $file ),
'Parser error: invalid PHP found in file "%file%"' );
return false ;
}
$class = $tokens [ $i - 1 ][ 1 ];
if ( strtolower ( $class ) != 'parent' ) {
$used_classes [ $class ] = true ;
}
continue 2 ;
}
}
return array (
" source_file " => $file ,
" declared_classes " => $declared_classes ,
" declared_interfaces " => $declared_interfaces ,
" declared_methods " => $declared_methods ,
" declared_functions " => $declared_functions ,
" used_classes " => array_diff ( array_keys ( $used_classes ), $nodeps ),
" inheritance " => $extends ,
" implements " => $implements ,
);
}
/**
* Build a " provides " array from data returned by
* analyzeSourceCode () . The format of the built array is like
* this :
*
* array (
* 'class;MyClass' => 'array(' type ' => ' class ', ' name ' => ' MyClass ' ),
* ...
* )
*
*
* @ param array $srcinfo array with information about a source file
* as returned by the analyzeSourceCode () method .
*
* @ return void
*
* @ access private
*
*/
function _buildProvidesArray ( $srcinfo )
{
if ( ! $this -> _isValid ) {
return array ();
}
$providesret = array ();
$file = basename ( $srcinfo [ 'source_file' ]);
$pn = $this -> _pf -> getPackage ();
$pnl = strlen ( $pn );
foreach ( $srcinfo [ 'declared_classes' ] as $class ) {
$key = " class; $class " ;
if ( isset ( $providesret [ $key ])) {
continue ;
}
$providesret [ $key ] =
array ( 'file' => $file , 'type' => 'class' , 'name' => $class );
if ( isset ( $srcinfo [ 'inheritance' ][ $class ])) {
$providesret [ $key ][ 'extends' ] =
$srcinfo [ 'inheritance' ][ $class ];
}
}
foreach ( $srcinfo [ 'declared_methods' ] as $class => $methods ) {
foreach ( $methods as $method ) {
$function = " $class :: $method " ;
$key = " function; $function " ;
if ( $method { 0 } == '_' || ! strcasecmp ( $method , $class ) ||
isset ( $providesret [ $key ])) {
continue ;
}
$providesret [ $key ] =
array ( 'file' => $file , 'type' => 'function' , 'name' => $function );
}
}
foreach ( $srcinfo [ 'declared_functions' ] as $function ) {
$key = " function; $function " ;
if ( $function { 0 } == '_' || isset ( $providesret [ $key ])) {
continue ;
}
if ( ! strstr ( $function , '::' ) && strncasecmp ( $function , $pn , $pnl )) {
$warnings [] = " in1 " . $file . " : function \" $function\ " not prefixed with package name \ " $pn\ " " ;
}
$providesret [ $key ] =
array ( 'file' => $file , 'type' => 'function' , 'name' => $function );
}
return $providesret ;
}
}
?>