php - tutorial - w3school insert data




Perché non dovrei usare le funzioni mysql_*in PHP? (10)

Facilità d'uso

Le ragioni analitiche e sintetiche sono già state citate. Per i nuovi arrivati ​​c'è un incentivo più significativo a smettere di usare le funzioni mysql_ datate.

Le moderne API di database sono solo più facili da usare.

Sono soprattutto i parametri associati che possono semplificare il codice. E con share il passaggio a PDO non è eccessivamente arduo.

Riscrivere una base di codice più grande in una volta, tuttavia, richiede tempo. Raison d'être per questa alternativa intermedia:

Funzioni equivalenti pdo_ * al posto di mysql_ *

Usando <pdo_mysql.php> puoi passare dalle vecchie funzioni mysql_ con il minimo sforzo . Aggiunge i wrapper di funzione pdo_ che sostituiscono le loro controparti mysql_ .

  1. Semplicemente include_once( <pdo_mysql.php> ); in ogni script di chiamata che deve interagire con il database.

  2. Rimuovi dappertutto il prefisso della funzione mysql_ e sostituiscilo con pdo_ .

    • mysql_ connect() diventa pdo_ connect()
    • mysql_ query() diventa pdo_ query()
    • mysql_ num_rows() diventa pdo_ num_rows()
    • mysql_ insert_id() diventa pdo_ insert_id()
    • mysql_ fetch_array() diventa pdo_ fetch_array()
    • mysql_ fetch_assoc() diventa pdo_ fetch_assoc()
    • mysql_ real_escape_string() diventa pdo_ real_escape_string()
    • e così via...

  3. Il tuo codice funzionerà allo stesso modo e per lo più sembra sempre lo stesso:

    include_once("pdo_mysql.php"); 
    
    pdo_connect("localhost", "usrABC", "pw1234567");
    pdo_select_db("test");
    
    $result = pdo_query("SELECT title, html FROM pages");  
    
    while ($row = pdo_fetch_assoc($result)) {
        print "$row[title] - $row[html]";
    }
    

Et voilà.
Il tuo codice sta usando PDO.
Ora è il momento di utilizzarlo davvero.

I parametri associati possono essere facili da usare

Hai solo bisogno di un'API meno ingombrante.

pdo_query() aggiunge un supporto molto facile per i parametri associati. La conversione del vecchio codice è semplice:

Sposta le tue variabili fuori dalla stringa SQL.

  • Aggiungili come parametri della funzione delimitata da virgole a pdo_query() .
  • Metti dei punti interrogativi ? come segnaposto in cui le variabili erano prima.
  • Elimina ' virgolette singole che hanno valori / variabili stringa precedentemente racchiusi.

Il vantaggio diventa più ovvio per codice più lungo.

Spesso le variabili stringa non vengono solo interpolate in SQL, ma concatenate con chiamate di escape intermedie.

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title='" . pdo_real_escape_string($title) . "' OR id='".
   pdo_real_escape_string($title) . "' AND user <> '" .
   pdo_real_escape_string($root) . "' ORDER BY date")

Con ? i segnaposto applicati non devono preoccuparsi di questo:

