class.db.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083
  1. <?php
  2. /*
  3. // create instance protocol://user:pass@host/db?charset=UTF8&persist=TRUE&timezone=Europe/Sofia
  4. $db = DB::get('mysqli://root@127.0.0.1/test');
  5. $db = DB::get('oracle://root:pass@VIRT/?charset=AL32UTF8');
  6. // execute a non-resulting query (returns boolean true)
  7. $db->query('UPDATE table SET value = 1 WHERE id = ?', array(1));
  8. // get all results as array
  9. $db->all('SELECT * FROM table WHERE id = ?', array(1), "array_key", bool_skip_key, "assoc"/"num");
  10. // get one result
  11. $db->one('SELECT * FROM table WHERE id = ?', array(1), "assoc"/"num");
  12. // get a traversable object to pass to foreach, or use count(), or use direct access: [INDEX]
  13. $db->get('SELECT * FROM table WHERE id = ?', array(1), "assoc"/"num")[1];
  14. */
  15. namespace
  16. {
  17. class db
  18. {
  19. private function __construct() {
  20. }
  21. public function __clone() {
  22. throw new \vakata\database\Exception('Cannot clone static DB');
  23. }
  24. public static function get($settings = null) {
  25. return new \vakata\database\DBC($settings);
  26. }
  27. public static function getc($settings = null, \vakata\cache\ICache $c = null) {
  28. if($c === null) { $c = \vakata\cache\cache::inst(); }
  29. return new \vakata\database\DBCCached($settings, $c);
  30. }
  31. }
  32. }
  33. namespace vakata\database
  34. {
  35. class Exception extends \Exception
  36. {
  37. }
  38. class Settings
  39. {
  40. public $type = null;
  41. public $username = 'root';
  42. public $password = null;
  43. public $database = null;
  44. public $servername = 'localhost';
  45. public $serverport = null;
  46. public $persist = false;
  47. public $timezone = null;
  48. public $charset = 'UTF8';
  49. public function __construct($settings) {
  50. $str = parse_url($settings);
  51. if(!$str) {
  52. throw new Exception('Malformed DB settings string: ' . $settings);
  53. }
  54. if(array_key_exists('scheme',$str)) {
  55. $this->type = rawurldecode($str['scheme']);
  56. }
  57. if(array_key_exists('user',$str)) {
  58. $this->username = rawurldecode($str['user']);
  59. }
  60. if(array_key_exists('pass',$str)) {
  61. $this->password = rawurldecode($str['pass']);
  62. }
  63. if(array_key_exists('path',$str)) {
  64. $this->database = trim(rawurldecode($str['path']),'/');
  65. }
  66. if(array_key_exists('host',$str)) {
  67. $this->servername = rawurldecode($str['host']);
  68. }
  69. if(array_key_exists('port',$str)) {
  70. $this->serverport = rawurldecode($str['port']);
  71. }
  72. if(array_key_exists('query',$str)) {
  73. parse_str($str['query'], $str);
  74. $this->persist = (array_key_exists('persist', $str) && $str['persist'] === 'TRUE');
  75. if(array_key_exists('charset', $str)) {
  76. $this->charset = $str['charset'];
  77. }
  78. if(array_key_exists('timezone', $str)) {
  79. $this->timezone = $str['timezone'];
  80. }
  81. }
  82. }
  83. }
  84. interface IDB
  85. {
  86. public function connect();
  87. public function query($sql, $vars);
  88. public function get($sql, $data, $key, $skip_key, $mode);
  89. public function all($sql, $data, $key, $skip_key, $mode);
  90. public function one($sql, $data, $mode);
  91. public function raw($sql);
  92. public function prepare($sql);
  93. public function execute($data);
  94. public function disconnect();
  95. }
  96. interface IDriver
  97. {
  98. public function prepare($sql);
  99. public function execute($data);
  100. public function query($sql, $data);
  101. public function nextr($result);
  102. public function seek($result, $row);
  103. public function nf($result);
  104. public function af();
  105. public function insert_id();
  106. public function real_query($sql);
  107. public function get_settings();
  108. }
  109. abstract class ADriver implements IDriver
  110. {
  111. protected $lnk = null;
  112. protected $settings = null;
  113. public function __construct(Settings $settings) {
  114. $this->settings = $settings;
  115. }
  116. public function __destruct() {
  117. if($this->is_connected()) {
  118. $this->disconnect();
  119. }
  120. }
  121. public function get_settings() {
  122. return $this->settings;
  123. }
  124. public function connect() {
  125. }
  126. public function is_connected() {
  127. return $this->lnk !== null;
  128. }
  129. public function disconnect() {
  130. }
  131. public function query($sql, $data = array()) {
  132. return $this->execute($this->prepare($sql), $data);
  133. }
  134. public function prepare($sql) {
  135. if(!$this->is_connected()) { $this->connect(); }
  136. return $sql;
  137. }
  138. public function execute($sql, $data = array()) {
  139. if(!$this->is_connected()) { $this->connect(); }
  140. if(!is_array($data)) { $data = array(); }
  141. $binder = '?';
  142. if(strpos($sql, $binder) !== false && is_array($data) && count($data)) {
  143. $tmp = explode($binder, $sql);
  144. if(!is_array($data)) { $data = array($data); }
  145. $data = array_values($data);
  146. if(count($data) >= count($tmp)) { $data = array_slice($data, 0, count($tmp)-1); }
  147. $sql = $tmp[0];
  148. foreach($data as $i => $v) {
  149. $sql .= $this->escape($v) . $tmp[($i + 1)];
  150. }
  151. }
  152. return $this->real_query($sql);
  153. }
  154. public function real_query($sql) {
  155. if(!$this->is_connected()) { $this->connect(); }
  156. }
  157. protected function escape($input) {
  158. if(is_array($input)) {
  159. foreach($input as $k => $v) {
  160. $input[$k] = $this->escape($v);
  161. }
  162. return implode(',',$input);
  163. }
  164. if(is_string($input)) {
  165. $input = addslashes($input);
  166. return "'".$input."'";
  167. }
  168. if(is_bool($input)) {
  169. return $input === false ? 0 : 1;
  170. }
  171. if(is_null($input)) {
  172. return 'NULL';
  173. }
  174. return $input;
  175. }
  176. public function nextr($result) {}
  177. public function nf($result) {}
  178. public function af() {}
  179. public function insert_id() {}
  180. public function seek($result, $row) {}
  181. }
  182. class Result implements \Iterator, \ArrayAccess, \Countable
  183. {
  184. protected $all = null;
  185. protected $rdy = false;
  186. protected $rslt = null;
  187. protected $mode = null;
  188. protected $fake = null;
  189. protected $skip = false;
  190. protected $fake_key = 0;
  191. protected $real_key = 0;
  192. public function __construct(Query $rslt, $key = null, $skip_key = false, $mode = 'assoc') {
  193. $this->rslt = $rslt;
  194. $this->mode = $mode;
  195. $this->fake = $key;
  196. $this->skip = $skip_key;
  197. }
  198. public function count() {
  199. return $this->rdy ? count($this->all) : $this->rslt->nf();
  200. }
  201. public function current() {
  202. if(!$this->count()) {
  203. return null;
  204. }
  205. if($this->rdy) {
  206. return current($this->all);
  207. }
  208. $tmp = $this->rslt->row();
  209. $row = array();
  210. switch($this->mode) {
  211. case 'num':
  212. foreach($tmp as $k => $v) {
  213. if(is_int($k)) {
  214. $row[$k] = $v;
  215. }
  216. }
  217. break;
  218. case 'both':
  219. $row = $tmp;
  220. break;
  221. case 'assoc':
  222. default:
  223. foreach($tmp as $k => $v) {
  224. if(!is_int($k)) {
  225. $row[$k] = $v;
  226. }
  227. }
  228. break;
  229. }
  230. if($this->fake) {
  231. $this->fake_key = $row[$this->fake];
  232. }
  233. if($this->skip) {
  234. unset($row[$this->fake]);
  235. }
  236. if(is_array($row) && count($row) === 1) {
  237. $row = current($row);
  238. }
  239. return $row;
  240. }
  241. public function key() {
  242. if($this->rdy) {
  243. return key($this->all);
  244. }
  245. return $this->fake ? $this->fake_key : $this->real_key;
  246. }
  247. public function next() {
  248. if($this->rdy) {
  249. return next($this->all);
  250. }
  251. $this->rslt->nextr();
  252. $this->real_key++;
  253. }
  254. public function rewind() {
  255. if($this->rdy) {
  256. return reset($this->all);
  257. }
  258. if($this->real_key !== null) {
  259. $this->rslt->seek(($this->real_key = 0));
  260. }
  261. $this->rslt->nextr();
  262. }
  263. public function valid() {
  264. if($this->rdy) {
  265. return current($this->all) !== false;
  266. }
  267. return $this->rslt->row() !== false && $this->rslt->row() !== null;
  268. }
  269. public function one() {
  270. $this->rewind();
  271. return $this->current();
  272. }
  273. public function get() {
  274. if(!$this->rdy) {
  275. $this->all = array();
  276. foreach($this as $k => $v) {
  277. $this->all[$k] = $v;
  278. }
  279. $this->rdy = true;
  280. }
  281. return $this->all;
  282. }
  283. public function offsetExists($offset) {
  284. if($this->rdy) {
  285. return isset($this->all[$offset]);
  286. }
  287. if($this->fake === null) {
  288. return $this->rslt->seek(($this->real_key = $offset));
  289. }
  290. $this->get();
  291. return isset($this->all[$offset]);
  292. }
  293. public function offsetGet($offset) {
  294. if($this->rdy) {
  295. return $this->all[$offset];
  296. }
  297. if($this->fake === null) {
  298. $this->rslt->seek(($this->real_key = $offset));
  299. $this->rslt->nextr();
  300. return $this->current();
  301. }
  302. $this->get();
  303. return $this->all[$offset];
  304. }
  305. public function offsetSet ($offset, $value ) {
  306. throw new Exception('Cannot set result');
  307. }
  308. public function offsetUnset ($offset) {
  309. throw new Exception('Cannot unset result');
  310. }
  311. public function __sleep() {
  312. $this->get();
  313. return array('all', 'rdy', 'mode', 'fake', 'skip');
  314. }
  315. public function __toString() {
  316. return print_r($this->get(), true);
  317. }
  318. }
  319. class Query
  320. {
  321. protected $drv = null;
  322. protected $sql = null;
  323. protected $prp = null;
  324. protected $rsl = null;
  325. protected $row = null;
  326. protected $num = null;
  327. protected $aff = null;
  328. protected $iid = null;
  329. public function __construct(IDriver $drv, $sql) {
  330. $this->drv = $drv;
  331. $this->sql = $sql;
  332. $this->prp = $this->drv->prepare($sql);
  333. }
  334. public function execute($vars = array()) {
  335. $this->rsl = $this->drv->execute($this->prp, $vars);
  336. $this->num = (is_object($this->rsl) || is_resource($this->rsl)) && is_callable(array($this->drv, 'nf')) ? (int)@$this->drv->nf($this->rsl) : 0;
  337. $this->aff = $this->drv->af();
  338. $this->iid = $this->drv->insert_id();
  339. return $this;
  340. }
  341. public function result($key = null, $skip_key = false, $mode = 'assoc') {
  342. return new Result($this, $key, $skip_key, $mode);
  343. }
  344. public function row() {
  345. return $this->row;
  346. }
  347. public function f($field) {
  348. return $this->row[$field];
  349. }
  350. public function nextr() {
  351. $this->row = $this->drv->nextr($this->rsl);
  352. return $this->row !== false && $this->row !== null;
  353. }
  354. public function seek($offset) {
  355. return @$this->drv->seek($this->rsl, $offset) ? true : false;
  356. }
  357. public function nf() {
  358. return $this->num;
  359. }
  360. public function af() {
  361. return $this->aff;
  362. }
  363. public function insert_id() {
  364. return $this->iid;
  365. }
  366. }
  367. class DBC implements IDB
  368. {
  369. protected $drv = null;
  370. protected $que = null;
  371. public function __construct($drv = null) {
  372. if(!$drv && defined('DATABASE')) {
  373. $drv = DATABASE;
  374. }
  375. if(!$drv) {
  376. $this->error('Could not create database (no settings)');
  377. }
  378. if(is_string($drv)) {
  379. $drv = new \vakata\database\Settings($drv);
  380. }
  381. if($drv instanceof Settings) {
  382. $tmp = '\\vakata\\database\\' . $drv->type . '_driver';
  383. if(!class_exists($tmp)) {
  384. $this->error('Could not create database (no driver: '.$drv->type.')');
  385. }
  386. $drv = new $tmp($drv);
  387. }
  388. if(!($drv instanceof IDriver)) {
  389. $this->error('Could not create database - wrong driver');
  390. }
  391. $this->drv = $drv;
  392. }
  393. public function connect() {
  394. if(!$this->drv->is_connected()) {
  395. try {
  396. $this->drv->connect();
  397. }
  398. catch (Exception $e) {
  399. $this->error($e->getMessage(), 1);
  400. }
  401. }
  402. return true;
  403. }
  404. public function disconnect() {
  405. if($this->drv->is_connected()) {
  406. $this->drv->disconnect();
  407. }
  408. }
  409. public function prepare($sql) {
  410. try {
  411. $this->que = new Query($this->drv, $sql);
  412. return $this->que;
  413. } catch (Exception $e) {
  414. $this->error($e->getMessage(), 2);
  415. }
  416. }
  417. public function execute($data = array()) {
  418. try {
  419. return $this->que->execute($data);
  420. } catch (Exception $e) {
  421. $this->error($e->getMessage(), 3);
  422. }
  423. }
  424. public function query($sql, $data = array()) {
  425. try {
  426. $this->que = new Query($this->drv, $sql);
  427. return $this->que->execute($data);
  428. }
  429. catch (Exception $e) {
  430. $this->error($e->getMessage(), 4);
  431. }
  432. }
  433. public function get($sql, $data = array(), $key = null, $skip_key = false, $mode = 'assoc') {
  434. return $this->query($sql, $data)->result($key, $skip_key, $mode);
  435. }
  436. public function all($sql, $data = array(), $key = null, $skip_key = false, $mode = 'assoc') {
  437. return $this->get($sql, $data, $key, $skip_key, $mode)->get();
  438. }
  439. public function one($sql, $data = array(), $mode = 'assoc') {
  440. return $this->query($sql, $data)->result(null, false, $mode)->one();
  441. }
  442. public function raw($sql) {
  443. return $this->drv->real_query($sql);
  444. }
  445. public function get_driver() {
  446. return $this->drv->get_settings()->type;
  447. }
  448. public function __call($method, $args) {
  449. if($this->que && is_callable(array($this->que, $method))) {
  450. try {
  451. return call_user_func_array(array($this->que, $method), $args);
  452. } catch (Exception $e) {
  453. $this->error($e->getMessage(), 5);
  454. }
  455. }
  456. }
  457. protected final function error($error = '') {
  458. $dirnm = defined('LOGROOT') ? LOGROOT : realpath(dirname(__FILE__));
  459. @file_put_contents(
  460. $dirnm . DIRECTORY_SEPARATOR . '_errors_sql.log',
  461. '[' . date('d-M-Y H:i:s') . '] ' . $this->settings->type . ' > ' . preg_replace("@[\s\r\n\t]+@", ' ', $error) . "\n",
  462. FILE_APPEND
  463. );
  464. throw new Exception($error);
  465. }
  466. }
  467. class DBCCached extends DBC
  468. {
  469. protected $cache_inst = null;
  470. protected $cache_nmsp = null;
  471. public function __construct($settings = null, \vakata\cache\ICache $c = null) {
  472. parent::__construct($settings);
  473. $this->cache_inst = $c;
  474. $this->cache_nmsp = 'DBCCached_' . md5(serialize($this->drv->get_settings()));
  475. }
  476. public function cache($expires, $sql, $data = array(), $key = null, $skip_key = false, $mode = 'assoc') {
  477. $arg = func_get_args();
  478. array_shift($arg);
  479. $key = md5(serialize($arg));
  480. if(!$this->cache_inst) {
  481. return call_user_func_array(array($this, 'all'), $arg);
  482. }
  483. $tmp = $this->cache_inst->get($key, $this->cache_nmsp);
  484. if(!$tmp) {
  485. $this->cache_inst->prep($key, $this->cache_nmsp);
  486. $tmp = call_user_func_array(array($this, 'all'), $arg);
  487. $this->cache_inst->set($key, $tmp, $this->cache_nmsp, $expires);
  488. }
  489. return $tmp;
  490. }
  491. public function clear() {
  492. if($this->cache_inst) {
  493. $this->cache_inst->clear($this->cache_nmsp);
  494. }
  495. }
  496. }
  497. class mysqli_driver extends ADriver
  498. {
  499. protected $iid = 0;
  500. protected $aff = 0;
  501. protected $mnd = false;
  502. public function __construct($settings) {
  503. parent::__construct($settings);
  504. if(!$this->settings->serverport) { $this->settings->serverport = 3306; }
  505. $this->mnd = function_exists('mysqli_fetch_all');
  506. }
  507. public function connect() {
  508. $this->lnk = new \mysqli(
  509. ($this->settings->persist ? 'p:' : '') . $this->settings->servername,
  510. $this->settings->username,
  511. $this->settings->password,
  512. $this->settings->database,
  513. $this->settings->serverport
  514. );
  515. if($this->lnk->connect_errno) {
  516. throw new Exception('Connect error: ' . $this->lnk->connect_errno);
  517. }
  518. if(!$this->lnk->set_charset($this->settings->charset)) {
  519. throw new Exception('Charset error: ' . $this->lnk->connect_errno);
  520. }
  521. if($this->settings->timezone) {
  522. @$this->lnk->query("SET time_zone = '" . addslashes($this->settings->timezone) . "'");
  523. }
  524. return true;
  525. }
  526. public function disconnect() {
  527. if($this->is_connected()) {
  528. @$this->lnk->close();
  529. }
  530. }
  531. public function real_query($sql) {
  532. if(!$this->is_connected()) { $this->connect(); }
  533. $temp = $this->lnk->query($sql);
  534. if(!$temp) {
  535. throw new Exception('Could not execute query : ' . $this->lnk->error . ' <'.$sql.'>');
  536. }
  537. $this->iid = $this->lnk->insert_id;
  538. $this->aff = $this->lnk->affected_rows;
  539. return $temp;
  540. }
  541. public function nextr($result) {
  542. if($this->mnd) {
  543. return $result->fetch_array(MYSQL_BOTH);
  544. }
  545. else {
  546. $ref = $result->result_metadata();
  547. if(!$ref) { return false; }
  548. $tmp = mysqli_fetch_fields($ref);
  549. if(!$tmp) { return false; }
  550. $ref = array();
  551. foreach($tmp as $col) { $ref[$col->name] = null; }
  552. $tmp = array();
  553. foreach($ref as $k => $v) { $tmp[] =& $ref[$k]; }
  554. if(!call_user_func_array(array($result, 'bind_result'), $tmp)) { return false; }
  555. if(!$result->fetch()) { return false; }
  556. $tmp = array();
  557. $i = 0;
  558. foreach($ref as $k => $v) { $tmp[$i++] = $v; $tmp[$k] = $v; }
  559. return $tmp;
  560. }
  561. }
  562. public function seek($result, $row) {
  563. $temp = $result->data_seek($row);
  564. return $temp;
  565. }
  566. public function nf($result) {
  567. return $result->num_rows;
  568. }
  569. public function af() {
  570. return $this->aff;
  571. }
  572. public function insert_id() {
  573. return $this->iid;
  574. }
  575. public function prepare($sql) {
  576. if(!$this->is_connected()) { $this->connect(); }
  577. $temp = $this->lnk->prepare($sql);
  578. if(!$temp) {
  579. throw new Exception('Could not prepare : ' . $this->lnk->error . ' <'.$sql.'>');
  580. }
  581. return $temp;
  582. }
  583. public function execute($sql, $data = array()) {
  584. if(!$this->is_connected()) { $this->connect(); }
  585. if(!is_array($data)) { $data = array(); }
  586. if(is_string($sql)) {
  587. return parent::execute($sql, $data);
  588. }
  589. $data = array_values($data);
  590. if($sql->param_count) {
  591. if(count($data) < $sql->param_count) {
  592. throw new Exception('Prepared execute - not enough parameters.');
  593. }
  594. $ref = array('');
  595. foreach($data as $i => $v) {
  596. switch(gettype($v)) {
  597. case "boolean":
  598. case "integer":
  599. $data[$i] = (int)$v;
  600. $ref[0] .= 'i';
  601. $ref[$i+1] =& $data[$i];
  602. break;
  603. case "double":
  604. $ref[0] .= 'd';
  605. $ref[$i+1] =& $data[$i];
  606. break;
  607. case "array":
  608. $data[$i] = implode(',',$v);
  609. $ref[0] .= 's';
  610. $ref[$i+1] =& $data[$i];
  611. break;
  612. case "object":
  613. case "resource":
  614. $data[$i] = serialize($data[$i]);
  615. $ref[0] .= 's';
  616. $ref[$i+1] =& $data[$i];
  617. break;
  618. default:
  619. $ref[0] .= 's';
  620. $ref[$i+1] =& $data[$i];
  621. break;
  622. }
  623. }
  624. call_user_func_array(array($sql, 'bind_param'), $ref);
  625. }
  626. $rtrn = $sql->execute();
  627. if(!$this->mnd) {
  628. $sql->store_result();
  629. }
  630. if(!$rtrn) {
  631. throw new Exception('Prepared execute error : ' . $this->lnk->error);
  632. }
  633. $this->iid = $this->lnk->insert_id;
  634. $this->aff = $this->lnk->affected_rows;
  635. if(!$this->mnd) {
  636. return $sql->field_count ? $sql : $rtrn;
  637. }
  638. else {
  639. return $sql->field_count ? $sql->get_result() : $rtrn;
  640. }
  641. }
  642. protected function escape($input) {
  643. if(is_array($input)) {
  644. foreach($input as $k => $v) {
  645. $input[$k] = $this->escape($v);
  646. }
  647. return implode(',',$input);
  648. }
  649. if(is_string($input)) {
  650. $input = $this->lnk->real_escape_string($input);
  651. return "'".$input."'";
  652. }
  653. if(is_bool($input)) {
  654. return $input === false ? 0 : 1;
  655. }
  656. if(is_null($input)) {
  657. return 'NULL';
  658. }
  659. return $input;
  660. }
  661. }
  662. class mysql_driver extends ADriver
  663. {
  664. protected $iid = 0;
  665. protected $aff = 0;
  666. public function __construct($settings) {
  667. parent::__construct($settings);
  668. if(!$this->settings->serverport) { $this->settings->serverport = 3306; }
  669. }
  670. public function connect() {
  671. $this->lnk = ($this->settings->persist) ?
  672. @mysql_pconnect(
  673. $this->settings->servername.':'.$this->settings->serverport,
  674. $this->settings->username,
  675. $this->settings->password
  676. ) :
  677. @mysql_connect(
  678. $this->settings->servername.':'.$this->settings->serverport,
  679. $this->settings->username,
  680. $this->settings->password
  681. );
  682. if($this->lnk === false || !mysql_select_db($this->settings->database, $this->lnk) || !mysql_query("SET NAMES '".$this->settings->charset."'", $this->lnk)) {
  683. throw new Exception('Connect error: ' . mysql_error());
  684. }
  685. if($this->settings->timezone) {
  686. @mysql_query("SET time_zone = '" . addslashes($this->settings->timezone) . "'", $this->lnk);
  687. }
  688. return true;
  689. }
  690. public function disconnect() {
  691. if(is_resource($this->lnk)) {
  692. mysql_close($this->lnk);
  693. }
  694. }
  695. public function real_query($sql) {
  696. if(!$this->is_connected()) { $this->connect(); }
  697. $temp = mysql_query($sql, $this->lnk);
  698. if(!$temp) {
  699. throw new Exception('Could not execute query : ' . mysql_error($this->lnk) . ' <'.$sql.'>');
  700. }
  701. $this->iid = mysql_insert_id($this->lnk);
  702. $this->aff = mysql_affected_rows($this->lnk);
  703. return $temp;
  704. }
  705. public function nextr($result) {
  706. return mysql_fetch_array($result, MYSQL_BOTH);
  707. }
  708. public function seek($result, $row) {
  709. $temp = @mysql_data_seek($result, $row);
  710. if(!$temp) {
  711. //throw new Exception('Could not seek : ' . mysql_error($this->lnk));
  712. }
  713. return $temp;
  714. }
  715. public function nf($result) {
  716. return mysql_num_rows($result);
  717. }
  718. public function af() {
  719. return $this->aff;
  720. }
  721. public function insert_id() {
  722. return $this->iid;
  723. }
  724. protected function escape($input) {
  725. if(is_array($input)) {
  726. foreach($input as $k => $v) {
  727. $input[$k] = $this->escape($v);
  728. }
  729. return implode(',',$input);
  730. }
  731. if(is_string($input)) {
  732. $input = mysql_real_escape_string($input, $this->lnk);
  733. return "'".$input."'";
  734. }
  735. if(is_bool($input)) {
  736. return $input === false ? 0 : 1;
  737. }
  738. if(is_null($input)) {
  739. return 'NULL';
  740. }
  741. return $input;
  742. }
  743. }
  744. class postgre_driver extends ADriver
  745. {
  746. protected $iid = 0;
  747. protected $aff = 0;
  748. public function __construct($settings) {
  749. parent::__construct($settings);
  750. if(!$this->settings->serverport) { $this->settings->serverport = 5432; }
  751. }
  752. public function connect() {
  753. $this->lnk = ($this->settings->persist) ?
  754. @pg_pconnect(
  755. "host=" . $this->settings->servername . " " .
  756. "port=" . $this->settings->serverport . " " .
  757. "user=" . $this->settings->username . " " .
  758. "password=" . $this->settings->password . " " .
  759. "dbname=" . $this->settings->database . " " .
  760. "options='--client_encoding=".strtoupper($this->settings->charset)."' "
  761. ) :
  762. @pg_connect(
  763. "host=" . $this->settings->servername . " " .
  764. "port=" . $this->settings->serverport . " " .
  765. "user=" . $this->settings->username . " " .
  766. "password=" . $this->settings->password . " " .
  767. "dbname=" . $this->settings->database . " " .
  768. "options='--client_encoding=".strtoupper($this->settings->charset)."' "
  769. );
  770. if($this->lnk === false) {
  771. throw new Exception('Connect error');
  772. }
  773. if($this->settings->timezone) {
  774. @pg_query($this->lnk, "SET TIME ZONE '".addslashes($this->settings->timezone)."'");
  775. }
  776. return true;
  777. }
  778. public function disconnect() {
  779. if(is_resource($this->lnk)) {
  780. pg_close($this->lnk);
  781. }
  782. }
  783. public function real_query($sql) {
  784. return $this->query($sql);
  785. }
  786. public function prepare($sql) {
  787. if(!$this->is_connected()) { $this->connect(); }
  788. $binder = '?';
  789. if(strpos($sql, $binder) !== false) {
  790. $tmp = explode($binder, $sql);
  791. $sql = $tmp[0];
  792. foreach($tmp as $i => $v) {
  793. $sql .= '$' . ($i + 1);
  794. if(isset($tmp[($i + 1)])) {
  795. $sql .= $tmp[($i + 1)];
  796. }
  797. }
  798. }
  799. return $sql;
  800. }
  801. public function execute($sql, $data = array()) {
  802. if(!$this->is_connected()) { $this->connect(); }
  803. if(!is_array($data)) { $data = array(); }
  804. $temp = (is_array($data) && count($data)) ? pg_query_params($this->lnk, $sql, $data) : pg_query_params($this->lnk, $sql, array());
  805. if(!$temp) {
  806. throw new Exception('Could not execute query : ' . pg_last_error($this->lnk) . ' <'.$sql.'>');
  807. }
  808. if(preg_match('@^\s*(INSERT|REPLACE)\s+INTO@i', $sql)) {
  809. $this->iid = pg_query($this->lnk, 'SELECT lastval()');
  810. $this->aff = pg_affected_rows($temp);
  811. }
  812. return $temp;
  813. }
  814. public function nextr($result) {
  815. return pg_fetch_array($result, NULL, PGSQL_BOTH);
  816. }
  817. public function seek($result, $row) {
  818. $temp = @pg_result_seek($result, $row);
  819. if(!$temp) {
  820. //throw new Exception('Could not seek : ' . pg_last_error($this->lnk));
  821. }
  822. return $temp;
  823. }
  824. public function nf($result) {
  825. return pg_num_rows($result);
  826. }
  827. public function af() {
  828. return $this->aff;
  829. }
  830. public function insert_id() {
  831. return $this->iid;
  832. }
  833. // Функция mysql_query?
  834. // - http://okbob.blogspot.com/2009/08/mysql-functions-for-postgresql.html
  835. // - http://www.xach.com/aolserver/mysql-to-postgresql.html
  836. // - REPLACE unixtimestamp / limit / curdate
  837. }
  838. class oracle_driver extends ADriver
  839. {
  840. protected $iid = 0;
  841. protected $aff = 0;
  842. public function connect() {
  843. $this->lnk = ($this->settings->persist) ?
  844. @oci_pconnect($this->settings->username, $this->settings->password, $this->settings->servername, $this->settings->charset) :
  845. @oci_connect ($this->settings->username, $this->settings->password, $this->settings->servername, $this->settings->charset);
  846. if($this->lnk === false) {
  847. throw new Exception('Connect error : ' . oci_error());
  848. }
  849. if($this->settings->timezone) {
  850. $this->real_query("ALTER session SET time_zone = '" . addslashes($this->settings->timezone) . "'");
  851. }
  852. return true;
  853. }
  854. public function disconnect() {
  855. if(is_resource($this->lnk)) {
  856. oci_close($this->lnk);
  857. }
  858. }
  859. public function real_query($sql) {
  860. if(!$this->is_connected()) { $this->connect(); }
  861. $temp = oci_parse($this->lnk, $sql);
  862. if(!$temp || !oci_execute($temp)) {
  863. throw new Exception('Could not execute real query : ' . oci_error($temp));
  864. }
  865. $this->aff = oci_num_rows($temp);
  866. return $temp;
  867. }
  868. public function prepare($sql) {
  869. if(!$this->is_connected()) { $this->connect(); }
  870. $binder = '?';
  871. if(strpos($sql, $binder) !== false && $vars !== false) {
  872. $tmp = explode($this->binder, $sql);
  873. $sql = $tmp[0];
  874. foreach($tmp as $i => $v) {
  875. $sql .= ':f' . $i;
  876. if(isset($tmp[($i + 1)])) {
  877. $sql .= $tmp[($i + 1)];
  878. }
  879. }
  880. }
  881. return oci_parse($this->lnk, $sql);
  882. }
  883. public function execute($sql, $data = array()) {
  884. if(!$this->is_connected()) { $this->connect(); }
  885. if(!is_array($data)) { $data = array(); }
  886. $data = array_values($data);
  887. foreach($data as $i => $v) {
  888. switch(gettype($v)) {
  889. case "boolean":
  890. case "integer":
  891. $data[$i] = (int)$v;
  892. oci_bind_by_name($sql, 'f'.$i, $data[$i], SQLT_INT);
  893. break;
  894. case "array":
  895. $data[$i] = implode(',',$v);
  896. oci_bind_by_name($sql, 'f'.$i, $data[$i]);
  897. break;
  898. case "object":
  899. case "resource":
  900. $data[$i] = serialize($data[$i]);
  901. oci_bind_by_name($sql, 'f'.$i, $data[$i]);
  902. break;
  903. default:
  904. oci_bind_by_name($sql, 'f'.$i, $data[$i]);
  905. break;
  906. }
  907. }
  908. $temp = oci_execute($sql);
  909. if(!$temp) {
  910. throw new Exception('Could not execute query : ' . oci_error($sql));
  911. }
  912. $this->aff = oci_num_rows($sql);
  913. /* TO DO: get iid
  914. if(!$seqname) { return $this->error('INSERT_ID not supported with no sequence.'); }
  915. $stm = oci_parse($this->link, 'SELECT '.strtoupper(str_replace("'",'',$seqname)).'.CURRVAL FROM DUAL');
  916. oci_execute($stm, $sql);
  917. $tmp = oci_fetch_array($stm);
  918. $tmp = $tmp[0];
  919. oci_free_statement($stm);
  920. */
  921. return $sql;
  922. }
  923. public function nextr($result) {
  924. return oci_fetch_array($result, OCI_BOTH);
  925. }
  926. public function seek($result, $row) {
  927. $cnt = 0;
  928. while($cnt < $row) {
  929. if(oci_fetch_array($result, OCI_BOTH) === false) {
  930. return false;
  931. }
  932. $cnt++;
  933. }
  934. return true;
  935. }
  936. public function nf($result) {
  937. return oci_num_rows($result);
  938. }
  939. public function af() {
  940. return $this->aff;
  941. }
  942. public function insert_id() {
  943. return $this->iid;
  944. }
  945. }
  946. class ibase_driver extends ADriver
  947. {
  948. protected $iid = 0;
  949. protected $aff = 0;
  950. public function __construct($settings) {
  951. parent::__construct($settings);
  952. if(!is_file($this->settings->database) && is_file('/'.$this->settings->database)) {
  953. $this->settings->database = '/'.$this->settings->database;
  954. }
  955. $this->settings->servername = ($this->settings->servername === 'localhost' || $this->settings->servername === '127.0.0.1' || $this->settings->servername === '') ?
  956. '' :
  957. $this->settings->servername . ':';
  958. }
  959. public function connect() {
  960. $this->lnk = ($this->settings->persist) ?
  961. @ibase_pconnect(
  962. $this->settings->servername . $this->settings->database,
  963. $this->settings->username,
  964. $this->settings->password,
  965. strtoupper($this->settings->charset)
  966. ) :
  967. @ibase_connect(
  968. $this->settings->servername . $this->settings->database,
  969. $this->settings->username,
  970. $this->settings->password,
  971. strtoupper($this->settings->charset)
  972. );
  973. if($this->lnk === false) {
  974. throw new Exception('Connect error: ' . ibase_errmsg());
  975. }
  976. return true;
  977. }
  978. public function disconnect() {
  979. if(is_resource($this->lnk)) {
  980. ibase_close($this->lnk);
  981. }
  982. }
  983. public function real_query($sql) {
  984. if(!$this->is_connected()) { $this->connect(); }
  985. $temp = ibase_query($sql, $this->lnk);
  986. if(!$temp) {
  987. throw new Exception('Could not execute query : ' . ibase_errmsg() . ' <'.$sql.'>');
  988. }
  989. //$this->iid = mysql_insert_id($this->lnk);
  990. $this->aff = ibase_affected_rows($this->lnk);
  991. return $temp;
  992. }
  993. public function prepare($sql) {
  994. if(!$this->is_connected()) { $this->connect(); }
  995. return ibase_prepare($this->lnk, $sql);
  996. }
  997. public function execute($sql, $data = array()) {
  998. if(!$this->is_connected()) { $this->connect(); }
  999. if(!is_array($data)) { $data = array(); }
  1000. $data = array_values($data);
  1001. foreach($data as $i => $v) {
  1002. switch(gettype($v)) {
  1003. case "boolean":
  1004. case "integer":
  1005. $data[$i] = (int)$v;
  1006. break;
  1007. case "array":
  1008. $data[$i] = implode(',',$v);
  1009. break;
  1010. case "object":
  1011. case "resource":
  1012. $data[$i] = serialize($data[$i]);
  1013. break;
  1014. }
  1015. }
  1016. array_unshift($data, $sql);
  1017. $temp = call_user_func_array("ibase_execute", $data);
  1018. if(!$temp) {
  1019. throw new Exception('Could not execute query : ' . ibase_errmsg() . ' <'.$sql.'>');
  1020. }
  1021. $this->aff = ibase_affected_rows($this->lnk);
  1022. return $temp;
  1023. }
  1024. public function nextr($result) {
  1025. return ibase_fetch_assoc($result, IBASE_TEXT);
  1026. }
  1027. public function seek($result, $row) {
  1028. return false;
  1029. }
  1030. public function nf($result) {
  1031. return false;
  1032. }
  1033. public function af() {
  1034. return $this->aff;
  1035. }
  1036. public function insert_id() {
  1037. return $this->iid;
  1038. }
  1039. }
  1040. }