oci_bind_by_name
(PHP 5, PHP 7, PHP 8, PECL OCI8 >= 1.1.0)
oci_bind_by_name — PHP 변수를 Oracle 자리 표시자에 바인딩
설명
oci_bind_by_name( resource $statement, string $param, mixed &$var, int $max_length = -1, int $type = 0 ): bool
PHP 변수 var
를 Oracle bind 변수 자리 표시자 param
에 바인딩합니다. 바인딩은 Oracle 데이터베이스 성능에 중요하며 SQL 주입 보안 문제를 피하기 위한 방법이기도 합니다.
바인딩을 사용하면 다른 사용자나 프로세스가 원래 실행한 경우에도 데이터베이스에서 명령문 컨텍스트와 이전 명령문의 캐시를 재사용할 수 있습니다. 바인딩은 바인드 변수와 연결된 데이터가 SQL 문의 일부로 처리되지 않기 때문에 SQL 주입 문제를 줄입니다. 인용이나 이스케이프가 필요하지 않습니다.
바인딩된 PHP 변수는 명령문을 다시 구문 분석하거나 다시 바인딩할 필요 없이 변경되고 명령문이 다시 실행될 수 있습니다.
Oracle에서 바인드 변수는 일반적으로 데이터베이스로 전달되는 값에 대한 IN 바인드와 PHP로 반환되는 값에 대한 OUT 바인드로 나뉩니다. 바인드 변수는 IN과 OUT 모두일 수 있습니다. 바인드 변수가 입력 또는 출력에 사용되는지 여부는 런타임에 결정됩니다.
PHP가 반환된 값을 보유하기에 충분한 메모리를 할당하도록 OUT 바인드를 사용할 때 max_length
를 지정해야 합니다.
IN 바인드의 경우 문이 PHP 변수에 대해 다른 값으로 여러 번 재실행되는 경우 max_length
길이를 설정하는 것이 좋습니다. 그렇지 않으면 Oracle은 초기 PHP 변수 값의 길이로 데이터를 자를 수 있습니다. 최대 길이가 무엇인지 모르는 경우 각 oci_execute() 호출 전에 현재 데이터 크기로 oci_bind_by_name()을 다시 호출하십시오. 불필요하게 긴 길이를 바인딩하면 데이터베이스의 프로세스 메모리에 영향을 미칩니다.
바인드 호출은 데이터를 읽을 메모리 주소를 Oracle에 알려줍니다. IN 바인드의 경우 해당 주소는 oci_execute()가 호출될 때 유효한 데이터를 포함해야 합니다. 이는 바인딩된 변수가 실행될 때까지 범위에 남아 있어야 함을 의미합니다. 그렇지 않은 경우 "ORA-01460: 구현되지 않았거나 부당한 변환 요청됨"과 같은 예기치 않은 결과 또는 오류가 발생할 수 있습니다. OUT 바인드의 경우 한 가지 증상은 PHP 변수에 값이 설정되지 않는다는 것입니다.
반복적으로 실행되는 명령문의 경우 변경되지 않는 바인딩 값은 Oracle 최적화 프로그램이 최상의 명령문 실행 계획을 선택하는 기능을 감소시킬 수 있습니다. 거의 다시 실행되지 않는 장기 실행 문은 바인딩의 이점을 얻지 못할 수 있습니다. 그러나 두 경우 모두 바인딩이 문자열을 SQL 문에 결합하는 것보다 안전할 수 있습니다. 필터링되지 않은 사용자 텍스트가 연결된 경우 보안 위험이 될 수 있기 때문입니다.
매개변수
statement
- 유효한 OCI 문 식별자입니다.
param
- 명령문에 사용된 콜론 접두사가 붙은 바인드 변수 자리 표시자입니다. 콜론은
param
에서 선택 사항입니다. Oracle은 자리 표시자에 물음표를 사용하지 않습니다. var
param
과 연결할 PHP 변수max_length
- 데이터의 최대 길이를 설정합니다. -1로 설정하면 이 함수는
var
의 현재 길이를 사용하여 최대 길이를 설정합니다. 이 경우var
는 반드시 존재해야 하며 oci_bind_by_name()이 호출될 때 데이터를 포함해야 합니다. type
- Oracle이 데이터를 처리할 데이터 유형입니다. 사용되는 기본
type
은SQLT_CHR
입니다. Oracle은 가능한 경우 이 유형과 데이터베이스 열(또는 PL/SQL 변수 유형) 간에 데이터를 변환합니다.추상 데이터 유형(LOB/ROWID/BFILE)을 바인딩해야 하는 경우 먼저 oci_new_descriptor() 함수를 사용하여 할당해야 합니다.
length
는 추상 데이터 유형에 사용되지 않으며 -1로 설정해야 합니다.type
에 가능한 값은 다음과 같습니다.-
SQLT_BFILEE or OCI_B_BFILE
- BFILE의 경우; -
SQLT_CFILEE or OCI_B_CFILEE
- CFILE의 경우; -
SQLT_CLOB or OCI_B_CLOB
- CLOB의 경우 -
SQLT_BLOB or OCI_B_BLOB
- BLOB의 경우 -
SQLT_RDD or OCI_B_ROWID
- ROWID의 경우 -
SQLT_NTY or OCI_B_NTY
- 명명된 데이터 유형의 경우 -
SQLT_INT or OCI_B_INT
- 정수의 경우 -
SQLT_CHR
- VARCHAR의 경우 -
SQLT_BIN or OCI_B_BIN
- RAW 열의 경우; -
SQLT_LNG
- LONG 열의 경우; -
SQLT_LBI
- LONG RAW 열의 경우; -
SQLT_RSET
- oci_new_cursor()로 생성된 커서의 경우; -
SQLT_BOL or OCI_B_BOL
- PL/SQL BOOLEAN용(OCI8 2.0.7 및 Oracle Database 12c 필요)
-
반환 값
성공하면 true
를, 실패하면 false
를 반환합니다.
Examples
예제 #1 oci_bind_by_name()으로 데이터 삽입하기
<?php
// Create the table with:
// 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);
// Table now contains: 1, 'Data to insert '
?>
예제 #2 여러 실행에 대해 한 번 바인딩
<?php
// Create the table with:
// 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); // data to insert
$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); // don't auto commit
}
oci_commit($conn); // commit everything at once
// Table contains five rows: 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) does not work
// because it binds each placeholder to the same location: $val
// instead use the actual location of the data: $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);
?>
예제 #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($stid, OCI_ASSOC)) != false) {
echo $row['LAST_NAME'] ."<br>\n";
}
// Output is
// 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);
}
// Find all cities that begin with 'South'
$stid = oci_parse($conn, "SELECT city FROM locations WHERE city LIKE :bv");
$city = 'South%'; // '%' is a wildcard 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";
}
// Output is
// 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);
}
// Find all cities that contain '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";
}
// Output is
// 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; // pretend we were not given this value
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";
}
// Output is
// Ernst
// Hunold
oci_free_statement($stid);
oci_close($conn);
?>
예제 #8 쿼리에서 반환된 ROWID 바인딩
<?php
// Create the table with:
// 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'];
// Change name to upper case & save the changes
$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);
// The table now contains 1, 100, CHRIS
oci_free_statement($stid);
oci_close($conn);
?>
예제 #9 INSERT에서 ROWID 바인딩
<?php
// This example inserts an id & name, and then updates the salary
// Create the table with:
// CREATE TABLE mytab (id NUMBER, salary NUMBER, name VARCHAR2(40));
//
// Based on original ROWID example by 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);
// ids and names to insert
$data = array(1111 => "Larry",
2222 => "Bill",
3333 => "Jim");
// Salary of each person
$salary = 10000;
// Insert and immediately update each row
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);
// Show the new rows
$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);
?>
예제 #10 PL/SQL 저장 함수에 대한 바인딩
<?php
// Before running the PHP program, create a stored function in
// SQL*Plus or 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);
// The return value is an OUT bind. The default type will be a string
// type so binding a length 40 means that at most 40 digits will be
// returned.
oci_bind_by_name($stid, ':r', $r, 40);
oci_execute($stid);
print "$r\n"; // prints 24
oci_free_statement($stid);
oci_close($conn);
?>
예제 #11 PL/SQL 저장 프로시저에 대한 바인딩 매개변수
<?php
// Before running the PHP program, create a 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);
// The second procedure parameter is an OUT bind. The default type
// will be a string type so binding a length 40 means that at most 40
// digits will be returned.
oci_bind_by_name($stid, ':p2', $p2, 40);
oci_execute($stid);
print "$p2\n"; // prints 16
oci_free_statement($stid);
oci_close($conn);
?>
예제 #12 CLOB 열 바인딩
<?php
// Before running, create the table:
// 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; // arbitrary key for this example;
$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);
// Fetching CLOB data
$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 a loop, freeing the large variable before the 2nd fetch reduces PHP's peak memory usage
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, -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
?>
노트
경고 따옴표가 필요하지 않으므로 addlashes() 및 oci_bind_by_name()을 동시에 사용하지 마십시오. oci_bind_by_name()이 데이터를 그대로 삽입하고 따옴표나 이스케이프 문자를 제거하지 않기 때문에 마법처럼 적용된 따옴표는 데이터베이스에 기록됩니다.
메모: WHERE 절의 CHAR 열에 문자열을 바인딩하는 경우 Oracle은 CHAR 열에 대해 공백으로 채워진 비교 의미 체계를 사용한다는 점을 기억하십시오. WHERE 절이 성공하려면 PHP 변수를 열과 같은 너비로 공백으로 채워야 합니다.
메모:
PHP var
인수는 참조입니다. 일부 형태의 루프가 예상대로 작동하지 않습니다.
<?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() - 실행을 위해 Oracle 문을 준비합니다.