Guest User

Untitled

a guest
Jun 22nd, 2018
147
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.65 KB | None | 0 0
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2.  
  3. class REST_Controller extends Controller {
  4.  
  5. // Not what you'd think, set this in a controller to use a default format
  6. protected $rest_format = NULL;
  7.  
  8. private $_method;
  9. private $_format;
  10.  
  11. private $_get_args;
  12. private $_put_args;
  13. private $_args;
  14.  
  15. // List all supported methods, the first will be the default format
  16. private $_supported_formats = array(
  17. 'xml' => 'application/xml',
  18. 'rawxml' => 'application/xml',
  19. 'json' => 'application/json',
  20. 'serialize' => 'text/plain',
  21. 'php' => 'text/plain',
  22. 'html' => 'text/html',
  23. 'csv' => 'application/csv'
  24. );
  25.  
  26. // Constructor function
  27. function __construct()
  28. {
  29. parent::Controller();
  30.  
  31. // How is this request being made? POST, DELETE, GET, PUT?
  32. $this->_method = $this->_detect_method();
  33.  
  34. // Lets grab the config and get ready to party
  35. $this->load->config('rest');
  36.  
  37. if($this->config->item('rest_auth') == 'basic')
  38. {
  39. $this->_prepareBasicAuth();
  40. }
  41.  
  42. elseif($this->config->item('rest_auth') == 'digest')
  43. {
  44. $this->_prepareDigestAuth();
  45. }
  46.  
  47. // Set caching based on the REST cache config item
  48. $this->output->cache( $this->config->item('rest_cache') );
  49.  
  50. // Set up our GET variables
  51. $this->_get_args = $this->uri->ruri_to_assoc();
  52.  
  53. // Set up out PUT variables
  54. parse_str(file_get_contents('php://input'), $this->_put_args);
  55.  
  56. // Merge both for one mega-args variable
  57. $this->_args = array_merge($this->_get_args, $this->_put_args);
  58.  
  59. // Which format should the data be returned in?
  60. $this->_format = $this->_detect_format();
  61. }
  62.  
  63. /*
  64. * Remap
  65. *
  66. * Requests are not made to methods directly The request will be for an "object".
  67. * this simply maps the object and method to the correct Controller method.
  68. */
  69. function _remap($object_called)
  70. {
  71. $controller_method = $object_called.'_'.$this->_method;
  72.  
  73. if(method_exists($this, $controller_method))
  74. {
  75. $this->$controller_method();
  76. }
  77.  
  78. else
  79. {
  80. show_404();
  81. }
  82. }
  83.  
  84. /*
  85. * response
  86. *
  87. * Takes pure data and optionally a status code, then creates the response
  88. */
  89. function response($data = '', $http_code = 200)
  90. {
  91. if(empty($data))
  92. {
  93. $this->output->set_status_header(404);
  94. return;
  95. }
  96.  
  97. $this->output->set_status_header($http_code);
  98.  
  99. // If the format method exists, call and return the output in that format
  100. if(method_exists($this, '_'.$this->_format))
  101. {
  102. // Set a XML header
  103. $this->output->set_header('Content-type: '.$this->_supported_formats[$this->_format]);
  104.  
  105. $formatted_data = $this->{'_'.$this->_format}($data);
  106. $this->output->set_output( $formatted_data );
  107. }
  108.  
  109. // Format not supported, output directly
  110. else
  111. {
  112. $this->output->set_output( $data );
  113. }
  114. }
  115.  
  116.  
  117. /*
  118. * Detect format
  119. *
  120. * Detect which format should be used to output the data
  121. */
  122. private function _detect_format()
  123. {
  124. // A format has been passed in the URL and it is supported
  125. if(array_key_exists('format', $this->_args) && array_key_exists($this->_args['format'], $this->_supported_formats))
  126. {
  127. return $this->_args['format'];
  128. }
  129.  
  130. // Otherwise, check the HTTP_ACCEPT (if it exists and we are allowed)
  131. if($this->config->item('rest_ignore_http_accept') === FALSE && $this->input->server('HTTP_ACCEPT'))
  132. {
  133. // Check all formats against the HTTP_ACCEPT header
  134. foreach(array_keys($this->_supported_formats) as $format)
  135. {
  136. // Has this format been requested?
  137. if(strpos($this->input->server('HTTP_ACCEPT'), $format) !== FALSE)
  138. {
  139. // If not HTML or XML assume its right and send it on its way
  140. if($format != 'html' && $format != 'xml')
  141. {
  142.  
  143. return $format;
  144. }
  145.  
  146. // HTML or XML have shown up as a match
  147. else
  148. {
  149. // If it is truely HTML, it wont want any XML
  150. if($format == 'html' && strpos($this->input->server('HTTP_ACCEPT'), 'xml') === FALSE)
  151. {
  152. return $format;
  153. }
  154. // If it is truely XML, it wont want any HTML
  155. elseif($format == 'xml' && strpos($this->input->server('HTTP_ACCEPT'), 'html') === FALSE)
  156. {
  157. return $format;
  158. }
  159. }
  160. }
  161. }
  162.  
  163. } // End HTTP_ACCEPT checking
  164.  
  165. // Well, none of that has worked! Let's see if the controller has a default
  166. if($this->rest_format != NULL)
  167. {
  168. return $this->rest_format;
  169. }
  170.  
  171. // Just use whatever the first supported type is, nothing else is working!
  172. list($default)=array_keys($this->_supported_formats);
  173. return $default;
  174. }
  175.  
  176.  
  177. /*
  178. * Detect method
  179. *
  180. * Detect which method (POST, PUT, GET, DELETE) is being used
  181. */
  182. private function _detect_method()
  183. {
  184. $method = strtolower($this->input->server('REQUEST_METHOD'));
  185. if(in_array($method, array('get', 'delete', 'post', 'put')))
  186. {
  187. return $method;
  188. }
  189.  
  190. return 'get';
  191. }
  192.  
  193.  
  194. // INPUT FUNCTION --------------------------------------------------------------
  195.  
  196. public function get($key)
  197. {
  198. return array_key_exists($key, $this->_get_args) ? $this->input->xss_clean( $this->_get_args[$key] ) : $this->input->get($key) ;
  199. }
  200.  
  201. public function post($key)
  202. {
  203. return $this->input->post($key);
  204. }
  205.  
  206. public function put($key)
  207. {
  208. return array_key_exists($key, $this->_put_args) ? $this->input->xss_clean( $this->_put_args[$key] ) : FALSE ;
  209. }
  210.  
  211. // SECURITY FUNCTIONS ---------------------------------------------------------
  212.  
  213. private function _checkLogin($username = '', $password = NULL)
  214. {
  215. if(empty($username))
  216. {
  217. return FALSE;
  218. }
  219.  
  220. $valid_logins =& $this->config->item('rest_valid_logins');
  221.  
  222. if(!array_key_exists($username, $valid_logins))
  223. {
  224. return FALSE;
  225. }
  226.  
  227. // If actually NULL (not empty string) then do not check it
  228. if($password !== NULL)
  229. {
  230. if($valid_logins[$username] != $password)
  231. {
  232. return FALSE;
  233. }
  234. }
  235.  
  236. return TRUE;
  237. }
  238.  
  239. private function _prepareBasicAuth()
  240. {
  241. $username = NULL;
  242. $password = NULL;
  243.  
  244. // mod_php
  245. if (isset($_SERVER['PHP_AUTH_USER']))
  246. {
  247. $username = $_SERVER['PHP_AUTH_USER'];
  248. $password = $_SERVER['PHP_AUTH_PW'];
  249. }
  250.  
  251. // most other servers
  252. elseif (isset($_SERVER['HTTP_AUTHENTICATION']))
  253. {
  254. if (strpos(strtolower($_SERVER['HTTP_AUTHENTICATION']),'basic')===0)
  255. {
  256. list($username,$password) = explode(':',base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
  257. }
  258. }
  259.  
  260. if ( !$this->_checkLogin($username, $password) )
  261. {
  262. $this->_forceLogin();
  263. }
  264.  
  265. }
  266.  
  267. private function _prepareDigestAuth()
  268. {
  269. $uniqid = uniqid(""); // Empty argument for backward compatibility
  270.  
  271. // We need to test which server authentication variable to use
  272. // because the PHP ISAPI module in IIS acts different from CGI
  273. if(isset($_SERVER['PHP_AUTH_DIGEST']))
  274. {
  275. $digest_string = $_SERVER['PHP_AUTH_DIGEST'];
  276. }
  277. elseif(isset($_SERVER['HTTP_AUTHORIZATION']))
  278. {
  279. $digest_string = $_SERVER['HTTP_AUTHORIZATION'];
  280. }
  281. else
  282. {
  283. $digest_string = "";
  284. }
  285.  
  286. /* The $_SESSION['error_prompted'] variabile is used to ask
  287. the password again if none given or if the user enters
  288. a wrong auth. informations. */
  289. if ( empty($digest_string) )
  290. {
  291. $this->_forceLogin($uniqid);
  292. }
  293.  
  294. // We need to retrieve authentication informations from the $auth_data variable
  295. preg_match_all('@(username|nonce|uri|nc|cnonce|qop|response)=[\'"]?([^\'",]+)@', $digest_string, $matches);
  296. $digest = array_combine($matches[1], $matches[2]);
  297.  
  298. if ( !array_key_exists('username', $digest) || !$this->_checkLogin($digest['username']) )
  299. {
  300. $this->_forceLogin($uniqid);
  301. }
  302.  
  303. $valid_logins =& $this->config->item('rest_valid_logins');
  304. $valid_pass = $valid_logins[$digest['username']];
  305.  
  306. // This is the valid response expected
  307. $A1 = md5($digest['username'] . ':' . $this->config->item('rest_realm') . ':' . $valid_pass);
  308. $A2 = md5(strtoupper($this->_method).':'.$digest['uri']);
  309. $valid_response = md5($A1.':'.$digest['nonce'].':'.$digest['nc'].':'.$digest['cnonce'].':'.$digest['qop'].':'.$A2);
  310.  
  311. if ($digest['response'] != $valid_response)
  312. {
  313. header('HTTP/1.0 401 Unauthorized');
  314. header('HTTP/1.1 401 Unauthorized');
  315. exit;
  316. }
  317.  
  318. }
  319.  
  320.  
  321. private function _forceLogin($nonce = '')
  322. {
  323. header('HTTP/1.0 401 Unauthorized');
  324. header('HTTP/1.1 401 Unauthorized');
  325.  
  326. if($this->config->item('rest_auth') == 'basic')
  327. {
  328. header('WWW-Authenticate: Basic realm="'.$this->config->item('rest_realm').'"');
  329. }
  330.  
  331. elseif($this->config->item('rest_auth') == 'digest')
  332. {
  333. header('WWW-Authenticate: Digest realm="'.$this->config->item('rest_realm'). '" qop="auth" nonce="'.$nonce.'" opaque="'.md5($this->config->item('rest_realm')).'"');
  334. }
  335.  
  336. echo 'Text to send if user hits Cancel button';
  337. die();
  338. }
  339.  
  340. // FORMATING FUNCTIONS ---------------------------------------------------------
  341.  
  342. // Format XML for output
  343. private function _xml($data = array(), $structure = NULL, $basenode = 'xml')
  344. {
  345. // turn off compatibility mode as simple xml throws a wobbly if you don't.
  346. if (ini_get('zend.ze1_compatibility_mode') == 1)
  347. {
  348. ini_set ('zend.ze1_compatibility_mode', 0);
  349. }
  350.  
  351. if ($structure == NULL)
  352. {
  353. $structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
  354. }
  355.  
  356. // loop through the data passed in.
  357. foreach($data as $key => $value)
  358. {
  359. // no numeric keys in our xml please!
  360. if (is_numeric($key))
  361. {
  362. // make string key...
  363. //$key = "item_". (string) $key;
  364. $key = "item";
  365. }
  366.  
  367. // replace anything not alpha numeric
  368. $key = preg_replace('/[^a-z]/i', '', $key);
  369.  
  370. // if there is another array found recrusively call this function
  371. if (is_array($value))
  372. {
  373. $node = $structure->addChild($key);
  374. // recrusive call.
  375. $this->_xml($value, $node, $basenode);
  376. }
  377. else
  378. {
  379. // add single node.
  380.  
  381. $value = htmlentities($value, ENT_NOQUOTES, "UTF-8");
  382.  
  383. $UsedKeys[] = $key;
  384.  
  385. $structure->addChild($key, $value);
  386. }
  387.  
  388. }
  389.  
  390. // pass back as string. or simple xml object if you want!
  391. return $structure->asXML();
  392. }
  393.  
  394.  
  395. // Format Raw XML for output
  396. private function _rawxml($data = array(), $structure = NULL, $basenode = 'xml')
  397. {
  398. // turn off compatibility mode as simple xml throws a wobbly if you don't.
  399. if (ini_get('zend.ze1_compatibility_mode') == 1)
  400. {
  401. ini_set ('zend.ze1_compatibility_mode', 0);
  402. }
  403.  
  404. if ($structure == NULL)
  405. {
  406. $structure = simplexml_load_string("<?xml version='1.0' encoding='utf-8'?><$basenode />");
  407. }
  408.  
  409. // loop through the data passed in.
  410. foreach($data as $key => $value)
  411. {
  412. // no numeric keys in our xml please!
  413. if (is_numeric($key))
  414. {
  415. // make string key...
  416. //$key = "item_". (string) $key;
  417. $key = "item";
  418. }
  419.  
  420. // replace anything not alpha numeric
  421. $key = preg_replace('/[^a-z0-9_-]/i', '', $key);
  422.  
  423. // if there is another array found recrusively call this function
  424. if (is_array($value))
  425. {
  426. $node = $structure->addChild($key);
  427. // recrusive call.
  428. $this->_xml($value, $node, $basenode);
  429. }
  430. else
  431. {
  432. // add single node.
  433.  
  434. $value = htmlentities($value, ENT_NOQUOTES, "UTF-8");
  435.  
  436. $UsedKeys[] = $key;
  437.  
  438. $structure->addChild($key, $value);
  439. }
  440.  
  441. }
  442.  
  443. // pass back as string. or simple xml object if you want!
  444. return $structure->asXML();
  445. }
  446.  
  447. // Format HTML for output
  448. private function _html($data = array())
  449. {
  450. // Multi-dimentional array
  451. if(isset($data[0]))
  452. {
  453. $headings = array_keys($data[0]);
  454. }
  455.  
  456. // Single array
  457. else
  458. {
  459. $headings = array_keys($data);
  460. $data = array($data);
  461. }
  462.  
  463. $this->load->library('table');
  464.  
  465. $this->table->set_heading($headings);
  466.  
  467. foreach($data as &$row)
  468. {
  469. $this->table->add_row($row);
  470. }
  471.  
  472. return $this->table->generate();
  473. }
  474.  
  475. // Format HTML for output
  476. private function _csv($data = array())
  477. {
  478. // Multi-dimentional array
  479. if(isset($data[0]))
  480. {
  481. $headings = array_keys($data[0]);
  482. }
  483.  
  484. // Single array
  485. else
  486. {
  487. $headings = array_keys($data);
  488. $data = array($data);
  489. }
  490.  
  491. $output = implode(',', $headings)."\r\n";
  492. foreach($data as &$row)
  493. {
  494. $output .= '"'.implode('","',$row)."\"\r\n";
  495. }
  496.  
  497. return $output;
  498. }
  499.  
  500. // Encode as JSON
  501. private function _json($data = array())
  502. {
  503. return json_encode($data);
  504. }
  505.  
  506. // Encode as Serialized array
  507. private function _serialize($data = array())
  508. {
  509. return serialize($data);
  510. }
  511.  
  512. // Encode raw PHP
  513. private function _php($data = array())
  514. {
  515. return var_export($data, TRUE);
  516. }
  517.  
  518.  
  519. }
  520. ?>
Add Comment
Please, Sign In to add comment