DbMysqli.class.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2007 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. defined('THINK_PATH') or exit();
  12. /**
  13. * Mysqli数据库驱动类
  14. * @category Think
  15. * @package Think
  16. * @subpackage Driver.Db
  17. * @author liu21st <liu21st@gmail.com>
  18. */
  19. class DbMysqli extends Db{
  20. /**
  21. * 架构函数 读取数据库配置信息
  22. * @access public
  23. * @param array $config 数据库配置数组
  24. */
  25. public function __construct($config=''){
  26. if ( !extension_loaded('mysqli') ) {
  27. throw_exception(L('_NOT_SUPPERT_').':mysqli');
  28. }
  29. if(!empty($config)) {
  30. $this->config = $config;
  31. if(empty($this->config['params'])) {
  32. $this->config['params'] = '';
  33. }
  34. }
  35. }
  36. /**
  37. * 连接数据库方法
  38. * @access public
  39. * @throws ThinkExecption
  40. */
  41. public function connect($config='',$linkNum=0) {
  42. if ( !isset($this->linkID[$linkNum]) ) {
  43. if(empty($config)) $config = $this->config;
  44. $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306);
  45. if (mysqli_connect_errno()) throw_exception(mysqli_connect_error());
  46. $dbVersion = $this->linkID[$linkNum]->server_version;
  47. // 设置数据库编码
  48. $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'");
  49. //设置 sql_model
  50. if($dbVersion >'5.0.1'){
  51. $this->linkID[$linkNum]->query("SET sql_mode=''");
  52. }
  53. // 标记连接成功
  54. $this->connected = true;
  55. //注销数据库安全信息
  56. if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
  57. }
  58. return $this->linkID[$linkNum];
  59. }
  60. /**
  61. * 释放查询结果
  62. * @access public
  63. */
  64. public function free() {
  65. $this->queryID->free_result();
  66. $this->queryID = null;
  67. }
  68. /**
  69. * 执行查询 返回数据集
  70. * @access public
  71. * @param string $str sql指令
  72. * @return mixed
  73. */
  74. public function query($str) {
  75. $this->initConnect(false);
  76. if ( !$this->_linkID ) return false;
  77. $this->queryStr = $str;
  78. //释放前次的查询结果
  79. if ( $this->queryID ) $this->free();
  80. N('db_query',1);
  81. // 记录开始执行时间
  82. G('queryStartTime');
  83. $this->queryID = $this->_linkID->query($str);
  84. // 对存储过程改进
  85. if( $this->_linkID->more_results() ){
  86. while (($res = $this->_linkID->next_result()) != NULL) {
  87. $res->free_result();
  88. }
  89. }
  90. $this->debug();
  91. if ( false === $this->queryID ) {
  92. $this->error();
  93. return false;
  94. } else {
  95. $this->numRows = $this->queryID->num_rows;
  96. $this->numCols = $this->queryID->field_count;
  97. return $this->getAll();
  98. }
  99. }
  100. /**
  101. * 执行语句
  102. * @access public
  103. * @param string $str sql指令
  104. * @return integer
  105. */
  106. public function execute($str) {
  107. $this->initConnect(true);
  108. if ( !$this->_linkID ) return false;
  109. $this->queryStr = $str;
  110. //释放前次的查询结果
  111. if ( $this->queryID ) $this->free();
  112. N('db_write',1);
  113. // 记录开始执行时间
  114. G('queryStartTime');
  115. $result = $this->_linkID->query($str);
  116. $this->debug();
  117. if ( false === $result ) {
  118. $this->error();
  119. return false;
  120. } else {
  121. $this->numRows = $this->_linkID->affected_rows;
  122. $this->lastInsID = $this->_linkID->insert_id;
  123. return $this->numRows;
  124. }
  125. }
  126. /**
  127. * 启动事务
  128. * @access public
  129. * @return void
  130. */
  131. public function startTrans() {
  132. $this->initConnect(true);
  133. //数据rollback 支持
  134. if ($this->transTimes == 0) {
  135. $this->_linkID->autocommit(false);
  136. }
  137. $this->transTimes++;
  138. return ;
  139. }
  140. /**
  141. * 用于非自动提交状态下面的查询提交
  142. * @access public
  143. * @return boolen
  144. */
  145. public function commit() {
  146. if ($this->transTimes > 0) {
  147. $result = $this->_linkID->commit();
  148. $this->_linkID->autocommit( true);
  149. $this->transTimes = 0;
  150. if(!$result){
  151. $this->error();
  152. return false;
  153. }
  154. }
  155. return true;
  156. }
  157. /**
  158. * 事务回滚
  159. * @access public
  160. * @return boolen
  161. */
  162. public function rollback() {
  163. if ($this->transTimes > 0) {
  164. $result = $this->_linkID->rollback();
  165. $this->transTimes = 0;
  166. if(!$result){
  167. $this->error();
  168. return false;
  169. }
  170. }
  171. return true;
  172. }
  173. /**
  174. * 获得所有的查询数据
  175. * @access private
  176. * @param string $sql sql语句
  177. * @return array
  178. */
  179. private function getAll() {
  180. //返回数据集
  181. $result = array();
  182. if($this->numRows>0) {
  183. //返回数据集
  184. for($i=0;$i<$this->numRows ;$i++ ){
  185. $result[$i] = $this->queryID->fetch_assoc();
  186. }
  187. $this->queryID->data_seek(0);
  188. }
  189. return $result;
  190. }
  191. /**
  192. * 取得数据表的字段信息
  193. * @access public
  194. * @return array
  195. */
  196. public function getFields($tableName) {
  197. $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName));
  198. $info = array();
  199. if($result) {
  200. foreach ($result as $key => $val) {
  201. $info[$val['Field']] = array(
  202. 'name' => $val['Field'],
  203. 'type' => $val['Type'],
  204. 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
  205. 'default' => $val['Default'],
  206. 'primary' => (strtolower($val['Key']) == 'pri'),
  207. 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
  208. );
  209. }
  210. }
  211. return $info;
  212. }
  213. /**
  214. * 取得数据表的字段信息
  215. * @access public
  216. * @return array
  217. */
  218. public function getTables($dbName='') {
  219. $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES ';
  220. $result = $this->query($sql);
  221. $info = array();
  222. if($result) {
  223. foreach ($result as $key => $val) {
  224. $info[$key] = current($val);
  225. }
  226. }
  227. return $info;
  228. }
  229. /**
  230. * 替换记录
  231. * @access public
  232. * @param mixed $data 数据
  233. * @param array $options 参数表达式
  234. * @return false | integer
  235. */
  236. public function replace($data,$options=array()) {
  237. foreach ($data as $key=>$val){
  238. $value = $this->parseValue($val);
  239. if(is_scalar($value)) { // 过滤非标量数据
  240. $values[] = $value;
  241. $fields[] = $this->parseKey($key);
  242. }
  243. }
  244. $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
  245. return $this->execute($sql);
  246. }
  247. /**
  248. * 插入记录
  249. * @access public
  250. * @param mixed $datas 数据
  251. * @param array $options 参数表达式
  252. * @param boolean $replace 是否replace
  253. * @return false | integer
  254. */
  255. public function insertAll($datas,$options=array(),$replace=false) {
  256. if(!is_array($datas[0])) return false;
  257. $fields = array_keys($datas[0]);
  258. array_walk($fields, array($this, 'parseKey'));
  259. $values = array();
  260. foreach ($datas as $data){
  261. $value = array();
  262. foreach ($data as $key=>$val){
  263. $val = $this->parseValue($val);
  264. if(is_scalar($val)) { // 过滤非标量数据
  265. $value[] = $val;
  266. }
  267. }
  268. $values[] = '('.implode(',', $value).')';
  269. }
  270. $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values);
  271. return $this->execute($sql);
  272. }
  273. /**
  274. * 关闭数据库
  275. * @access public
  276. * @return volid
  277. */
  278. public function close() {
  279. if ($this->_linkID){
  280. $this->_linkID->close();
  281. }
  282. $this->_linkID = null;
  283. }
  284. /**
  285. * 数据库错误信息
  286. * 并显示当前的SQL语句
  287. * @static
  288. * @access public
  289. * @return string
  290. */
  291. public function error() {
  292. $this->error = $this->_linkID->errno.':'.$this->_linkID->error;
  293. if('' != $this->queryStr){
  294. $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
  295. }
  296. trace($this->error,'','ERR');
  297. return $this->error;
  298. }
  299. /**
  300. * SQL指令安全过滤
  301. * @static
  302. * @access public
  303. * @param string $str SQL指令
  304. * @return string
  305. */
  306. public function escapeString($str) {
  307. if($this->_linkID) {
  308. return $this->_linkID->real_escape_string($str);
  309. }else{
  310. return addslashes($str);
  311. }
  312. }
  313. /**
  314. * 字段和表名处理添加`
  315. * @access protected
  316. * @param string $key
  317. * @return string
  318. */
  319. protected function parseKey(&$key) {
  320. $key = trim($key);
  321. if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
  322. $key = '`'.$key.'`';
  323. }
  324. return $key;
  325. }
  326. }