" . htmlspecialchars($reason) . "";
if ($showStackTrace) {
echo "
Stack Trace:
\n";
$trace = debug_backtrace();
// Remove the call to fatalError from the call trace.
array_shift($trace);
// Back-trace pretty-printer adapted from the following URL:
// http://ca3.php.net/manual/en/function.debug-backtrace.php
// Thanks to diz at ysagoon dot com
// FIXME: Is there any way to localize this when the localization
// functions may have caused the failure in the first place?
foreach ($trace as $bt) {
$args = '';
if (isset($bt['args'])) foreach ($bt['args'] as $a) {
if (!empty($args)) {
$args .= ', ';
}
switch (gettype($a)) {
case 'integer':
case 'double':
$args .= $a;
break;
case 'string':
$a = htmlspecialchars(substr($a, 0, 64)).((strlen($a) > 64) ? '...' : '');
$args .= "\"$a\"";
break;
case 'array':
$args .= 'Array('.count($a).')';
break;
case 'object':
$args .= 'Object('.get_class($a).')';
break;
case 'resource':
$args .= 'Resource('.strstr($a, '#').')';
break;
case 'boolean':
$args .= $a ? 'True' : 'False';
break;
case 'NULL':
$args .= 'Null';
break;
default:
$args .= 'Unknown';
}
}
$class = isset($bt['class'])?$bt['class']:'';
$type = isset($bt['type'])?$bt['type']:'';
$function = isset($bt['function'])?$bt['function']:'';
$file = isset($bt['file'])?$bt['file']:'(unknown)';
$line = isset($bt['line'])?$bt['line']:'(unknown)';
echo "File: {$file} line {$line}
\n";
echo "Function: {$class}{$type}{$function}($args)
\n";
echo "
\n";
}
}
// Determine the application name. Use defensive code so that we
// can handle errors during early application initialization.
$application = null;
if (class_exists('Registry')) {
$application = Registry::get('application', true, null);
}
$applicationName = '';
if (!is_null($application)) {
$applicationName = $application->getName().': ';
}
error_log($applicationName.$reason);
if (defined('DONT_DIE_ON_ERROR') && DONT_DIE_ON_ERROR == true) {
// trigger an error to be catched outside the application
trigger_error($reason);
return;
}
die();
}
/**
* Check to see if the server meets a minimum version requirement for PHP.
* @param $version Name of version (see version_compare documentation)
* @return boolean
*/
function checkPhpVersion($version) {
return (version_compare(PHP_VERSION, $version) !== -1);
}
/**
* Instantiates an object for a given fully qualified
* class name after executing several checks on the class.
*
* The checks prevent certain vulnerabilities when
* instantiating classes generically.
*
* NB: We currently only support one constructor
* argument. If we need arbitrary arguments later
* we can do that via func_get_args() which allows us
* to handle an arbitrary number of optional
* constructor arguments. The $constructorArg
* parameter needs to be last in the parameter list
* to be forward compatible with this potential use
* case.
*
* @param $fullyQualifiedClassName string
* @param $expectedTypes string|array the class
* must conform to at least one of the given types.
* @param $expectedPackages string|array the class
* must be part of at least one of the given packages.
* @param $expectedMethods string|array names of methods
* that must all be present for the requested class.
* @param $constructorArg mixed constructor argument
*
* @return object|boolean the instantiated object or false
* if the class instantiation didn't result in the expected
* type.
*/
function &instantiate($fullyQualifiedClassName, $expectedTypes = null, $expectedPackages = null, $expectedMethods = null, $constructorArg = null) {
$errorFlag = false;
// Validate the class name
if (!preg_match('/^[a-zA-Z0-9.]+$/', $fullyQualifiedClassName)) {
return $errorFlag;
}
// Validate the class package
if (!is_null($expectedPackages)) {
if (is_scalar($expectedPackages)) $expectedPackages = array($expectedPackages);
$validPackage = false;
foreach ($expectedPackages as $expectedPackage) {
// No need to use String class here as class names are always US-ASCII
if (substr($fullyQualifiedClassName, 0, strlen($expectedPackage)+1) == $expectedPackage.'.') {
$validPackage = true;
break;
}
}
// Raise a fatal error if the class does not belong
// to any of the expected packages. This is to prevent
// certain types of code inclusion attacks.
if (!$validPackage) {
// Construct meaningful error message.
$expectedPackageCount = count($expectedPackages);
$separator = '';
foreach($expectedPackages as $expectedPackageIndex => $expectedPackage) {
if ($expectedPackageIndex > 0) {
$separator = ($expectedPackageIndex == $expectedPackageCount-1 ? ' or ' : ', ' );
}
$expectedPackageString .= $separator.'"'.$expectedPackage.'"';
}
fatalError('Trying to instantiate class "'.$fullyQualifiedClassName.'" which is not in any of the expected packages '.$expectedPackageString.'.');
}
}
// Import the requested class
import($fullyQualifiedClassName);
// Identify the class name
$fullyQualifiedClassNameParts = explode('.', $fullyQualifiedClassName);
$className = array_pop($fullyQualifiedClassNameParts);
// Type check I: The requested class should be declared by now.
if (!class_exists($className)) {
fatalError('Cannot instantiate class. Class "'.$className.'" is not declared in "'.$fullyQualifiedClassName.'".');
}
// Ensure all expected methods are declared.
$expectedMethods = (array) $expectedMethods; // Possibly scalar or null; ensure array
$declaredMethods = get_class_methods($className);
if (count(array_intersect($expectedMethods, $declaredMethods)) != count($expectedMethods)) {
return $errorFlag;
}
// Instantiate the requested class
if (is_null($constructorArg)) {
$classInstance = new $className();
} else {
$classInstance = new $className($constructorArg);
}
// Type check II: The object must conform to the given interface (if any).
if (!is_null($expectedTypes)) {
if (is_scalar($expectedTypes)) $expectedTypes = array($expectedTypes);
$validType = false;
foreach($expectedTypes as $expectedType) {
if (is_a($classInstance, $expectedType)) {
$validType = true;
break;
}
}
if (!$validType) return $errorFlag;
}
return $classInstance;
}
/**
* Remove empty elements from an array
* @param $array array
* @return array
*/
function arrayClean($array) {
if (!is_array($array)) return null;
return array_filter($array, function($o) {
return !empty($o);
});
}
/**
* Recursively strip HTML from a (multidimensional) array.
* @param $values array
* @return array the cleansed array
*/
function stripAssocArray($values) {
foreach ($values as $key => $value) {
if (is_scalar($value)) {
$values[$key] = strip_tags($values[$key]);
} else {
$values[$key] = stripAssocArray($values[$key]);
}
}
return $values;
}
/**
* Perform a code-safe strtolower, i.e. one that doesn't behave differently
* based on different locales. (tr_TR, I'm looking at you.)
* @param $str string Input string
* @return string
*/
function strtolower_codesafe($str) {
return strtr($str, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz');
}
/**
* Convert a Windows path to a cygwin path.
* @param string $path Windows path
* @return string Cygwin path.
*/
function cygwinConversion($path) {
$path = str_replace('\\', '/', $path);
$matches = null;
PKPString::regexp_match_get('/^([A-Z]):/i', $path, $matches);
if (isset($matches[1]) && strlen($matches[1]) === 1) {
$path = PKPString::regexp_replace('/^[A-Z]:/i', '/cygdrive/' . strtolower($matches[1]), $path);
}
return $path;
}
/**
* Helper function to define custom autoloader
* @param string $rootPath
* @param string $prefix
* @param string $class
*
* @return void
*/
function customAutoload($rootPath, $prefix, $class) {
if (substr($class, 0, strlen($prefix)) !== $prefix) {
return;
}
$class = substr($class, strlen($prefix));
$parts = explode('\\', $class);
// we expect at least one folder in the namespace
// there is no class defined directly under classes/ folder
if (count($parts) < 2) {
return;
}
$className = Core::cleanFileVar(array_pop($parts));
$parts = array_map(function($part) {
return lcfirst(Core::cleanFileVar($part));
}, $parts);
$subParts = join('/', $parts);
$filePath = "{$rootPath}/{$subParts}/{$className}.inc.php";
if (is_file($filePath)) {
require_once($filePath);
}
}
?>