pdo_query("SELECT id, links, html, title, user, date FROM articles
   WHERE title=? OR id=? AND user<>? ORDER BY date", $title, $id, $root)

Ricorda che pdo_ * consente ancora o .
Basta non sfuggire a una variabile e collegarla nella stessa query.

  • La funzione segnaposto è fornita dal vero PDO dietro di esso.
  • Così permesso anche :named liste segnaposto :named più tardi.

Ancora più importante è possibile passare le variabili $ _REQUEST [] in modo sicuro dietro qualsiasi query. Quando i campi <form> inviati corrispondono esattamente alla struttura del database, è ancora più breve:

pdo_query("INSERT INTO pages VALUES (?,?,?,?,?)", $_POST);

Tanta semplicità Ma torniamo ad altri consigli di riscrittura e motivi tecnici sul perché potresti voler liberarti di mysql_ e scappare.

Correggi o rimuovi qualsiasi funzione oldizeit sanitize()

Una volta convertite tutte mysql_ chiamate mysql_ in pdo_query con parametri associati, rimuovere tutte le chiamate ridondanti pdo_real_escape_string .

In particolare, è necessario correggere qualsiasi funzione di clean o filterThis o di clean_data come pubblicizzato da tutorial datati in una forma o nell'altra:

function sanitize($str) {
   return trim(strip_tags(htmlentities(pdo_real_escape_string($str))));
}

La maggior parte dei bug abbaglianti qui è la mancanza di documentazione. Più significativamente l'ordine di filtraggio era esattamente nell'ordine sbagliato.

  • L'ordine corretto sarebbe stato: stripslashes deprecatedly come la chiamata più interna, quindi trim , in seguito strip_tags , htmlentities per il contesto di output e infine solo _escape_string poiché la sua applicazione dovrebbe precedere direttamente l'intersparsing SQL.

  • Ma come primo passo basta sbarazzarsi della chiamata _real_escape_string .

  • Potrebbe essere necessario mantenere il resto della funzione sanitize() per ora se il flusso del database e dell'applicazione si aspettano stringhe HTML-context-safe. Aggiungi un commento che applica solo l'escape HTML in seguito.

  • La gestione di stringhe / valori è delegata a PDO e alle sue istruzioni parametrizzate.

  • Se c'è qualche menzione di stripslashes() nella tua funzione di stripslashes() , potrebbe indicare un controllo di livello superiore.

    • Era solito lì per annullare il danno (doppia fuga) dalle magic_quotes deprecate. Che comunque è meglio sistemato centralmente , non stringa per stringa.

    • Utilizzare uno degli approcci di inversione degli utenti . Quindi rimuovere le stripslashes() nella funzione di stripslashes() .

    Nota storica su magic_quotes. Questa caratteristica è giustamente deprecata. Tuttavia, viene spesso raffigurato in modo non corretto come funzionalità di sicurezza non riuscita. Ma magic_quotes è tanto una caratteristica di sicurezza fallita quanto le palline da tennis hanno fallito come fonte di nutrizione. Questo semplicemente non era il loro scopo.

    L'implementazione originale in PHP2 / FI l'ha introdotta esplicitamente con solo "le virgolette saranno automaticamente sfuggite rendendo più semplice il passaggio dei dati del modulo direttamente alle query msql ". In particolare è stato accidentalmente sicuro da usare con mSQL , poiché supportava solo ASCII.
    Quindi PHP3 / Zend ha reintrodotto magic_quotes per MySQL e lo ha erroneamente documentato. Ma in origine era solo una caratteristica di convenienza , non intendeva per sicurezza.

Quanto differiscono le dichiarazioni preparate

Quando si mischiano le variabili stringa nelle query SQL, non solo diventa più complicato da seguire. È anche uno sforzo estenuante per MySQL di segregare nuovamente codice e dati.

Le iniezioni SQL sono semplicemente quando i dati sanguinano nel contesto del codice . Un server di database non può successivamente individuare dove PHP ha originariamente incollato le variabili tra le clausole di query.

Con i parametri associati, si separano il codice SQL e i valori del contesto SQL nel codice PHP. Ma non viene rimescolato dietro le quinte (tranne con PDO :: EMULATE_PREPARES). Il tuo database riceve i comandi SQL invariati e i valori delle variabili 1: 1.

Mentre questa risposta sottolinea che dovresti preoccuparti dei vantaggi di leggibilità del rilascio di mysql_ . Occasionalmente c'è anche un vantaggio in termini di prestazioni (INSERT ripetuto con valori diversi) a causa di questa separazione visibile / tecnica dei dati / codice.

Attenzione però che il binding dei parametri non è una soluzione one-stop per tutte le iniezioni SQL. Gestisce l'uso più comune di dati / valori. Ma non è possibile inserire nella whitelist identificatori di nome / tabella, aiuto nella costruzione di clausole dinamiche o semplicemente elenchi di valori di array.

Uso ibrido DOP

Queste funzioni wrapper pdo_* rendono un'API stop-gap adatta alla codifica. (È praticamente ciò che MYSQLI avrebbe potuto essere se non fosse stato per l'idiosincratico spostamento della firma della funzione). Espongono anche la vera DOP alla maggior parte delle volte.
La riscrittura non deve smettere di usare i nuovi nomi delle funzioni pdo_. È possibile passare uno alla volta ogni pdo_query () in una semplice chiamata $ pdo-> prepare () -> execute ().

Tuttavia, è meglio ricominciare a semplificare di nuovo. Ad esempio il recupero dei risultati comuni:

