1, 2편에 이어 작업하시는 것이 아니라면 구름 IDE에 다음과 같은 명령어를 터미널에 입력해주세요.
service mysql restart
1. Bootstrap 입히기
<html> <head> <title>Hello goorm</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> </head> <body> <h1>검색</h1> <form action="index.php" method="get"> <input type="search" name="search"> <input type="submit" value="Submit"> </form> <?php echo "select * from testtable where description like '%".$_GET["search"]."%'"; $conn = mysqli_connect('localhost', 'root', 'qwer1234', 'testdb'); /* $sql = "select * from testtable where description like '%not%'"; */ $sql = "select * from testtable where description like '%".$_GET["search"]."%'" $result = mysqli_query($conn, $sql); echo "<table class='table table-dark'>"; echo "<tr><th>ID</th><th>Title</th><th>Description</th></tr>"; while ($row = mysqli_fetch_array($result)){ echo "<tr><td>{$row['id']}</td><td>{$row['title']}</td><td>{$row['description']}</td></tr>"; } echo "</table>"; ?> </body> </html>
지난번 시간에 완성된 코드는 위와 같습니다. 2편에서도 말씀드린 것처럼 Bootstrap을 자세히 설명하지 않고 Bootstrap을 입혔는데요. 저 코드가 어디서 나온 것인지 설명해 드리도록 하겠습니다.
위 홈페이지에서
get started
를 클릭하여 CSS 부분에 코드를 카피한 코드였습니다.
Bootstrap은 위에 나온 설명처럼 세계에서 가장 많이 사용하는 프론트엔드 라이브러리 입니다. 버튼, 메뉴, 폼 등이 이미 구현되어 있고, 마치 레고 조립을 하듯이 웹 서비스를 만들어 낼 수 있습니다. 실제로 조립을 어떻게 할 수 있는지를 보도록 할게요.
- Examples를 클릭해주세요.

- 많은 예제가 있는데, 저는 Carousel을 클릭하도록 하겠습니다.

- 크롬에 개발자 도구를 열어주세요. 윈도우는
Ctrl + i
입니다.

- 아래 마우스 버튼을 클릭해주세요.

- 메뉴에 마우스를 오버하고 아래와 같이 나오셨다면 클릭하세요.

- Ctrl + C를 눌러 코드를 가져오세요. 그리고 우리가 가진 코드 body 태그 바로 아래 배치해주세요.

자, 여기까지 전체 코드입니다. 그리고 실행시켜보세요.
<html> <head> <title>Hello goorm</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> </head> <body> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <a class="navbar-brand" href="#">Carousel</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="#">Link</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a> </li> </ul> <form class="form-inline mt-2 mt-md-0"> <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form> </div> </nav> <h1>검색</h1> <form action="index.php" method="get"> <input type="search" name="search"> <input type="submit" value="Submit"> </form> <?php echo "select * from testtable where description like '%".$_GET["search"]."%'"; $conn = mysqli_connect('localhost', 'root', 'qwer1234', 'testdb'); /* $sql = "select * from testtable where description like '%not%'"; */ $sql = "select * from testtable where description like '%".$_GET["search"]."%'"; $result = mysqli_query($conn, $sql); echo "<table class='table table-dark'>"; echo "<tr><th>ID</th><th>Title</th><th>Description</th></tr>"; while ($row = mysqli_fetch_array($result)){ echo "<tr><td>{$row['id']}</td><td>{$row['title']}</td><td>{$row['description']}</td></tr>"; } echo "</table>"; ?> </body> </html>
여기까지 완성된 화면은 아래와 같습니다. 메뉴가 생겼죠? 이처럼 Bootstrap으로 만든 예제들은 CSS가 동일하기 때문에 동일한 UI를 구성할 수 있습니다. 물론 Custom CSS가 있는 경우(개발자가 임의로 수정하거나, 새로운 CSS를 입힌 경우), 여러분들이 해당 CSS 요소를 가지고 올 수 있어야 동일한 UI 구성을 할 수 있습니다.
우리 결과물을 보았을 때, 아래 검색창이 가려지는군요. 좀 더 코드를 Bootstrap에 맞게 고쳐주도록 하겠습니다. Bootstrap을 공부하고 싶으시다면 홈페이지에 있는 Document를 천천히 따라해 보시는 것을 추천해드립니다.

