class.db.php 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. <?php
  2. /**
  3. * $db = new DB( array ( array('192.168.1.239','3306', 'socialgame', 'socialgame', '')));
  4. */
  5. class muDB{
  6. private $host;//主机
  7. private $port;//端口
  8. private $user;//用户
  9. private $password;//密码
  10. private $dbname;//db名
  11. /**
  12. * mysqli对象
  13. * @var mysqli
  14. */
  15. static private $mysqli;//mysqli对象
  16. /**
  17. * @var mysqli_stmt
  18. */
  19. static private $stmt;//预处理对象
  20. /**
  21. * 为了兼容老版 采用二维数组
  22. * 参数 array ( array('192.168.1.239:3306', 'socialgame', 'socialgame', ''))
  23. * @param unknown_type $servers
  24. */
  25. public function __construct( $servers){
  26. $servers = $servers[0];//为了兼容老版
  27. $aHost = explode(':', $servers[0]);
  28. $this->host = $aHost[0];
  29. $this->port = isset( $aHost[1]) ? $aHost[1] : '3306';//默认端口3306
  30. $this->user = $servers[1];
  31. $this->password = $servers[2];
  32. $this->dbname = $servers[3];
  33. }
  34. /**
  35. * 检查并连接数据库
  36. * @return mysqli
  37. */
  38. public function connect(){
  39. if ( isset(self::$mysqli[$this->host]) && !empty(self::$mysqli[$this->host]) && self::$mysqli[$this->host]->ping()) {//如果已经连接
  40. return self::$mysqli[$this->host];
  41. }
  42. if ( ! class_exists('mysqli')) {
  43. die('This Lib Requires The Mysqli Extention!');
  44. }
  45. self::$mysqli[$this->host] = new mysqli($this->host, $this->user, $this->password, $this->dbname, $this->port);
  46. if ( $error = mysqli_connect_error()) {
  47. $backtrace = array();
  48. $straces = debug_backtrace();
  49. foreach ((array) $straces as $k => $v)
  50. {
  51. if ($k == 0)
  52. {
  53. continue;
  54. }
  55. $backtrace['backtrace'][$k]['file'] = $v['file'];
  56. $backtrace['backtrace'][$k]['line'] = $v['line'];
  57. $backtrace['backtrace'][$k]['function'] = $v['function'];
  58. $backtrace['backtrace'][$k]['args'] = $v['args'];
  59. }
  60. $errstr .= "backtrace:".var_export($backtrace, true);
  61. $this->errorlog( $error, "host:{$this->host},user:{$this->user},pwd:{$this->password},dbname:{$this->dbname},port:{$this->port},strace:{$errstr}");
  62. }
  63. self::$mysqli[$this->host]->query("SET SQL_MODE=''");
  64. // self::$mysqli[$this->host]->query("SET SQL_MODE='',CHARACTER_SET_CONNECTION='utf8',CHARACTER_SET_RESULTS='utf8',CHARACTER_SET_CLIENT='binary',NAMES 'utf8'");
  65. return self::$mysqli[$this->host];
  66. }
  67. /**
  68. * 执行sql
  69. * @param string $query
  70. public function query( $query){
  71. $this->connect();
  72. $result = self::$mysqli[$this->host]->query( $query);
  73. $error = mysqli_error( self::$mysqli[$this->host]);
  74. if ( $error) {
  75. $this->errorlog( $error, $query);
  76. }
  77. return $result;
  78. }
  79. */
  80. public function query( $query , $showError = true, &$rows = 0){
  81. $s = oo::getMsectime();
  82. $this->connect();
  83. $result = self::$mysqli[$this->host]->query( $query);
  84. $rows = self::$mysqli[$this->host]->affected_rows;
  85. $error = mysqli_error( self::$mysqli[$this->host]);
  86. if ( $error ) {
  87. $this->errorlog( $error, $query , $showError);
  88. }
  89. $e = oo::getMsectime();
  90. if($e - $s > 2000){
  91. //记录数据表查询日志,排查掉线问题
  92. oo::logs()->debug3(['query' => $query, 'expend_ts'=>($e-$s)], 'db_query');
  93. }
  94. return $result;
  95. }
  96. public function numRows($result=null){ //Return number of rows in selected table
  97. if( is_object( $result)){
  98. return $result->num_rows;
  99. }
  100. return 0;
  101. }
  102. //查询一条记录
  103. public function getOne($query, $mode = MYSQLI_ASSOC){
  104. $result = $this->query($query);
  105. if ( ! is_object( $result)) {
  106. return array();
  107. }
  108. $re = $result->fetch_array( $mode);
  109. if ( ! is_array($re)) {
  110. $re = array();
  111. }
  112. return $re;
  113. }
  114. //查询多条记录
  115. public function getAll($query, $mode = MYSQLI_ASSOC){
  116. $result = $this->query($query);
  117. if ( ! is_object( $result)) {
  118. return array();
  119. }
  120. $dataList = array();
  121. while ($row = $result->fetch_array( $mode)) {
  122. $dataList[] = $row;
  123. }
  124. return $dataList;
  125. }
  126. /**
  127. * 缓存多行数据
  128. */
  129. public function getCacheAll($sql, $expire, $mode=MYSQLI_ASSOC, $key=false){
  130. $key = $key===false ? md5($sql) : $key;
  131. if( ($temp = ocache::cache()->get($key)) === false){
  132. $temp = $this->getAll($sql, $mode);
  133. ocache::cache()->set($key, $temp, $expire);
  134. }
  135. return $temp;
  136. }
  137. /**
  138. * 缓存一行数据
  139. */
  140. public function getCacheOne($sql, $expire, $mode=MYSQLI_ASSOC, $key=false){
  141. $key = $key===false ? md5($sql) : $key;
  142. if( ($temp = ocache::cache()->get($key)) === false){
  143. $temp = $this->getOne($sql, $mode);
  144. ocache::cache()->set($key, $temp, $expire);
  145. }
  146. return $temp;
  147. }
  148. public function fetchArray($result=null,$mode=MYSQLI_ASSOC){
  149. if ( ! is_object($result)) {
  150. return array();
  151. }
  152. $row = $result->fetch_array( $mode);
  153. return is_array($row) ? $row : array();
  154. }
  155. public function fetchAssoc($result=null){
  156. if ( ! is_object($result)) {
  157. return array();
  158. }
  159. $row = $result->fetch_assoc();
  160. return is_array($row) ? $row : array();
  161. }
  162. //获取最新插入的记录ID
  163. public function insertID(){
  164. return self::$mysqli[$this->host]->insert_id;
  165. }
  166. /**
  167. *
  168. * sql执行的影响行数
  169. */
  170. public function affectedRows(){
  171. return self::$mysqli[$this->host]->affected_rows;
  172. }
  173. /**
  174. *
  175. * 关闭数据库
  176. */
  177. public function close(){
  178. self::$mysqli[$this->host]->close();
  179. unset(self::$mysqli[$this->host]);
  180. }
  181. /**
  182. * 安全性检测.调用escape存入的,一定要调unescape取出
  183. */
  184. public function escape( $string){
  185. if ( oo::functions()->isPhpVersion()) {
  186. return addslashes( trim($string));
  187. }
  188. return mysql_escape_string( trim($string));
  189. }
  190. public function unescape( $string){
  191. return stripslashes( $string);
  192. }
  193. /**
  194. * 事务处理章节
  195. */
  196. public function Start(){
  197. $this->connect();
  198. self::$mysqli[$this->host]->autocommit( false);
  199. }
  200. /**
  201. *
  202. * 提交事务
  203. */
  204. public function Commit(){
  205. self::$mysqli[$this->host]->commit();
  206. self::$mysqli[$this->host]->autocommit( true);//恢复自动提交
  207. }
  208. public function CommitId(){
  209. $aId = $this->getOne('SELECT LAST_INSERT_ID()', MYSQL_NUM);
  210. return (int)$aId[0];
  211. }
  212. public function Rollback(){
  213. self::$mysqli[$this->host]->rollback();
  214. }
  215. /**
  216. * mysqli 预处理章节
  217. */
  218. /**
  219. * 该方法准备要执行的预处理语句
  220. * @return mysqli_stmt
  221. */
  222. public function stmtPrepare( $query){
  223. if ( ! $query) {
  224. $this->errorlog('no query');
  225. }
  226. $this->connect();
  227. self::$stmt = self::$mysqli[$this->host]->prepare( $query);
  228. return self::$stmt;
  229. }
  230. /**
  231. * ping 用于保持php和mysql连接不超时
  232. * 多用于死循环
  233. */
  234. public function ping() {
  235. if (self::$mysqli[$this->host]) {
  236. return self::$mysqli[$this->host]->ping();
  237. } else {
  238. return false;
  239. }
  240. }
  241. /**
  242. * MYSQL报错日志
  243. * @param string $msg
  244. */
  245. private function errorlog( $msg='', $query='' ,$errorDie = true){
  246. $date = date( 'Ymd');
  247. $file = FCPATH . '/deBUG/mysql/' . $date . '.php';
  248. $error = '';
  249. if ( ! is_dir( FCPATH . '/deBUG/phperror')) {
  250. mkdir( FCPATH . '/deBUG/mysql', 0775);
  251. }
  252. if ( ! file_exists( $file)) {
  253. touch($file) && chmod($file, ENVIRONMENT == 'production' ? 0664 : 0666);
  254. $error = "<?php\nexit();\n";
  255. }
  256. $query = oo::functions()->escape( $query);
  257. $error .= date('Y-m-d H:i:s') . "-- ". mysqli_errno( self::$mysqli[$this->host]) . "-- msg:". $msg . ";" . " query:". $query;
  258. $backtrace = array();
  259. $straces = debug_backtrace();
  260. foreach ((array) $straces as $k => $v)
  261. {
  262. if ($k == 0)
  263. {
  264. continue;
  265. }
  266. $backtrace['backtrace'][$k]['file'] = $v['file'];
  267. $backtrace['backtrace'][$k]['line'] = $v['line'];
  268. $backtrace['backtrace'][$k]['function'] = $v['function'];
  269. $backtrace['backtrace'][$k]['args'] = $v['args'];
  270. }
  271. $error .= "backtrace:".var_export($backtrace, true);
  272. if ( ! ENVIRONMENT == 'production') {
  273. echo $error;
  274. }
  275. @file_put_contents( $file, $error . " \n ", FILE_APPEND | LOCK_EX);
  276. // oo::funModel('logs')->debug($error, 'mysql'.$date);
  277. // if($errorDie)
  278. // die(date('Y-m-d H:i:s').'-DB Insvalid!!!');
  279. }
  280. }