1. 程式人生 > >php pdo類 防注入,事務,多庫自動選擇,鏈式操作

php pdo類 防注入,事務,多庫自動選擇,鏈式操作

因為某些原因目前業務不用框架開發,自己寫了一個pdo類實現防注入,事務等,後續還會繼續完善 

<?php
/**
 * Created by PhpStorm.
 * User: ywx
 * Date: 2019/7/10
 * Time: 14:57
 */

class Db
{
    private $conn;
    private $sql = [
        'where'   => null,
        'wheresql'   => null,
        'orderBy' => null,
        'limit'   => null,
        'up'   => null,
        'ins'   => null,
    ];
    private $type;


    public function __construct( $data = [])
    {
        if($data){
            $this->_setDbDrive($data);
        }
    }

    private function _setDbDrive($dbConf){
        $dns = 'mysql:host='.$dbConf['DB_IP'].';dbname='.$dbConf['DB_NAME'].';charset=utf8mb4';

        try {
            $db = new PDO($dns,$dbConf['DB_USER'],$dbConf['DB_PASS']);
        } catch(PDOException $e) {
            die('Could not connect to the database:<br/>' . $e);
        }
        $this->conn[$dbConf['name']] = $db;
    }

    public function table($tablename) {
        //獲取表庫資訊
        $db_info = $this->_getDBIP($tablename);
        $this->sql = [];//重置快取
        $this->type = $db_info['name'];
        if(!isset($this->conn[$db_info['name']])){
            $this->_setDbDrive($db_info);
        }

        $this->tablename = $tablename;
        return $this;
    }

    public function select($fields = '*') {
        $querySql = sprintf("SELECT %s FROM %s", $fields, $this->tablename);
        if(!empty($this->sql['where'])) {
            $querySql .= ' WHERE ' . $this->sql['wheresql'];
        }
        if(!empty($this->sql['orderBy'])) {
            $querySql .= ' ORDER BY ' . $this->sql['orderBy'];
        }
        if(!empty($this->sql['limit'])) {
            $querySql .= ' LIMIT ' . $this->sql['limit'];
        }

        return $this->_query($querySql);
    }

    public function find($fields = '*') {
        $result = $this->select($fields);
        return isset($result[0]) ? $result[0] : null;
    }

    public function insert($data) {
        foreach ($data as $key => &$value) {
            $value = addslashes($value);
        }
        $keys = "`".implode('`,`', array_keys($data))."`";
        $values = ":i".implode(", :i", array_keys($data));
        $this->sql['ins'] = $data;

        $querySql = sprintf("INSERT INTO %s ( %s ) VALUES ( %s )", $this->tablename, $keys, $values);
        return $this->_query($querySql);
    }

    public function delete() {
        $querySql = sprintf("DELETE FROM %s WHERE ( %s )", $this->tablename, $this->sql['wheresql']);
        return $this->_query($querySql);
    }

    /**
     * 傳入陣列 ['apid'=>['+',15],'bpid'=>105] 目前二位陣列僅支援 加減
     * @param $data
     * @return mixed
     */
    public function update($data) {
        $updateFields = [];
        foreach ($data as $key => $value) {
            if(!is_array($value)){
                $updateFields[] = "`$key`=:u{$key} ";
            }else{
                $updateFields[] = "`$key`= `{$key}` {$value[0]} {$value[1]}";
                unset($data[$key]);
            }
        }
        $this->sql['up'] = $data;
        $updateFields = implode(',', $updateFields);
        $querySql = sprintf("UPDATE %s SET %s", $this->tablename, $updateFields);

        if(!empty($this->sql['where'])) {
            $querySql .= ' WHERE ' . $this->sql['wheresql'];
        }

        return $this->_query($querySql);
    }