조금 더 고쳐 아래 처럼 코드를 입혔습니다. 물론 margin을 주는 방법이 아래와 같이 별도로 정의되어 있지만, 이해하기 쉽도록 직접 태그에 부여하였습니다.
기본적으로 Bootstrap은 전체 웹 서비스를 row(행)로 나누고 각각 행에 12개의 column(열)으로 나눠 홈페이지를 만드는 개념입니다. 아래 이미지를 참고해주세요. 물론 아래처럼 검은색 실선이 그려지는 것은 아닙니다.

상세 내용은 아래 grid시스템을 참고해주세요.
전체코드입니다.
<html> <head> <title>Hello goorm</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> </head> <body> <div class="container"> <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark"> <a class="navbar-brand" href="#">Carousel</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarCollapse"> <ul class="navbar-nav mr-auto"> <li class="nav-item active"> <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a> </li> <li class="nav-item"> <a class="nav-link" href="#">Link</a> </li> <li class="nav-item"> <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a> </li> </ul> <form class="form-inline mt-2 mt-md-0"> <input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form> </div> </nav> </div> <div class="container"> <div class="row"> <div class="col-md-12" style="margin-top:25px;"> <h1>검색</h1> <form action="index.php" method="get"> <div class="row"> <div class="col"> <input type="search" class="form-control" name="search"> </div> <div class="col"> <input type="submit" class="btn btn-info" value="검색"> </div> </div> </form> <?php echo "select * from testtable where description like '%".$_GET["search"]."%'"; $conn = mysqli_connect('localhost', 'root', 'qwer1234', 'testdb'); /* $sql = "select * from testtable where description like '%not%'"; */ $sql = "select * from testtable where description like '%".$_GET["search"]."%'"; $result = mysqli_query($conn, $sql); echo "<table class='table table-dark'>"; echo "<tr><th>ID</th><th>Title</th><th>Description</th></tr>"; while ($row = mysqli_fetch_array($result)){ echo "<tr><td>{$row['id']}</td><td>{$row['title']}</td><td>{$row['description']}</td></tr>"; } echo "</table>"; ?> </div> </div> </div> </body> </html>
아래 화면은 실행 화면입니다. 어떤가요? 조금 더 홈페이지 같아졌죠?

2. 무료 템플릿 입히기
홈페이지를 일일이 꾸며줄 수도 있지만, Bootstrap 무료 템플릿을 사용하여 홈페이지를 꾸밀 수 있습니다.
Google에서 Bootstrap 무료 템플릿을 검색해주세요. 무료 템플릿을 다운로드 받아 서버에 업로드 하세요. 아래 사이트를 추천합니다.
많은 테마 중에서도 깔끔한 아래 태마를 추천해드립니다.
아래 창에서
Free Download
를 클릭하시면 전체 코드를 다운로드 받으실 수 있습니다. 구름IDE에 업로드를 하실 때에는 꼭 전체 폴더를 함께 업로드 하셔야 합니다. HTML, CSS, JS, 이미지와 폴더 모두요.
저는 압축파일을 업로드해서 구름IDE에서 압축을 풀도록 하겠습니다. 최상이 폴더를 클릭하시고 마우스 오른쪽 버튼을 클릭하신다음
가져오기
> 파일
을 클릭해주세요.


터미널 창(
창
> 새 터미널 창
)에서 아래 코드를 실행해주세요. 파일을 더블클릭하셔도 파일이 압축이 풀립니다.unzip startbootstrap-clean-blog-gh-pages.zip

드래그엔 드롭을 통해 최상이 폴더로 해당 파일들을 모두 올려주세요. 아래처럼 폴더트리가 만들어져야 합니다. (폴더 밖으로 모든 요소를 꺼냈고, 해당 폴더를 삭제하였습니다.)

