优惠券订单及其他脚本

PDO.class.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. <?php
  2. class PDO_DB {
  3. protected static $_dbh = null; //静态属性,所有数据库实例共用,避免重复连接数据库
  4. protected $_dbType = 'mysql';
  5. protected $_pconnect = true; //是否使用长连接
  6. protected $_host = 'localhost';
  7. protected $_port = 3306;
  8. protected $_user = 'root';
  9. protected $_pass = 'root';
  10. protected $_dbName = 'tbk_onlive'; //数据库名
  11. protected $_sql = false; //最后一条sql语句
  12. protected $_where = '';
  13. protected $_order = '';
  14. protected $_limit = '';
  15. protected $_field = '*';
  16. protected $_tbName = '*';
  17. protected $_clear = 0; //状态,0表示查询条件干净,1表示查询条件污染
  18. protected $_trans = 0; //事务指令数
  19. /**
  20. * 初始化类
  21. * @param array $conf 数据库配置
  22. */
  23. public function __construct(array $conf) {
  24. class_exists('PDO') or die("PDO: class not exists.");
  25. $this->_host = $conf['host'];
  26. $this->_port = $conf['port'];
  27. $this->_user = $conf['user'];
  28. $this->_pass = $conf['password'];
  29. $this->_dbName = $conf['dbName'];
  30. //连接数据库
  31. if ( is_null(self::$_dbh) ) {
  32. $this->_connect();
  33. }
  34. }
  35. /**
  36. * 连接数据库的方法
  37. */
  38. protected function _connect() {
  39. $dsn = $this->_dbType.':host='.$this->_host.';port='.$this->_port.';dbname='.$this->_dbName;
  40. //持久化连接
  41. $options = $this->_pconnect ? array(PDO::ATTR_PERSISTENT=>true) : array();
  42. try {
  43. $dbh = new PDO($dsn, $this->_user, $this->_pass, $options);
  44. $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); //设置如果sql语句执行错误则抛出异常,事务会自动回滚
  45. $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); //禁用prepared statements的仿真效果(防SQL注入)
  46. } catch (PDOException $e) {
  47. die('Connection failed: ' . $e->getMessage());
  48. }
  49. $dbh->exec('SET NAMES utf8');
  50. self::$_dbh = $dbh;
  51. }
  52. /**
  53. * 字段和表名添加 `符号
  54. * 保证指令中使用关键字不出错 针对mysql
  55. * @param string $value
  56. * @return string
  57. */
  58. protected function _addChar($value) {
  59. if ('*'==$value || false!==strpos($value,'(') || false!==strpos($value,'.') || false!==strpos($value,'`')) {
  60. //如果包含* 或者 使用了sql方法 则不作处理
  61. } elseif (false === strpos($value,'`') ) {
  62. $value = '`'.trim($value).'`';
  63. }
  64. return $value;
  65. }
  66. /**
  67. * 取得数据表的字段信息
  68. * @param string $tbName 表名
  69. * @return array
  70. */
  71. protected function _tbFields($tbName) {
  72. $sql = 'SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME="'.$tbName.'" AND TABLE_SCHEMA="'.$this->_dbName.'"';
  73. $stmt = self::$_dbh->prepare($sql);
  74. $stmt->execute();
  75. $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
  76. $ret = array();
  77. foreach ($result as $key=>$value) {
  78. $ret[$value['COLUMN_NAME']] = 1;
  79. }
  80. return $ret;
  81. }
  82. /**
  83. * 过滤并格式化数据表字段
  84. * @param string $tbName 数据表名
  85. * @param array $data POST提交数据
  86. * @return array $newdata
  87. */
  88. protected function _dataFormat($tbName,$data) {
  89. if (!is_array($data)) return array();
  90. $table_column = $this->_tbFields($tbName);
  91. $ret=array();
  92. foreach ($data as $key=>$val) {
  93. if (!is_scalar($val)) continue; //值不是标量则跳过
  94. if (array_key_exists($key,$table_column)) {
  95. $key = $this->_addChar($key);
  96. if (is_int($val)) {
  97. $val = intval($val);
  98. } elseif (is_float($val)) {
  99. $val = floatval($val);
  100. } elseif (preg_match('/^\(\w*(\+|\-|\*|\/)?\w*\)$/i', $val)) {
  101. // 支持在字段的值里面直接使用其它字段 ,例如 (score+1) (name) 必须包含括号
  102. $val = $val;
  103. } elseif (is_string($val)) {
  104. //将字符串中的单引号(')、双引号(")、反斜线(\)与 NUL(NULL 字符转义
  105. $val = '"'.addslashes($val).'"';
  106. }
  107. $ret[$key] = $val;
  108. }
  109. }
  110. return $ret;
  111. }
  112. /**
  113. * 执行查询 主要针对 SELECT, SHOW 等指令
  114. * @param string $sql sql指令
  115. * @return mixed
  116. */
  117. protected function _doQuery($sql='') {
  118. $this->_sql = $sql;
  119. $pdostmt = self::$_dbh->prepare($this->_sql); //prepare或者query 返回一个PDOStatement
  120. $pdostmt->execute();
  121. $result = $pdostmt->fetchAll(PDO::FETCH_ASSOC);
  122. return $result;
  123. }
  124. /**
  125. * 执行语句 针对 INSERT, UPDATE 以及DELETE,exec结果返回受影响的行数
  126. * @param string $sql sql指令
  127. * @return integer
  128. */
  129. protected function _doExec($sql='') {
  130. $this->_sql = $sql;
  131. return self::$_dbh->exec($this->_sql);
  132. }
  133. /**
  134. * 执行sql语句,自动判断进行查询或者执行操作
  135. * @param string $sql SQL指令
  136. * @return mixed
  137. */
  138. public function doSql($sql='') {
  139. $queryIps = 'INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|SELECT .* INTO|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK';
  140. if (preg_match('/^\s*"?(' . $queryIps . ')\s+/i', $sql)) {
  141. return $this->_doExec($sql);
  142. }
  143. else {
  144. //查询操作
  145. return $this->_doQuery($sql);
  146. }
  147. }
  148. /**
  149. * 获取最近一次查询的sql语句
  150. * @return String 执行的SQL
  151. */
  152. public function getLastSql() {
  153. return $this->_sql;
  154. }
  155. /**
  156. * 插入方法
  157. * @param string $tbName 操作的数据表名
  158. * @param array $data 字段-值的一维数组
  159. * @return int 受影响的行数
  160. */
  161. public function insert(array $data){
  162. $data = $this->_dataFormat($this->_tbName,$data);
  163. if (!$data) return;
  164. $sql = "insert into ".$this->_tbName."(".implode(',',array_keys($data)).") values(".implode(',',array_values($data)).")";
  165. return $this->_doExec($sql);
  166. }
  167. /**
  168. * 删除方法
  169. * @param string $tbName 操作的数据表名
  170. * @return int 受影响的行数
  171. */
  172. public function delete() {
  173. //安全考虑,阻止全表删除
  174. if (!trim($this->_where)) return false;
  175. $sql = "delete from ".$this->_tbName." ".$this->_where;
  176. $this->_clear = 1;
  177. $this->_clear();
  178. return $this->_doExec($sql);
  179. }
  180. /**
  181. * 更新函数
  182. * @param string $tbName 操作的数据表名
  183. * @param array $data 参数数组
  184. * @return int 受影响的行数
  185. */
  186. public function update(array $data) {
  187. //安全考虑,阻止全表更新
  188. if (!trim($this->_where)) return false;
  189. $data = $this->_dataFormat($this->_tbName,$data);
  190. if (!$data) return;
  191. $valArr = [];
  192. foreach($data as $k=>$v){
  193. $valArr[] = $k.'='.$v;
  194. }
  195. $valStr = implode(',', $valArr);
  196. $sql = "update ".trim($this->_tbName)." set ".trim($valStr)." ".trim($this->_where);
  197. return $this->_doExec($sql);
  198. }
  199. /**
  200. * 查询函数
  201. * @param string $tbName 操作的数据表名
  202. * @return array 结果集
  203. */
  204. public function get() {
  205. $sql = "select ".trim($this->_field)." from ".$this->_tbName." ".trim($this->_where)." ".trim($this->_order)." ".trim($this->_limit);
  206. $this->_clear = 1;
  207. $this->_clear();
  208. return $this->_doQuery(trim($sql));
  209. }
  210. /**
  211. * 查询函数
  212. * @param string $tbName 操作的数据表名
  213. * @return array 结果集
  214. */
  215. public function first() {
  216. $sql = "select ".trim($this->_field)." from ".$this->_tbName." ".trim($this->_where)." ".trim($this->_order)." limit 1 ";
  217. $this->_clear = 1;
  218. $this->_clear();
  219. $this->_sql = $sql;
  220. $pdostmt = self::$_dbh->prepare($this->_sql); //prepare或者query 返回一个PDOStatement
  221. $pdostmt->execute();
  222. $result = $pdostmt->fetch(PDO::FETCH_ASSOC);
  223. return $result;
  224. }
  225. public function table($table){
  226. if ($this->_clear>0) $this->_clear();
  227. $this->_tbName = $table;
  228. return $this;
  229. }
  230. /**
  231. * @param mixed $option 组合条件的二维数组,例:$option['field1'] = array(1,'=>','or')
  232. * @return $this
  233. */
  234. public function where($option) {
  235. if ($this->_clear>0) $this->_clear();
  236. $this->_where = ' where ';
  237. $logic = 'and';
  238. if (is_string($option)) {
  239. $this->_where .= $option;
  240. }
  241. elseif (is_array($option)) {
  242. foreach($option as $k=>$v) {
  243. if (is_array($v)) {
  244. $relative = isset($v[1]) ? $v[1] : '=';
  245. $logic = isset($v[2]) ? $v[2] : 'and';
  246. if(!is_numeric($v[0])){
  247. $v[0] = "'".$v[0]."'";
  248. }
  249. $condition = ' ('.$this->_addChar($k).' '.$relative.' '.$v[0].') ';
  250. }
  251. else {
  252. if(!is_numeric($v)){
  253. $v = "'".$v."'";
  254. }
  255. $logic = 'and';
  256. $condition = ' ('.$this->_addChar($k).'='.$v.') ';
  257. }
  258. $this->_where .= isset($mark) ? $logic.$condition : $condition;
  259. $mark = 1;
  260. }
  261. }
  262. return $this;
  263. }
  264. /**
  265. * 设置排序
  266. * @param mixed $option 排序条件数组 例:array('sort'=>'desc')
  267. * @return $this
  268. */
  269. public function orderBy($option, $fl='') {
  270. if ($this->_clear>0) $this->_clear();
  271. $this->_order = ' order by ';
  272. if (is_string($option)) {
  273. $this->_order .= $option. ' ' .$fl;
  274. }
  275. elseif (is_array($option)) {
  276. foreach($option as $k=>$v){
  277. $order = $this->_addChar($k).' '.$v;
  278. $this->_order .= isset($mark) ? ','.$order : $order;
  279. $mark = 1;
  280. }
  281. }
  282. return $this;
  283. }
  284. /**
  285. * 设置查询行数及页数
  286. * @param int $page pageSize不为空时为页数,否则为行数
  287. * @param int $pageSize 为空则函数设定取出行数,不为空则设定取出行数及页数
  288. * @return $this
  289. */
  290. public function limit($limit, $offset=null) {
  291. if ($this->_clear>0) $this->_clear();
  292. if ($offset===null) {
  293. $this->_limit = "limit ".$limit;
  294. }
  295. else {
  296. $this->_limit = "limit ".$limit.",".$offset;
  297. }
  298. return $this;
  299. }
  300. /**
  301. * 设置查询字段
  302. * @param mixed $field 字段数组
  303. * @return $this
  304. */
  305. public function select($field){
  306. if ($this->_clear>0) $this->_clear();
  307. #假如是sql,直接执行
  308. $queryIps = 'SELECT|INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|SELECT .* INTO|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK';
  309. if (preg_match('/^\s*"?(' . $queryIps . ')\s+/i', $field)) {
  310. return $this->doSql($field);
  311. }
  312. if (is_string($field)) {
  313. $field = explode(',', $field);
  314. }
  315. $nField = array_map(array($this,'_addChar'), $field);
  316. $this->_field = implode(',', $nField);
  317. return $this;
  318. }
  319. /**
  320. * 清理标记函数
  321. */
  322. protected function _clear() {
  323. $this->_where = '';
  324. $this->_order = '';
  325. $this->_limit = '';
  326. $this->_field = '*';
  327. $this->_clear = 0;
  328. }
  329. /**
  330. * 手动清理标记
  331. * @return $this
  332. */
  333. public function clearKey() {
  334. $this->_clear();
  335. return $this;
  336. }
  337. /**
  338. * 启动事务
  339. * @return void
  340. */
  341. public function startTrans() {
  342. //数据rollback 支持
  343. if ($this->_trans==0) self::$_dbh->beginTransaction();
  344. $this->_trans++;
  345. return;
  346. }
  347. /**
  348. * 用于非自动提交状态下面的查询提交
  349. * @return boolen
  350. */
  351. public function commit() {
  352. $result = true;
  353. if ($this->_trans>0) {
  354. $result = self::$_dbh->commit();
  355. $this->_trans = 0;
  356. }
  357. return $result;
  358. }
  359. /**
  360. * 事务回滚
  361. * @return boolen
  362. */
  363. public function rollback() {
  364. $result = true;
  365. if ($this->_trans>0) {
  366. $result = self::$_dbh->rollback();
  367. $this->_trans = 0;
  368. }
  369. return $result;
  370. }
  371. /**
  372. * 关闭连接
  373. * PHP 在脚本结束时会自动关闭连接。
  374. */
  375. public function close() {
  376. if (!is_null(self::$_dbh)) self::$_dbh = null;
  377. }
  378. }