query.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. <?php
  2. namespace MGModule\DNSManager2\mgLibs\MySQL;
  3. use MGModule\DNSManager2 as main;
  4. /**
  5. * MySQL Query Class
  6. *
  7. * @author Michal Czech <michael@modulesgarden.com>
  8. * @SuppressWarnings(PHPMD)
  9. */
  10. class query{
  11. /**
  12. *
  13. * @var array
  14. */
  15. protected $connection = array();
  16. /**
  17. * Use PDO for Connection
  18. *
  19. * @var boolean
  20. */
  21. static private $usePDO = false;
  22. /**
  23. *
  24. * @var main\mgLibs\MySQL\Query
  25. */
  26. static private $_instance;
  27. static $lastQuery;
  28. /**
  29. * Disable construct & clone method
  30. */
  31. private function __construct() {;}
  32. private function __clone() {;}
  33. /**
  34. * Get Singleton instance
  35. *
  36. * @author Michal Czech <michael@modulesgarden.com>
  37. * @param string $hostName
  38. * @param string $username
  39. * @param string $password
  40. * @param string $dbname
  41. * @param string $connectionName
  42. * @return main\mgLibs\MySQL\Query
  43. * @throws main\exception\System
  44. */
  45. public static function I()
  46. {
  47. if(empty(self::$_instance))
  48. {
  49. throw new main\mgLibs\exceptions\System('Object not Spawned');
  50. }
  51. return self::$_instance;
  52. }
  53. /**
  54. * Use Current Default MySQL Connection for queries
  55. *
  56. * @author Michal Czech <michael@modulesgarden.com>
  57. */
  58. public static function useCurrentConnection(){
  59. //Use by default PDO in WHMCS 6 and 7
  60. if(class_exists('\Illuminate\Database\Capsule\Manager') && \Illuminate\Database\Capsule\Manager::connection()->getPdo())
  61. {
  62. self::$usePDO = true;
  63. self::$_instance->connection['default'] = \Illuminate\Database\Capsule\Manager::connection()->getPdo();
  64. }
  65. else
  66. {
  67. self::$_instance = new self();
  68. self::$_instance->connection['default'] = false;
  69. }
  70. }
  71. /**
  72. * Connect DB From File
  73. *
  74. * @author Michal Czech <michael@modulesgarden.com>
  75. * @param string $file
  76. * @throws main\exception\System
  77. * @return boolean
  78. */
  79. public static function connectFromFile($file)
  80. {
  81. if(!file_exists($file))
  82. {
  83. throw new main\mgLibs\exceptions\System('DB Connection File does not exits', main\mgLibs\exceptions\Codes::MYSQL_MISING_CONFIG_FILE);
  84. }
  85. self::$_instance = new self();
  86. include $file;
  87. foreach($config as $connectionName => $config)
  88. {
  89. if ($config['host'])
  90. {
  91. if(self::$usePDO)
  92. {
  93. if(!extension_loaded('PDO'))
  94. {
  95. throw new main\mgLibs\exceptions\System('Missing PDO Extension', main\mgLibs\exceptions\Codes::MYSQL_MISING_PDO_EXTENSION);
  96. }
  97. try{
  98. self::$_instance->connection[$connectionName] = new \PDO("mysql:host=".$config['host'].";dbname=".$config['name'], $config['user'], $config['pass']);
  99. self::$_instance->connection[$connectionName]->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
  100. } catch (\Exception $ex) {
  101. throw new main\mgLibs\exceptions\System('SQL Connection Error',exceptions\Codes::MYSQL_CONNECTION_FAILED);
  102. }
  103. }
  104. else
  105. {
  106. throw new main\mgLibs\exceptions\System('SQL Connection Error',main\mgLibs\exceptions\Codes::MYSQL_CONNECTION_FAILED);
  107. }
  108. }
  109. }
  110. return true;
  111. }
  112. /**
  113. * Disconnect all mysql connection
  114. *
  115. * @author Michal Czech <michael@modulesgarden.com>
  116. */
  117. static function dropAllConnection(){
  118. foreach(self::I()->connection as $name => &$connection)
  119. {
  120. $connection = null;
  121. unset(self::I()->connection[$name]);
  122. }
  123. }
  124. /**
  125. * Custom MySQL Query
  126. *
  127. * @param string $query
  128. * @param array $params
  129. * @param string $connectionName
  130. * @return result
  131. * @throws main\mgLibs\exceptions\System
  132. */
  133. public static function query($query,array $params=array(), $connectionName = 'default')
  134. {
  135. if(!isset(self::$_instance->connection[$connectionName]))
  136. {
  137. throw new main\mgLibs\exceptions\system("Connection ".$connectionName.' not exits', main\mgLibs\exceptions\codes::MYSQL_MISING_CONNECTION);
  138. }
  139. if(self::$usePDO)
  140. {
  141. try{
  142. $sth = self::$_instance->connection[$connectionName]->prepare($query);
  143. $sth->execute($params);
  144. } catch (\Exception $ex) {
  145. $dQuery = $query;
  146. foreach($params as $n => $v)
  147. {
  148. $dQuery = str_replace($n, "'".$v."'", $dQuery);
  149. }
  150. throw new main\mgLibs\MySQL\exception('Error in SQL Query:'.$ex->getMessage(),$ex);
  151. }
  152. if(strpos($query, 'insert') !== false || strpos($query, 'INSERT')!== false )
  153. {
  154. $id = self::$_instance->connection[$connectionName]->lastInsertId();
  155. }
  156. else
  157. {
  158. $id = null;
  159. }
  160. return new main\mgLibs\MySQL\result($sth,$id);
  161. }
  162. else
  163. {
  164. throw new main\mgLibs\exceptions\System('SQL Connection Error',main\mgLibs\exceptions\Codes::MYSQL_CONNECTION_FAILED);
  165. }
  166. }
  167. /**
  168. * Disconnect specifi MySQL socket
  169. *
  170. * @param string $connectionName
  171. */
  172. static function dropInstance($connectionName = 'default')
  173. {
  174. if(self::$usePDO)
  175. {
  176. unset(self::$_instance->connection[$connectionName]);
  177. }
  178. else
  179. {
  180. throw new main\mgLibs\exceptions\System('SQL Connection Error',main\mgLibs\exceptions\Codes::MYSQL_CONNECTION_FAILED);
  181. }
  182. }
  183. /**
  184. * Simple Insert Query
  185. *
  186. * @author Michal Czech <michael@modulesgarden.com>
  187. * @param string $table
  188. * @param array $data
  189. * @param string $connectionName
  190. * @throws \exception\System
  191. * @return int id of new record
  192. */
  193. static function insert($table,array $data, $connectionName = 'default')
  194. {
  195. $cols = array();
  196. $valuesLabels = array();
  197. $values = array();
  198. $i = 0;
  199. foreach($data as $col => $value)
  200. {
  201. $cols[] = $col;
  202. $colName = 'col'.$i;
  203. $valuesLabels[] = ':'.$colName;
  204. $values[$colName] = $value;
  205. $i++;
  206. }
  207. $cols = implode("`,`", $cols);
  208. $valuesLabels = implode(",", $valuesLabels);
  209. $sql = "INSERT INTO $table (`$cols`) VALUES ($valuesLabels)";
  210. $val = self::query($sql,$values,$connectionName)->getID();
  211. return $val;
  212. }
  213. /**
  214. * Simple Insert Query
  215. *
  216. * @author Michal Czech <michael@modulesgarden.com>
  217. * @param string $table
  218. * @param array $data
  219. * @param string $connectionName
  220. * @throws \exception\System
  221. * @return int id of new record
  222. */
  223. static function insertOnDuplicateUpdate($table,array $data, array $update, $connectionName = 'default')
  224. {
  225. $cols = array();
  226. $valuesLabels = array();
  227. $values = array();
  228. $i = 0;
  229. foreach($data as $col => $value)
  230. {
  231. $cols[] = $col;
  232. $colName = 'col'.$i;
  233. $valuesLabels[] = ':'.$colName;
  234. $values[$colName] = $value;
  235. $i++;
  236. }
  237. $cols = implode("`,`", $cols);
  238. $valuesLabels = implode(",", $valuesLabels);
  239. $sql = "INSERT INTO $table (`$cols`) VALUES ($valuesLabels)";
  240. $sql .= "ON DUPLICATE KEY UPDATE ";
  241. $cols = array();
  242. $valuesLabels = array();
  243. foreach($update as $col => $value)
  244. {
  245. $colName = preg_replace("/[^A-Za-z0-9]/", '', $col);
  246. $cols[] = "`$col` = :$colName";
  247. $values[$colName] = $value;
  248. }
  249. $sql .= implode(",", $cols);
  250. $val = self::query($sql,$values,$connectionName)->getID();
  251. return $val;
  252. }
  253. /**
  254. * Simple Update Request
  255. *
  256. * @author Michal Czech <michael@modulesgarden.com>
  257. * @param string $table
  258. * @param array $data
  259. * @param array $condition
  260. * @param array $conditionValues
  261. * @throws \exception\System
  262. * @return result
  263. */
  264. static function update($table,array $data,array $condition)
  265. {
  266. $conditionParsed = self::parseConditions($condition,$values);
  267. $cols = array();
  268. $valuesLabels = array();
  269. foreach($data as $col => $value)
  270. {
  271. $colName = preg_replace("/[^A-Za-z0-9]/", '', $col);
  272. $cols[] = "`$col` = :$colName";
  273. $values[$colName] = $value;
  274. }
  275. $cols = implode(",", $cols);
  276. $sql = "UPDATE $table SET $cols ";
  277. if($conditionParsed)
  278. {
  279. $sql .= " WHERE ".$conditionParsed;
  280. }
  281. return self::query($sql,$values);
  282. }
  283. /**
  284. * Simple Delete Request
  285. *
  286. * @author Michal Czech <michael@modulesgarden.com>
  287. * @param string $table
  288. * @param array $condition
  289. * @param array $conditionValues
  290. * @throws \exception\System
  291. * @return result
  292. */
  293. static function delete($table,array $condition)
  294. {
  295. $sql = "DELETE FROM $table";
  296. $conditionParsed = self::parseConditions($condition,$values);
  297. if($conditionParsed)
  298. {
  299. $sql .= " WHERE ".$conditionParsed;
  300. }
  301. return self::query($sql,$values);
  302. }
  303. /**
  304. * Parse MySQL Conditions
  305. *
  306. * @author Michal Czech <michael@modulesgarden.com>
  307. * @param type $condition
  308. * @param type $values
  309. * @return type
  310. */
  311. static function parseConditions($condition, &$values, $prefix = null, &$i = 0){
  312. $conditionParsed = array();
  313. $values = array();
  314. foreach($condition as $col => $value)
  315. {
  316. if(is_string($col))
  317. {
  318. if(is_array($value))
  319. {
  320. $conditionTmp = array();
  321. foreach($value as $v)
  322. {
  323. $colName = ':cond'.$i;
  324. $conditionTmp[] = $colName;
  325. $values['cond'.$i] = $v;
  326. $i++;
  327. }
  328. if($prefix)
  329. {
  330. $tmpValue = "`$prefix`.`$col` in (".implode(',',$conditionTmp).')';
  331. $conditionParsed[] = $value['or'] ? array('or' => true, 'value' => $tmpValue) : $tmpValue;
  332. }
  333. else
  334. {
  335. $tmpValue = "`$col` in (".implode(',',$conditionTmp).')';
  336. $conditionParsed[] = $value['or'] ? array('or' => true, 'value' => $tmpValue) : $tmpValue;
  337. }
  338. }
  339. elseif($value === 'ISNULL')
  340. {
  341. $conditionParsed[] = $prefix ? "`$prefix`.`$col` IS NULL " : "`$col` IS NULL ";
  342. }
  343. else
  344. {
  345. $colName = ':cond'.$i;
  346. if($prefix)
  347. {
  348. $conditionParsed[] = "`$prefix`.`$col` = $colName";
  349. }
  350. else
  351. {
  352. $conditionParsed[] = "`$col` = $colName";
  353. }
  354. $values['cond'.$i] = $value;
  355. $i++;
  356. }
  357. }
  358. elseif(is_array($value) && isset($value['customQuery']))
  359. {
  360. $conditionParsed[] = $value['or'] ? array('or' => true, 'value' => $value['customQuery']) : $value['customQuery'];
  361. foreach ($value['params'] as $n => $v)
  362. {
  363. $values[$n] = $v;
  364. }
  365. }
  366. else
  367. {
  368. $conditionParsed[] = $value;
  369. }
  370. }
  371. $out = '';
  372. $first = true;
  373. foreach($conditionParsed as $v2)
  374. {
  375. if(is_array($v2))
  376. {
  377. $out = $out . ($first ? '' : ($v2['or'] ? ' OR ':' AND ')) . $v2['value'];
  378. }
  379. else
  380. {
  381. $out = $out . ($first ? '' : ' AND ') . $v2;
  382. }
  383. $first = false;
  384. }
  385. return $out;
  386. }
  387. static function formatSelectFields($cols,$prefix = null){
  388. foreach($cols as $name => &$value)
  389. {
  390. if(!is_int($name))
  391. {
  392. if($prefix)
  393. {
  394. $value = "`$prefix`.`$name` as '$value'";
  395. }
  396. else
  397. {
  398. $value = "`$name` as '$value'";
  399. }
  400. }
  401. else
  402. {
  403. if($prefix)
  404. {
  405. $value = "`$prefix`.`$value`";
  406. }
  407. else
  408. {
  409. $value = "`$value`";
  410. }
  411. }
  412. }
  413. unset($value);
  414. return implode(",", $cols);
  415. }
  416. static function formatOrderBy($orderBy,$prefix = null){
  417. if(empty($orderBy))
  418. {
  419. return;
  420. }
  421. $tmp = array();
  422. foreach($orderBy as $col => $vect)
  423. {
  424. if($prefix)
  425. {
  426. $tmp[] = "`$prefix`.`$col` ".(($vect=='ASC'||$vect=='asc')?'ASC':'DESC');
  427. }
  428. else
  429. {
  430. $tmp[] = "`$col` ".(($vect=='ASC'||$vect=='asc')?'ASC':'DESC');
  431. }
  432. }
  433. return " ORDER BY ".implode(',', $tmp);
  434. }
  435. static function formarLimit($limit,$offset)
  436. {
  437. if($limit)
  438. {
  439. if($offset)
  440. {
  441. return " LIMIT $offset , $limit ";
  442. }
  443. else
  444. {
  445. return " LIMIT 0 , $limit ";
  446. }
  447. }
  448. }
  449. /**
  450. * Simple Select Query
  451. *
  452. * @author Michal Czech <michael@modulesgarden.com>
  453. * @param array $cols
  454. * @param string $table
  455. * @param array $conditionValues
  456. * @param array $groupBy
  457. * @param int $limit
  458. * @param int $offset
  459. * @throws \exception\System
  460. * @return result
  461. */
  462. static function select(array $cols,$table,array $condition = array(),array $orderBy = array(),$limit = null,$offset = 0, $connectionName = 'default')
  463. {
  464. $cols = (count($cols) === 1 && $cols[0] === '*') ? $cols[0] : self::formatSelectFields($cols);
  465. $sql = "SELECT $cols FROM $table";
  466. $conditionParsed = self::parseConditions($condition, $values);
  467. if($conditionParsed)
  468. {
  469. $sql .= " WHERE ".$conditionParsed;
  470. }
  471. $sql .= self::formatOrderBy($orderBy);
  472. $sql .= self::formarLimit($limit, $offset);
  473. return self::query($sql, $values, $connectionName);
  474. }
  475. /**
  476. * Simple Select Query
  477. *
  478. * @author Michal Czech <michael@modulesgarden.com>
  479. * @param array $cols
  480. * @param string $table
  481. * @param array $conditionValues
  482. * @param array $groupBy
  483. * @param int $limit
  484. * @param int $offset
  485. * @throws \exception\System
  486. * @return result
  487. */
  488. static function count($colsName,$table,array $condition = array(),array $orderBy = array(),$limit = null,$offset = 0, $connectionName = 'default')
  489. {
  490. $sql = "SELECT count($colsName) as count FROM $table";
  491. $conditionParsed = self::parseConditions($condition,$values);
  492. if($conditionParsed)
  493. {
  494. $sql .= " WHERE ".$conditionParsed;
  495. }
  496. if($orderBy)
  497. {
  498. $sql .= " ORDER BY ";
  499. $tmp = array();
  500. foreach($orderBy as $col => $vect)
  501. {
  502. $tmp[] = "`$col` $vect";
  503. }
  504. $sql .= implode(',', $tmp);
  505. }
  506. if($limit)
  507. {
  508. if($offset)
  509. {
  510. $sql .= " LIMIT $offset , $limit ";
  511. }
  512. else
  513. {
  514. $sql .= " LIMIT 0 , $limit ";
  515. }
  516. }
  517. return self::query($sql, $values, $connectionName)->fetchColumn('count');
  518. }
  519. public static function startTransaction($connectionName = 'default')
  520. {
  521. self::$_instance->connection[$connectionName]->setAttribute(\PDO::ATTR_AUTOCOMMIT , false);
  522. self::$_instance->connection[$connectionName]->beginTransaction();
  523. }
  524. public static function endTransaction($connectionName = 'default')
  525. {
  526. self::$_instance->connection[$connectionName]->commit();
  527. self::$_instance->connection[$connectionName]->setAttribute(\PDO::ATTR_AUTOCOMMIT , true);
  528. }
  529. public static function getLastQuery()
  530. {
  531. return self::$lastQuery;
  532. }
  533. public static function createInstance($connectionParams = array(), $connectionName = 'pdns')
  534. {
  535. try
  536. {
  537. self::$_instance = self::$_instance ? self::$_instance : new self();
  538. self::$_instance->connection[$connectionName] = new \PDO("mysql:host=".$connectionParams['host'].";dbname=".$connectionParams['name'],
  539. $connectionParams['user'], $connectionParams['pass']);
  540. self::$_instance->connection[$connectionName]->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
  541. }
  542. catch(\PDOException $ex)
  543. {
  544. $_instance->connection[$connectionName] = null;
  545. throw new \MGModule\DNSManager2\mgLibs\exceptions\system('SQL Connection Error', \MGModule\DNSManager2\mgLibs\exceptions\codes::MYSQL_CONNECTION_FAILED);
  546. }
  547. return self::$_instance;
  548. }
  549. public static function debugQuery($query, $params = array(), $connectionName = 'pdns')
  550. {
  551. if(count($params) > 0)
  552. {
  553. foreach($params as &$param)
  554. {
  555. $param = substr(self::$_instance->connection[$connectionName]->quote($param),1,-1);
  556. }
  557. $parsedQuery = vsprintf(str_replace("?", "'%s'", $query), $params);
  558. return $parsedQuery;
  559. }
  560. return $query;
  561. }
  562. public static function realEscapeString($string, $connectionName = 'default')
  563. {
  564. return substr(self::$_instance->connection[$connectionName]->quote($string),1,-1);
  565. }
  566. }