    private function _query($querySql) {
        $querystr = strtolower(trim(substr($querySql,0,6)));
        $stmt = $this->conn[$this->type]->prepare($querySql);
        //繫結引數 where
        if($this->sql['wheresql']){
            foreach($this->sql['where'] as $k=>$v){
                if(!is_array($v)){
                    $val = $v;
                }else{
                    $val = $v[1];
                }
                $stmt->bindValue('w'.$k,addslashes($val));
            }
        }

        //update
        if($this->sql['up']){
            foreach($this->sql['up'] as $k=>$v){
                $stmt->bindValue('u'.$k,trim($v,'\''));
            }
        }

        //install
        if($this->sql['ins']){
            foreach($this->sql['ins'] as $k=>$v){
                $stmt->bindValue('i'.$k,addslashes($v));
            }
        }

        $ret = $stmt->execute();
        $this->sql = [];
        if(!$ret) var_dump($stmt->errorInfo());

        if($querystr == 'select') {
            $retData = $stmt->fetchAll(PDO::FETCH_ASSOC);
            return $retData;
        }elseif($ret && $querystr == 'insert') {
            return $this->conn[$this->type]->lastInsertId();
        }else{
            return $ret;
        }
    }

    public function limit($limit, $limitCount = null) {
        if(!$limitCount) {
            $this->sql['limit'] = $limit;
        }else{
            $this->sql['limit'] = $limit .','. $limitCount;
        }
        return $this;
    }

    public function orderBy($orderBy) {
        $this->sql['orderBy'] = $orderBy;
        return $this;
    }

    public function where($where) {
        if(!is_array($where)) {
            return null;
        }

        $crondsArr = [];
        foreach ($where as $key => $value) {
            $fieldValue = $value;
            if(is_array($fieldValue)) {
                $crondsArr[] = "`$key` ".$fieldValue[0]. ' :w' . $key;
            }else{
                $crondsArr[] = "`$key`=:w{$key}";
            }
        }

        $this->sql['wheresql'] = implode(' AND ', $crondsArr);
        $this->sql['where'] = $where;
        return $this;
    }

    public function close() {
        return $this->conn = null;
    }

    //開啟事務
    public function startTrans(){
        if(empty($this->conn[$this->type])){
            exit();
        }
        $this->conn[$this->type]->beginTransaction();
    }

    //提交事務
    public function dbCommit(){
        if(empty($this->conn[$this->type])){
            exit();
        }
        $this->conn[$this->type]->commit();
    }

    //回滾事務
    public function dbRollBack(){
        if(empty($this->conn[$this->type])){
            exit();
        }
        $this->conn[$this->type]->rollBack();
    }

    /**
     * 原生查詢
     * @param $querySql
     * @return mixed
     */
    public function query($querySql) {
        $querystr = strtolower(trim(substr($querySql,0,6)));
        $stmt = $this->conn[$this->type]->prepare($querySql);

        $ret = $stmt->execute();
        $this->sql = [];
        if(!$ret) var_dump($stmt->errorInfo());

        if($querystr == 'select') {
            $retData = $stmt->fetchAll(PDO::FETCH_ASSOC);
            return $retData;
        }elseif($ret && $querystr == 'insert') {
            return $this->conn[$this->type]->lastInsertId();
        }else{
            return $ret;
        }
    }

    private function _getDBIP($tableName){
        switch($tableName){
            default:
                return array(
                    'name' =>'server',
                    'DB_IP'   => DB_IP,
                    'DB_NAME' => DB_NAME,
                    'DB_USER' => DB_USER,
                    'DB_PASS' => DB_PASS,
                );
                break;

            case 'xxxx':
            case 'xxxx':
                return array(
                    'name' =>'master',
                    'DB_IP'   => DB_MAS_IP,
                    'DB_NAME' => DB_MAS_NAME,
                    'DB_USER' => DB_MAS_USER,
                    'DB_PASS' => DB_MAS_PASS,
                );
                break;

            case 'xxx':
            case 'xxx':
                return array(
                    'name' =>'manage',
                    'DB_IP'   => DB_MNG_IP,
                    'DB_NAME' => DB_MNG_NAME,
                    'DB_USER' => DB_MNG_USER,
                    'DB_PASS' => DB_MNG_PASS,
                );
                break;

            // LOGS
            case 'xxx':
                return array(
                    'name' =>'log',
                    'DB_IP'   => DB_LOG_IP,
                    'DB_NAME' => DB_LOG_NAME,
                    'DB_USER' => DB_LOG_USER,
                    'DB_PASS' => DB_LOG_PASS,
                );
                break;
        }
    }
}