_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 and * is the name of the model or of the library * 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=&function=&=&=&= * will call .(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; } }