Прикрепляет переменную PHP к соответствующей метке в SQL-выражении


(PHP 5, PECL OCI8 >= 1.1.0)

oci_bind_by_nameПрикрепляет переменную PHP к соответствующей метке в SQL-выражении

Описание

bool oci_bind_by_name ( resource $statement , string $bv_name , mixed &$variable [, int $maxlength = -1 [, int $type = SQLT_CHR ]] )

Прикрепляет переменную variable к метке bv_name. Такое прикрепеление позволяет повысить производительность и избежать SQL-инъекций.

Прикрепление переменной позволяет базе данных повторно использовать кэшированные контекстные выражения от предыдущих запросов, даже если они первоначально были запущены другим пользователем или процессом. Это также снижает риск SQL-инъекций, поскольку данные в таком случае никогда не рассматриваются как инструкции SQL. Данные не требуется экранировать или заключать в кавычки.

Прикрепленные PHP-переменные могут быть изменены и снова выполнены без необходимости повторной обработки запроса или повторного прикрепления.

В Oracle, прикрепление переменных обычно разделяют на IN (прикрепляет значения, передаваемые в базу данных) и OUT (прикрепляет значения, возвращаемые PHP). Переменная может быть одновременно IN и OUT. Независимо от этого, характер прикрепленния переменных будет определен во время выполнения.

Необходимо указать maxlength при использовании OUT-привязки, что позволяет PHP зарезервировать больше памяти для хранения возвращаемого значения

Для IN-привязки рекомендуется также указать параметр maxlength, если выражение выполняется несколько раз с раздичными значениями PHP-переменной. В противном случае, Oracle может урезать размер данных до размера первоначального значения переменной PHP. Если максимальная длина значения неизвестна, рекомендуется вызывать oci_bind_by_name() перед каждым вызовом oci_execute(). Прикрепление неоправданно большой переменной повлияет на процесс сохранения базы данных.

Вид прикрепления указывает Oracle как работать с памятью при чтении данных. Для IN-прикрепления адрес в памяти должен содержать допустимые данные при вызове oci_execute(). Это значит, что значение переменной должно находиться в памяти во время исполнения. Если это не так, возможны некорректные результаты или ошибки наподобие "ORA-01460: unimplemented or unreasonable conversion requested" (запрошены невыполнимые или некорректные преобразования) Для OUT-прикрепления основным признаком является установка значения в переменную PHP.

Для многократно выполняемого выражения, привязка одних и тех же значений может уменьшить возможности оптимизатора Oracle по выработке наилучшего варианта выполнения инструкции. Длительное прикрепление выражений, которые редко исполняются, может также не принести пользы. Тем не менее, в обоих случаях, прикрепление является более безопасным, чем конкатенация строки запроса и непроверенных пользовательских данных.

Список параметров

statement

Допустимый идентификатор выражения OCI8.

bv_name

Метка с префиксом в виде двоеточия, используемая в выражении. Двоеточие опционально в bv_name. Oracle не использует знак вопроса для меток.

variable

Переменная PHP, ассоциированная с bv_name

maxlength

Устанавливает максимальный размер данных. Если указать -1, функция будет использовать текущий размер переменной variable в качестве максимального. При этом переменная variable должна существовать и содержать данные во время вызова oci_bind_by_name().

type

Тип данных, к которому Oracle будет приводить значения. По умолчанию type имеет значение SQLT_CHR. Oracle приводит данные от данного типа к типу поля (или типу переменной PL/SQL), если это возможно.

Если необходимо прикрепить переменную абстрактного типа (LOB/ROWID/BFILE), следует предварительно использовать oci_new_descriptor(). Параметр length не используется для абстрактных типов и должен быть установлен в -1.

