PHP
PHP MySQLi
수색…
소개
mysqli
인터페이스 는 버전 5.5에서 사용되지 않으며 버전 7.0에서 제거 된 mysql
인터페이스의 향상된 기능 ( "MySQL 개선 확장 기능"을 의미 함)입니다. MySQL 확장 버전 인 mysqli 확장은 MySQL 시스템 버전 4.1.3 이후의 새로운 기능을 활용하기 위해 개발되었습니다. mysqli 확장은 PHP 버전 5 이상에 포함되어 있습니다.
비고
풍모
mysqli 인터페이스에는 다음과 같은 몇 가지 이점이 있습니다.
- 객체 지향 인터페이스
- Prepared Statements 지원
- 다중 명령문 지원
- 트랜잭션 지원
- 향상된 디버깅 기능
- 임베디드 서버 지원
듀얼 인터페이스를 특징으로합니다 : 구식의 절차 적 스타일과 새로운 객체 지향 프로그래밍 (OOP) 스타일. 더 이상 사용되지 않는 mysql
은 프로 시저 인터페이스 만 가지고 있으므로 객체 지향 스타일이 선호되는 경우가 많다. 그러나 새로운 스타일은 OOP의 힘 때문에 또한 유리합니다.
대안
데이터베이스에 접근하기위한 mysqli
인터페이스의 대안은 더 새로운 PHP 데이터 객체 (PDO) 인터페이스이다. 이것은 OOP 스타일 프로그래밍 만 제공하며 MySQL 유형의 데이터베이스 이상을 액세스 할 수 있습니다.
MySQLi 연결
객체 지향 스타일
서버에 연결
$conn = new mysqli("localhost","my_user","my_password");
기본 데이터베이스를 설정합니다 : $conn->select_db("my_db");
데이터베이스에 연결
$conn = new mysqli("localhost","my_user","my_password","my_db");
절차 스타일
서버에 연결
$conn = mysqli_connect("localhost","my_user","my_password");
기본 데이터베이스를 설정합니다 : mysqli_select_db($conn, "my_db");
데이터베이스에 연결
$conn = mysqli_connect("localhost","my_user","my_password","my_db");
데이터베이스 연결 확인
객체 지향 스타일
if ($conn->connect_errno > 0) {
trigger_error($db->connect_error);
} // else: successfully connected
절차 스타일
if (!$conn) {
trigger_error(mysqli_connect_error());
} // else: successfully connected
MySQLi 쿼리
query
함수는 유효한 SQL 문자열을 가져 와서 데이터베이스 연결 $conn
에 대해 직접 실행합니다.
객체 지향 스타일
$result = $conn->query("SELECT * FROM `people`");
절차 스타일
$result = mysqli_query($conn, "SELECT * FROM `people`");
주의
여기서 일반적인 문제는 사람들이 쿼리를 실행하고 쿼리가 작동 할 것으로 기대한다는 것입니다 (즉, mysqli_stmt 객체를 반환). 이 함수는 문자열 만 취하므로 먼저 쿼리를 직접 작성해야합니다. SQL에 실수가 있다면, MySQL 컴파일러는 실패 할 것이다 . 이 시점에서이 함수는 false
를 리턴 할 것이다 .
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
$row = $result->fetch_assoc();
위의 코드는 $result
가 false
가 아니고 객체가 아니기 때문에 E_FATAL
오류를 생성합니다.
PHP 치명적인 오류 : 비 객체의 fetch_assoc () 멤버 함수 호출
절차상의 오류는 비슷하지만 치명적이지는 않습니다. 왜냐하면 우리는 단지 그 기능의 기대에 위배되기 때문입니다.
$row = mysqli_fetch_assoc($result); // same query as previous
PHP에서 다음 메시지가 표시됩니다.
mysqli_fetch_array ()는 매개 변수 1이 mysqli_result가 될 것으로 예상하고, 부울은 주어진다.
테스트를 먼저하면이 문제를 피할 수 있습니다.
if($result) $row = mysqli_fetch_assoc($result);
MySQLi 결과 루프
PHP는 결과에서 데이터를 얻고 while
문을 사용하여 쉽게 반복 할 수있게합니다. 다음 행을 얻지 못하면 false
반환하고 루프가 끝납니다. 이 예제는
- mysqli_fetch_assoc - 열 이름을 키로하는 연관 배열
- mysqli_fetch_object - 열 이름을 변수로 가지는
stdClass
객체 - mysqli_fetch_array - 연관 AND 숫자 배열 (하나 또는 다른 인수를 얻기 위해 인수를 사용할 수 있음)
- mysqli_fetch_row - 수치 배열
객체 지향 스타일
while($row = $result->fetch_assoc()) {
var_dump($row);
}
절차 스타일
while($row = mysqli_fetch_assoc($result)) {
var_dump($row);
}
결과에서 정확한 정보를 얻으려면 다음을 사용할 수 있습니다.
while ($row = $result->fetch_assoc()) {
echo 'Name and surname: '.$row['name'].' '.$row['surname'].'<br>';
echo 'Age: '.$row['age'].'<br>'; // Prints info from 'age' column
}
연결 닫기
데이터베이스 쿼리를 완료하면 리소스를 확보하기 위해 연결을 닫는 것이 좋습니다.
객체 지향 스타일
$conn->close();
절차 스타일
mysqli_close($conn);
참고 : 서버에 대한 연결은 닫기 연결 함수를 명시 적으로 호출하여 이전에 닫히지 않는 한 스크립트 실행이 끝나는 즉시 닫힙니다.
사용 사례 : 결과를 가져온 후 스크립트가 상당한 처리량을 수행하고 전체 결과 집합을 검색 한 경우 확실히 연결을 닫아야합니다. 그렇게하지 않으면 웹 서버가 과도하게 사용되는 경우 MySQL 서버가 연결 제한에 도달 할 가능성이 있습니다.
MySQLi에서 준비된 문
준비된 문이 SQL 주입 공격으로부터 SQL 문을 보호하는 데 도움이되는 이유에 대한 전체 설명은 매개 변수가있는 쿼리 로 SQL 주입 방지를 참조하십시오.
여기서 $conn
변수는 MySQLi 객체입니다. 자세한 내용은 MySQLi connect 예제 를 참조하십시오.
두 예제 모두 $sql
이
$sql = "SELECT column_1
FROM table
WHERE column_2 = ?
AND column_3 > ?";
?
나중에 제공 할 값을 나타냅니다. 유형에 관계없이 자리 표시 자에 대한 따옴표가 필요하지 않습니다. 또한 쿼리의 데이터 부분에 SET
, VALUES
및 WHERE
라는 의미의 자리 표시 자만 제공 할 수 있습니다. SELECT
또는 FROM
부분에는 자리 표시자를 사용할 수 없습니다.
객체 지향 스타일
if ($stmt = $conn->prepare($sql)) {
$stmt->bind_param("si", $column_2_value, $column_3_value);
$stmt->execute();
$stmt->bind_result($column_1);
$stmt->fetch();
//Now use variable $column_1 one as if it were any other PHP variable
$stmt->close();
}
절차 스타일
if ($stmt = mysqli_prepare($conn, $sql)) {
mysqli_stmt_bind_param($stmt, "si", $column_2_value, $column_3_value);
mysqli_stmt_execute($stmt);
// Fetch data here
mysqli_stmt_close($stmt);
}
$stmt->bind_param
의 첫 번째 매개 변수 또는 mysqli_stmt_bind_param
의 두 번째 매개 변수는 SQL 쿼리에서 해당 매개 변수의 데이터 유형에 의해 결정됩니다.
매개 변수 | 바인딩 된 매개 변수의 데이터 형식 |
---|---|
i | 정수 |
d | 더블 |
s | 끈 |
b | 얼룩 |
귀하의 매개 변수 목록은 귀하의 질의에 제공된 순서대로 이루어져야합니다. 이 예제에서 si
는 첫 번째 매개 변수 ( column_2 = ?
) 가 string이고 두 번째 매개 변수 ( column_3 > ?
) 가 정수임을 의미합니다.
데이터를 가져 오는 방법은 준비된 문에서 데이터를 가져 오는 방법을 참조하십시오 .
이스케이프 문자열
이스케이프 문자열은 쿼리에 삽입하기 위해 데이터를 보호하는 이전 방법 ( 덜 안전합니다 )입니다. MySQL의 mysql_real_escape_string () 함수 를 사용하여 데이터를 처리하고 위생적으로 처리합니다 (즉, PHP는 이스케이프 처리를하지 않습니다). MySQLi API는이 함수에 대한 직접 접근을 제공한다.
$escaped = $conn->real_escape_string($_GET['var']);
// OR
$escaped = mysqli_real_escape_string($conn, $_GET['var']);
이 시점에서 MySQL은 직접 쿼리에서 사용하는 것이 안전하다고 생각하는 문자열을 가지고 있습니다
$sql = 'SELECT * FROM users WHERE username = "' . $escaped . '"';
$result = $conn->query($sql);
그렇다면 이것은 왜 준비된 진술 처럼 안전하지 못합니까? 안전하다고 생각되는 문자열을 생성하기 위해 MySQL을 속이는 방법이 있습니다. 다음 예제를 고려해보십시오.
$id = mysqli_real_escape_string("1 OR 1=1");
$sql = 'SELECT * FROM table WHERE id = ' . $id;
1 OR 1=1
은 MySQL이 이스케이프 할 데이터를 나타내지 않지만 여전히 SQL 주입을 나타냅니다. 안전하지 않은 데이터를 반환하는 장소를 나타내는 다른 예도 있습니다. 문제는 MySQL의 탈출 함수가 데이터가 SQL 구문을 준수 하도록 설계 되었기 때문 입니다. MySQL이 SQL 명령어에 대한 사용자 데이터를 혼동하지 않도록하기위한 것이 아닙니다 .
MySQLi 삽입 ID
AUTO_INCREMENT 컬럼이있는 테이블에서 INSERT
쿼리에 의해 생성 된 마지막 ID를 검색하십시오.
객체 지향 스타일
$id = $conn->insert_id;
절차 스타일
$id = mysqli_insert_id($conn);
연결에 이전 쿼리가 없거나 쿼리가 AUTO_INCREMENT 값을 업데이트하지 않은 경우 0을 반환합니다.
행을 업데이트 할 때 ID 삽입
일반적으로 AUTO_INCREMENT
id는 새로운 행이 저장 (또는 삽입)되었을 때만 반환되므로 UPDATE
문은 삽입 ID를 반환하지 않습니다. 새 ID를 업데이트하는 한 가지 방법은 INSERT ... ON DUPLICATE KEY UPDATE
구문을 사용하여 업데이트하는 것입니다.
수행 할 예제 설정 :
CREATE TABLE iodku (
id INT AUTO_INCREMENT NOT NULL,
name VARCHAR(99) NOT NULL,
misc INT NOT NULL,
PRIMARY KEY(id),
UNIQUE(name)
) ENGINE=InnoDB;
INSERT INTO iodku (name, misc)
VALUES
('Leslie', 123),
('Sally', 456);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 456 |
+----+--------+------+
IODKU가 관련 id
검색하는 "업데이트"및 LAST_INSERT_ID()
를 수행하는 경우 :
$sql = "INSERT INTO iodku (name, misc)
VALUES
('Sally', 3333) -- should update
ON DUPLICATE KEY UPDATE -- `name` will trigger "duplicate key"
id = LAST_INSERT_ID(id),
misc = VALUES(misc)";
$conn->query($sql);
$id = $conn->insert_id; -- picking up existing value (2)
IODKU가 "삽입"을 수행하고 LAST_INSERT_ID()
가 새 id
검색하는 경우 :
$sql = "INSERT INTO iodku (name, misc)
VALUES
('Dana', 789) -- Should insert
ON DUPLICATE KEY UPDATE
id = LAST_INSERT_ID(id),
misc = VALUES(misc);
$conn->query($sql);
$id = $conn->insert_id; -- picking up new value (3)
결과 테이블 내용 :
SELECT * FROM iodku;
+----+--------+------+
| id | name | misc |
+----+--------+------+
| 1 | Leslie | 123 |
| 2 | Sally | 3333 | -- IODKU changed this
| 3 | Dana | 789 | -- IODKU added this
+----+--------+------+
MySQLi에서 SQL 디버깅하기
따라서 쿼리가 실패했습니다 ( MySQLi 가 $conn
를 생성하는 방법을 참조하십시오)
$result = $conn->query('SELECT * FROM non_existent_table'); // This query will fail
무슨 일이 있었는지 어떻게 알 수 있습니까? $result
는 false
이므로 도움이되지 않습니다. 고맙게도 connect $conn
은 MySQL이 실패에 대해 우리에게 말한 것을 말해 줄 수 있습니다.
trigger_error($conn->error);
또는 절차 적
trigger_error(mysqli_error($conn));
비슷한 오류가 발생해야합니다.
테이블 'my_db.non_existent_table'이 존재하지 않습니다.
준비된 진술에서 데이터를 얻는 방법
준비된 진술
쿼리 준비 및 실행 방법 은 MySQLi의 Prepared statements를 참조하십시오.
결과 묶기
객체 지향 스타일
$stmt->bind_result($forename);
절차 스타일
mysqli_stmt_bind_result($stmt, $forename);
bind_result
를 사용할 bind_result
의 문제점은 사용할 컬럼을 지정하는 명령문이 필요하다는 것입니다. 즉 위의 쿼리를 실행하려면 SELECT forename FROM users
와 같이 보일 것입니다. 더 많은 열을 포함 시키려면 매개 변수로 bind_result
함수에 추가하십시오 (SQL 질의에 추가해야합니다).
두 경우 모두 forename
열을 $forename
변수에 할당합니다. 이 함수는 할당하려는 열만큼의 인수를 사용합니다. 함수는 참조에 의해 바인딩되므로 할당은 한 번만 수행됩니다.
그러면 다음과 같이 반복 할 수 있습니다.
객체 지향 스타일
while ($stmt->fetch())
echo "$forename<br />";
절차 스타일
while (mysqli_stmt_fetch($stmt))
echo "$forename<br />";
단점은 한 번에 많은 변수를 할당해야한다는 것입니다. 이것은 큰 쿼리를 추적하는 것을 어렵게 만듭니다. MySQL 네이티브 드라이버 ( mysqlnd
)를 설치 했다면 get_result 만 사용 하면 됩니다.
객체 지향 스타일
$result = $stmt->get_result();
절차 스타일
$result = mysqli_stmt_get_result($stmt);
mysqli_result 객체를 얻었 기 때문에 작업하기가 훨씬 쉽다. 이것은 mysqli_query가 반환 하는 것과 같은 객체이다. 즉, 정기적 인 결과 루프 를 사용하여 데이터를 얻을 수 있습니다.
mysqlnd
설치할 수 mysqlnd
어떻게 mysqlnd
?
그렇다면 @Sophivorus 가이 놀라운 대답으로 덮여 있습니다.
이 함수는 서버에 설치하지 않고 get_result
태스크를 수행 할 수 있습니다. 단순히 결과를 반복하고 결합 배열을 만듭니다.
function get_result(\mysqli_stmt $statement)
{
$result = array();
$statement->store_result();
for ($i = 0; $i < $statement->num_rows; $i++)
{
$metadata = $statement->result_metadata();
$params = array();
while ($field = $metadata->fetch_field())
{
$params[] = &$result[$i][$field->name];
}
call_user_func_array(array($statement, 'bind_result'), $params);
$statement->fetch();
}
return $result;
}
그런 다음 mysqli_fetch_assoc()
을 사용하는 것처럼 함수를 사용하여 이와 같은 결과를 얻을 수있다.
<?php
$query = $mysqli->prepare("SELECT * FROM users WHERE forename LIKE ?");
$condition = "J%";
$query->bind_param("s", $condition);
$query->execute();
$result = get_result($query);
while ($row = array_shift($result)) {
echo $row["id"] . ' - ' . $row["forename"] . ' ' . $row["surname"] . '<br>';
}
mysqlnd
드라이버를 사용하는 것과 동일한 출력을 mysqlnd
설치하지 않아도됩니다. 이 드라이버는 시스템에 드라이버를 설치할 수없는 경우 매우 유용합니다. 이 솔루션을 구현하십시오.