Problemi con classe di astrazione per il database

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
Salve, sto facendo una classe come avete già visto in precedenti post.
Ora il mio codice è cosi:
PHP:
<?php
class Database {

    var $db;

//connessione al DBMS 
    function Connect($db_host, $db_utente, $db_password, $db_nomedb){
        $this->db = new mysqli($db_host, $db_utente, $db_password, $db_nomedb);
    }

//query sulla tabella  
    function Query($sql){
		try {
        $return_sql = $this->db->query($sql);
        return $return_sql;
		} 
		catch (mysqli_sql_exception $e) {
          echo $e->__toString();
       }
    }

//conteggio dei records 
    function FetchNum($sql){
        $num = $this->db->num_rows($sql);
        return $num;
    }

//estrazione dei records   
    function Fetch(){
		if(mode=='assoc')
		{
			$array = $this->db->fetch_assoc();
		}
		else if(mode=='array')
		{
        $array = $this->db->fetch_array();
		}
        return $array;
    }

//chiusura della connessione 
    function Close(){
        $this->db->close();
    }
} 
?>
è il mio index è cosi:
PHP:
<?php
ini_set('error_reporting', E_ALL);
ini_set("display_errors", 1);
include_once("database.php");
$db=new Database();
$db->connect("localhost","root","root","myDatabase");
echo "connessione effetuata";	

$sql = $db->Query("SELECT * FROM Uscite; ");

while($f = $db->Fetch('array'))
{
	echo "".$f["importo"]."";
}
$db->close();
?>
Mi segnala:
PHP:
connessione effetuata
Notice: Use of undefined constant mode - assumed 'mode' in /media/dati/www/prove/database.php on line 30

Notice: Use of undefined constant mode - assumed 'mode' in /media/dati/www/prove/database.php on line 34

Notice: Undefined variable: array in /media/dati/www/prove/database.php on line 38
come mai?

Mi dite come procedere .. perché ho i libri po vecchi ansi usano la mysql normale quella di 1 anno fa.

come posso fare?
grazie mille.
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
visto in precedente post e mi è riuscito ad abilittare gli errori con il driver mysqli.. mi segnala questo:
exception 'mysqli_sql_exception' with message 'No index used in query/prepared statement SELECT * FROM Uscite' in /media/dati/www/prove/database.php:17 Stack trace: #0 /media/dati/www/prove/database.php(17): mysqli->query('SELECT * FROM U...') #1 /media/dati/www/prove/index_2.php(7): Database->Query('SELECT * FROM U...') #2 {main}
Fatal error: Call to a member function FetchArray() on a non-object in /media/dati/www/prove/index_2.php on line 9

il codice modificato adesso è questo:
PHP:
<?php
ini_set('error_reporting', E_ALL);
ini_set("display_errors", 1);
include_once("database.php");
$db=new Database("localhost","root","root","myDatabase");

$sql = $db->Query("SELECT * FROM Uscite");

while($f = $sql->Fetch('array'))
{
	echo "".$f["importo"]."";
}

$db->close();
?>
Mi dite come fare?

grazie mille.
 
Ultima modifica:

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
se vi interessa posto qui la fetch:
PHP:
//estrazione dei records   
    function Fetch($mode){
		if($mode=='assoc')
		{
			try {
				$array = $this->db->fetch_assoc();
			} 
			catch (mysqli_sql_exception $e) 
			{
				echo $e->__toString();
			}
		}
		else if($mode=='array')
		{
			try {
				$array = $this->db->fetch_array();
			} 
			catch (mysqli_sql_exception $e) 
			{
				echo $e->__toString();
			}
		}
        return $array;
    }
grazie
 

flameseeker

Utente Attivo
27 Nov 2013
699
0
0
Il problema è dato dalla query in se.
Mysqli ti sta avvertendo che con quella richiesta il dbms deve effettuare una fullscan della tabella in questione (che effettivamente non è il motivo principale per cui uno sceglie di usare un database relazionale).

Se nella tua applicazione prevedi di eseguire spesso query di quel tipo, potrebbe tornarti più comodo da usare PDO.

ps: non aprire tanti topic per lo stesso problema, nel tuo caso il tuo scopo è ottenere un layer di astrazione per il database, quindi puoi discutere di tutti i problemi della tua classe in questo topic. Modifico il titolo della discussione così che sia più chiaro ;)


Ritiro quello che dicevo su PDO, si possono rimuovere errori di quel preciso tipo.
Dove ti ho indicato di inserire la modifica del report mode del driver di mysqli, cambia l'impostazione con:
$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;
Questa sintassi dovrebbe disabilitare MYSQLI_REPORT_INDEX che, secondo la documentazione di php (eh, dico sempre che bisogna lavorarci a stretto contatto), è la causa di quel messaggio d'errore.
 
