oci_bind_by_name

(PHP 5, PHP 7, PHP 8, PECL OCI8 >= 1.1.0)

oci_bind_by_nameEffettua il binding di una variabile PHP a un segnaposto Oracle

Descrizione

oci_bind_by_name(
    resource $statement,
    string $param,
    mixed &$var,
    int $max_length = -1,
    int $type = 0
): bool

Associa una variabile PHP var al segnaposto per la variabile di bind Oracle param. Il binding è importante per le prestazioni del database Oracle e anche come metodo per evitare problemi di sicurezza legati all'SQL Injection.

Il binding consente al database di riutilizzare il contesto della dichiarazione e le cache dalle esecuzioni precedenti della dichiarazione, anche se un altro utente o processo l'ha inizialmente eseguita. Il binding riduce i rischi legati all'SQL Injection, perché i dati associati a una variabile di bind non sono mai trattati come parte della dichiarazione SQL. Non è necessaria né il quoting né l'escaping.

Le variabili PHP sui cui è stato effettuato il binding possono essere modificate e la dichiarazione rieseguita senza bisogno di rieffettuare il parsing della dichiarazione o di rifare il bind.

In Oracle, le variabili di bind sono comunemente suddivise in bind IN per i valori che vengono passati nel database, e bind OUT per i valori che vengono restituiti a PHP. Una variabile di bind può essere sia IN che OUT. Se una variabile di bind verrà utilizzata per l'input o per l'output viene determinato in fase di esecuzione.

Bisogna specificare max_length quando si utilizza un bind OUT affinché PHP possa allocare abbastanza memoria per contenere il valore restituito.

Per i bind IN, è consigliato impostare la lunghezza di max_length se la dichiarazione viene rieseguita più volte con valori differenti per la variabile PHP. Altrimenti Oracle potrebbe troncare i dati alla lunghezza del valore iniziale della variabile PHP. Se non si conosce quale sarà la lunghezza massima, richiamare di nuovo oci_bind_by_name() con la dimensione dei dati correnti prima di ogni chiamata a oci_execute(). Un binding con una lunghezza eccessivamente grande avrà un impatto sulla memoria del processo nel database.

Una chiamata al bind indica a Oracle da quale indirizzo di memoria leggere i dati. Per i bind IN, questo indirizzo deve contenere dati validi quando viene chiamato oci_execute(). Ciò significa che la variabile su cui è stato fatto il binding deve rimanere in scope fino all'esecuzione. Se non rimane in scope, potrebbero verificarsi risultati imprevisti o errori come "ORA-01460: unimplemented or unreasonable conversion requested". Per i bind OUT, uno dei sintomi è che nessun valore viene impostato nella variabile PHP.

Per una dichiarazione che viene eseguita ripetutamente, effeettuare il binding di valori che non cambiano mai potrebbe ridurre la capacità dell'ottimizzatore Oracle di scegliere il piano di esecuzione migliore. Le dichiarazioni di lunga durata che vengono rieseguite raramente potrebbero non trarre vantaggio dal binding. Tuttavia, in entrambi i casi, il binding potrebbe essere più sicuro rispetto all'unione di stringhe in una dichiarazione SQL, poiché questo può rappresentare un rischio per la sicurezza se vengono concatenate stringhe dell'utente non filtrate.

Elenco dei parametri

statement

Un identificatore valido di una dichiarazione OCI8.

param

Il segnaposto della variabile bind con prefisso due punti utilizzato nella dichiarazione. Il due punti è opzionale in param. Oracle non utilizza i punti interrogativi per i segnaposti.

var

La variabile PHP da associare a param

max_length

Imposta la lunghezza massima per i dati. Se la imposti su -1, questa funzione utilizzerà la lunghezza attuale di var per impostare la lunghezza massima. In questo caso, var deve esistere e contenere dati quando viene chiamato oci_bind_by_name().

type

Il tipo di dato che Oracle tratterà come tale. Il tipo default utilizzato è SQLT_CHR. Oracle convertirà i dati tra questo tipo e la colonna del database (o il tipo di variabile PL/SQL), se possibile.

Se devi associare un tipo di dato astratto (LOB/ROWID/BFILE), devi prima allocarlo utilizzando la funzione oci_new_descriptor(). La length non viene utilizzata per i tipi di dato astratti e dovrebbe essere impostata su -1.

