1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
37:
38: namespace Simpletools\Db\Mysql;
39:
40: class Client
41: {
42: protected $_credentials = false;
43: protected $_connected = false;
44: protected $_modelDir = '';
45: protected $_quotes_on = '';
46: private $_query = '';
47: private static $_instance = null;
48: private $_settings = null;
49: private $_current_db = null;
50: private $_mysqli = null;
51:
52: const _noArgs = '$--SimpleMySQL--n0-aRg5--';
53:
54: public function __construct(array $settings=null)
55: {
56: $this->setSettings($settings);
57:
58: if(empty(self::$_instance))
59: {
60: self::$_instance = &$this;
61: }
62: }
63:
64: public function setSettings($settings)
65: {
66: $settings['charset_type'] = isset($settings['charset']) ? $settings['charset'] : (isset($settings['charset_type']) ? $settings['charset_type'] : null);
67:
68: $this->_settings = $settings;
69: $this->_settings['die_on_error'] = isset($settings['die_on_error']) ? (boolean) $settings['die_on_error'] : true;
70: $this->_settings['custom_mysqli_class_name'] = isset($settings['custom_mysqli_class_name']) ? (string) $settings['custom_mysqli_class_name'] : false;
71:
72: $this->_settings['connect_error_filepath'] = isset($settings['connect_error_filepath']) ? $settings['connect_error_filepath'] : false;
73:
74:
75: if(isset($settings['model_dir']))
76: {
77: $this->_modelDir = $settings['model_dir'];
78: }
79: elseif(isset($settings['modelsDir']))
80: {
81: $this->_modelDir = $settings['modelsDir'];
82: }
83:
84: $this->setCredentials($settings);
85: $this->quotes_on = (get_magic_quotes_gpc()==1 || get_magic_quotes_runtime()==1) ? true : false ;
86: }
87:
88: public function setDb($db)
89: {
90: if($this->_current_db==$db){return true;}
91:
92: if(!$this->isConnected())
93: {
94: $this->connect();
95: if(!$this->isConnected()) return false;
96: }
97:
98: $this->_current_db = $db;
99: return $this->_mysqli->select_db($db);
100: }
101:
102: public function getCurrentDb()
103: {
104: if(!$this->isConnected())
105: {
106: $this->connect();
107: if(!$this->isConnected()) return false;
108: }
109:
110: return $this->_current_db;
111: }
112:
113: public static function &getInstance($settings=false)
114: {
115: if(empty(self::$_instance) && $settings)
116: {
117: self::$_instance = new \Simpletools\Db\Mysql\Client($settings);
118: }
119:
120: return self::$_instance;
121: }
122:
123: public static function &settings($settings)
124: {
125: if(empty(self::$_instance))
126: new \Simpletools\Db\Mysql\Client($settings);
127: else
128: self::$_instance->setSettings($settings);
129:
130: return self::$_instance;
131: }
132:
133: public function setNewConnectionDetails($credentials, $user=false, $pass=false, $db=false)
134: {
135: if($this->_connected)
136: {
137: $this->close();
138: }
139:
140: $this->setCredentials($credentials, $user, $pass, $db);
141: }
142:
143: public function setCredentials($settings)
144: {
145: $this->_credentials['host'] = isset($settings['host']) ? $settings['host'] : 'localhost';
146: $this->_credentials['user'] = isset($settings['user']) ? $settings['user'] : null;
147: $this->_credentials['pass'] = isset($settings['pass']) ? $settings['pass'] : null;
148: $this->_credentials['db'] = isset($settings['db']) ? $settings['db'] : null;
149: $this->_credentials['port'] = isset($settings['port']) ? $settings['port'] : 3306;
150: }
151:
152: public function __desctruct()
153: {
154: $this->close();
155: }
156:
157: public function setMysqliClass($class=false)
158: {
159: $this->_settings['custom_mysqli_class_name'] = $class;
160: }
161:
162: public function getMysqliClass()
163: {
164: return (($this->_settings['custom_mysqli_class_name'] === false) ? 'mysqli' : $this->_settings['custom_mysqli_class_name']);
165: }
166:
167: public function setTimeout($time=10)
168: {
169: if($this->_mysqli === null)
170: {
171: if($this->_settings['custom_mysqli_class_name'] != false)
172: $mysqli_class = $this->_settings['custom_mysqli_class_name'];
173: else
174: $mysqli_class = 'mysqli';
175:
176: $this->_mysqli = new $mysqli_class();
177: $this->_mysqli->init();
178: }
179:
180: return $this->_mysqli->options(MYSQLI_OPT_CONNECT_TIMEOUT,$time);
181: }
182:
183: public function setTimezone($timezone)
184: {
185: if(!$this->isConnected())
186: {
187: $this->connect();
188: if(!$this->isConnected()) return false;
189: }
190:
191: $this->prepare('SET time_zone = ?')->execute($timezone,false);
192: }
193:
194: public function getTimezone()
195: {
196: if(!$this->isConnected())
197: {
198: $this->connect();
199: if(!$this->isConnected()) return false;
200: }
201:
202: $r = $this->query('SELECT @@time_zone as tz;',false);
203: if($this->isEmpty($r)) return false;
204: else return $this->fetch($r)->tz;
205: }
206:
207: public function connect($credentials=false, $user=false, $pass=false, $db=false, $port=3306, $die_on_error=null)
208: {
209: if($this->isConnected()) return true;
210:
211: $mysqli_class = 'mysqli';
212:
213: if($this->_settings['custom_mysqli_class_name'] != false)
214: $mysqli_class = $this->_settings['custom_mysqli_class_name'];
215:
216: $this->_mysqli = new $mysqli_class();
217: $this->_mysqli->init();
218: $this->setTimeout();
219:
220: if(!$credentials)
221: {
222: if(!$this->_credentials['host']) throw new \Exception('Please specify connection settings before',111);
223: $this->_current_db = $this->_credentials['db'];
224: @$this->_mysqli->real_connect($this->_credentials['host'], $this->_credentials['user'], $this->_credentials['pass'], $this->_credentials['db'],$this->_credentials['port']);
225: }
226: else
227: {
228: if(is_array($credentials))
229: {
230: if(isset($credentials['db']))
231: {
232: $this->_current_db = $credentials['db'];
233: @$this->_mysqli->real_connect($credentials['host'], $credentials['user'], $credentials['pass'], $credentials['db'], isset($credentials['db']) ? $credentials['db'] : 3306);
234: }
235: else
236: {
237: @$this->_mysqli->real_connect($credentials['host'], $credentials['user'], $credentials['pass'],null,isset($credentials['db']) ? $credentials['db'] : 3306);
238: }
239: }
240: else
241: {
242: $this->_current_db = $db;
243: @$this->_mysqli->real_connect($credentials, $user, $pass, $db, $port);
244: }
245: }
246:
247: if(mysqli_connect_errno())
248: {
249: if(isset($_SERVER['SERVER_PROTOCOL'])){header($_SERVER['SERVER_PROTOCOL'].' 503 Service Unavailable');}
250:
251: if(
252: $die_on_error === true ||
253: (isset($credentials['die_on_error']) && $credentials['die_on_error'] === true)
254: )
255: {
256: if($this->_settings['connect_error_filepath'] && realpath($this->_settings['connect_error_filepath']))
257: {
258: include_once realpath($this->_settings['connect_error_filepath']);
259: exit();
260: }
261: else
262: {
263:
264:
265:
266: throw new \Exception("Connect Error: ".mysqli_connect_error(),mysqli_connect_errno());
267: }
268:
269: }
270: else if($this->_settings['die_on_error'])
271: {
272: if($this->_settings['connect_error_filepath'] && realpath($this->_settings['connect_error_filepath']))
273: {
274: include_once realpath($this->_settings['connect_error_filepath']);
275: exit();
276: }
277: else
278: {
279:
280:
281:
282: throw new \Exception("Connect Error: ".mysqli_connect_error(),mysqli_connect_errno());
283: }
284:
285: }
286:
287: $this->_connected = false;
288: }
289: else
290: {
291: if(isset($this->_settings['charset_type']))
292: {
293: $this->_mysqli->set_charset($this->_settings['charset_type']);
294: }
295:
296: $this->_connected = true;
297:
298: if(isset($this->_settings['time_zone']))
299: {
300: $this->setTimezone($this->_settings['time_zone']);
301: }
302: }
303:
304: return $this->_connected;
305: }
306:
307: public function getServerInfo()
308: {
309: if(!$this->isConnected())
310: {
311: $this->connect();
312: if(!$this->isConnected()) return false;
313: }
314:
315: return $this->_mysqli->server_info;
316: }
317:
318: public function getConnectError()
319: {
320: return $this->_mysqli->connect_error;
321: }
322:
323: public function isThreadSafe()
324: {
325: if(!$this->isConnected())
326: {
327: $this->connect();
328: if(!$this->isConnected()) return false;
329: }
330:
331: return $this->_mysqli->thread_safe;
332: }
333:
334: public function getConnectErrorNo()
335: {
336: return $this->_mysqli->connect_errno;
337: }
338:
339: public function isTable($table,$db=null,$die_on_error=null)
340: {
341: $table = $this->escape($table);
342:
343: if($db === null)
344: $res = $this->query('SHOW TABLES LIKE "'.$table.'"',$die_on_error);
345: else
346: {
347: $db = $this->escape($db);
348: $res = $this->query('SHOW TABLES FROM '.$db.' LIKE "'.$table.'"',$die_on_error);
349: }
350:
351: return !$this->isEmpty($res);
352: }
353:
354: 355: 356:
357: public function setAutoCommit($autoCommit=true)
358: {
359: if($autoCommit)
360: $this->query('SET AUTOCOMMIT=1');
361: else
362: $this->query('SET AUTOCOMMIT=0');
363: }
364:
365: public function startTransaction()
366: {
367: $this->query('START TRANSACTION');
368: }
369:
370: public function beginTransaction()
371: {
372: $this->query('BEGIN');
373: }
374:
375: public function rollback()
376: {
377: $this->query('ROLLBACK');
378: }
379:
380: public function commit()
381: {
382: $this->query('COMMIT');
383: }
384:
385: public function setUniqueChecks($uniqueChecks=true)
386: {
387: if(!$this->isConnected())
388: {
389: $this->connect();
390: if(!$this->isConnected()) return false;
391: }
392:
393: if($uniqueChecks)
394: $this->query('SET UNIQUE_CHECKS=1');
395: else
396: $this->query('SET UNIQUE_CHECKS=0');
397: }
398: 399: 400:
401:
402: public function getInfo()
403: {
404: if(!$this->isConnected())
405: {
406: $this->connect();
407: if(!$this->isConnected()) return false;
408: }
409:
410: return $this->_mysqli->info;
411: }
412:
413: public function getError()
414: {
415: return $this->_mysqli->error;
416: }
417:
418: public function getErrorNo()
419: {
420: return $this->_mysqli->errno;
421: }
422:
423: public function isError()
424: {
425: return (boolean) $this->_mysqli->errno;
426: }
427:
428: public function getCharset()
429: {
430: if(!$this->isConnected())
431: {
432: $this->connect();
433: if(!$this->isConnected()) return false;
434: }
435:
436: return $this->_mysqli->get_charset();
437: }
438:
439: public function setCharset($charset)
440: {
441: if(!$this->isConnected())
442: {
443: $this->connect();
444: if(!$this->isConnected()) return false;
445: }
446:
447: $this->_mysqli->set_charset($charset);
448: }
449:
450:
451: public function close()
452: {
453: $this->_mysqli->close();
454: $this->_connected = false;
455: }
456:
457: public function getConnectionStatus()
458: {
459: if($this->_connected)
460: {
461: $status = new \StdClass();
462: $status->connected = true;
463: $status->host = $this->_credentials['host'];
464: $status->db = $this->_credentials['db'];
465: $status->user = $this->_credentials['user'];
466:
467: return $status;
468: }
469: else
470: {
471: return false;
472: }
473: }
474:
475: public function &prepare($query, $args=self::_noArgs, $prepare_type=true)
476: {
477: $this->_query = $query;
478: $this->_args = $args;
479: $this->_prepare_typ = $prepare_type;
480:
481: return $this;
482: }
483:
484: public function exec()
485: {
486: $args = func_get_args();
487: if(!count($args))
488: {
489: $args=self::_noArgs;
490: }
491:
492: if($args === self::_noArgs && is_array($this->_args))
493: $args = $this->_args;
494: else if($args === self::_noArgs && $this->_args !== self::_noArgs)
495: $args = array($this->_args);
496: else if(!is_array($args) && $args !== self::_noArgs)
497: $args = array($args);
498: else if($args === self::_noArgs)
499: throw new \Exception("Please specify arguments for prepare() and/or execute() methods of \Simpletools\Db\Mysql class.",10001);
500:
501: if(!$this->isConnected())
502: {
503: $this->connect();
504: if(!$this->isConnected()) return false;
505: }
506:
507: $query = $this->_query;
508:
509: return $this->_query($this->_prepareQuery($query,$args),null);
510:
511: }
512:
513: public function execute($args=self::_noArgs,$die_on_error=null)
514: {
515: if($args === self::_noArgs && is_array($this->_args))
516: $args = $this->_args;
517: else if($args === self::_noArgs && $this->_args !== self::_noArgs)
518: $args = array($this->_args);
519: else if(!is_array($args) && $args !== self::_noArgs)
520: $args = array($args);
521: else if($args === self::_noArgs)
522: throw new \Exception("Please specify arguments for prepare() and/or execute() methods of \Simpletools\Db\Mysql class.",10001);
523:
524: if(!$this->isConnected())
525: {
526: $this->connect();
527: if(!$this->isConnected()) return false;
528: }
529:
530: $query = $this->_query;
531:
532: return $this->_query($this->_prepareQuery($query,$args),$die_on_error);
533:
534: }
535:
536: private function _prepareQuery($query, array $args)
537: {
538: foreach($args as $arg)
539: {
540: if(is_string($arg))
541: {
542: if(strpos($arg,'?') !== false)
543: {
544: $arg = str_replace('?','<--SimpleMySQL-QuestionMark-->',$arg);
545: }
546:
547: if($this->_prepare_typ === true)
548: {
549: $arg = "'".$this->_escape($arg)."'";
550: }
551: else
552: {
553: $arg = $this->_escape($arg);
554: }
555: }
556:
557: if($arg === null)
558: {
559: $arg = 'NULL';
560: }
561:
562: $query = $this->replace_first('?', $arg, $query);
563: }
564:
565: if(strpos($query,'<--SimpleMySQL-QuestionMark-->') !== false)
566: {
567: $query = str_replace('<--SimpleMySQL-QuestionMark-->','?',$query);
568: }
569:
570: return $query;
571: }
572:
573: public function replace_first($needle , $replace , $haystack)
574: {
575: $pos = strpos($haystack, $needle);
576:
577: if ($pos === false)
578: {
579:
580: return $haystack;
581: }
582:
583: return substr_replace($haystack, $replace, $pos, strlen($needle));
584: }
585:
586: public function query($query,$die_on_error=null)
587: {
588: if(!$this->isConnected())
589: {
590: $this->connect();
591: if(!$this->isConnected()) return false;
592: }
593:
594: return $this->_query($query,$die_on_error);
595: }
596:
597: private function _query($query,$die_on_error=null)
598: {
599: $result = @$this->_mysqli->query($query);
600:
601: 602: 603:
604: if(!$result && $this->_mysqli->errno == 2006)
605: {
606: $this->_connected = false;
607: $this->connect();
608:
609: $result = $this->_mysqli->query($query);
610: }
611:
612: if(
613: !$result &&
614: ($die_on_error === null && $this->_settings['die_on_error']) OR
615: $die_on_error
616: )
617: {
618: throw new \Exception($this->_mysqli->error,$this->_mysqli->errno);
619:
620: }
621:
622: return new \Simpletools\Db\Mysql\Result($result,$this->_mysqli);
623: }
624:
625:
626: public function escape($string)
627: {
628: if(!$this->isConnected())
629: {
630: $this->connect();
631: if(!$this->isConnected()) return false;
632: }
633:
634: return $this->_escape($string);
635: }
636:
637: private function _escape($string)
638: {
639: if($this->_quotes_on)
640: {
641: $string = stripslashes($string);
642: }
643:
644: return $this->_mysqli->real_escape_string($string);
645: }
646:
647:
648: public function getInsertedId()
649: {
650: return $this->_mysqli->insert_id;
651: }
652:
653: public function getAffectedRows()
654: {
655: return $this->_mysqli->affected_rows;
656: }
657:
658:
659: public function affectedRows()
660: {
661: return $this->getAffectedRows();
662: }
663:
664: public function fetch($result,$returnObject=true)
665: {
666: return $result->fetch($returnObject);
667:
668: 669: 670: 671: 672: 673: 674: 675:
676: }
677:
678: public function fetchAll($result,$returnObject=true)
679: {
680: return $result->fetchAll($returnObject);
681:
682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693:
694: }
695:
696: public function free($result)
697: {
698: $result->free();
699: 700: 701: 702: 703:
704: }
705:
706: public function getNumRows($result)
707: {
708: return $result->length();
709:
710: 711: 712: 713: 714:
715: }
716:
717:
718: public function checkResult($result)
719: {
720: return $result->isEmpty();
721:
722: 723: 724: 725: 726:
727: }
728:
729: public function isEmpty($result)
730: {
731: return $result->isEmpty();
732: }
733:
734: public function isConnected()
735: {
736: if($this->getConnectionStatus() !== false)
737: {
738: return true;
739: }
740: else
741: {
742: return false;
743: }
744: }
745:
746: public function getInstanceOfModel($modelName,$initArgs=null,$namespace='')
747: {
748: $class = $namespace ? $namespace.'\\'.$modelName.'Model' : $modelName.'Model';
749:
750: if($namespace)
751: {
752: $path = $this->_modelDir.str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$modelName.'.php';
753: }
754: else
755: {
756: $path = $this->_modelDir.'/'.$modelName.'.php';
757: }
758:
759: if(!class_exists($class)) require($path);
760:
761: $obj = new $class($this->_settings);
762:
763: if($obj instanceof \Simpletools\Db\Mysql\Model)
764: $obj->setMysqliClass($this->_settings['custom_mysqli_class_name']);
765:
766: if(is_callable(array($obj,'init')))
767: {
768: call_user_func_array(array($obj,'init'),$initArgs);
769: }
770:
771: return $obj;
772: }
773:
774: public function isPost($id=false)
775: {
776: if(!$id)
777: return (count($_POST) === 0) ? false : true;
778: else
779: return isset($_POST[$id]);
780: }
781:
782: public function isQuery($id=false)
783: {
784: if(!$id)
785: return (count($_GET) === 0) ? false : true;
786: else
787: return isset($_GET[$id]);
788: }
789:
790: public function isRequest($id=false)
791: {
792: if(!$id)
793: return (count($_REQUEST) === 0) ? false : true;
794: else
795: return isset($_REQUEST[$id]);
796: }
797:
798: public function getQuery($id=null)
799: {
800: if($id==null) return $_GET;
801: return isset($_GET[$id]) ? $_GET[$id] : null;
802: }
803:
804: public function getPost($id=null)
805: {
806: if($id==null) return $_POST;
807: return isset($_POST[$id]) ? $_POST[$id] : null;
808: }
809:
810: public function getRequest($id=null)
811: {
812: if($id==null) return $_REQUEST;
813: return isset($_REQUEST[$id]) ? $_REQUEST[$id] : null;
814: }
815:
816: public function getIterator($query,$params=array())
817: {
818: if(!$query) return false;
819:
820: $query = trim($query);
821:
822: preg_match('/(\w+)\s*('.implode('|',array(
823: '\=', '\>', '\<', '\>\=', '\<\=', '\<\>', '\!\='
824: )).')\s*\:\:(\w+)/i',$query,$matches);
825:
826: if(!isset($matches[1]) OR !isset($matches[3]) OR !$matches[1]) return false;
827:
828: $settings['query'] = trim(str_replace('::'.$matches[3],'::',$query));
829: $settings['start'] = $matches[3];
830: $settings['iteratorField'] = $matches[1];
831: $settings['iteratorDirection'] = $matches[2];
832: $settings['params'] = $params;
833:
834: return new \Simpletools\Db\Mysql\Iterator($this,$settings);
835: }
836: }
837:
838: ?>