Допустимые значения параметра type:

  • SQLT_BFILEE или OCI_B_BFILE - для BFILE-объектов;

  • SQLT_CFILEE или OCI_B_CFILEE - для CFILE-объектов;

  • SQLT_CLOB или OCI_B_CLOB - для CLOB-объектов;

  • SQLT_BLOB или OCI_B_BLOB - для BLOB-объектов;

  • SQLT_RDD или OCI_B_ROWID - для ROWID-объектов;

  • SQLT_NTY или OCI_B_NTY - для именованных типов даты;

  • SQLT_INT или OCI_B_INT - для целых чисел;

  • SQLT_CHR - для символов VARCHAR;

  • SQLT_BIN или OCI_B_BIN - для RAW-полей;

  • SQLT_LNG - для LONG-полей;

  • SQLT_LBI - для LONG RAW полей;

  • SQLT_RSET - для курсоров, созданных функцией oci_new_cursor();

  • SQLT_BOL или OCI_B_BOL - для PL/SQL BOOLEAN (Требуется OCI8 2.0.7 и Oracle Database 12c)

Возвращаемые значения

Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.

Примеры

Пример #1 Добавление данных с использованием oci_bind_by_name()

<?php

// Создание таблицы:
//   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 "Data to insert     ";
oci_bind_by_name($stid":id_bv"$id);
oci_bind_by_name($stid":text_bv"$text);
oci_execute($stid);

// В таблице содержится: 1, 'Data to insert     '

?>

Пример #2 Одна привязка для многократного использования

<?php

// Создание таблицы:
//   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);  // данные для вставки

$stid oci_parse($conn'INSERT INTO mytab (id) VALUES (:bv)');
oci_bind_by_name($stid':bv'$v20);
foreach (
$a as $v) {
    
$r oci_execute($stidOCI_DEFAULT);  // не использовать автоматическое завершение транзакции
}
oci_commit($conn); // завершение транзакции

// Таблица содержит пять записей: 1, 3, 5, 7, 11

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

?>

Пример #3 Прикрепление в цикле 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) не работает,
    // потому что прикрепляет каждое значение в одно место: $val
    // Вместо этого следует указывать конкретное место: $ba[$key]
    
oci_bind_by_name($stid$key$ba[$key]);
}

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

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

?>

Пример #4 Прикрепление в выражение 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($stidOCI_ASSOC)) != false) {
    echo 
$row['LAST_NAME'] ."<br>\n";
}

// Выводом будет
//    Austin
//    Ernst
//    Hunold
//    Lorentz
//    Pataballa

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

?>

Пример #5 Прикрепление в выражение LIKE

<?php

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

// Поиск всех городов, начинающихся на 'South'
$stid oci_parse($conn"SELECT city FROM locations WHERE city LIKE :bv");
$city 'South%';  // '%' - это знак шаблона 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";
}
// Выводом будет:
//   South Brunswick
//   South San Francisco
//   Southlake

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

?>

Пример #6 Прикрепление в выражение REGEXP_LIKE

<?php

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

// Поиск названий городов, содержащих '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";
}
// Выводом будет:
//   Beijing
//   Singapore

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

?>

Для небольшого, фиксированного количества условий в выражении IN, используются индивидуальные имена переменных. Неизвестные значения при исполнении могут быть установлены в NULL. Это позволяет использовать одно выражение нескольким пользователям, что повышает эффективность кэширования Oracle DB.

Пример #7 Прикрепление нескольких значений в выржаение 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// притворимся, что не получили это значение
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";
}

// Выводом будет:
//   Ernst
//   Hunold

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

?>

Пример #8 Прикрепеление ROWID, возвращаемое запросом

<?php

// Создадим и наполним таблицу:
//   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($stidOCI_ASSOC+OCI_RETURN_NULLS);
$rid $row['ROWID'];
$name $row['NAME'];

// Переведем имя в верхний регистр и зафиксируем изменения
$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, -1OCI_B_ROWID);
oci_execute($stid);

// Теперь таблица содержит: 1, 100, CHRIS

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

?>

Пример #9 OUT-прикрепление ROWID, возвращаемое при INSERT

<?php

// В данном примере добавляется запись с идентификатором и именем,
// после чего увеличивается заработная плата
// Создание таблицы:
//   CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// На основе собственных ROWID на примере thies[at]thieso.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($connOCI_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, -1OCI_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, -1OCI_B_ROWID);
oci_bind_by_name($upd_stid":salary"$salary,   32);

