mysql.class.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. /**
  3. * mysql.class.php 数据库实现类
  4. *
  5. * @copyright (C) 2005-2010 PHPCMS
  6. * @license http://www.phpcms.cn/license/
  7. * @lastmodify 2010-6-1
  8. */
  9. final class mysql {
  10. /**
  11. * 数据库配置信息
  12. */
  13. private $config = null;
  14. /**
  15. * 数据库连接资源句柄
  16. */
  17. public $link = null;
  18. /**
  19. * 最近一次查询资源句柄
  20. */
  21. public $lastqueryid = null;
  22. /**
  23. * 统计数据库查询次数
  24. */
  25. public $querycount = 0;
  26. public function __construct() {
  27. }
  28. /**
  29. * 打开数据库连接,有可能不真实连接数据库
  30. * @param $config 数据库连接参数
  31. *
  32. * @return void
  33. */
  34. public function open($config) {
  35. $this->config = $config;
  36. if($config['autoconnect'] == 1) {
  37. $this->connect();
  38. }
  39. }
  40. /**
  41. * 真正开启数据库连接
  42. *
  43. * @return void
  44. */
  45. public function connect() {
  46. $func = $this->config['pconnect'] == 1 ? 'mysql_pconnect' : 'mysql_connect';
  47. if(!$this->link = @$func($this->config['hostname'], $this->config['username'], $this->config['password'], 1)) {
  48. $this->halt(mysql_error());
  49. return false;
  50. }
  51. if($this->version() > '4.1') {
  52. $charset = isset($this->config['charset']) ? $this->config['charset'] : '';
  53. $serverset = $charset ? "character_set_connection='$charset',character_set_results='$charset',character_set_client=binary" : '';
  54. $serverset .= $this->version() > '5.0.1' ? ((empty($serverset) ? '' : ',')." sql_mode='' ") : '';
  55. $serverset && mysql_query("SET $serverset", $this->link);
  56. }
  57. if($this->config['database'] && !@mysql_select_db($this->config['database'], $this->link)) {
  58. $this->halt('Cannot use database '.$this->config['database']);
  59. return false;
  60. }
  61. $this->database = $this->config['database'];
  62. return $this->link;
  63. }
  64. /**
  65. * 数据库查询执行方法
  66. * @param $sql 要执行的sql语句
  67. * @return 查询资源句柄
  68. */
  69. private function execute($sql) {
  70. if(!is_resource($this->link)) {
  71. $this->connect();
  72. }
  73. $this->lastqueryid = mysql_query($sql, $this->link) or $this->halt(mysql_error(), $sql);
  74. $this->querycount++;
  75. return $this->lastqueryid;
  76. }
  77. /**
  78. * 执行sql查询
  79. * @param $data 需要查询的字段值[例`name`,`gender`,`birthday`]
  80. * @param $table 数据表
  81. * @param $where 查询条件[例`name`='$name']
  82. * @param $limit 返回结果范围[例:10或10,10 默认为空]
  83. * @param $order 排序方式 [默认按数据库默认方式排序]
  84. * @param $group 分组方式 [默认为空]
  85. * @param $key 返回数组按键名排序
  86. * @return array 查询结果集数组
  87. */
  88. public function select($data, $table, $where = '', $limit = '', $order = '', $group = '', $key = '') {
  89. $where = $where == '' ? '' : ' WHERE '.$where;
  90. $order = $order == '' ? '' : ' ORDER BY '.$order;
  91. $group = $group == '' ? '' : ' GROUP BY '.$group;
  92. $limit = $limit == '' ? '' : ' LIMIT '.$limit;
  93. $field = explode(',', $data);
  94. array_walk($field, array($this, 'add_special_char'));
  95. $data = implode(',', $field);
  96. $sql = 'SELECT '.$data.' FROM `'.$this->config['database'].'`.`'.$table.'`'.$where.$group.$order.$limit;
  97. $this->execute($sql);
  98. if(!is_resource($this->lastqueryid)) {
  99. return $this->lastqueryid;
  100. }
  101. $datalist = array();
  102. while(($rs = $this->fetch_next()) != false) {
  103. if($key) {
  104. $datalist[$rs[$key]] = $rs;
  105. } else {
  106. $datalist[] = $rs;
  107. }
  108. }
  109. $this->free_result();
  110. return $datalist;
  111. }
  112. /**
  113. * 获取单条记录查询
  114. * @param $data 需要查询的字段值[例`name`,`gender`,`birthday`]
  115. * @param $table 数据表
  116. * @param $where 查询条件
  117. * @param $order 排序方式 [默认按数据库默认方式排序]
  118. * @param $group 分组方式 [默认为空]
  119. * @return array/null 数据查询结果集,如果不存在,则返回空
  120. */
  121. public function get_one($data, $table, $where = '', $order = '', $group = '') {
  122. $where = $where == '' ? '' : ' WHERE '.$where;
  123. $order = $order == '' ? '' : ' ORDER BY '.$order;
  124. $group = $group == '' ? '' : ' GROUP BY '.$group;
  125. $limit = ' LIMIT 1';
  126. $field = explode( ',', $data);
  127. array_walk($field, array($this, 'add_special_char'));
  128. $data = implode(',', $field);
  129. $sql = 'SELECT '.$data.' FROM `'.$this->config['database'].'`.`'.$table.'`'.$where.$group.$order.$limit;
  130. $this->execute($sql);
  131. $res = $this->fetch_next();
  132. $this->free_result();
  133. return $res;
  134. }
  135. /**
  136. * 遍历查询结果集
  137. * @param $type 返回结果集类型
  138. * MYSQL_ASSOC,MYSQL_NUM 和 MYSQL_BOTH
  139. * @return array
  140. */
  141. public function fetch_next($type=MYSQL_ASSOC) {
  142. $res = mysql_fetch_array($this->lastqueryid, $type);
  143. if(!$res) {
  144. $this->free_result();
  145. }
  146. return $res;
  147. }
  148. /**
  149. * 释放查询资源
  150. * @return void
  151. */
  152. public function free_result() {
  153. if(is_resource($this->lastqueryid)) {
  154. mysql_free_result($this->lastqueryid);
  155. $this->lastqueryid = null;
  156. }
  157. }
  158. /**
  159. * 直接执行sql查询
  160. * @param $sql 查询sql语句
  161. * @return boolean/query resource 如果为查询语句,返回资源句柄,否则返回true/false
  162. */
  163. public function query($sql) {
  164. return $this->execute($sql);
  165. }
  166. /**
  167. * 执行添加记录操作
  168. * @param $data 要增加的数据,参数为数组。数组key为字段值,数组值为数据取值
  169. * @param $table 数据表
  170. * @return boolean
  171. */
  172. public function insert($data, $table, $return_insert_id = false, $replace = false) {
  173. if(!is_array( $data ) || $table == '' || count($data) == 0) {
  174. return false;
  175. }
  176. $fielddata = array_keys($data);
  177. $valuedata = array_values($data);
  178. array_walk($fielddata, array($this, 'add_special_char'));
  179. array_walk($valuedata, array($this, 'escape_string'));
  180. $field = implode (',', $fielddata);
  181. $value = implode (',', $valuedata);
  182. $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO';
  183. $sql = $cmd.' `'.$this->config['database'].'`.`'.$table.'`('.$field.') VALUES ('.$value.')';
  184. $return = $this->execute($sql);
  185. return $return_insert_id ? $this->insert_id() : $return;
  186. }
  187. /**
  188. * 获取最后一次添加记录的主键号
  189. * @return int
  190. */
  191. public function insert_id() {
  192. return mysql_insert_id($this->link);
  193. }
  194. /**
  195. * 执行更新记录操作
  196. * @param $data 要更新的数据内容,参数可以为数组也可以为字符串,建议数组。
  197. * 为数组时数组key为字段值,数组值为数据取值
  198. * 为字符串时[例:`name`='phpcms',`hits`=`hits`+1]。
  199. * 为数组时[例: array('name'=>'phpcms','password'=>'123456')]
  200. * 数组可使用array('name'=>'+=1', 'base'=>'-=1');程序会自动解析为`name` = `name` + 1, `base` = `base` - 1
  201. * @param $table 数据表
  202. * @param $where 更新数据时的条件
  203. * @return boolean
  204. */
  205. public function update($data, $table, $where = '') {
  206. if($table == '' or $where == '') {
  207. return false;
  208. }
  209. $where = ' WHERE '.$where;
  210. $field = '';
  211. if(is_string($data) && $data != '') {
  212. $field = $data;
  213. } elseif (is_array($data) && count($data) > 0) {
  214. $fields = array();
  215. foreach($data as $k=>$v) {
  216. switch (substr($v, 0, 2)) {
  217. case '+=':
  218. $v = substr($v,2);
  219. if (is_numeric($v)) {
  220. $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'+'.$this->escape_string($v, '', false);
  221. } else {
  222. continue;
  223. }
  224. break;
  225. case '-=':
  226. $v = substr($v,2);
  227. if (is_numeric($v)) {
  228. $fields[] = $this->add_special_char($k).'='.$this->add_special_char($k).'-'.$this->escape_string($v, '', false);
  229. } else {
  230. continue;
  231. }
  232. break;
  233. default:
  234. $fields[] = $this->add_special_char($k).'='.$this->escape_string($v);
  235. }
  236. }
  237. $field = implode(',', $fields);
  238. } else {
  239. return false;
  240. }
  241. $sql = 'UPDATE `'.$this->config['database'].'`.`'.$table.'` SET '.$field.$where;
  242. return $this->execute($sql);
  243. }
  244. /**
  245. * 执行删除记录操作
  246. * @param $table 数据表
  247. * @param $where 删除数据条件,不充许为空。
  248. * 如果要清空表,使用empty方法
  249. * @return boolean
  250. */
  251. public function delete($table, $where) {
  252. if ($table == '' || $where == '') {
  253. return false;
  254. }
  255. $where = ' WHERE '.$where;
  256. $sql = 'DELETE FROM `'.$this->config['database'].'`.`'.$table.'`'.$where;
  257. return $this->execute($sql);
  258. }
  259. /**
  260. * 获取最后数据库操作影响到的条数
  261. * @return int
  262. */
  263. public function affected_rows() {
  264. return mysql_affected_rows($this->link);
  265. }
  266. /**
  267. * 获取数据表主键
  268. * @param $table 数据表
  269. * @return array
  270. */
  271. public function get_primary($table) {
  272. $this->execute("SHOW COLUMNS FROM $table");
  273. while($r = $this->fetch_next()) {
  274. if($r['Key'] == 'PRI') break;
  275. }
  276. return $r['Field'];
  277. }
  278. /**
  279. * 获取表字段
  280. * @param $table 数据表
  281. * @return array
  282. */
  283. public function get_fields($table) {
  284. $fields = array();
  285. $this->execute("SHOW COLUMNS FROM $table");
  286. while($r = $this->fetch_next()) {
  287. $fields[$r['Field']] = $r['Type'];
  288. }
  289. return $fields;
  290. }
  291. /**
  292. * 检查不存在的字段
  293. * @param $table 表名
  294. * @return array
  295. */
  296. public function check_fields($table, $array) {
  297. $fields = $this->get_fields($table);
  298. $nofields = array();
  299. foreach($array as $v) {
  300. if(!array_key_exists($v, $fields)) {
  301. $nofields[] = $v;
  302. }
  303. }
  304. return $nofields;
  305. }
  306. /**
  307. * 检查表是否存在
  308. * @param $table 表名
  309. * @return boolean
  310. */
  311. public function table_exists($table) {
  312. $tables = $this->list_tables();
  313. return in_array($table, $tables) ? 1 : 0;
  314. }
  315. public function list_tables() {
  316. $tables = array();
  317. $this->execute("SHOW TABLES");
  318. while($r = $this->fetch_next()) {
  319. $tables[] = $r['Tables_in_'.$this->config['database']];
  320. }
  321. return $tables;
  322. }
  323. /**
  324. * 检查字段是否存在
  325. * @param $table 表名
  326. * @return boolean
  327. */
  328. public function field_exists($table, $field) {
  329. $fields = $this->get_fields($table);
  330. return array_key_exists($field, $fields);
  331. }
  332. public function num_rows($sql) {
  333. $this->lastqueryid = $this->execute($sql);
  334. return mysql_num_rows($this->lastqueryid);
  335. }
  336. public function num_fields($sql) {
  337. $this->lastqueryid = $this->execute($sql);
  338. return mysql_num_fields($this->lastqueryid);
  339. }
  340. public function result($sql, $row) {
  341. $this->lastqueryid = $this->execute($sql);
  342. return @mysql_result($this->lastqueryid, $row);
  343. }
  344. public function error() {
  345. return @mysql_error($this->link);
  346. }
  347. public function errno() {
  348. return intval(@mysql_errno($this->link)) ;
  349. }
  350. public function version() {
  351. if(!is_resource($this->link)) {
  352. $this->connect();
  353. }
  354. return mysql_get_server_info($this->link);
  355. }
  356. public function close() {
  357. if (is_resource($this->link)) {
  358. @mysql_close($this->link);
  359. }
  360. }
  361. public function escape($str){
  362. if(!is_resource($this->link)) {
  363. $this->connect();
  364. }
  365. return mysql_real_escape_string($str,$this->link);
  366. }
  367. public function halt($message = '', $sql = '') {
  368. if($this->config['debug']) {
  369. $this->errormsg = "<b>MySQL Query : </b> $sql <br /><b> MySQL Error : </b>".$this->error()." <br /> <b>MySQL Errno : </b>".$this->errno()." <br /><b> Message : </b> $message <br /><a href='http://faq.phpcms.cn/?errno=".$this->errno()."&msg=".urlencode($this->error())."' target='_blank' style='color:red'>Need Help?</a>";
  370. $msg = $this->errormsg;
  371. echo '<div style="font-size:12px;text-align:left; border:1px solid #9cc9e0; padding:1px 4px;color:#000000;font-family:Arial, Helvetica,sans-serif;"><span>'.$msg.'</span></div>';
  372. exit;
  373. } else {
  374. return false;
  375. }
  376. }
  377. /**
  378. * 对字段两边加反引号,以保证数据库安全
  379. * @param $value 数组值
  380. */
  381. public function add_special_char(&$value) {
  382. if('*' == $value || false !== strpos($value, '(') || false !== strpos($value, '.') || false !== strpos ( $value, '`')) {
  383. //不处理包含* 或者 使用了sql方法。
  384. } else {
  385. $value = '`'.trim($value).'`';
  386. }
  387. if (preg_match("/\b(select|insert|update|delete)\b/i", $value)) {
  388. $value = preg_replace("/\b(select|insert|update|delete)\b/i", '', $value);
  389. }
  390. return $value;
  391. }
  392. /**
  393. * 对字段值两边加引号,以保证数据库安全
  394. * @param $value 数组值
  395. * @param $key 数组key
  396. * @param $quotation
  397. */
  398. public function escape_string(&$value, $key='', $quotation = 1) {
  399. if ($quotation) {
  400. $q = '\'';
  401. } else {
  402. $q = '';
  403. }
  404. $value = $q.$value.$q;
  405. return $value;
  406. }
  407. }
  408. ?>