자, 이제 index.php를 아래 코드로 수정해주시면, 저 템플릿을 사용할 수 있게 됩니다.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>Clean Blog - Start Bootstrap Theme</title> <!-- Bootstrap core CSS --> <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom fonts for this template --> <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css"> <link href='https://fonts.googleapis.com/css?family=Lora:400,700,400italic,700italic' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'> <!-- Custom styles for this template --> <link href="css/clean-blog.min.css" rel="stylesheet"> </head> <body> <!-- Navigation --> <nav class="navbar navbar-expand-lg navbar-light fixed-top" id="mainNav"> <div class="container"> <a class="navbar-brand" href="index.html">Start Bootstrap</a> <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> Menu <i class="fas fa-bars"></i> </button> <div class="collapse navbar-collapse" id="navbarResponsive"> <ul class="navbar-nav ml-auto"> <li class="nav-item"> <a class="nav-link" href="index.html">Home</a> </li> <li class="nav-item"> <a class="nav-link" href="about.html">About</a> </li> <li class="nav-item"> <a class="nav-link" href="post.html">Sample Post</a> </li> <li class="nav-item"> <a class="nav-link" href="contact.html">Contact</a> </li> </ul> </div> </div> </nav> <!-- Page Header --> <header class="masthead" style="background-image: url('img/home-bg.jpg')"> <div class="overlay"></div> <div class="container"> <div class="row"> <div class="col-lg-8 col-md-10 mx-auto"> <div class="site-heading"> <h1>Clean Blog</h1> <span class="subheading">A Blog Theme by Start Bootstrap</span> </div> </div> </div> </div> </header> <div class="container"> <div class="row"> <div class="col-lg-8 col-md-10 mx-auto"> <h1>검색</h1> <form action="index.php" method="get"> <div class="row"> <div class="col"> <input type="search" class="form-control" name="search"> </div> <div class="col"> <input type="submit" class="btn btn-info" value="검색"> </div> </div> </form> <?php echo "select * from testtable where description like '%".$_GET["search"]."%'"; $conn = mysqli_connect('localhost', 'root', 'qwer1234', 'testdb'); /* $sql = "select * from testtable where description like '%not%'"; */ $sql = "select * from testtable where description like '%".$_GET["search"]."%'"; $result = mysqli_query($conn, $sql); echo "<div class='post-preview'>"; while ($row = mysqli_fetch_array($result)){ echo "<a href='#'><h2 class='post-title'>{$row['id']} - {$row['title']}</h2><h3 class='post-subtitle'>{$row['description']}</h3></a><p class='post-meta'>Posted by<a href='#'>Start Bootstrap</a>on September 24, 2019</p>"; } echo "</div>"; ?> <hr> <!-- Pager --> <div class="clearfix"> <a class="btn btn-primary float-right" href="#">Older Posts →</a> </div> </div> </div> </div> <hr> <!-- Footer --> <footer> <div class="container"> <div class="row"> <div class="col-lg-8 col-md-10 mx-auto"> <ul class="list-inline text-center"> <li class="list-inline-item"> <a href="#"> <span class="fa-stack fa-lg"> <i class="fas fa-circle fa-stack-2x"></i> <i class="fab fa-twitter fa-stack-1x fa-inverse"></i> </span> </a> </li> <li class="list-inline-item"> <a href="#"> <span class="fa-stack fa-lg"> <i class="fas fa-circle fa-stack-2x"></i> <i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i> </span> </a> </li> <li class="list-inline-item"> <a href="#"> <span class="fa-stack fa-lg"> <i class="fas fa-circle fa-stack-2x"></i> <i class="fab fa-github fa-stack-1x fa-inverse"></i> </span> </a> </li> </ul> <p class="copyright text-muted">Copyright © Your Website 2020</p> </div> </div> </div> </footer> <!-- Bootstrap core JavaScript --> <script src="vendor/jquery/jquery.min.js"></script> <script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script> <!-- Custom scripts for this template --> <script src="js/clean-blog.min.js"></script> </body> </html>