// идентификаторы и имена для вставки
$data = array(1111 => "Larry",
              
2222 => "Bill",
              
3333 => "Jim");

// Заработная плата для каждого сотрудника
$salary 10000;

// Вставка и немедленное обновление каждой строки
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);

// Показать новые записи
$stid oci_parse($conn"SELECT * FROM mytab");
oci_execute($stid);
while (
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_NULLS)) {
    
var_dump($row);
}

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

?>

Пример #10 Прикрепление для хранимой функции PL/SQL

<?php

//  Перед запуском PHP-сценария, создайте хранимую функцию в
//  SQL*Plus или 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);

// Возвращаемое значение OUT-прикреплено. По умолчаннию типом данных будет строка.
// Прикрепление со значением 40 означает, что будет возвращено 40 символов.
oci_bind_by_name($stid':r'$r40);

oci_execute($stid);

print 
"$r\n";   // выведет 24

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

?>

Пример #11 Прикрепление параметров для PL/SQL хранимой процедуры

<?php

//  Перед запуском PHP-сценария, создайте хранимую процедуру в
//  SQL*Plus или 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);

// Второй параметр процедуры OUT-прикреплен. По умолчаннию типом данных будет строка.
// Прикрепление со значением 40 означает, что будет возвращено 40 символов.
oci_bind_by_name($stid':p2'$p240);

oci_execute($stid);

print 
"$p2\n";   // выведет 16

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

?>

Пример #12 Прикрепление CLOB-объекта

<?php

// Перед запуском создаем таблицу:
//     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;  // произвольный ключ для примера

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

$stid oci_parse($conn$sql);
$clob oci_new_descriptor($connOCI_D_LOB);
oci_bind_by_name($stid":mykey"$mykey5);
oci_bind_by_name($stid":myclob"$clob, -1OCI_B_CLOB);
oci_execute($stidOCI_DEFAULT);
$clob->save("A very long string");

oci_commit($conn);

// Получение CLOB-данных

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

$stid oci_parse ($conn$query);
oci_bind_by_name($stid":mykey"$mykey5);
oci_execute($stid);

print 
'<table border="1">';
while (
$row oci_fetch_array($stidOCI_ASSOC+OCI_RETURN_LOBS)) {
    print 
'<tr><td>'.$row['MYCLOB'].'</td></tr>';
    
// В цикле, очищение больших переменных перед повторным получением данных, уменьшает пиковое потребление памяти PHP
    
unset($row);  
}
print 
'</table>';

?>

Пример #13 Прикрепление PL/SQL BOOLEAN

<?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, -1OCI_B_BOL);
oci_bind_by_name($s':output2'$output2, -1OCI_B_BOL);
oci_execute($s);
var_dump($output1);  // true
var_dump($output2);  // false

?>

Возвращаемые значения

Возвращает TRUE в случае успешного завершения или FALSE в случае возникновения ошибки.

Примечания

Внимание

Не используйте magic_quotes_gpc или addslashes() одновременно с oci_bind_by_name(), так как кавычек быть не должно. Все указанные кавычки будут записаны в базу данных, потому что oci_bind_by_name() вставляет данные дословно и не удаляет кавычки или символы экранирования.

Замечание:

Если прикрепляется строка к CHAR-полю в выражении WHERE, помните, что Oracle использует при сравнении значения CHAR, дополненные пробелами. Переменная PHP должна быть дополнена пробелами до того же размера, что и поле, чтобы выражение WHERE выполнялось верно.

Замечание:

Переменная PHP variable является ссылкой. Некоторые виды циклов могут работать не так, как ожидается:

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

В этом случае каждый ключ прикрепляется к $value, поэтому все прикрепленные переменные указывают на значение в последней итерации цикла. Вместо этого следует использовать:

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

Смотрите также

  • oci_bind_array_by_name() - Связывает PHP массив с массивом Oracle PL/SQL
  • oci_parse() - Подготавливает запрос к выполнению