<?php
/**
* 數據庫PDO操作
*/
class MysqlPdo {
public static $PDOStatement = null;
/**
* 數據庫的連接參數配置
* @var array
* @access public
*/
public static $config = array();
/**
* 是否使用永久連接
* @var bool
* @access public
*/
public static $pconnect = false;
/**
* 錯誤信息
* @var string
* @access public
*/
public static $error = '';
/**
* 單件模式,保存Pdo類唯一實例,數據庫的連接資源
* @var object
* @access public
*/
protected static $link;
/**
* 是否已經連接數據庫
* @var bool
* @access public
*/
public static $connected = false;
/**
* 數據庫版本
* @var string
* @access public
*/
public static $dbVersion = null;
/**
* 當前SQL語句
* @var string
* @access public
*/
public static $queryStr = '';
/**
* 最后插入記錄的ID
* @var integer
* @access public
*/
public static $lastInsertId = null;
/**
* 返回影響記錄數
* @var integer
* @access public
*/
public static $numRows = 0;
// 事務指令數
public static $transTimes = 0;
/**
* 構造函數,
* @param $dbconfig 數據庫連接相關信息,array('ServerName', 'UserName', 'Password', 'DefaultDb', 'DB_Port', 'DB_TYPE')
*/
public function __construct($dbConfig=''){
if (!class_exists('PDO')) throw_exception("不支持:PDO");
//若沒有傳輸任何參數,則使用默認的數據定義
if (!is_array($dbConfig)) {
$dbConfig = array(
'hostname' => DB_HOST,
'username' => DB_USER,
'password' => DB_PWD,
'database' => DB_NAME,
'hostport' => DB_PORT,
'dbms' => DB_TYPE,
'dsn' => DB_TYPE.":host=".DB_HOST.";dbname=".DB_NAME
);
}
if(empty($dbConfig['hostname'])) throw_exception("沒有定義數據庫配置");
self::$config = $dbConfig;
if(empty(self::$config['params'])) self::$config['params'] = array();
/*************************************華麗分隔線*******************************************/
if (!isset(self::$link) ) {
$configs = self::$config;
if(self::$pconnect) {
$configs['params'][constant('PDO::ATTR_PERSISTENT')] = true;
}
try {
self::$link = new PDO( $configs['dsn'], $configs['username'], $configs['password'],$configs['params']);
} catch (PDOException $e) {
throw_exception($e->getMessage());
//exit('連接失敗:'.$e->getMessage());
}
if(!self::$link) {
throw_exception('PDO CONNECT ERROR');
return false;
}
self::$link->exec('SET NAMES '.DB_CHARSET);
self::$dbVersion = self::$link->getAttribute(constant("PDO::ATTR_SERVER_INFO"));
// 標記連接成功
self::$connected = true;
// 注銷數據庫連接配置信息
unset($configs);
}
return self::$link;
}
/**
* 釋放查詢結果
* @access function
*/
static function free() {
self::$PDOStatement = null;
}
/*********************************************************************************************************/
/* 數據庫操作 */
/*********************************************************************************************************/
/**
* 獲得所有的查詢數據
* @access function
* @return array
*/
static function getAll($sql=null) {
self::query($sql);
//返回數據集
$result = self::$PDOStatement->fetchAll(constant('PDO::FETCH_ASSOC'));
return $result;
}
/**
* 獲得一條查詢結果
* @access function
* @param string $sql SQL指令
* @param integer $seek 指針位置
* @return array
*/
static function getRow($sql=null) {
self::query($sql);
// 返回數組集
$result = self::$PDOStatement->fetch(constant('PDO::FETCH_ASSOC'),constant('PDO::FETCH_ORI_NEXT'));
return $result;
}
/**
* 執行sql語句,自動判斷進行查詢或者執行操作
* @access function
* @param string $sql SQL指令
* @return mixed
*/
static function doSql($sql='') {
if(self::isMainIps($sql)) {
return self::execute($sql);
}else {
return self::getAll($sql);
}
}
/**
* 根據指定ID查找表中記錄(僅用於單表操作)
* @access function
* @param integer $priId 主鍵ID
* @param string $tables 數據表名
* @param string $fields 字段名
* @return ArrayObject 表記錄
*/
static function findById($tabName,$priId,$fields='*'){
$sql = 'SELECT %s FROM %s WHERE id=%d';
return self::getRow(sprintf($sql, self::parseFields($fields), $tabName, $priId));
}
/**
* 查找記錄
* @access function
* @param string $tables 數據表名
* @param mixed $where 查詢條件
* @param string $fields 字段名
* @param string $order 排序
* @param string $limit 取多少條數據
* @param string $group 分組
* @param string $having
* @param boolean $lock 是否加鎖
* @return ArrayObject
*/
static function find($tables,$where="",$fields='*',$order=null,$limit=null,$group=null,$having=null) {
$sql = 'SELECT '.self::parseFields($fields)
.' FROM '.$tables
.self::parseWhere($where)
.self::parseGroup($group)
.self::parseHaving($having)
.self::parseOrder($order)
.self::parseLimit($limit);
$dataAll = self::getAll($sql);
if(count($dataAll)==1){$rlt=$dataAll[0];}else{$rlt=$dataAll;}
return $rlt;
}
/**
* 插入(單條)記錄
* @access function
* @param mixed $data 數據
* @param string $table 數據表名
* @return false | integer
*/ static function add($data,$table) { //過濾提交數據 $data=self::filterPost($table,$data); foreach ($data as $key=>$val){ if(is_array($val) && strtolower($val[0]) == 'exp') { $val = $val[1]; // 使用表達式 ??? }elseif (is_scalar($val)){ $val = self::fieldFormat($val); }else{ // 去掉復合對象 continue; } $data[$key] = $val; } $fields = array_keys($data); array_walk($fields, array($this, 'addSpecialChar')); $fieldsStr = implode(',', $fields); $values = array_values($data); $valuesStr = implode(',', $values); $sql = 'INSERT INTO '.$table.' ('.$fieldsStr.') VALUES ('.$valuesStr.')'; return self::execute($sql); } /** * 更新記錄 * @access function * @param mixed $sets 數據 * @param string $table 數據表名 * @param string $where 更新條件 * @param string $limit * @param string $order * @return false | integer */ static function update($sets,$table,$where,$limit=0,$order='') { $sets = self::filterPost($table,$sets); $sql = 'UPDATE '.$table.' SET '.self::parseSets($sets).self::parseWhere($where).self::parseOrder($order).self::parseLimit($limit); return self::execute($sql); } /** * 保存某個字段的值 * @access function * @param string $field 要保存的字段名 * @param string $value 字段值 * @param string $table 數據表 * @param string $where 保存條件 * @param boolean $asString 字段值是否為字符串 * @return void */ static function setField($field, $value, $table, $condition="", $asString=false) { // 如果有'(' 視為 SQL指令更新 否則 更新字段內容為純字符串 if(false === strpos($value,'(') || $asString) $value = '"'.$value.'"'; $sql = 'UPDATE '.$table.' SET '.$field.'='.$value.self::parseWhere($condition); return self::execute($sql); } /** * 刪除記錄 * @access function * @param mixed $where 為條件Map、Array或者String * @param string $table 數據表名 * @param string $limit * @param string $order * @return false | integer */ static function remove($where,$table,$limit='',$order='') { $sql = 'DELETE FROM '.$table.self::parseWhere($where).self::parseOrder($order).self::parseLimit($limit); return self::execute($sql); } /** +---------------------------------------------------------- * 修改或保存數據(僅用於單表操作) * 有主鍵ID則為修改,無主鍵ID則為增加 * 修改記錄: +---------------------------------------------------------- * @access function +---------------------------------------------------------- * @param $tabName 表名 * @param $aPost 提交表單的 $_POST * @param $priId 主鍵ID * @param $aNot 要排除的一個字段或數組 * @param $aCustom 自定義的一個數組,附加到數據庫中保存 * @param $isExits 是否已經存在 存在:true, 不存在:false +---------------------------------------------------------- * @return Boolean 修改或保存是否成功 +---------------------------------------------------------- */ static function saveOrUpdate($tabName, $aPost, $priId="", $aNot="", $aCustom="", $isExits=false) { if(empty($tabName) || !is_array($aPost) || is_int($aNot)) return false; if(is_string($aNot) && !empty($aNot)) $aNot = array($aNot); if(is_array($aNot) && is_int(key($aNot))) $aPost = array_diff_key($aPost, array_flip($aNot)); if(is_array($aCustom) && is_string(key($aCustom))) $aPost = array_merge($aPost,$aCustom); if (empty($priId) && !$isExits) { //新增 $aPost = array_filter($aPost, array($this, 'removeEmpty')); return self::add($aPost, $tabName); } else { //修改 return self::update($aPost, $tabName, "id=".$priId); } } /** * 獲取最近一次查詢的sql語句 * @access function * @param * @return String 執行的SQL */ static function getLastSql() { $link = self::$link; if ( !$link ) return false; return self::$queryStr; } /** * 獲取最后插入的ID * @access function * @param * @return integer 最后插入時的數據ID */ static function getLastInsId(){ $link = self::$link; if ( !$link ) return false; return self::$lastInsertId; } /** * 獲取DB版本 * @access function * @param * @return string */ static function getDbVersion(){ $link = self::$link; if ( !$link ) return false; return self::$dbVersion; } /** * 取得數據庫的表信息 * @access function * @return array */ static function getTables() { $info = array(); if(self::query("SHOW TABLES")) { $result = self::getAll(); foreach ($result as $key => $val) { $info[$key] = current($val); } } return $info; } /** * 取得數據表的字段信息 * @access function * @return array */ static function getFields($tableName) { // 獲取數據庫聯接 $link = self::$link; $sql = "SELECT ORDINAL_POSITION ,COLUMN_NAME, COLUMN_TYPE, DATA_TYPE, IF(ISNULL(CHARACTER_MAXIMUM_LENGTH), (NUMERIC_PRECISION + NUMERIC_SCALE), CHARACTER_MAXIMUM_LENGTH) AS MAXCHAR, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_KEY, EXTRA, COLUMN_COMMENT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = :tabName AND TABLE_SCHEMA='".DB_NAME."'"; self::$queryStr = sprintf($sql, $tableName); $sth = $link->prepare($sql); $sth->bindParam(':tabName', $tableName); $sth->execute(); $result = $sth->fetchAll(constant('PDO::FETCH_ASSOC')); $info = array(); foreach ($result as $key => $val) { $info[$val['COLUMN_NAME']] = array( 'postion' => $val['ORDINAL_POSITION'], 'name' => $val['COLUMN_NAME'], 'type' => $val['COLUMN_TYPE'], 'd_type' => $val['DATA_TYPE'], 'length' => $val['MAXCHAR'], 'notnull' => (strtolower($val['IS_NULLABLE']) == "no"), 'default' => $val['COLUMN_DEFAULT'], 'primary' => (strtolower($val['COLUMN_KEY']) == 'pri'), 'autoInc' => (strtolower($val['EXTRA']) == 'auto_increment'), 'comment' => $val['COLUMN_COMMENT'] ); } // 有錯誤則拋出異常 self::haveErrorThrowException(); return $info; } /** * 關閉數據庫 * @access function */ static function close() { self::$link = null; } /** * SQL指令安全過濾 * @access function * @param string $str SQL指令 * @return string */ static function escape_string($str) { return addslashes($str); } /*********************************************************************************************************/ /* 內部操作方法 */ /*********************************************************************************************************/ /** * 有出錯拋出異常 * @access function * @return */ static function haveErrorThrowException() { $obj = empty(self::$PDOStatement) ? self::$link : self::$PDOStatement; $arrError = $obj->errorInfo(); if(count($arrError) > 1) { // 有錯誤信息 //$this->rollback(); self::$error = $arrError[2]. "<br/><br/> [ SQL語句 ] : ".self::$queryStr; //throw_exception($this->error); throw_exception(self::$error); return false; } //主要針對execute()方法拋出異常 if(self::$queryStr=='')throw_exception('Query was empty<br/><br/>[ SQL語句 ] :'); } /** * where分析 * @access function * @param mixed $where 查詢條件 * @return string */ static function parseWhere($where) { $whereStr = ''; if(is_string($where) || is_null($where)) { $whereStr = $where; } return empty($whereStr)?'':' WHERE '.$whereStr; } /** * order分析 * @access function * @param mixed $order 排序 * @return string */ static function parseOrder($order) { $orderStr = ''; if(is_array($order)) $orderStr .= ' ORDER BY '.implode(',', $order); else if(is_string($order) && !empty($order)) $orderStr .= ' ORDER BY '.$order; return $orderStr; } /** * limit分析 * @access function * @param string $limit * @return string */ static function parseLimit($limit) { $limitStr = ''; if(is_array($limit)) { if(count($limit)>1) $limitStr .= ' LIMIT '.$limit[0].' , '.$limit[1].' '; else $limitStr .= ' LIMIT '.$limit[0].' '; } else if(is_string($limit) && !empty($limit)) { $limitStr .= ' LIMIT '.$limit.' '; } return $limitStr; } /** * group分析 * @access function * @param mixed $group * @return string */ static function parseGroup($group) { $groupStr = ''; if(is_array($group)) $groupStr .= ' GROUP BY '.implode(',', $group); else if(is_string($group) && !empty($group)) $groupStr .= ' GROUP BY '.$group; return empty($groupStr)?'':$groupStr; } /** * having分析 * @access function * @param string $having * @return string */ static function parseHaving($having) { $havingStr = ''; if(is_string($having) && !empty($having)) $havingStr .= ' HAVING '.$having; return $havingStr; } /** * fields分析 * @access function * @param mixed $fields * @return string */ static function parseFields($fields) { if(is_array($fields)) { array_walk($fields, array($this, 'addSpecialChar')); $fieldsStr = implode(',', $fields); }else if(is_string($fields) && !empty($fields)) { if( false === strpos($fields,'`') ) { $fields = explode(',',$fields); array_walk($fields, array($this, 'addSpecialChar')); $fieldsStr = implode(',', $fields); }else { $fieldsStr = $fields; } }else $fieldsStr = '*'; return $fieldsStr; } /** * sets分析,在更新數據時調用 * @access function * @param mixed $values * @return string */ private function parseSets($sets) { $setsStr = ''; if(is_array($sets)){ foreach ($sets as $key=>$val){ $key = self::addSpecialChar($key); $val = self::fieldFormat($val); $setsStr .= "$key = ".$val.","; } $setsStr = substr($setsStr,0,-1); }else if(is_string($sets)) { $setsStr = $sets; } return $setsStr; } /** * 字段格式化 * @access function * @param mixed $value * @return mixed */ static function fieldFormat(&$value) { if(is_int($value)) { $value = intval($value); } else if(is_float($value)) { $value = floatval($value); } elseif(preg_match('/^\(\w*(\+|\-|\*|\/)?\w*\)$/i',$value)){ // 支持在字段的值里面直接使用其它字段 // 例如 (score+1) (name) 必須包含括號 $value = $value; }else if(is_string($value)) { $value = '\''.self::escape_string($value).'\''; } return $value; } /** * 字段和表名添加` 符合 * 保證指令中使用關鍵字不出錯 針對mysql * @access function * @param mixed $value * @return mixed */ static function addSpecialChar(&$value) { if( '*' == $value || false !== strpos($value,'(') || false !== strpos($value,'.') || false !== strpos($value,'`')) { //如果包含* 或者 使用了sql方法 則不作處理 } elseif(false === strpos($value,'`') ) { $value = '`'.trim($value).'`'; } return $value; } /** +---------------------------------------------------------- * 去掉空元素 +---------------------------------------------------------- * @access function +---------------------------------------------------------- * @param mixed $value +---------------------------------------------------------- * @return mixed +---------------------------------------------------------- */ static function removeEmpty($value){ return !empty($value); } /** * 執行查詢 主要針對 SELECT, SHOW 等指令 * @access function * @param string $sql sql指令 * @return mixed */ static function query($sql='') { // 獲取數據庫聯接 $link = self::$link; if ( !$link ) return false; self::$queryStr = $sql; //釋放前次的查詢結果 if ( !empty(self::$PDOStatement) ) self::free(); self::$PDOStatement = $link->prepare(self::$queryStr); $bol = self::$PDOStatement->execute(); // 有錯誤則拋出異常 self::haveErrorThrowException(); return $bol; } /** * 數據庫操作方法 * @access function * @param string $sql 執行語句 * @param boolean $lock 是否鎖定(默認不鎖定) * @return void public function execute($sql='',$lock=false) { if(empty($sql)) $sql = $this->queryStr; return $this->_execute($sql); }*/ /** * 執行語句 針對 INSERT, UPDATE 以及DELETE * @access function * @param string $sql sql指令 * @return integer */ static function execute($sql='') { // 獲取數據庫聯接 $link = self::$link; if ( !$link ) return false; self::$queryStr = $sql; //釋放前次的查詢結果 if ( !empty(self::$PDOStatement) ) self::free(); $result = $link->exec(self::$queryStr); // 有錯誤則拋出異常 self::haveErrorThrowException(); if ( false === $result) { return false; } else { self::$numRows = $result; self::$lastInsertId = $link->lastInsertId(); return self::$numRows; } } /** * 是否為數據庫更改操作 * @access private * @param string $query SQL指令 * @return boolen 如果是查詢操作返回false */ static function isMainIps($query) { $queryIps = 'INSERT|UPDATE|DELETE|REPLACE|CREATE|DROP|LOAD DATA|SELECT .* INTO|COPY|ALTER|GRANT|REVOKE|LOCK|UNLOCK'; if (preg_match('/^\s*"?(' . $queryIps . ')\s+/i', $query)) { return true; } return false; } /** * 過濾POST提交數據 * @access private * @param mixed $data POST提交數據 * @param string $table 數據表名 * @return mixed $newdata */ static function filterPost($table,$data) { $table_column = self::getFields($table); $newdata=array(); foreach ($table_column as $key=>$val){ if(array_key_exists($key,$data) && ($data[$key])!==''){ $newdata[$key] = $data[$key]; } } return $newdata; } /** * 啟動事務 * @access function * @return void */ static function startTrans() { //數據rollback 支持 $link = self::$link; if ( !$link ) return false; if (self::$transTimes == 0) { $link->beginTransaction(); } self::$transTimes++; return ; } /** * 用於非自動提交狀態下面的查詢提交 * @access function * @return boolen */ static function commit() { $link = self::$link; if ( !$link ) return false; if (self::$transTimes > 0) { $result = $link->commit(); self::$transTimes = 0; if(!$result){ throw_exception(self::$error()); return false; } } return true; } /** * 事務回滾 * @access function * @return boolen */ public function rollback() { $link = self::$link; if ( !$link ) return false; if (self::$transTimes > 0) { $result = $link->rollback(); self::$transTimes = 0; if(!$result){ throw_exception(self::$error()); return false; } } return true; } } ?>