api de gestion de ticket, basé sur php-crud-api. Le but est de décorrélé les outils de gestion des données, afin
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.

api.php 36KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. <?php
  2. class MySQL_CRUD_API extends REST_CRUD_API {
  3. protected $queries = array(
  4. 'reflect_table'=>'SELECT "TABLE_NAME" FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_NAME" LIKE ? AND "TABLE_SCHEMA" = ?',
  5. 'reflect_pk'=>'SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "COLUMN_KEY" = \'PRI\' AND "TABLE_NAME" = ? AND "TABLE_SCHEMA" = ?',
  6. 'reflect_belongs_to'=>'SELECT
  7. "TABLE_NAME","COLUMN_NAME",
  8. "REFERENCED_TABLE_NAME","REFERENCED_COLUMN_NAME"
  9. FROM
  10. "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE"
  11. WHERE
  12. "TABLE_NAME" = ? AND
  13. "REFERENCED_TABLE_NAME" IN ? AND
  14. "TABLE_SCHEMA" = ? AND
  15. "REFERENCED_TABLE_SCHEMA" = ?',
  16. 'reflect_has_many'=>'SELECT
  17. "TABLE_NAME","COLUMN_NAME",
  18. "REFERENCED_TABLE_NAME","REFERENCED_COLUMN_NAME"
  19. FROM
  20. "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE"
  21. WHERE
  22. "TABLE_NAME" IN ? AND
  23. "REFERENCED_TABLE_NAME" = ? AND
  24. "TABLE_SCHEMA" = ? AND
  25. "REFERENCED_TABLE_SCHEMA" = ?',
  26. 'reflect_habtm'=>'SELECT
  27. k1."TABLE_NAME", k1."COLUMN_NAME",
  28. k1."REFERENCED_TABLE_NAME", k1."REFERENCED_COLUMN_NAME",
  29. k2."TABLE_NAME", k2."COLUMN_NAME",
  30. k2."REFERENCED_TABLE_NAME", k2."REFERENCED_COLUMN_NAME"
  31. FROM
  32. "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" k1, "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" k2
  33. WHERE
  34. k1."TABLE_SCHEMA" = ? AND
  35. k2."TABLE_SCHEMA" = ? AND
  36. k1."REFERENCED_TABLE_SCHEMA" = ? AND
  37. k2."REFERENCED_TABLE_SCHEMA" = ? AND
  38. k1."TABLE_NAME" = k2."TABLE_NAME" AND
  39. k1."REFERENCED_TABLE_NAME" = ? AND
  40. k2."REFERENCED_TABLE_NAME" IN ?'
  41. );
  42. protected function connectDatabase($hostname,$username,$password,$database,$port,$socket,$charset) {
  43. $db = mysqli_connect($hostname,$username,$password,$database,$port,$socket);
  44. if (mysqli_connect_errno()) {
  45. throw new \Exception('Connect failed. '.mysqli_connect_error());
  46. }
  47. if (!mysqli_set_charset($db,$charset)) {
  48. throw new \Exception('Error setting charset. '.mysqli_error($db));
  49. }
  50. if (!mysqli_query($db,'SET SESSION sql_mode = \'ANSI_QUOTES\';')) {
  51. throw new \Exception('Error setting ANSI quotes. '.mysqli_error($db));
  52. }
  53. return $db;
  54. }
  55. protected function query($db,$sql,$params) {
  56. $sql = preg_replace_callback('/\!|\?/', function ($matches) use (&$db,&$params) {
  57. $param = array_shift($params);
  58. if ($matches[0]=='!') return preg_replace('/[^a-zA-Z0-9\-_=<>]/','',$param);
  59. if (is_array($param)) return '('.implode(',',array_map(function($v) use (&$db) {
  60. return "'".mysqli_real_escape_string($db,$v)."'";
  61. },$param)).')';
  62. if (is_object($param) && $param->type=='base64') {
  63. return "x'".bin2hex(base64_decode($param->data))."'";
  64. }
  65. if ($param===null) return 'NULL';
  66. return "'".mysqli_real_escape_string($db,$param)."'";
  67. }, $sql);
  68. //echo "\n$sql\n";
  69. return mysqli_query($db,$sql);
  70. }
  71. protected function fetch_assoc($result) {
  72. return mysqli_fetch_assoc($result);
  73. }
  74. protected function fetch_row($result) {
  75. return mysqli_fetch_row($result);
  76. }
  77. protected function insert_id($db,$result) {
  78. return mysqli_insert_id($db);
  79. }
  80. protected function affected_rows($db,$result) {
  81. return mysqli_affected_rows($db);
  82. }
  83. protected function close($result) {
  84. return mysqli_free_result($result);
  85. }
  86. protected function fetch_fields($result) {
  87. return mysqli_fetch_fields($result);
  88. }
  89. protected function add_limit_to_sql($sql,$limit,$offset) {
  90. return "$sql LIMIT $limit OFFSET $offset";
  91. }
  92. protected function likeEscape($string) {
  93. return addcslashes($string,'%_');
  94. }
  95. protected function is_binary_type($field) {
  96. //echo "$field->name: $field->type ($field->flags)\n";
  97. return (($field->flags & 128) && ($field->type==252));
  98. }
  99. protected function base64_encode($string) {
  100. return base64_encode($string);
  101. }
  102. }
  103. class PgSQL_CRUD_API extends REST_CRUD_API {
  104. protected $queries = array(
  105. 'reflect_table'=>'select "table_name" from "information_schema"."tables" where "table_name" like ? and "table_catalog" = ?',
  106. 'reflect_pk'=>'select
  107. "column_name"
  108. from
  109. "information_schema"."table_constraints" tc, "information_schema"."key_column_usage" ku
  110. where
  111. tc."constraint_type" = \'PRIMARY KEY\' and
  112. tc."constraint_name" = ku."constraint_name" and
  113. ku."table_name" = ? and
  114. ku."table_catalog" = ?',
  115. 'reflect_belongs_to'=>'select
  116. cu1."table_name",cu1."column_name",
  117. cu2."table_name",cu2."column_name"
  118. from
  119. "information_schema".referential_constraints rc,
  120. "information_schema".key_column_usage cu1,
  121. "information_schema".key_column_usage cu2
  122. where
  123. cu1."constraint_name" = rc."constraint_name" and
  124. cu2."constraint_name" = rc."unique_constraint_name" and
  125. cu1."table_name" = ? and
  126. cu2."table_name" in ? and
  127. cu1."table_catalog" = ? and
  128. cu2."table_catalog" = ?',
  129. 'reflect_has_many'=>'select
  130. cu1."table_name",cu1."column_name",
  131. cu2."table_name",cu2."column_name"
  132. from
  133. "information_schema".referential_constraints rc,
  134. "information_schema".key_column_usage cu1,
  135. "information_schema".key_column_usage cu2
  136. where
  137. cu1."constraint_name" = rc."constraint_name" and
  138. cu2."constraint_name" = rc."unique_constraint_name" and
  139. cu1."table_name" in ? and
  140. cu2."table_name" = ? and
  141. cu1."table_catalog" = ? and
  142. cu2."table_catalog" = ?',
  143. 'reflect_habtm'=>'select
  144. cua1."table_name",cua1."column_name",
  145. cua2."table_name",cua2."column_name",
  146. cub1."table_name",cub1."column_name",
  147. cub2."table_name",cub2."column_name"
  148. from
  149. "information_schema".referential_constraints rca,
  150. "information_schema".referential_constraints rcb,
  151. "information_schema".key_column_usage cua1,
  152. "information_schema".key_column_usage cua2,
  153. "information_schema".key_column_usage cub1,
  154. "information_schema".key_column_usage cub2
  155. where
  156. cua1."constraint_name" = rca."constraint_name" and
  157. cua2."constraint_name" = rca."unique_constraint_name" and
  158. cub1."constraint_name" = rcb."constraint_name" and
  159. cub2."constraint_name" = rcb."unique_constraint_name" and
  160. cua1."table_catalog" = ? and
  161. cub1."table_catalog" = ? and
  162. cua2."table_catalog" = ? and
  163. cub2."table_catalog" = ? and
  164. cua1."table_name" = cub1."table_name" and
  165. cua2."table_name" = ? and
  166. cub2."table_name" in ?'
  167. );
  168. protected function connectDatabase($hostname,$username,$password,$database,$port,$socket,$charset) {
  169. $e = function ($v) { return str_replace(array('\'','\\'),array('\\\'','\\\\'),$v); };
  170. $conn_string = '';
  171. if ($hostname || $socket) {
  172. if ($socket) $hostname = $e($socket);
  173. else $hostname = $e($hostname);
  174. $conn_string.= " host='$hostname'";
  175. }
  176. if ($port) {
  177. $port = ($port+0);
  178. $conn_string.= " port='$port'";
  179. }
  180. if ($database) {
  181. $database = $e($database);
  182. $conn_string.= " dbname='$database'";
  183. }
  184. if ($username) {
  185. $username = $e($username);
  186. $conn_string.= " user='$username'";
  187. }
  188. if ($password) {
  189. $password = $e($password);
  190. $conn_string.= " password='$password'";
  191. }
  192. if ($charset) {
  193. $charset = $e($charset);
  194. $conn_string.= " options='--client_encoding=$charset'";
  195. }
  196. $db = pg_connect($conn_string);
  197. return $db;
  198. }
  199. protected function query($db,$sql,$params) {
  200. $sql = preg_replace_callback('/\!|\?/', function ($matches) use (&$db,&$params) {
  201. $param = array_shift($params);
  202. if ($matches[0]=='!') return preg_replace('/[^a-zA-Z0-9\-_=<>]/','',$param);
  203. if (is_array($param)) return '('.implode(',',array_map(function($v) use (&$db) {
  204. return "'".pg_escape_string($db,$v)."'";
  205. },$param)).')';
  206. if (is_object($param) && $param->type=='base64') {
  207. return "'\x".bin2hex(base64_decode($param->data))."'";
  208. }
  209. if ($param===null) return 'NULL';
  210. return "'".pg_escape_string($db,$param)."'";
  211. }, $sql);
  212. if (strtoupper(substr($sql,0,6))=='INSERT') {
  213. $sql .= ' RETURNING id;';
  214. }
  215. //echo "\n$sql\n";
  216. return @pg_query($db,$sql);
  217. }
  218. protected function fetch_assoc($result) {
  219. return pg_fetch_assoc($result);
  220. }
  221. protected function fetch_row($result) {
  222. return pg_fetch_row($result);
  223. }
  224. protected function insert_id($db,$result) {
  225. list($id) = pg_fetch_row($result);
  226. return (int)$id;
  227. }
  228. protected function affected_rows($db,$result) {
  229. return pg_affected_rows($result);
  230. }
  231. protected function close($result) {
  232. return pg_free_result($result);
  233. }
  234. protected function fetch_fields($result) {
  235. $fields = array();
  236. for($i=0;$i<pg_num_fields($result);$i++) {
  237. $field = array();
  238. $field['name'] = pg_field_name($result,$i);
  239. $field['type'] = pg_field_type($result,$i);
  240. $fields[$i] = (object)$field;
  241. }
  242. return $fields;
  243. }
  244. protected function add_limit_to_sql($sql,$limit,$offset) {
  245. return "$sql LIMIT $limit OFFSET $offset";
  246. }
  247. protected function likeEscape($string) {
  248. return addcslashes($string,'%_');
  249. }
  250. protected function is_binary_type($field) {
  251. return $field->type == 'bytea';
  252. }
  253. protected function base64_encode($string) {
  254. return base64_encode(hex2bin(substr($string,2)));
  255. }
  256. }
  257. class MsSQL_CRUD_API extends REST_CRUD_API {
  258. protected $queries = array(
  259. 'reflect_table'=>'SELECT "TABLE_NAME" FROM "INFORMATION_SCHEMA"."TABLES" WHERE "TABLE_NAME" LIKE ? AND "TABLE_CATALOG" = ?',
  260. 'reflect_pk'=>'SELECT
  261. "COLUMN_NAME"
  262. FROM
  263. "INFORMATION_SCHEMA"."TABLE_CONSTRAINTS" tc, "INFORMATION_SCHEMA"."KEY_COLUMN_USAGE" ku
  264. WHERE
  265. tc."CONSTRAINT_TYPE" = \'PRIMARY KEY\' AND
  266. tc."CONSTRAINT_NAME" = ku."CONSTRAINT_NAME" AND
  267. ku."TABLE_NAME" = ? AND
  268. ku."TABLE_CATALOG" = ?',
  269. 'reflect_belongs_to'=>'SELECT
  270. cu1."TABLE_NAME",cu1."COLUMN_NAME",
  271. cu2."TABLE_NAME",cu2."COLUMN_NAME"
  272. FROM
  273. "INFORMATION_SCHEMA".REFERENTIAL_CONSTRAINTS rc,
  274. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cu1,
  275. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cu2
  276. WHERE
  277. cu1."CONSTRAINT_NAME" = rc."CONSTRAINT_NAME" AND
  278. cu2."CONSTRAINT_NAME" = rc."UNIQUE_CONSTRAINT_NAME" AND
  279. cu1."TABLE_NAME" = ? AND
  280. cu2."TABLE_NAME" IN ? AND
  281. cu1."TABLE_CATALOG" = ? AND
  282. cu2."TABLE_CATALOG" = ?',
  283. 'reflect_has_many'=>'SELECT
  284. cu1."TABLE_NAME",cu1."COLUMN_NAME",
  285. cu2."TABLE_NAME",cu2."COLUMN_NAME"
  286. FROM
  287. "INFORMATION_SCHEMA".REFERENTIAL_CONSTRAINTS rc,
  288. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cu1,
  289. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cu2
  290. WHERE
  291. cu1."CONSTRAINT_NAME" = rc."CONSTRAINT_NAME" AND
  292. cu2."CONSTRAINT_NAME" = rc."UNIQUE_CONSTRAINT_NAME" AND
  293. cu1."TABLE_NAME" IN ? AND
  294. cu2."TABLE_NAME" = ? AND
  295. cu1."TABLE_CATALOG" = ? AND
  296. cu2."TABLE_CATALOG" = ?',
  297. 'reflect_habtm'=>'SELECT
  298. cua1."TABLE_NAME",cua1."COLUMN_NAME",
  299. cua2."TABLE_NAME",cua2."COLUMN_NAME",
  300. cub1."TABLE_NAME",cub1."COLUMN_NAME",
  301. cub2."TABLE_NAME",cub2."COLUMN_NAME"
  302. FROM
  303. "INFORMATION_SCHEMA".REFERENTIAL_CONSTRAINTS rca,
  304. "INFORMATION_SCHEMA".REFERENTIAL_CONSTRAINTS rcb,
  305. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cua1,
  306. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cua2,
  307. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cub1,
  308. "INFORMATION_SCHEMA".CONSTRAINT_COLUMN_USAGE cub2
  309. WHERE
  310. cua1."CONSTRAINT_NAME" = rca."CONSTRAINT_NAME" AND
  311. cua2."CONSTRAINT_NAME" = rca."UNIQUE_CONSTRAINT_NAME" AND
  312. cub1."CONSTRAINT_NAME" = rcb."CONSTRAINT_NAME" AND
  313. cub2."CONSTRAINT_NAME" = rcb."UNIQUE_CONSTRAINT_NAME" AND
  314. cua1."TABLE_CATALOG" = ? AND
  315. cub1."TABLE_CATALOG" = ? AND
  316. cua2."TABLE_CATALOG" = ? AND
  317. cub2."TABLE_CATALOG" = ? AND
  318. cua1."TABLE_NAME" = cub1."TABLE_NAME" AND
  319. cua2."TABLE_NAME" = ? AND
  320. cub2."TABLE_NAME" IN ?'
  321. );
  322. protected function connectDatabase($hostname,$username,$password,$database,$port,$socket,$charset) {
  323. $connectionInfo = array();
  324. if ($port) $hostname.=','.$port;
  325. if ($username) $connectionInfo['UID']=$username;
  326. if ($password) $connectionInfo['PWD']=$password;
  327. if ($database) $connectionInfo['Database']=$database;
  328. if ($charset) $connectionInfo['CharacterSet']=$charset;
  329. $connectionInfo['QuotedId']=1;
  330. $connectionInfo['ReturnDatesAsStrings']=1;
  331. $db = sqlsrv_connect($hostname, $connectionInfo);
  332. if (!$db) {
  333. throw new \Exception('Connect failed. '.print_r( sqlsrv_errors(), true));
  334. }
  335. if ($socket) {
  336. throw new \Exception('Socket connection is not supported.');
  337. }
  338. return $db;
  339. }
  340. protected function query($db,$sql,$params) {
  341. $args = array();
  342. $sql = preg_replace_callback('/\!|\?/', function ($matches) use (&$db,&$params,&$args) {
  343. static $i=-1;
  344. $i++;
  345. $param = $params[$i];
  346. if ($matches[0]=='!') {
  347. return preg_replace('/[^a-zA-Z0-9\-_=<>]/','',$param);
  348. }
  349. // This is workaround because SQLSRV cannot accept NULL in a param
  350. if ($matches[0]=='?' && is_null($param)) {
  351. return 'NULL';
  352. }
  353. if (is_array($param)) {
  354. $args = array_merge($args,$param);
  355. return '('.implode(',',str_split(str_repeat('?',count($param)))).')';
  356. }
  357. if (is_object($param)) {
  358. switch($param->type) {
  359. case 'base64':
  360. $args[] = bin2hex(base64_decode($param->data));
  361. return 'CONVERT(VARBINARY(MAX),?,2)';
  362. }
  363. }
  364. $args[] = $param;
  365. return '?';
  366. }, $sql);
  367. //var_dump($params);
  368. //echo "\n$sql\n";
  369. //var_dump($args);
  370. if (strtoupper(substr($sql,0,6))=='INSERT') {
  371. $sql .= ';SELECT SCOPE_IDENTITY()';
  372. }
  373. return sqlsrv_query($db,$sql,$args)?:null;
  374. }
  375. protected function fetch_assoc($result) {
  376. $values = sqlsrv_fetch_array($result, SQLSRV_FETCH_ASSOC);
  377. if ($values) $values = array_map(function($v){ return is_null($v)?null:(string)$v; },$values);
  378. return $values;
  379. }
  380. protected function fetch_row($result) {
  381. $values = sqlsrv_fetch_array($result, SQLSRV_FETCH_NUMERIC);
  382. if ($values) $values = array_map(function($v){ return is_null($v)?null:(string)$v; },$values);
  383. return $values;
  384. }
  385. protected function insert_id($db,$result) {
  386. sqlsrv_next_result($result);
  387. sqlsrv_fetch($result);
  388. return (int)sqlsrv_get_field($result, 0);
  389. }
  390. protected function affected_rows($db,$result) {
  391. return sqlsrv_rows_affected($result);
  392. }
  393. protected function close($result) {
  394. return sqlsrv_free_stmt($result);
  395. }
  396. protected function fetch_fields($result) {
  397. //var_dump(sqlsrv_field_metadata($result));
  398. return array_map(function($a){
  399. $p = array();
  400. foreach ($a as $k=>$v) {
  401. $p[strtolower($k)] = $v;
  402. }
  403. return (object)$p;
  404. },sqlsrv_field_metadata($result));
  405. }
  406. protected function add_limit_to_sql($sql,$limit,$offset) {
  407. return "$sql OFFSET $offset ROWS FETCH NEXT $limit ROWS ONLY";
  408. }
  409. protected function likeEscape($string) {
  410. return str_replace(array('%','_'),array('[%]','[_]'),$string);
  411. }
  412. protected function is_binary_type($field) {
  413. return ($field->type>=-4 && $field->type<=-2);
  414. }
  415. protected function base64_encode($string) {
  416. return base64_encode($string);
  417. }
  418. }
  419. class REST_CRUD_API {
  420. protected $config;
  421. protected function mapMethodToAction($method,$key) {
  422. switch ($method) {
  423. case 'OPTIONS': $this->exitWithCorsHeaders();
  424. case 'GET': return $key?'read':'list';
  425. case 'PUT': return 'update';
  426. case 'POST': return 'create';
  427. case 'DELETE': return 'delete';
  428. default: $this->exitWith404('method');
  429. }
  430. }
  431. protected function parseRequestParameter(&$request,$characters,$default) {
  432. if (!count($request)) return $default;
  433. $value = array_shift($request);
  434. return $characters?preg_replace("/[^$characters]/",'',$value):$value;
  435. }
  436. protected function parseGetParameter($get,$name,$characters,$default) {
  437. $value = isset($get[$name])?$get[$name]:$default;
  438. return $characters?preg_replace("/[^$characters]/",'',$value):$value;
  439. }
  440. protected function parseGetParameterArray($get,$name,$characters,$default) {
  441. $values = isset($get[$name])?$get[$name]:$default;
  442. if (!is_array($values)) $values = array($values);
  443. if ($characters) {
  444. foreach ($values as &$value) {
  445. $value = preg_replace("/[^$characters]/",'',$value);
  446. }
  447. }
  448. return $values;
  449. }
  450. protected function applyTableAuthorizer($callback,$action,$database,&$tables) {
  451. if (is_callable($callback,true)) foreach ($tables as $i=>$table) {
  452. if (!$callback($action,$database,$table)) {
  453. unset($tables[$i]);
  454. }
  455. }
  456. if (empty($tables)) $this->exitWith404('entity');
  457. }
  458. protected function applyColumnAuthorizer($callback,$action,$database,&$columns) {
  459. if (is_callable($callback,true)) foreach ($columns as $table=>$fields) {
  460. foreach ($fields as $field) {
  461. if (!$callback($action,$database,$table,$field->name)) {
  462. unset($columns[$table][$field->name]);
  463. }
  464. }
  465. }
  466. }
  467. protected function applyInputSanitizer($callback,$action,$database,$table,&$input) {
  468. if (is_callable($callback,true)) foreach ((array)$input as $key=>$value) {
  469. $input->$key = $callback($action,$database,$table,$key,$value);
  470. }
  471. }
  472. protected function applyInputValidator($callback,$action,$database,$table,&$input) {
  473. $errors = array();
  474. if (is_callable($callback,true)) foreach ((array)$input as $key=>$value) {
  475. $error = $callback($action,$database,$table,$key,$value);
  476. if ($error!==true) $errors[$key] = $error;
  477. }
  478. if (!empty($errors)) $this->exitWith422($errors);
  479. }
  480. protected function processTableParameter($database,$table,$db) {
  481. if (in_array(strtolower($database), array('information_schema','mysql','sys','pg_catalog'))) return array();
  482. $tablelist = explode(',',$table);
  483. $tables = array();
  484. foreach ($tablelist as $table) {
  485. $table = str_replace('*','%',$table);
  486. if ($result = $this->query($db,$this->queries['reflect_table'],array($table,$database))) {
  487. while ($row = $this->fetch_row($result)) $tables[] = $row[0];
  488. $this->close($result);
  489. }
  490. }
  491. return $tables;
  492. }
  493. protected function findSinglePrimaryKey($table,$database,$db) {
  494. $keys = array();
  495. if ($result = $this->query($db,$this->queries['reflect_pk'],array($table[0],$database))) {
  496. while ($row = $this->fetch_row($result)) $keys[] = $row[0];
  497. $this->close($result);
  498. }
  499. return count($keys)==1?$keys[0]:false;
  500. }
  501. protected function exitWith404($type) {
  502. if (isset($_SERVER['REQUEST_METHOD'])) {
  503. header('Content-Type:',true,404);
  504. die("Not found ($type)");
  505. } else {
  506. throw new \Exception("Not found ($type)");
  507. }
  508. }
  509. protected function exitWith403($object) {
  510. if (isset($_SERVER['REQUEST_METHOD'])) {
  511. header('Content-Type:',true,403);
  512. die('Forbidden');
  513. } else {
  514. throw new \Exception(json_encode($object));
  515. }
  516. }
  517. protected function exitWith409($object) {
  518. if (isset($_SERVER['REQUEST_METHOD'])) {
  519. header('Content-Type:',true,409);
  520. die('Conflict');
  521. } else {
  522. throw new \Exception(json_encode($object));
  523. }
  524. }
  525. protected function exitWith422($object) {
  526. if (isset($_SERVER['REQUEST_METHOD'])) {
  527. header('Content-Type:',true,422);
  528. die(json_encode($object));
  529. } else {
  530. throw new \Exception(json_encode($object));
  531. }
  532. }
  533. protected function exitWithCorsHeaders() {
  534. $headers = array();
  535. $headers[]='Access-Control-Allow-Headers: Content-Type';
  536. $headers[]='Access-Control-Allow-Methods: OPTIONS, GET, PUT, POST, DELETE';
  537. $headers[]='Access-Control-Max-Age: 1728000';
  538. if (isset($_SERVER['REQUEST_METHOD'])) {
  539. foreach ($headers as $header) header($header);
  540. die();
  541. } else {
  542. throw new \Exception(json_encode($headers));
  543. }
  544. }
  545. protected function startOutput($callback) {
  546. if (isset($_SERVER['REQUEST_METHOD'])) {
  547. if ($callback) {
  548. header('Content-Type: application/javascript');
  549. echo $callback.'(';
  550. } else {
  551. header('Content-Type: application/json');
  552. }
  553. }
  554. }
  555. protected function endOutput($callback) {
  556. if ($callback) {
  557. echo ');';
  558. }
  559. }
  560. protected function processKeyParameter($key,$table,$database,$db) {
  561. if ($key) {
  562. $key = array($key,$this->findSinglePrimaryKey($table,$database,$db));
  563. if ($key[1]===false) $this->exitWith404('1pk');
  564. }
  565. return $key;
  566. }
  567. protected function processOrderParameter($order) {
  568. if ($order) {
  569. $order = explode(',',$order,2);
  570. if (count($order)<2) $order[1]='ASC';
  571. $order[1] = strtoupper($order[1])=='DESC'?'DESC':'ASC';
  572. }
  573. return $order;
  574. }
  575. protected function processFilterParameter($filter,$db) {
  576. if ($filter) {
  577. $filter = explode(',',$filter,3);
  578. if (count($filter)==3) {
  579. $match = $filter[1];
  580. $filter[1] = 'LIKE';
  581. if ($match=='cs') $filter[2] = '%'.$this->likeEscape($filter[2]).'%';
  582. if ($match=='sw') $filter[2] = $this->likeEscape($filter[2]).'%';
  583. if ($match=='ew') $filter[2] = '%'.$this->likeEscape($filter[2]);
  584. if ($match=='eq') $filter[1] = '=';
  585. if ($match=='ne') $filter[1] = '<>';
  586. if ($match=='lt') $filter[1] = '<';
  587. if ($match=='le') $filter[1] = '<=';
  588. if ($match=='ge') $filter[1] = '>=';
  589. if ($match=='gt') $filter[1] = '>';
  590. if ($match=='in') {
  591. $filter[1] = 'IN';
  592. $filter[2] = explode(',',$filter[2]);
  593. }
  594. } else {
  595. $filter = false;
  596. }
  597. }
  598. return $filter;
  599. }
  600. protected function processPageParameter($page) {
  601. if ($page) {
  602. $page = explode(',',$page,2);
  603. if (count($page)<2) $page[1]=20;
  604. $page[0] = ($page[0]-1)*$page[1];
  605. }
  606. return $page;
  607. }
  608. protected function retrieveObject($key,$columns,$table,$db) {
  609. if (!$key) return false;
  610. $sql = 'SELECT ';
  611. $sql .= '"'.implode('","',array_keys($columns[$table[0]])).'"';
  612. $sql .= ' FROM "!" WHERE "!" = ?';
  613. if ($result = $this->query($db,$sql,array($table[0],$key[1],$key[0]))) {
  614. $object = $this->fetch_assoc($result);
  615. foreach ($columns[$table[0]] as $field) {
  616. if ($this->is_binary_type($field) && $object[$field->name]) {
  617. $object[$field->name] = $this->base64_encode($object[$field->name]);
  618. }
  619. }
  620. $this->close($result);
  621. }
  622. return $object;
  623. }
  624. protected function createObject($input,$table,$db) {
  625. if (!$input) return false;
  626. $input = (array)$input;
  627. $keys = implode('","',str_split(str_repeat('!', count($input))));
  628. $values = implode(',',str_split(str_repeat('?', count($input))));
  629. $params = array_merge(array_keys($input),array_values($input));
  630. array_unshift($params, $table[0]);
  631. $result = $this->query($db,'INSERT INTO "!" ("'.$keys.'") VALUES ('.$values.')',$params);
  632. if (!$result) return null;
  633. return $this->insert_id($db,$result);
  634. }
  635. protected function updateObject($key,$input,$table,$db) {
  636. if (!$input) return false;
  637. $input = (array)$input;
  638. $params = array();
  639. $sql = 'UPDATE "!" SET ';
  640. $params[] = $table[0];
  641. foreach (array_keys($input) as $i=>$k) {
  642. if ($i) $sql .= ',';
  643. $v = $input[$k];
  644. $sql .= '"!"=?';
  645. $params[] = $k;
  646. $params[] = $v;
  647. }
  648. $sql .= ' WHERE "!"=?';
  649. $params[] = $key[1];
  650. $params[] = $key[0];
  651. $result = $this->query($db,$sql,$params);
  652. return $this->affected_rows($db, $result);
  653. }
  654. protected function deleteObject($key,$table,$db) {
  655. $result = $this->query($db,'DELETE FROM "!" WHERE "!" = ?',array($table[0],$key[1],$key[0]));
  656. return $this->affected_rows($db, $result);
  657. }
  658. protected function findRelations($tables,$database,$db) {
  659. $collect = array();
  660. $select = array();
  661. if (count($tables)>1) {
  662. $table0 = array_shift($tables);
  663. $result = $this->query($db,$this->queries['reflect_belongs_to'],array($table0,$tables,$database,$database));
  664. while ($row = $this->fetch_row($result)) {
  665. $collect[$row[0]][$row[1]]=array();
  666. $select[$row[2]][$row[3]]=array($row[0],$row[1]);
  667. }
  668. $result = $this->query($db,$this->queries['reflect_has_many'],array($tables,$table0,$database,$database));
  669. while ($row = $this->fetch_row($result)) {
  670. $collect[$row[2]][$row[3]]=array();
  671. $select[$row[0]][$row[1]]=array($row[2],$row[3]);
  672. }
  673. $result = $this->query($db,$this->queries['reflect_habtm'],array($database,$database,$database,$database,$table0,$tables));
  674. while ($row = $this->fetch_row($result)) {
  675. $collect[$row[2]][$row[3]]=array();
  676. $select[$row[0]][$row[1]]=array($row[2],$row[3]);
  677. $collect[$row[4]][$row[5]]=array();
  678. $select[$row[6]][$row[7]]=array($row[4],$row[5]);
  679. }
  680. }
  681. return array($collect,$select);
  682. }
  683. protected function retrieveInput($post) {
  684. $input = (object)array();
  685. $data = trim(file_get_contents($post));
  686. if (strlen($data)>0) {
  687. if ($data[0]=='{') {
  688. $input = json_decode($data);
  689. } else {
  690. parse_str($data, $input);
  691. foreach ($input as $key => $value) {
  692. if (substr($key,-9)=='__is_null') {
  693. $input[substr($key,0,-9)] = null;
  694. unset($input[$key]);
  695. }
  696. }
  697. $input = (object)$input;
  698. }
  699. }
  700. return $input;
  701. }
  702. protected function findFields($table,$collect,$select,$columns,$database,$db) {
  703. $tables = array_unique(array_merge($table,array_keys($collect),array_keys($select)));
  704. $fields = array();
  705. foreach ($tables as $i=>$table) {
  706. $fields[$table] = array();
  707. $result = $this->query($db,'SELECT * FROM "!" WHERE 1=2;',array($table));
  708. foreach ($this->fetch_fields($result) as $field) {
  709. if ($i || !$columns || in_array($field->name, $columns)) {
  710. $fields[$table][$field->name] = $field;
  711. }
  712. }
  713. }
  714. return $fields;
  715. }
  716. protected function limitInputFields($input,$fields) {
  717. foreach (array_keys((array)$input) as $key) {
  718. if (!isset($fields[$key])) {
  719. unset($input->$key);
  720. }
  721. }
  722. return $input;
  723. }
  724. protected function convertBinary($input,$fields) {
  725. foreach ($fields as $key=>$field) {
  726. if (isset($input->$key) && $input->$key && $this->is_binary_type($field)) {
  727. $data = $input->$key;
  728. $data = str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT);
  729. $input->$key = (object)array('type'=>'base64','data'=>$data);
  730. }
  731. }
  732. return $input;
  733. }
  734. protected function getParameters($config) {
  735. extract($config);
  736. $table = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_*,', false);
  737. $key = $this->parseRequestParameter($request, 'a-zA-Z0-9\-,', false); // auto-increment or uuid
  738. $action = $this->mapMethodToAction($method,$key);
  739. $callback = $this->parseGetParameter($get, 'callback', 'a-zA-Z0-9\-_', false);
  740. $page = $this->parseGetParameter($get, 'page', '0-9,', false);
  741. $filters = $this->parseGetParameterArray($get, 'filter', false, false);
  742. $satisfy = $this->parseGetParameter($get, 'satisfy', 'a-z', 'all');
  743. $columns = $this->parseGetParameter($get, 'columns', 'a-zA-Z0-9\-_,', false);
  744. $order = $this->parseGetParameter($get, 'order', 'a-zA-Z0-9\-_*,', false);
  745. $transform = $this->parseGetParameter($get, 'transform', '1', false);
  746. $table = $this->processTableParameter($database,$table,$db);
  747. $key = $this->processKeyParameter($key,$table,$database,$db);
  748. foreach ($filters as &$filter) $filter = $this->processFilterParameter($filter,$db);
  749. if ($columns) $columns = explode(',',$columns);
  750. $page = $this->processPageParameter($page);
  751. $order = $this->processOrderParameter($order);
  752. if (empty($table)) $this->exitWith404('entity');
  753. // reflection
  754. list($collect,$select) = $this->findRelations($table,$database,$db);
  755. $columns = $this->findFields($table,$collect,$select,$columns,$database,$db);
  756. // input
  757. $input = $this->retrieveInput($post);
  758. if ($callbacks['input_sanitizer']) $this->applyInputSanitizer($callbacks['input_sanitizer'],$action,$database,$table[0],$input);
  759. if ($callbacks['input_validator']) $this->applyInputValidator($callbacks['input_validator'],$action,$database,$table[0],$input);
  760. // permissions
  761. if ($callbacks['table_authorizer']) $this->applyTableAuthorizer($callbacks['table_authorizer'],$action,$database,$table);
  762. if ($callbacks['column_authorizer']) $this->applyColumnAuthorizer($callbacks['column_authorizer'],$action,$database,$columns);
  763. // conversion
  764. if (!empty($input)) $input = $this->limitInputFields($input,$columns[$table[0]]);
  765. if (!empty($input)) $input = $this->convertBinary($input,$columns[$table[0]]);
  766. return compact('action','database','table','key','callback','page','filters','satisfy','columns','order','transform','db','input','collect','select');
  767. }
  768. protected function listCommand($parameters) {
  769. extract($parameters);
  770. $this->startOutput($callback);
  771. echo '{';
  772. $tables = $table;
  773. $table = array_shift($tables);
  774. // first table
  775. $count = false;
  776. echo '"'.$table.'":{';
  777. if (is_array($order) && is_array($page)) {
  778. $params = array();
  779. $sql = 'SELECT COUNT(*) FROM "!"';
  780. $params[] = $table;
  781. foreach ($filters as $i=>$filter) {
  782. if (is_array($filter)) {
  783. $sql .= $i==0?' WHERE ':($satisfy=='all'?' AND ':' OR ');
  784. $sql .= '"!" ! ?';
  785. $params[] = $filter[0];
  786. $params[] = $filter[1];
  787. $params[] = $filter[2];
  788. }
  789. }
  790. if ($result = $this->query($db,$sql,$params)) {
  791. while ($pages = $this->fetch_row($result)) {
  792. $count = $pages[0];
  793. }
  794. }
  795. }
  796. $params = array();
  797. $sql = 'SELECT ';
  798. $sql .= '"'.implode('","',array_keys($columns[$table])).'"';
  799. $sql .= ' FROM "!"';
  800. $params[] = $table;
  801. foreach ($filters as $i=>$filter) {
  802. if (is_array($filter)) {
  803. $sql .= $i==0?' WHERE ':($satisfy=='all'?' AND ':' OR ');
  804. $sql .= '"!" ! ?';
  805. $params[] = $filter[0];
  806. $params[] = $filter[1];
  807. $params[] = $filter[2];
  808. }
  809. }
  810. if (is_array($order)) {
  811. $sql .= ' ORDER BY "!" !';
  812. $params[] = $order[0];
  813. $params[] = $order[1];
  814. }
  815. if (is_array($order) && is_array($page)) {
  816. $sql = $this->add_limit_to_sql($sql,$page[1],$page[0]);
  817. }
  818. if ($result = $this->query($db,$sql,$params)) {
  819. echo '"columns":';
  820. $fields = array();
  821. $base64 = array();
  822. foreach ($columns[$table] as $field) {
  823. $base64[] = $this->is_binary_type($field);
  824. $fields[] = $field->name;
  825. }
  826. echo json_encode($fields);
  827. $fields = array_flip($fields);
  828. echo ',"records":[';
  829. $first_row = true;
  830. while ($row = $this->fetch_row($result)) {
  831. if ($first_row) $first_row = false;
  832. else echo ',';
  833. if (isset($collect[$table])) {
  834. foreach (array_keys($collect[$table]) as $field) {
  835. $collect[$table][$field][] = $row[$fields[$field]];
  836. }
  837. }
  838. foreach ($base64 as $k=>$v) {
  839. if ($v && $row[$k]) {
  840. $row[$k] = $this->base64_encode($row[$k]);
  841. }
  842. }
  843. echo json_encode($row);
  844. }
  845. $this->close($result);
  846. echo ']';
  847. if ($count) echo ',';
  848. }
  849. if ($count) echo '"results":'.$count;
  850. echo '}';
  851. // prepare for other tables
  852. foreach (array_keys($collect) as $t) {
  853. if ($t!=$table && !in_array($t,$tables)) {
  854. array_unshift($tables,$t);
  855. }
  856. }
  857. // other tables
  858. foreach ($tables as $t=>$table) {
  859. echo ',';
  860. echo '"'.$table.'":{';
  861. $params = array();
  862. $sql = 'SELECT ';
  863. $sql .= '"'.implode('","',array_keys($columns[$table])).'"';
  864. $sql .= ' FROM "!"';
  865. $params[] = $table;
  866. if (isset($select[$table])) {
  867. $first_row = true;
  868. echo '"relations":{';
  869. foreach ($select[$table] as $field => $path) {
  870. $values = $collect[$path[0]][$path[1]];
  871. $sql .= $first_row?' WHERE ':' OR ';
  872. $sql .= '"!" IN ?';
  873. $params[] = $field;
  874. $params[] = $values;
  875. if ($first_row) $first_row = false;
  876. else echo ',';
  877. echo '"'.$field.'":"'.implode('.',$path).'"';
  878. }
  879. echo '}';
  880. }
  881. if ($result = $this->query($db,$sql,$params)) {
  882. if (isset($select[$table])) echo ',';
  883. echo '"columns":';
  884. $fields = array();
  885. $base64 = array();
  886. foreach ($columns[$table] as $field) {
  887. $base64[] = $this->is_binary_type($field);
  888. $fields[] = $field->name;
  889. }
  890. echo json_encode($fields);
  891. $fields = array_flip($fields);
  892. echo ',"records":[';
  893. $first_row = true;
  894. while ($row = $this->fetch_row($result)) {
  895. if ($first_row) $first_row = false;
  896. else echo ',';
  897. if (isset($collect[$table])) {
  898. foreach (array_keys($collect[$table]) as $field) {
  899. $collect[$table][$field][]=$row[$fields[$field]];
  900. }
  901. }
  902. foreach ($base64 as $k=>$v) {
  903. if ($v && $row[$k]) {
  904. $row[$k] = $this->base64_encode($row[$k]);
  905. }
  906. }
  907. echo json_encode($row);
  908. }
  909. $this->close($result);
  910. echo ']';
  911. }
  912. echo '}';
  913. }
  914. echo '}';
  915. $this->endOutput($callback);
  916. }
  917. protected function readCommand($parameters) {
  918. extract($parameters);
  919. $object = $this->retrieveObject($key,$columns,$table,$db);
  920. if (!$object) $this->exitWith404('object');
  921. $this->startOutput($callback);
  922. echo json_encode($object);
  923. $this->endOutput($callback);
  924. }
  925. protected function createCommand($parameters) {
  926. extract($parameters);
  927. if (!$input) $this->exitWith404('input');
  928. $this->startOutput($callback);
  929. echo json_encode($this->createObject($input,$table,$db));
  930. $this->endOutput($callback);
  931. }
  932. protected function updateCommand($parameters) {
  933. extract($parameters);
  934. if (!$input) $this->exitWith404('subject');
  935. $this->startOutput($callback);
  936. echo json_encode($this->updateObject($key,$input,$table,$db));
  937. $this->endOutput($callback);
  938. }
  939. protected function deleteCommand($parameters) {
  940. extract($parameters);
  941. $this->startOutput($callback);
  942. echo json_encode($this->deleteObject($key,$table,$db));
  943. $this->endOutput($callback);
  944. }
  945. protected function listCommandTransform($parameters) {
  946. if ($parameters['transform']) {
  947. ob_start();
  948. }
  949. $this->listCommand($parameters);
  950. if ($parameters['transform']) {
  951. $content = ob_get_contents();
  952. ob_end_clean();
  953. $data = json_decode($content,true);
  954. echo json_encode(self::php_crud_api_transform($data));
  955. }
  956. }
  957. public function __construct($config) {
  958. extract($config);
  959. $hostname = isset($hostname)?$hostname:null;
  960. $username = isset($username)?$username:'root';
  961. $password = isset($password)?$password:null;
  962. $database = isset($database)?$database:false;
  963. $port = isset($port)?$port:null;
  964. $socket = isset($socket)?$socket:null;
  965. $charset = isset($charset)?$charset:'utf8';
  966. $callbacks['table_authorizer'] = isset($table_authorizer)?$table_authorizer:false;
  967. $callbacks['column_authorizer'] = isset($column_authorizer)?$column_authorizer:false;
  968. $callbacks['input_sanitizer'] = isset($input_sanitizer)?$input_sanitizer:false;
  969. $callbacks['input_validator'] = isset($input_validator)?$input_validator:false;
  970. $db = isset($db)?$db:null;
  971. $method = isset($method)?$method:$_SERVER['REQUEST_METHOD'];
  972. $request = isset($request)?$request:(isset($_SERVER['PATH_INFO'])?$_SERVER['PATH_INFO']:'');
  973. $get = isset($get)?$get:$_GET;
  974. $post = isset($post)?$post:'php://input';
  975. $request = explode('/', trim($request,'/'));
  976. $multidb = !$database;
  977. if ($multidb) {
  978. $database = $this->parseRequestParameter($request, 'a-zA-Z0-9\-_,', false);
  979. }
  980. if (!$db) {
  981. $db = $this->connectDatabase($hostname,$username,$password,$database,$port,$socket,$charset);
  982. }
  983. $this->config = compact('method', 'request', 'get', 'post', 'multidb', 'database', 'callbacks', 'db');
  984. }
  985. public static function php_crud_api_transform(&$tables) {
  986. $get_objects = function (&$tables,$table_name,$where_index=false,$match_value=false) use (&$get_objects) {
  987. $objects = array();
  988. foreach ($tables[$table_name]['records'] as $record) {
  989. if ($where_index===false || $record[$where_index]==$match_value) {
  990. $object = array();
  991. foreach ($tables[$table_name]['columns'] as $index=>$column) {
  992. $object[$column] = $record[$index];
  993. foreach ($tables as $relation=>$reltable) {
  994. if (isset($reltable['relations'])) {
  995. foreach ($reltable['relations'] as $key=>$target) {
  996. if ($target == "$table_name.$column") {
  997. $column_indices = array_flip($reltable['columns']);
  998. $object[$relation] = $get_objects($tables,$relation,$column_indices[$key],$record[$index]);
  999. }
  1000. }
  1001. }
  1002. }
  1003. }
  1004. $objects[] = $object;
  1005. }
  1006. }
  1007. return $objects;
  1008. };
  1009. $tree = array();
  1010. foreach ($tables as $name=>$table) {
  1011. if (!isset($table['relations'])) {
  1012. $tree[$name] = $get_objects($tables,$name);
  1013. if (isset($table['results'])) {
  1014. $tree['_results'] = $table['results'];
  1015. }
  1016. }
  1017. }
  1018. return $tree;
  1019. }
  1020. public function executeCommand() {
  1021. if (isset($_SERVER['REQUEST_METHOD'])) {
  1022. header('Access-Control-Allow-Origin: *');
  1023. }
  1024. $parameters = $this->getParameters($this->config);
  1025. switch($parameters['action']){
  1026. case 'list': $this->listCommandTransform($parameters); break;
  1027. case 'read': $this->readCommand($parameters); break;
  1028. case 'create': $this->createCommand($parameters); break;
  1029. case 'update': $this->updateCommand($parameters); break;
  1030. case 'delete': $this->deleteCommand($parameters); break;
  1031. }
  1032. }
  1033. }
  1034. // uncomment the lines below when running in stand-alone mode:
  1035. // $api = new MySQL_CRUD_API(array(
  1036. // 'hostname'=>'localhost',
  1037. // 'username'=>'xxx',
  1038. // 'password'=>'xxx',
  1039. // 'database'=>'xxx',
  1040. // 'charset'=>'utf8'
  1041. // ));
  1042. // $api->executeCommand();
  1043. // For Microsoft SQL Server use:
  1044. // $api = new MsSQL_CRUD_API(array(
  1045. // 'hostname'=>'(local)',
  1046. // 'username'=>'',
  1047. // 'password'=>'',
  1048. // 'database'=>'xxx',
  1049. // 'charset'=>'UTF-8'
  1050. // ));
  1051. // $api->executeCommand();
  1052. // For PostgreSQL use:
  1053. // $api = new PgSQL_CRUD_API(array(
  1054. // 'hostname'=>'localhost',
  1055. // 'username'=>'xxx',
  1056. // 'password'=>'xxx',
  1057. // 'database'=>'xxx',
  1058. // 'charset'=>'UTF8'
  1059. // ));
  1060. // $api->executeCommand();