Ultima modifica:

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
si , fatto ero funziona:

PHP:
<?php	
class Database {

    private $db;
    private $result;

	//connessione al DBMS 
    function __construct($db_host, $db_utente, $db_password, $db_nomedb){
		/* activate reporting */
		$driver = new mysqli_driver();
		$driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT; 
        $this->db = new mysqli($db_host, $db_utente, $db_password, $db_nomedb);
    }
	
	function __destruct()
	{
			$this->close();
	}
	
//query sulla tabella  
    function Query($sql){
		try {
        $this->result = $this->db->query($sql);
        } 
		catch (mysqli_sql_exception $e) {
          echo $e->__toString();
       }
    }

	//conteggio dei records 
    function FetchNum($sql){
        $num = $this->db->num_rows($sql);
        return $num;
    }

	//estrazione dei records   
    function Fetch($mode = 'array'){
		if($mode=='assoc')
		{
			try {
				$row = $this->result->fetch_assoc();
			} 
			catch (mysqli_sql_exception $e) 
			{
				echo $e->__toString();
			}
		}
		else if($mode=='array')
		{
			try {
				$row = $this->result->fetch_array();
			} 
			catch (mysqli_sql_exception $e) 
			{
				echo $e->__toString();
			}
		}
        return $row;
    }

	//chiusura della connessione 
    function Close(){
        $this->db->close();
    }
} 
?>
dimmi se va bene come classe ..

poi mi protesti sapere come posso usare i prepare?

grazie mille e ti ringrazio moltissimo.

saluti.
 

flameseeker

Utente Attivo
27 Nov 2013
699
0
0
Occhio:
PHP:
    function __destruct()
    {
            $this->close();
    }
Il metodo close della tua classe inizia con la C maiuscola.

PHP:
    //query sulla tabella  
    function Query($sql){
        try {
        $this->result = $this->db->query($sql);
        } 
        catch (mysqli_sql_exception $e) {
          echo $e->__toString();
       }
    }
Se non gestisci gli errori o non te ne fai nulla qui, puoi ritornare l'errore all'esterno della classe lanciando un eccezione standard di PHP, così puoi usare il paradigma try/catch anche quando la utilizzi per scrivere la logica della tua applicazione e prendere di conseguenza decisioni su come gestire l'output da inviare al client.

Per esempio, se al posto di echo $e->__toString(), fai così:
PHP:
throw new Exception($e->__toString());
Quando scriverai una query potrai così realizzare..
PHP:
try{

    $result = $db->Query("Sintassi non valida");

} catch(Exception $e)
{
    echo "Caro utente, sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
    
    // da qualche parte ti salvi come log nascosto il contenuto di $e->getMessage() oppure lo stampi semplicemente fuori con un echo.
}
Per il resto, predi in considerazione un implementazione per la chiamata verso il metodo free, che serve a pulire il recordset caricato per la query.


Per quanto riguarda i prepared statements ti consiglio questa pagina di php.net per capirne il funzionamento base e quest'altra per ulteriori approfondimenti sull'utilizzo del metodo prepare.

Posta ciò che riesci a fare poi ;)
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
ok, quando ho tempo provo le tue informazioni che mi stai dando ..

ti ringrazio molto e buon inizio settimana.

saluti,
luigi.
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
salve ritorno con questa discussione.. volevo sapere se passasi a pdo cosa cambia?

PHP:
//connessione al DBMS  
    function __construct($db_host, $db_utente, $db_password, $db_nomedb){ 
        /* activate reporting */ 
        $driver = new mysqli_driver(); 
        $driver->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT;  
        $this->db = new mysqli($db_host, $db_utente, $db_password, $db_nomedb); 
    }
qui?

mi protesti darmi una mano che poi la pubblico a tutti amici online.

grazie mille.
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
sto provando dimmi se va bene:
PHP:
  //connessione al DBMS  
   function __construct($db_host, $db_utente, $db_password, $db_nomedb){ 
   try {
			$db = new PDO('mysql:host='.$db_host.';dbname='.$db_nomedb.'', $db_utente, $db_password);
			$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		} catch(PDOException $e) {
			echo 'ERROR: ' . $e->getMessage();
		}
	}
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
Ho provato ma non so come mai mi dice nella parte dove c'e execute che non riesco ad manipolare..
il server locale mi risponde:

Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 65488 bytes) in D:\xampp\htdocs\test\database_class.php on line 36

rimedio?

