|
@@ -2,22 +2,19 @@
|
2
|
2
|
|
3
|
3
|
class MySQL_CRUD_API {
|
4
|
4
|
|
5
|
|
- public $method;
|
6
|
|
- public $request;
|
7
|
5
|
public $mysqli;
|
8
|
|
- public $database;
|
9
|
|
- public $whitelist;
|
10
|
|
- public $blacklist;
|
11
|
6
|
|
12
|
|
- private function connectDatabase($hostname,$username,$password,$database) {
|
13
|
|
- $mysqli = new mysqli($hostname,$username,$password,$database);
|
|
7
|
+ protected $config;
|
|
8
|
+
|
|
9
|
+ protected function connectDatabase($hostname,$username,$password,$database,$port,$socket) {
|
|
10
|
+ $mysqli = new mysqli($hostname,$username,$password,$database,$port,$socket);
|
14
|
11
|
if ($mysqli->connect_errno) {
|
15
|
12
|
throw new \Exception('Connect failed: '.$mysqli->connect_error);
|
16
|
13
|
}
|
17
|
14
|
return $mysqli;
|
18
|
15
|
}
|
19
|
16
|
|
20
|
|
- private function mapMethodToAction($method,$request) {
|
|
17
|
+ protected function mapMethodToAction($method,$request) {
|
21
|
18
|
switch ($method) {
|
22
|
19
|
case 'GET': return count($request)>1?'read':'list';
|
23
|
20
|
case 'PUT': return 'update';
|
|
@@ -27,17 +24,17 @@ class MySQL_CRUD_API {
|
27
|
24
|
}
|
28
|
25
|
}
|
29
|
26
|
|
30
|
|
- private function parseRequestParameter($request,$position,$characters,$default) {
|
|
27
|
+ protected function parseRequestParameter($request,$position,$characters,$default) {
|
31
|
28
|
$value = isset($request[$position])?$request[$position]:$default;
|
32
|
29
|
return $characters?preg_replace("/[^$characters]/",'',$value):$value;
|
33
|
30
|
}
|
34
|
31
|
|
35
|
|
- private function parseGetParameter($name,$characters,$default) {
|
36
|
|
- $value = isset($_GET[$name])?$_GET[$name]:$default;
|
|
32
|
+ protected function parseGetParameter($get,$name,$characters,$default) {
|
|
33
|
+ $value = isset($get[$name])?$get[$name]:$default;
|
37
|
34
|
return $characters?preg_replace("/[^$characters]/",'',$value):$value;
|
38
|
35
|
}
|
39
|
36
|
|
40
|
|
- private function applyWhitelist($table,$action,$list) {
|
|
37
|
+ protected function applyWhitelist($table,$action,$list) {
|
41
|
38
|
if ($list===false) return $table;
|
42
|
39
|
$list = array_filter($list, function($actions) use ($action) {
|
43
|
40
|
return strpos($actions,$action[0])!==false;
|
|
@@ -45,7 +42,7 @@ class MySQL_CRUD_API {
|
45
|
42
|
return array_intersect($table, array_keys($list));
|
46
|
43
|
}
|
47
|
44
|
|
48
|
|
- private function applyBlacklist($table,$action,$list) {
|
|
45
|
+ protected function applyBlacklist($table,$action,$list) {
|
49
|
46
|
if ($list===false) return $table;
|
50
|
47
|
$list = array_filter($list, function($actions) use ($action) {
|
51
|
48
|
return strpos($actions,$action[0])!==false;
|
|
@@ -53,14 +50,14 @@ class MySQL_CRUD_API {
|
53
|
50
|
return array_diff($table, array_keys($list));
|
54
|
51
|
}
|
55
|
52
|
|
56
|
|
- private function applyWhitelistAndBlacklist($table, $action, $whitelist, $blacklist) {
|
|
53
|
+ protected function applyWhitelistAndBlacklist($table, $action, $whitelist, $blacklist) {
|
57
|
54
|
$table = $this->applyWhitelist($table, $action, $whitelist);
|
58
|
55
|
$table = $this->applyBlacklist($table, $action, $blacklist);
|
59
|
56
|
if (empty($table)) $this->exitWith404();
|
60
|
57
|
return $table;
|
61
|
58
|
}
|
62
|
59
|
|
63
|
|
- private function processTableParameter($table,$database,$mysqli) {
|
|
60
|
+ protected function processTableParameter($table,$database,$mysqli) {
|
64
|
61
|
$tablelist = explode(',',$table);
|
65
|
62
|
$tables = array();
|
66
|
63
|
foreach ($tablelist as $table) {
|
|
@@ -73,7 +70,7 @@ class MySQL_CRUD_API {
|
73
|
70
|
return $tables;
|
74
|
71
|
}
|
75
|
72
|
|
76
|
|
- private function findPrimaryKey($table,$database,$mysqli) {
|
|
73
|
+ protected function findPrimaryKey($table,$database,$mysqli) {
|
77
|
74
|
$keys = array();
|
78
|
75
|
if ($result = $mysqli->query("SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `COLUMN_KEY` = 'PRI' AND `TABLE_NAME` = '$table[0]' AND `TABLE_SCHEMA` = '$database'")) {
|
79
|
76
|
while ($row = $result->fetch_row()) $keys[] = $row[0];
|
|
@@ -82,7 +79,7 @@ class MySQL_CRUD_API {
|
82
|
79
|
return count($keys)?$keys[0]:false;
|
83
|
80
|
}
|
84
|
81
|
|
85
|
|
- private function exitWith404() {
|
|
82
|
+ protected function exitWith404() {
|
86
|
83
|
if (isset($_SERVER['REQUEST_METHOD'])) {
|
87
|
84
|
die(header("Content-Type:",true,404));
|
88
|
85
|
} else {
|
|
@@ -90,7 +87,7 @@ class MySQL_CRUD_API {
|
90
|
87
|
}
|
91
|
88
|
}
|
92
|
89
|
|
93
|
|
- private function startOutput($callback) {
|
|
90
|
+ protected function startOutput($callback) {
|
94
|
91
|
if (isset($_SERVER['REQUEST_METHOD'])) {
|
95
|
92
|
if ($callback) {
|
96
|
93
|
header("Content-Type: application/javascript");
|
|
@@ -101,13 +98,13 @@ class MySQL_CRUD_API {
|
101
|
98
|
}
|
102
|
99
|
}
|
103
|
100
|
|
104
|
|
- private function endOutput($callback) {
|
|
101
|
+ protected function endOutput($callback) {
|
105
|
102
|
if ($callback) {
|
106
|
103
|
echo ');';
|
107
|
104
|
}
|
108
|
105
|
}
|
109
|
106
|
|
110
|
|
- private function processKeyParameter($key,$table,$database,$mysqli) {
|
|
107
|
+ protected function processKeyParameter($key,$table,$database,$mysqli) {
|
111
|
108
|
if ($key) {
|
112
|
109
|
$key = array($key,$this->findPrimaryKey($table,$database,$mysqli));
|
113
|
110
|
if ($key[1]===false) $this->exitWith404();
|
|
@@ -115,7 +112,7 @@ class MySQL_CRUD_API {
|
115
|
112
|
return $key;
|
116
|
113
|
}
|
117
|
114
|
|
118
|
|
- private function processOrderParameter($order,$table,$database,$mysqli) {
|
|
115
|
+ protected function processOrderParameter($order,$table,$database,$mysqli) {
|
119
|
116
|
if ($order) {
|
120
|
117
|
$order = explode(',',$order,2);
|
121
|
118
|
if (count($order)<2) $order[1]='ASC';
|
|
@@ -124,7 +121,7 @@ class MySQL_CRUD_API {
|
124
|
121
|
return $order;
|
125
|
122
|
}
|
126
|
123
|
|
127
|
|
- private function processFilterParameter($filter,$match,$mysqli) {
|
|
124
|
+ protected function processFilterParameter($filter,$match,$mysqli) {
|
128
|
125
|
if ($filter) {
|
129
|
126
|
$filter = explode(':',$filter,2);
|
130
|
127
|
if (count($filter)==2) {
|
|
@@ -152,7 +149,7 @@ class MySQL_CRUD_API {
|
152
|
149
|
return $filter;
|
153
|
150
|
}
|
154
|
151
|
|
155
|
|
- private function processPageParameter($page) {
|
|
152
|
+ protected function processPageParameter($page) {
|
156
|
153
|
if ($page) {
|
157
|
154
|
$page = explode(',',$page,2);
|
158
|
155
|
if (count($page)<2) $page[1]=20;
|
|
@@ -161,7 +158,7 @@ class MySQL_CRUD_API {
|
161
|
158
|
return $page;
|
162
|
159
|
}
|
163
|
160
|
|
164
|
|
- private function retrieveObject($key,$table,$mysqli) {
|
|
161
|
+ protected function retrieveObject($key,$table,$mysqli) {
|
165
|
162
|
if (!$key) return false;
|
166
|
163
|
if ($result = $mysqli->query("SELECT * FROM `$table[0]` WHERE `$key[1]` = '$key[0]'")) {
|
167
|
164
|
$object = $result->fetch_assoc();
|
|
@@ -170,7 +167,7 @@ class MySQL_CRUD_API {
|
170
|
167
|
return $object;
|
171
|
168
|
}
|
172
|
169
|
|
173
|
|
- private function createObject($input,$table,$mysqli) {
|
|
170
|
+ protected function createObject($input,$table,$mysqli) {
|
174
|
171
|
if (!$input) return false;
|
175
|
172
|
$keys = implode('`,`',array_map(function($v){ return preg_replace('/[^a-zA-Z0-9\-_]/','',$v); },array_keys((array)$input)));
|
176
|
173
|
$values = implode("','",array_map(function($v) use ($mysqli){ return $mysqli->real_escape_string($v); },array_values((array)$input)));
|
|
@@ -178,7 +175,7 @@ class MySQL_CRUD_API {
|
178
|
175
|
return $mysqli->insert_id;
|
179
|
176
|
}
|
180
|
177
|
|
181
|
|
- private function updateObject($key,$input,$table,$mysqli) {
|
|
178
|
+ protected function updateObject($key,$input,$table,$mysqli) {
|
182
|
179
|
if (!$input) return false;
|
183
|
180
|
$sql = "UPDATE `$table[0]` SET ";
|
184
|
181
|
foreach (array_keys((array)$input) as $i=>$k) {
|
|
@@ -191,12 +188,12 @@ class MySQL_CRUD_API {
|
191
|
188
|
return $mysqli->affected_rows;
|
192
|
189
|
}
|
193
|
190
|
|
194
|
|
- private function deleteObject($key,$table,$mysqli) {
|
|
191
|
+ protected function deleteObject($key,$table,$mysqli) {
|
195
|
192
|
$mysqli->query("DELETE FROM `$table[0]` WHERE `$key[1]`='$key[0]'");
|
196
|
193
|
return $mysqli->affected_rows;
|
197
|
194
|
}
|
198
|
195
|
|
199
|
|
- private function findRelations($action,$table,$database,$mysqli) {
|
|
196
|
+ protected function findRelations($action,$table,$database,$mysqli) {
|
200
|
197
|
$collect = array();
|
201
|
198
|
$select = array();
|
202
|
199
|
if (count($table)>1) {
|
|
@@ -255,16 +252,17 @@ class MySQL_CRUD_API {
|
255
|
252
|
return array($collect,$select);
|
256
|
253
|
}
|
257
|
254
|
|
258
|
|
- private function getParameters($method, $request, $database, $whitelist, $blacklist, $mysqli) {
|
|
255
|
+ protected function getParameters($config, $mysqli) {
|
|
256
|
+ extract($config);
|
259
|
257
|
$action = $this->mapMethodToAction($method, $request);
|
260
|
258
|
$table = $this->parseRequestParameter($request, 0, 'a-zA-Z0-9\-_*,', '*');
|
261
|
259
|
$key = $this->parseRequestParameter($request, 1, 'a-zA-Z0-9\-,', false); // auto-increment or uuid
|
262
|
|
- $callback = $this->parseGetParameter('callback', 'a-zA-Z0-9\-_', false);
|
263
|
|
- $page = $this->parseGetParameter('page', '0-9,', false);
|
264
|
|
- $filter = $this->parseGetParameter('filter', false, 'exact');
|
265
|
|
- $match = $this->parseGetParameter('match', 'a-z', false);
|
266
|
|
- $order = $this->parseGetParameter('order', 'a-zA-Z0-9\-_*,', false);
|
267
|
|
- $transform = $this->parseGetParameter('transform', '1', false);
|
|
260
|
+ $callback = $this->parseGetParameter($get, 'callback', 'a-zA-Z0-9\-_', false);
|
|
261
|
+ $page = $this->parseGetParameter($get, 'page', '0-9,', false);
|
|
262
|
+ $filter = $this->parseGetParameter($get, 'filter', false, 'exact');
|
|
263
|
+ $match = $this->parseGetParameter($get, 'match', 'a-z', false);
|
|
264
|
+ $order = $this->parseGetParameter($get, 'order', 'a-zA-Z0-9\-_*,', false);
|
|
265
|
+ $transform = $this->parseGetParameter($get, 'transform', '1', false);
|
268
|
266
|
|
269
|
267
|
$table = $this->processTableParameter($table,$database,$mysqli);
|
270
|
268
|
$key = $this->processKeyParameter($key,$table,$database,$mysqli);
|
|
@@ -275,14 +273,14 @@ class MySQL_CRUD_API {
|
275
|
273
|
$table = $this->applyWhitelistAndBlacklist($table,$action,$whitelist,$blacklist);
|
276
|
274
|
|
277
|
275
|
$object = $this->retrieveObject($key,$table,$mysqli);
|
278
|
|
- $input = json_decode(file_get_contents('php://input'));
|
|
276
|
+ $input = json_decode(file_get_contents($post));
|
279
|
277
|
|
280
|
278
|
list($collect,$select) = $this->findRelations($action,$table,$database,$mysqli);
|
281
|
279
|
|
282
|
280
|
return compact('action','table','key','callback','page','filter','match','order','transform','mysqli','object','input','collect','select');
|
283
|
281
|
}
|
284
|
282
|
|
285
|
|
- private function listCommand($parameters) {
|
|
283
|
+ protected function listCommand($parameters) {
|
286
|
284
|
extract($parameters);
|
287
|
285
|
$this->startOutput($callback);
|
288
|
286
|
echo '{';
|
|
@@ -378,7 +376,7 @@ class MySQL_CRUD_API {
|
378
|
376
|
$this->endOutput($callback);
|
379
|
377
|
}
|
380
|
378
|
|
381
|
|
- private function readCommand($parameters) {
|
|
379
|
+ protected function readCommand($parameters) {
|
382
|
380
|
extract($parameters);
|
383
|
381
|
if (!$object) $this->exitWith404();
|
384
|
382
|
$this->startOutput($callback);
|
|
@@ -386,7 +384,7 @@ class MySQL_CRUD_API {
|
386
|
384
|
$this->endOutput($callback);
|
387
|
385
|
}
|
388
|
386
|
|
389
|
|
- private function createCommand($parameters) {
|
|
387
|
+ protected function createCommand($parameters) {
|
390
|
388
|
extract($parameters);
|
391
|
389
|
if (!$input) $this->exitWith404();
|
392
|
390
|
$this->startOutput($callback);
|
|
@@ -394,7 +392,7 @@ class MySQL_CRUD_API {
|
394
|
392
|
$this->endOutput($callback);
|
395
|
393
|
}
|
396
|
394
|
|
397
|
|
- private function updateCommand($parameters) {
|
|
395
|
+ protected function updateCommand($parameters) {
|
398
|
396
|
extract($parameters);
|
399
|
397
|
if (!$input) $this->exitWith404();
|
400
|
398
|
$this->startOutput($callback);
|
|
@@ -402,14 +400,14 @@ class MySQL_CRUD_API {
|
402
|
400
|
$this->endOutput($callback);
|
403
|
401
|
}
|
404
|
402
|
|
405
|
|
- private function deleteCommand($parameters) {
|
|
403
|
+ protected function deleteCommand($parameters) {
|
406
|
404
|
extract($parameters);
|
407
|
405
|
$this->startOutput($callback);
|
408
|
406
|
echo json_encode($this->deleteObject($key,$table,$mysqli));
|
409
|
407
|
$this->endOutput($callback);
|
410
|
408
|
}
|
411
|
409
|
|
412
|
|
- private function listCommandTransform($parameters) {
|
|
410
|
+ protected function listCommandTransform($parameters) {
|
413
|
411
|
if ($parameters['transform']) {
|
414
|
412
|
ob_start();
|
415
|
413
|
}
|
|
@@ -421,15 +419,33 @@ class MySQL_CRUD_API {
|
421
|
419
|
}
|
422
|
420
|
}
|
423
|
421
|
|
424
|
|
- public function __construct($hostname,$username,$password,$database,$whitelist,$blacklist) {
|
425
|
|
- $this->method = isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:'';
|
426
|
|
- $this->request = explode('/', isset($_SERVER['PATH_INFO'])?trim($_SERVER['PATH_INFO'],'/'):'');
|
427
|
|
- if ($hostname) {
|
428
|
|
- $this->mysqli = $this->connectDatabase($hostname,$username,$password,$database);
|
|
422
|
+ public function __construct($parameters) {
|
|
423
|
+ extract($parameters);
|
|
424
|
+
|
|
425
|
+ $connect = isset($connect)?$connect:true;
|
|
426
|
+
|
|
427
|
+ $hostname = isset($hostname)?$hostname:null;
|
|
428
|
+ $username = isset($username)?$username:'root';
|
|
429
|
+ $password = isset($password)?$password:null;
|
|
430
|
+ $database = isset($database)?$database:'';
|
|
431
|
+ $port = isset($port)?$port:null;
|
|
432
|
+ $socket = isset($socket)?$socket:null;
|
|
433
|
+
|
|
434
|
+ $whitelist = isset($whitelist)?$whitelist:false;
|
|
435
|
+ $blacklist = isset($blacklist)?$blacklist:false;
|
|
436
|
+
|
|
437
|
+ $method = isset($method)?$method:$_SERVER['REQUEST_METHOD'];
|
|
438
|
+ $request = isset($request)?$request:$_SERVER['PATH_INFO'];
|
|
439
|
+ $get = isset($get)?$get:$_GET;
|
|
440
|
+ $post = isset($post)?$post:'php://input';
|
|
441
|
+
|
|
442
|
+ $request = explode('/', trim($request,'/'));
|
|
443
|
+
|
|
444
|
+ if ($connect) {
|
|
445
|
+ $this->mysqli = $this->connectDatabase($hostname,$username,$password,$database,$port,$socket);
|
429
|
446
|
}
|
430
|
|
- $this->database = $database;
|
431
|
|
- $this->whitelist = $whitelist;
|
432
|
|
- $this->blacklist = $blacklist;
|
|
447
|
+
|
|
448
|
+ $this->config = compact('method', 'request', 'get', 'post', 'database', 'whitelist', 'blacklist');
|
433
|
449
|
}
|
434
|
450
|
|
435
|
451
|
public static function mysql_crud_api_transform(&$tables) {
|
|
@@ -466,7 +482,7 @@ class MySQL_CRUD_API {
|
466
|
482
|
}
|
467
|
483
|
|
468
|
484
|
public function executeCommand() {
|
469
|
|
- $parameters = $this->getParameters($this->method, $this->request, $this->database, $this->whitelist, $this->blacklist, $this->mysqli);
|
|
485
|
+ $parameters = $this->getParameters($this->config, $this->mysqli);
|
470
|
486
|
switch($parameters['action']){
|
471
|
487
|
case 'list': $this->listCommandTransform($parameters); break;
|
472
|
488
|
case 'read': $this->readCommand($parameters); break;
|
|
@@ -480,13 +496,10 @@ class MySQL_CRUD_API {
|
480
|
496
|
|
481
|
497
|
// only execute this when running in stand-alone mode
|
482
|
498
|
if(count(get_required_files())<2) {
|
483
|
|
- $api = new MySQL_CRUD_API(
|
484
|
|
- "localhost", // hostname
|
485
|
|
- "user", // username
|
486
|
|
- "pass", // password
|
487
|
|
- "db", // database
|
488
|
|
- false, // whitelist
|
489
|
|
- array("users"=>"crudl") // blacklist
|
490
|
|
- );
|
|
499
|
+ $api = new MySQL_CRUD_API(array(
|
|
500
|
+ 'username'=>'xxx',
|
|
501
|
+ 'password'=>'xxx',
|
|
502
|
+ 'database'=>'xxx'
|
|
503
|
+ ));
|
491
|
504
|
$api->executeCommand();
|
492
|
505
|
}
|