$result = pdo_query("SELECT * FROM tbl");
while ($row = pdo_fetch_assoc($result)) {

Può essere sostituito con solo un'iterazione foreach:

foreach ($result as $row) {

O meglio ancora un recupero di array diretto e completo:

$result->fetchAll();

Nella maggior parte dei casi riceverai avvertenze più utili rispetto a PDO o mysql_ che di solito forniscono dopo query non riuscite.

Altre opzioni

Quindi questo sperava di visualizzare alcune ragioni pratiche e un percorso mysql_ per eliminare mysql_ .

Il solo passaggio a pdo non lo taglia. pdo_query() è anche solo un frontend su di esso.

A meno che tu non introduca il binding dei parametri o che possa utilizzare qualcos'altro dall'API più carina, è un passaggio inutile. Spero che sia ritratto abbastanza semplice da non favorire lo scoraggiamento verso i nuovi arrivati. (L'istruzione di solito funziona meglio del proibizionismo.)

Anche se si qualifica per la categoria più semplice-che-potrebbe-potrebbe-lavorare, è anche un codice ancora molto sperimentale. L'ho appena scritto durante il fine settimana. C'è comunque una pletora di alternative. Basta google per l' astrazione del database PHP e sfogliare un po '. Ci sono sempre state e ci saranno molte librerie eccellenti per tali compiti.

Se vuoi semplificare ulteriormente l'interazione con il tuo database, vale la pena provare mappatori come Paris/Idiorm . Proprio come nessuno usa più il bland DOM in JavaScript, non è necessario fare da babysitter a un'interfaccia di database raw al giorno d'oggi.

Quali sono le ragioni tecniche per cui non si dovrebbero usare le funzioni mysql_* ? (ad esempio mysql_query() , mysql_connect() o mysql_real_escape_string() )?

Perché dovrei usare qualcos'altro anche se funzionano sul mio sito?

Se non funzionano sul mio sito, perché ottengo errori come

Avviso: mysql_connect (): nessun file o directory di questo tipo


Innanzitutto, iniziamo con il commento standard che diamo a tutti:

share . Non sono più mantenuti deprecated . Vedi la scatola rossa ? Scopri invece le istruzioni preparate e usa PDO o MySQLi : questo articolo ti aiuterà a decidere quale. Se scegli PDO, ecco un buon tutorial .

Passiamo a questo, frase per frase, e spieghiamo:

  • Non sono più mantenuti e sono ufficialmente deprecati

    Ciò significa che la comunità PHP sta gradualmente abbandonando il supporto per queste funzioni molto vecchie. È probabile che non esistano in una versione futura (recente) di PHP! L'uso continuato di queste funzioni potrebbe violare il codice nel futuro (non così).

    NUOVO! - ext / mysql è deprecated

    Più nuovo! ext / mysql è stato rimosso in PHP 7 .

  • Invece, dovresti imparare delle dichiarazioni preparate

    mysql_* estensione mysql_* non supporta le istruzioni preparate , che è (tra le altre cose) una contromisura molto efficace contro SQL Injection . Ha risolto una vulnerabilità molto seria nelle applicazioni dipendenti da MySQL che consente agli aggressori di accedere al tuo script ed eseguire qualsiasi query sul tuo database.

    Per maggiori informazioni, vedi Come posso evitare l'SQL injection in PHP?

  • Vedi la scatola rossa?

    Quando vai su qualsiasi pagina di manuale della funzione mysql , vedi una casella rossa, spiegando che non dovrebbe più essere usata.

  • Usa PDO o MySQLi

    Ci sono alternative migliori, più robuste e ben costruite, PDO , che offre un approccio OOP completo all'interazione del database e MySQLi , che è un miglioramento specifico di MySQL.


PHP offre tre API diverse per connettersi a MySQL. Queste sono le estensioni mysql (rimosse come da PHP 7), mysqli e PDO .

Le funzioni mysql_* erano molto popolari, ma il loro uso non è più incoraggiato. Il team di documentazione sta discutendo la situazione della sicurezza del database e l'istruzione degli utenti ad allontanarsi dall'estensione ext / mysql comunemente usata fa parte di questa (controlla php.internals: deprecating ext / mysql ).

E il successivo team di sviluppatori PHP ha preso la decisione di generare errori E_DEPRECATED quando gli utenti si connettono a MySQL, tramite mysql_connect() , mysql_pconnect() o la funzionalità di connessione implicita incorporata in ext/mysql .

ext/mysql stato deprecated ed è stato rimosso da PHP 7 .

Vedi la scatola rossa?

Quando vai su qualsiasi pagina di manuale della funzione mysql_* , vedi una casella rossa, spiegando che non dovrebbe più essere usata.

Perché

Allontanarsi da ext/mysql non riguarda solo la sicurezza, ma anche l'accesso a tutte le funzionalità del database MySQL.

ext/mysql stato creato per MySQL 3.23 e da allora ha ottenuto solo poche aggiunte, mentre per lo più mantiene la compatibilità con questa vecchia versione che rende il codice un po 'più difficile da mantenere. Le funzionalità mancanti non supportate da ext/mysql includono: ( deprecated ).

Motivo per non utilizzare la funzione mysql_* :

  • Non in sviluppo attivo
  • Rimosso da PHP 7
  • Manca un'interfaccia OO
  • Non supporta query asincrone non bloccanti
  • Non supporta istruzioni preparate o query con parametri
  • Non supporta le stored procedure
  • Non supporta più istruzioni
  • Non supporta le transactions
  • Non supporta tutte le funzionalità di MySQL 5.1

Sopra il punto citato dalla risposta di Quentin

La mancanza di supporto per le istruzioni preparate è particolarmente importante in quanto forniscono un metodo più chiaro e meno soggetto a errori di escaping e di citazione dei dati esterni rispetto all'esclusione manuale con una chiamata di funzione separata.

Vedi il confronto delle estensioni SQL .

Soppressione degli avvisi di deprecazione

Mentre il codice viene convertito in MySQLi / PDO , E_DEPRECATED errori E_DEPRECATED possono essere E_DEPRECATED impostando error_reporting in php.ini per escludere E_DEPRECATED:

error_reporting = E_ALL ^ E_DEPRECATED

Si noti che questo nasconderà anche altri avvisi di deprecazione , che, tuttavia, potrebbero riguardare cose diverse da MySQL. ( dal manuale PHP )

L'articolo PDO vs MySQLi: quale dovresti usare? di Dejan Marjanovic ti aiuterà a scegliere.

E un modo migliore è PDO , e ora sto scrivendo un semplice tutorial su PDO .

Un tutorial PDO semplice e breve

D. La prima domanda nella mia mente è stata: che cosa è "DOP"?

A. " PDO - PHP Data Objects - è un livello di accesso al database che fornisce un metodo uniforme di accesso a più database".

Connessione a MySQL

Con la funzione mysql_* o possiamo dirlo alla vecchia maniera (deprecato in PHP 5.5 e versioni successive)

$link = mysql_connect('localhost', 'user', 'pass');
mysql_select_db('testdb', $link);
mysql_set_charset('UTF-8', $link);

Con PDO : tutto ciò che devi fare è creare un nuovo oggetto PDO . Il costruttore accetta i parametri per specificare il costruttore del database. Il costruttore di PDO prende principalmente quattro parametri che sono DSN (nome dell'origine dati) e facoltativamente username , password .

Qui penso che tu abbia familiarità con tutti tranne DSN ; questo è nuovo in PDO . Un DSN è fondamentalmente una serie di opzioni che indicano a quale driver utilizzare, e i dettagli della connessione. Per ulteriori riferimenti, consultare PDO MySQL DSN .

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8', 'username', 'password');

Nota: puoi usare anche charset=UTF-8 , ma a volte causa un errore, quindi è meglio usare utf8 .

Se c'è un errore di connessione, lancia un oggetto PDOException che può essere catturato per gestire ulteriormente l' Exception .

Buona lettura : connessioni e gestione delle connessioni ¶

È anche possibile passare diverse opzioni del driver come array al quarto parametro. Raccomando di passare il parametro che mette il PDO in modalità di eccezione. Poiché alcuni driver PDO non supportano le istruzioni preparate in modo nativo, quindi PDO esegue l'emulazione della preparazione. Permette anche di abilitare manualmente questa emulazione. Per utilizzare le istruzioni preparate sul lato server nativo, è necessario impostarlo in modo esplicito.

L'altro è di disattivare l'emulazione di preparazione che è abilitata nel driver MySQL per impostazione predefinita, ma preparare l'emulazione dovrebbe essere disattivata per utilizzare PDO modo sicuro.

In seguito spiegherò perché preparare l'emulazione dovrebbe essere disattivata. Per trovare la ragione, controlla questo post .

È utilizzabile solo se si utilizza una vecchia versione di MySQL che non è consigliabile.

Di seguito è riportato un esempio di come è possibile farlo:

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password',
              array(PDO::ATTR_EMULATE_PREPARES => false,
              PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));

Possiamo impostare gli attributi dopo la costruzione dei PDO?

, possiamo anche impostare alcuni attributi dopo la costruzione di PDO con il metodo setAttribute :

$db = new PDO('mysql:host=localhost;dbname=testdb;charset=UTF-8', 
              'username', 
              'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

Gestione degli errori

La gestione degli errori è molto più facile in PDO di mysql_* .

Una pratica comune quando si usa mysql_* è:

//Connected to MySQL
$result = mysql_query("SELECT * FROM table", $link) or die(mysql_error($link));

OR die() non è un buon modo per gestire l'errore poiché non possiamo gestire la cosa in die . Interrompe bruscamente lo script e quindi fa eco all'errore che di solito NON vuoi mostrare ai tuoi utenti finali e lascia che i malintenzionati scoprano il tuo schema. In alternativa, i valori di ritorno delle funzioni mysql_* possono essere spesso utilizzati insieme a mysql_error() per gestire gli errori.

PDO offre una soluzione migliore: eccezioni. Tutto ciò che facciamo con PDO dovrebbe essere racchiuso in un blocco try - catch . Possiamo forzare PDO in una delle tre modalità di errore impostando l'attributo della modalità errore. Di seguito sono riportate tre modalità di gestione degli errori.

  • PDO::ERRMODE_SILENT . Sta solo impostando i codici di errore e agisce più o meno come mysql_* dove devi controllare ogni risultato e poi guardare $db->errorInfo(); per ottenere i dettagli dell'errore.
  • PDO::ERRMODE_WARNING Alza E_WARNING . (Avvisi in fase di esecuzione (errori non fatali). L'esecuzione dello script non viene interrotta.)
  • PDO::ERRMODE_EXCEPTION : PDO::ERRMODE_EXCEPTION eccezioni. Rappresenta un errore generato da PDO. Non dovresti lanciare un PDOException dal tuo codice. Vedi Eccezioni per maggiori informazioni sulle eccezioni in PHP. Agisce molto or die(mysql_error()); , quando non viene catturato. Ma diversamente da or die() , la PDOException può essere catturata e gestita PDOException se si sceglie di farlo.

Buona lettura :

Piace:

$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING );
$stmt->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

E puoi avvolgerlo in try - catch , come di seguito:

try {
    //Connect as appropriate as above
    $db->query('hi'); //Invalid query!
} 
catch (PDOException $ex) {
    echo "An Error occured!"; //User friendly message/message you want to show to user
    some_logging_function($ex->getMessage());
}

Non devi gestire con try - catch questo momento. Puoi prenderlo in qualsiasi momento, ma ti consiglio vivamente di usare try - catch . Inoltre potrebbe avere più senso prenderlo al di fuori della funzione che chiama il materiale PDO :

function data_fun($db) {
    $stmt = $db->query("SELECT * FROM table");
    return $stmt->fetchAll(PDO::FETCH_ASSOC);
}

//Then later
try {
    data_fun($db);
}
catch(PDOException $ex) {
    //Here you can handle error and show message/perform action you want.
}

Inoltre, puoi gestire by or die() o possiamo dire come mysql_* , ma sarà davvero vario. È possibile nascondere i messaggi di errore pericolosi in produzione display_errors off e leggendo semplicemente il log degli errori.

Ora, dopo aver letto tutto quanto sopra, probabilmente stai pensando: che diamine è che quando voglio iniziare semplicemente appoggiando semplici SELECT , INSERT , UPDATE o DELETE ? Non preoccuparti, eccoci qui:

Selezione dei dati

Quindi quello che stai facendo in mysql_* è:

<?php
$result = mysql_query('SELECT * from table') or die(mysql_error());

$num_rows = mysql_num_rows($result);

while($row = mysql_fetch_assoc($result)) {
    echo $row['field1'];
}

Ora in PDO , puoi fare questo:

<?php
$stmt = $db->query('SELECT * FROM table');

while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
    echo $row['field1'];
}

O

<?php
$stmt = $db->query('SELECT * FROM table');
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);

//Use $results

Nota : se si utilizza il metodo come di seguito ( query() ), questo metodo restituisce un oggetto PDOStatement . Quindi se vuoi recuperare il risultato, usalo come sopra.

<?php
foreach($db->query('SELECT * FROM table') as $row) {
    echo $row['field1'];
}

In Dati PDO, si ottiene tramite ->fetch() , un metodo del tuo handle di istruzioni. Prima di chiamare fetch, l'approccio migliore sarebbe dire a DOP come desideri che i dati vengano recuperati. Nella sezione seguente lo sto spiegando.

Modalità di recupero

Notare l'uso di PDO::FETCH_ASSOC nel PDO::FETCH_ASSOC fetch() e fetchAll() sopra. Questo dice a PDO di restituire le righe come array associativo con i nomi dei campi come chiavi. Ci sono anche molte altre modalità di recupero che spiegherò una per una.

Prima di tutto, spiego come selezionare la modalità di recupero:

 $stmt->fetch(PDO::FETCH_ASSOC)

In quanto sopra, sto usando fetch() . Puoi anche usare:

Ora vengo in modalità di recupero:

  • PDO::FETCH_ASSOC : restituisce un array indicizzato per nome colonna come restituito nel set di risultati
  • PDO::FETCH_BOTH (predefinito): restituisce un array indicizzato dal nome della colonna e dal numero di colonna con indice 0 restituito nel set di risultati

Ci sono ancora più scelte! Leggi di tutti loro nella documentazione di PDOStatement del PDOStatement . .

Ottenere il conteggio delle righe :

Invece di usare mysql_num_rows per ottenere il numero di righe restituite, puoi ottenere una PDOStatement e fare rowCount() , come:

<?php
$stmt = $db->query('SELECT * FROM table');
$row_count = $stmt->rowCount();
echo $row_count.' rows selected';

Ottenere l'ultimo ID inserito

<?php
$result = $db->exec("INSERT INTO table(firstname, lastname) VAULES('John', 'Doe')");
$insertId = $db->lastInsertId();

Inserisci e aggiorna o cancella le istruzioni

Quello che stiamo facendo nella funzione mysql_* è:

<?php
$results = mysql_query("UPDATE table SET field='value'") or die(mysql_error());
echo mysql_affected_rows($result);

E in pdo, questa stessa cosa può essere fatta da:

<?php
$affected_rows = $db->exec("UPDATE table SET field='value'");
echo $affected_rows;

Nella query precedente PDO::exec esegue un'istruzione SQL e restituisce il numero di righe interessate.

Inserimento ed eliminazione saranno trattati in seguito.

Il metodo precedente è utile solo quando non si utilizza la variabile nella query. Ma quando hai bisogno di usare una variabile in una query, non provarci mai come sopra e lì per istruzioni preparate o istruzioni parametrizzate .

Dichiarazioni preparate

D. Cos'è una dichiarazione preparata e perché ne ho bisogno?
A. Un'istruzione preparata è un'istruzione SQL precompilata che può essere eseguita più volte inviando solo i dati al server.

Il tipico flusso di lavoro dell'utilizzo di una dichiarazione preparata è il seguente ( citato da Wikipedia tre punti 3 ):

  1. Preparazione : il modello dell'istruzione viene creato dall'applicazione e inviato al sistema di gestione del database (DBMS). Alcuni valori non sono specificati, denominati parametri, segnaposti o variabili di collegamento (contrassegnati da ? ):

    INSERT INTO PRODUCT (name, price) VALUES (?, ?)

  2. Il DBMS analizza, compila ed esegue l'ottimizzazione della query sul modello dell'istruzione e memorizza il risultato senza eseguirlo.

  3. Esegui : in un secondo momento, l'applicazione fornisce (o associa) i valori per i parametri e il DBMS esegue l'istruzione (eventualmente restituendo un risultato). L'applicazione può eseguire l'istruzione tutte le volte che vuole con valori diversi. In questo esempio, potrebbe fornire "Pane" per il primo parametro e 1.00 per il secondo parametro.

È possibile utilizzare una dichiarazione preparata includendo segnaposti nel proprio SQL. Ci sono fondamentalmente tre senza segnaposto (non provatelo con la variabile sopra), uno con segnaposto senza nome e uno con segnaposto con nome.

D. Così ora, quali sono i segnaposto nominati e come li uso?
A. Segnaposto nominati. Usa nomi descrittivi preceduti da due punti, invece di punti interrogativi. Non ci interessa la posizione / l'ordine di valore nel titolare del nome:

 $stmt->bindParam(':bla', $bla);

bindParam(parameter,variable,data_type,length,driver_options)

Puoi anche eseguire il binding utilizzando un array execute:

<?php
$stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
$stmt->execute(array(':name' => $name, ':id' => $id));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

Un'altra caratteristica interessante per gli amici OOP è che i segnaposto con nome hanno la possibilità di inserire oggetti direttamente nel database, assumendo che le proprietà corrispondano ai campi nominati. Per esempio:

class person {
    public $name;
    public $add;
    function __construct($a,$b) {
        $this->name = $a;
        $this->add = $b;
    }

}
$demo = new person('john','29 bla district');
$stmt = $db->prepare("INSERT INTO table (name, add) value (:name, :add)");
$stmt->execute((array)$demo);

D. Allora, quali sono i segnaposto senza nome e come li uso?
A. Facciamo un esempio:

<?php
$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->bindValue(1, $name, PDO::PARAM_STR);
$stmt->bindValue(2, $add, PDO::PARAM_STR);
$stmt->execute();

e

$stmt = $db->prepare("INSERT INTO folks (name, add) values (?, ?)");
$stmt->execute(array('john', '29 bla district'));

In quanto sopra, puoi vedere quelli ? invece di un nome come nel nome di un segnaposto. Ora, nel primo esempio, assegniamo le variabili ai vari segnaposto ( $stmt->bindValue(1, $name, PDO::PARAM_STR); ). Quindi, assegniamo valori a quei segnaposto ed eseguiamo la dichiarazione. Nel secondo esempio, il primo elemento dell'array va al primo ? e il secondo al secondo ? .

NOTA : nei segnaposto senza nome dobbiamo occuparci dell'ordinamento corretto degli elementi dell'array che stiamo passando al PDOStatement::execute() .

SELECT , INSERT , UPDATE , DELETE query preparate

  1. SELECT :

    $stmt = $db->prepare("SELECT * FROM table WHERE id=:id AND name=:name");
    $stmt->execute(array(':name' => $name, ':id' => $id));
    $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
    
  2. INSERT :

    $stmt = $db->prepare("INSERT INTO table(field1,field2) VALUES(:field1,:field2)");
    $stmt->execute(array(':field1' => $field1, ':field2' => $field2));
    $affected_rows = $stmt->rowCount();
    
  3. DELETE :

    $stmt = $db->prepare("DELETE FROM table WHERE id=:id");
    $stmt->bindValue(':id', $id, PDO::PARAM_STR);
    $stmt->execute();
    $affected_rows = $stmt->rowCount();
    
  4. UPDATE :

    $stmt = $db->prepare("UPDATE table SET name=? WHERE id=?");
    $stmt->execute(array($name, $id));
    $affected_rows = $stmt->rowCount();
    

NOTA:

Tuttavia PDO e / o MySQLi non sono completamente sicuri. Controlla la risposta Le dichiarazioni preparate da un PDO sono sufficienti per prevenire l'iniezione SQL? di ircmaxell . Inoltre, sto citando una parte della sua risposta:

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$pdo->query('SET NAMES GBK');
$stmt = $pdo->prepare("SELECT * FROM test WHERE name = ? LIMIT 1");
$stmt->execute(array(chr(0xbf) . chr(0x27) . " OR 1=1 /*"));

Le funzioni di mysql_ * sono state ammortizzate (come da php 5.5 ) dato che sono state sviluppate migliori funzioni e strutture di codice. Il fatto che la funzione sia stata ammortizzata significa che non saranno fatti ulteriori sforzi per migliorarlo in termini di prestazioni e sicurezza, il che significa che è meno a prova di futuro .

Se hai bisogno di più motivi:

  • Le funzioni mysql_ * non supportano le istruzioni preparate.
  • Le funzioni mysql_ * non supportano il binding dei parametri.
  • Le funzioni mysql_ * mancano di funzionalità per la programmazione orientata agli oggetti.
  • la lista continua ...

Trovo molto lunghe le risposte di cui sopra, quindi riassumiamo:

L'estensione mysqli ha una serie di vantaggi, i miglioramenti chiave sull'estensione mysql sono:

  • Interfaccia orientata agli oggetti
  • Supporto per le dichiarazioni preparate
  • Supporto per più dichiarazioni
  • Supporto per le transazioni
  • Funzionalità di debug migliorate
  • Supporto del server integrato

Fonte: panoramica MySQLi

Come spiegato nelle risposte precedenti, le alternative a mysql sono mysqli e PDO (PHP Data Objects).

  • L'API supporta le dichiarazioni preparate sul lato server: supportate da MYSQLi e PDO
  • L'API supporta le istruzioni preparate lato client: supportate solo da PDO
  • API supporta stored procedure: sia MySQLi che PDO
  • API supporta più dichiarazioni e tutte le funzionalità di MySQL 4.1+ - Supportato da MySQLi e principalmente anche da PDO

Sia MySQLi che PDO sono stati introdotti in PHP 5.0, mentre MySQL è stato introdotto prima di PHP 3.0. Un punto da notare è che MySQL è incluso in PHP5.x anche se deprecato nelle versioni successive.


È possibile definire quasi tutte le mysql_*funzioni usando mysqli o PDO. Inseriscili sopra la tua vecchia applicazione PHP e funzionerà su PHP7. La mia soluzione here .

<?php

define('MYSQL_LINK', 'dbl');
$GLOBALS[MYSQL_LINK] = null;

function mysql_link($link=null) {
    return ($link === null) ? $GLOBALS[MYSQL_LINK] : $link;
}

function mysql_connect($host, $user, $pass) {
    $GLOBALS[MYSQL_LINK] = mysqli_connect($host, $user, $pass);
    return $GLOBALS[MYSQL_LINK];
}

function mysql_pconnect($host, $user, $pass) {
    return mysql_connect($host, $user, $pass);
}

function mysql_select_db($db, $link=null) {
    $link = mysql_link($link);
    return mysqli_select_db($link, $db);
}

function mysql_close($link=null) {
    $link = mysql_link($link);
    return mysqli_close($link);
}

function mysql_error($link=null) {
    $link = mysql_link($link);
    return mysqli_error($link);
}

function mysql_errno($link=null) {
    $link = mysql_link($link);
    return mysqli_errno($link);
}

function mysql_ping($link=null) {
    $link = mysql_link($link);
    return mysqli_ping($link);
}

function mysql_stat($link=null) {
    $link = mysql_link($link);
    return mysqli_stat($link);
}

function mysql_affected_rows($link=null) {
    $link = mysql_link($link);
    return mysqli_affected_rows($link);
}

function mysql_client_encoding($link=null) {
    $link = mysql_link($link);
    return mysqli_character_set_name($link);
}

function mysql_thread_id($link=null) {
    $link = mysql_link($link);
    return mysqli_thread_id($link);
}

function mysql_escape_string($string) {
    return mysql_real_escape_string($string);
}

function mysql_real_escape_string($string, $link=null) {
    $link = mysql_link($link);
    return mysqli_real_escape_string($link, $string);
}

function mysql_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql);
}

