array( 'json', 'xml', 'csv', 'yaml' ) ); /** * Rules to check the route * * @var array * @access private */ private $_rules = array( 'alpha_numeric', 'numeric' ); /** * Select result for api * * @var array */ private $_result = array(); /** * Let the magic start ;) * * @param resource $db * @access public */ public function __construct($db) { $this->_db = $db; } /** * Register new namespace * * @param type $namespace * @todo Set defaults to array * @access public * @return Api */ public function register($namespace) { if( ! isset($this->_namespaces[$namespace]) ) { $this->_namespaces[$namespace] = array( 'key' => false, 'sort' => false, 'request' => false, 'limit' => false, 'cache' => false, 'conditions' => false ); $this->_current_namaspace = $namespace; } else { $this->_error('Namespace already exists.'); } return $this; } /** * * @param string $message * @access private * @todo output * @return Api */ private function _error($message) { header("Content-Type: application/json"); die(json_encode($message)); } /** * Set table name * * @param string $table * @return Api */ public function setTable($table) { if( is_string($table) ) { $this->_namespaces[$this->_current_namaspace]['table'] = $table; } else { $this->_error('Table name musst be a string.'); } return $this; } /** * Set output type * * @access public * @param array|string $output * @return Api */ public function setOutput($output) { if( is_array($output) ) { foreach($output as $o) { if( ! in_array($o, $this->_options['output_types']) ) { $this->_error('Output as '.$o.' is not supported.'); } } $this->_namespaces[$this->_current_namaspace]['output'] = $output; } else { if( ! in_array($output, $this->_options['output_types']) ) { $this->_error('Output as '.$output.' is not supported.'); } $this->_namespaces[$this->_current_namaspace]['output'] = $output; } return $this; } /** * Set if unique key is required (false = default) * * @access public * @param boolean $key * @return Api */ public function setKey($key) { if( is_bool($key) ) { $this->_namespaces[$this->_current_namaspace]['key'] = $key; } return $this; } /** * Set request limit per hour. (false = default) * * @access public * @param integer $limit * @return Api */ public function setLimit($limit) { if( is_integer($limit) ) { $this->_namespaces[$this->_current_namaspace]['limit'] = $limit; } return $this; } // Limit output public function setRequest($request) { if( is_integer($request) ) { $this->_namespaces[$this->_current_namaspace]['request'] = $request; } return $this; } // Sort output public function setSort($sort) { if( is_string($sort) ) { $this->_namespaces[$this->_current_namaspace]['sort'] = $sort; } return $this; } /** * Activate cache * * @param integer $time * @param string $folder * @return Api */ public function setCache($time, $folder) { if( ! is_dir($folder) ) { $this->_error('Cache folder musst be a folder.'); } if( ! is_integer($time) ) { $this->_error('Cache time musst be integer.'); } $this->_namespaces[$this->_current_namaspace]['cache'] = array( 'folder' => $folder, 'time' => $time ); return $this; } /** * Set columns which should be displayed * * @param array $columns * @return Api */ public function setColumns($columns) { if( is_array($columns) ) { $this->_namespaces[$this->_current_namaspace]['columns'] = $columns; } else { $this->_error('Columns musst be given as array.'); } return $this; } /** * Set conditions for data * * @param array $conditions * @return Api */ public function setWhere($conditions) { if( is_array($conditions) ) { $this->_namespaces[$this->_current_namaspace]['conditions'] = $conditions; } else { $this->_error('Where conditions musst be given as array.'); } return $this; } /** * Output data * * @access public * @param arra $route */ public function render($route) { if( ! isset($route['namespace']) || ! isset($this->_namespaces[$route['namespace']]) || strlen($route['namespace']) == 0 ) { $this->_error('No namespace found.'); } $this->_render_namepsace = $route['namespace']; // secure input foreach($route as $key => $value) { $route[strip_tags($key)] = strip_tags($value); } $this->_route_data = $route; // check if connection is working if( ! mysql_ping($this->_db) ) { $this->_error('Database connection is not working.'); } // check if request limit is reached if( ! $this->_check_key() ) { $this->_error('Soory, but your api key is not valid.'); } // check if request limit is reached if( ! $this->_check_request() ) { $this->_error('Soory, you reached the maximum request limit per hour ('.$this->_namespaces[$this->_render_namepsace]['limit'].').'); } // get data from mysql table if( ! $this->_create() ) { $this->_error('Soory, but the system was not able to generate data.'); } } /** * Check if the user key is valid * * @access private * @return boolean */ private function _check_key() { if( $this->_namespaces[$this->_render_namepsace]['key'] == true ) { $result = mysql_query('SELECT id FROM api_keys WHERE hash = "'.mysql_real_escape_string($this->_route_data['key']).'"', $this->_db) or die(mysql_error()); if( mysql_num_rows($result) == false ) { return false; } else { return true; } } else { return true; } } /** * Check if request limit is reached * * @access prviate * @return boolean */ private function _check_request() { if( $this->_namespaces[$this->_render_namepsace]['limit'] != false ) { // check request limit // delete old requests if( $this->_namespaces[$this->_render_namepsace]['key'] == true ) { // request limit with key // delete old requests mysql_query('DELETE FROM api_requests WHERE hash = "'.mysql_real_escape_string($this->_route_data['key']).'" AND ((UNIX_TIMESTAMP() - time) > 3600) AND namespace = "'.$this->_render_namepsace.'"', $this->_db) or die(mysql_error()); // count stored requests $result = mysql_query('SELECT COUNT(time) AS requests FROM api_requests WHERE hash = "'.mysql_real_escape_string($this->_route_data['key']).'" AND ((UNIX_TIMESTAMP() - time) < 3600) AND namespace = "'.$this->_render_namepsace.'"', $this->_db) or die(mysql_error()); $total_requests = mysql_fetch_array($result); if( $total_requests['requests'] >= $this->_namespaces[$this->_render_namepsace]['limit'] ) { // request limit reached return false; } else { // insert new request mysql_query('INSERT INTO api_requests (namespace, hash, ip, time) VALUES("'.$this->_render_namepsace.'", "'.mysql_real_escape_string($this->_route_data['key']).'", "'.$_SERVER['REMOTE_ADDR'].'", "'.time().'")', $this->_db) or die(mysql_error()); return true; } } else { // request limit without key // delete old requests mysql_query('DELETE FROM api_requests WHERE ((UNIX_TIMESTAMP() - time) > 3600) AND namespace = "'.$this->_render_namepsace.'"', $this->_db) or die(mysql_error()); // count stored requests $result = mysql_query('SELECT COUNT(time) AS requests FROM api_requests WHERE ((UNIX_TIMESTAMP() - time) < 3600) AND namespace = "'.$this->_render_namepsace.'"', $this->_db) or die(mysql_error()); $total_requests = mysql_fetch_array($result); if( $total_requests['requests'] >= $this->_namespaces[$this->_render_namepsace]['limit'] ) { // request limit reached return false; } else { // insert new request mysql_query('INSERT INTO api_requests (namespace, ip, time) VALUES("'.$this->_render_namepsace.'", "'.$_SERVER['REMOTE_ADDR'].'", "'.time().'")', $this->_db) or die(mysql_error()); return true; } } } else { // no limit is set return true; } } /** * Array to json * * @access private * @return json */ private function _write_json() { header("Content-Type: application/json"); return json_encode($this->_result); } /** * Array to xml * * @access private * @return string */ private function _write_xml() { header("Content-Type: application/xml"); $xml = "\n"; $xml .= ""; foreach($this->_result as $key => $value) { $xml .= "<{$this->_render_namepsace}>\n"; foreach($value as $k => $d) { $xml .= "<{$k}>{$d}\n"; } $xml .= "_render_namepsace}>\n"; } $xml .= ""; return $xml; } /** * Array to csv * * @access private * @return string */ private function _write_csv() { $lines = array(); foreach ($this->_result as $key => $value) { $lines[] = implode(';', array_filter($value, function($var) { return $var; })); } return implode("\n", $lines); } /** * Array to yaml * * @access private * @return string */ private function _write_yaml() { $yaml = "---\n"; $yaml .= "{$this->_render_namepsace}: \n"; foreach($this->_result as $key => $value) { $yaml .= "-"; $count = 0; foreach($value as $k => $d) { if( $count != 0 ) { $yaml .= " "; } $yaml .= " {$k}: {$d} \n"; $count++; } } return $yaml; } /** * Gets data from database * * @access private */ private function _get() { foreach($this->_namespaces[$this->_render_namepsace]['columns'] as $c) { $columns .= $c.', '; } $sql = 'SELECT '.substr($columns, 0, -2).' FROM ' . $this->_namespaces[$this->_render_namepsace]['table']; if( $this->_namespaces[$this->_render_namepsace]['conditions'] != false ) { $sql .= ' WHERE '; foreach($this->_namespaces[$this->_render_namepsace]['conditions'] as $where => $data) { if( ! isset($this->_route_data[$data['route']]) ) { $this->_error('Route '.$data['route'].' is required.'); } // validate if( isset($data['rule']) ) { if( ! in_array($data['rule'], $this->_rules) ) { $this->_error('Rule '.$data['rule'].' is not avaiable.'); } $rule = '_'.$data['rule']; if( ! $this->$rule($this->_route_data[$data['route']]) ) { $this->_error('Wrong route format.'); } } $sql .= $where.' = "'.mysql_real_escape_string($this->_route_data[$data['route']]).'"'; if( isset($data['connect']) ) { $sql .= ' '.$data['connect']; } } } if( $this->_namespaces[$this->_render_namepsace]['sort'] != false ) { $sql .= ' ORDER BY ' . $this->_namespaces[$this->_render_namepsace]['sort']; } if( $this->_namespaces[$this->_render_namepsace]['request'] != false ) { $sql .= ' LIMIT ' . $this->_namespaces[$this->_render_namepsace]['request']; } $result = mysql_query($sql, $this->_db) or die(mysql_error()); if( mysql_num_rows($result) == false ) { $this->_error('No results found.'); } // write data to a nice array for($i = 0; $i < mysql_num_rows($result); $i++) { $dump[$i] = mysql_fetch_array($result, MYSQL_ASSOC); } $this->_result = $dump; } private function _alpha_numeric($validate) { if( ctype_alnum($validate) ) { return true; } else { return false; } } private function _numeric($validate) { if( ctype_digit($validate) ) { return true; } else { return false; } } private function _create() { if( $this->_namespaces[$this->_render_namepsace]['cache'] == false ) { $this->_get(); } else { // cache is turned on if( $this->_namespaces[$this->_render_namepsace]['key'] == false ) { // key musst truned off $file = $this->_namespaces[$this->_render_namepsace]['cache']['folder'].sha1($this->_render_namepsace).'.txt'; if( ! file_exists($file) || (time() - filemtime($file) > $this->_namespaces[$this->_render_namepsace]['cache']['time']) ) { // write to cache and delete old file @unlink($file); $f = fopen($file, 'w'); $this->_get(); $cache = new stdClass; $cache->result = $this->_result; fwrite($f, serialize($cache)); fclose($f); } // read from cache $data = unserialize(file_get_contents($file)); $this->_result = $data->result; } else { $this->_namespaces[$this->_render_namepsace]['cache'] = false; $this->_create(); } } $type_function = '_write_'; if( is_array($this->_namespaces[$this->_render_namepsace]['output']) ) { if( isset($this->_route_data['output']) ) { $type_function .= $this->_route_data['output']; } else { $type_function .= $this->_namespaces[$this->_render_namepsace]['output'][0]; } } else { $type_function .= $this->_namespaces[$this->_render_namepsace]['output']; } die($this->$type_function()); } } ?>