Db.class.php 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  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 精简模式数据库中间层实现类 只支持Mysql
  16. +------------------------------------------------------------------------------
  17. */
  18. class Db extends Think
  19. {
  20. static private $_instance = null;
  21. // 是否自动释放查询结果
  22. protected $autoFree = false;
  23. // 是否显示调试信息 如果启用会在日志文件记录sql语句
  24. public $debug = false;
  25. // 是否使用永久连接
  26. protected $pconnect = false;
  27. // 当前SQL指令
  28. protected $queryStr = '';
  29. // 最后插入ID
  30. protected $lastInsID = null;
  31. // 返回或者影响记录数
  32. protected $numRows = 0;
  33. // 返回字段数
  34. protected $numCols = 0;
  35. // 事务指令数
  36. protected $transTimes = 0;
  37. // 错误信息
  38. protected $error = '';
  39. // 当前连接ID
  40. protected $linkID = null;
  41. // 当前查询ID
  42. protected $queryID = null;
  43. // 是否已经连接数据库
  44. protected $connected = false;
  45. // 数据库连接参数配置
  46. protected $config = '';
  47. // SQL 执行时间记录
  48. protected $beginTime;
  49. // 数据库表达式
  50. protected $comparison = array('eq'=>'=','neq'=>'!=','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE');
  51. // 查询表达式
  52. protected $selectSql = 'SELECT%DISTINCT% %FIELDS% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT%';
  53. /**
  54. +----------------------------------------------------------
  55. * 架构函数
  56. +----------------------------------------------------------
  57. * @access public
  58. +----------------------------------------------------------
  59. * @param array $config 数据库配置数组
  60. +----------------------------------------------------------
  61. */
  62. public function __construct($config=''){
  63. if ( !extension_loaded('mysql') ) {
  64. throw_exception(L('_NOT_SUPPERT_').':mysql');
  65. }
  66. $this->config = $this->parseConfig($config);
  67. }
  68. /**
  69. +----------------------------------------------------------
  70. * 连接数据库方法
  71. +----------------------------------------------------------
  72. * @access public
  73. +----------------------------------------------------------
  74. * @throws ThinkExecption
  75. +----------------------------------------------------------
  76. */
  77. public function connect() {
  78. if(!$this->connected) {
  79. $config = $this->config;
  80. // 处理不带端口号的socket连接情况
  81. $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":'');
  82. if($this->pconnect) {
  83. $this->linkID = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS);
  84. }else{
  85. $this->linkID = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS);
  86. }
  87. if ( !$this->linkID || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID)) ) {
  88. throw_exception(mysql_error());
  89. }
  90. $dbVersion = mysql_get_server_info($this->linkID);
  91. if ($dbVersion >= "4.1") {
  92. //使用UTF8存取数据库 需要mysql 4.1.0以上支持
  93. mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID);
  94. }
  95. //设置 sql_model
  96. if($dbVersion >'5.0.1'){
  97. mysql_query("SET sql_mode=''",$this->linkID);
  98. }
  99. // 标记连接成功
  100. $this->connected = true;
  101. // 注销数据库连接配置信息
  102. unset($this->config);
  103. }
  104. }
  105. /**
  106. +----------------------------------------------------------
  107. * 释放查询结果
  108. +----------------------------------------------------------
  109. * @access public
  110. +----------------------------------------------------------
  111. */
  112. public function free() {
  113. mysql_free_result($this->queryID);
  114. $this->queryID = 0;
  115. }
  116. /**
  117. +----------------------------------------------------------
  118. * 执行查询 主要针对 SELECT, SHOW 等指令
  119. * 返回数据集
  120. +----------------------------------------------------------
  121. * @access public
  122. +----------------------------------------------------------
  123. * @param string $str sql指令
  124. +----------------------------------------------------------
  125. * @return mixed
  126. +----------------------------------------------------------
  127. * @throws ThinkExecption
  128. +----------------------------------------------------------
  129. */
  130. public function query($str='') {
  131. $this->connect();
  132. if ( !$this->linkID ) return false;
  133. if ( $str != '' ) $this->queryStr = $str;
  134. //释放前次的查询结果
  135. if ( $this->queryID ) { $this->free(); }
  136. $this->Q(1);
  137. $this->queryID = mysql_query($this->queryStr, $this->linkID);
  138. $this->debug();
  139. if ( !$this->queryID ) {
  140. if ( $this->debug )
  141. throw_exception($this->error());
  142. else
  143. return false;
  144. } else {
  145. $this->numRows = mysql_num_rows($this->queryID);
  146. return $this->getAll();
  147. }
  148. }
  149. /**
  150. +----------------------------------------------------------
  151. * 执行语句 针对 INSERT, UPDATE 以及DELETE
  152. +----------------------------------------------------------
  153. * @access public
  154. +----------------------------------------------------------
  155. * @param string $str sql指令
  156. +----------------------------------------------------------
  157. * @return integer
  158. +----------------------------------------------------------
  159. * @throws ThinkExecption
  160. +----------------------------------------------------------
  161. */
  162. public function execute($str='') {
  163. $this->connect();
  164. if ( !$this->linkID ) return false;
  165. if ( $str != '' ) $this->queryStr = $str;
  166. //释放前次的查询结果
  167. if ( $this->queryID ) { $this->free(); }
  168. $this->W(1);
  169. $result = mysql_query($this->queryStr, $this->linkID) ;
  170. $this->debug();
  171. if ( false === $result) {
  172. if ( $this->debug )
  173. throw_exception($this->error());
  174. else
  175. return false;
  176. } else {
  177. $this->numRows = mysql_affected_rows($this->linkID);
  178. $this->lastInsID = mysql_insert_id($this->linkID);
  179. return $this->numRows;
  180. }
  181. }
  182. /**
  183. +----------------------------------------------------------
  184. * 启动事务
  185. +----------------------------------------------------------
  186. * @access public
  187. +----------------------------------------------------------
  188. * @return void
  189. +----------------------------------------------------------
  190. * @throws ThinkExecption
  191. +----------------------------------------------------------
  192. */
  193. public function startTrans() {
  194. $this->connect(true);
  195. if ( !$this->linkID ) return false;
  196. //数据rollback 支持
  197. if ($this->transTimes == 0) {
  198. mysql_query('START TRANSACTION', $this->linkID);
  199. }
  200. $this->transTimes++;
  201. return ;
  202. }
  203. /**
  204. +----------------------------------------------------------
  205. * 用于非自动提交状态下面的查询提交
  206. +----------------------------------------------------------
  207. * @access public
  208. +----------------------------------------------------------
  209. * @return boolen
  210. +----------------------------------------------------------
  211. * @throws ThinkExecption
  212. +----------------------------------------------------------
  213. */
  214. public function commit()
  215. {
  216. if ($this->transTimes > 0) {
  217. $result = mysql_query('COMMIT', $this->linkID);
  218. $this->transTimes = 0;
  219. if(!$result){
  220. throw_exception($this->error());
  221. return false;
  222. }
  223. }
  224. return true;
  225. }
  226. /**
  227. +----------------------------------------------------------
  228. * 事务回滚
  229. +----------------------------------------------------------
  230. * @access public
  231. +----------------------------------------------------------
  232. * @return boolen
  233. +----------------------------------------------------------
  234. * @throws ThinkExecption
  235. +----------------------------------------------------------
  236. */
  237. public function rollback()
  238. {
  239. if ($this->transTimes > 0) {
  240. $result = mysql_query('ROLLBACK', $this->linkID);
  241. $this->transTimes = 0;
  242. if(!$result){
  243. throw_exception($this->error());
  244. return false;
  245. }
  246. }
  247. return true;
  248. }
  249. /**
  250. +----------------------------------------------------------
  251. * 获得所有的查询数据
  252. +----------------------------------------------------------
  253. * @access public
  254. +----------------------------------------------------------
  255. * @return array
  256. +----------------------------------------------------------
  257. * @throws ThinkExecption
  258. +----------------------------------------------------------
  259. */
  260. public function getAll() {
  261. if ( !$this->queryID ) {
  262. throw_exception($this->error());
  263. return false;
  264. }
  265. //返回数据集
  266. $result = array();
  267. if($this->numRows >0) {
  268. while($row = mysql_fetch_assoc($this->queryID)){
  269. $result[] = $row;
  270. }
  271. mysql_data_seek($this->queryID,0);
  272. }
  273. return $result;
  274. }
  275. /**
  276. +----------------------------------------------------------
  277. * 取得数据表的字段信息
  278. +----------------------------------------------------------
  279. * @access public
  280. +----------------------------------------------------------
  281. */
  282. public function getFields($tableName) {
  283. $result = $this->query('SHOW COLUMNS FROM '.$tableName);
  284. $info = array();
  285. foreach ($result as $key => $val) {
  286. $info[$val['Field']] = array(
  287. 'name' => $val['Field'],
  288. 'type' => $val['Type'],
  289. 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
  290. 'default' => $val['Default'],
  291. 'primary' => (strtolower($val['Key']) == 'pri'),
  292. 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
  293. );
  294. }
  295. return $info;
  296. }
  297. /**
  298. +----------------------------------------------------------
  299. * 取得数据库的表信息
  300. +----------------------------------------------------------
  301. * @access public
  302. +----------------------------------------------------------
  303. */
  304. public function getTables($dbName='') {
  305. if(!empty($dbName)) {
  306. $sql = 'SHOW TABLES FROM '.$dbName;
  307. }else{
  308. $sql = 'SHOW TABLES ';
  309. }
  310. $result = $this->query($sql);
  311. $info = array();
  312. foreach ($result as $key => $val) {
  313. $info[$key] = current($val);
  314. }
  315. return $info;
  316. }
  317. /**
  318. +----------------------------------------------------------
  319. * 关闭数据库
  320. +----------------------------------------------------------
  321. * @access public
  322. +----------------------------------------------------------
  323. * @throws ThinkExecption
  324. +----------------------------------------------------------
  325. */
  326. public function close() {
  327. if (!empty($this->queryID))
  328. mysql_free_result($this->queryID);
  329. if ($this->linkID && !mysql_close($this->linkID)){
  330. throw_exception($this->error());
  331. }
  332. $this->linkID = 0;
  333. }
  334. /**
  335. +----------------------------------------------------------
  336. * 数据库错误信息
  337. * 并显示当前的SQL语句
  338. +----------------------------------------------------------
  339. * @access public
  340. +----------------------------------------------------------
  341. * @return string
  342. +----------------------------------------------------------
  343. */
  344. public function error() {
  345. $this->error = mysql_error($this->linkID);
  346. if($this->queryStr!=''){
  347. $this->error .= "\n [ SQL语句 ] : ".$this->queryStr;
  348. }
  349. return $this->error;
  350. }
  351. /**
  352. +----------------------------------------------------------
  353. * SQL指令安全过滤
  354. +----------------------------------------------------------
  355. * @access public
  356. +----------------------------------------------------------
  357. * @param string $str SQL字符串
  358. +----------------------------------------------------------
  359. * @return string
  360. +----------------------------------------------------------
  361. */
  362. public function escape_string($str) {
  363. return mysql_escape_string($str);
  364. }
  365. /**
  366. +----------------------------------------------------------
  367. * 析构方法
  368. +----------------------------------------------------------
  369. * @access public
  370. +----------------------------------------------------------
  371. */
  372. public function __destruct()
  373. {
  374. // 关闭连接
  375. $this->close();
  376. }
  377. /**
  378. +----------------------------------------------------------
  379. * 取得数据库类实例
  380. +----------------------------------------------------------
  381. * @static
  382. * @access public
  383. +----------------------------------------------------------
  384. * @return mixed 返回数据库驱动类
  385. +----------------------------------------------------------
  386. */
  387. public static function getInstance($db_config='')
  388. {
  389. if ( self::$_instance==null ){
  390. self::$_instance = new Db($db_config);
  391. }
  392. return self::$_instance;
  393. }
  394. /**
  395. +----------------------------------------------------------
  396. * 分析数据库配置信息,支持数组和DSN
  397. +----------------------------------------------------------
  398. * @access private
  399. +----------------------------------------------------------
  400. * @param mixed $db_config 数据库配置信息
  401. +----------------------------------------------------------
  402. * @return string
  403. +----------------------------------------------------------
  404. */
  405. private function parseConfig($db_config='') {
  406. if ( !empty($db_config) && is_string($db_config)) {
  407. // 如果DSN字符串则进行解析
  408. $db_config = $this->parseDSN($db_config);
  409. }else if(empty($db_config)){
  410. // 如果配置为空,读取配置文件设置
  411. $db_config = array (
  412. 'dbms' => C('DB_TYPE'),
  413. 'username' => C('DB_USER'),
  414. 'password' => C('DB_PWD'),
  415. 'hostname' => C('DB_HOST'),
  416. 'hostport' => C('DB_PORT'),
  417. 'database' => C('DB_NAME'),
  418. 'dsn' => C('DB_DSN'),
  419. 'params' => C('DB_PARAMS'),
  420. );
  421. }
  422. return $db_config;
  423. }
  424. /**
  425. +----------------------------------------------------------
  426. * DSN解析
  427. * 格式: mysql://username:passwd@localhost:3306/DbName
  428. +----------------------------------------------------------
  429. * @static
  430. * @access public
  431. +----------------------------------------------------------
  432. * @param string $dsnStr
  433. +----------------------------------------------------------
  434. * @return array
  435. +----------------------------------------------------------
  436. */
  437. public function parseDSN($dsnStr)
  438. {
  439. if( empty($dsnStr) ){return false;}
  440. $info = parse_url($dsnStr);
  441. if($info['scheme']){
  442. $dsn = array(
  443. 'dbms' => $info['scheme'],
  444. 'username' => isset($info['user']) ? $info['user'] : '',
  445. 'password' => isset($info['pass']) ? $info['pass'] : '',
  446. 'hostname' => isset($info['host']) ? $info['host'] : '',
  447. 'hostport' => isset($info['port']) ? $info['port'] : '',
  448. 'database' => isset($info['path']) ? substr($info['path'],1) : ''
  449. );
  450. }else {
  451. preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches);
  452. $dsn = array (
  453. 'dbms' => $matches[1],
  454. 'username' => $matches[2],
  455. 'password' => $matches[3],
  456. 'hostname' => $matches[4],
  457. 'hostport' => $matches[5],
  458. 'database' => $matches[6]
  459. );
  460. }
  461. return $dsn;
  462. }
  463. /**
  464. +----------------------------------------------------------
  465. * 数据库调试 记录当前SQL
  466. +----------------------------------------------------------
  467. * @access protected
  468. +----------------------------------------------------------
  469. */
  470. protected function debug() {
  471. // 记录操作结束时间
  472. if ( $this->debug ) {
  473. $runtime = number_format(microtime(TRUE) - $this->beginTime, 6);
  474. Log::record(" RunTime:".$runtime."s SQL = ".$this->queryStr,Log::SQL);
  475. }
  476. }
  477. /**
  478. +----------------------------------------------------------
  479. * 设置锁机制
  480. +----------------------------------------------------------
  481. * @access protected
  482. +----------------------------------------------------------
  483. * @return string
  484. +----------------------------------------------------------
  485. */
  486. protected function parseLock($lock=false) {
  487. if(!$lock) return '';
  488. if('ORACLE' == $this->dbType) {
  489. return ' FOR UPDATE NOWAIT ';
  490. }
  491. return ' FOR UPDATE ';
  492. }
  493. /**
  494. +----------------------------------------------------------
  495. * set分析
  496. +----------------------------------------------------------
  497. * @access protected
  498. +----------------------------------------------------------
  499. * @param array $data
  500. +----------------------------------------------------------
  501. * @return string
  502. +----------------------------------------------------------
  503. */
  504. protected function parseSet($data) {
  505. foreach ($data as $key=>$val){
  506. $value = $this->parseValue($val);
  507. if(is_scalar($value)) // 过滤非标量数据
  508. $set[] = $this->addSpecialChar($key).'='.$value;
  509. }
  510. return ' SET '.implode(',',$set);
  511. }
  512. /**
  513. +----------------------------------------------------------
  514. * value分析
  515. +----------------------------------------------------------
  516. * @access protected
  517. +----------------------------------------------------------
  518. * @param mixed $value
  519. +----------------------------------------------------------
  520. * @return string
  521. +----------------------------------------------------------
  522. */
  523. protected function parseValue($value) {
  524. if(is_string($value)) {
  525. $value = '\''.$this->escape_string($value).'\'';
  526. }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){
  527. $value = $this->escape_string($value[1]);
  528. }elseif(is_null($value)){
  529. $value = 'null';
  530. }
  531. return $value;
  532. }
  533. /**
  534. +----------------------------------------------------------
  535. * field分析
  536. +----------------------------------------------------------
  537. * @access protected
  538. +----------------------------------------------------------
  539. * @param mixed $fields
  540. +----------------------------------------------------------
  541. * @return string
  542. +----------------------------------------------------------
  543. */
  544. protected function parseField($fields) {
  545. if(is_array($fields)) {
  546. // 完善数组方式传字段名的支持
  547. // 支持 'field1'=>'field2' 这样的字段别名定义
  548. $array = array();
  549. foreach ($fields as $key=>$field){
  550. if(!is_numeric($key))
  551. $array[] = $this->addSpecialChar($key).' AS '.$this->addSpecialChar($field);
  552. else
  553. $array[] = $this->addSpecialChar($field);
  554. }
  555. $fieldsStr = implode(',', $array);
  556. }elseif(is_string($fields) && !empty($fields)) {
  557. $fieldsStr = $this->addSpecialChar($fields);
  558. }else{
  559. $fieldsStr = '*';
  560. }
  561. return $fieldsStr;
  562. }
  563. /**
  564. +----------------------------------------------------------
  565. * table分析
  566. +----------------------------------------------------------
  567. * @access protected
  568. +----------------------------------------------------------
  569. * @param mixed $table
  570. +----------------------------------------------------------
  571. * @return string
  572. +----------------------------------------------------------
  573. */
  574. protected function parseTable($tables) {
  575. if(is_string($tables))
  576. $tables = explode(',',$tables);
  577. array_walk($tables, array(&$this, 'addSpecialChar'));
  578. return implode(',',$tables);
  579. }
  580. /**
  581. +----------------------------------------------------------
  582. * where分析
  583. +----------------------------------------------------------
  584. * @access protected
  585. +----------------------------------------------------------
  586. * @param mixed $where
  587. +----------------------------------------------------------
  588. * @return string
  589. +----------------------------------------------------------
  590. */
  591. protected function parseWhere($where) {
  592. $whereStr = '';
  593. if(is_string($where)) {
  594. // 直接使用字符串条件
  595. $whereStr = $where;
  596. }else{ // 使用数组条件表达式
  597. if(array_key_exists('_logic',$where)) {
  598. // 定义逻辑运算规则 例如 OR XOR AND NOT
  599. $operate = ' '.strtoupper($where['_logic']).' ';
  600. unset($where['_logic']);
  601. }else{
  602. // 默认进行 AND 运算
  603. $operate = ' AND ';
  604. }
  605. foreach ($where as $key=>$val){
  606. $whereStr .= "( ";
  607. if(0===strpos($key,'_')) {
  608. // 解析特殊条件表达式
  609. $whereStr .= $this->parseThinkWhere($key,$val);
  610. }else{
  611. $key = $this->addSpecialChar($key);
  612. if(is_array($val)) {
  613. if(is_string($val[0])) {
  614. if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算
  615. $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);
  616. }elseif('exp'==strtolower($val[0])){ // 使用表达式
  617. $whereStr .= ' ('.$key.' '.$val[1].') ';
  618. }elseif(preg_match('/IN/i',$val[0])){ // IN 运算
  619. $zone = is_array($val[1])? implode(',',$this->parseValue($val[1])):$val[1];
  620. $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
  621. }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算
  622. $data = is_string($val[1])? explode(',',$val[1]):$val[1];
  623. $whereStr .= ' ('.$key.' BETWEEN '.$data[0].' AND '.$data[1].' )';
  624. }else{
  625. throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]);
  626. }
  627. }else {
  628. $count = count($val);
  629. if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) {
  630. $rule = strtoupper(trim($val[$count-1]));
  631. $count = $count -1;
  632. }else{
  633. $rule = 'AND';
  634. }
  635. for($i=0;$i<$count;$i++) {
  636. $data = is_array($val[$i])?$val[$i][1]:$val[$i];
  637. if('exp'==strtolower($val[$i][0])) {
  638. $whereStr .= '('.$key.' '.$data.') '.$rule.' ';
  639. }else{
  640. $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'=';
  641. $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' ';
  642. }
  643. }
  644. $whereStr = substr($whereStr,0,-4);
  645. }
  646. }else {
  647. //对字符串类型字段采用模糊匹配
  648. if(C('LIKE_MATCH_FIELDS') && preg_match('/('.C('LIKE_MATCH_FIELDS').')/i',$key)) {
  649. $val = '%'.$val.'%';
  650. $whereStr .= $key." LIKE ".$this->parseValue($val);
  651. }else {
  652. $whereStr .= $key." = ".$this->parseValue($val);
  653. }
  654. }
  655. }
  656. $whereStr .= ' )'.$operate;
  657. }
  658. $whereStr = substr($whereStr,0,-strlen($operate));
  659. }
  660. return empty($whereStr)?'':' WHERE '.$whereStr;
  661. }
  662. /**
  663. +----------------------------------------------------------
  664. * 特殊条件分析
  665. +----------------------------------------------------------
  666. * @access protected
  667. +----------------------------------------------------------
  668. * @param string $key
  669. * @param mixed $val
  670. +----------------------------------------------------------
  671. * @return string
  672. +----------------------------------------------------------
  673. */
  674. protected function parseThinkWhere($key,$val) {
  675. $whereStr = '';
  676. switch($key) {
  677. case '_string':
  678. // 字符串模式查询条件
  679. $whereStr = $val;
  680. break;
  681. case '_complex':
  682. // 复合查询条件
  683. $whereStr = substr($this->parseWhere($val),6);
  684. break;
  685. case '_query':
  686. // 字符串模式查询条件
  687. parse_str($val,$where);
  688. if(array_key_exists('_logic',$where)) {
  689. $op = ' '.strtoupper($where['_logic']).' ';
  690. unset($where['_logic']);
  691. }else{
  692. $op = ' AND ';
  693. }
  694. $array = array();
  695. foreach ($where as $field=>$data)
  696. $array[] = $this->addSpecialChar($field).' = '.$this->parseValue($data);
  697. $whereStr = implode($op,$array);
  698. break;
  699. }
  700. return $whereStr;
  701. }
  702. /**
  703. +----------------------------------------------------------
  704. * limit分析
  705. +----------------------------------------------------------
  706. * @access protected
  707. +----------------------------------------------------------
  708. * @param mixed $lmit
  709. +----------------------------------------------------------
  710. * @return string
  711. +----------------------------------------------------------
  712. */
  713. protected function parseLimit($limit) {
  714. return !empty($limit)? ' LIMIT '.$limit.' ':'';
  715. }
  716. /**
  717. +----------------------------------------------------------
  718. * join分析
  719. +----------------------------------------------------------
  720. * @access protected
  721. +----------------------------------------------------------
  722. * @param mixed $join
  723. +----------------------------------------------------------
  724. * @return string
  725. +----------------------------------------------------------
  726. */
  727. protected function parseJoin($join) {
  728. $joinStr = '';
  729. if(!empty($join)) {
  730. if(is_array($join)) {
  731. foreach ($join as $key=>$_join){
  732. if(false !== stripos($_join,'JOIN'))
  733. $joinStr .= ' '.$_join;
  734. else
  735. $joinStr .= ' LEFT JOIN ' .$_join;
  736. }
  737. }else{
  738. $joinStr .= ' LEFT JOIN ' .$join;
  739. }
  740. }
  741. return $joinStr;
  742. }
  743. /**
  744. +----------------------------------------------------------
  745. * order分析
  746. +----------------------------------------------------------
  747. * @access protected
  748. +----------------------------------------------------------
  749. * @param mixed $order
  750. +----------------------------------------------------------
  751. * @return string
  752. +----------------------------------------------------------
  753. */
  754. protected function parseOrder($order) {
  755. return !empty($order)? ' ORDER BY '.$order:'';
  756. }
  757. /**
  758. +----------------------------------------------------------
  759. * group分析
  760. +----------------------------------------------------------
  761. * @access protected
  762. +----------------------------------------------------------
  763. * @param mixed $group
  764. +----------------------------------------------------------
  765. * @return string
  766. +----------------------------------------------------------
  767. */
  768. protected function parseGroup($group)
  769. {
  770. return !empty($group)? ' GROUP BY '.$group:'';
  771. }
  772. /**
  773. +----------------------------------------------------------
  774. * having分析
  775. +----------------------------------------------------------
  776. * @access protected
  777. +----------------------------------------------------------
  778. * @param string $having
  779. +----------------------------------------------------------
  780. * @return string
  781. +----------------------------------------------------------
  782. */
  783. protected function parseHaving($having)
  784. {
  785. return !empty($having)? ' HAVING '.$having:'';
  786. }
  787. /**
  788. +----------------------------------------------------------
  789. * distinct分析
  790. +----------------------------------------------------------
  791. * @access protected
  792. +----------------------------------------------------------
  793. * @param mixed $distinct
  794. +----------------------------------------------------------
  795. * @return string
  796. +----------------------------------------------------------
  797. */
  798. protected function parseDistinct($distinct) {
  799. return !empty($distinct)? ' DISTINCT ' :'';
  800. }
  801. /**
  802. +----------------------------------------------------------
  803. * 插入记录
  804. +----------------------------------------------------------
  805. * @access public
  806. +----------------------------------------------------------
  807. * @param mixed $data 数据
  808. * @param array $options 参数表达式
  809. +----------------------------------------------------------
  810. * @return false | integer
  811. +----------------------------------------------------------
  812. */
  813. public function insert($data,$options=array()) {
  814. foreach ($data as $key=>$val){
  815. $value = $this->parseValue($val);
  816. if(is_scalar($value)) { // 过滤非标量数据
  817. $values[] = $value;
  818. $fields[] = $this->addSpecialChar($key);
  819. }
  820. }
  821. $sql = 'INSERT INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
  822. $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
  823. return $this->execute($sql);
  824. }
  825. /**
  826. +----------------------------------------------------------
  827. * 更新记录
  828. +----------------------------------------------------------
  829. * @access public
  830. +----------------------------------------------------------
  831. * @param mixed $data 数据
  832. * @param array $options 表达式
  833. +----------------------------------------------------------
  834. * @return false | integer
  835. +----------------------------------------------------------
  836. */
  837. public function update($data,$options) {
  838. $sql = 'UPDATE '
  839. .$this->parseTable($options['table'])
  840. .$this->parseSet($data)
  841. .$this->parseWhere(isset($options['where'])?$options['where']:'')
  842. .$this->parseOrder(isset($options['order'])?$options['order']:'')
  843. .$this->parseLimit(isset($options['limit'])?$options['limit']:'')
  844. .$this->parseLock(isset($options['lock'])?$options['lock']:false);
  845. return $this->execute($sql);
  846. }
  847. /**
  848. +----------------------------------------------------------
  849. * 删除记录
  850. +----------------------------------------------------------
  851. * @access public
  852. +----------------------------------------------------------
  853. * @param array $options 表达式
  854. +----------------------------------------------------------
  855. * @return false | integer
  856. +----------------------------------------------------------
  857. */
  858. public function delete($options=array())
  859. {
  860. $sql = 'DELETE FROM '
  861. .$this->parseTable($options['table'])
  862. .$this->parseWhere(isset($options['where'])?$options['where']:'')
  863. .$this->parseOrder(isset($options['order'])?$options['order']:'')
  864. .$this->parseLimit(isset($options['limit'])?$options['limit']:'')
  865. .$this->parseLock(isset($options['lock'])?$options['lock']:false);
  866. return $this->execute($sql);
  867. }
  868. /**
  869. +----------------------------------------------------------
  870. * 查找记录
  871. +----------------------------------------------------------
  872. * @access public
  873. +----------------------------------------------------------
  874. * @param array $options 表达式
  875. +----------------------------------------------------------
  876. * @return array
  877. +----------------------------------------------------------
  878. */
  879. public function select($options=array()) {
  880. if(isset($options['page'])) {
  881. // 根据页数计算limit
  882. list($page,$listRows) = explode(',',$options['page']);
  883. $listRows = $listRows?$listRows:($options['limit']?$options['limit']:20);
  884. $offset = $listRows*((int)$page-1);
  885. $options['limit'] = $offset.','.$listRows;
  886. }
  887. $sql = str_replace(
  888. array('%TABLE%','%DISTINCT%','%FIELDS%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%'),
  889. array(
  890. $this->parseTable($options['table']),
  891. $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
  892. $this->parseField(isset($options['field'])?$options['field']:'*'),
  893. $this->parseJoin(isset($options['join'])?$options['join']:''),
  894. $this->parseWhere(isset($options['where'])?$options['where']:''),
  895. $this->parseGroup(isset($options['group'])?$options['group']:''),
  896. $this->parseHaving(isset($options['having'])?$options['having']:''),
  897. $this->parseOrder(isset($options['order'])?$options['order']:''),
  898. $this->parseLimit(isset($options['limit'])?$options['limit']:'')
  899. ),$this->selectSql);
  900. $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
  901. return $this->query($sql);
  902. }
  903. /**
  904. +----------------------------------------------------------
  905. * 字段和表名添加`
  906. * 保证指令中使用关键字不出错 针对mysql
  907. +----------------------------------------------------------
  908. * @access protected
  909. +----------------------------------------------------------
  910. * @param mixed $value
  911. +----------------------------------------------------------
  912. * @return mixed
  913. +----------------------------------------------------------
  914. */
  915. protected function addSpecialChar(&$value) {
  916. $value = trim($value);
  917. if( false !== strpos($value,' ') || false !== strpos($value,',') || false !== strpos($value,'*') || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) {
  918. //如果包含* 或者 使用了sql方法 则不作处理
  919. }else{
  920. $value = '`'.$value.'`';
  921. }
  922. return $value;
  923. }
  924. /**
  925. +----------------------------------------------------------
  926. * 查询次数更新或者查询
  927. +----------------------------------------------------------
  928. * @access public
  929. +----------------------------------------------------------
  930. * @param mixed $times
  931. +----------------------------------------------------------
  932. * @return void
  933. +----------------------------------------------------------
  934. */
  935. public function Q($times='') {
  936. static $_times = 0;
  937. if(empty($times)) {
  938. return $_times;
  939. }else{
  940. $_times++;
  941. // 记录开始执行时间
  942. $this->beginTime = microtime(TRUE);
  943. }
  944. }
  945. /**
  946. +----------------------------------------------------------
  947. * 写入次数更新或者查询
  948. +----------------------------------------------------------
  949. * @access public
  950. +----------------------------------------------------------
  951. * @param mixed $times
  952. +----------------------------------------------------------
  953. * @return void
  954. +----------------------------------------------------------
  955. */
  956. public function W($times='') {
  957. static $_times = 0;
  958. if(empty($times)) {
  959. return $_times;
  960. }else{
  961. $_times++;
  962. // 记录开始执行时间
  963. $this->beginTime = microtime(TRUE);
  964. }
  965. }
  966. /**
  967. +----------------------------------------------------------
  968. * 获取最近一次查询的sql语句
  969. +----------------------------------------------------------
  970. * @access public
  971. +----------------------------------------------------------
  972. * @return string
  973. +----------------------------------------------------------
  974. */
  975. public function getLastSql() {
  976. return $this->queryStr;
  977. }
  978. }//类定义结束
  979. ?>