Come applicare il metodo bindValue nella clausola LIMIT?
Domanda
Ecco un'istantanea del mio codice:
$fetchPictures = $PDO->prepare("SELECT *
FROM pictures
WHERE album = :albumId
ORDER BY id ASC
LIMIT :skip, :max");
$fetchPictures->bindValue(':albumId', $_GET['albumid'], PDO::PARAM_INT);
if(isset($_GET['skip'])) {
$fetchPictures->bindValue(':skip', trim($_GET['skip']), PDO::PARAM_INT);
} else {
$fetchPictures->bindValue(':skip', 0, PDO::PARAM_INT);
}
$fetchPictures->bindValue(':max', $max, PDO::PARAM_INT);
$fetchPictures->execute() or die(print_r($fetchPictures->errorInfo()));
$pictures = $fetchPictures->fetchAll(PDO::FETCH_ASSOC);
ho
Hai un errore nella sintassi SQL; controllare il manuale che corrisponde la versione del server MySQL per la sintassi diritto di utilizzare vicino a '' 15' , 15' a Linea 1
Sembra che DOP è l'aggiunta di apici ai miei variabili nella parte LIMIT del codice SQL. Ho cercato Ho trovato questo bug che credo sia correlato: http://bugs.php.net/bug.php?id=44639
E 'questo che sto guardando? Questo bug è stato aperto da April 2008! Quello che dovremmo fare nel frattempo?
Ho bisogno di costruire un po 'di impaginazione, e la necessità di assicurarsi che i dati è pulito, SQL Injection di sicurezza, prima di inviare la dichiarazione di sql.
Soluzione
Mi ricordo di avere questo problema prima. Cast del valore di un numero intero prima di passare alla funzione bind. Credo che questo risolve.
$fetchPictures->bindValue(':skip', (int) trim($_GET['skip']), PDO::PARAM_INT);
Altri suggerimenti
La soluzione più semplice sarebbe quella di commutare la modalità di emulazione off . È possibile farlo sia come opzione di connessione o semplicemente aggiungendo la seguente riga
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
E non solo risolvere il problema con bind param, ma permetterà anche di inviare i valori in execute (), che renderà il vostro codice muchshorter
$skip = $_GET['skip'] ?: 0;
$sql = "SELECT * FROM pictures WHERE album = ? ORDER BY id LIMIT ?, ?";
$PDO->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
$stmt = $PDO->prepare($sql);
$stmt->execute([$_GET['albumid'], $skip, $max]);
$pictures = $stmt->fetchAll(PDO::FETCH_ASSOC);
Guardando il bug report, il seguente potrebbe funzionare:
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
$fetchPictures->bindValue(':skip', (int)trim($_GET['skip']), PDO::PARAM_INT);
ma sei sicuro i dati in ingresso è corretto? Perché nel messaggio di errore, sembra che ci sia solo una citazione dopo il numero (in contrasto con il numero intero di essere racchiuso tra virgolette). Questo potrebbe anche essere un errore con i tuoi dati in arrivo. Si può fare un print_r($_GET);
per scoprire?
Questo proprio come sintesi.
Ci sono quattro opzioni per parametrizzare Limitare / valori di offset:
-
PDO::ATTR_EMULATE_PREPARES
Disable come menzionato sopra .che impedisce valori passati per
->execute([...])
a mostrare sempre come stringhe. -
Passa alla popolazione parametro
->bindValue(..., ..., PDO::PARAM_INT)
manuale.Il che, tuttavia, è meno conveniente di un -> execute elenco []
.
-
È sufficiente fare un'eccezione qui e solo interpolare interi semplici quando si prepara la query SQL.
$limit = intval($limit); $s = $pdo->prepare("SELECT * FROM tbl LIMIT {$limit}");
Il casting è importante. Più comunemente vedete
->prepare(sprintf("SELECT ... LIMIT %d", $num))
utilizzati a tal fine. -
Se non si utilizza MySQL, ma per esempio SQLite, o Postgres; è anche possibile cast legato parametri direttamente in SQL.
SELECT * FROM tbl LIMIT (1 * :limit)
Anche in questo caso, MySQL / MariaDB non supportano espressioni nella clausola LIMIT. Non ancora.
per LIMIT :init, :end
È necessario legare in quel modo. se si ha qualcosa di simile $req->execute(Array());
non funzionerà come sarà gettato PDO::PARAM_STR
a tutti Vars nella matrice e per la LIMIT
è assolutamente necessario un numero intero.
bindValue o BindParam come si desidera.
$fetchPictures->bindValue(':albumId', (int)$_GET['albumid'], PDO::PARAM_INT);
Dal momento che nessuno ha spiegato perché questo sta accadendo, io sono l'aggiunta di una risposta. Il motivo per cui si sta comportando questo è stato è perché si sta utilizzando trim()
. Se si guarda al manuale di PHP per trim
, il tipo di ritorno è string
. Si sta quindi cercando di far passare questo come PDO::PARAM_INT
. A pochi modi per aggirare questo sono:
- Usa
filter_var($integer, FILTER_VALIDATE_NUMBER_INT)
per assicurarsi che si sta passando un intero. - Come altri hanno detto, usando
intval()
- Casting con
(int)
- Verificando è un intero con
is_int()
Ci sono molti altri modi, ma questo è fondamentalmente la causa principale.
bindValue di offset e il limite di utilizzo DOP :: PARAM_INT e funzionerà
// prima (errore Presente) $ Query = ".... LIMITE: p1, 30;"; ... $ Stmt-> BindParam ( 'p1', $ limiteInferior);
// DOPO (errore corretto) $ Query = ".... LIMITE: p1, 30;"; ... $ LimiteInferior = (int) $ limiteInferior; $ Stmt-> BindParam ( 'p1', $ limiteInferior, DOP :: PARAM_INT);
PDO::ATTR_EMULATE_PREPARES
mi ha dato la
driver non supporta questa funzione: Questo driver non supporta errore di impostazione attributi.
La mia soluzione era quella di impostare una variabile $limit
come una stringa, poi si combinano nella dichiarazione di preparare, come nel seguente esempio:
$limit = ' LIMIT ' . $from . ', ' . $max_results;
$stmt = $pdo->prepare( 'SELECT * FROM users WHERE company_id = :cid ORDER BY name ASC' . $limit . ';' );
try {
$stmt->execute( array( ':cid' => $company_id ) );
...
}
catch ( Exception $e ) {
...
}