├── .htaccess ├── README.md ├── config.php ├── index.php └── lib ├── arrest-mysql.php └── db.php /.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine on 3 | RewriteCond %{REQUEST_FILENAME} !-f 4 | RewriteCond %{REQUEST_FILENAME} !-d 5 | RewriteRule ^(.*)$ index.php/$1 [L] 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### This repo is no longer maintained. Development has continued over at [ArrestDB](https://github.com/alixaxel/ArrestDB) 2 | -------------------------------------------------------------------------------- /config.php: -------------------------------------------------------------------------------- 1 | 'localhost', // Usually localhost 5 | 'database' => '', // The database name 6 | 'username' => '', // The database username 7 | 'password' => '', // The database password 8 | 'verbose' => false // If true errors will be shown 9 | ); 10 | 11 | ?> -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | set_table_index('my_table', 'some_index'); 21 | 22 | $arrest->rest(); 23 | 24 | } catch (Exception $e) { 25 | echo $e; 26 | } 27 | 28 | ?> -------------------------------------------------------------------------------- /lib/arrest-mysql.php: -------------------------------------------------------------------------------- 1 | 7 | * $arrest = new ArrestMySQL($db_config); 8 | * $arrest->rest(); 9 | * 10 | * 11 | * Author: Gilbert Pellegrom 12 | * Website: http://dev7studios.com 13 | * Date: Jan 2013 14 | * Version 1.0 15 | */ 16 | require('lib/db.php'); 17 | 18 | class ArrestMySQL { 19 | 20 | /** 21 | * The instance of Database 22 | * 23 | * @var Database 24 | */ 25 | private $db; 26 | /** 27 | * The structure of the database 28 | * 29 | * @var array 30 | */ 31 | private $db_structure; 32 | /** 33 | * The URI segments 34 | * 35 | * @var array 36 | */ 37 | private $segments; 38 | /** 39 | * Array of custom table indexes 40 | * 41 | * @var array 42 | */ 43 | private $table_index; 44 | 45 | /** 46 | * Create an instance, optionally setting a base URI 47 | * 48 | * @param array $db_config An array of database config options. Format: 49 | * 50 | * $db_config = array( 51 | * 'server' => 'localhost', 52 | * 'database' => '', 53 | * 'username' => '', 54 | * 'password' => '', 55 | * 'verbose' => false 56 | * ); 57 | * 58 | * @param string $base_uri Optional base URI if not in root folder 59 | * @access public 60 | */ 61 | public function __construct($db_config, $base_uri = '') 62 | { 63 | $this->db = new Database($db_config); 64 | if(!$this->db->init()) throw new Exception($this->db->get_error()); 65 | 66 | $this->db_structure = $this->map_db($db_config['database']); 67 | $this->segments = $this->get_uri_segments($base_uri); 68 | $this->table_index = array(); 69 | } 70 | 71 | /** 72 | * Handle the REST calls and map them to corresponding CRUD 73 | * 74 | * @access public 75 | */ 76 | public function rest() 77 | { 78 | header('Content-type: application/json'); 79 | /* 80 | create > POST /table 81 | read > GET /table[/id] 82 | update > PUT /table/id 83 | delete > DELETE /table/id 84 | */ 85 | switch ($_SERVER['REQUEST_METHOD']) { 86 | case 'POST': 87 | $this->create(); 88 | break; 89 | case 'GET': 90 | $this->read(); 91 | break; 92 | case 'PUT': 93 | $this->update(); 94 | break; 95 | case 'DELETE': 96 | $this->delete(); 97 | break; 98 | } 99 | } 100 | 101 | /** 102 | * Add a custom index (usually primary key) for a table 103 | * 104 | * @param string $table Name of the table 105 | * @param string $field Name of the index field 106 | * @access public 107 | */ 108 | public function set_table_index($table, $field) 109 | { 110 | $this->table_index[$table] = $field; 111 | } 112 | 113 | /** 114 | * Map the stucture of the MySQL db to an array 115 | * 116 | * @param string $database Name of the database 117 | * @return array Returns array of db structure 118 | * @access private 119 | */ 120 | private function map_db($database) 121 | { 122 | // Map db structure to array 123 | $tables_arr = array(); 124 | $this->db->query('SHOW TABLES FROM '. $database); 125 | while($table = $this->db->fetch_array()){ 126 | if(isset($table['Tables_in_'. $database])){ 127 | $table_name = $table['Tables_in_'. $database]; 128 | $tables_arr[$table_name] = array(); 129 | } 130 | } 131 | foreach($tables_arr as $table_name=>$val){ 132 | $this->db->query('SHOW COLUMNS FROM '. $table_name); 133 | $fields = $this->db->fetch_all(); 134 | $tables_arr[$table_name] = $fields; 135 | } 136 | return $tables_arr; 137 | } 138 | 139 | /** 140 | * Get the URI segments from the URL 141 | * 142 | * @param string $base_uri Optional base URI if not in root folder 143 | * @return array Returns array of URI segments 144 | * @access private 145 | */ 146 | private function get_uri_segments($base_uri) 147 | { 148 | // Fix REQUEST_URI if required 149 | if(!isset($_SERVER['REQUEST_URI'])){ 150 | $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'], 1); 151 | if(isset($_SERVER['QUERY_STRING'])) $_SERVER['REQUEST_URI'] .= '?'. $_SERVER['QUERY_STRING']; 152 | } 153 | 154 | $url = ''; 155 | $request_url = $_SERVER['REQUEST_URI']; 156 | $script_url = $_SERVER['PHP_SELF']; 157 | $request_url = str_replace($base_uri, '', $request_url); 158 | if($request_url != $script_url) $url = trim(preg_replace('/'. str_replace('/', '\/', str_replace('index.php', '', $script_url)) .'/', '', $request_url, 1), '/'); 159 | $url = rtrim(preg_replace('/\?.*/', '', $url), '/'); 160 | 161 | return explode('/', $url); 162 | } 163 | 164 | /** 165 | * Get a URI segment 166 | * 167 | * @param int $index Index of the URI segment 168 | * @return mixed Returns URI segment or false if none exists 169 | * @access private 170 | */ 171 | private function segment($index) 172 | { 173 | if(isset($this->segments[$index])) return $this->segments[$index]; 174 | return false; 175 | } 176 | 177 | /** 178 | * Handles a POST and inserts into the database 179 | * 180 | * @access private 181 | */ 182 | private function create() 183 | { 184 | $table = $this->segment(0); 185 | 186 | if(!$table || !isset($this->db_structure[$table])){ 187 | $error = array('error' => array( 188 | 'message' => 'Not Found', 189 | 'code' => 404 190 | )); 191 | die(json_encode($error)); 192 | } 193 | 194 | if($data = $this->_post()){ 195 | $this->db->insert($table, $data) 196 | ->query(); 197 | $success = array('success' => array( 198 | 'message' => 'Success', 199 | 'code' => 200 200 | )); 201 | die(json_encode($success)); 202 | } else { 203 | $error = array('error' => array( 204 | 'message' => 'No Content', 205 | 'code' => 204 206 | )); 207 | die(json_encode($error)); 208 | } 209 | } 210 | 211 | /** 212 | * Handles a GET and reads from the database 213 | * 214 | * @access private 215 | */ 216 | private function read() 217 | { 218 | $table = $this->segment(0); 219 | $id = intval($this->segment(1)); 220 | 221 | if(!$table || !isset($this->db_structure[$table])){ 222 | $error = array('error' => array( 223 | 'message' => 'Not Found', 224 | 'code' => 404 225 | )); 226 | die(json_encode($error)); 227 | } 228 | 229 | if($id && is_int($id)) { 230 | $index = 'id'; 231 | if(isset($this->table_index[$table])) $index = $this->table_index[$table]; 232 | $this->db->select('*') 233 | ->from($table) 234 | ->where($index, $id) 235 | ->query(); 236 | if($result = $this->db->fetch_array()){ 237 | die(json_encode($result)); 238 | } else { 239 | $error = array('error' => array( 240 | 'message' => 'No Content', 241 | 'code' => 204 242 | )); 243 | die(json_encode($error)); 244 | } 245 | } else { 246 | $this->db->select('*') 247 | ->from($table) 248 | ->order_by($this->_get('order_by'), $this->_get('order')) 249 | ->limit(intval($this->_get('limit')), intval($this->_get('offset'))) 250 | ->query(); 251 | if($result = $this->db->fetch_all()){ 252 | die(json_encode($result)); 253 | } else { 254 | $error = array('error' => array( 255 | 'message' => 'No Content', 256 | 'code' => 204 257 | )); 258 | die(json_encode($error)); 259 | } 260 | } 261 | } 262 | 263 | /** 264 | * Handles a PUT and updates the database 265 | * 266 | * @access private 267 | */ 268 | private function update() 269 | { 270 | $table = $this->segment(0); 271 | $id = intval($this->segment(1)); 272 | 273 | if(!$table || !isset($this->db_structure[$table]) || !$id){ 274 | $error = array('error' => array( 275 | 'message' => 'Not Found', 276 | 'code' => 404 277 | )); 278 | die(json_encode($error)); 279 | } 280 | 281 | $index = 'id'; 282 | if(isset($this->table_index[$table])) $index = $this->table_index[$table]; 283 | $this->db->select('*') 284 | ->from($table) 285 | ->where($index, $id) 286 | ->query(); 287 | if($result = $this->db->fetch_array()){ 288 | $this->db->update($table) 289 | ->set($this->_put()) 290 | ->where($index, $id) 291 | ->query(); 292 | $success = array('success' => array( 293 | 'message' => 'Success', 294 | 'code' => 200 295 | )); 296 | die(json_encode($success)); 297 | } else { 298 | $error = array('error' => array( 299 | 'message' => 'No Content', 300 | 'code' => 204 301 | )); 302 | die(json_encode($error)); 303 | } 304 | } 305 | 306 | /** 307 | * Handles a DELETE and deletes from the database 308 | * 309 | * @access private 310 | */ 311 | private function delete() 312 | { 313 | $table = $this->segment(0); 314 | $id = intval($this->segment(1)); 315 | 316 | if(!$table || !isset($this->db_structure[$table]) || !$id){ 317 | $error = array('error' => array( 318 | 'message' => 'Not Found', 319 | 'code' => 404 320 | )); 321 | die(json_encode($error)); 322 | } 323 | 324 | $index = 'id'; 325 | if(isset($this->table_index[$table])) $index = $this->table_index[$table]; 326 | $this->db->select('*') 327 | ->from($table) 328 | ->where($index, $id) 329 | ->query(); 330 | if($result = $this->db->fetch_array()){ 331 | $this->db->delete($table) 332 | ->where($index, $id) 333 | ->query(); 334 | $success = array('success' => array( 335 | 'message' => 'Success', 336 | 'code' => 200 337 | )); 338 | die(json_encode($success)); 339 | } else { 340 | $error = array('error' => array( 341 | 'message' => 'No Content', 342 | 'code' => 204 343 | )); 344 | die(json_encode($error)); 345 | } 346 | } 347 | 348 | /** 349 | * Helper function to retrieve $_GET variables 350 | * 351 | * @param string $index Optional $_GET index 352 | * @return mixed Returns the $_GET var at the specified index, 353 | * the whole $_GET array or false 354 | * @access private 355 | */ 356 | private function _get($index = '') 357 | { 358 | if($index){ 359 | if(isset($_GET[$index]) && $_GET[$index]) return strip_tags($_GET[$index]); 360 | } else { 361 | if(isset($_GET) && !empty($_GET)) return $_GET; 362 | } 363 | return false; 364 | } 365 | 366 | /** 367 | * Helper function to retrieve $_POST variables 368 | * 369 | * @param string $index Optional $_POST index 370 | * @return mixed Returns the $_POST var at the specified index, 371 | * the whole $_POST array or false 372 | * @access private 373 | */ 374 | private function _post($index = '') 375 | { 376 | if($index){ 377 | if(isset($_POST[$index]) && $_POST[$index]) return $_POST[$index]; 378 | } else { 379 | if(isset($_POST) && !empty($_POST)) return $_POST; 380 | } 381 | return false; 382 | } 383 | 384 | /** 385 | * Helper function to retrieve PUT variables 386 | * 387 | * @return mixed Returns the contents of PUT as an array 388 | * @access private 389 | */ 390 | private function _put() 391 | { 392 | $output = array(); 393 | parse_str(file_get_contents('php://input'), $output); 394 | return $output; 395 | } 396 | 397 | } 398 | 399 | ?> -------------------------------------------------------------------------------- /lib/db.php: -------------------------------------------------------------------------------- 1 | _config = $config; 19 | } 20 | 21 | /* 22 | * Initializes the database. Checks the configuration, connects, selects database. 23 | */ 24 | public function init() { 25 | if(!$this->__check_config()) { 26 | return false; 27 | } 28 | 29 | if(!$this->__connect()) { 30 | return false; 31 | } 32 | 33 | if(!$this->__select_db()) { 34 | return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | /* 41 | * Checks the configuration for blanks. 42 | */ 43 | private function __check_config() { 44 | $config = $this->_config; 45 | 46 | if(empty($config["server"]) || empty($config["username"]) || empty($config["database"])) { 47 | $this->_error = "Configuration details were blank."; 48 | return false; 49 | } 50 | 51 | $this->_verbose = ($config["verbose"]) ? true : false; 52 | 53 | return true; 54 | } 55 | 56 | /* 57 | * Connects to the database. 58 | */ 59 | private function __connect() { 60 | $connection = @mysql_connect($this->_config["server"], $this->_config["username"], $this->_config["password"]); 61 | 62 | if(!$connection) { 63 | $this->_error = ($this->_verbose) ? mysql_error() : "Could not connect to database."; 64 | return false; 65 | } 66 | 67 | return true; 68 | } 69 | 70 | /* 71 | * Selects the database to be working with. 72 | */ 73 | private function __select_db() { 74 | $database = @mysql_select_db($this->_config["database"]); 75 | 76 | if(!$database) { 77 | $this->_error = ($this->_verbose) ? mysql_error() : "Could not select database."; 78 | return false; 79 | } 80 | 81 | return true; 82 | } 83 | 84 | /* 85 | * SELECT starter. $fields can be either a string or an array of strings to select. 86 | */ 87 | public function select($fields) { 88 | $query = "SELECT"; 89 | 90 | if(!empty($fields) && !is_array($fields)) { 91 | $query .= " {$fields}"; 92 | } else if(is_array($fields)) { 93 | $query .= " `"; 94 | $query .= implode("`,`", $fields); 95 | $query .= "`"; 96 | } else { 97 | $query .= " *"; 98 | } 99 | 100 | $this->_buildQuery = $query; 101 | return $this; 102 | } 103 | 104 | /* 105 | * Adds where the SELECT is going to be coming from (table wise). 106 | * select("*") 107 | * select("username") 108 | * select(array("username", "password")) 109 | */ 110 | public function from($table) { 111 | $this->_buildQuery .= " FROM `{$table}`"; 112 | return $this; 113 | } 114 | 115 | /* 116 | * UPDATE starter. 117 | * update("users") 118 | */ 119 | public function update($table) { 120 | $this->_buildQuery = "UPDATE `{$table}`"; 121 | return $this; 122 | } 123 | 124 | /* 125 | * DELETE starter. 126 | * delete("users") 127 | */ 128 | public function delete($table) { 129 | $this->_buildQuery = "DELETE FROM `{$table}`"; 130 | return $this; 131 | } 132 | 133 | /* 134 | * INSERT starter. $data is an array matched columns to values: 135 | * $data = array("username" => "Caleb", "email" => "caleb@mingle-graphics.com"); 136 | * insert("users", array("username" => "Caleb", "password" => "hash")) 137 | */ 138 | public function insert($table, $data) { 139 | $query = "INSERT INTO `{$table}` ("; 140 | $keys = array_keys($data); 141 | $values = array_values($data); 142 | 143 | $query .= implode(", ", $keys); 144 | $query .= ") VALUES ("; 145 | 146 | $array = array(); 147 | 148 | foreach($values as $value) { 149 | $array[] = "'{$value}'"; 150 | } 151 | 152 | $query .= implode(", ", $array) . ")"; 153 | 154 | $this->_buildQuery = $query; 155 | return $this; 156 | } 157 | 158 | /* 159 | * SET. $data is an array matched key => value. 160 | * set(array("username" => "Caleb")) 161 | */ 162 | public function set($data) { 163 | if(!is_array($data)) return $this; 164 | 165 | $query = "SET "; 166 | $array = array(); 167 | 168 | foreach($data as $key => $value) { 169 | $array[] = "`{$key}`='{$value}'"; 170 | } 171 | 172 | $query .= implode(", ", $array); 173 | 174 | $this->_buildQuery .= " " . $query; 175 | return $this; 176 | } 177 | 178 | /* 179 | * WHERE. $fields and $values can either be strings or arrays based on how many you need. 180 | * $operators can be an array to add in <, >, etc. Must match the index for $fields and $values. 181 | * where("username", "Caleb") 182 | * where(array("username", "password"), array("Caleb", "testing")) 183 | * where(array("username", "level"), array("Caleb", "10"), array("=", "<")) 184 | */ 185 | public function where($fields, $values, $operators = '') { 186 | if(!is_array($fields) && !is_array($values)) { 187 | $operator = (empty($operators)) ? '=' : $operators[0]; 188 | $query = " WHERE `{$fields}` {$operator} '{$values}'"; 189 | } else { 190 | $array = array_combine($fields, $values); 191 | $query = " WHERE "; 192 | 193 | $data = array(); 194 | $counter = 0; 195 | 196 | foreach($array as $key => $value) { 197 | 198 | $operator = (!empty($operators) && !empty($operators[$counter])) ? $operators[$counter] : '='; 199 | 200 | $data[] = "`{$key}` {$operator} '{$value}'"; 201 | 202 | $counter++; 203 | } 204 | 205 | $query .= implode(" AND ", $data); 206 | } 207 | 208 | $this->_buildQuery .= $query; 209 | return $this; 210 | } 211 | 212 | /* 213 | * Order By: 214 | * order_by("username", "asc") 215 | */ 216 | public function order_by($field, $direction = 'asc') { 217 | if($field) $this->_buildQuery .= " ORDER BY `{$field}` " . strtoupper($direction); 218 | return $this; 219 | } 220 | 221 | /* 222 | * Limit: 223 | * limit(1) 224 | * limit(1, 0) 225 | */ 226 | public function limit($max, $min = '0') { 227 | if($max) $this->_buildQuery .= " LIMIT {$min},{$max}"; 228 | return $this; 229 | } 230 | 231 | /* 232 | * Will return the object of data from the query. 233 | */ 234 | public function fetch_object() { 235 | $object = @mysql_fetch_object($this->_query); 236 | 237 | if(!$object && $this->_verbose) { 238 | $this->_error = mysql_error(); 239 | } 240 | 241 | return $object; 242 | } 243 | 244 | /* 245 | * Will return the array of data from the query. 246 | */ 247 | public function fetch_array() { 248 | $array = @mysql_fetch_array($this->_query); 249 | if($array){ 250 | foreach($array as $key=>$val){ 251 | if(is_numeric($key)){ 252 | unset($array[$key]); 253 | } 254 | } 255 | } 256 | 257 | if(!$array && $this->_verbose) { 258 | $this->_error = mysql_error(); 259 | } 260 | 261 | return $array; 262 | } 263 | 264 | public function fetch_all() { 265 | $results = array(); 266 | while($array = @mysql_fetch_array($this->_query)){ 267 | foreach($array as $key=>$val){ 268 | if(is_numeric($key)){ 269 | unset($array[$key]); 270 | } 271 | } 272 | $results[] = $array; 273 | } 274 | 275 | 276 | 277 | if(!$array && $this->_verbose) { 278 | $this->_error = mysql_error(); 279 | } 280 | 281 | return $results; 282 | } 283 | 284 | /* 285 | * Will return the number or rows affected from the query. 286 | */ 287 | public function num_rows() { 288 | $num = @mysql_num_rows($this->_query); 289 | 290 | if(!$num && $this->_verbose) { 291 | $this->_error = mysql_error(); 292 | } 293 | 294 | return $num; 295 | } 296 | 297 | /* 298 | * If $query_text is blank, query will be performed on the built query stored. 299 | */ 300 | public function query($query_text = '') { 301 | $query_text = ($query_text == '') ? $this->_buildQuery : $query_text; 302 | 303 | $query = @mysql_query($query_text); 304 | 305 | if(!$query && $this->_verbose) { 306 | echo "

MySQL Error:

"; 307 | echo "

" . mysql_error() . "

"; 308 | } 309 | 310 | $this->_query = $query; 311 | 312 | return $this; 313 | } 314 | 315 | /* 316 | * Will return the current built query story in $this->_buildQuery; 317 | */ 318 | public function get_query() { 319 | return $this->_buildQuery; 320 | } 321 | 322 | /* 323 | * Will return the current stored error. 324 | */ 325 | public function get_error() { 326 | return $this->_error; 327 | } 328 | } 329 | 330 | ?> --------------------------------------------------------------------------------