mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-06-01 20:29:29 +00:00
2b15c88410
- Added comments
362 lines
9.6 KiB
PHP
362 lines
9.6 KiB
PHP
<?php
|
|
|
|
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
|
|
|
/**
|
|
* Library used to call a method of a model or a library
|
|
*/
|
|
class CallerLib
|
|
{
|
|
const RESOURCE_PARAMETER = 'resource';
|
|
const FUNCTION_PARAMETER = 'function';
|
|
const REG_SPLIT_EXPR = '/\//';
|
|
const LIB_PREFIX = 'Lib';
|
|
const LIB_FILE_EXTENSION = '.php';
|
|
const LIBS_PATH = 'libraries';
|
|
const MODEL_PREFIX = '_model';
|
|
|
|
// Black list of resources that are no allowed to be used
|
|
private static $RESOURCES_BLACK_LIST = array(
|
|
'CallerLib', // disabled self loading
|
|
'LogLib', // hardly usefull and virtually dangerous
|
|
'MigrationLib', // virtually dangerous, DB manipulation
|
|
'FilesystemLib', // virtually dangerous, direct access to file system
|
|
'PermissionLib', // usefull?
|
|
'PersonLogLib'
|
|
);
|
|
|
|
private $_ci; // CI instance
|
|
|
|
/**
|
|
* Library initialization
|
|
*/
|
|
public function __construct()
|
|
{
|
|
$this->_ci =& get_instance(); // Gets CI instance
|
|
}
|
|
|
|
/**
|
|
* Wrapper method for _call
|
|
*/
|
|
public function callLibrary($callParameters)
|
|
{
|
|
return $this->_call($callParameters);
|
|
}
|
|
|
|
/**
|
|
* Wrapper method for _call
|
|
*/
|
|
public function callModel($callParameters)
|
|
{
|
|
return $this->_call($callParameters);
|
|
}
|
|
|
|
/**
|
|
* Everything starts here...
|
|
*/
|
|
private function _call($callParameters)
|
|
{
|
|
$result = null;
|
|
$parameters = $this->_getParameters($callParameters);
|
|
$validation = $this->_validateCall($parameters);
|
|
|
|
// If the validation was passed
|
|
if (isSuccess($validation))
|
|
{
|
|
$loaded = null;
|
|
// If the given resource is a model
|
|
if (strpos($parameters->resourceName, CallerLib::MODEL_PREFIX) !== false)
|
|
{
|
|
// Try to load the model
|
|
$result = $this->_loadModel($parameters->resourcePath, $parameters->resourceName);
|
|
if (isSuccess($result))
|
|
{
|
|
$loaded = $result->retval;
|
|
}
|
|
}
|
|
// If the given resource is a library
|
|
elseif (strpos($parameters->resourceName, CallerLib::LIB_PREFIX) !== false)
|
|
{
|
|
// Check if the resource is already loaded, it works only with libraries and drivers
|
|
$isLoaded = $this->_ci->load->is_loaded($parameters->resourceName);
|
|
// If not loaded then load it
|
|
if ($isLoaded === false)
|
|
{
|
|
// Try to load the library
|
|
$result = $this->_loadLibrary($parameters->resourcePath, $parameters->resourceName);
|
|
if (isSuccess($result))
|
|
{
|
|
$loaded = $result->retval;
|
|
}
|
|
}
|
|
// If it is already loaded $isLoaded contains the instance of the library
|
|
else
|
|
{
|
|
$loaded = $isLoaded;
|
|
}
|
|
}
|
|
// Wrong selection!
|
|
else
|
|
{
|
|
$result = error('Neither a lib nor model: '.$parameters->resourcePath.$parameters->resourceName);
|
|
}
|
|
|
|
// If the resource was found and loaded
|
|
if (!is_null($loaded))
|
|
{
|
|
$result = $this->_callThis($parameters->resourceName, $parameters->function, $parameters->parameters);
|
|
}
|
|
else
|
|
{
|
|
// Resource not loaded
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$result = $validation;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Gets the parameters from the http call
|
|
* Search for parameters <RESOURCE_PARAMETER> and <FUNCTION_PARAMETER>
|
|
* <RESOURCE_PARAMETER> is the name of the model or of the library
|
|
* <FUNCTION_PARAMETER> is the name of the method present in the model/library
|
|
* All the others parameters will be given to the method in the same order that
|
|
* they are present in the HTTP call
|
|
* EX:
|
|
* URL: ../system/CallerLibrary/Call?resource=<resource>&function=<method>&<par1>=<val1>&<par2>=<val2>&<par3>=<val3>
|
|
* will call <resource>.<method>(par1, par2, par3)
|
|
*/
|
|
private function _getParameters($parametersArray)
|
|
{
|
|
$parameters = new stdClass();
|
|
$parameters->parameters = array();
|
|
$count = 0;
|
|
|
|
foreach ($parametersArray as $parameterName => $parameterValue)
|
|
{
|
|
// The name of the resource, path included
|
|
if ($parameterName == CallerLib::RESOURCE_PARAMETER)
|
|
{
|
|
// Separates the resource path from the resource name
|
|
$splittedResource = preg_split(CallerLib::REG_SPLIT_EXPR, $parameterValue);
|
|
$parameters->resourceName = $splittedResource[count($splittedResource) - 1];
|
|
$parameters->resourcePath = str_replace($parameters->resourceName, '', $parameterValue);
|
|
}
|
|
// The name of the function
|
|
elseif ($parameterName == CallerLib::FUNCTION_PARAMETER)
|
|
{
|
|
$parameters->function = $parameterValue;
|
|
}
|
|
// It is assumed that all other parameters are the parameters to be passed to the function
|
|
// They will be passed to the function in the same order in which they are passed to
|
|
// this controller
|
|
else
|
|
{
|
|
$parameters->parameters[$count++] = $parameterValue;
|
|
}
|
|
}
|
|
|
|
return $parameters;
|
|
}
|
|
|
|
/**
|
|
* Validate the given parameters
|
|
*/
|
|
private function _validateCall($parameters)
|
|
{
|
|
if (!is_object($parameters))
|
|
{
|
|
return error('Parameter is not an object');
|
|
}
|
|
if (!isset($parameters->resourcePath))
|
|
{
|
|
return error('Resource path is not specified');
|
|
}
|
|
if (!isset($parameters->resourceName))
|
|
{
|
|
return error('Resource name is not specified');
|
|
}
|
|
if (!isset($parameters->function))
|
|
{
|
|
return error('Function is not specified');
|
|
}
|
|
if (!is_array($parameters->parameters))
|
|
{
|
|
return error('Parameters are not specified');
|
|
}
|
|
if (in_array($parameters->resourceName, CallerLib::$RESOURCES_BLACK_LIST))
|
|
{
|
|
return error('You are trying to access to unauthorized resources');
|
|
}
|
|
|
|
return success('Input data are valid');
|
|
}
|
|
|
|
/**
|
|
* Loads a model using the given path and name
|
|
*
|
|
* NOTE: the models automatically handle the permissions
|
|
*/
|
|
private function _loadModel($resourcePath, $resourceName)
|
|
{
|
|
$loaded = null;
|
|
$result = null;
|
|
|
|
try
|
|
{
|
|
$loaded = $this->_ci->load->model($resourcePath.$resourceName);
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
// Errors while loading the model
|
|
$result = error('Errors while loading the model: '.$e->getMessage());
|
|
}
|
|
|
|
if (!is_null($loaded))
|
|
{
|
|
$result = success($loaded);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Loads a library using the given path and name
|
|
*
|
|
* The method 'library' of the class CI_Loader provided by CI has some limitations,
|
|
* so to be able to check errors was used a workaround.
|
|
* It consists in:
|
|
* - Checking if the file (identified by parameters $resourcePath and $resourceName) exists
|
|
* - If exists it will be loaded using the method 'file' from CI_Loader
|
|
* - Checks if the loaded file contains a class identified by parameter $resourceName
|
|
*
|
|
* If one of the previous tests fails, it will be returned a null value
|
|
*/
|
|
private function _loadLibrary($resourcePath, $resourceName)
|
|
{
|
|
$loaded = null;
|
|
|
|
try
|
|
{
|
|
// Gets all the configured resources paths
|
|
$packagePaths = $this->_ci->load->get_package_paths();
|
|
// Looking for a file in every paths with the same name of the resource
|
|
$found = null;
|
|
for ($i = 0; $i < count($packagePaths) && is_null($found); $i++)
|
|
{
|
|
$file = $packagePaths[$i].CallerLib::LIBS_PATH.DIRECTORY_SEPARATOR.
|
|
$resourcePath.$resourceName.CallerLib::LIB_FILE_EXTENSION;
|
|
if (file_exists($file))
|
|
{
|
|
$found = $file;
|
|
}
|
|
}
|
|
|
|
// If the file was found
|
|
if (!is_null($found))
|
|
{
|
|
// Load the file
|
|
$loaded = $this->_ci->load->file($found);
|
|
// If the resource is not present inside the file
|
|
if (!class_exists($resourceName))
|
|
{
|
|
$loaded = null;
|
|
// Same phrase error as load->model() provided by CI
|
|
$result = error($found.' exists, but doesn\'t declare class '.$resourceName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$loaded = null;
|
|
// Same phrase error as load->model() provided by CI
|
|
$result = error('Unable to load the requested class: '.$resourceName);
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
// Errors while loading the library
|
|
$result = error('Errors while loading the library: '.$e->getMessage());
|
|
}
|
|
|
|
if (!is_null($loaded))
|
|
{
|
|
$result = success($loaded);
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Calls a method of a class with the given parameters and returns its result
|
|
*
|
|
* @param string $resourceName identifies the class name
|
|
* @param string $function identifies the method name
|
|
* @param array $parameters contains the parameters to be passed to the method
|
|
*/
|
|
private function _callThis($resourceName, $function, $parameters)
|
|
{
|
|
$result = null;
|
|
|
|
try
|
|
{
|
|
// Get informations about the function
|
|
$reflectionMethod = new ReflectionMethod($resourceName, $function);
|
|
// If the number of given parameters is greater or equal to the number of
|
|
// parameters required by the function
|
|
if (count($parameters) >= $reflectionMethod->getNumberOfRequiredParameters())
|
|
{
|
|
// If the function is static
|
|
if ($reflectionMethod->isStatic() === true)
|
|
{
|
|
$classMethod = $resourceName.'::'.$function;
|
|
}
|
|
// If the function is not static
|
|
else
|
|
{
|
|
$classMethod = array(new $resourceName(), $function);
|
|
}
|
|
|
|
// If the resource's function is callable
|
|
if (is_callable($classMethod))
|
|
{
|
|
// Call resource->function()
|
|
// @ was applied to prevent really ugly and unmanageable errors
|
|
$resultCall = @call_user_func_array($classMethod, $parameters);
|
|
// If errors occurred while running it
|
|
// NOTE: if the called function via call_user_func_array returns a boolean set as false,
|
|
// it will be recognized like a running error. A little bit tricky ;)
|
|
if ($resultCall === false)
|
|
{
|
|
$result = error('Error running '.$resourceName.'->'.$function.'()');
|
|
}
|
|
// Returns the result of resource->function()
|
|
else
|
|
{
|
|
$result = success($resultCall);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$result = error($resourceName.'->'.$function.'() is not callable!');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$result = error(
|
|
'Number of required parameters: '.$reflectionMethod->getNumberOfRequiredParameters().'. Given: '.count($parameters)
|
|
);
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
$result = error($e->getMessage());
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
}
|