1. PHP의 데이터베이스 연동 방식
PHP에서 데이터베이스(DBMS)에 접속하기 위해 사용하는 함수군은 크게 세 가지로 발전해 왔다.
1️⃣ mysql_???() 함수 (구형 방식)
과거에 사용되던 방식으로, 현재는 보안과 성능 문제로 인해 PHP 7.0 이상부터는 완전히 삭제되었다.
- mysql_connect(): DBMS 접속
- mysql_query(): 쿼리 실행
- mysql_num_rows(): 결과 행의 개수 확인
2️⃣ mysqli_???() 함수 (개선된 방식)
MySQL Improved의 약자로, MySQL 4.1.13 이상의 기능을 지원하기 위해 만들어졌다.
객체지향 방식과 절차지향 방식을 모두 지원한다.
- 객체지향 스타일: $mysqli = new mysqli(...) 형태로 사용.
- 절차지향 스타일: mysqli_connect(...) 형태로 사용하며, 기존 mysql 함수와 구조가 유사하여 전환이 쉽다.
3️⃣ PDO (PHP Data Objects)
여러 종류의 데이터베이스(MySQL, PostgreSQL, Oracle 등)를 동일한 인터페이스로 다룰 수 있게 해주는 추상화 레이어다.
보안상 가장 권장되며, 특히 'Prepared Statement'를 통한 SQL 인젝션 방어에 탁월하다.
2. MariaDB 접속을 위한 함수
이번 실습에서는 mysqli의 절차지향 방식을 사용하여 접속 프로세스를 익힌다.
1️⃣ mysqli_connect 함수의 구조
PHP 내부에서 정의된 함수의 원형은 다음과 같다.
mysqli_connect(
?string $hostname = null,
?string $username = null,
#[\SensitiveParameter] ?string $password = null,
?string $database = null,
?int $port = null,
?string $socket = null
): mysqli|false
- ?string: 해당 인자값은 문자열(string)이거나 null일 수 있음을 의미한다.
- #[\SensitiveParameter]: PHP 8.2부터 도입된 속성(Attribute)이다. 에러가 발생하여 스택 트레이스(Stack Trace)가 출력될 때, 비밀번호와 같은 민감 정보가 화면에 노출되지 않도록 가려주는 역할을 한다.
- 반환형 (mysqli|false): 접속에 성공하면 mysqli 객체를 반환하고, 실패하면 false를 반환한다.
2️⃣ 주요 연동 함수
| 함수명 | 설명 |
| mysqli_connect($host, $user, $pw, $db) | DB 서버에 접속 및 세션 수립 |
| mysqli_query($conn, $query) | 연결된 세션을 통해 SQL 질의문 실행 |
| mysqli_fetch_row($result) | 실행 결과(Result set)에서 한 행씩 데이터를 가져옴 |
| mysqli_free_result($result) | 사용이 끝난 결과 집합 메모리 해제 |
| mysqli_close($conn) | DB 연결 종료 |
3️⃣ 데이터베이스 연동 프로세스

3. 실습 환경 설정: PHP 에러 출력 활성화
개발 단계에서는 문법 오류나 DB 접속 오류를 즉시 확인해야 하므로 php.ini 설정을 변경해야 한다.
- 설정 파일 수정: vi /etc/php.ini를 열어 478라인 근처의 display_errors 항목을 On으로 변경한다.
- 서비스 재시작: 설정 적용을 위해 아파치 서버를 재시작한다.
[root@victim php]# vi /etc/php.ini
display_errors = On
[root@victim php]# systemctl restart httpd.service
📌아파치와 PHP의 결합 방식 (mod_php)
CentOS 7에서 기본적으로 APM을 구축하면 아파치가 PHP를 모듈(mod_php) 형태로 포함하는 경우가 많다.
- 이 방식에서 PHP는 독립적인 프로그램이 아니라 아파치의 일부분처럼 동작한다.
- 즉, 아파치 프로세스가 뜰 때 PHP 환경 설정도 같이 불러와지기 때문에 아파치를 재시작해야 PHP 설정도 갱신되는 구조다.
4. 실습 1: MariaDB 기본 접속 및 데이터 조회
1️⃣ 코드 작성 (dbconnect1.php)
이 코드는 MariaDB에 접속하여 현재 존재하는 데이터베이스 목록 중 상위 2개를 출력하는 예제다.
<?php
// dbconnect1.php
$dbhost = "localhost";
$dbuser = "root";
$dbpass = "1234"; // 실제 패스워드 입력
$dbname = "test";
// 1. DB 접속
$conn = mysqli_connect($dbhost, $dbuser, $dbpass, $dbname);
// 2. 쿼리 준비 및 실행
$query = "SHOW DATABASES";
$result = mysqli_query($conn, $query);
// 3. 데이터 가져오기 (첫 번째 행)
$row = mysqli_fetch_row($result);
print($row[0] . "<br>"); // information_schema 출력 예상
// 4. 데이터 가져오기 (두 번째 행)
$row = mysqli_fetch_row($result);
print($row[0]); // mysql 출력 예상
// 5. DB 연결 종료
mysqli_close($conn);
?>
2️⃣ 시퀀스 다이어그램

