This is a collection of the one and other function around PHP source code handling, including sandboxing without the need to install PEAR (I just didn't have it - if you do, then use the Sandbox class, the function here is slower). Other static functions are checking the overhead of a PHP file and getting some information about a PHP file, such as defined classes, functions or interfaces.
Diese Klasse ist eine Zusammenstellung der einen und anderen Funktion, die ich mal benötigte. Dazu gehört Sandboxing ohne PEAR (hatte ich einfach nicht - wenn Du PEAR installiert hast, dann nutze die Sandbox-Klasse, die ist schneller). Andere statische Funktionen prüfen den Dokumentations-Overhead einer PHP-Datei oder ermitteln, welche Klassen, Interfaces und Funktionen in einem PHP-Skript definiert sind.
Sample source code
Anwendungsbeispiel
<?php
require_once('PhpCode.class.php');
print '<html><body><pre>';
// Print out the documentation overhead, which is the
// ratio between stripped and original file.
print "PhpCode::documentationOverhead(...) = " . print_r(
PhpCode::documentationOverhead(__FILE__), true
) . "\n\n";
// This should show one class "MySql". Note that this source code info
// does not work for file that are already loaded.
print "PhpCode::getSourceInfo(...) = " . print_r(
PhpCode::getSourceInfo('MySql.class.php'), true
) . "\n\n";
$result = PhpCode::evaluate(<<<CODE_HERE
// A new function
function f() { return true; }
// Some new classes etc.
abstract class A { }
interface I { }
class B extends A implements I { }
\$a = 1001;
\$b = "I'm a text";
\$c = new Exception('Throw me');
print "\$a, \$b, " . \$c->getMessage();
CODE_HERE
);
// This should show the output, an exception that occured, new added
// functions, classes and interfaces.
print "PhpCode::evaluate(...) = " . print_r($result, true) . "\n\n";
// This is executed sandboxed, note that savemode must be switched off to
// to this.
$result = PhpCode::evaluateSandboxed(<<<CODE_HERE
// This is executed sandboxed
print "<b>Sandboxed eval ...</b>";
print "Arguments = ";
print_r(\$GLOBALS);
CODE_HERE
, array(
// Here some arguments
'_GET' => array(
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
)
));
print "PhpCode::evaluateSandboxed(...) = " . print_r($result, true) . "\n\n";
print '</pre></body></html>';
?>
Output
The output on my localhost is:
Ausgabe
Auf meinem localhost erhalte ich diese Ausgabe:
PhpCode::documentationOverhead(...) = Array
(
[original_size] => 1720
[stripped_size] => 1208
[relation_percent] => 142
[error] =>
)
PhpCode::getSourceInfo(...) = Array
(
[output] =>
[classes] => Array
(
[171] => MySql
)
)
PhpCode::evaluate(...) = Array
(
[exception] =>
[interfaces] => Array
(
[13] => I
)
[classes] => Array
(
[172] => A
[173] => B
)
[functions] => Array
(
[0] => f
)
[output] => 1001, I'm a text, Throw me
)
PhpCode::evaluateSandboxed(...) = Sandboxed eval ...Arguments = Array
(
[_GET] => Array
(
[key1] => value1
[key2] => value2
[key3] => value3
)
[_SERVER] => Array
(
[UNIQUE_ID] => TDHrOMCoAQsAADS09t8AAAAH
[HTTP_HOST] => htx.my
[HTTP_ACCEPT_ENCODING] => gzip, deflate
[HTTP_ACCEPT_LANGUAGE] => en-us
[HTTP_USER_AGENT] => Mozilla/5.0 (Macintosh; U; ...
[HTTP_ACCEPT] => application/xml,application/xhtml+xml,...
[HTTP_CACHE_CONTROL] => max-age=0
[HTTP_COOKIE] => PHPSESSID=f6bc29eab1be0c12564b3a57cb837199
[HTTP_CONNECTION] => keep-alive
[PATH] => /usr/bin:/bin:/usr/sbin:/sbin
[SERVER_SIGNATURE] =>
[SERVER_SOFTWARE] => Apache/2.2.14 (Unix) DAV/2 mod_ssl/2.2.14 ...
[SERVER_NAME] => htx.my
[SERVER_ADDR] => ::1
[SERVER_PORT] => 80
[REMOTE_ADDR] => ::1
[DOCUMENT_ROOT] => /Users/.../Sites/htxdocs
[SERVER_ADMIN] => ...@atwillys.de
[SCRIPT_FILENAME] => /Users/.../Sites/htxdocs/tests/index.php
[REMOTE_PORT] => 59737
[GATEWAY_INTERFACE] => CGI/1.1
[SERVER_PROTOCOL] => HTTP/1.1
[REQUEST_METHOD] => GET
[QUERY_STRING] =>
[REQUEST_URI] => /tests/
[SCRIPT_NAME] => /tests/index.php
[PHP_SELF] => /tests/index.php
[REQUEST_TIME] => 1278339896
[argv] => Array ( )
[argc] => 0
)
)
Class source code
Klassen-Quelltext
<?php
/**
* PHP code information and execution. The evaluateSandboxed() should work
* even if PEAR is not installed (no class SandBox), but safemode should be
* disabled because PHP has to be executed in the shell. This means longer
* processing time as well.
* @gpackage de.atwillys.sw.php
* @author Stefan Wilhelm
* @copyright Stefan Wilhelm, 2007-2010
* @license GPL
* @version 1.0
*/
namespace sw;
final class PhpCode {
/**
* Load and find classes, returns classes difference
* @return array
*/
public static function getSourceInfo($phpSourceCodeFile) {
$c1 = get_declared_classes();
$bl = ob_get_level();
ob_start();
try {
$t = microtime(true);
include $phpSourceCodeFile;
$t = microtime(true) - $t;
} catch (\Exception $e) {
throw new \Exception("Exception in executed file '$phpSourceCodeFile': $e");
}
$c2 = get_declared_classes();
$output['output'] = '';
while(ob_get_level() > $bl) $output['output'] .= ob_get_clean();
$output['classes'] = array_diff($c2, $c1);
unset($c1, $c2, $buffer);
return $output;
}
/**
* Execute php code and returns its print output
* @return array
*/
public static function evaluate($phpSourceCode) {
$c0 = get_declared_classes();
$f0 = get_defined_functions();
$f0 = $f0['user'];
$i0 = get_declared_interfaces();
$t0 = microtime(true);
$out = array();
$out['exception'] = null;
$bl = ob_get_level();
ob_start();
try {
eval($phpSourceCode);
} catch (\Exception $e) {
$out['exception'] = $e;
}
$t0 = microtime(true) - $t0;
$c1 = get_declared_classes();
$f1 = get_defined_functions();
$f1 = $f1['user'];
$i1 = get_declared_interfaces();
$out['interfaces'] = array_diff($i1, $i0);
$out['classes'] = array_diff($c1, $c0);
$out['functions'] = array_diff($f1, $f0);
$out['output'] = '';
while(ob_get_level() > $bl) $out['output'] .= ob_get_clean();
return $out;
}
/**
* Executes a string independent from the actual script
* using command line PHP. Takes more time than normal
* execution, but cannot crash your script.
* Normally a Sandbox could be used for this, but this
* is an alternative also running without PEAR.
* But again: SLOW.
* @param string $phpSourceCode
* @param array $args
* @return string
*/
public static function evaluateSandboxed($phpSourceCode, $args=null) {
if (!empty($args) && is_array($args)) {
$argf = tempnam('/tmp', 'php_evaluate_args_');
$aop = "<?php ";
$globs = array();
if (!isset($args['_SERVER']))
$args['_SERVER'] = $_SERVER;
foreach ($args as $key => $arg) {
$aop .= '$' . $key . '=' . var_export($arg, true) . ';';
$globs[] = '"' . $key . '" => &$' . $key;
}
$aop .= "\n?>";
file_put_contents($argf, $aop);
unset($aop);
$phpSourceCode = '<?php $_SERVER=array(); $_GET=array(); $_POST=array(); $_SESSION=array(); $_FILES=array(); include("' . $argf . '"); ' .
'$GLOBALS=array(' . implode(',', $globs) . '); ' . $phpSourceCode . '?>';
}
$file = tempnam('/tmp', 'php_evaluate_');
file_put_contents($file, $phpSourceCode);
$out = shell_exec("php $file");
@unlink($file);
@unlink($argf);
return $out;
}
/**
* Returns an array containing information about the
* "overhead" using documentation and code structuring.
* @return array
*/
public static function documentationOverhead($file) {
$out = array(
'original_size' => 0,
'stripped_size' => 0,
'relation_percent' => 0,
'error' => ''
);
$file = trim(str_replace("\\", "/", $file)); // windows, windows ;)
if (!file_exists($file))
$file = str_replace('//', '/', $_SERVER['DOCUMENT_ROOT'] . $file);
if (!file_exists($file)) {
$out['error'] = "file does not exist";
} else if (!is_readable($file)) {
$out['error'] = "file not readable, no access";
} else {
$out['stripped_size'] = strlen(php_strip_whitespace($file));
$out['original_size'] = strlen(file_get_contents($file));
$out['relation_percent'] = intval(100 * $out['original_size'] / $out['stripped_size']);
}
return $out;
}
}