~~~ <?php define('PDO_DEBUG', true); class MySqlPDO { protected $pdo; protected $cfg; protected $tablepre; protected $errors = array(); public function __construct($config) { $this->cfg = $config; $this->connect($name); } /** * @param string $name */ public function connect(){ $this->tablepre = $cfg['tablepre']; if(empty($cfg)) { exit("The master database is not found, Please checking 'data/config.php'"); } $dsn = "mysql:dbname={$cfg['database']};host={$cfg['host']};port={$cfg['port']};charset={$cfg['charset']}"; $options = array(); $this->pdo = new PDO($dsn, $cfg['username'], $cfg['password'], $options); $sql = "SET NAMES '{$cfg['charset']}';"; $this->pdo->exec($sql); $this->pdo->exec("SET sql_mode='';"); if(is_string($name)) { $this->link[$name] = $this->pdo; } self::sqllog($sql); } /** * @param $sql */ public function run($sql){ if(!isset($sql) || empty($sql)) return; $sql = str_replace("\r", "\n", str_replace(' ' . $this->tablepre, ' ' . $this->tablepre, $sql)); $sql = str_replace("\r", "\n", str_replace(' `' . $this->tablepre, ' `' . $this->tablepre, $sql)); $ret = array(); $num = 0; $sql = preg_replace("/\;[ \f\t\v]+/", ';', $sql); foreach(explode(";\n", trim($sql)) as $query) { $ret[$num] = ''; $queries = explode("\n", trim($query)); foreach($queries as $query) { $ret[$num] .= (isset($query[0]) && $query[0] == '#') || (isset($query[1]) && isset($query[1]) && $query[0].$query[1] == '--') ? '' : $query; } $num++; } unset($sql); foreach($ret as $query) { $query = trim($query); if($query) { $this->query($query, array()); } } } /** * @param $tablename * @param $fieldname * @return bool */ public function fieldexists($tablename, $fieldname) { $isexists = $this->fetch("DESCRIBE " . $this->tablename($tablename) . " `{$fieldname}`", array()); return !empty($isexists) ? true : false; } /** * @param $tablename * @param $fieldname * @param string $datatype * @param string $length * @return bool|int */ public function fieldmatch($tablename, $fieldname, $datatype = '', $length = '') { $datatype = strtolower($datatype); $field_info = $this->fetch("DESCRIBE " . $this->tablename($tablename) . " `{$fieldname}`", array()); if (empty($field_info)) { return false; } if (!empty($datatype)) { $find = strexists($field_info['Type'], '('); if (empty($find)) { $length = ''; } if (!empty($length)) { $datatype .= ("({$length})"); } return strpos($field_info['Type'], $datatype) === 0 ? true : -1; } return true; } /** * @param $tablename * @param $indexname * @return array|bool */ public function indexexists($tablename, $indexname) { if (!empty($indexname)) { $indexs = $this->fetchall("SHOW INDEX FROM " . $this->tablename($tablename), array(), ''); if (!empty($indexs) && is_array($indexs)) { foreach ($indexs as $row) { if ($row['Key_name'] == $indexname) { return true; } } } } return $indexs; } /** * @param $table * @return bool */ public function tableexists($table) { if(!empty($table)) { $data = $this->fetch("SHOW TABLES LIKE '{$this->tablepre}{$table}'", array()); if(!empty($data)) { $data = array_values($data); $tablename = $this->tablepre . $table; if(in_array($tablename, $data)) { return true; } else { return false; } } else { return false; } } else { return false; } } /** * @param $tablename * @param array $params * @param int $cachetime * @return int */ public function count($tablename, $params = array(), $cachetime = 30) { $total = pdo_getcolumn($tablename, $params, 'count(*)'); return intval($total); } /** * @param $tablename * @param array $params * @param string $field * @return bool|mixed */ public function getcolumn($tablename, $params = array(), $field = '') { $result = $this->get($tablename, $params, $field); if (!empty($result)) { if (strexists($field, '(')) { return array_shift($result); } else { return $result[$field]; } } else { return false; } } /** * @param $tablename * @param array $params * @return bool */ public function exists($tablename, $params = array()) { $row = $this->get($tablename, $params); if (empty($row) || !is_array($row) || count($row) == 0) { return false; } else { return true; } } /** * @param $tablename * @param array $params * @param array $limit * @param null $total * @param array $fields * @param string $keyfield * @param array $orderby * @return array */ public function getslice($tablename, $params = array(), $limit = array(), &$total = null, $fields = array(), $keyfield = '', $orderby = array()) { $select = SqlPaser::parseSelect($fields); $condition = SqlPaser::parseParameter($params, 'AND'); $limitsql = SqlPaser::parseLimit($limit); if (!empty($orderby)) { if (is_array($orderby)) { $orderbysql = implode(',', $orderby); } else { $orderbysql = $orderby; } } $sql = "{$select} FROM " . $this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . (!empty($orderbysql) ? " ORDER BY $orderbysql " : '') . $limitsql; $total = pdo_fetchcolumn("SELECT COUNT(*) FROM " . tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : ''), $condition['params']); return $this->fetchall($sql, $condition['params'], $keyfield); } /** * @param $tablename * @param array $params * @param array $fields * @param array $orderby * @return bool */ public function get($tablename, $params = array(), $fields = array(), $orderby = array()) { $select = SqlPaser::parseSelect($fields); $condition = SqlPaser::parseParameter($params, 'AND'); $orderbysql = SqlPaser::parseOrderby($orderby); $sql = "{$select} FROM " . $this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . " $orderbysql LIMIT 1"; return $this->fetch($sql, $condition['params']); } /** * @param $tablename * @param array $params * @param array $fields * @param string $keyfield * @param array $orderby * @param array $limit * @return array */ public function getall($tablename, $params = array(), $fields = array(), $keyfield = '', $orderby = array(), $limit = array()) { $select = SqlPaser::parseSelect($fields); $condition = SqlPaser::parseParameter($params, 'AND'); $limitsql = SqlPaser::parseLimit($limit); $orderbysql = SqlPaser::parseOrderby($orderby); $sql = "{$select} FROM " .$this->tablename($tablename) . (!empty($condition['fields']) ? " WHERE {$condition['fields']}" : '') . $orderbysql . $limitsql; return $this->fetchall($sql, $condition['params'], $keyfield); } /** * @param $sql * @param array $params * @return bool */ public function fetch($sql, $params = array()) { $statement = $this->prepare($sql); $result = $statement->execute($params); self::sqllog($sql, $params, $statement->errorInfo()); if (!$result) { return false; } else { $data = $statement->fetch(PDO::FETCH_ASSOC); return $data; } } /** * @param $sql * @param array $params * @param string $keyfield * @return array|bool */ public function fetchall($sql, $params = array(), $keyfield = '') { $statement = $this->prepare($sql); $result = $statement->execute($params); self::sqllog($sql, $params, $statement->errorInfo()); if(!$result){ return false; }else{ if (empty($keyfield)) { $result = $statement->fetchAll(pdo::FETCH_ASSOC); }else{ $temp = $statement->fetchAll(pdo::FETCH_ASSOC); $result = array(); if (!empty($temp)) { foreach ($temp as $key => &$row) { if (isset($row[$keyfield])) { $result[$row[$keyfield]] = $row; } else { $result[] = $row; } } } } return $result; } } /** * @param $sql * @param array $params * @param int $column * @return bool */ public function fetchcolumn($sql, $params = array(), $column = 0) { $statement = $this->prepare($sql); $result = $statement->execute($params); self::sqllog($sql, $params, $statement->errorInfo()); if (!$result) { return false; } else { $data = $statement->fetchColumn($column); return $data; } } /** * @param $table * @param array $data * @param array $params * @param string $glue * @return bool */ public function update($table, $data = array(), $params = array(), $glue = 'AND'){ $fields = SqlPaser::parseParameter($data, ','); $condition = SqlPaser::parseParameter($params, $glue); $params = array_merge($fields['params'], $condition['params']); $sql = "UPDATE " . $this->tablename($table) . " SET {$fields['fields']}"; $sql .= $condition['fields'] ? ' WHERE '.$condition['fields'] : ''; return $this->query($sql, $params); } /** * @param $table * @param array $params * @param string $glue * @return bool */ public function delete($table, $params = array(), $glue = 'AND') { $this->tablename($table); $condition = SqlPaser::parseParameter($params, $glue); $sql = "DELETE FROM " . $this->tablename($table); $sql .= $condition['fields'] ? ' WHERE '.$condition['fields'] : ''; return $this->query($sql, $condition['params']); } /** * @param $table * @param array $data * @param bool $replace * @return bool */ public function insert($table, $data = array(), $replace = FALSE){ $cmd = $replace ? 'REPLACE INTO' : 'INSERT INTO'; $condition = SqlPaser::parseParameter($data, ','); return $this->query("$cmd " . $this->tablename($table) . " SET {$condition['fields']}", $condition['params']); } /** * @param $sql * @param array $params * @return bool */ public function query($sql, $params = array()){ $sqlsafe = SqlPaser::checkquery($sql); if($sqlsafe){ $starttime = microtime(true); if(empty($params)){ $result = $this->pdo->exec($sql); self::sqllog($sql, array(), $this->pdo->errorInfo()); return $result; } $statement = $this->prepare($sql); $result = $statement->execute($params); self::sqllog($sql, $params, $statement->errorInfo()); if (!$result) { return false; } else { return $statement->rowCount(); } } } /** * @param $sql * @return mixed */ public function prepare($sql){ $sqlsafe = SqlPaser::checkquery($sql); if($sqlsafe){ $statement = $this->pdo->prepare($sql); return $statement; } } /** * @return mixed */ public function insertid() { return $this->pdo->lastInsertId(); } /** * 事务开始 */ public function begin() { $this->pdo->beginTransaction(); } /** * 提交事务 */ public function commit() { $this->pdo->commit(); } /** * 回滚事务 */ public function rollback() { $this->pdo->rollBack(); } /** * @param $table * @return string */ public function tablename($table) { return (strpos($table, $this->tablepre) === 0 || strpos($table, 'ims_') === 0) ? $table : "`{$this->tablepre}{$table}`"; } /** * @param bool $output * @param array $append * @return array */ public function debug($output = true, $append = array()){ if(!empty($append)) { $output = false; array_push($this->errors, $append); } if($output) { print_r($this->errors); }else{ if (!empty($append['error'][1])) { $traces = debug_backtrace(); $ts = ''; foreach($traces as $trace) { $trace['file'] = str_replace('\\', '/', $trace['file']); $trace['file'] = str_replace(IA_ROOT, '', $trace['file']); $ts .= "file: {$trace['file']}; line: {$trace['line']}; <br />"; } $params = var_export($append['params'], true); trigger_error("SQL: <br/>{$append['sql']}<hr/>Params: <br/>{$params}<hr/>SQL Error: <br/>{$append['error'][2]}<hr/>Traces: <br/>{$ts}", E_USER_WARNING); } } return $this->errors; } /** * @param $sql * @param array $params * @param string $message * @return bool */ private function sqllog($sql, $params = array(), $message = '') { if(PDO_DEBUG) { $info = array(); $info['sql'] = $sql; $info['params'] = $params; $info['error'] = empty($message) ? $this->pdo->errorInfo() : $message; self::debug(false, $info); } return true; } } class SqlPaser { private static $checkcmd = array( 'SELECT', 'UPDATE', 'INSERT','REPLAC','DELETE','ALTER' ); private static $disable = array( 'function' => array('load_file', 'floor', 'hex', 'substring', 'if', 'ord', 'char', 'benchmark', 'reverse', 'strcmp', 'datadir', 'updatexml', 'extractvalue', 'name_const', 'multipoint', 'database', 'user'), 'action' => array('@', 'intooutfile', 'intodumpfile', 'unionselect', 'uniondistinct', 'information_schema', 'current_user', 'current_date'), 'note' => array('/*','*/','#','--'), ); public static function parseOrderby($orderby, $alias = '') { $orderbysql = ''; if (empty($orderby)) { return $orderbysql; } if (!is_array($orderby)) { $orderby = explode(',', $orderby); } foreach ($orderby as $i => &$row) { $row = strtolower($row); list($field, $orderbyrule) = explode(' ', $row); if ($orderbyrule != 'asc' && $orderbyrule != 'desc') { unset($orderby[$i]); } $field = self::parseFieldAlias($field, $alias); $row = "{$field} {$orderbyrule}"; } $orderbysql = implode(',', $orderby); return !empty($orderbysql) ? " ORDER BY $orderbysql " : ''; } public static function parseLimit($limit, $inpage = true) { $limitsql = ''; if (empty($limit)) { return $limitsql; } if (is_array($limit)) { if (empty($limit[0]) && !empty($limit[1])) { $limitsql = " LIMIT 0, " . $limit[1]; } else { $limit[0] = max(intval($limit[0]), 1); !empty($limit[1]) && $limit[1] = max(intval($limit[1]), 1); if (empty($limit[0]) && empty($limit[1])) { $limitsql = ''; } elseif (!empty($limit[0]) && empty($limit[1])) { $limitsql = " LIMIT " . $limit[0]; } else { $limitsql = " LIMIT " . ($inpage ? ($limit[0] - 1) * $limit[1] : $limit[0]) . ', ' . $limit[1]; } } } else { $limit = trim($limit); if (preg_match('/^(?:limit)?[\s,0-9]+$/i', $limit)) { $limitsql = strexists(strtoupper($limit), 'LIMIT') ? " $limit " : " LIMIT $limit"; } } return $limitsql; } public static function parseSelect($field = array(), $alias = '') { if (empty($field) || $field == '*') { return ' SELECT *'; } if (!is_array($field)) { $field = array($field); } $select = array(); $index = 0; foreach ($field as $field_row) { if (strexists($field_row, '*')) { if (!strexists(strtolower($field_row), 'as')) { } } elseif (strexists(strtolower($field_row), 'select')) { if ($field_row[0] != '(') { $field_row = "($field_row) AS '{$index}'"; } } elseif (strexists($field_row, '(')) { $field_row = str_replace(array('(', ')'), array('(' . (!empty($alias) ? "`{$alias}`." : '') . '`', '`)'), $field_row); if (!strexists(strtolower($field_row), 'as')) { $field_row .= " AS '{$index}'"; } } else { $field_row = self::parseFieldAlias($field_row, $alias); } $select[] = $field_row; $index++; } return " SELECT " . implode(',', $select); } public static function parseParameter($params, $glue = ',', $alias = '') { $result = array('fields' => ' 1 ', 'params' => array()); $split = ''; $suffix = ''; $allow_operator = array('>', '<', '<>', '!=', '>=', '<=', '+=', '-=', 'LIKE', 'like'); if (in_array(strtolower($glue), array('and', 'or'))) { $suffix = '__'; } if (!is_array($params)) { $result['fields'] = $params; return $result; } if (is_array($params)) { $result['fields'] = ''; foreach ($params as $fields => $value) { if ($glue == ',') { $value = $value === null ? '' : $value; } $operator = ''; if (strpos($fields, ' ') !== FALSE) { list($fields, $operator) = explode(' ', $fields, 2); if (!in_array($operator, $allow_operator)) { $operator = ''; } } if (empty($operator)) { $fields = trim($fields); if (is_array($value) && !empty($value)) { $operator = 'IN'; } elseif ($value === 'NULL') { $operator = 'IS'; } else { $operator = '='; } } elseif ($operator == '+=') { $operator = " = `$fields` + "; } elseif ($operator == '-=') { $operator = " = `$fields` - "; } elseif ($operator == '!=' || $operator == '<>') { if (is_array($value) && !empty($value)) { $operator = 'NOT IN'; } elseif ($value === 'NULL') { $operator = 'IS NOT'; } } $select_fields = self::parseFieldAlias($fields, $alias); if (is_array($value) && !empty($value)) { $insql = array(); $value = array_values($value); foreach ($value as $v) { $placeholder = self::parsePlaceholder($fields, $suffix); $insql[] = $placeholder; $result['params'][$placeholder] = is_null($v) ? '' : $v; } $result['fields'] .= $split . "$select_fields {$operator} (".implode(",", $insql).")"; $split = ' ' . $glue . ' '; } else { $placeholder = self::parsePlaceholder($fields, $suffix); $result['fields'] .= $split . "$select_fields {$operator} " . ($value === 'NULL' ? 'NULL' : $placeholder); $split = ' ' . $glue . ' '; if ($value !== 'NULL') { $result['params'][$placeholder] = is_array($value) ? '' : $value; } } } } return $result; } public static function checkquery($sql) { $cmd = strtoupper(substr(trim($sql), 0, 6)); if(in_array($cmd,self::$checkcmd)){ $mark = $clean = ''; $sql = str_replace(array('\\\\', '\\\'', '\\"', '\'\''), '', $sql); if (strpos($sql, '/') === false && strpos($sql, '#') === false && strpos($sql, '-- ') === false && strpos($sql, '@') === false && strpos($sql, '`') === false) { $cleansql = preg_replace("/'(.+?)'/s", '', $sql); } else { $cleansql = self::stripSafeChar($sql); } $cleansql = preg_replace("/[^a-z0-9_\-\(\)#\*\/\"]+/is", "", strtolower($cleansql)); if (is_array(self::$disable['function'])) { foreach (self::$disable['function'] as $fun) { if (strpos($cleansql, $fun . '(') !== false) { trigger_error("SQL中包含禁用函数-{$fun}",E_USER_ERROR); return false; } } } if (is_array(self::$disable['action'])) { foreach (self::$disable['action'] as $action) { if (strpos($cleansql, $action) !== false) { trigger_error("SQL中包含禁用操作符-{$action}",E_USER_ERROR); return false; } } } if (is_array(self::$disable['note'])) { foreach (self::$disable['note'] as $note) { if (strpos($cleansql, $note) !== false) { trigger_error("SQL中包含注释信息",E_USER_ERROR); return false; } } } }else if(substr($cmd, 0, 2) === '/*'){ trigger_error("SQL中包含注释信息"); return false; } return true; } private static function stripSafeChar($sql) { $len = strlen($sql); $mark = $clean = ''; for ($i = 0; $i < $len; $i++) { $str = $sql[$i]; switch ($str) { case '\'': if (!$mark) { $mark = '\''; $clean .= $str; } elseif ($mark == '\'') { $mark = ''; } break; case '/': if (empty($mark) && $sql[$i + 1] == '*') { $mark = '/*'; $clean .= $mark; $i++; } elseif ($mark == '/*' && $sql[$i - 1] == '*') { $mark = ''; $clean .= '*'; } break; case '#': if (empty($mark)) { $mark = $str; $clean .= $str; } break; case "\n": if ($mark == '#' || $mark == '--') { $mark = ''; } break; case '-': if (empty($mark) && substr($sql, $i, 3) == '-- ') { $mark = '-- '; $clean .= $mark; } break; default: break; } $clean .= $mark ? '' : $str; } return $clean; } private static function parsePlaceholder($field, $suffix = '') { static $params_index = 0; $params_index++; $illegal_str = array('(', ')', '.', '*'); $placeholder = ":{$suffix}" . str_replace($illegal_str, '_', $field) . "_{$params_index}"; return $placeholder; } private static function parseFieldAlias($field, $alias = '') { if (strexists($field, '.') || strexists($field, '*')) { return $field; } if (strexists($field, '(')) { $select_fields = str_replace(array('(', ')'), array('(' . (!empty($alias) ? "`{$alias}`." : '') .'`', '`)'), $field); } else { $select_fields = (!empty($alias) ? "`{$alias}`." : '') . "`$field`"; } return $select_fields; } } ~~~ 助手函数 ~~~ <?php function pdo(){ global $_W; static $db; if(empty($db)){ load()->classs('Mysql'); $db = new MySqlPDO('master'); } return $db; } /** * @param $tablename * @param string $fieldname * @return bool */ function pdo_fieldexists($tablename, $fieldname = '') { return pdo()->fieldexists($tablename, $fieldname); } /** * @param $tablename * @param $fieldname * @param string $datatype * @param string $length * @return bool|int */ function pdo_fieldmatch($tablename, $fieldname, $datatype = '', $length = '') { return pdo()->fieldmatch($tablename, $fieldname, $datatype, $length); } /** * @param $tablename * @param string $indexname * @return array|bool */ function pdo_indexexists($tablename, $indexname = '') { return pdo()->indexexists($tablename, $indexname); } /** * @param $tablename * @return array */ function pdo_fetchallfields($tablename){ $fields = pdo_fetchall("DESCRIBE {$tablename}", array(), 'Field'); $fields = array_keys($fields); return $fields; } /** * @param $tablename * @return bool */ function pdo_tableexists($tablename){ return pdo()->tableexists($tablename); } /** * @param $sql */ function pdo_run($sql) { return pdo()->run($sql); } /** * @param $tablename * @param array $condition * @param int $cachetime * @return int */ function pdo_count($tablename, $condition = array(), $cachetime = 15) { return pdo()->count($tablename, $condition, $cachetime); } /** * @param $tablename * @param array $condition * @return bool */ function pdo_exists($tablename, $condition = array()) { return pdo()->exists($tablename, $condition); } /** * @param $tablename * @param array $condition * @param $field * @return bool|mixed */ function pdo_getcolumn($tablename, $condition = array(), $field) { return pdo()->getcolumn($tablename, $condition, $field); } /** * @param $tablename * @param array $condition * @param array $limit * @param null $total * @param array $fields * @param string $keyfield * @param array $orderby * @return array */ function pdo_getslice($tablename, $condition = array(), $limit = array(), &$total = null, $fields = array(), $keyfield = '', $orderby = array()) { return pdo()->getslice($tablename, $condition, $limit, $total, $fields, $keyfield, $orderby); } /** * @param $sql * @param array $params * @param int $column * @return bool */ function pdo_fetchcolumn($sql, $params = array(), $column = 0) { return pdo()->fetchcolumn($sql, $params, $column); } /** * @param $tablename * @param array $condition * @param array $fields * @param string $keyfield * @param array $orderby * @param array $limit * @return array */ function pdo_getall($tablename, $condition = array(), $fields = array(), $keyfield = '', $orderby = array(), $limit = array()) { return pdo()->getall($tablename, $condition, $fields, $keyfield, $orderby, $limit); } /** * @param $tablename * @param array $condition * @param array $fields * @return bool */ function pdo_get($tablename, $condition = array(), $fields = array()) { return pdo()->get($tablename, $condition, $fields); } /** * @param $sql * @param array $params * @param string $keyfield * @return array */ function pdo_fetchall($sql, $params = array(), $keyfield = '') { return pdo()->fetchall($sql, $params, $keyfield); } /** * @param $sql * @param array $params * @return bool */ function pdo_fetch($sql, $params = array()) { return pdo()->fetch($sql, $params); } /** * @param $table * @param array $data * @param array $params * @param string $glue * @return bool */ function pdo_update($table, $data = array(), $params = array(), $glue = 'AND') { return pdo()->update($table, $data, $params, $glue); } /** * @param $table * @param array $data * @param bool $replace * @return bool */ function pdo_insert($table, $data = array(), $replace = FALSE) { return pdo()->insert($table, $data, $replace); } /** * @return mixed */ function pdo_insertid() { return pdo()->insertid(); } /** * @param bool $output * @param array $append * @return array */ function pdo_debug($output = true, $append = array()) { return pdo()->debug($output, $append); } /** * 启动一个事务 */ function pdo_begin() { pdo()->begin(); } /** * 提交一个事务 */ function pdo_commit() { pdo()->commit(); } /** * 回滚一个事务 */ function pdo_rollback() { pdo()->rollBack(); } /** * @param $table * @param array $params * @param string $glue * @return bool */ function pdo_delete($table, $params = array(), $glue = 'AND') { return pdo()->delete($table, $params, $glue); } /** * @param $sql * @param array $params * @return bool */ function pdo_query($sql, $params = array()) { return pdo()->query($sql, $params); } ~~~