grazie mille e buona giornata.
il pezzo incriminato :
PHP:
   function execute() // qui non riesco a manipolarlo. 
    { 
    try {  
         $this->result = $this->execute();  
        }   
       catch(PDOException $e) { 
            echo "Caro utente,  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug."; 
          echo 'ERROR: ' . $e->getMessage(); 
       }  
    }
codice completo:
PHP:
<?php     
class Database { 

    private $db; 
    private $result; 

    //connessione al DBMS  
   function __construct($db_host, $db_utente, $db_password, $db_nomedb){ 
   try {
			$this->db = new PDO('mysql:host='.$db_host.';dbname='.$db_nomedb.'', $db_utente, $db_password);
			$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
		} catch(PDOException $e) {
			echo 'ERROR: ' . $e->getMessage();
		}
	} 
     
    function __destruct() 
    { 
          
    } 
     
//query sulla tabella   
    function Query($sql){ 
        try { 
        $this->result = $this->db->prepare($sql); 
        }  
       catch(PDOException $e) {
  		  echo "Caro utente,  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
          echo 'ERROR: ' . $e->getMessage();
       } 
    } 

	function execute() // qui non riesco a manipolarlo.
	{
    try { 
		 $this->result = $this->execute(); 
        }  
       catch(PDOException $e) {
  		  echo "Caro utente,  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
          echo 'ERROR: ' . $e->getMessage();
       } 
	}
    //conteggio dei records  
    function FetchNum($sql){ 
        $num = $this->db->num_rows($sql); 
        return $num; 
    } 

    //estrazione dei records    
    function Fetch($mode = 'array'){ 
        if($mode=='assoc') 
        { 
            try { 
                $row = $this->result->fetchAll(); 
            }  
           catch(PDOException $e) 
            { 
                echo "Caro utente, 
		  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
        echo 'ERROR: ' . $e->getMessage();
            } 
        } 
        else if($mode=='array') 
        { 
            try { 
                $row = $this->result->fetchAll(); 
            }  
            catch(PDOException $e) 
            { 
                echo "Caro utente, 
		  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
				echo 'ERROR: ' . $e->getMessage();
            } 
        } 
        return $row; 
    } 
}  
?>
 

marino51

Utente Attivo
28 Feb 2013
2.912
162
63
Lombardia
ciao,
prova a guardare questa discussione,
magari comincia dall'ultima risposta
ciao
Marino

ps ho modificato la classe che hai postato tempo fa, usa pdo e i messaggi di errore li invia al log di php
all'utente da un info generica, così che in caso di errore puoi recuperare log
 
Ultima modifica:

marino51

Utente Attivo
28 Feb 2013
2.912
162
63
Lombardia
per quanto riguarda l'errore forse stai leggendo una tabella molto grande,
metti la clausola where o limit 10 nella select
ciao
Marino
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
ciao marino e grazie per la risposta.. ma purtroppo non è cosi.
i dati ci sono solamente 4 e sono int.
Tabella:
Codice:
CREATE TABLE test(uscite INT)
questo è il codice main "test.php".

PHP:
<?php
ini_set('error_reporting', E_ALL);
ini_set("display_errors", 1);
include_once("database_class.php");
$db=new Database("localhost","root","","prove");

$sql = $db->Query("SELECT * FROM test");

while($f = $db->Fetch())
{
    echo "".$f["uscite"]."";
}
?>
questa è la classe sempre in modifica:

PHP:
<?php     
class Database { 

    private $db; 
    private $result; 

    //connessione al DBMS  
   function __construct($db_host, $db_utente, $db_password, $db_nomedb){ 
   try {
            $this->db = new PDO('mysql:host='.$db_host.';dbname='.$db_nomedb.'', $db_utente, $db_password);
            $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch(PDOException $e) {
            echo 'ERROR: ' . $e->getMessage();
        }
    } 
    // chiusura.
    function __destruct() 
    { 
           $this->db->close();
    } 
     
	//query sulla tabella   
    function Query($sql){ 
        try { 
        $this->result = $this->db->prepare($sql); 
		$this->result->execute(); 
        }  
       catch(PDOException $e) {
            echo "Caro utente,  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
          echo 'ERROR: ' . $e->getMessage();
       } 
    } 
  
  //Fetch per estrarre tutti i dati della tabella   
   public function Fetch(){
    try { 
		 return $this->result->fetchAll(PDO::FETCH_ASSOC); 
	}
    catch(PDOException $e){ 
	    echo "Caro utente,  sembra ci siano stati problemi imprevisti e forse dovresti contattare il supporto tecnico del sito per segnalare il bug.";
          echo 'ERROR: ' . $e->getMessage();
	}
  } 
}
?>
e mi salta fuori l'errori:

Notice: Undefined index: uscite in D:\xampp\htdocs\test\test.php on line 11

Fatal error: Call to undefined method PDO::close() in D:\xampp\htdocs\test\database_class.php on line 19

non capisco perché mi da un undefined index che la tabella e il database ci sono e ci sono 4 dati interi.

come mai?

grazie mille e buona giornata.
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
ok, mi arrendo uso quella mysqli che tanto io uso solo mysql .. perché pdo dicono che serve se hai delle esigenze di accedere qualsiasi database diverso da mysql ..
 

marino51

Utente Attivo
28 Feb 2013
2.912
162
63
Lombardia
no aspetta c'è soluzione,
di seguito le modifiche della classe,

PHP:
    function __destruct()  
    {  
       $this->close();  // modifica
    }  

....