I valori possibili per type sono:

Valori restituiti

Restituisce true in caso di successo, false in caso di fallimento.

Esempi

Example #1 Inserimento di dati con oci_bind_by_name()

<?php

// Crea la tabella con:
// CREATE TABLE mytab (id NUMBER, text VARCHAR2(40));

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$stid = oci_parse($conn,"INSERT INTO mytab (id, text) VALUES(:id_bv, :text_bv)");

$id = 1;
$text = "Dati da inserire ";
oci_bind_by_name($stid, ":id_bv", $id);
oci_bind_by_name($stid, ":text_bv", $text);
oci_execute($stid);

// La tabella ora contiene: 1, 'Dati da inserire '

?>

Example #2 Binding una sola volta per più esecuzioni

<?php

// Crea la tabella con:
// CREATE TABLE mytab (id NUMBER);

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$a = array(1,3,5,7,11); // dati da inserire

$stid = oci_parse($conn, 'INSERT INTO mytab (id) VALUES (:bv)');
oci_bind_by_name($stid, ':bv', $v, 20);
foreach (
$a as $v) {
$r = oci_execute($stid, OCI_DEFAULT); // non eseguire il commit automatico
}
oci_commit($conn); // esegue il commit di tutto

// La tabella contiene cinque righe: 1, 3, 5, 7, 11

oci_free_statement($stid);
oci_close($conn);

?>

Example #3 Binding con un ciclo foreach

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql = 'SELECT * FROM departments WHERE department_name = :dname AND location_id = :loc';
$stid = oci_parse($conn, $sql);

$ba = array(':dname' => 'IT Support', ':loc' => 1700);

foreach (
$ba as $key => $val) {

// oci_bind_by_name($stid, $key, $val) non funziona
// perché associa ogni segnaposto alla stessa posizione: $val
// invece usa la posizione effettiva dei dati: $ba[$key]
oci_bind_by_name($stid, $key, $ba[$key]);
}

oci_execute($stid);
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);
foreach (
$row as $item) {
print
$item."<br>\n";
}

oci_free_statement($stid);
oci_close($conn);

?>

Example #4 Binding in una clausola WHERE

<?php

$conn
= oci_connect("hr", "hrpwd", "localhost/XE");
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql = 'SELECT last_name FROM employees WHERE department_id = :didbv ORDER BY last_name';
$stid = oci_parse($conn, $sql);
$didbv = 60;
oci_bind_by_name($stid, ':didbv', $didbv);
oci_execute($stid);
while ((
$row = oci_fetch_array($stid, OCI_ASSOC)) != false) {
echo
$row['LAST_NAME'] ."<br>\n";
}

// L'output è
// Austin
// Ernst
// Hunold
// Lorentz
// Pataballa

oci_free_statement($stid);
oci_close($conn);

?>

Example #5 Binding con una clausola LIKE

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

// Trova tutte le città che iniziano con 'South'
$stid = oci_parse($conn, "SELECT city FROM locations WHERE city LIKE :bv");
$city = 'South%'; // '%' è un carattere jolly in SQL
oci_bind_by_name($stid, ":bv", $city);
oci_execute($stid);
oci_fetch_all($stid, $res);

foreach (
$res['CITY'] as $c) {
print
$c . "<br>\n";
}
// L'output è
// South Brunswick
// South San Francisco
// Southlake

oci_free_statement($stid);
oci_close($conn);

?>

Example #6 Binding con REGEXP_LIKE

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

// Trova tutte le città che contengono 'ing'
$stid = oci_parse($conn, "SELECT city FROM locations WHERE REGEXP_LIKE(city, :bv)");
$city = '.*ing.*';
oci_bind_by_name($stid, ":bv", $city);
oci_execute($stid);
oci_fetch_all($stid, $res);

foreach (
$res['CITY'] as $c) {
print
$c . "<br>\n";
}
// L'output è
// Beijing
// Singapore

oci_free_statement($stid);
oci_close($conn);

?>

Per un numero limitato e fisso di condizioni nella clausola IN, usare variabili di bind individuali. I valori sconosciuti al momento dell'esecuzione possono essere impostati su NULL. Questo permette di utilizzare una singola dichiarazione per tutti gli utenti dell'applicazione, massimizzando l'efficienza della cache del database Oracle.