function mysql_unbuffered_query($sql, $link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, $sql, MYSQLI_USE_RESULT);
}

function mysql_set_charset($charset, $link=null){
    $link = mysql_link($link);
    return mysqli_set_charset($link, $charset);
}

function mysql_get_host_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_host_info($link);
}

function mysql_get_proto_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_proto_info($link);
}
function mysql_get_server_info($link=null) {
    $link = mysql_link($link);
    return mysqli_get_server_info($link);
}

function mysql_info($link=null) {
    $link = mysql_link($link);
    return mysqli_info($link);
}

function mysql_get_client_info() {
    $link = mysql_link();
    return mysqli_get_client_info($link);
}

function mysql_create_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "CREATE DATABASE `$db`");
}

function mysql_drop_db($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "DROP DATABASE `$db`");
}

function mysql_list_dbs($link=null) {
    $link = mysql_link($link);
    return mysqli_query($link, "SHOW DATABASES");
}

function mysql_list_fields($db, $table, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    $table = str_replace('`', '', mysqli_real_escape_string($link, $table));
    return mysqli_query($link, "SHOW COLUMNS FROM `$db`.`$table`");
}

function mysql_list_tables($db, $link=null) {
    $link = mysql_link($link);
    $db = str_replace('`', '', mysqli_real_escape_string($link, $db));
    return mysqli_query($link, "SHOW TABLES FROM `$db`");
}