3️⃣ 예상 결과
- 비밀번호가 틀렸을 경우: 웹 페이지에 Access denied for user 'root'@'localhost' 경고 메시지가 출력된다. 이는 콘솔에서 mysql -u root -p 접속 시 실패하는 것과 동일한 원리다.
- 성공 시: 브라우저 화면에 information_schema와 mysql이 줄바꿈되어 나타난다.
5. 실습 2: 웹과 DB 연동 (회원 목록 출력)
데이터베이스에 실제 테이블을 생성하고, PHP에서 이를 조회하여 웹 화면에 뿌려주는 실습이다.
1️⃣ MariaDB 데이터 준비
터미널에서 test 데이터베이스에 접속하여 member 테이블을 생성하고 샘플 데이터를 입력한다.
mysql test
CREATE TABLE member (
no int,
userid varchar(15),
userpass varchar(20)
);
INSERT INTO member VALUES(1, 'admin', '1234');
INSERT INTO member VALUES(2, 'whitehat', '2026');
INSERT INTO member VALUES(3, 'blackhat', '1111');
2️⃣ PHP 코드 작성 (dbmemberlist.php)
<?php
// dbmemberlist.php
$conn = mysqli_connect("localhost", "root", "1234", "test");
$query = "SELECT * FROM member";
$result = mysqli_query($conn, $query);
// 반복적으로 행을 읽어와 출력
while($row = mysqli_fetch_row($result)) {
print("$row[0] $row[1] $row[2] <br>");
}
mysqli_close($conn);
?>
3️⃣ 시퀀스 다이어그램

4️⃣ 예상 결과
URL http://192.168.100.10/php/dbmemberlist.php 접속 시 다음과 같이 출력된다.
1 admin 1234
2 whitehat 2026
3 blackhat 1111
6. 실습 3: 게시판 페이징(Pagination) 로직 구현
방대한 데이터를 한 화면에 모두 표시하면 가독성이 떨어지고 부하가 발생한다.
이를 해결하기 위해 데이터를 일정 단위로 나누어 보여주는 페이징 처리가 필수적이다.
1️⃣ 변수 정의
- 총 게시글 수($total\_post$): DB에 저장된 전체 레코드 개수.
- 페이지당 글 수($limit$): 한 화면에 보여줄 게시글 개수.
- 총 페이지 수: ceil(총 게시글 수 / 페이지당 글 수)
- 시작 위치($start$): 현재 페이지에 따라 가져올 데이터의 시작 인덱스. (현재 페이지 - 1) * 페이지당 글 수
2️⃣ PHP 코드 작성
🟢 [page_link.php] - 링크 생성 함수
이 파일은 하단에 [이전] [1] [2] [3] [다음] 형태의 HTML을 생성하는 함수를 담고 있다.
<?php
function paging($total_post, $post_per_page, $current_page) {
$total_page = ceil($total_post / $post_per_page);
$html = "<div class='paging'>";
// [이전] 버튼: 1페이지가 아닐 때만 링크 활성
if ($current_page > 1) {
$prev_page = $current_page - 1;
$html .= "<a href='list.php?page={$prev_page}'>[이전]</a> ";
} else {
$html .= "[이전] ";
}
// 페이지 번호 출력
for ($i = 1; $i <= $total_page; $i++) {
if ($i == $current_page) {
$html .= "<strong>$i</strong> "; // 현재 페이지 강조
} else {
$html .= "<a href='list.php?page={$i}'>[{$i}]</a> ";
}
}
// [다음] 버튼
if ($current_page < $total_page) {
$next_page = $current_page + 1;
$html .= "<a href='list.php?page={$next_page}'>[다음]</a>";
} else {
$html .= "[다음]";
}
$html .= "</div>";
return $html;
}
?>
🟢 [list.php] - 메인 목록 페이지
배열 데이터를 활용하여 페이징 로직을 재현한다.
실제 서비스에서는 array_slice 대신 SQL의 LIMIT $start, $limit 구문을 사용하게 된다.
<?php
include "page_link.php";
// 1. 샘플 데이터 (실제로는 DB에서 가져옴)
$board = array(
array("num" => 1, "subject" => "게시글 1", "name" => "홍길동"),
// ... (중략) ...
array("num" => 15, "subject" => "게시글 15", "name" => "이병헌")
);
// 최신글이 위로 오도록 역순 정렬
$board = array_reverse($board);
// 2. 페이징 변수 설정
$limit = 5; // 한 페이지에 5개씩
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
if ($page < 1) $page = 1;
$total_post = count($board);
$total_page = ceil($total_post / $limit);
if ($page > $total_page) $page = $total_page;
// 3. 데이터 추출 범위 계산
$start = ($page - 1) * $limit;
$page_data = array_slice($board, $start, $limit);
?>
<table>
<tr><th>번호</th><th>제목</th><th>작성자</th></tr>
<?php foreach ($page_data as $row) { ?>
<tr>
<td><?php echo $row["num"]; ?></td>
<td><?php echo $row["subject"]; ?></td>
<td><?php echo $row["name"]; ?></td>
</tr>
<?php } ?>
</table>
<?php echo paging($total_post, $limit, $page); ?>
3️⃣ 시퀀스 다이어그램

4️⃣ 예상 결과
- list.php 최초 접속 시: 15번부터 11번까지 게시글이 보이고 하단에 [1] [2] [3] [다음] 링크가 생성된다.
- [2] 클릭 시: URL이 list.php?page=2로 변경되며 10번부터 6번 게시글이 출력된다.