Example #7 Binding di più valori in una clausola IN

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql = 'SELECT last_name FROM employees WHERE employee_id in (:e1, :e2, :e3)';
$stid = oci_parse($conn, $sql);
$mye1 = 103;
$mye2 = 104;
$mye3 = NULL; // supponiamo di non aver ricevuto questo valore
oci_bind_by_name($stid, ':e1', $mye1);
oci_bind_by_name($stid, ':e2', $mye2);
oci_bind_by_name($stid, ':e3', $mye3);
oci_execute($stid);
oci_fetch_all($stid, $res);
foreach (
$res['LAST_NAME'] as $name) {
print
$name ."<br>\n";
}

// L'output è:
// Ernst
// Hunold

oci_free_statement($stid);
oci_close($conn);

?>

Example #8 Binding di un ROWID restituito da una query

<?php

// Crea la tabella con:
// CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
// INSERT INTO mytab (id, salary, name) VALUES (1, 100, 'Chris');
// COMMIT;

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$stid = oci_parse($conn, 'SELECT ROWID, name FROM mytab WHERE id = :id_bv FOR UPDATE');
$id = 1;
oci_bind_by_name($stid, ':id_bv', $id);
oci_execute($stid);
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);
$rid = $row['ROWID'];
$name = $row['NAME'];

// Cambia il nome in maiuscolo e salva le modifiche
$name = strtoupper($name);
$stid = oci_parse($conn, 'UPDATE mytab SET name = :n_bv WHERE ROWID = :r_bv');
oci_bind_by_name($stid, ':n_bv', $name);
oci_bind_by_name($stid, ':r_bv', $rid, -1, OCI_B_ROWID);
oci_execute($stid);

// La tabella ora contiene 1, 100, CHRIS

oci_free_statement($stid);
oci_close($conn);

?>

Example #9 Binding di un ROWID su INSERT

<?php

// Questo esempio inserisce un id e un nome, e poi aggiorna lo stipendio
// Crea la tabella con:
// CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// Basato sull'esempio originale di ROWID di thies at thieso dot net (980221)

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}

$sql = "INSERT INTO mytab (id, name) VALUES(:id_bv, :name_bv)
RETURNING ROWID INTO :rid"
;

$ins_stid = oci_parse($conn, $sql);

$rowid = oci_new_descriptor($conn, OCI_D_ROWID);
oci_bind_by_name($ins_stid, ":id_bv", $id, 10);
oci_bind_by_name($ins_stid, ":name_bv", $name, 32);
oci_bind_by_name($ins_stid, ":rid", $rowid, -1, OCI_B_ROWID);

$sql = "UPDATE mytab SET salary = :salary WHERE ROWID = :rid";
$upd_stid = oci_parse($conn, $sql);
oci_bind_by_name($upd_stid, ":rid", $rowid, -1, OCI_B_ROWID);
oci_bind_by_name($upd_stid, ":salary", $salary, 32);

// id e nomi da inserire
$data = array(1111 => "Larry",
2222 => "Bill",
3333 => "Jim");

// Stipendio per ogni persona
$salary = 10000;

// Inserisce ed immediatamente aggiorna ogni riga
foreach ($data as $id => $name) {
oci_execute($ins_stid);
oci_execute($upd_stid);
}

$rowid->free();
oci_free_statement($upd_stid);
oci_free_statement($ins_stid);

// Mostra le nuove righe
$stid = oci_parse($conn, "SELECT * FROM mytab");
oci_execute($stid);
while (
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
var_dump($row);
}

oci_free_statement($stid);
oci_close($conn);

?>

Example #10 Binding per una stored function PL/SQL

<?php

// Prima di eseguire il programma PHP, creare una stored function in
// SQL*Plus o SQL Developer:
//
// CREATE OR REPLACE FUNCTION myfunc(p IN NUMBER) RETURN NUMBER AS
// BEGIN
// RETURN p * 3;
// END;

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$p = 8;

$stid = oci_parse($conn, 'begin :r := myfunc(:p); end;');
oci_bind_by_name($stid, ':p', $p);

// Il valore di ritorno è un OUT bind. Il tipo predefinito sarà una stringa
// quindi legare una lunghezza di 40 significa che al massimo verranno restituiti
// 40 caratteri.
oci_bind_by_name($stid, ':r', $r, 40);