function mysql_db_query($db, $sql, $link=null) {
    $link = mysql_link($link);
    mysqli_select_db($link, $db);
    return mysqli_query($link, $sql);
}

function mysql_fetch_row($qlink) {
    return mysqli_fetch_row($qlink);
}

function mysql_fetch_assoc($qlink) {
    return mysqli_fetch_assoc($qlink);
}

function mysql_fetch_array($qlink, $result=MYSQLI_BOTH) {
    return mysqli_fetch_array($qlink, $result);
}

function mysql_fetch_lengths($qlink) {
    return mysqli_fetch_lengths($qlink);
}

function mysql_insert_id($qlink) {
    return mysqli_insert_id($qlink);
}

function mysql_num_rows($qlink) {
    return mysqli_num_rows($qlink);
}

function mysql_num_fields($qlink) {
    return mysqli_num_fields($qlink);
}

function mysql_data_seek($qlink, $row) {
    return mysqli_data_seek($qlink, $row);
}

function mysql_field_seek($qlink, $offset) {
    return mysqli_field_seek($qlink, $offset);
}

function mysql_fetch_object($qlink, $class="stdClass", array $params=null) {
    return ($params === null)
        ? mysqli_fetch_object($qlink, $class)
        : mysqli_fetch_object($qlink, $class, $params);
}

