(PHP 5, PECL OCI8 >= 1.1.0)
oci_bind_by_name — Vincula una variable de PHP a un parámetro de sustitución de Oracle
$statement
, string $bv_name
, mixed &$variable
[, int $maxlength
= -1
[, int $type
= SQLT_CHR
]] )
Vincula la variable de PHP variable
al parámetro de
sustitución de variable vinculada de Oracle bv_name
. La vinculación
es importante para el rendimiento de la base de datos de Oracle y también como un forma de
evitar problemas de seguridad de Inyecciones SQL.
La vinculación permite que la base de datos reutilice el contexto de la sentencia y use la caché desde ejecuciones previas de dicha sentencia, incluso si otro usuario o proceso la ejecutó inicialmente. La vinculación reduce las inquietudes con Inyecciones SQL ya que los datos asociados con una variable vinculada nunca son tratados como parte de la sentencia SQL. Hace que no sean necesarios la entrecomillación o el escape.
Las variables de PHP que han sido vinculadas se pueden cambiar, por lo que la sentencia se reejecutará sin necesidad de reanalizarla o revincularla.
En Oracle, la vinculaión de variables se divide normalmente en vínculos IN para valores que son pasados a la base de datos, y vínculos OUT para valores que son devueltos a PHP. Una variable vinculada podría ser tanto IN como OUT. Si una variable vinculada será usada para entrada o salida se determina en en tiempo de ejecución.
Se debe especificar maxlength
al utilizar
un vínculo OUT para que PHP asigne suficiente memoria
para contener el valor devuelto.
Para los vínculos IN, se recomienda establecer
la longitud maxlength
si la sentencia es
reejecutada múltiples veces con diferentes valores para la variable de
PHP. Si no, Oracle podría truncar los datos a la longitud del
valor inicial de la variable de PHP. Si no se conoce cuál será la longitud
máxima, reinvoque a oci_bind_by_name()
con el tamaño de los datos actuales antes de
cada llamada a oci_execute(). Vincular una
longitud grande innecesariamente tendrá un impacto en la memoria del proceso
de la base de datos.
Una llamada vinculada le indica a Oracle desde qué dirección de memoria debe leer datos. Para vínculos IN, esta dirección necesita contener datos válidos cuando se invoque a oci_execute(). Esto significa que la variable vinculada debe permanecer en el ámbito hasta su ejecución. Si no se hace, pueden ocurrir errores inesperados como "ORA-01460: unimplemented or unreasonable conversion requested". Para vínculos OUT, un síntoma es que no se ha establecido un valor en la variable de PHP.
Para una sentencia que sea ejecutada repetidamente, los valores vinculados que nunca cambian podrían reducir la capacidad del optimizador de Oracle para elegir el mejor plan de ejecución de sentencias. Las sentencias que tarden en ejecutarse y que sean reejecutadas raramente podrían no beneficiarse de la vinculación. Sin embargo, en ambos casos, la vinculación podría ser más segura que unir cadenas en una sentencia SQL, ya que esto puede ser un riesgo para la seguridad si se concatena el texto no filtrado de un usuario.
statement
Un identificador de sentencia de OCI8 válido.
bv_name
El parámetro de sustitución de la variable vinculada prefijado por dos puntos (:) usado
en la sentencia. Los dos puntos son opcionales
en bv_name
. Oracle no usa los signos de interrogación
en los parámetros de sustitución.
variable
La variable de PHP que va a ser asociada con bv_name
maxlength
Establece la longitud máxima para los datos. Si se establece a -1, esta
función utilizará la longitud actual
de variable
para establecer la longitud
máxima. En este caso, el parámetro variable
debe
existir y contener datos cuando
se invoque a oci_bind_by_name().
type
El tipo de datos con el que Oracle trartará los datos. El tipo usado
predeterminado dado por type
es SQLT_CHR
. Oracle convertirá los datos
entre este tipo y la columna de la base de datos (o un tipo de variable de
PL/SQL), cuando sea posible.
Si fuera necesario vincular un tipo de datos abstractos (LOB/ROWID/BFILE),
debe asignarlo primero usando la función
oci_new_descriptor(). La longitud
length
no se usa para tipos de datos abstractos,
por lo que debería establecerse a -1.
Los valores posibles para type
son:
SQLT_BFILEE
or OCI_B_BFILE
- para BFILEs;
SQLT_CFILEE
o OCI_B_CFILEE
- para CFILEs;
SQLT_CLOB
o OCI_B_CLOB
- para CLOBs;
SQLT_BLOB
o OCI_B_BLOB
- para BLOBs;
SQLT_RDD
o OCI_B_ROWID
- para ROWIDs;
SQLT_NTY
o OCI_B_NTY
- para tipos de datos con nombre;
SQLT_INT
o OCI_B_INT
- para enteros;
SQLT_CHR
- para VARCHARs;
SQLT_BIN
o OCI_B_BIN
- para columnas RAW;
SQLT_LNG
- para columnas LONG;
SQLT_LBI
- para columnas LONG RAW;
SQLT_RSET
- para cursores creados
con oci_new_cursor();
SQLT_BOL
o OCI_B_BOL
- para BOOLEAN de PL/SQL (Requiere OCI8 2.0.7 y Oracle Database 12c)
Devuelve TRUE
en caso de éxito o FALSE
en caso de error.
Ejemplo #1 Insertar datos con oci_bind_by_name()
<?php
// Cree la tabla con:
// CREATE TABLE mytab (id NUMBER, text VARCHAR2(40));
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
$stid = oci_parse($conexión,"INSERT INTO mytab (id, text) VALUES(:id_bv, :text_bv)");
$id = 1;
$texto = "Datos a insertar ";
oci_bind_by_name($stid, ":id_bv", $id);
oci_bind_by_name($stid, ":text_bv", $texto);
oci_execute($stid);
// La tabla ahora contiene: 1, 'Datos a insertar '
?>
Ejemplo #2 Vincular una vez para múltiples ejecuciones
<?php
// Cree la tabla con:
// CREATE TABLE mytab (id NUMBER);
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
$a = array(1,3,5,7,11); // datos a insertar
$stid = oci_parse($conexión, 'INSERT INTO mytab (id) VALUES (:bv)');
oci_bind_by_name($stid, ':bv', $v, 20);
foreach ($a as $v) {
$r = oci_execute($stid, OCI_DEFAULT); // no autoconsigna
}
oci_commit($conexión); // consigna todo una vez
// La tabla contiene cinco filas: 1, 3, 5, 7, 11
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #3 Vinculación con un bucle foreach()
<?php
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$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($conexión, $sql);
$ba = array(':dname' => 'IT Support', ':loc' => 1700);
foreach ($ba as $clave => $valor) {
// oci_bind_by_name($stid, $clave, $valor) no funciona debido a
// que vincula cada parámetro de sustitución a la misma ubicación: $valor
// En su lugar, use la ubicación real de los datos: $ba[$clave]
oci_bind_by_name($stid, $clave, $ba[$clave]);
}
oci_execute($stid);
$fila = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);
foreach ($fila as $item) {
print $item."<br>\n";
}
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #4 Vinculación en una cláusula WHERE
<?php
$conexión = oci_connect("hr", "hrpwd", "localhost/XE");
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
$sql = 'SELECT last_name FROM employees WHERE employee_id = :eidbv';
$stid = oci_parse($conexión, $sql);
$myeid = 101;
oci_bind_by_name($stid, ':eidbv', $myeid);
oci_execute($stid);
$fila = oci_fetch_array($stid, OCI_ASSOC);
echo $fila['LAST_NAME'] ."<br>\n";
// La salida es
// Kochhar
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #5 Vinculación con una cláusula LIKE
<?php
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
// Busca todas las ciudades que empiecen por 'South'
$stid = oci_parse($conexión, "SELECT city FROM locations WHERE city LIKE :bv");
$ciudad = 'South%'; // '%' es un comodín en SQL
oci_bind_by_name($stid, ":bv", $ciudad);
oci_execute($stid);
oci_fetch_all($stid, $res);
foreach ($res['CITY'] as $c) {
print $c . "<br>\n";
}
// La salida es
// South Brunswick
// South San Francisco
// Southlake
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #6 Vinculación con REGEXP_LIKE
<?php
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
// Busca todas las ciudades que contengan 'ing'
$stid = oci_parse($conexión, "SELECT city FROM locations WHERE REGEXP_LIKE(city, :bv)");
$ciudad = '.*ing.*';
oci_bind_by_name($stid, ":bv", $ciudad);
oci_execute($stid);
oci_fetch_all($stid, $res);
foreach ($res['CITY'] as $c) {
print $c . "<br>\n";
}
// La salida es
// Beijing
// Singapore
oci_free_statement($stid);
oci_close($conexión);
?>
Para un número fijo pequeño de condiciones de la cláusula IN, use variables vinculadas individuales. Los valores desconocidos en tiempo de ejecución pueden ser establecidos a NULL. Esto permite que una única sentencia sea usada por todos los usuarios de una aplicación, maximizando la enficiencia de la caché de la base de datos de Oracle.
Ejemplo #7 Vinculación de múltiples valores en una cláusula IN
<?php
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$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($conexión, $sql);
$mye1 = 103;
$mye2 = 104;
$mye3 = NULL; // se pretende que no se proporcione este valor
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 $nombre) {
print $nombre ."<br>\n";
}
// La salida es
// Ernst
// Hunold
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #8 Vinculación de un ROWID devuelto por una consulta
<?php
// Cree la tabla con:
// CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
// INSERT INTO mytab (id, salary, name) VALUES (1, 100, 'Chris');
// COMMIT;
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$m = oci_error();
trigger_error(htmlentities($m['message']), E_USER_ERROR);
}
$stid = oci_parse($conexión, 'SELECT ROWID, name FROM mytab WHERE id = :id_bv FOR UPDATE');
$id = 1;
oci_bind_by_name($stid, ':id_bv', $id);
oci_execute($stid);
$fila = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS);
$rid = $fila['ROWID'];
$nombre = $fila['NAME'];
// Cambiar el nombre a mayúsculas y guardar los cambios
$nombre = strtoupper($nombre);
$stid = oci_parse($conexión, 'UPDATE mytab SET name = :n_bv WHERE ROWID = :r_bv');
oci_bind_by_name($stid, ':n_bv', $nombre);
oci_bind_by_name($stid, ':r_bv', $rid, -1, OCI_B_ROWID);
oci_execute($stid);
// La tabla contiene ahora 1, 100, CHRIS
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #9 Vinculación de un ROWID sobre INSERT
<?php
// Este ejemplo inserta un id y un nombre, y luego actualiza el salario
// Cree la tabla con:
// CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// Basado en el ejemplo original de ROWID de thies at thieso dot net (980221)
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$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($conexión, $sql);
$id_fila = oci_new_descriptor($conexión, OCI_D_ROWID);
oci_bind_by_name($ins_stid, ":id_bv", $id, 10);
oci_bind_by_name($ins_stid, ":name_bv", $nombre, 32);
oci_bind_by_name($ins_stid, ":rid", $id_fila, -1, OCI_B_ROWID);
$sql = "UPDATE mytab SET salary = :salary WHERE ROWID = :rid";
$upd_stid = oci_parse($conexión, $sql);
oci_bind_by_name($upd_stid, ":rid", $id_fila, -1, OCI_B_ROWID);
oci_bind_by_name($upd_stid, ":salary", $salario, 32);
// Los identificadores y los nombres a insertar
$datos = array(1111 => "Larry",
2222 => "Bill",
3333 => "Jim");
// El salario para cada persona
$salario = 10000;
// Insertar e inmediatamente actualizar cada fila
foreach ($datos as $id => $nombre) {
oci_execute($ins_stid);
oci_execute($upd_stid);
}
$id_fila->free();
oci_free_statement($upd_stid);
oci_free_statement($ins_stid);
// Mostrar las nuevas filas
$stid = oci_parse($conexión, "SELECT * FROM mytab");
oci_execute($stid);
while ($fila = oci_fetch_array($stid, OCI_ASSOC+OCI_RETURN_NULLS)) {
var_dump($fila);
}
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #10 Vinculación para una función almacenada de PL/SQL
<?php
// Antes de ejecutar este programa de PHP, cree una función almacenada en
// SQL*Plus o SQL Developer:
//
// CREATE OR REPLACE FUNCTION myfunc(p IN NUMBER) RETURN NUMBER AS
// BEGIN
// RETURN p * 3;
// END;
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}
$p = 8;
$stid = oci_parse($conexión, 'begin :r := myfunc(:p); end;');
oci_bind_by_name($stid, ':p', $p);
// El valor devuelto es un vínculo OUT. El tipo predeterminado será una cadena,
// por lo que vincular 40 significa que serán devueltos 40 dígitos
// como máximo.
oci_bind_by_name($stid, ':r', $r, 40);
oci_execute($stid);
print "$r\n"; // imprime 24
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #11 Vinculación de parámetros para un procedimiento almacenado de PL/SQL
<?php
// Antes de ejecutar este programa de PHP, cree un procedemiento almacenado en
// SQL*Plus o SQL Developer:
//
// CREATE OR REPLACE PROCEDURE myproc(p1 IN NUMBER, p2 OUT NUMBER) AS
// BEGIN
// p2 := p1 * 2;
// END;
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}
$p1 = 8;
$stid = oci_parse($conexión, 'begin myproc(:p1, :p2); end;');
oci_bind_by_name($stid, ':p1', $p1);
// El segundo parámetro del procedimiento es un vínculo OUT. El tipo predeterminado
// será una cadena, por lo que vincular 40 significa que serán devueltos 40 dígitos
// como máximo.
oci_bind_by_name($stid, ':p2', $p2, 40);
oci_execute($stid);
print "$p2\n"; // imprime 16
oci_free_statement($stid);
oci_close($conexión);
?>
Ejemplo #12 Vinculación de una columna CLOB
<?php
// Antes de ejecutarlo, cree la tabla:
// CREATE TABLE mytab (mykey NUMBER, myclob CLOB);
$conexión = oci_connect('hr', 'welcome', 'localhost/XE');
if (!$conexión) {
$e = oci_error();
trigger_error(htmlentities($e['message']), E_USER_ERROR);
}
$mykey = 12343; // clave arbitraria para este ejemplo;
$sql = "INSERT INTO mytab (mykey, myclob)
VALUES (:mykey, EMPTY_CLOB())
RETURNING myclob INTO :myclob";
$stid = oci_parse($conexión, $sql);
$clob = oci_new_descriptor($conexión, 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($conexión);
// Obtener los datos CLOB
$consulta = 'SELECT myclob FROM mytab WHERE mykey = :mykey';
$stid = oci_parse ($conexión, $consulta);
oci_bind_by_name($stid, ":mykey", $mykey, 5);
oci_execute($stid);
print '<table border="1">';
while ($fila = oci_fetch_array($stid, OCI_ASSOC)) {
$resultado = $fila['MYCLOB']->load();
print '<tr><td>'.$resultado.'</td></tr>';
}
print '</table>';
?>
Ejemplo #13 Vincular un BOOLEAN de 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
?>
Devuelve TRUE
en caso de éxito o FALSE
en caso de error.
No use magic_quotes_gpc o addslashes() y oci_bind_by_name() simultáneamente, ya que no es necesario el entrecomillado. Cualquier comilla aplicada mágicamente será escrita en la base de datos debido a que oci_bind_by_name() inserta los datos textualmente y no elimina las comillas o los caracteres de escape.
Nota:
Si vincula una cadena con una columna CHAR en una cláusula WHERE, recuerde que Oracle utiliza una semántica de comparación de relleno en blanco para columnas CHAR. La variable de PHP debería estar rellena con espacios en blanco a la misma longitud que la columna para que la cláusula WHERE tenga éxito.
Nota:
El argumento
variable
de PHP es una referencia. Algunas formas de bucles no funcionan como era de esperar:<?php
foreach ($array as $clave => $valor) {
oci_bind_by_name($stid, $clave, $valor);
}
?>Esto vincula cada clave a la ubicación de $valor, por lo que todas las variables vinculadas terminaran apuntando al valor de la última interación del bucle. En su lugar, se ha de utilizar lo siguiente:
<?php
foreach ($array as $clave => $valor) {
oci_bind_by_name($stid, $clave, $array[$clave]);
}
?>