You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							2166 lines
						
					
					
						
							72 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							2166 lines
						
					
					
						
							72 KiB
						
					
					
				
								<?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;
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * 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'
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    public function __construct($config = 'rest')
							 | 
						|
								    {
							 | 
						|
								        parent::__construct();
							 | 
						|
								
							 | 
						|
								        // Disable XML Entity (security vulnerability)
							 | 
						|
								        libxml_disable_entity_loader(TRUE);
							 | 
						|
								
							 | 
						|
								        // 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');
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // 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();
							 | 
						|
								
							 | 
						|
								        // 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;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // 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();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * 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;
							 | 
						|
								
							 | 
						|
								        // 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();
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            $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) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $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_NOT_FOUND);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // 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);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // 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')];
							 | 
						|
								            $authorized || $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
							 | 
						|
								            $this->response([
							 | 
						|
								                $this->config->item('rest_status_field_name') => FALSE,
							 | 
						|
								                $this->config->item('rest_message_field_name') => [
							 | 
						|
								                    'classname' => get_class($ex),
							 | 
						|
								                    'message' => $ex->getMessage()
							 | 
						|
								                ]
							 | 
						|
								            ], self::HTTP_INTERNAL_SERVER_ERROR);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Takes mixed data and optionally a status code, then creates the response
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param array|NULL $data Data to output to the user
							 | 
						|
								     * @param int|NULL $http_code HTTP status code
							 | 
						|
								     * @param bool $continue TRUE to flush the response to the client and continue
							 | 
						|
								     * running the script; otherwise, exit
							 | 
						|
								     */
							 | 
						|
								    public function response($data = NULL, $http_code = NULL, $continue = FALSE)
							 | 
						|
								    {
							 | 
						|
								        // If the HTTP status is not NULL, then cast as an integer
							 | 
						|
								        if ($http_code !== NULL)
							 | 
						|
								        {
							 | 
						|
								            // So as to be safe later on in the process
							 | 
						|
								            $http_code = (int) $http_code;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Set the output as NULL by default
							 | 
						|
								        $output = NULL;
							 | 
						|
								
							 | 
						|
								        // If data is NULL and no HTTP status code provided, then display, error and exit
							 | 
						|
								        if ($data === NULL && $http_code === NULL)
							 | 
						|
								        {
							 | 
						|
								            $http_code = self::HTTP_NOT_FOUND;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If data is not NULL and a HTTP status code provided, then continue
							 | 
						|
								        elseif ($data !== NULL)
							 | 
						|
								        {
							 | 
						|
								            // If the format method exists, call and return the output in that format
							 | 
						|
								            if (method_exists($this->format, 'to_' . $this->response->format))
							 | 
						|
								            {
							 | 
						|
								                // Set the format header
							 | 
						|
								                $this->output->set_content_type($this->_supported_formats[$this->response->format], strtolower($this->config->item('charset')));
							 | 
						|
								                $output = $this->format->factory($data)->{'to_' . $this->response->format}();
							 | 
						|
								
							 | 
						|
								                // An array must be parsed as a string, so as not to cause an array to string error
							 | 
						|
								                // Json is the most appropriate form for such a datatype
							 | 
						|
								                if ($this->response->format === 'array')
							 | 
						|
								                {
							 | 
						|
								                    $output = $this->format->factory($output)->{'to_json'}();
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								            else
							 | 
						|
								            {
							 | 
						|
								                // If an array or object, then parse as a json, so as to be a 'string'
							 | 
						|
								                if (is_array($data) || is_object($data))
							 | 
						|
								                {
							 | 
						|
								                    $data = $this->format->factory($data)->{'to_json'}();
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Format is not supported, so output the raw data as a string
							 | 
						|
								                $output = $data;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // If not greater than zero, then set the HTTP status code as 200 by default
							 | 
						|
								        // Though perhaps 500 should be set instead, for the developer not passing a
							 | 
						|
								        // correct HTTP status code
							 | 
						|
								        $http_code > 0 || $http_code = self::HTTP_OK;
							 | 
						|
								
							 | 
						|
								        $this->output->set_status_header($http_code);
							 | 
						|
								
							 | 
						|
								        // JC: Log response code only if rest logging enabled
							 | 
						|
								        if ($this->config->item('rest_enable_logging') === TRUE)
							 | 
						|
								        {
							 | 
						|
								            $this->_log_response_code($http_code);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Output the data
							 | 
						|
								        $this->output->set_output($output);
							 | 
						|
								
							 | 
						|
								        if ($continue === FALSE)
							 | 
						|
								        {
							 | 
						|
								            // Display the data and exit execution
							 | 
						|
								            $this->output->_display();
							 | 
						|
								            exit;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Otherwise dump the output automatically
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Takes mixed data and optionally a status code, then creates the response
							 | 
						|
								     * within the buffers of the Output class. The response is sent to the client
							 | 
						|
								     * lately by the framework, after the current controller's method termination.
							 | 
						|
								     * All the hooks after the controller's method termination are executable
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param array|NULL $data Data to output to the user
							 | 
						|
								     * @param int|NULL $http_code HTTP status code
							 | 
						|
								     */
							 | 
						|
								    public function set_response($data = NULL, $http_code = NULL)
							 | 
						|
								    {
							 | 
						|
								        $this->response($data, $http_code, TRUE);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Get the input format e.g. json or xml
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return string|NULL Supported input format; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    protected function _detect_input_format()
							 | 
						|
								    {
							 | 
						|
								        // Get the CONTENT-TYPE value from the SERVER variable
							 | 
						|
								        $content_type = $this->input->server('CONTENT_TYPE');
							 | 
						|
								
							 | 
						|
								        if (empty($content_type) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            // Check all formats against the HTTP_ACCEPT header
							 | 
						|
								            foreach ($this->_supported_formats as $key => $value)
							 | 
						|
								            {
							 | 
						|
								                // $key = format e.g. csv
							 | 
						|
								                // $value = mime type e.g. application/csv
							 | 
						|
								
							 | 
						|
								                // If a semi-colon exists in the string, then explode by ; and get the value of where
							 | 
						|
								                // the current array pointer resides. This will generally be the first element of the array
							 | 
						|
								                $content_type = (strpos($content_type, ';') !== FALSE ? current(explode(';', $content_type)) : $content_type);
							 | 
						|
								
							 | 
						|
								                // If both the mime types match, then return the format
							 | 
						|
								                if ($content_type === $value)
							 | 
						|
								                {
							 | 
						|
								                    return $key;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Gets the default format from the configuration. Fallbacks to 'json'
							 | 
						|
								     * if the corresponding configuration option $config['rest_default_format']
							 | 
						|
								     * is missing or is empty
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return string The default supported input format
							 | 
						|
								     */
							 | 
						|
								    protected function _get_default_output_format()
							 | 
						|
								    {
							 | 
						|
								        $default_format = (string) $this->config->item('rest_default_format');
							 | 
						|
								        return $default_format === '' ? 'json' : $default_format;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Detect which format should be used to output the data
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return mixed|NULL|string Output format
							 | 
						|
								     */
							 | 
						|
								    protected function _detect_output_format()
							 | 
						|
								    {
							 | 
						|
								        // Concatenate formats to a regex pattern e.g. \.(csv|json|xml)
							 | 
						|
								        $pattern = '/\.(' . implode('|', array_keys($this->_supported_formats)) . ')($|\/)/';
							 | 
						|
								        $matches = [];
							 | 
						|
								
							 | 
						|
								        // Check if a file extension is used e.g. http://example.com/api/index.json?param1=param2
							 | 
						|
								        if (preg_match($pattern, $this->uri->uri_string(), $matches))
							 | 
						|
								        {
							 | 
						|
								            return $matches[1];
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get the format parameter named as 'format'
							 | 
						|
								        if (isset($this->_get_args['format']))
							 | 
						|
								        {
							 | 
						|
								            $format = strtolower($this->_get_args['format']);
							 | 
						|
								
							 | 
						|
								            if (isset($this->_supported_formats[$format]) === TRUE)
							 | 
						|
								            {
							 | 
						|
								                return $format;
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Get the HTTP_ACCEPT server variable
							 | 
						|
								        $http_accept = $this->input->server('HTTP_ACCEPT');
							 | 
						|
								
							 | 
						|
								        // Otherwise, check the HTTP_ACCEPT server variable
							 | 
						|
								        if ($this->config->item('rest_ignore_http_accept') === FALSE && $http_accept !== NULL)
							 | 
						|
								        {
							 | 
						|
								            // Check all formats against the HTTP_ACCEPT header
							 | 
						|
								            foreach (array_keys($this->_supported_formats) as $format)
							 | 
						|
								            {
							 | 
						|
								                // Has this format been requested?
							 | 
						|
								                if (strpos($http_accept, $format) !== FALSE)
							 | 
						|
								                {
							 | 
						|
								                    if ($format !== 'html' && $format !== 'xml')
							 | 
						|
								                    {
							 | 
						|
								                        // If not HTML or XML assume it's correct
							 | 
						|
								                        return $format;
							 | 
						|
								                    }
							 | 
						|
								                    elseif ($format === 'html' && strpos($http_accept, 'xml') === FALSE)
							 | 
						|
								                    {
							 | 
						|
								                        // HTML or XML have shown up as a match
							 | 
						|
								                        // If it is truly HTML, it wont want any XML
							 | 
						|
								                        return $format;
							 | 
						|
								                    }
							 | 
						|
								                    else if ($format === 'xml' && strpos($http_accept, 'html') === FALSE)
							 | 
						|
								                    {
							 | 
						|
								                        // If it is truly XML, it wont want any HTML
							 | 
						|
								                        return $format;
							 | 
						|
								                    }
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Check if the controller has a default format
							 | 
						|
								        if (empty($this->rest_format) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            return $this->rest_format;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Obtain the default format from the configuration
							 | 
						|
								        return $this->_get_default_output_format();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Get the HTTP request string e.g. get or post
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return string|NULL Supported request method as a lowercase string; otherwise, NULL if not supported
							 | 
						|
								     */
							 | 
						|
								    protected function _detect_method()
							 | 
						|
								    {
							 | 
						|
								        // Declare a variable to store the method
							 | 
						|
								        $method = NULL;
							 | 
						|
								
							 | 
						|
								        // Determine whether the 'enable_emulate_request' setting is enabled
							 | 
						|
								        if ($this->config->item('enable_emulate_request') === TRUE)
							 | 
						|
								        {
							 | 
						|
								            $method = $this->input->post('_method');
							 | 
						|
								            if ($method === NULL)
							 | 
						|
								            {
							 | 
						|
								                $method = $this->input->server('HTTP_X_HTTP_METHOD_OVERRIDE');
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            $method = strtolower($method);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (empty($method))
							 | 
						|
								        {
							 | 
						|
								            // Get the request method as a lowercase string
							 | 
						|
								            $method = $this->input->method();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return in_array($method, $this->allowed_http_methods) && method_exists($this, '_parse_' . $method) ? $method : 'get';
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * See if the user has provided an API key
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function _detect_api_key()
							 | 
						|
								    {
							 | 
						|
								        // Get the api key name variable set in the rest config file
							 | 
						|
								        $api_key_variable = $this->config->item('rest_key_name');
							 | 
						|
								
							 | 
						|
								        // Work out the name of the SERVER entry based on config
							 | 
						|
								        $key_name = 'HTTP_' . strtoupper(str_replace('-', '_', $api_key_variable));
							 | 
						|
								
							 | 
						|
								        $this->rest->key = NULL;
							 | 
						|
								        $this->rest->level = NULL;
							 | 
						|
								        $this->rest->user_id = NULL;
							 | 
						|
								        $this->rest->ignore_limits = FALSE;
							 | 
						|
								
							 | 
						|
								        // Find the key from server or arguments
							 | 
						|
								        if (($key = isset($this->_args[$api_key_variable]) ? $this->_args[$api_key_variable] : $this->input->server($key_name)))
							 | 
						|
								        {
							 | 
						|
								            if (!($row = $this->rest->db->where($this->config->item('rest_key_column'), $key)->get($this->config->item('rest_keys_table'))->row()))
							 | 
						|
								            {
							 | 
						|
								                return FALSE;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            $this->rest->key = $row->{$this->config->item('rest_key_column')};
							 | 
						|
								
							 | 
						|
								            isset($row->user_id) && $this->rest->user_id = $row->user_id;
							 | 
						|
								            isset($row->level) && $this->rest->level = $row->level;
							 | 
						|
								            isset($row->ignore_limits) && $this->rest->ignore_limits = $row->ignore_limits;
							 | 
						|
								
							 | 
						|
								            $this->_apiuser = $row;
							 | 
						|
								
							 | 
						|
								            /*
							 | 
						|
								             * If "is private key" is enabled, compare the ip address with the list
							 | 
						|
								             * of valid ip addresses stored in the database
							 | 
						|
								             */
							 | 
						|
								            if (empty($row->is_private_key) === FALSE)
							 | 
						|
								            {
							 | 
						|
								                // Check for a list of valid ip addresses
							 | 
						|
								                if (isset($row->ip_addresses))
							 | 
						|
								                {
							 | 
						|
								                    // multiple ip addresses must be separated using a comma, explode and loop
							 | 
						|
								                    $list_ip_addresses = explode(',', $row->ip_addresses);
							 | 
						|
								                    $found_address = FALSE;
							 | 
						|
								
							 | 
						|
								                    foreach ($list_ip_addresses as $ip_address)
							 | 
						|
								                    {
							 | 
						|
								                        if ($this->input->ip_address() === trim($ip_address))
							 | 
						|
								                        {
							 | 
						|
								                            // there is a match, set the the value to TRUE and break out of the loop
							 | 
						|
								                            $found_address = TRUE;
							 | 
						|
								                            break;
							 | 
						|
								                        }
							 | 
						|
								                    }
							 | 
						|
								
							 | 
						|
								                    return $found_address;
							 | 
						|
								                }
							 | 
						|
								                else
							 | 
						|
								                {
							 | 
						|
								                    // There should be at least one IP address for this private key
							 | 
						|
								                    return FALSE;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return TRUE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // No key has been sent
							 | 
						|
								        return FALSE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Preferred return language
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return string|NULL The language code
							 | 
						|
								     */
							 | 
						|
								    protected function _detect_lang()
							 | 
						|
								    {
							 | 
						|
								        $lang = $this->input->server('HTTP_ACCEPT_LANGUAGE');
							 | 
						|
								        if ($lang === NULL)
							 | 
						|
								        {
							 | 
						|
								            return NULL;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // It appears more than one language has been sent using a comma delimiter
							 | 
						|
								        if (strpos($lang, ',') !== FALSE)
							 | 
						|
								        {
							 | 
						|
								            $langs = explode(',', $lang);
							 | 
						|
								
							 | 
						|
								            $return_langs = [];
							 | 
						|
								            foreach ($langs as $lang)
							 | 
						|
								            {
							 | 
						|
								                // Remove weight and trim leading and trailing whitespace
							 | 
						|
								                list($lang) = explode(';', $lang);
							 | 
						|
								                $return_langs[] = trim($lang);
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            return $return_langs;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Otherwise simply return as a string
							 | 
						|
								        return $lang;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Add the request to the log table
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param bool $authorized TRUE the user is authorized; otherwise, FALSE
							 | 
						|
								     * @return bool TRUE the data was inserted; otherwise, FALSE
							 | 
						|
								     */
							 | 
						|
								    protected function _log_request($authorized = FALSE)
							 | 
						|
								    {
							 | 
						|
								        // Insert the request into the log table
							 | 
						|
								        $is_inserted = $this->rest->db
							 | 
						|
								            ->insert(
							 | 
						|
								                $this->config->item('rest_logs_table'), [
							 | 
						|
								                'uri' => $this->uri->uri_string(),
							 | 
						|
								                'method' => $this->request->method,
							 | 
						|
								                'params' => $this->_args ? ($this->config->item('rest_logs_json_params') === TRUE ? json_encode($this->_args) : serialize($this->_args)) : NULL,
							 | 
						|
								                'api_key' => isset($this->rest->key) ? $this->rest->key : '',
							 | 
						|
								                'ip_address' => $this->input->ip_address(),
							 | 
						|
								                'time' => time(),
							 | 
						|
								                'authorized' => $authorized
							 | 
						|
								            ]);
							 | 
						|
								
							 | 
						|
								        // Get the last insert id to update at a later stage of the request
							 | 
						|
								        $this->_insert_id = $this->rest->db->insert_id();
							 | 
						|
								
							 | 
						|
								        return $is_inserted;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check if the requests to a controller method exceed a limit
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param  string $controller_method The method being called
							 | 
						|
								     * @return bool TRUE the call limit is below the threshold; otherwise, FALSE
							 | 
						|
								     */
							 | 
						|
								    protected function _check_limit($controller_method)
							 | 
						|
								    {
							 | 
						|
								        // They are special, or it might not even have a limit
							 | 
						|
								        if (empty($this->rest->ignore_limits) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            // Everything is fine
							 | 
						|
								            return TRUE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        switch ($this->config->item('rest_limits_method'))
							 | 
						|
								        {
							 | 
						|
								            case 'API_KEY':
							 | 
						|
								                $limited_uri = 'api-key:' . (isset($this->rest->key) ? $this->rest->key : '');
							 | 
						|
								                $limited_method_name = isset($this->rest->key) ? $this->rest->key : '';
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case 'METHOD_NAME':
							 | 
						|
								                $limited_uri = 'method-name:' . $controller_method;
							 | 
						|
								                $limited_method_name =  $controller_method;
							 | 
						|
								                break;
							 | 
						|
								
							 | 
						|
								            case 'ROUTED_URL':
							 | 
						|
								            default:
							 | 
						|
								                $limited_uri = $this->uri->ruri_string();
							 | 
						|
								                if (strpos(strrev($limited_uri), strrev($this->response->format)) === 0)
							 | 
						|
								                {
							 | 
						|
								                    $limited_uri = substr($limited_uri,0, -strlen($this->response->format) - 1);
							 | 
						|
								                }
							 | 
						|
								                $limited_uri = 'uri:' . $limited_uri . ':' . $this->request->method; // It's good to differentiate GET from PUT
							 | 
						|
								                $limited_method_name = $controller_method;
							 | 
						|
								                break;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (isset($this->methods[$limited_method_name]['limit']) === FALSE )
							 | 
						|
								        {
							 | 
						|
								            // Everything is fine
							 | 
						|
								            return TRUE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // How many times can you get to this method in a defined time_limit (default: 1 hour)?
							 | 
						|
								        $limit = $this->methods[$limited_method_name]['limit'];
							 | 
						|
								
							 | 
						|
								        $time_limit = (isset($this->methods[$limited_method_name]['time']) ? $this->methods[$limited_method_name]['time'] : 3600); // 3600 = 60 * 60
							 | 
						|
								
							 | 
						|
								        // Get data about a keys' usage and limit to one row
							 | 
						|
								        $result = $this->rest->db
							 | 
						|
								            ->where('uri', $limited_uri)
							 | 
						|
								            ->where('api_key', $this->rest->key)
							 | 
						|
								            ->get($this->config->item('rest_limits_table'))
							 | 
						|
								            ->row();
							 | 
						|
								
							 | 
						|
								        // No calls have been made for this key
							 | 
						|
								        if ($result === NULL)
							 | 
						|
								        {
							 | 
						|
								            // Create a new row for the following key
							 | 
						|
								            $this->rest->db->insert($this->config->item('rest_limits_table'), [
							 | 
						|
								                'uri' => $limited_uri,
							 | 
						|
								                'api_key' => isset($this->rest->key) ? $this->rest->key : '',
							 | 
						|
								                'count' => 1,
							 | 
						|
								                'hour_started' => time()
							 | 
						|
								            ]);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Been a time limit (or by default an hour) since they called
							 | 
						|
								        elseif ($result->hour_started < (time() - $time_limit))
							 | 
						|
								        {
							 | 
						|
								            // Reset the started period and count
							 | 
						|
								            $this->rest->db
							 | 
						|
								                ->where('uri', $limited_uri)
							 | 
						|
								                ->where('api_key', isset($this->rest->key) ? $this->rest->key : '')
							 | 
						|
								                ->set('hour_started', time())
							 | 
						|
								                ->set('count', 1)
							 | 
						|
								                ->update($this->config->item('rest_limits_table'));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // They have called within the hour, so lets update
							 | 
						|
								        else
							 | 
						|
								        {
							 | 
						|
								            // The limit has been exceeded
							 | 
						|
								            if ($result->count >= $limit)
							 | 
						|
								            {
							 | 
						|
								                return FALSE;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Increase the count by one
							 | 
						|
								            $this->rest->db
							 | 
						|
								                ->where('uri', $limited_uri)
							 | 
						|
								                ->where('api_key', $this->rest->key)
							 | 
						|
								                ->set('count', 'count + 1', FALSE)
							 | 
						|
								                ->update($this->config->item('rest_limits_table'));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return TRUE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check if there is a specific auth type set for the current class/method/HTTP-method being called
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function _auth_override_check()
							 | 
						|
								    {
							 | 
						|
								        // Assign the class/method auth type override array from the config
							 | 
						|
								        $auth_override_class_method = $this->config->item('auth_override_class_method');
							 | 
						|
								
							 | 
						|
								        // Check to see if the override array is even populated
							 | 
						|
								        if (!empty($auth_override_class_method))
							 | 
						|
								        {
							 | 
						|
								            // check for wildcard flag for rules for classes
							 | 
						|
								            if (!empty($auth_override_class_method[$this->router->class]['*'])) // Check for class overrides
							 | 
						|
								            {
							 | 
						|
								                // None auth override found, prepare nothing but send back a TRUE override flag
							 | 
						|
								                if ($auth_override_class_method[$this->router->class]['*'] === 'none')
							 | 
						|
								                {
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Basic auth override found, prepare basic
							 | 
						|
								                if ($auth_override_class_method[$this->router->class]['*'] === 'basic')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_basic_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Digest auth override found, prepare digest
							 | 
						|
								                if ($auth_override_class_method[$this->router->class]['*'] === 'digest')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_digest_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Session auth override found, check session
							 | 
						|
								                if ($auth_override_class_method[$this->router->class]['*'] === 'session')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_php_session();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Whitelist auth override found, check client's ip against config whitelist
							 | 
						|
								                if ($auth_override_class_method[$this->router->class]['*'] === 'whitelist')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_whitelist_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Check to see if there's an override value set for the current class/method being called
							 | 
						|
								            if (!empty($auth_override_class_method[$this->router->class][$this->router->method]))
							 | 
						|
								            {
							 | 
						|
								                // None auth override found, prepare nothing but send back a TRUE override flag
							 | 
						|
								                if ($auth_override_class_method[$this->router->class][$this->router->method] === 'none')
							 | 
						|
								                {
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Basic auth override found, prepare basic
							 | 
						|
								                if ($auth_override_class_method[$this->router->class][$this->router->method] === 'basic')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_basic_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Digest auth override found, prepare digest
							 | 
						|
								                if ($auth_override_class_method[$this->router->class][$this->router->method] === 'digest')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_digest_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Session auth override found, check session
							 | 
						|
								                if ($auth_override_class_method[$this->router->class][$this->router->method] === 'session')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_php_session();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Whitelist auth override found, check client's ip against config whitelist
							 | 
						|
								                if ($auth_override_class_method[$this->router->class][$this->router->method] === 'whitelist')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_whitelist_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Assign the class/method/HTTP-method auth type override array from the config
							 | 
						|
								        $auth_override_class_method_http = $this->config->item('auth_override_class_method_http');
							 | 
						|
								
							 | 
						|
								        // Check to see if the override array is even populated
							 | 
						|
								        if (!empty($auth_override_class_method_http))
							 | 
						|
								        {
							 | 
						|
								            // check for wildcard flag for rules for classes
							 | 
						|
								            if(!empty($auth_override_class_method_http[$this->router->class]['*'][$this->request->method]))
							 | 
						|
								            {
							 | 
						|
								                // None auth override found, prepare nothing but send back a TRUE override flag
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'none')
							 | 
						|
								                {
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Basic auth override found, prepare basic
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'basic')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_basic_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Digest auth override found, prepare digest
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'digest')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_digest_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Session auth override found, check session
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'session')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_php_session();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Whitelist auth override found, check client's ip against config whitelist
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class]['*'][$this->request->method] === 'whitelist')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_whitelist_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            // Check to see if there's an override value set for the current class/method/HTTP-method being called
							 | 
						|
								            if(!empty($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method]))
							 | 
						|
								            {
							 | 
						|
								                // None auth override found, prepare nothing but send back a TRUE override flag
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'none')
							 | 
						|
								                {
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Basic auth override found, prepare basic
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'basic')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_basic_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Digest auth override found, prepare digest
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'digest')
							 | 
						|
								                {
							 | 
						|
								                    $this->_prepare_digest_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Session auth override found, check session
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'session')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_php_session();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								
							 | 
						|
								                // Whitelist auth override found, check client's ip against config whitelist
							 | 
						|
								                if ($auth_override_class_method_http[$this->router->class][$this->router->method][$this->request->method] === 'whitelist')
							 | 
						|
								                {
							 | 
						|
								                    $this->_check_whitelist_auth();
							 | 
						|
								
							 | 
						|
								                    return TRUE;
							 | 
						|
								                }
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								        return FALSE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the GET request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_get()
							 | 
						|
								    {
							 | 
						|
								        // Merge both the URI segments and query parameters
							 | 
						|
								        $this->_get_args = array_merge($this->_get_args, $this->_query_args);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the POST request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_post()
							 | 
						|
								    {
							 | 
						|
								        $this->_post_args = $_POST;
							 | 
						|
								
							 | 
						|
								        if ($this->request->format)
							 | 
						|
								        {
							 | 
						|
								            $this->request->body = $this->input->raw_input_stream;
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the PUT request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_put()
							 | 
						|
								    {
							 | 
						|
								        if ($this->request->format)
							 | 
						|
								        {
							 | 
						|
								            $this->request->body = $this->input->raw_input_stream;
							 | 
						|
								        }
							 | 
						|
								        else if ($this->input->method() === 'put')
							 | 
						|
								        {
							 | 
						|
								            // If no filetype is provided, then there are probably just arguments
							 | 
						|
								            $this->_put_args = $this->input->input_stream();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the HEAD request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_head()
							 | 
						|
								    {
							 | 
						|
								        // Parse the HEAD variables
							 | 
						|
								        parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $head);
							 | 
						|
								
							 | 
						|
								        // Merge both the URI segments and HEAD params
							 | 
						|
								        $this->_head_args = array_merge($this->_head_args, $head);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the OPTIONS request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_options()
							 | 
						|
								    {
							 | 
						|
								        // Parse the OPTIONS variables
							 | 
						|
								        parse_str(parse_url($this->input->server('REQUEST_URI'), PHP_URL_QUERY), $options);
							 | 
						|
								
							 | 
						|
								        // Merge both the URI segments and OPTIONS params
							 | 
						|
								        $this->_options_args = array_merge($this->_options_args, $options);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the PATCH request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_patch()
							 | 
						|
								    {
							 | 
						|
								        // It might be a HTTP body
							 | 
						|
								        if ($this->request->format)
							 | 
						|
								        {
							 | 
						|
								            $this->request->body = $this->input->raw_input_stream;
							 | 
						|
								        }
							 | 
						|
								        else if ($this->input->method() === 'patch')
							 | 
						|
								        {
							 | 
						|
								            // If no filetype is provided, then there are probably just arguments
							 | 
						|
								            $this->_patch_args = $this->input->input_stream();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the DELETE request arguments
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_delete()
							 | 
						|
								    {
							 | 
						|
								        // These should exist if a DELETE request
							 | 
						|
								        if ($this->input->method() === 'delete')
							 | 
						|
								        {
							 | 
						|
								            $this->_delete_args = $this->input->input_stream();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Parse the query parameters
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _parse_query()
							 | 
						|
								    {
							 | 
						|
								        $this->_query_args = $this->input->get();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // INPUT FUNCTION --------------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a GET request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the GET request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the GET request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function get($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_get_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_get_args[$key]) ? $this->_xss_clean($this->_get_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a OPTIONS request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the OPTIONS request.
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the OPTIONS request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function options($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_options_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_options_args[$key]) ? $this->_xss_clean($this->_options_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a HEAD request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the HEAD request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the HEAD request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function head($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_head_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_head_args[$key]) ? $this->_xss_clean($this->_head_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a POST request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the POST request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the POST request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function post($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_post_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_post_args[$key]) ? $this->_xss_clean($this->_post_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a PUT request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the PUT request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the PUT request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function put($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_put_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_put_args[$key]) ? $this->_xss_clean($this->_put_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a DELETE request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the DELETE request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the DELETE request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function delete($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_delete_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_delete_args[$key]) ? $this->_xss_clean($this->_delete_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from a PATCH request
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the PATCH request
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the PATCH request; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function patch($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_patch_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_patch_args[$key]) ? $this->_xss_clean($this->_patch_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve a value from the query parameters
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @param NULL $key Key to retrieve from the query parameters
							 | 
						|
								     * If NULL an array of arguments is returned
							 | 
						|
								     * @param NULL $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return array|string|NULL Value from the query parameters; otherwise, NULL
							 | 
						|
								     */
							 | 
						|
								    public function query($key = NULL, $xss_clean = NULL)
							 | 
						|
								    {
							 | 
						|
								        if ($key === NULL)
							 | 
						|
								        {
							 | 
						|
								            return $this->_query_args;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return isset($this->_query_args[$key]) ? $this->_xss_clean($this->_query_args[$key], $xss_clean) : NULL;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Sanitizes data so that Cross Site Scripting Hacks can be
							 | 
						|
								     * prevented
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param  string $value Input data
							 | 
						|
								     * @param  bool $xss_clean Whether to apply XSS filtering
							 | 
						|
								     * @return string
							 | 
						|
								     */
							 | 
						|
								    protected function _xss_clean($value, $xss_clean)
							 | 
						|
								    {
							 | 
						|
								        is_bool($xss_clean) || $xss_clean = $this->_enable_xss;
							 | 
						|
								
							 | 
						|
								        return $xss_clean === TRUE ? $this->security->xss_clean($value) : $value;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Retrieve the validation errors
							 | 
						|
								     *
							 | 
						|
								     * @access public
							 | 
						|
								     * @return array
							 | 
						|
								     */
							 | 
						|
								    public function validation_errors()
							 | 
						|
								    {
							 | 
						|
								        $string = strip_tags($this->form_validation->error_string());
							 | 
						|
								
							 | 
						|
								        return explode(PHP_EOL, trim($string, PHP_EOL));
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // SECURITY FUNCTIONS ---------------------------------------------------------
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Perform LDAP Authentication
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param  string $username The username to validate
							 | 
						|
								     * @param  string $password The password to validate
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function _perform_ldap_auth($username = '', $password = NULL)
							 | 
						|
								    {
							 | 
						|
								        if (empty($username))
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', 'LDAP Auth: failure, empty username');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        log_message('debug', 'LDAP Auth: Loading configuration');
							 | 
						|
								
							 | 
						|
								        $this->config->load('ldap.php', TRUE);
							 | 
						|
								
							 | 
						|
								        $ldap = [
							 | 
						|
								            'timeout' => $this->config->item('timeout', 'ldap'),
							 | 
						|
								            'host' => $this->config->item('server', 'ldap'),
							 | 
						|
								            'port' => $this->config->item('port', 'ldap'),
							 | 
						|
								            'rdn' => $this->config->item('binduser', 'ldap'),
							 | 
						|
								            'pass' => $this->config->item('bindpw', 'ldap'),
							 | 
						|
								            'basedn' => $this->config->item('basedn', 'ldap'),
							 | 
						|
								        ];
							 | 
						|
								
							 | 
						|
								        log_message('debug', 'LDAP Auth: Connect to ' . (isset($ldaphost) ? $ldaphost : '[ldap not configured]'));
							 | 
						|
								
							 | 
						|
								        // Connect to the ldap server
							 | 
						|
								        $ldapconn = ldap_connect($ldap['host'], $ldap['port']);
							 | 
						|
								        if ($ldapconn)
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', 'Setting timeout to ' . $ldap['timeout'] . ' seconds');
							 | 
						|
								
							 | 
						|
								            ldap_set_option($ldapconn, LDAP_OPT_NETWORK_TIMEOUT, $ldap['timeout']);
							 | 
						|
								
							 | 
						|
								            log_message('debug', 'LDAP Auth: Binding to ' . $ldap['host'] . ' with dn ' . $ldap['rdn']);
							 | 
						|
								
							 | 
						|
								            // Binding to the ldap server
							 | 
						|
								            $ldapbind = ldap_bind($ldapconn, $ldap['rdn'], $ldap['pass']);
							 | 
						|
								
							 | 
						|
								            // Verify the binding
							 | 
						|
								            if ($ldapbind === FALSE)
							 | 
						|
								            {
							 | 
						|
								                log_message('error', 'LDAP Auth: bind was unsuccessful');
							 | 
						|
								                return FALSE;
							 | 
						|
								            }
							 | 
						|
								
							 | 
						|
								            log_message('debug', 'LDAP Auth: bind successful');
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Search for user
							 | 
						|
								        if (($res_id = ldap_search($ldapconn, $ldap['basedn'], "uid=$username")) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'LDAP Auth: User ' . $username . ' not found in search');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (ldap_count_entries($ldapconn, $res_id) !== 1)
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'LDAP Auth: Failure, username ' . $username . 'found more than once');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (($entry_id = ldap_first_entry($ldapconn, $res_id)) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'LDAP Auth: Failure, entry of search result could not be fetched');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (($user_dn = ldap_get_dn($ldapconn, $entry_id)) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'LDAP Auth: Failure, user-dn could not be fetched');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // User found, could not authenticate as user
							 | 
						|
								        if (($link_id = ldap_bind($ldapconn, $user_dn, $password)) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'LDAP Auth: Failure, username/password did not match: ' . $user_dn);
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        log_message('debug', 'LDAP Auth: Success ' . $user_dn . ' authenticated successfully');
							 | 
						|
								
							 | 
						|
								        $this->_user_ldap_dn = $user_dn;
							 | 
						|
								
							 | 
						|
								        ldap_close($ldapconn);
							 | 
						|
								
							 | 
						|
								        return TRUE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Perform Library Authentication - Override this function to change the way the library is called
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param  string $username The username to validate
							 | 
						|
								     * @param  string $password The password to validate
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function _perform_library_auth($username = '', $password = NULL)
							 | 
						|
								    {
							 | 
						|
								        if (empty($username))
							 | 
						|
								        {
							 | 
						|
								            log_message('error', 'Library Auth: Failure, empty username');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $auth_library_class = strtolower($this->config->item('auth_library_class'));
							 | 
						|
								        $auth_library_function = strtolower($this->config->item('auth_library_function'));
							 | 
						|
								
							 | 
						|
								        if (empty($auth_library_class))
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', 'Library Auth: Failure, empty auth_library_class');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (empty($auth_library_function))
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', 'Library Auth: Failure, empty auth_library_function');
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (is_callable([$auth_library_class, $auth_library_function]) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $this->load->library($auth_library_class);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return $this->{$auth_library_class}->$auth_library_function($username, $password);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check if the user is logged in
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param  string $username The user's name
							 | 
						|
								     * @param  bool|string $password The user's password
							 | 
						|
								     * @return bool
							 | 
						|
								     */
							 | 
						|
								    protected function _check_login($username = NULL, $password = FALSE)
							 | 
						|
								    {
							 | 
						|
								        if (empty($username))
							 | 
						|
								        {
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $auth_source = strtolower($this->config->item('auth_source'));
							 | 
						|
								        $rest_auth = strtolower($this->config->item('rest_auth'));
							 | 
						|
								        $valid_logins = $this->config->item('rest_valid_logins');
							 | 
						|
								
							 | 
						|
								        if (!$this->config->item('auth_source') && $rest_auth === 'digest')
							 | 
						|
								        {
							 | 
						|
								            // For digest we do not have a password passed as argument
							 | 
						|
								            return md5($username . ':' . $this->config->item('rest_realm') . ':' . (isset($valid_logins[$username]) ? $valid_logins[$username] : ''));
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($password === FALSE)
							 | 
						|
								        {
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($auth_source === 'ldap')
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', "Performing LDAP authentication for $username");
							 | 
						|
								
							 | 
						|
								            return $this->_perform_ldap_auth($username, $password);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($auth_source === 'library')
							 | 
						|
								        {
							 | 
						|
								            log_message('debug', "Performing Library authentication for $username");
							 | 
						|
								
							 | 
						|
								            return $this->_perform_library_auth($username, $password);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (array_key_exists($username, $valid_logins) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if ($valid_logins[$username] !== $password)
							 | 
						|
								        {
							 | 
						|
								            return FALSE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        return TRUE;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check to see if the user is logged in with a PHP session key
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _check_php_session()
							 | 
						|
								    {
							 | 
						|
								        // Get the auth_source config item
							 | 
						|
								        $key = $this->config->item('auth_source');
							 | 
						|
								
							 | 
						|
								        // If falsy, then the user isn't logged in
							 | 
						|
								        if (!$this->session->userdata($key))
							 | 
						|
								        {
							 | 
						|
								            // 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_unauthorized')
							 | 
						|
								            ], self::HTTP_UNAUTHORIZED);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Prepares for basic authentication
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _prepare_basic_auth()
							 | 
						|
								    {
							 | 
						|
								        // If whitelist is enabled it has the first chance to kick them out
							 | 
						|
								        if ($this->config->item('rest_ip_whitelist_enabled'))
							 | 
						|
								        {
							 | 
						|
								            $this->_check_whitelist_auth();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Returns NULL if the SERVER variables PHP_AUTH_USER and HTTP_AUTHENTICATION don't exist
							 | 
						|
								        $username = $this->input->server('PHP_AUTH_USER');
							 | 
						|
								        $http_auth = $this->input->server('HTTP_AUTHENTICATION');
							 | 
						|
								
							 | 
						|
								        $password = NULL;
							 | 
						|
								        if ($username !== NULL)
							 | 
						|
								        {
							 | 
						|
								            $password = $this->input->server('PHP_AUTH_PW');
							 | 
						|
								        }
							 | 
						|
								        elseif ($http_auth !== NULL)
							 | 
						|
								        {
							 | 
						|
								            // If the authentication header is set as basic, then extract the username and password from
							 | 
						|
								            // HTTP_AUTHORIZATION e.g. my_username:my_password. This is passed in the .htaccess file
							 | 
						|
								            if (strpos(strtolower($http_auth), 'basic') === 0)
							 | 
						|
								            {
							 | 
						|
								                // Search online for HTTP_AUTHORIZATION workaround to explain what this is doing
							 | 
						|
								                list($username, $password) = explode(':', base64_decode(substr($this->input->server('HTTP_AUTHORIZATION'), 6)));
							 | 
						|
								            }
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Check if the user is logged into the system
							 | 
						|
								        if ($this->_check_login($username, $password) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $this->_force_login();
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Prepares for digest authentication
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _prepare_digest_auth()
							 | 
						|
								    {
							 | 
						|
								        // If whitelist is enabled it has the first chance to kick them out
							 | 
						|
								        if ($this->config->item('rest_ip_whitelist_enabled'))
							 | 
						|
								        {
							 | 
						|
								            $this->_check_whitelist_auth();
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // We need to test which server authentication variable to use,
							 | 
						|
								        // because the PHP ISAPI module in IIS acts different from CGI
							 | 
						|
								        $digest_string = $this->input->server('PHP_AUTH_DIGEST');
							 | 
						|
								        if ($digest_string === NULL)
							 | 
						|
								        {
							 | 
						|
								            $digest_string = $this->input->server('HTTP_AUTHORIZATION');
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $unique_id = uniqid();
							 | 
						|
								
							 | 
						|
								        // The $_SESSION['error_prompted'] variable is used to ask the password
							 | 
						|
								        // again if none given or if the user enters wrong auth information
							 | 
						|
								        if (empty($digest_string))
							 | 
						|
								        {
							 | 
						|
								            $this->_force_login($unique_id);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // We need to retrieve authentication data from the $digest_string variable
							 | 
						|
								        $matches = [];
							 | 
						|
								        preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
							 | 
						|
								        $digest = (empty($matches[1]) || empty($matches[2])) ? [] : array_combine($matches[1], $matches[2]);
							 | 
						|
								
							 | 
						|
								        // For digest authentication the library function should return already stored md5(username:restrealm:password) for that username @see rest.php::auth_library_function config
							 | 
						|
								        $username = $this->_check_login($digest['username'], TRUE);
							 | 
						|
								        if (array_key_exists('username', $digest) === FALSE || $username === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $this->_force_login($unique_id);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        $md5 = md5(strtoupper($this->request->method) . ':' . $digest['uri']);
							 | 
						|
								        $valid_response = md5($username . ':' . $digest['nonce'] . ':' . $digest['nc'] . ':' . $digest['cnonce'] . ':' . $digest['qop'] . ':' . $md5);
							 | 
						|
								
							 | 
						|
								        // Check if the string don't compare (case-insensitive)
							 | 
						|
								        if (strcasecmp($digest['response'], $valid_response) !== 0)
							 | 
						|
								        {
							 | 
						|
								            // 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_invalid_credentials')
							 | 
						|
								            ], self::HTTP_UNAUTHORIZED);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Checks if the client's ip is in the 'rest_ip_blacklist' config and generates a 401 response
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _check_blacklist_auth()
							 | 
						|
								    {
							 | 
						|
								        // Match an ip address in a blacklist e.g. 127.0.0.0, 0.0.0.0
							 | 
						|
								        $pattern = sprintf('/(?:,\s*|^)\Q%s\E(?=,\s*|$)/m', $this->input->ip_address());
							 | 
						|
								
							 | 
						|
								        // Returns 1, 0 or FALSE (on error only). Therefore implicitly convert 1 to TRUE
							 | 
						|
								        if (preg_match($pattern, $this->config->item('rest_ip_blacklist')))
							 | 
						|
								        {
							 | 
						|
								            // 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_ip_denied')
							 | 
						|
								            ], self::HTTP_UNAUTHORIZED);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check if the client's ip is in the 'rest_ip_whitelist' config and generates a 401 response
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _check_whitelist_auth()
							 | 
						|
								    {
							 | 
						|
								        $whitelist = explode(',', $this->config->item('rest_ip_whitelist'));
							 | 
						|
								
							 | 
						|
								        array_push($whitelist, '127.0.0.1', '0.0.0.0');
							 | 
						|
								
							 | 
						|
								        foreach ($whitelist as &$ip)
							 | 
						|
								        {
							 | 
						|
								            // As $ip is a reference, trim leading and trailing whitespace, then store the new value
							 | 
						|
								            // using the reference
							 | 
						|
								            $ip = trim($ip);
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        if (in_array($this->input->ip_address(), $whitelist) === FALSE)
							 | 
						|
								        {
							 | 
						|
								            $this->response([
							 | 
						|
								                $this->config->item('rest_status_field_name') => FALSE,
							 | 
						|
								                $this->config->item('rest_message_field_name') => $this->lang->line('text_rest_ip_unauthorized')
							 | 
						|
								            ], self::HTTP_UNAUTHORIZED);
							 | 
						|
								        }
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Force logging in by setting the WWW-Authenticate header
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @param string $nonce A server-specified data string which should be uniquely generated
							 | 
						|
								     * each time
							 | 
						|
								     * @return void
							 | 
						|
								     */
							 | 
						|
								    protected function _force_login($nonce = '')
							 | 
						|
								    {
							 | 
						|
								        $rest_auth = $this->config->item('rest_auth');
							 | 
						|
								        $rest_realm = $this->config->item('rest_realm');
							 | 
						|
								        if (strtolower($rest_auth) === 'basic')
							 | 
						|
								        {
							 | 
						|
								            // See http://tools.ietf.org/html/rfc2617#page-5
							 | 
						|
								            header('WWW-Authenticate: Basic realm="' . $rest_realm . '"');
							 | 
						|
								        }
							 | 
						|
								        elseif (strtolower($rest_auth) === 'digest')
							 | 
						|
								        {
							 | 
						|
								            // See http://tools.ietf.org/html/rfc2617#page-18
							 | 
						|
								            header(
							 | 
						|
								                'WWW-Authenticate: Digest realm="' . $rest_realm
							 | 
						|
								                . '", qop="auth", nonce="' . $nonce
							 | 
						|
								                . '", opaque="' . md5($rest_realm) . '"');
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // 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_unauthorized')
							 | 
						|
								        ], self::HTTP_UNAUTHORIZED);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Updates the log table with the total access time
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @author Chris Kacerguis
							 | 
						|
								     * @return bool TRUE log table updated; otherwise, FALSE
							 | 
						|
								     */
							 | 
						|
								    protected function _log_access_time()
							 | 
						|
								    {
							 | 
						|
								        $payload['rtime'] = $this->_end_rtime - $this->_start_rtime;
							 | 
						|
								
							 | 
						|
								        return $this->rest->db->update(
							 | 
						|
								            $this->config->item('rest_logs_table'), $payload, [
							 | 
						|
								            'id' => $this->_insert_id
							 | 
						|
								        ]);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Updates the log table with HTTP response code
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @author Justin Chen
							 | 
						|
								     * @param $http_code int HTTP status code
							 | 
						|
								     * @return bool TRUE log table updated; otherwise, FALSE
							 | 
						|
								     */
							 | 
						|
								    protected function _log_response_code($http_code)
							 | 
						|
								    {
							 | 
						|
								        $payload['response_code'] = $http_code;
							 | 
						|
								
							 | 
						|
								        return $this->rest->db->update(
							 | 
						|
								            $this->config->item('rest_logs_table'), $payload, [
							 | 
						|
								            'id' => $this->_insert_id
							 | 
						|
								        ]);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * Check to see if the API key has access to the controller and methods
							 | 
						|
								     *
							 | 
						|
								     * @access protected
							 | 
						|
								     * @return bool TRUE the API key has access; otherwise, FALSE
							 | 
						|
								     */
							 | 
						|
								    protected function _check_access()
							 | 
						|
								    {
							 | 
						|
								        // If we don't want to check access, just return TRUE
							 | 
						|
								        if ($this->config->item('rest_enable_access') === FALSE)
							 | 
						|
								        {
							 | 
						|
								            return TRUE;
							 | 
						|
								        }
							 | 
						|
								
							 | 
						|
								        // Fetch controller based on path and controller name
							 | 
						|
								        $controller = implode(
							 | 
						|
								            '/', [
							 | 
						|
								            $this->router->directory,
							 | 
						|
								            $this->router->class
							 | 
						|
								        ]);
							 | 
						|
								
							 | 
						|
								        // Remove any double slashes for safety
							 | 
						|
								        $controller = str_replace('//', '/', $controller);
							 | 
						|
								
							 | 
						|
								        // Query the access table and get the number of results
							 | 
						|
								        return $this->rest->db
							 | 
						|
								                ->where('key', $this->rest->key)
							 | 
						|
								                ->where('controller', $controller)
							 | 
						|
								                ->get($this->config->item('rest_access_table'))
							 | 
						|
								                ->num_rows() > 0;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								
							 | 
						|
								    /**
							 | 
						|
								     * 에러 리턴
							 | 
						|
								     * @param $message
							 | 
						|
								     * @param int $error_code
							 | 
						|
								     */
							 | 
						|
								    public function error_return( $message, $error_code = 400 )
							 | 
						|
								    {
							 | 
						|
								        $result = array(
							 | 
						|
								            "result" => FALSE,
							 | 
						|
								            "message" => $message
							 | 
						|
								        );
							 | 
						|
								        $this->response($result, $error_code);
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								}
							 |