PHP+MySQL로 간단한 홈페이지 만들기 - 3편!

 
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 부분에 코드를 카피한 코드였습니다.
 
notion imagenotion image
 
Bootstrap은 위에 나온 설명처럼 세계에서 가장 많이 사용하는 프론트엔드 라이브러리 입니다. 버튼, 메뉴, 폼 등이 이미 구현되어 있고, 마치 레고 조립을 하듯이 웹 서비스를 만들어 낼 수 있습니다. 실제로 조립을 어떻게 할 수 있는지를 보도록 할게요.
 
  1. Examples를 클릭해주세요.
    1. notion imagenotion image
  1. 많은 예제가 있는데, 저는 Carousel을 클릭하도록 하겠습니다.
    1. notion imagenotion image
  1. 크롬에 개발자 도구를 열어주세요. 윈도우는 Ctrl + i입니다.
    1. notion imagenotion image
  1. 아래 마우스 버튼을 클릭해주세요.
    1. notion imagenotion image
  1. 메뉴에 마우스를 오버하고 아래와 같이 나오셨다면 클릭하세요.
    1. notion imagenotion image
  1. Ctrl + C를 눌러 코드를 가져오세요. 그리고 우리가 가진 코드 body 태그 바로 아래 배치해주세요.
    1. notion imagenotion image
 
자, 여기까지 전체 코드입니다. 그리고 실행시켜보세요.
<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를 천천히 따라해 보시는 것을 추천해드립니다.
 
notion imagenotion image
 
조금 더 고쳐 아래 처럼 코드를 입혔습니다. 물론 margin을 주는 방법이 아래와 같이 별도로 정의되어 있지만, 이해하기 쉽도록 직접 태그에 부여하였습니다.
 
 
기본적으로 Bootstrap은 전체 웹 서비스를 row(행)로 나누고 각각 행에 12개의 column(열)으로 나눠 홈페이지를 만드는 개념입니다. 아래 이미지를 참고해주세요. 물론 아래처럼 검은색 실선이 그려지는 것은 아닙니다.
 
notion imagenotion image
 
상세 내용은 아래 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>
아래 화면은 실행 화면입니다. 어떤가요? 조금 더 홈페이지 같아졌죠?
notion imagenotion image

2. 무료 템플릿 입히기

홈페이지를 일일이 꾸며줄 수도 있지만, Bootstrap 무료 템플릿을 사용하여 홈페이지를 꾸밀 수 있습니다.
Google에서 Bootstrap 무료 템플릿을 검색해주세요. 무료 템플릿을 다운로드 받아 서버에 업로드 하세요. 아래 사이트를 추천합니다.
 
많은 테마 중에서도 깔끔한 아래 태마를 추천해드립니다.
 
아래 창에서 Free Download를 클릭하시면 전체 코드를 다운로드 받으실 수 있습니다. 구름IDE에 업로드를 하실 때에는 꼭 전체 폴더를 함께 업로드 하셔야 합니다. HTML, CSS, JS, 이미지와 폴더 모두요.
 
notion imagenotion image
 
저는 압축파일을 업로드해서 구름IDE에서 압축을 풀도록 하겠습니다. 최상이 폴더를 클릭하시고 마우스 오른쪽 버튼을 클릭하신다음 가져오기 > 파일을 클릭해주세요.
 
notion imagenotion image
notion imagenotion image
notion imagenotion image
 
터미널 창( > 새 터미널 창)에서 아래 코드를 실행해주세요. 파일을 더블클릭하셔도 파일이 압축이 풀립니다.
unzip startbootstrap-clean-blog-gh-pages.zip
 
notion imagenotion image
 
드래그엔 드롭을 통해 최상이 폴더로 해당 파일들을 모두 올려주세요. 아래처럼 폴더트리가 만들어져야 합니다. (폴더 밖으로 모든 요소를 꺼냈고, 해당 폴더를 삭제하였습니다.)
 
notion imagenotion image
 
자, 이제 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 &rarr;</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 &copy; 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>
 
notion imagenotion image
 
완성된 코드는 아래 링크에서 다운로드 받을 수 있습니다.
 
핵심 코드는 아래와 같습니다. 나머지는 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에 다른 값들도 볼 수 있습니다.
notion imagenotion image
 
 
이번에는 아래와 같이 입력해보세요.
%' union all select id, id, id, id from testtable where description like '%
 
notion imagenotion image
 
전혀 새로운 값들이 검색이 된 것을 볼 수 있습니다. 이제 검색에 없던 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 '%
 
notion imagenotion image
 
만약, 아래와 같이 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 '%
 
notion imagenotion image

4. SQL Injection 방지

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