완성된 코드는 아래 링크에서 다운로드 받을 수 있습니다.
핵심 코드는 아래와 같습니다. 나머지는 bootstrap 무료 템플릿 코드입니다.
<?php echo "select * from testtable where description like '%".$_GET["search"]."%'"; $conn = mysqli_connect('localhost', 'root', 'qwer1234', 'testdb'); $sql = "select * from testtable where description like '%".$_GET["search"]."%'"; $result = mysqli_query($conn, $sql); echo "<div class='post-preview'>"; while ($row = mysqli_fetch_array($result)){ echo "<a href='#'><h2 class='post-title'>{$row['id']} - {$row['title']}</h2><h3 class='post-subtitle'>{$row['description']}</h3></a><p class='post-meta'>Posted by<a href='#'>Start Bootstrap</a>on September 24, 2019</p>"; } echo "</div>"; ?>
3. SQL Injection 공격 대비
SQL Injection 공격은 웹 공격에서도 수년동안 Top 10자리를 지키고 있을만큼 흔히 일어나게 되는 해킹 공격입니다. 국내에서도 이름만 들으면 알만한 기업들이 이 공격에 해킹당한 적이 있습니다. 그만큼 주위해야 하는 공격이에요.
아래 코드를 검색에 입력해보세요.
%' union all select * from testtable where description like '%
Query문이 우리가 생각했던 쿼리문이 아니죠? 이처럼 의도하지 않았던 검색 결과를 볼 수 있게 하는 것이 SQL Injection 공격에 핵심입니다. 이렇게 이어 붙이는 것 뿐만 아니라 여기서 table에 다른 값들도 볼 수 있습니다.

이번에는 아래와 같이 입력해보세요.
%' union all select id, id, id, id from testtable where description like '%

전혀 새로운 값들이 검색이 된 것을 볼 수 있습니다. 이제 검색에 없던 table 값을 검색해보도록 하겠습니다. 우리가 입력한 테이블 값은 아래와 같고 일부러 created를 출력하지 않은 상태였습니다.
id int(11) NOT NULL AUTO_INCREMENT, title varchar(30) NOT NULL, description text, created datetime NOT NULL,
이게 만약 사용자 ID와 PW였다고 생각해보세요. 이처럼, 우리는 웹 서비스를 만들 때 정보보안에 관점에서도 코딩을 해야 합니다. 이러한 코딩 방법을 시큐어코딩이라고 합니다.
%' union all select created, created, created, created from testtable where description like '%

만약, 아래와 같이 user 테이블이 저장되어 있다면, 아래와 같은 대참사가 일어나게 됩니다.
create database userid; use testdb; CREATE TABLE usertable ( id int(11) NOT NULL AUTO_INCREMENT, userid varchar(30) NOT NULL, password text, PRIMARY KEY(id) ) ENGINE=InnoDB;
INSERT INTO usertable(userid, password) VALUES ('leehojun', '1q2w3e4r'); INSERT INTO usertable(userid, password) VALUES ('honghojun', 'admin1!'); INSERT INTO usertable(userid, password) VALUES ('junho', 'qawsedrf!'); SELECT * FROM usertable;
SQL Injection 공격
%' union all select userid, password, userid, password from usertable where userid like '%

4. SQL Injection 방지
이러한 공격은 javascript 단에서 막을 수 있을 것 같지만, 프록시 변조로 공격을 할 수 있기 때문에 PHP에서 유효성 검증 해주는 것이 좋습니다. 아래 같은 문자열이 포함된 쿼리문이 들어오면 검색을 하지 않는거죠.
/*, –, ‘, “, ?, #, (, ), ;, @, =, *, +, union, select, drop, update, from, where, join, substr...
상세 코드는 인터넷에 있는 블로그 또는 시큐어 코딩 가이드를 참고해주시기 바랍니다.