Db.class.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2009 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. // $Id$
  12. define('CLIENT_MULTI_RESULTS', 131072);
  13. /**
  14. +------------------------------------------------------------------------------
  15. * ThinkPHP 简洁模式数据库中间层实现类
  16. * 只支持mysql
  17. +------------------------------------------------------------------------------
  18. */
  19. class Db extends Think
  20. {
  21. static private $_instance = null;
  22. // 是否自动释放查询结果
  23. protected $autoFree = false;
  24. // 是否显示调试信息 如果启用会在日志文件记录sql语句
  25. public $debug = false;
  26. // 是否使用永久连接
  27. protected $pconnect = false;
  28. // 当前SQL指令
  29. protected $queryStr = '';
  30. // 最后插入ID
  31. protected $lastInsID = null;
  32. // 返回或者影响记录数
  33. protected $numRows = 0;
  34. // 返回字段数
  35. protected $numCols = 0;
  36. // 事务指令数
  37. protected $transTimes = 0;
  38. // 错误信息
  39. protected $error = '';
  40. // 当前连接ID
  41. protected $linkID = null;
  42. // 当前查询ID
  43. protected $queryID = null;
  44. // 是否已经连接数据库
  45. protected $connected = false;
  46. // 数据库连接参数配置
  47. protected $config = '';
  48. // SQL 执行时间记录
  49. protected $beginTime;
  50. // 数据库表达式
  51. protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE');
  52. // 查询表达式
  53. protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%';
  54. /**
  55. +----------------------------------------------------------
  56. * 架构函数
  57. +----------------------------------------------------------
  58. * @access public
  59. +----------------------------------------------------------
  60. * @param array $config 数据库配置数组
  61. +----------------------------------------------------------
  62. */
  63. public function __construct($config=''){
  64. if ( !extension_loaded('mysql') ) {
  65. throw_exception(L('_NOT_SUPPERT_').':mysql');
  66. }
  67. $this->config = $this->parseConfig($config);
  68. }
  69. /**
  70. +----------------------------------------------------------
  71. * 连接数据库方法
  72. +----------------------------------------------------------
  73. * @access public
  74. +----------------------------------------------------------
  75. * @throws ThinkExecption
  76. +----------------------------------------------------------
  77. */
  78. public function connect() {
  79. if(!$this->connected) {
  80. $config = $this->config;
  81. // 处理不带端口号的socket连接情况
  82. $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":'');
  83. if($this->pconnect) {
  84. $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS);
  85. }else{
  86. $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS);
  87. }
  88. if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) {
  89. throw_exception(mysql_error());
  90. }
  91. $dbVersion = mysql_get_server_info($this->linkID);
  92. if ($dbVersion >= "4.1") {
  93. //使用UTF8存取数据库 需要mysql 4.1.0以上支持
  94. mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID);
  95. }
  96. //设置 sql_model
  97. if($dbVersion >'5.0.1'){
  98. mysql_query("SET sql_mode=''",$this->linkID);
  99. }
  100. // 标记连接成功
  101. $this->connected = true;
  102. // 注销数据库连接配置信息
  103. unset($this->config);
  104. }
  105. }
  106. /**
  107. +----------------------------------------------------------
  108. * 释放查询结果
  109. +----------------------------------------------------------
  110. * @access public
  111. +----------------------------------------------------------
  112. */
  113. public function free() {
  114. mysql_free_result($this->queryID);
  115. $this->queryID = 0;
  116. }
  117. /**
  118. +----------------------------------------------------------
  119. * 执行查询 主要针对 SELECT, SHOW 等指令
  120. * 返回数据集
  121. +----------------------------------------------------------
  122. * @access public
  123. +----------------------------------------------------------
  124. * @param string $str sql指令
  125. +----------------------------------------------------------
  126. * @return mixed
  127. +----------------------------------------------------------
  128. * @throws ThinkExecption
  129. +----------------------------------------------------------
  130. */
  131. public function query($str='') {
  132. $this->connect();
  133. if ( !$this->linkID ) return false;
  134. if ( $str != '' ) $this->queryStr = $str;
  135. //释放前次的查询结果
  136. if ( $this->queryID ) { $this->free(); }
  137. $this->Q(1);
  138. $this->queryID = mysql_query($this->queryStr, $this->linkID);
  139. $this->debug();
  140. if ( !$this->queryID ) {
  141. if ( $this->debug )
  142. throw_exception($this->error());
  143. else
  144. return false;
  145. } else {
  146. $this->numRows = mysql_num_rows($this->queryID);
  147. return $this->getAll();
  148. }
  149. }
  150. /**
  151. +----------------------------------------------------------
  152. * 执行语句 针对 INSERT, UPDATE 以及DELETE
  153. +----------------------------------------------------------
  154. * @access public
  155. +----------------------------------------------------------
  156. * @param string $str sql指令
  157. +----------------------------------------------------------
  158. * @return integer
  159. +----------------------------------------------------------
  160. * @throws ThinkExecption
  161. +----------------------------------------------------------
  162. */
  163. public function execute($str='') {
  164. $this->connect();
  165. if ( !$this->linkID ) return false;
  166. if ( $str != '' ) $this->queryStr = $str;
  167. //释放前次的查询结果
  168. if ( $this->queryID ) { $this->free(); }
  169. $this->W(1);
  170. $result = mysql_query($this->queryStr, $this->linkID) ;
  171. $this->debug();
  172. if ( false === $result) {
  173. if ( $this->debug )
  174. throw_exception($this->error());
  175. else
  176. return false;
  177. } else {
  178. $this->numRows = mysql_affected_rows($this->linkID);
  179. $this->lastInsID = mysql_insert_id($this->linkID);
  180. return $this->numRows;
  181. }
  182. }
  183. /**
  184. +----------------------------------------------------------
  185. * 启动事务
  186. +----------------------------------------------------------
  187. * @access public
  188. +----------------------------------------------------------
  189. * @return void
  190. +----------------------------------------------------------
  191. * @throws ThinkExecption
  192. +----------------------------------------------------------
  193. */
  194. public function startTrans() {
  195. $this->connect(true);
  196. if ( !$this->linkID ) return false;
  197. //数据rollback 支持
  198. if ($this->transTimes == 0) {
  199. mysql_query('START TRANSACTION', $this->linkID);
  200. }
  201. $this->transTimes++;
  202. return ;
  203. }
  204. /**
  205. +----------------------------------------------------------
  206. * 用于非自动提交状态下面的查询提交
  207. +----------------------------------------------------------
  208. * @access public
  209. +----------------------------------------------------------
  210. * @return boolen
  211. +----------------------------------------------------------
  212. * @throws ThinkExecption
  213. +----------------------------------------------------------
  214. */
  215. public function commit()
  216. {
  217. if ($this->transTimes > 0) {
  218. $result = mysql_query('COMMIT', $this->linkID);
  219. $this->transTimes = 0;
  220. if(!$result){
  221. throw_exception($this->error());
  222. return false;
  223. }
  224. }
  225. return true;
  226. }
  227. /**
  228. +----------------------------------------------------------
  229. * 事务回滚
  230. +----------------------------------------------------------
  231. * @access public
  232. +----------------------------------------------------------
  233. * @return boolen
  234. +----------------------------------------------------------
  235. * @throws ThinkExecption
  236. +----------------------------------------------------------
  237. */
  238. public function rollback()
  239. {
  240. if ($this->transTimes > 0) {
  241. $result = mysql_query('ROLLBACK', $this->linkID);
  242. $this->transTimes = 0;
  243. if(!$result){
  244. throw_exception($this->error());
  245. return false;
  246. }
  247. }
  248. return true;
  249. }
  250. /**
  251. +----------------------------------------------------------
  252. * 获得所有的查询数据
  253. +----------------------------------------------------------
  254. * @access public
  255. +----------------------------------------------------------
  256. * @return array
  257. +----------------------------------------------------------
  258. * @throws ThinkExecption
  259. +----------------------------------------------------------
  260. */
  261. public function getAll() {
  262. if ( !$this->queryID ) {
  263. throw_exception($this->error());
  264. return false;
  265. }
  266. //返回数据集
  267. $result = array();
  268. if($this->numRows >0) {
  269. while($row = mysql_fetch_assoc($this->queryID)){
  270. $result[] = $row;
  271. }
  272. mysql_data_seek($this->queryID,0);
  273. }
  274. return $result;
  275. }
  276. /**
  277. +----------------------------------------------------------
  278. * 关闭数据库
  279. +----------------------------------------------------------
  280. * @access public
  281. +----------------------------------------------------------
  282. * @throws ThinkExecption
  283. +----------------------------------------------------------
  284. */
  285. public function close() {
  286. if (!empty($this->queryID))
  287. mysql_free_result($this->queryID);
  288. if ($this->linkID && !mysql_close($this->linkID)){
  289. throw_exception($this->error());
  290. }
  291. $this->linkID = 0;
  292. }
  293. /**
  294. +----------------------------------------------------------
  295. * 数据库错误信息
  296. * 并显示当前的SQL语句
  297. +----------------------------------------------------------
  298. * @access public
  299. +----------------------------------------------------------
  300. * @return string
  301. +----------------------------------------------------------
  302. */
  303. public function error() {
  304. $this->error = mysql_error($this->linkID);
  305. if($this->queryStr!=''){
  306. $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
  307. }
  308. return $this->error;
  309. }
  310. /**
  311. +----------------------------------------------------------
  312. * SQL指令安全过滤
  313. +----------------------------------------------------------
  314. * @access public
  315. +----------------------------------------------------------
  316. * @param string $str SQL字符串
  317. +----------------------------------------------------------
  318. * @return string
  319. +----------------------------------------------------------
  320. */
  321. public function escape_string($str) {
  322. return mysql_escape_string($str);
  323. }
  324. /**
  325. +----------------------------------------------------------
  326. * 析构方法
  327. +----------------------------------------------------------
  328. * @access public
  329. +----------------------------------------------------------
  330. */
  331. public function __destruct()
  332. {
  333. // 关闭连接
  334. $this->close();
  335. }
  336. /**
  337. +----------------------------------------------------------
  338. * 取得数据库类实例
  339. +----------------------------------------------------------
  340. * @static
  341. * @access public
  342. +----------------------------------------------------------
  343. * @return mixed 返回数据库驱动类
  344. +----------------------------------------------------------
  345. */
  346. public static function getInstance($db_config='')
  347. {
  348. if ( self::$_instance==null ){
  349. self::$_instance = new Db($db_config);
  350. }
  351. return self::$_instance;
  352. }
  353. /**
  354. +----------------------------------------------------------
  355. * 分析数据库配置信息,支持数组和DSN
  356. +----------------------------------------------------------
  357. * @access private
  358. +----------------------------------------------------------
  359. * @param mixed $db_config 数据库配置信息
  360. +----------------------------------------------------------
  361. * @return string
  362. +----------------------------------------------------------
  363. */
  364. private function parseConfig($db_config='') {
  365. if ( !empty($db_config) && is_string($db_config)) {
  366. // 如果DSN字符串则进行解析
  367. $db_config = $this->parseDSN($db_config);
  368. }else if(empty($db_config)){
  369. // 如果配置为空,读取配置文件设置
  370. $db_config = array (
  371. 'dbms' => C('DB_TYPE'),
  372. 'username' => C('DB_USER'),
  373. 'password' => C('DB_PWD'),
  374. 'hostname' => C('DB_HOST'),
  375. 'hostport' => C('DB_PORT'),
  376. 'database' => C('DB_NAME'),
  377. 'dsn' => C('DB_DSN'),
  378. 'params' => C('DB_PARAMS'),
  379. );
  380. }
  381. return $db_config;
  382. }
  383. /**
  384. +----------------------------------------------------------
  385. * DSN解析
  386. * 格式: mysql://username:passwd@localhost:3306/DbName
  387. +----------------------------------------------------------
  388. * @static
  389. * @access public
  390. +----------------------------------------------------------
  391. * @param string $dsnStr
  392. +----------------------------------------------------------
  393. * @return array
  394. +----------------------------------------------------------
  395. */
  396. public function parseDSN($dsnStr)
  397. {
  398. if( empty($dsnStr) ){return false;}
  399. $info = parse_url($dsnStr);
  400. if($info['scheme']){
  401. $dsn = array(
  402. 'dbms' => $info['scheme'],
  403. 'username' => isset($info['user']) ? $info['user'] : '',
  404. 'password' => isset($info['pass']) ? $info['pass'] : '',
  405. 'hostname' => isset($info['host']) ? $info['host'] : '',
  406. 'hostport' => isset($info['port']) ? $info['port'] : '',
  407. 'database' => isset($info['path']) ? substr($info['path'],1) : ''
  408. );
  409. }else {
  410. preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches);
  411. $dsn = array (
  412. 'dbms' => $matches[1],
  413. 'username' => $matches[2],
  414. 'password' => $matches[3],
  415. 'hostname' => $matches[4],
  416. 'hostport' => $matches[5],
  417. 'database' => $matches[6]
  418. );
  419. }
  420. return $dsn;
  421. }
  422. /**
  423. +----------------------------------------------------------
  424. * 数据库调试 记录当前SQL
  425. +----------------------------------------------------------
  426. * @access protected
  427. +----------------------------------------------------------
  428. */
  429. protected function debug() {
  430. // 记录操作结束时间
  431. if ( $this->debug ) {
  432. $runtime = number_format(microtime(TRUE) - $this->beginTime, 6);
  433. Log::record(" RunTime:".$runtime."s SQL = ".$this->queryStr,Log::SQL);
  434. }
  435. }
  436. /**
  437. +----------------------------------------------------------
  438. * 查询次数更新或者查询
  439. +----------------------------------------------------------
  440. * @access public
  441. +----------------------------------------------------------
  442. * @param mixed $times
  443. +----------------------------------------------------------
  444. * @return void
  445. +----------------------------------------------------------
  446. */
  447. public function Q($times='') {
  448. static $_times = 0;
  449. if(empty($times)) {
  450. return $_times;
  451. }else{
  452. $_times++;
  453. // 记录开始执行时间
  454. $this->beginTime = microtime(TRUE);
  455. }
  456. }
  457. /**
  458. +----------------------------------------------------------
  459. * 写入次数更新或者查询
  460. +----------------------------------------------------------
  461. * @access public
  462. +----------------------------------------------------------
  463. * @param mixed $times
  464. +----------------------------------------------------------
  465. * @return void
  466. +----------------------------------------------------------
  467. */
  468. public function W($times='') {
  469. static $_times = 0;
  470. if(empty($times)) {
  471. return $_times;
  472. }else{
  473. $_times++;
  474. // 记录开始执行时间
  475. $this->beginTime = microtime(TRUE);
  476. }
  477. }
  478. /**
  479. +----------------------------------------------------------
  480. * 获取最近一次查询的sql语句
  481. +----------------------------------------------------------
  482. * @access public
  483. +----------------------------------------------------------
  484. * @return string
  485. +----------------------------------------------------------
  486. */
  487. public function getLastSql() {
  488. return $this->queryStr;
  489. }
  490. }//类定义结束
  491. ?>