function mysql_db_name($qlink, $row, $field='Database') {
    mysqli_data_seek($qlink, $row);
    $db = mysqli_fetch_assoc($qlink);
    return $db[$field];
}

function mysql_fetch_field($qlink, $offset=null) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    return mysqli_fetch_field($qlink);
}

function mysql_result($qlink, $offset, $field=0) {
    if ($offset !== null)
        mysqli_field_seek($qlink, $offset);
    $row = mysqli_fetch_array($qlink);
    return (!is_array($row) || !isset($row[$field]))
        ? false
        : $row[$field];
}

function mysql_field_len($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->length : false;
}

function mysql_field_name($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgname) ? $field->name : $field->orgname;
}

function mysql_field_table($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    if (!is_object($field))
        return false;
    return empty($field->orgtable) ? $field->table : $field->orgtable;
}

function mysql_field_type($qlink, $offset) {
    $field = mysqli_fetch_field_direct($qlink, $offset);
    return is_object($field) ? $field->type : false;
}

function mysql_free_result($qlink) {
    try {
        mysqli_free_result($qlink);
    } catch (Exception $e) {
        return false;
    }
    return true;
}

Ci sono molte ragioni, ma forse la più importante è che quelle funzioni incoraggiano pratiche di programmazione non sicure perché non supportano le istruzioni preparate. Le istruzioni preparate aiutano a prevenire attacchi di SQL injection.