  function close(){     // inserisci
    unset($this->db); 
  }

    function Query($sql){  
        try {  
        $this->result = $this->db->prepare($sql);  
        $this->result->execute(); 
        return $this->result;      // inserisci
        }   

   public function Fetch($result){   // modifica
    try {  
         return $result->fetch(PDO::FETCH_ASSOC);  // modifica
    }
nello script modifica,

PHP:
while($f = $db->Fetch($sql))  // modifica
mi sembra di averti scritto tutto,
ciao
Marino
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
grazie mille e grazie mille di nuovo..

hai idee come posso fare per fare le insert e update ed delete usando cosi:
$db->insert($sql)
etc..
ti ringrazio moltissimo.

buona serata.
 

marino51

Utente Attivo
28 Feb 2013
2.912
162
63
Lombardia
puoi creare un'unica funzione "Query_exec($sql)", come ho fatto io,

PHP:
  function Query_exec($sql){
     try { return $this->db->exec($sql); }
    catch(PDOException $e){ $this->handle_sql_errors($sql, $e); }
  }
alla quale passi indistintamente insert, update e delete, che chiami con

PHP:
  $dbresult = $db->Query_exec($sql);  // $sql = insert, update, delete
  if ($dbresult) {
    // se == 1 eseguita con successo altrimenti "non ha fatto nulla"
  }
quando non fa nulla, non entra in funzione il try-catch ma devi controllare tu la situazione
try-catch entra in funzione per errore di ortografia della query o disastri nel db

se invece, vuoi differenziare le chiamate, come nel tuo esempio,
scrivila 3 volte, dando a ciascuna il nome che preferisci.

ti suggerisco anche la funzione per gestire gli errori, chiamata con

PHP:
  catch(PDOException $e){ $this->handle_sql_errors($sql, $e); }  // vedi Query_exec
che ti scrive il comando sql e relativo errore nel log di php e
visualizza il messaggio che preferisci all'utente

PHP:
  function handle_sql_errors($sql, $e){
    error_log("SQL cmd    : $sql", 0);
    error_log("error code : ". $e->getCode(), 0);
    error_log("error info : ". $e->getMessage(), 0);
    print "ERRORE INATTESO, contatta l'amministratore del sistema";
    die;
  }
ciao
Marino
 
Ultima modifica:

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
ok, ti ringrazio molto.. l'ultima cosa.. Per usare i bind value o bind param per evitare sql injection ..

perché cosi come è, è facile che qualcuno me lo attacchi..

idee?

grazie mille.
 

luigi777

Utente Attivo
14 Feb 2008
1.073
1
38
38
Massa, Italy
ad esempio .. che ho trovato un tutorial di code of ninja ..
che dici ?
PHP:
<?php
$action = isset($_POST['action']) ? $_POST['action'] : "";

if($action=='create'){
	//include database connection
	include 'libs/db_connect.php';

	try{
	
		//write query
		$query = "INSERT INTO users SET firstname = ?, lastname = ?, username = ?, password  = ?";

		//prepare query for excecution
		$stmt = $con->prepare($query);

		//bind the parameters
		//this is the first question mark
		$stmt->bindParam(1, $_POST['firstname']);

		//this is the second question mark
		$stmt->bindParam(2, $_POST['lastname']);

		//this is the third question mark
		$stmt->bindParam(3, $_POST['username']);

		//this is the fourth question mark
		$stmt->bindParam(4, $_POST['password']);

		// Execute the query
		if($stmt->execute()){
		
			echo "Record was saved.";
		}else{
			die('Unable to save record.');
		}
		
	}catch(PDOException $exception){ //to handle error
		echo "Error: " . $exception->getMessage();
	}
}

?>
http://www.codeofaninja.com/2011/12/php-and-mysql-crud-tutorial.html


ti ringrazio molto..