You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					919 lines
				
				31 KiB
			
		
		
			
		
	
	
					919 lines
				
				31 KiB
			|   
											1 year ago
										 | <?php | ||
|  | /** | ||
|  |  * 数据层基础类 | ||
|  |  * | ||
|  |  * @author wangyong1 | ||
|  |  * @version 1.0 | ||
|  |  * @package data | ||
|  |  */ | ||
|  | 
 | ||
|  | class dBase extends publicBase { | ||
|  |     private $table; | ||
|  |     private $logpath; | ||
|  | 
 | ||
|  |     protected $fieldlist; | ||
|  |     protected $fields; | ||
|  | 
 | ||
|  |     protected $primary_keys; | ||
|  |     protected $primary_key; | ||
|  | 
 | ||
|  |     protected $dbflag = 'simplyphp'; | ||
|  |     private static $db_w = null; | ||
|  |     private static $db_r = null; | ||
|  |     private static $link; | ||
|  | 
 | ||
|  |     private $ismaster = false; | ||
|  | 
 | ||
|  |     protected $rownum; | ||
|  | 
 | ||
|  |     public function __construct() { | ||
|  |         $this->logpath = LOG_PATH_BASE.'/mysql_index/%s/%s_%s.log'; | ||
|  |     } | ||
|  |     private function getInstance() { | ||
|  |         $dbpara = $this->ismaster==false ? 'db_r' : 'db_w'; | ||
|  | 
 | ||
|  |         if(!is_null(self::$$dbpara)) { | ||
|  |             self::$link = self::$$dbpara; | ||
|  | 
 | ||
|  |             // 判断mysql是否gone away | ||
|  |             $status = self::$link->getAttribute(PDO::ATTR_SERVER_INFO); | ||
|  |             if($status == 'MySQL server has gone away') { | ||
|  |                 self::$link = self::$$dbpara = $this->toDb(); | ||
|  |             } | ||
|  |         } else { | ||
|  |            self::$link = self::$$dbpara = $this->toDb(); | ||
|  |         } | ||
|  |         return self::$link; | ||
|  |     } | ||
|  | 
 | ||
|  |     private function __clone() {} | ||
|  | 
 | ||
|  |     private function initDb($table, $ismaster=false) { | ||
|  |         $this->table = $table; | ||
|  |         $this->ismaster = $ismaster; | ||
|  | 
 | ||
|  |         $this->fields = $this->fieldlist[$this->table]; | ||
|  |         $this->primary_key = empty($this->primary_keys[$this->table]) ? 'id' : $this->primary_keys[$this->table]; | ||
|  | 
 | ||
|  |         return self::getInstance(); | ||
|  |     } | ||
|  | 
 | ||
|  |     private function toDb() { | ||
|  |         $type = strtolower($this->dbflag); | ||
|  |         $cnf = $this->parseDbCnf($this->dbflag, $this->ismaster); | ||
|  | 
 | ||
|  |         if (count($cnf)<=0 && $cnf['host'] == '') { | ||
|  |          return false; | ||
|  |         } | ||
|  |         try { | ||
|  |             $conn[PDO::ATTR_TIMEOUT] = 3; | ||
|  |             if($GLOBALS['pconnect_db']===true) $conn[PDO::ATTR_PERSISTENT] = true; | ||
|  |             $conn[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES UTF8;"; | ||
|  |             $db = new PDO('mysql:host='.$cnf['host'].';port='.$cnf['port'].';dbname='.$cnf['db'],$cnf['user'],$cnf['pwd'], $conn); | ||
|  |         } catch(PDOException $e) { | ||
|  |             //error_log('['.date('Y-m-d H:i:s').'][first-fail]'.implode('|', $cnf).':'.$e->getMessage()."\n", 3, LOG_PATH_BASE.'/mysql/stat_todb_'.date('Y-m-d').'.log'); | ||
|  | 
 | ||
|  |             try { | ||
|  |                 $conn[PDO::ATTR_TIMEOUT] = 3; | ||
|  |                 if($GLOBALS['pconnect_db']===true) $conn[PDO::ATTR_PERSISTENT] = true; | ||
|  |                 $conn[PDO::MYSQL_ATTR_INIT_COMMAND] = "SET NAMES UTF8;"; | ||
|  |                 $db = new PDO('mysql:host='.$cnf['host'].';port='.$cnf['port'].';dbname='.$cnf['db'],$cnf['user'],$cnf['pwd'], $conn); | ||
|  |             } catch(PDOException $e) { | ||
|  |                 //error_log('['.date('Y-m-d H:i:s').'][second-fail]'.implode('|', $cnf).':'.$e->getMessage()."\n", 3, LOG_PATH_BASE.'/mysql/stat_todb_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             //error_log('['.date('Y-m-d H:i:s').'][second-succ]'.implode('|', $cnf)."\n", 3, LOG_PATH_BASE.'/mysql/stat_todb_'.date('Y-m-d').'.log'); | ||
|  |             return $db; | ||
|  |         } | ||
|  | 
 | ||
|  |         //error_log('['.date('Y-m-d H:i:s').'][first-succ]'.implode('|', $cnf)."\n", 3, LOG_PATH_BASE.'/mysql/stat_todb_'.date('Y-m-d').'.log'); | ||
|  |         return $db; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Insert | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 一维数组 key:表字段 value:值 | ||
|  |      */ | ||
|  |     public function insert($table, $array, $action='INSERT') { | ||
|  |         if(empty($array)) return false; | ||
|  | 
 | ||
|  |         $this->initDb($table, true); | ||
|  |         try { | ||
|  |             $keys = array_keys($array); | ||
|  |             $newkeys = array_intersect($this->fields, $keys); | ||
|  |             foreach ($newkeys as $k) { | ||
|  |                 $vals[] = $array[$k]; | ||
|  |             } | ||
|  |             $vnum = count($newkeys); | ||
|  |             $sql = $action." INTO `{$this->table}`(`".implode('`, `', $newkeys)."`) value(".substr(str_pad('',2*$vnum,',?'),1).")"; | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/insert_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             $last_id = self::$link->lastInsertId(); | ||
|  |             return $last_id > 0 ? $last_id : true; | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 批量插入 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 二维数组 key:表字段 value:值 | ||
|  |      */ | ||
|  |     public function mutiInsert($table, $arrays) { | ||
|  |         if(empty($arrays)) return false; | ||
|  | 
 | ||
|  |         $this->initDb($table, true); | ||
|  |         try { | ||
|  |             $newkeys = array_intersect($this->fields, array_keys($arrays[0])); | ||
|  |             $vnum = count($newkeys); | ||
|  | 
 | ||
|  |             $sql = "INSERT IGNORE INTO `{$this->table}`(`".implode('`, `', $newkeys)."`) values"; | ||
|  |             foreach ($arrays as $array) { | ||
|  |                 foreach ($newkeys as $k) { | ||
|  |                     $vals[] = $array[$k]; | ||
|  |                 } | ||
|  |                 $sql2 .= ",(".substr(str_pad('',2*$vnum,',?'),1).")"; | ||
|  |             } | ||
|  | 
 | ||
|  |             $sql .= substr($sql2, 1); | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/insert_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return true; | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Replace | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 一维数组 key:表字段 value:值 | ||
|  |      */ | ||
|  |     public function replace($table, $array) { | ||
|  |         return $this->insert($table, $array, 'REPLACE'); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     private function logSql($table, $flag, $sql, $vals) { | ||
|  |         return ; | ||
|  |         $logpath = sprintf($this->logpath, $table, $flag, date('Y-m-d')); | ||
|  |         if(!is_dir(dirname($logpath))) mkdir(dirname($logpath), 0775, true); | ||
|  |         error_log($sql.'|'.json_encode($vals)."\n", 3, $logpath); | ||
|  |     } | ||
|  | 
 | ||
|  |     public function sqlSlow($sql_arr){ | ||
|  |         $logpath = sprintf($this->logpath, 'sqlslow', '', date('Y-m-d')); | ||
|  |         if(!is_dir(dirname($logpath))) mkdir(dirname($logpath), 0775, true); | ||
|  |         if($sql_arr[0]>=0.5) error_log(date('Y-m-d H:i:s').'|'.implode('|', $sql_arr)."\n", 3, $logpath); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库select in | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 数组,只支持一个 key(in的字段),多个 value | ||
|  |      */ | ||
|  |     public function selectIn($table, $array, $where=array(), $orderby='', $limit=array()) { | ||
|  |         $this->initDb($table, true); | ||
|  |         try { | ||
|  |             $keys = array_keys($array); | ||
|  |             $values = array_values($array); | ||
|  |             $values = (array)$values[0]; | ||
|  |             sort($values); | ||
|  |             $vnum = count($values); | ||
|  |             $sql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` WHERE `{$keys[0]}` in (".substr(str_pad('',2*$vnum,',?'),1).")"; | ||
|  |             if(!empty($where)) { | ||
|  |                 $sql .= " and {$where['sql']}"; | ||
|  |                 $values = array_merge($values, $where['vals']); | ||
|  |             } | ||
|  |             $sql .= empty($orderby) ? $orderby = '' : " ORDER BY {$orderby} "; | ||
|  |             $sql .= empty($limit) ? '' : "LIMIT {$limit[0]}, {$limit[1]}"; | ||
|  | 
 | ||
|  |             $this->logSql($table, 'selectin', $sql, $values); | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  | 
 | ||
|  |             $start_time = $this->microtime_float(); | ||
|  | 
 | ||
|  |             $res = $st->execute($values); | ||
|  | 
 | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库select in | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 数组,只支持一个 key(in的字段),多个 value | ||
|  |      */ | ||
|  |     public function selectInMulti($table, $array, $where=array(), $orderby='', $limit=array()) { | ||
|  |         $this->initDb($table, true); | ||
|  |         try { | ||
|  |             $keys = array_keys($array); | ||
|  |             $vs = array_values($array); | ||
|  | 
 | ||
|  |             $values = array(); | ||
|  |             $sql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` WHERE"; | ||
|  |             foreach ($keys as $k => $key) { | ||
|  |                 $vals = $vs[$k]; | ||
|  |                 sort($vals); | ||
|  |                 $vnum = count($vals); | ||
|  | 
 | ||
|  |                 $values = array_merge($values, $vals); | ||
|  | 
 | ||
|  |                 $sql .= " `{$key}` in (".substr(str_pad('',2*$vnum,',?'),1).") and"; | ||
|  |             } | ||
|  |             $sql = rtrim($sql, 'and'); | ||
|  |             if(!empty($where)) { | ||
|  |                 $sql .= " and {$where['sql']}"; | ||
|  |                 $values = array_merge($values, $where['vals']); | ||
|  |             } | ||
|  |             $sql .= empty($orderby) ? $orderby = '' : " ORDER BY {$orderby} "; | ||
|  |             $sql .= empty($limit) ? '' : "LIMIT {$limit[0]}, {$limit[1]}"; | ||
|  | 
 | ||
|  |             $this->logSql($table, 'selectin', $sql, $values); | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  | 
 | ||
|  |             $start_time = $this->microtime_float(); | ||
|  | 
 | ||
|  |             $res = $st->execute($values); | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Select单条数据 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      */ | ||
|  |     public function select($table, $where=array(), $orderby='') { | ||
|  |         $this->initDb($table); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             $orderby = empty($orderby) ? $orderby = '' : "ORDER BY {$orderby}"; | ||
|  |             $sql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` {$wheresql} {$orderby}"; | ||
|  | 
 | ||
|  |             $this->logSql($table, 'select', $sql, $vals); | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  | 
 | ||
|  |             $start_time = $this->microtime_float(); | ||
|  | 
 | ||
|  |             $res = $st->execute($vals); | ||
|  | 
 | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             return $st->fetch(PDO::FETCH_ASSOC); | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Select多数据 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      * @param string $orderby 排序,比如:"ctime desc, name asc" | ||
|  |      * @param array $limit 读取数量 array(起始数, 数量) | ||
|  |      */ | ||
|  |     public function selectAll($table, $where=array(), $orderby='', $limit=array()) { | ||
|  |         $this->initDb($table); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             $orderby = empty($orderby) ? $orderby = "ORDER BY {$this->primary_key} DESC" : "ORDER BY {$orderby}"; | ||
|  |             if($orderby === null) $orderby = ''; | ||
|  | 
 | ||
|  |             $limitstr = empty($limit) ? '' : "LIMIT {$limit[0]}, {$limit[1]}"; | ||
|  |             $sql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` {$wheresql} {$orderby} {$limitstr}"; | ||
|  |             $this->logSql($table, 'selectAll', $sql, $vals); | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $start_time = $this->microtime_float(); | ||
|  |             $res = $st->execute($vals); | ||
|  | 
 | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             $this->rownum = $st->rowCount(); | ||
|  |             return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Select多数据 大数据分页查询 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      * @param string $orderby 排序,比如:"ctime desc, name asc" | ||
|  |      * @param array $limit 读取数量 array(起始数, 数量) | ||
|  |      */ | ||
|  |     public function selectAllForLimit($table, $where=array(), $orderby='', $limit=array(), $condition = array(), $key_name = '') { | ||
|  |         $this->initDb($table); | ||
|  | 
 | ||
|  |         try { | ||
|  |             if($condition['end_page']>0 || $condition['maxid']>0) $orderby = str_replace('desc', 'asc', $orderby); | ||
|  |             if($condition['end_page']<=0 && $condition['maxid']>0) $where['sql'] .= " and `id` > {$condition['maxid']} "; | ||
|  |             if($condition['end_page']<=0 &&  $condition['minid']>0) $where['sql'] .= " and `id` < {$condition['minid']} "; | ||
|  | 
 | ||
|  |             if($condition['jump_to_page']>0) { | ||
|  |                 $key_name = $key_name ? $key_name : $this->primary_key; | ||
|  |                 $where['sql'] .= " and `{$key_name}`<=(select `{$key_name}` from {$table} where {$where['sql']} order by {$orderby} limit ".($condition['jump_to_page']-1)*$limit[1].",1)"; | ||
|  |             } | ||
|  |             if($condition['end_page']>0 || $condition['maxid']>0 || $condition['minid']>0 || $condition['jump_to_page']>0) $limit[0] = 0; | ||
|  | 
 | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             $orderby = empty($orderby) ? $orderby = "ORDER BY {$this->primary_key} DESC" : "ORDER BY {$orderby}"; | ||
|  |             if($orderby === null) $orderby = ''; | ||
|  | 
 | ||
|  |             $limitstr = empty($limit) ? '' : "LIMIT {$limit[0]}, {$limit[1]}"; | ||
|  |             $sql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` {$wheresql} {$orderby} {$limitstr}"; | ||
|  |             $this->logSql($table, 'selectAll', $sql, $vals); | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $start_time = $this->microtime_float(); | ||
|  |             $res = $st->execute($vals); | ||
|  | 
 | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             $this->rownum = $st->rowCount(); | ||
|  |             return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库统计条数 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      * @param string $orderby 排序,比如:"ctime desc, name asc" | ||
|  |      * @param array $limit 读取数量 array(起始数, 数量) | ||
|  |      */ | ||
|  |     public function count($table, $where=array(), $orderby='', $limit=array()) { | ||
|  |         $this->initDb($table); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             $orderby = empty($orderby) ? $orderby = "ORDER BY {$this->primary_key} DESC" : "ORDER BY {$orderby}"; | ||
|  |             $limitstr = empty($limit) ? '' : "LIMIT {$limit[0]}, {$limit[1]}"; | ||
|  |             $sql = "SELECT count(*) as num FROM `{$this->table}` {$wheresql} {$orderby} {$limitstr}"; | ||
|  | 
 | ||
|  |             $this->logSql($table, 'count', $sql, $vals); | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  | 
 | ||
|  |             $start_time = $this->microtime_float(); | ||
|  | 
 | ||
|  |             $res = $st->execute($vals); | ||
|  | 
 | ||
|  |             $finish_time = $this->microtime_float(); | ||
|  |             $this->sqlSlow(array($finish_time-$start_time,$sql)); | ||
|  | 
 | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             $info = $st->fetch(PDO::FETCH_ASSOC); | ||
|  |             return $info['num']+0; | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Update | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 更新数据 key:表字段 value:值 | ||
|  |      * @param string $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      */ | ||
|  |     public function update($table, $array, $where='') { | ||
|  |         $this->initDb($table, true); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $keys = array_keys($array); | ||
|  |             $newkeys = array_intersect($this->fields, $keys); | ||
|  |             foreach ($newkeys as $k) { | ||
|  |                 $setstr .= ",`$k`=?"; | ||
|  |                 $vals[] = $array[$k]; | ||
|  |             } | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = array_merge($vals, $where['vals']); | ||
|  |             } | ||
|  |             $setstr = substr($setstr, 1); | ||
|  | 
 | ||
|  |             $sql = "UPDATE `{$this->table}` SET {$setstr} {$wheresql}"; | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/update_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return true; | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库UpdateIn | ||
|  |      * 更新多个符合条件的某字段数据值 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param array $array 更新数据 key:表字段 value:值 | ||
|  |      * @param array $where 数组,只支持一个 key(in的字段),多个 value | ||
|  |      */ | ||
|  |     public function updateIn($table, $array, $where) { | ||
|  |         $this->initDb($table, true); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $keys = array_keys($array); | ||
|  |             $newkeys = array_intersect($this->fields, $keys); | ||
|  |             foreach ($newkeys as $k) { | ||
|  |                 $setstr .= ",`$k`=?"; | ||
|  |                 $vals[] = $array[$k]; | ||
|  |             } | ||
|  | 
 | ||
|  |             $wheresql = ''; | ||
|  |             $keys = array_keys($where); | ||
|  |             $values = array_values($where); | ||
|  |             $values = $values[0]; | ||
|  |             sort($values); | ||
|  |             $vals = array_merge($vals, $values); | ||
|  |             $vnum = count($values); | ||
|  |             $wheresql = " WHERE `{$keys[0]}` in (".substr(str_pad('',2*$vnum,',?'),1).")"; | ||
|  |             $setstr = substr($setstr, 1); | ||
|  | 
 | ||
|  |             $sql = "UPDATE `{$this->table}` SET {$setstr} {$wheresql}"; | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/updatein_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return true; | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库Delete | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件 | ||
|  |      * 字符串,比如:"name1='***' and name2='***'" | ||
|  |      * 数组,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      */ | ||
|  |     public function delete($table, $where=array()) { | ||
|  |         $this->initDb($table, true); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  |             $sql = "DELETE FROM `{$this->table}` {$wheresql}"; | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/delete_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return true; | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库累加 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件 | ||
|  |      * 字符串,比如:"name1='***' and name2='***'" | ||
|  |      * @param string $field 字段名 / array('field'=>int/float) 逐渐改为数组 | ||
|  |      * @param int $num 增量数 | ||
|  |      * true/false | ||
|  |      */ | ||
|  |     public function increase($table, $where, $fields, $num=1) { | ||
|  |         $this->initDb($table, true); | ||
|  | 
 | ||
|  |         if(is_array($fields)) { | ||
|  |             try { | ||
|  |                 $wheresql = ''; | ||
|  |                 if(!empty($where)) { | ||
|  |                     $wheresql = "WHERE {$where['sql']}"; | ||
|  |                     $vals = $where['vals']; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // 判断是否存在记录 | ||
|  |                 $chksql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` {$wheresql}"; | ||
|  |                 $st = self::$link->prepare($chksql); | ||
|  |                 $res = $st->execute($vals); | ||
|  |                 if(!$res) return false; | ||
|  | 
 | ||
|  |                 $rownum = $st->rowCount(); | ||
|  |                 $st->closeCursor(); | ||
|  | 
 | ||
|  |                 foreach ($fields as $field => $num) { | ||
|  |                     $setdata .= ",`$field`=`$field`+$num"; | ||
|  |                 } | ||
|  |                 $setdata = substr($setdata, 1); | ||
|  | 
 | ||
|  |                 if($rownum>0) { | ||
|  |                     $sql = "UPDATE `{$this->table}` SET {$setdata} {$wheresql}"; | ||
|  |                 } else { | ||
|  |                     $sql = "REPLACE INTO `{$this->table}` SET {$setdata} "; | ||
|  |                     if(!empty($where))  $sql .= ",".str_replace('WHERE', '', str_replace(array('and', 'AND'), ",", $wheresql)); | ||
|  |                 } | ||
|  |                 $st = self::$link->prepare($sql); | ||
|  |                 $res = $st->execute($vals); | ||
|  |                 if(!$res) { | ||
|  |                     error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/increase_'.date('Y-m-d').'.log'); | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 return true; | ||
|  | 
 | ||
|  |             } catch(PDOException $e) { | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             return false; | ||
|  |         } | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             // 判断是否存在记录 | ||
|  |             $chksql = "SELECT `".implode('`, `',$this->fields)."` FROM `{$this->table}` {$wheresql}"; | ||
|  |             $st = self::$link->prepare($chksql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             $rownum = $st->rowCount(); | ||
|  | 
 | ||
|  |             $st->closeCursor(); | ||
|  |             if($rownum==1) { | ||
|  |                $sql = "UPDATE `{$this->table}` SET `$fields`=`$fields`+$num {$wheresql}"; | ||
|  |             } else { | ||
|  |                $sql = "REPLACE INTO `{$this->table}` SET `$fields`=`$fields`+$num "; | ||
|  |                if(!empty($where))  $sql .= ",".str_replace('WHERE', '', str_replace(array('and', 'AND'), ",", $wheresql)); | ||
|  |             } | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/increase_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return true; | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 数据库减 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $table 表名 | ||
|  |      * @param string $where where条件 | ||
|  |      * 字符串,比如:"name1='***' and name2='***'" | ||
|  |      * @param string $field 字段名 | ||
|  |      * @param int $num 增量数 | ||
|  |      * true/false | ||
|  |      */ | ||
|  |     public function decrease($table, $where, $field, $num=1) { | ||
|  |         $this->initDb($table, true); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  |             $sql = "UPDATE `{$this->table}` SET `$field`=`$field`-$num {$wheresql}"; | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.'|'.json_encode($vals).':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/decrease_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  |             return true; | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 执行SQL查询语句 | ||
|  |      * | ||
|  |      * 当SQL语句为查询语句时返回执行后的全部数据 | ||
|  |      * @access public | ||
|  |      * @param string $sql SQL语句 | ||
|  |      * @param boolean $all_rows 是否显示全部数据开关,当为true时,显示全部数据,为false时,显示一行数据,默认为true | ||
|  |      * @param boolean $is_select 是否为查询语句 | ||
|  |      * @return array | void | ||
|  |      */ | ||
|  |     public function execute($sql, $all_rows=true, $is_select=false) { | ||
|  |         $sql = trim($sql); | ||
|  |         if(!$sql) return false; | ||
|  | 
 | ||
|  |         $this->ismaster = $is_select==false ? true : false; | ||
|  |         self::getInstance(); | ||
|  |         try { | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute(); | ||
|  |             if(!$res) { | ||
|  |                 error_log('['.date('Y-m-d H:i:s').']'.$sql.':'.json_encode($st->errorInfo())."\n", 3, LOG_PATH_BASE.'/mysql/execute_'.date('Y-m-d').'.log'); | ||
|  |                 return false; | ||
|  |             } | ||
|  | 
 | ||
|  |             if(!$is_select) return $res; | ||
|  |             $this->logSql('execute', 'execute', $sql, array()); | ||
|  |             if($all_rows==true) { | ||
|  |                 $this->rownum = $st->rowCount(); | ||
|  |                 return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  |             } else { | ||
|  |                 return $st->fetch(PDO::FETCH_ASSOC); | ||
|  |             } | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /* | ||
|  |      * 数据库事务操作 | ||
|  |      * 封装标准方法 | ||
|  |      * @param string $sqls sql语句数组 | ||
|  |      * 将根据sql数组index顺序执行,执行SQL的表必须是innodb | ||
|  |      */ | ||
|  |     public function execTrans($sqls) { | ||
|  |         $this->ismaster = true; | ||
|  |         self::getInstance(); | ||
|  | 
 | ||
|  |         try { | ||
|  |             self::$link->beginTransaction();	// 开启事务处 | ||
|  | 
 | ||
|  |             foreach ($sqls as $sql) { | ||
|  |                 if(trim($sql)=='') continue; | ||
|  | 
 | ||
|  |                 $st = self::$link->prepare($sql); | ||
|  |                 $res = $st->execute(); | ||
|  |                 if(!$res) { | ||
|  |                     self::$link->rollBack(); | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 $st->closeCursor(); | ||
|  |             } | ||
|  | 
 | ||
|  |             self::$link->commit();				// 事务处理结束 | ||
|  | 
 | ||
|  |         } catch(PDOException $e) { | ||
|  |         	return false; | ||
|  |         } | ||
|  |         return true; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 执行自定义SQL语句 | ||
|  |      * @param unknown $sql | ||
|  |      * @param boolean $is_list 是否为列表,否则单条记录 | ||
|  |      */ | ||
|  |     public function exec($sql, $is_list=true) { | ||
|  |         self::getInstance(); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $st = self::$link->prepare($sql['sql']); | ||
|  |             $res = $st->execute($sql['vals']); | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             if($is_list) { | ||
|  |                 return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  |             } else { | ||
|  |                 return $st->fetch(PDO::FETCH_ASSOC); | ||
|  |             } | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 累计统计数据 | ||
|  |      * @param string $table | ||
|  |      * @param string $sum_fields 累计字段,比如array('field'=>'alias_field', ...) | ||
|  |      * @param array $where where条件,比如:array('sql'=>'name1=? and name2=?', 'vals'=>array('name1', 'name2')) | ||
|  |      * @return array | ||
|  |      */ | ||
|  |     public function sum($table, $fields, $sum_fields, $where) { | ||
|  |         $this->initDb($table); | ||
|  | 
 | ||
|  |         try { | ||
|  |             $wheresql = ''; | ||
|  |             if(!empty($where)) { | ||
|  |                 $wheresql = "WHERE {$where['sql']}"; | ||
|  |                 $vals = $where['vals']; | ||
|  |             } | ||
|  | 
 | ||
|  |             $sumgroup = $sumsql = "`".implode('`, `', $fields)."`"; | ||
|  |             foreach ($sum_fields as $field => $alias_field) { | ||
|  |                 $sumsql .= ", sum(`{$field}`) as $alias_field"; | ||
|  |             } | ||
|  | 
 | ||
|  |             $sql = "SELECT {$sumsql} FROM `{$this->table}` {$wheresql} GROUP BY {$sumgroup}"; | ||
|  |             $this->logSql($table, 'count', $sql, $vals); | ||
|  | 
 | ||
|  |             $st = self::$link->prepare($sql); | ||
|  |             $res = $st->execute($vals); | ||
|  |             if(!$res) return false; | ||
|  | 
 | ||
|  |             return $st->fetchAll(PDO::FETCH_ASSOC); | ||
|  |         } catch(PDOException $e) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * 解析数据库配置信息 | ||
|  |      * 获得数据库的相关连接信息 | ||
|  |      * @param sting $dbflag 数据库标识 | ||
|  |      * @param boolean $master 是否为主库 | ||
|  |      */ | ||
|  |     private function parseDbCnf($dbflag,$master=false) { | ||
|  |         $configs = parse_ini_file(_Storage_CNF_PATH, true); | ||
|  |         $config = $configs[strtolower($dbflag)]; | ||
|  | 
 | ||
|  |         if($master)	{ | ||
|  |             $host_port = $config['master']; | ||
|  |         } else { | ||
|  |             $host_port = $config['slave']; | ||
|  |         } | ||
|  |         $hps = explode(',', $host_port); | ||
|  |         $random = rand(0, count($hps)-1); | ||
|  |         $hp = $hps[$random]; | ||
|  | 
 | ||
|  |         list($host, $port) = explode(':', $hp); | ||
|  | 
 | ||
|  |         $cnf = array(); | ||
|  |         $cnf['host'] = trim($host); | ||
|  |         $cnf['port'] = trim($port); | ||
|  |         $cnf['user'] = $master==false ? trim($config['user_r']) : trim($config['user']); | ||
|  |         $cnf['pwd'] = $master==false ? trim($config['passwd_r']) : trim($config['passwd']); | ||
|  |         $cnf['db'] = trim($config['db']); | ||
|  |         return $cnf; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * CUrl封装的get方式请求API的方法 | ||
|  |      * @param string $url URL | ||
|  |      * @param int $timeout 超时时间 | ||
|  |      */ | ||
|  |     public function getCUrl($url, $timeout=3) { | ||
|  |         $ch = curl_init(); | ||
|  |         curl_setopt($ch, CURLOPT_URL, $url); | ||
|  |         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | ||
|  |         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); | ||
|  | 
 | ||
|  |         //分析是否开启SSL加密 | ||
|  |         $ssl = substr($url, 0, 8) == 'https://' ? true : false; | ||
|  |         if ($ssl) { | ||
|  |             curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查 | ||
|  |             curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在 | ||
|  |         } | ||
|  | 
 | ||
|  |         $res = curl_exec($ch); | ||
|  |         if(curl_error($ch)=='') { | ||
|  |             curl_close($ch); | ||
|  |             return $res; | ||
|  |         } | ||
|  |         curl_close($ch); | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * CUrl封装的get方式请求API的方法 | ||
|  |      * @param string $url | ||
|  |      * @param array $data post数据 | ||
|  |      * @param int $timeout 超时时间 | ||
|  |      */ | ||
|  |     public function postCUrl($url, $data, $timeout=3) { | ||
|  |         $ch = curl_init(); | ||
|  | 
 | ||
|  |         $urlinfo = parse_url($url); | ||
|  |         $domain = $urlinfo['host']; | ||
|  |         $headers = array("Host: $domain"); | ||
|  |         curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); | ||
|  | 
 | ||
|  |         //分析是否开启SSL加密 | ||
|  |         $ssl = substr($url, 0, 8) == 'https://' ? true : false; | ||
|  |         if ($ssl) { | ||
|  |             curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查 | ||
|  |             curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在 | ||
|  |         } | ||
|  | 
 | ||
|  |         curl_setopt($ch, CURLOPT_URL, $url); | ||
|  |         curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); | ||
|  |         curl_setopt($ch, CURLOPT_POST, true); | ||
|  |         curl_setopt($ch, CURLOPT_POSTFIELDS, $data); | ||
|  |         curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); | ||
|  |         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); | ||
|  | 
 | ||
|  |         $res = curl_exec($ch); | ||
|  |         if(curl_error($ch)=='') { | ||
|  |             curl_close($ch); | ||
|  |             return $res; | ||
|  |         } | ||
|  |         curl_close($ch); | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  | } | ||
|  | 
 |