Closed ngoctt18 closed 5 years ago
application\libraries\Format.php
Remove following code on line 2-3
namespace Restserver\Libraries;
use Exception;
application\libraries\REST_Controller.php
Replace below code upto line 740
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* CodeIgniter Rest Controller
* A fully RESTful server implementation for CodeIgniter using one library, one config file and one controller.
*
* @package CodeIgniter
* @subpackage Libraries
* @category Libraries
* @author Phil Sturgeon, Chris Kacerguis
* @license MIT
* @link https://github.com/chriskacerguis/codeigniter-restserver
* @version 3.0.0
*/
abstract class REST_Controller extends CI_Controller {
// Note: Only the widely used HTTP status codes are documented
// Informational
const HTTP_CONTINUE = 100;
const HTTP_SWITCHING_PROTOCOLS = 101;
const HTTP_PROCESSING = 102; // RFC2518
// Success
/**
* The request has succeeded
*/
const HTTP_OK = 200;
/**
* The server successfully created a new resource
*/
const HTTP_CREATED = 201;
const HTTP_ACCEPTED = 202;
const HTTP_NON_AUTHORITATIVE_INFORMATION = 203;
/**
* The server successfully processed the request, though no content is returned
*/
const HTTP_NO_CONTENT = 204;
const HTTP_RESET_CONTENT = 205;
const HTTP_PARTIAL_CONTENT = 206;
const HTTP_MULTI_STATUS = 207; // RFC4918
const HTTP_ALREADY_REPORTED = 208; // RFC5842
const HTTP_IM_USED = 226; // RFC3229
// Redirection
const HTTP_MULTIPLE_CHOICES = 300;
const HTTP_MOVED_PERMANENTLY = 301;
const HTTP_FOUND = 302;
const HTTP_SEE_OTHER = 303;
/**
* The resource has not been modified since the last request
*/
const HTTP_NOT_MODIFIED = 304;
const HTTP_USE_PROXY = 305;
const HTTP_RESERVED = 306;
const HTTP_TEMPORARY_REDIRECT = 307;
const HTTP_PERMANENTLY_REDIRECT = 308; // RFC7238
// Client Error
/**
* The request cannot be fulfilled due to multiple errors
*/
const HTTP_BAD_REQUEST = 400;
/**
* The user is unauthorized to access the requested resource
*/
const HTTP_UNAUTHORIZED = 401;
const HTTP_PAYMENT_REQUIRED = 402;
/**
* The requested resource is unavailable at this present time
*/
const HTTP_FORBIDDEN = 403;
/**
* The requested resource could not be found
*
* Note: This is sometimes used to mask if there was an UNAUTHORIZED (401) or
* FORBIDDEN (403) error, for security reasons
*/
const HTTP_NOT_FOUND = 404;
/**
* The request method is not supported by the following resource
*/
const HTTP_METHOD_NOT_ALLOWED = 405;
/**
* The request was not acceptable
*/
const HTTP_NOT_ACCEPTABLE = 406;
const HTTP_PROXY_AUTHENTICATION_REQUIRED = 407;
const HTTP_REQUEST_TIMEOUT = 408;
/**
* The request could not be completed due to a conflict with the current state
* of the resource
*/
const HTTP_CONFLICT = 409;
const HTTP_GONE = 410;
const HTTP_LENGTH_REQUIRED = 411;
const HTTP_PRECONDITION_FAILED = 412;
const HTTP_REQUEST_ENTITY_TOO_LARGE = 413;
const HTTP_REQUEST_URI_TOO_LONG = 414;
const HTTP_UNSUPPORTED_MEDIA_TYPE = 415;
const HTTP_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
const HTTP_EXPECTATION_FAILED = 417;
const HTTP_I_AM_A_TEAPOT = 418; // RFC2324
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
const HTTP_LOCKED = 423; // RFC4918
const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
const HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431; // RFC6585
// Server Error
/**
* The server encountered an unexpected error
*
* Note: This is a generic error message when no specific message
* is suitable
*/
const HTTP_INTERNAL_SERVER_ERROR = 500;
/**
* The server does not recognise the request method
*/
const HTTP_NOT_IMPLEMENTED = 501;
const HTTP_BAD_GATEWAY = 502;
const HTTP_SERVICE_UNAVAILABLE = 503;
const HTTP_GATEWAY_TIMEOUT = 504;
const HTTP_VERSION_NOT_SUPPORTED = 505;
const HTTP_VARIANT_ALSO_NEGOTIATES_EXPERIMENTAL = 506; // RFC2295
const HTTP_INSUFFICIENT_STORAGE = 507; // RFC4918
const HTTP_LOOP_DETECTED = 508; // RFC5842
const HTTP_NOT_EXTENDED = 510; // RFC2774
const HTTP_NETWORK_AUTHENTICATION_REQUIRED = 511;
/**
* This defines the rest format
* Must be overridden it in a controller so that it is set
*
* @var string|NULL
*/
protected $rest_format = NULL;
/**
* Defines the list of method properties such as limit, log and level
*
* @var array
*/
protected $methods = [];
/**
* List of allowed HTTP methods
*
* @var array
*/
protected $allowed_http_methods = ['get', 'delete', 'post', 'put', 'options', 'patch', 'head'];
/**
* Contains details about the request
* Fields: body, format, method, ssl
* Note: This is a dynamic object (stdClass)
*
* @var object
*/
protected $request = NULL;
/**
* Contains details about the response
* Fields: format, lang
* Note: This is a dynamic object (stdClass)
*
* @var object
*/
protected $response = NULL;
/**
* Contains details about the REST API
* Fields: db, ignore_limits, key, level, user_id
* Note: This is a dynamic object (stdClass)
*
* @var object
*/
protected $rest = NULL;
/**
* The arguments for the GET request method
*
* @var array
*/
protected $_get_args = [];
/**
* The arguments for the POST request method
*
* @var array
*/
protected $_post_args = [];
/**
* The arguments for the PUT request method
*
* @var array
*/
protected $_put_args = [];
/**
* The arguments for the DELETE request method
*
* @var array
*/
protected $_delete_args = [];
/**
* The arguments for the PATCH request method
*
* @var array
*/
protected $_patch_args = [];
/**
* The arguments for the HEAD request method
*
* @var array
*/
protected $_head_args = [];
/**
* The arguments for the OPTIONS request method
*
* @var array
*/
protected $_options_args = [];
/**
* The arguments for the query parameters
*
* @var array
*/
protected $_query_args = [];
/**
* The arguments from GET, POST, PUT, DELETE, PATCH, HEAD and OPTIONS request methods combined
*
* @var array
*/
protected $_args = [];
/**
* The insert_id of the log entry (if we have one)
*
* @var string
*/
protected $_insert_id = '';
/**
* If the request is allowed based on the API key provided
*
* @var bool
*/
protected $_allow = TRUE;
/**
* The LDAP Distinguished Name of the User post authentication
*
* @var string
*/
protected $_user_ldap_dn = '';
/**
* The start of the response time from the server
*
* @var string
*/
protected $_start_rtime = '';
/**
* The end of the response time from the server
*
* @var string
*/
protected $_end_rtime = '';
/**
* List all supported methods, the first will be the default format
*
* @var array
*/
protected $_supported_formats = [
'json' => 'application/json',
'array' => 'application/json',
'csv' => 'application/csv',
'html' => 'text/html',
'jsonp' => 'application/javascript',
'php' => 'text/plain',
'serialized' => 'application/vnd.php.serialized',
'xml' => 'application/xml'
];
/**
* Information about the current API user
*
* @var object
*/
protected $_apiuser;
/**
* Whether or not to perform a CORS check and apply CORS headers to the request
*
* @var bool
*/
protected $check_cors = NULL;
/**
* Enable XSS flag
* Determines whether the XSS filter is always active when
* GET, OPTIONS, HEAD, POST, PUT, DELETE and PATCH data is encountered
* Set automatically based on config setting
*
* @var bool
*/
protected $_enable_xss = FALSE;
/**
* HTTP status codes and their respective description
* Note: Only the widely used HTTP status codes are used
*
* @var array
* @link http://www.restapitutorial.com/httpstatuscodes.html
*/
protected $http_status_codes = [
self::HTTP_OK => 'OK',
self::HTTP_CREATED => 'CREATED',
self::HTTP_NO_CONTENT => 'NO CONTENT',
self::HTTP_NOT_MODIFIED => 'NOT MODIFIED',
self::HTTP_BAD_REQUEST => 'BAD REQUEST',
self::HTTP_UNAUTHORIZED => 'UNAUTHORIZED',
self::HTTP_FORBIDDEN => 'FORBIDDEN',
self::HTTP_NOT_FOUND => 'NOT FOUND',
self::HTTP_METHOD_NOT_ALLOWED => 'METHOD NOT ALLOWED',
self::HTTP_NOT_ACCEPTABLE => 'NOT ACCEPTABLE',
self::HTTP_CONFLICT => 'CONFLICT',
self::HTTP_INTERNAL_SERVER_ERROR => 'INTERNAL SERVER ERROR',
self::HTTP_NOT_IMPLEMENTED => 'NOT IMPLEMENTED'
];
/**
* Extend this function to apply additional checking early on in the process
*
* @access protected
* @return void
*/
protected function early_checks()
{
}
/**
* Constructor for the REST API
*
* @access public
* @param string $config Configuration filename minus the file extension
* e.g: my_rest.php is passed as 'my_rest'
*/
public function __construct($config = 'rest')
{
parent::__construct();
$this->preflight_checks();
// Set the default value of global xss filtering. Same approach as CodeIgniter 3
$this->_enable_xss = ($this->config->item('global_xss_filtering') === TRUE);
// Don't try to parse template variables like {elapsed_time} and {memory_usage}
// when output is displayed for not damaging data accidentally
$this->output->parse_exec_vars = FALSE;
// Start the timer for how long the request takes
$this->_start_rtime = microtime(TRUE);
// Load the rest.php configuration file
$this->load->config($config);
// At present the library is bundled with REST_Controller 2.5+, but will eventually be part of CodeIgniter (no citation)
$this->load->library('format');
// Determine supported output formats from configuration
$supported_formats = $this->config->item('rest_supported_formats');
// Validate the configuration setting output formats
if (empty($supported_formats))
{
$supported_formats = [];
}
if ( ! is_array($supported_formats))
{
$supported_formats = [$supported_formats];
}
// Add silently the default output format if it is missing
$default_format = $this->_get_default_output_format();
if (!in_array($default_format, $supported_formats))
{
$supported_formats[] = $default_format;
}
// Now update $this->_supported_formats
$this->_supported_formats = array_intersect_key($this->_supported_formats, array_flip($supported_formats));
// Get the language
$language = $this->config->item('rest_language');
if ($language === NULL)
{
$language = 'english';
}
// Load the language file
$this->lang->load('rest_controller', $language);
// Initialise the response, request and rest objects
$this->request = new stdClass();
$this->response = new stdClass();
$this->rest = new stdClass();
// Check to see if the current IP address is blacklisted
if ($this->config->item('rest_ip_blacklist_enabled') === TRUE)
{
$this->_check_blacklist_auth();
}
// Determine whether the connection is HTTPS
$this->request->ssl = is_https();
// How is this request being made? GET, POST, PATCH, DELETE, INSERT, PUT, HEAD or OPTIONS
$this->request->method = $this->_detect_method();
// Check for CORS access request
$check_cors = $this->config->item('check_cors');
if ($check_cors === TRUE)
{
$this->_check_cors();
}
// Create an argument container if it doesn't exist e.g. _get_args
if (isset($this->{'_'.$this->request->method.'_args'}) === FALSE)
{
$this->{'_'.$this->request->method.'_args'} = [];
}
// Set up the query parameters
$this->_parse_query();
// Set up the GET variables
$this->_get_args = array_merge($this->_get_args, $this->uri->ruri_to_assoc());
// Try to find a format for the request (means we have a request body)
$this->request->format = $this->_detect_input_format();
// Not all methods have a body attached with them
$this->request->body = NULL;
$this->{'_parse_' . $this->request->method}();
// Now we know all about our request, let's try and parse the body if it exists
if ($this->request->format && $this->request->body)
{
$this->request->body = $this->format->factory($this->request->body, $this->request->format)->to_array();
// Assign payload arguments to proper method container
$this->{'_'.$this->request->method.'_args'} = $this->request->body;
}
//get header vars
$this->_head_args = $this->input->request_headers();
// Merge both for one mega-args variable
$this->_args = array_merge(
$this->_get_args,
$this->_options_args,
$this->_patch_args,
$this->_head_args,
$this->_put_args,
$this->_post_args,
$this->_delete_args,
$this->{'_'.$this->request->method.'_args'}
);
// Which format should the data be returned in?
$this->response->format = $this->_detect_output_format();
// Which language should the data be returned in?
$this->response->lang = $this->_detect_lang();
// Extend this function to apply additional checking early on in the process
$this->early_checks();
// Load DB if its enabled
if ($this->config->item('rest_database_group') && ($this->config->item('rest_enable_keys') || $this->config->item('rest_enable_logging')))
{
$this->rest->db = $this->load->database($this->config->item('rest_database_group'), TRUE);
}
// Use whatever database is in use (isset returns FALSE)
elseif (property_exists($this, 'db'))
{
$this->rest->db = $this->db;
}
// Check if there is a specific auth type for the current class/method
// _auth_override_check could exit so we need $this->rest->db initialized before
$this->auth_override = $this->_auth_override_check();
// Checking for keys? GET TO WorK!
// Skip keys test for $config['auth_override_class_method']['class'['method'] = 'none'
if ($this->config->item('rest_enable_keys') && $this->auth_override !== TRUE)
{
$this->_allow = $this->_detect_api_key();
}
// Only allow ajax requests
if ($this->input->is_ajax_request() === FALSE && $this->config->item('rest_ajax_only'))
{
// Display an error response
$this->response([
$this->config->item('rest_status_field_name') => FALSE,
$this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ajax_only')
], self::HTTP_NOT_ACCEPTABLE);
}
// When there is no specific override for the current class/method, use the default auth value set in the config
if ($this->auth_override === FALSE &&
(! ($this->config->item('rest_enable_keys') && $this->_allow === TRUE) ||
($this->config->item('allow_auth_and_keys') === TRUE && $this->_allow === TRUE)))
{
$rest_auth = strtolower($this->config->item('rest_auth'));
switch ($rest_auth)
{
case 'basic':
$this->_prepare_basic_auth();
break;
case 'digest':
$this->_prepare_digest_auth();
break;
case 'session':
$this->_check_php_session();
break;
}
if ($this->config->item('rest_ip_whitelist_enabled') === TRUE)
{
$this->_check_whitelist_auth();
}
}
}
/**
* Deconstructor
*
* @author Chris Kacerguis
* @access public
* @return void
*/
public function __destruct()
{
// Get the current timestamp
$this->_end_rtime = microtime(TRUE);
// Log the loading time to the log table
if ($this->config->item('rest_enable_logging') === TRUE)
{
$this->_log_access_time();
}
}
/**
* Checks to see if we have everything we need to run this library.
*
* @access protected
* @@throws Exception
*/
protected function preflight_checks()
{
// Check to see if PHP is equal to or greater than 5.4.x
if (is_php('5.4') === FALSE)
{
// CodeIgniter 3 is recommended for v5.4 or above
throw new Exception('Using PHP v'.PHP_VERSION.', though PHP v5.4 or greater is required');
}
// Check to see if this is CI 3.x
if (explode('.', CI_VERSION, 2)[0] < 3)
{
throw new Exception('REST Server requires CodeIgniter 3.x');
}
}
/**
* Requests are not made to methods directly, the request will be for
* an "object". This simply maps the object and method to the correct
* Controller method
*
* @access public
* @param string $object_called
* @param array $arguments The arguments passed to the controller method
*/
public function _remap($object_called, $arguments = [])
{
// Should we answer if not over SSL?
if ($this->config->item('force_https') && $this->request->ssl === FALSE)
{
$this->response([
$this->config->item('rest_status_field_name') => FALSE,
$this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unsupported')
], self::HTTP_FORBIDDEN);
}
// Remove the supported format from the function name e.g. index.json => index
$object_called = preg_replace('/^(.*)\.(?:'.implode('|', array_keys($this->_supported_formats)).')$/', '$1', $object_called);
$controller_method = $object_called.'_'.$this->request->method;
// Does this method exist? If not, try executing an index method
if (!method_exists($this, $controller_method)) {
$controller_method = "index_" . $this->request->method;
array_unshift($arguments, $object_called);
}
// Do we want to log this method (if allowed by config)?
$log_method = ! (isset($this->methods[$controller_method]['log']) && $this->methods[$controller_method]['log'] === FALSE);
// Use keys for this method?
$use_key = ! (isset($this->methods[$controller_method]['key']) && $this->methods[$controller_method]['key'] === FALSE);
// They provided a key, but it wasn't valid, so get them out of here
if ($this->config->item('rest_enable_keys') && $use_key && $this->_allow === FALSE)
{
if ($this->config->item('rest_enable_logging') && $log_method)
{
$this->_log_request();
}
// fix cross site to option request error
if($this->request->method == 'options') {
exit;
}
$this->response([
$this->config->item('rest_status_field_name') => FALSE,
$this->config->item('rest_message_field_name') => sprintf($this->lang->line('text_rest_invalid_api_key'), $this->rest->key)
], self::HTTP_FORBIDDEN);
}
// Check to see if this key has access to the requested controller
if ($this->config->item('rest_enable_keys') && $use_key && empty($this->rest->key) === FALSE && $this->_check_access() === FALSE)
{
if ($this->config->item('rest_enable_logging') && $log_method)
{
$this->_log_request();
}
$this->response([
$this->config->item('rest_status_field_name') => FALSE,
$this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_unauthorized')
], self::HTTP_UNAUTHORIZED);
}
// Sure it exists, but can they do anything with it?
if (! method_exists($this, $controller_method))
{
$this->response([
$this->config->item('rest_status_field_name') => FALSE,
$this->config->item('rest_message_field_name') => $this->lang->line('text_rest_unknown_method')
], self::HTTP_METHOD_NOT_ALLOWED);
}
// Doing key related stuff? Can only do it if they have a key right?
if ($this->config->item('rest_enable_keys') && empty($this->rest->key) === FALSE)
{
// Check the limit
if ($this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === FALSE)
{
$response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_time_limit')];
$this->response($response, self::HTTP_UNAUTHORIZED);
}
// If no level is set use 0, they probably aren't using permissions
$level = isset($this->methods[$controller_method]['level']) ? $this->methods[$controller_method]['level'] : 0;
// If no level is set, or it is lower than/equal to the key's level
$authorized = $level <= $this->rest->level;
// IM TELLIN!
if ($this->config->item('rest_enable_logging') && $log_method)
{
$this->_log_request($authorized);
}
if($authorized === FALSE)
{
// They don't have good enough perms
$response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_api_key_permissions')];
$this->response($response, self::HTTP_UNAUTHORIZED);
}
}
//check request limit by ip without login
elseif ($this->config->item('rest_limits_method') == "IP_ADDRESS" && $this->config->item('rest_enable_limits') && $this->_check_limit($controller_method) === FALSE)
{
$response = [$this->config->item('rest_status_field_name') => FALSE, $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_address_time_limit')];
$this->response($response, self::HTTP_UNAUTHORIZED);
}
// No key stuff, but record that stuff is happening
elseif ($this->config->item('rest_enable_logging') && $log_method)
{
$this->_log_request($authorized = TRUE);
}
// Call the controller method and passed arguments
try
{
call_user_func_array([$this, $controller_method], $arguments);
}
catch (Exception $ex)
{
// If the method doesn't exist, then the error will be caught and an error response shown
$_error = &load_class('Exceptions', 'core');
$_error->show_exception($ex);
}
}
................
...............
Hi, i do it, but i have a question abou the response.
In the example is the next
$this->response([ 'status' => TRUE, 'message' => 'The user has been added successfully.', 'data' => $insert ], REST_Controller::HTTP_OK);
But when the method insert, i don't have the correct response, i received this Fatal error: Undefined class constant 'HTTP_OK'
How to resolve this?
Version 3.1 should fix this.
Thanks, the version 3.1 worked successfully!
I have an other cuestion about the controller.
In my case i construct this
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
use Restserver\Libraries\RestController;
require APPPATH . '/libraries/RestController.php';
require APPPATH . '/libraries/Format.php';
class DemoRestserver extends RestController {
}
If i comment the "require", i receive an error Fatal error: Class 'Restserver\Libraries\RestController' not found.
I load the libraries in the config.php, but doen't work
Based on what you posted, it doesn't look like you followed the install directions. Please give it another try.
Based on what you posted, it doesn't look like you followed the install directions. Please give it another try.
Ok man, but i don't find the documentation for this version, can you give me the link please?
Thanks a lot!!
I copy all the folders inside folder application into my folder application in my project. I also use
composer require chriskacerguis/codeigniter-restserver
but when i open example page. I got this error.