Db.class.php 38 KB

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