Quando si utilizzano le mysql_*funzioni, è necessario ricordare di eseguire i parametri forniti dall'utente attraverso mysql_real_escape_string(). Se ti dimentichi in un solo posto o se sfuggi solo a una parte dell'input, il tuo database potrebbe essere soggetto ad attacchi.

Utilizzare istruzioni preparate PDOo mysqlirenderle in modo che sia più difficile eseguire questo tipo di errori di programmazione.


L'estensione MySQL è la più vecchia delle tre ed era il modo originale con cui gli sviluppatori comunicavano con MySQL. Questa estensione viene ora deprecated a favore delle altre mysqli_ PDO causa dei miglioramenti apportati alle nuove versioni di PHP e MySQL.

  • mysqli_ è l'estensione "migliorata" per lavorare con i database MySQL. Sfrutta le funzionalità disponibili nelle versioni più recenti del server MySQL, espone allo sviluppatore un'interfaccia orientata alle funzioni e un'interfaccia orientata agli oggetti, oltre a poche altre cose interessanti.

  • PDO offre un'API che consolida la maggior parte delle funzionalità precedentemente distribuite tra le principali estensioni di accesso al database, ad esempio MySQL, PostgreSQL, SQLite, MSSQL, ecc. L'interfaccia espone oggetti di alto livello per il programmatore che lavora con connessioni di database, query e set di risultati e driver di basso livello eseguono la comunicazione e la gestione delle risorse con il server del database. Un sacco di discussioni e di lavori sono in corso DOP ed è considerato il metodo appropriato per lavorare con i database nel codice moderno e professionale.


Le funzioni che sono simili a questo mysql_connect(), mysql_query()tipo sono le precedenti funzioni PHP ie (PHP 4) e ora non sono in uso.

Questi sono sostituiti da mysqli_connect(), mysqli_query()analogamente nell'ultimo PHP5.

Questa è la ragione dietro l'errore.


Perché (tra le altre ragioni) è molto più difficile garantire che i dati di input siano disinfettati. Se si utilizzano query parametrizzate, come si fa con PDO o mysqli, è possibile evitare del tutto il rischio.

Ad esempio, qualcuno potrebbe usare "enhzflep); drop table users"come nome utente. Le vecchie funzioni consentiranno l'esecuzione di più istruzioni per query, quindi qualcosa come quel brutto bugger può cancellare un'intera tabella.

Se si dovesse usare PDO di mysqli, il nome utente finirebbe per essere "enhzflep); drop table users".

Vedi bobby-tables.com .





database