phpMinAdmin – abstrakce databázové extenze

Školení, která pořádám

phpMinAdmin umí používat tři extenze pro práci s databází: MySQLi, MySQL a PDO. Nad těmito extenzemi je vytvořena jednoduchá abstrakce, která dovoluje se všemi extenzemi pracovat jednotným způsobem.

MySQLi

Za základ je zvoleno MySQLi, protože disponuje nejvíce funkcemi:

<?php
class Min_MySQLi extends MySQLi {
    function Min_MySQLi() {
        $this->init();
    }
    
    function connect($server, $username, $password) {
        return @$this->real_connect(
            (strlen($server) ? $server : ini_get("mysqli.default_host")),
            (strlen("$server$username") ? $username : ini_get("mysqli.default_user")),
            (strlen("$server$username$password") ? $password : ini_get("mysqli.default_pw"))
        );
    }
    
    function result($result, $field = 0) {
        $row = $result->fetch_array();
        return $row[$field];
    }
}
?>

V potomku třídy mysqli je přepsán konstruktor, kde je provedena pouze inicializace a je přidána metoda connect, která se připojí k serveru s předanými nebo výchozími parametry. Metoda result, která vrátí dané pole prvního řádku výsledku, by měla být spíše součástí třídy mysqli_result, extenze MySQLi tuto třídu ale bohužel nedovoluje snadno rozšiřovat, proto je přímo součástí hlavní třídy.

MySQL

<?php
class Min_MySQL {
    var $_link, $_result, $server_info, $affected_rows, $error;
    
    function connect($server, $username, $password) {
        $this->_link = @mysql_pconnect(
            (strlen($server) ? $server : ini_get("mysql.default_host")),
            (strlen("$server$username") ? $username : ini_get("mysql.default_user")),
            (strlen("$server$username$password") ? $password : ini_get("mysql.default_password")),
            131072 // CLIENT_MULTI_RESULTS for CALL
        );
        if ($this->_link) {
            $this->server_info = mysql_get_server_info($this->_link);
        }
        return (bool) $this->_link;
    }
    
    function select_db($database) {
        return mysql_select_db($database, $this->_link);
    }
    
    function query($query) {
        $result = mysql_query($query, $this->_link);
        if (!$result) {
            $this->error = mysql_error($this->_link);
            return false;
        } elseif ($result === true) {
            $this->affected_rows = mysql_affected_rows($this->_link);
            return true;
        }
        return new Min_MySQLResult($result);
    }
    
    function multi_query($query) {
        return $this->_result = $this->query($query);
    }
    
    function store_result() {
        return $this->_result;
    }
    
    function next_result() {
        return false;
    }
    
    function result($result, $field = 0) {
        return mysql_result($result->_result, 0, $field);
    }
    
    function escape_string($string) {
        return mysql_real_escape_string($string, $this->_link);
    }
}

class Min_MySQLResult {
    var $_result, $_offset = 0, $num_rows;
    
    function Min_MySQLResult($result) {
        $this->_result = $result;
        $this->num_rows = mysql_num_rows($result);
    }
    
    function fetch_assoc() {
        return mysql_fetch_assoc($this->_result);
    }
    
    function fetch_row() {
        return mysql_fetch_row($this->_result);
    }
    
    function fetch_field() {
        $row = mysql_fetch_field($this->_result, $this->_offset++);
        $row->orgtable = $row->table;
        $row->orgname = $row->name;
        $row->charsetnr = ($row->blob ? 63 : 0);
        return $row;
    }
    
    function free() {
        return mysql_free_result($this->_result);
    }
}
?>

V abstrakci nad extenzí MySQL stojí za pozornost několik věcí:

PDO

<?php
class Min_PDO_MySQL extends PDO {
    var $_result, $server_info, $affected_rows, $error;
    
    function __construct() {
    }
    
    function connect($server, $username, $password) {
        set_exception_handler('auth_error'); // try/catch is not compatible with PHP 4
        parent::__construct("mysql:host=$server", $username, $password);
        restore_exception_handler();
        $this->setAttribute(13, array('Min_PDOStatement')); // PDO::ATTR_STATEMENT_CLASS
        $this->server_info = $this->result($this->query("SELECT VERSION()"));
        return true;
    }
    
    function select_db($database) {
        return $this->query("USE " . idf_escape($database));
    }
    
    function query($query) {
        $result = parent::query($query);
        if (!$result) {
            $errorInfo = $this->errorInfo();
            $this->error = $errorInfo[2];
            return false;
        }
        $this->_result = $result;
        if (!$result->columnCount()) {
            $this->affected_rows = $result->rowCount();
            return true;
        }
        $result->num_rows = $result->rowCount();
        return $result;
    }
    
    function multi_query($query) {
        return $this->query($query);
    }
    
    function store_result() {
        return ($this->_result->columnCount() ? $this->_result : true);
    }
    
    function next_result() {
        return $this->_result->nextRowset();
    }
    
    function result($result, $field = 0) {
        $row = $result->fetch();
        return $row[$field];
    }
    
    function escape_string($string) {
        return substr($this->quote($string), 1, -1);
    }
}

class Min_PDOStatement extends PDOStatement {
    var $_offset = 0, $num_rows;
    
    function fetch_assoc() {
        return $this->fetch(2); // PDO::FETCH_ASSOC
    }
    
    function fetch_row() {
        return $this->fetch(3); // PDO::FETCH_NUM
    }
    
    function fetch_field() {
        $row = (object) $this->getColumnMeta($this->_offset++);
        // table and charset is not available
        return $row;
    }
    
    function free() {
        // $this->__destruct() is not callable
    }
}
?>

Podpora přes extenzi PDO je nejslabší. Opět několik poznámek:

Jakub Vrána, Adminer, 8.8.2007, diskuse: 2 (nové: 0)

Diskuse

Jakub:

Mám na vás dva dotazy:

Proč používáte strlen("$server$username") a ne strlen($username) ?

V manuálu jsem našel že funkce set_exception_handler() je v PHP dostupná až od verze 5

Jinak články o phpMinAdmin jsou výborné. Jen tak dál.

ikona Jakub Vrána OpenID:

Nechceme, aby se na cizím serveru použilo defaultní jméno a heslo.

set_exception_handler() je pochopitelně dostupná až v PHP 5, protože v PHP 4 výjimky nejsou. Jde o to, že to je volání normální funkce, které je syntakticky v pořádku (na rozdíl od try/catch) i v PHP 4. Kód se na to místo nikdy nedostane, protože PDO je k dispozici až v PHP 5, takže k volání neexistující funkce nedojde.

Diskuse je zrušena z důvodu spamu.

avatar © 2005-2024 Jakub Vrána. Publikované texty můžete přetiskovat pouze se svolením autora. Ukázky kódu smíte používat s uvedením autora a URL tohoto webu bez dalších omezení Creative Commons. Můžeme si tykat. Skripty předpokládají nastavení: magic_quotes_gpc=Off, magic_quotes_runtime=Off, error_reporting=E_ALL & ~E_NOTICE a očekávají předchozí zavolání mysql_set_charset. Skripty by měly být funkční v PHP >= 4.3 a PHP >= 5.0.