oci_execute($stid);

print
"$r\n"; // prints 24

oci_free_statement($stid);
oci_close($conn);

?>

Example #11 Binding di parametri per una stored procedure PL/SQL

<?php

// Prima di eseguire il programma PHP, creare una stored procedure in
// SQL*Plus or SQL Developer:
//
// CREATE OR REPLACE PROCEDURE myproc(p1 IN NUMBER, p2 OUT NUMBER) AS
// BEGIN
// p2 := p1 * 2;
// END;

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$p1 = 8;

$stid = oci_parse($conn, 'begin myproc(:p1, :p2); end;');
oci_bind_by_name($stid, ':p1', $p1);

// Il secondo parametro della procedura è un OUT bind. Il tipo predefinito
// sarà una stringa quindi legare una lunghezza di 40 significa che al massimo verranno
// restituite 40 cifre.
oci_bind_by_name($stid, ':p2', $p2, 40);

oci_execute($stid);

print
"$p2\n"; // stampa 16

oci_free_statement($stid);
oci_close($conn);

?>

Example #12 Binding di una colonna CLOB

<?php

// Prima di eseguire, creare la tabella:
// CREATE TABLE mytab (mykey NUMBER, myclob CLOB);

$conn = oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$mykey = 12343; // chiave arbitraria per questo esempio;

$sql = "INSERT INTO mytab (mykey, myclob)
VALUES (:mykey, EMPTY_CLOB())
RETURNING myclob INTO :myclob"
;

$stid = oci_parse($conn, $sql);
$clob = oci_new_descriptor($conn, OCI_D_LOB);
oci_bind_by_name($stid, ":mykey", $mykey, 5);
oci_bind_by_name($stid, ":myclob", $clob, -1, OCI_B_CLOB);
oci_execute($stid, OCI_DEFAULT);
$clob->save("A very long string");

oci_commit($conn);

// Recupero dei dati CLOB

$query = 'SELECT myclob FROM mytab WHERE mykey = :mykey';

$stid = oci_parse ($conn, $query);
oci_bind_by_name($stid, ":mykey", $mykey, 5);
oci_execute($stid);

print
'<table border="1">';
while (
$row = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_LOBS)) {
print
'<tr><td>'.$row['MYCLOB'].'</td></tr>';
// In un ciclo, liberare la variabile di grandi dimensioni prima del secondo fetch riduce l'utilizzo massimo della memoria da parte di PHP
unset($row);
}
print
'</table>';

?>

Example #13 Binding di un BOOLEAN PL/SQL

<?php

$conn
= oci_connect('hr', 'welcome', 'localhost/XE');
if (!
$conn) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}

$plsql =
"begin
:output1 := true;
:output2 := false;
end;"
;

$s = oci_parse($c, $plsql);
oci_bind_by_name($s, ':output1', $output1, -1, OCI_B_BOL);
oci_bind_by_name($s, ':output2', $output2, -1, OCI_B_BOL);
oci_execute($s);
var_dump($output1); // true
var_dump($output2); // false

?>

Note

Avviso

Non usare addslashes() e oci_bind_by_name() contemporaneamente, in quanto non è necessario nessun quoting. Qualsiasi tipo di quote applicato magicamente verrà scritto nel tuo database, poiché oci_bind_by_name() inserisce i dati letteralmente e non rimuove le virgolette o i caratteri di escape.

Nota:

Se associ una stringa a una colonna CHAR in una clausola WHERE, ricorda che Oracle utilizza la semantica di confronto con padding vuoto per le colonne CHAR. La tua variabile PHP dovrebbe essere riempita con spazi vuoti alla stessa larghezza della colonna affinché la clausola WHERE abbia successo.

Nota:

L'argomento var di PHP è un riferimento. Alcune forme di loop non funzionano come ci si aspetterebbe:

<?php
foreach ($myarray as $key => $value) {
oci_bind_by_name($stid, $key, $value);
}
?>

Questo associa ogni chiave alla posizione di $value, quindi tutte le variabili legate finiscono per puntare al valore dell'ultima iterazione del ciclo. Usa invece il seguente codice:

<?php
foreach ($myarray as $key => $value) {
oci_bind_by_name($stid, $key, $myarray[$key]);
}
?>

Vedere anche: