PHP

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

PDO

데이터베이스란?

데이터의 저장, 조회, 수정을 편리하고 안전하게 할 수 있도록 고안된 소프트웨어다.

MySQL이란?

데이터베이스라는 분류의 제품군에 속한 구체적인 상품으로 ORACLE에 의해서 개발되고 있다. 오픈소스이고, 가장 많은 사용자를 가지고 있는 데이터베이스 시스템에 속한다. MySQL과 같은 분류에 속한 데이터베이스로는 ORACLE, MSSQL 등이 있다.

데이터베이스와 PHP

일반적으로 데이터를 저장해야 하는 에플리케이션을 구축하는 경우 데이터는 데이터베이스 서버에 저장한다. PHP 에플리케이션의 코드에는 데이터베이스 서버에 접속해서 데이터를 조회/수정/삭제하는 코드를 작성한다. PHP 에플리케이션이 호출되면 PHP 엔진은 PHP 에플리케이션의 코드에 따라서 데이터베이스의 클라이언트가 되어서 데이터베이스에 접속해서 여러가지 작업을 처리한다.

선행지식

본 수업은 데이터베이스에 대한 수업이 아니라 PHP를 이용해서 데이터베이스를 제어하는 방법에 대한 수업이다. 따라서 데이터베이스 자체에 대한 설명은 수업의 범위에 포함되지 않기 때문에 MySQL 수업을 참고한다.

선행작업

아래의 명령을 입력해서 데이터베이스를 생성한다. 아래의 명령은 opentutorials라는 데이터베이스를 생성한다.

CREATE DATABASE opentutorials CHARACTER SET utf8 COLLATE utf8_general_ci;

아래 명령을 입력해서 데이터베이스 opentutorials를 선택한다.

use opentutorials;

아래 명령을 입력해서 데이터베이스 opentutorials 내에 테이블 topic을 생성한다.

CREATE TABLE topic (
    id  int(11) NOT NULL AUTO_INCREMENT,
    title  varchar(255) NOT NULL ,
    description  text NULL ,
    created  datetime NOT NULL ,
    PRIMARY KEY (id)
);

PDO

PDO(PHP Data Objects)란 여러가지 데이터베이스를 제어하는 방법을 표준화시킨 것이다. 데이터베이스는 다양한 종류가 있다. 그리고 종류에 따라서 서로 다른 드라이브를 사용해 왔는데 드라이브의 종류에 따라서 데이터베이스를 제어하기 위한 API가 달랐다. PDO를 사용하면 동일한 방법으로 데이터베이스를 제어할 수 있다.

PHP의 mysql client library(mysql_connect와 같은 함수)는 PHP 5.5 버전부터 지원되지 않을 예정이다. 따라서 더 이상 새로운 에플리케이션의 경우 mysql client library를 사용해서는 안된다. 하지만 사용하는 환경이 PDO나 mysqli를 지원하지 않거나 기존의 코드가 mysql client library라면 이것의 사용법을 알아야 한다. 이런 경우 데이터베이스와 PHP 수업을 참고한다.

또한 PHP에 대한 올바른 사용법을 전파하고 있는 PHP Right Way에서는 PDO를 사용할 것을 권하고 있다. 이에 대한 내용은 PHP Right Way의 데이터베이스 편을 참고한다.

예제 트러블슈팅

만약 아래와 같은 에러가 발생한다면 PDO MySQL 익스텐션이 설치되지 않았기 때문이다.
Fatal error: Uncaught exception 'PDOException' with message 'could not find driver' in D:\BitNami\wampstack-5.4.21-0\apache2\htdocs\database\list.php:4 Stack trace: #0 D:\BitNami\wampstack-5.4.21-0\apache2\htdocs\database\list.php(4): PDO->__construct('mysql:host=loca...', 'root', '111111') #1 {main} thrown in D:\BitNami\wampstack-5.4.21-0\apache2\htdocs\database\list.php on line 4

이를 해결하기 위해서는 PDO 익스텐션을 활성화해야 한다. Bitnami의 윈도우 버전인 경우 아래와 같이 처리한다.

php의 디렉토리가 D:\BitNami\wampstack-5.4.21-0\php일 경우 D:\BitNami\wampstack-5.4.21-0\php\php.ini 파일을 열고 아래의 코드 앞의 ;을 제거한다.

extension=php_pdo_mysql.dll

그리고 익스텐션의 dll 파일이 설치된 디렉토리의 기본경로를 변경해준다. 아래의 경로는 필자가 설치한 Bitnami를 기준으로 한 것이기 때문에 사용자마다 다를 수 있다. 자신의 환경에 맞게 수정해준다.

extension_dir = "D:\BitNami\wampstack-5.4.21-0\php\ext"

예제

아래의 파일은 전송 버튼을 눌렀을 때 process.php 파일로 데이터를 전송한다.

input.php

<!DOCTYPE html>
<html>
    <head>
		<meta charset="utf-8"/>
	</head>	
	<body>
		<form action="./process.php?mode=insert" method="POST">
			<p>제목 : <input type="text" name="title"></p>
			<p>본문 : <textarea name="description" id="" cols="30" rows="10"></textarea></p>
			<p><input type="submit" /></p>			
		</form>
	</body>
</html>

아래의 파일은 데이터베이스를 조작하는 작업을 모아둔 PHP 에플리케이션이다. URL에 포함된 mode의 값에 따라서 다른 작업을 하도록 switch 문을 사용했다.

process.php

<?php
$dbh = new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
switch($_GET['mode']){
    case 'insert':
		$stmt = $dbh->prepare("INSERT INTO topic (title, description, created) VALUES (:title, :description, now())");
		$stmt->bindParam(':title',$title);
		$stmt->bindParam(':description',$description);

		$title = $_POST['title'];
		$description = $_POST['description'];
		$stmt->execute();
		header("Location: list.php"); 
		break;
	case 'delete':
		$stmt = $dbh->prepare('DELETE FROM topic WHERE id = :id');
		$stmt->bindParam(':id', $id);

		$id = $_POST['id'];
		$stmt->execute();
		header("Location: list.php"); 
		break;
	case 'modify':
		$stmt = $dbh->prepare('UPDATE topic SET title = :title, description = :description WHERE id = :id');
		$stmt->bindParam(':title', $title);
		$stmt->bindParam(':description', $description);
		$stmt->bindParam(':id', $id);

		$title = $_POST['title'];
		$description = $_POST['description'];
		$id = $_POST['id'];
		$stmt->execute();
		header("Location: list.php?id={$_POST['id']}");
		break;
}
?>

아래의 파일은 데이터베이스에 저장된 토픽의 리스트와 선택된 토픽의 자세한 정보를 화면에 출력하는 에플리케이션이다.

list.php

<?php
$dbh = new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111');
$stmt = $dbh->prepare('SELECT * FROM topic');
$stmt->execute();
$list = $stmt->fetchAll();
if(!empty($_GET['id'])) {
    $stmt = $dbh->prepare('SELECT * FROM topic WHERE id = :id');
    $stmt->bindParam(':id', $id, PDO::PARAM_INT);
    $id = $_GET['id'];
    $stmt->execute();
    $topic = $stmt->fetch();
}
?>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <style type="text/css">
            body {
                font-size: 0.8em;
                font-family: dotum;
                line-height: 1.6em;
            }
            header {
                border-bottom: 1px solid #ccc;
                padding: 20px 0;
            }
            nav {
                float: left;
                margin-right: 20px;
                min-height: 1000px;
                min-width:150px;
                border-right: 1px solid #ccc;
            }
            nav ul {
                list-style: none;
                padding-left: 0;
                padding-right: 20px;
            }
            article {
                float: left;
            }
            .description{
                width:500px;
            }
        </style>
    </head>
  
    <body id="body">
        <div>
            <nav>
                <ul>
                    <?php
                    foreach($list as $row) {
                        echo "<li><a href=\"?id={$row['id']}\">".htmlspecialchars($row['title'])."</a></li>";                        }
                    ?>
                </ul>
                <ul>
                    <li><a href="input.php">추가</a></li>
                </ul>
            </nav>
            <article>
                <?php
                if(!empty($topic)){
                ?>
                <h2><?=htmlspecialchars($topic['title'])?></h2>
                <div class="description">
                    <?=htmlspecialchars($topic['description'])?>
                </div>
                <div>
                    <a href="modify.php?id=<?=$topic['id']?>">수정</a>
                    <form method="POST" action="process.php?mode=delete">
                        <input type="hidden" name="id" value="<?=$topic['id']?>" />
                        <input type="submit" value="삭제" />
                    </form>
                </div>
                <?php
                }
                ?>
            </article>
        </div>
    </body>
</html>

아래 파일은 토픽의 내용을 수정하기 위해서 사용할 에플리케이션이다.

<?php
$dbh = new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111');
$stmt = $dbh->prepare('SELECT * FROM topic WHERE id = :id');
$stmt->bindParam(':id', $id, PDO::PARAM_INT);
$id = $_GET['id'];
$stmt->execute();
$topic = $stmt->fetch();
?>
<!DOCTYPE html>
<html>
    <head>
		<meta charset="utf-8"/>
	</head>	
	<body>
		<form action="./process.php?mode=modify" method="POST">
			<input type="hidden" name="id" value="<?=$topic['id']?>" />
			<p>제목 : <input type="text" name="title" value="<?=htmlspecialchars($topic['title'])?>"></p>
			<p>본문 : <textarea name="description" id="" cols="30" rows="10"><?=htmlspecialchars($topic['description'])?></textarea></p>
			<p><input type="submit" /></p>
		</form>
	</body>
</html>

댓글

댓글 본문
작성자
비밀번호
  1. 나즈나
    array(PDO::MYSQL_ATTR_INIT_COMMAND=>"SET NAMES utf8")
    이부분이 에러가 나는데 왜 나는지 모르겠습니다.
    사용하면 => 이후부터 코드가 그대로 노출이 됩니다.
  2. JustStudy
    고맙습니다
  3. 멘탈망
    현재 로그인 부분을 완성 시키려구 공부를 하고 있는데요 질문이 있습니다.
    <form name="login" method="post">
    <div class="loginform">
    <label for="email">이메일:</label>
    <p class="inp"><input type="email" name="email" id="email" placeholder="이메일" /></p>

    <label for="password">비밀번호:</label>
    <p class="inp"><input type="password" name="password" id="password" placeholder="비밀번호" /></p>


    <button type="submit">로그인</button>
    <div class="joinbtn"><a href="/member/register.do">회원가입</a></div>
    </div>

    이런식으로 되어 있는데요 action을 설정하지 않으면 자기 자신으로 데이터?를 보낸다고 알고 있습니다 그래서 제가 파일 가장 상단에

    <?php
    $dbh = new PDO('mysql:host=localhost;dbname=user', 'root', 'kutemsys', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
    $stmt = $dbh->prepare("INSERT INTO topic (title, description, created) VALUES (:title, :description, now())");

    $stmt->bindParam(':title', $title);
    $stmt->bindParam(':description', $description);


    // $title = $_POST['title'];
    // $description = $_POST['description'];

    $stmt->execute();


    header("Location: /main/main.do");
    ?>

    이런 코드를 넣어 주었거든요 (주석친 부분은 오류가 나서 .....)
    근데 여기서 문제가
    header("Location: /main/main.do");부분은 잘 실행 되는데 위쪽 데이터 베이스 관련된 문장은 전혀 작동이 안되서 질문 드립니다 ㅠㅠ

    혹시나 해서 action = "/member/login.php"를 해 줘서 따로 경로를 설정해 줘서 테스트를 해보면 여기서는
    header("Location: /main/main.do");조차 실행이 안됩니다 .... 아마 login.php파일을 못찾아 간거 같은데.....
  4. Fatal error: Class 'PDO' not found in C:\APM_Setup\htdocs\pdo\process.php on line 2
    이런 메세지가 뜨는데 무엇이 문제일까요
    트러블 슈팅문제도 다 해봤습니다.
    (extension=php_pdo_mysql.dll
    extension_dir = "C:\APM_Setup\Server\PHP5\ext")
    혹시 mysql 암호를 제것으로 해야되나 싶어서 process.php list.php modify.php코드에서 암호도 바꾸어 봤는데 안되네요..
    참고 mysql확장예제는 잘 됩니다.
    php버젼 문제라고도 하는데 혹시 5.2.12라서 안되는 건가요??
  5. 이진샘
    같은 상황을 겪으며 곤란해 하고 있었는데... 정말 큰 도움이 되었습니다. ^^
    대화보기
    • 뽀록이야
      생활코딩 덕분에..서비스 하는데 도움이 많이 되고 있습니다~
    • 홈리스
      와!!! 기존 만들어두었던 게시판을 PDO로 다 바꿨더니 에러 풍년이네;;;
      자꾸 수정하다보니 걸래가 되서 맘에 안들었었는데....
      디비 설계부터 첨부터 다시 해야겠어요 ㅋㅋ
    • Quan Lee
      트러블 슈팅 관련 문의합니다.
      리눅스에서 PDO로 데이타베스 연동하려는데 아래와 같은 메시지가 뜸니다.
      위의 강의를 보고 리눅스도 비트나미와 비슷한 식으로 해야겠다 생각해서
      PHP.ini파일을 찾아 extension=php_pdo_mysql.dll 앞의 ';'부호를 제거 했습니다.
      BITNAMI경우 해당 extension을 활성화 한 후, 디렉토리를 변경하는데 리눅스 경우 어떻게 조작해야 합니까?

      Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2003] Can't connect to MySQL server on '112.74.108.24' (111)' in /var/www/html/process.php:2 Stack trace: #0 /var/www/html/process.php(2): PDO->__construct('mysql:host=112....', 'root', '142536', Array) #1 {main} thrown in /var/www/html/process.php on line 2


      그리고 linux 경우 이 문구 new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111'에 mysql의 해당 port값도 적어야 하는지요?
    • 라따뚜이
      웹 서비스 만들기부터 시작해서 여기까지 왔습니다!
      누구나 조금만 공부하면 이해할 수 있을 수준의 체계적인 언어들에 토픽마다 감탄을 합니다.
      어느세 이런 언어들이 제작되고 발전하고 대체되는 과정을 지켜보는 입장이 되었습니다.
      오픈튜토리얼스에서 컴퓨터 언어 뿐만 아니라 더 많은 것들을 느끼게 해줍니다.
      항상 감사합니다!

      다름아니라 '한글깨짐' 때문에 덧글을 남깁니다!
      MySQL 확장편을 실습 중 PHP버젼이 달랐는지, list.php에서 토픽을 클릭해도 내용이 나오지 않았습니다.
      PDO 예제로 하니 오류가 나고,,, 그러던 중 무료호스팅 환경에서 PDO로 실습을 해봤는데 잘 되었습니다!
      그런데 한글이 깨져서 보였습니다.

      PDO토픽에서 '한글깨짐'은 중요하지 않지만, 간단히 해결할 수 있어 글을 남깁니다!


      $dbh = new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111');

      PDO list.php 의 예제의 2번을

      $dbh = new PDO('mysql:host=localhost;dbname=opentutorials', 'root', '111111', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));

      PDO process.php 예제의 2번처럼 바꿔주니 간단하게 해결되었습니다.

      처음으로 덧글을 다려다보니 이렇게 장문의 덧글을 쓰게되었네요...ㅎ
      감사합니다!
    • 금도끼은도끼
      데이터베이스하구 데이터가 왔다갔다하닌가 넘재미있네요
      감사합니다(__)
    • JPARK
      PDO 에 대해서 감이 안잡혀서 예제를 따라하면서 공부하는것도 좋을 거 같네요
      http://blog.naver.com......485
      예제를 소개하는 블로그입니다.
    • ssandk
      감사!
      대화보기
      • Daniel
        php 5.6부터 된다고 봤어요. mysqli는 5.5부터구요. 둘의 차이는 아주 미미하다네요.
        대화보기
        • ssandk
          php 4.4.9에서 pdo 사용 가능한가요?
        • ddojai
          Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000] [2002] No such file or directory' in

          혹시 위와 같은 에러가 발생한다면 PDO('mysql:host=localhost 에서 localhost를 127.0.0.1로 수정해 보세요.
          OS X 매버릭스 환경에서 localhost로 하면 에러 발생하네요. Bitnami가 아니라서 그럴수도 있는거 같구요.
        • 김범
          $list에 저장된 배열이 2개씩인건가요.......
          그럼 foreach로 출력하는것은 별도의 옵션이 필요한걸까요..ㅎㅎ;;
        • egoing
          아래와 같이 하면 어떻게 되나요?

          $stmt = $dbh -> prepare("SELECT * FROM member_management");
          $stmt->execute();
          $list = $stmt->fetchAll();
          foreach($list as $row){
          print_r($row);
          foreach($row as $cul){
          print_r($cul);
          echo "$cul\n";
          }}
          ?>
        • 김범
          Array ( [0] => Array ( [id] => 1 [0] => 1 [name] => 김범 [1] => 김범 [school] => 충남 [2] => 충남 [grade] => 3학년 [3] => 3학년 [address] => 09동 602호 [4] => 09동 602호 [mom_phone] => 123-13123-123 [5] => 123-13123-123 [stu_phone] => 1231-23131-13 [6] => 1231-23131-13 [home_phone] => 12313-123123-12 [7] => 12313-123123-12 [created] => 2014-03-17 17:13:57 [8] => 2014-03-17 17:13:57 ) [1] => Array ( [id] => 4 [0] => 4 [name] => 진아 [1] => 진아 [school] => 여고 [2] => 여고 [grade] => 3학년 [3] => 3학년 [address] => 0동 602호 [4] => 0동 602호 [mom_phone] => 131231321 [5] => 131231321 [stu_phone] => 4093858 [6] => 4093858 [home_phone] => 12347892 [7] => 12347892 [created] => 2014-03-18 04:28:00 [8] => 2014-03-18 04:28:00 ) [2] => Array ( [id] => 6 [0] => 6 [name] => 이화 [1] => 이화 [school] => 고등학교 [2] => 고등학교 [grade] => 3학년 [3] => 3학년 [address] => 0동 602호 [4] => 0동 602호 [mom_phone] => 1323978 [5] => 1323978 [stu_phone] => 8798372582 [6] => 8798372582 [home_phone] => 35793274 [7] => 35793274 [created] => 2014-03-18 04:34:22 [8] => 2014-03-18 04:34:22 ) )
          이렇게게 나옵니당 ..
        • egoing
          print_r($list);를 실행하면 어떤 결과가 나오나요?


          $stmt = $dbh -> prepare("SELECT * FROM member_management");
          $stmt->execute();
          $list = $stmt->fetchAll();
          print_r($list);
          foreach($list as $row){
          foreach($row as $cul){
          echo "$cul\n";
          }}
          ?>
          대화보기
          • 김범
            수고가 많으세요..
            $stmt = $dbh -> prepare("SELECT * FROM member_management");
            $stmt->execute();
            $list = $stmt->fetchAll();
            foreach($list as $row){
            foreach($row as $cul){
            echo "$cul\n";
            }}
            ?>
            제가 위처럼 조금 바꿨는데요.. 데이터가 2번씩 중복되어 출력됩니다. (즉, member_management table의 id=1의 row값들이 2번씩 반복되요. 11, 김범김범 충남충남 010-1231-1231 010-1231-1231 ....이렇게요..)
            echo "$list[0][0]";
            echo "$list[1][0]";
            을 수행하면 분명 1하고 4가 나오거든요. 중간에 데이터를 지우는 연습을 해서 id가 1,4, 6 이렇게 나갑니다.ㅜㅜ
            근본적으로 이해를 잘못하고 있는것 같아요
            ㅜㅜ 도와주십시오.
          • 김범
            오오 고맙습니닷!!
          • egoing
            :title은 테이블의 title 필드를 의미합니다. 측 :title 필드의 값으로 변수 $title의 값을 사용하겠다는 의미죠.

            $stmt = $dbh->prepare('UPDATE topic SET title = :title, description = :description WHERE id = :id');
            $stmt->bindParam(':title', $title);
            $stmt->bindParam(':description', $description);
            $stmt->bindParam(':id', $id);

            $title = $_POST['title'];
            $description = $_POST['description'];
            $id = $_POST['id'];
            $stmt->execute();

            위에서 $stmt->execute는 그 위의 과정을 통해서 완성한 쿼리(UPDATE topic SET title = "$title", description = "$description" WHERE id = $id)를 실제로 서버로 전송한다는 의미입니다.
            대화보기
            • egoing
              예 맞습니다!
              대화보기
              • 김범
                header("location : list.php");는 다음 갈곳을 지정하는 함수인것 맞지요? ㅎㅎ
                무엇을 모르는 지를 아는 것!
              • 김범
                이고잉님의 강의 덕분에 짙은 안개에서 조금씩 빛이 보이는 기분입니다. 고맙습니다.
                두가지만 부탁드리겠습니다.
                첫번째는 제 설명에서 오류가 있는 점을 지적해주시고, 두번째는 궁금증좀 풀어주세요. 아무리 검색해봐도 함수 및 문법에 대해 명확하게 설명된 곳이 없어서..ㅜ
                $dbh = new PDO() 는 PDO란 내부 클래스를 정의한것 같고, 자바에서 인스턴스를 생성하는 것 같습니다. ()안에 들어갈 변수 및 옵션들은 아직은 이해안해도 넘어갈 수 있습니다.
                $stmt = $dbh->prepare("INSERT INTO~) 이 구분은 변수stmt에 dbh에서 호출한 클래스내부 함수 prepare()를 정의한 것같고,
                $stmt->bindParam();은 prepare 내부에 또 다른 함수 bindParam()을 수행하라는 것 같습니다.
                여기서 질문1. bindParam(':title', $title)에서 :title이 의미하는 것이 무엇일까요.ㅋ
                질문2. $stmt->execute(); 함수는 파라미터도 없고 무슨 의민지 모르겠습니다.
                간략하게 흐름좀 설명해주시면 안될까요.
              • 닭살
                input에서는 post 방식으로 보내고, process에서는 get방식으로 받고...

                이렇게 해도 상관없나요??
              • egoing
                수정 했습니다 :)
                대화보기
                • SniperM
                  데이터베이스와 PHP 수업 링크누르니 404뜹니다.
                • 자유로운푸른곰
                  부담이 하나 증가했네요
                • egoing
                  맙소사 간판에 오타가 있었군요. 수정했습니다~
                  대화보기
                  • 엠제이
                    왕건이 오타 신고
                    제목, POD -> PDO
                  버전 관리
                  egoing
                  현재 버전
                  선택 버전
                  graphittie 자세히 보기