Because the version 2 is a full API rewrites, and used namespaces, your old code cannot migrate without a little change.
We will try to explain how to do in few steps.
Containers
Version 1.x used customizable containers feature to store parsing results.
For example, in version 1.x when we wanted to retrieve user functions, we could either do :
<?php
require_once 'Bartlett/PHP/Reflect/Autoload.php';
$source = '/path/to/source_file.php';
$options = array();
$reflect = new PHP_Reflect($options);
$reflect->scan($source);
$functions = $reflect->getFunctions();
// OR
$functions = $reflect['functions'];
<?php
require_once 'Bartlett/PHP/Reflect/Autoload.php';
$source = '/path/to/source_file.php';
$options = array('containers' => array('function' => 'userFunctions');
$reflect = new PHP_Reflect($options);
$reflect->scan($source);
$functions = $reflect->getUserFunctions();
// OR
$functions = $reflect['userFunctions'];
In version 2.x, we have collections of data models that we can enumerate and exploit.
<?php
require_once 'vendor/autoload.php';
use Bartlett\Reflect;
use Bartlett\Reflect\ProviderManager;
use Bartlett\Reflect\Provider\SymfonyFinderProvider;
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()
->name('source_file.php')
->in('/path/to/');
// Identify Data Source
$pm = new ProviderManager;
$pm->set('Sample', new SymfonyFinderProvider($finder));
$reflect = new Reflect;
$reflect->setProviderManager($pm);
$reflect->parse();
// Exploit results
foreach ($reflect->getPackages() as $package) {
$functions = $package->getFunctions();
}
Properties
Version 1.x may provide a variable properties list. Version 2.x provides all properties anytime. It’s up to you to decide to use them or not.
For example, in version 1.x when we wanted to retrieve only keywords and signature of each class methods of a data source.
<?php
require_once 'Bartlett/PHP/Reflect/Autoload.php';
$source = '/path/to/PEAR-1.9.2/PEAR.php';
$options = array(
'properties' => array(
'interface' => array(
'parent', 'methods'
),
'class' => array(
'parent', 'methods', 'interfaces', 'package'
),
'function' => array(
'signature'
),
)
);
$reflect = new PHP_Reflect($options);
$reflect->scan($source);
$classes = $reflect->getClasses();
print_r($classes['\\']['PEAR_Error']['methods']);
Array ( [PEAR_Error] => Array ( [signature] => PEAR_Error($message = 'unknown error', $code = null, $mode = null, $options = null, $userinfo = null) ) [getMode] => Array ( [signature] => getMode() ) [getCallback] => Array ( [signature] => getCallback() ) [getMessage] => Array ( [signature] => getMessage() ) [getCode] => Array ( [signature] => getCode() ) [getType] => Array ( [signature] => getType() ) [getUserInfo] => Array ( [signature] => getUserInfo() ) [getDebugInfo] => Array ( [signature] => getDebugInfo() ) [getBacktrace] => Array ( [signature] => getBacktrace($frame = null) ) [addUserInfo] => Array ( [signature] => addUserInfo($info) ) [__toString] => Array ( [signature] => __toString() ) [toString] => Array ( [signature] => toString() ) )
In version 2.x, when we did the same.
<?php
require_once 'vendor/autoload.php';
use Bartlett\Reflect;
use Bartlett\Reflect\ProviderManager;
use Bartlett\Reflect\Provider\SymfonyFinderProvider;
use Symfony\Component\Finder\Finder;
$finder = new Finder();
$finder->files()
->name('PEAR.php')
->in('/path/to/PEAR-1.9.2/');
// Identify Data Source
$pm = new ProviderManager;
$pm->set('PEAR192', new SymfonyFinderProvider($finder));
$reflect = new Reflect;
$reflect->setProviderManager($pm);
$reflect->parse();
// Exploit results
$out = array();
foreach ($reflect->getPackages() as $package) {
foreach ($package->getClasses() as $class) {
if ($class->getShortName() !== 'PEAR_Error') {
continue;
}
foreach ($class->getMethods() as $method) {
if ($method->isPrivate()) {
$visibility = 'private';
} elseif ($method->isProtected()) {
$visibility = 'protected';
} else {
$visibility = 'public';
}
$name = $method->getShortName();
$parameters = $method->getParameters();
$args = array();
foreach ($parameters as $parameter) {
$args[] = sprintf(
'%s%s%s',
$parameter->isPassedByReference() ? '&' : '',
'$' . $parameter->getName(),
$parameter->isDefaultValueAvailable() ? ' = ' . $parameter->getDefaultValue() : ''
);
}
$out[$name] = array(
'signature' => sprintf('%s %s(%s)', $visibility, $name, implode(',', $args))
);
}
}
}
print_r($out);
Array ( [PEAR_Error] => Array ( [signature] => public PEAR_Error($message = 'unknown error',$code = null,$mode = null,$options = null,$userinfo = null) ) [getMode] => Array ( [signature] => public getMode() ) [getCallback] => Array ( [signature] => public getCallback() ) [getMessage] => Array ( [signature] => public getMessage() ) [getCode] => Array ( [signature] => public getCode() ) [getType] => Array ( [signature] => public getType() ) [getUserInfo] => Array ( [signature] => public getUserInfo() ) [getDebugInfo] => Array ( [signature] => public getDebugInfo() ) [getBacktrace] => Array ( [signature] => public getBacktrace($frame = null) ) [addUserInfo] => Array ( [signature] => public addUserInfo($info) ) [__toString] => Array ( [signature] => public __toString() ) [toString] => Array ( [signature] => public toString() ) )
Summary
Let’s review what we’ve did :
-
Compared Containers configuration solutions, and how to do it with both versions 1.x and 2.x
-
Compared Properties configuration solutions, and how to do it with both versions 1.x and 2.x
-
Used some methods of the new API 2.x, to enumerate and exploit parsing results.
Next
For PHP developers only.