프로그래밍 언어/PHP

PHP: 게시판

게시판

해당 포스트에서는 간단하게 게시판을 만들어본다. 누군가 이런 질문을 하곤 한다.

 

게시판만 만들 줄 알면 취업할 수 있는거 아닌가요?

네, 아닙니다. 그렇다면 누구나 개발자로 취직하고 먹고살 수 있었을 것이다. 게시판은 그저 웹 프로그래밍을 시작하면서 그나마 프로그램 다운 프로그램의 첫번째 프로젝트라고 해도 될 것이다. 물론 게시판은 무궁무진하다. 블로그를 포함한 많은 것이 게시판을 기반으로 만들어졌다. 그만큼 게시판이라는 것은 모든 것의 기초이며 많은 것을 만들어 낼 수 있다.

 

우리가 만들 게시판은 그저 포스트를 쓰고, 읽고, 수정하고, 삭제하고, 리스트를 보는 게시판의 아주 기초적인 형태로만 작성할 것이다. 많은 기능을 포함하더라도 게시판의 본질을 파악하면 이를 응용하여 만들어볼 수 있을 것이다.

디렉터리 구조

우리 프로젝트는 아래와 같은 구조를 따른다. 아주 간단하지 않은가.

/
├── index.php
├── create.php
├── read.php
├── delete.php
└── update.php

목록

게시글의 목록을 출력하는 것을 먼저 만들어보자.

index.php

몇 줄의 코드면 끝나지만, 일단 우리 게시판은 데이터베이스를 사용하지 않고, 세션을 공통 저장소로 삼는다. 데이터베이스를 쓰면 본질과 어긋나는 코드가 늘어나기 때문이다. 그래서 저장소를 만드는 코드를 하나 넣는다.

session_start();

if (empty($_SESSION['__storage'])) {
    $_SESSION['__storage'] = [];
}
세션을 사용하면 글도 세션에 저장되므로 다른 이에게 게시글은 보이지 않을 것이다. 하지만 포인트는 그것이 아니다.

데이터베이스를 사용해보고 싶다면, 다음의 글을 보고 응용해보길 바란다.

 

PHP: 데이터베이스 (MySQLi, PDO)

 

PHP: 데이터베이스 (MySQLi, PDO)

데이터베이스 데이터베이스를 사용하는 일은 웹 어플리케이션을 작성한다면 대부분 있는 일이기에 이 부분을 빼놓을 수는 없다. PHP도 물론 오라클이나 MS-SQL 같은 다양한 데이터베이스에 연결��

pronist.tistory.com

자 그럼 이제 게시글을 출력하는 코드를 만들자. HTML 도 같이 사용한다. SSR(Server-Side Rendering)에서는 HTML 코드와 PHP 코드가 섞여있는 경우가 많다. 간단하게 저장소를 대상으로 루프를 돌려 출력하는 코드다. 보이는가? read.php 가 글 읽기 페이지다.

<ul>
    <?php foreach ($_SESSION['__storage'] as $id => $post): ?>
        <li>
            <a href="/read.php?id=<?=$id?>"><?=$post['title']?></a>
        </li>
    <?php endforeach; ?>
</ul>

쓰기

자 이제 게시판에 글을 써보자. 저장소는 이미 만들어두었으니, 저곳에다가 CREATE 를 해주면 된다. 우리는 배열을 사용하므로 그냥 배열에 값만 추가하면 될 것이다.

게시판을 쓰려면 기본적으로 이 필요할 것이다. 더미로 데이터를 만들어서 넣어도 되겠지만, 조금은 일반적일 필요가 있을 것이다. 간단하게 제목과 내용만 넣는 폼이다.

<form action='/create.php' method='POST'>
    <input type='text' name='title'>
    <textarea name='content'></textarea>
    <input type='submit'>
</form>

폼에 대한 더 자세한 이야기를 듣고 싶다면 아래의 글을 참고하자. 참고로 아래의 포스팅에서는 보안에 대해서도 이야기하고 있다. 게시판을 만들때 보안은 반드시 지켜주어야 하는 요소다.

 

PHP: HTML 폼 (GET, POST)

 

PHP: HTML 폼 (GET, POST)

HTML 폼 HTML 폼은 HTTP 요청의 역사에서 오래된 것 중 하나이다. HTTP 요청은 cURL, Ajax 등 다양한 기술로 처리를 할 수 있으나 폼요청은 웹사이트에서 가장 많이 사용하는 요청이자 역사가 오래된 ��

pronist.tistory.com

create.php

filter_input() 과 관련된 함수를 통해 외부에서 날아온 데이터를 검증한다. 데이터를 검증하는 행위는 선택이 아니라 필수다. 사용자는 무슨 데이터를 넣을지 알 수 없다.

 

주목해봐야 할 부분은 배열에 값을 추가하는 부분인데, compact() 함수를 통해 새로운 배열을 만들고 count + 1 에 해당하는 키에 값을 넣는다. 하나를 더해주는 이유는 단순하다. 보통 아이디는 제로 베이스로 사용하지 않으니까. 데이터베이스에서도 대부분 그렇듯 auto_increment 를 통해 사용하는 것을 그럴듯하게 표현해놓았을 뿐이다.

session_start();

[ $title, $content ] = array_values(filter_input_array(INPUT_POST, [
    'title' => FILTER_SANITIZE_FULL_SPECIAL_CHARS,
    'content' => FILTER_SANITIZE_FULL_SPECIAL_CHARS
]));

if ($title && $content) {
    $_SESSION['__storage'][count($_SESSION['__storage']) + 1] = compact('title', 'content');
}

읽기

읽기는 넘어온 쿼리 파라매터에 해당하는 게시글의 키에 매핑된 글을 보여주면 그만이다.

read.php

배열에서 해당하는 키값을 찾아 그것을 보여주자. 아래와 같은 코드를 사용하여 저장소로부터 글을 하나 불러오자. GET 요청을 통해 id 값을 받아올 것이다. 못 찾았다면? 404 를 던지면 그만이다. 어떻게 받아올 것인지는 목록 파트에서 이미 보았지 않았는가?

session_start();

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

if ($id && array_key_exists($id, $_SESSION['__storage'])) {
    $post = $_SESSION['__storage'][$id];
} else {
    return http_response_code(404);
}

출력을 하는 파트는 단순히 HTML 에 해주는 것 뿐이다.

<section>
    <h1><?=$post['title']?></h1>
    </article><?=$post['content']?></article>
</section>

수정

글을 수정하는 것은 읽기와 쓰기가 결합되어 나타난다. 먼저 또한 수정은 폼이 별도로 존재하므로 폼과 데이터를 처리하는 영역이 분리된다.

먼저 수정 폼은 데이터를 서버사이드에서 가져와서 미리 채워놓아야 사용자가 수정하기 편하다. 애초에 수정인데 데이터가 안 채워져 있다면 무슨 의미가 있을까. 따라서 읽기처럼 먼저 데이터를 읽어와야 한다. 데이터를 긁어오는 코드는 읽기와 같다. 그럼 이제 출력만 해주면 된다.

<form action='/update.php?id=<?=$id?>' method='POST'>
    <input type='text' name='title' value="<?=$post['title']?>">
    <textarea name='content'><?=$post['content']?></textarea>
    <input type='submit'>
</form>
action 속성에서 id 를 GET 으로 넘겨주는 것을 잘 관찰하자.

update.php

아래의 코드를 보자. 조건문까지의 전체적인 코드는 사실 쓰기의 코드와 거의 똑같지만, 차이점이라면 저장소에 접근할 때 키를 count + 1 이 아니라 외부에서 받아온 id 를 키로 쓴다는 점이다. 이렇게 하면 내용을 수정(값을 재할당)할 수 있다.

session_start();

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

// Form data ... ($_POST)

$_SESSION['__storage'][$id] = compact('title', 'content');

삭제

이제 글을 삭제하는 것만 남았다. 삭제는 저장소에서 해당 포스트를 날려주면 된다.

delete.php

unset() 언어구조를 사용하여 배열에 있는 요소를 지우자.

session_start();

$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT);

if (array_key_exists($id, $_SESSION['__storage'])) {
    unset($_SESSION['__storage'][$id]);
} else {
    return http_response_code(404);
}

여담

이 포스팅에서 다룬 것은 아주 기초적인 게시판이다. 따라서 다음과 같은 기능이 포함될 수 있다. 게시판도 게시판 나름이다. 조금 더 복잡한 게시판이라면 다음과 같은 것들이 있을 것이다.

 

  • 파일 업로드 드래그 앤 드롭이 있는 게시판.
  • 페이징 무한 스크롤이 가능한 게시판.
  • 다양한 기능이 탑재된 텍스트 에디터를 사용하는 게시판.
  • 태그, 카테고리, 미리보기 등 블로그의 기능을 할 수 있는 게시판.
  • 댓글 대댓글 기능이 있는 게시판.
  • XSS, CSRF, 회원제 등 보안 요소가 결합된 게시판.

위와 같은 기능들은 게시판에서 추가될 수 있는 부가적인 기능들이다. 있어도 되고 없어도 된다. 하지만 게시판 그 자체의 본질을 알아야 위와 같은 요소를 추가할 수 있는 것이다. 예를 들어 댓글 기능이 있는 게시판은 데이터베이스에서 대체로 외래키(FK)를 만들어서 관계를 형성하겠지만, 위와 같이 배열 형태에서도 그냥 2차원 배열로 처리하고 게시글의 id 를 댓글 정보에 넣어두면 연결이 가능하다.

 

 

 

PHP 7+ 프로그래밍: 리부트 - 인프런

기초 문법부터 내장 함수, 웹 보안, 게시판 만들기까지 PHP 언어를 시작하는 분들을 위해 바이블이 될 수 있게 만들어보고자 하는 마음으로 이번 강좌를 만들어보았습니다. 입문 웹 개발 프로그��

www.inflearn.com

 

PHP 7+ 프로그래밍: 객체지향 - 인프런

PHP 객체지향, 내장 클래스, PSR, Composer, MVC(Model, View, Controller)까지 모던 PHP를 익히기 위한 근간을 이야기합니다. 초급 프로그래밍 언어 알고리즘 PHP 객체지향 알고리즘 온라인 강의 모던 PHP 프로��

www.inflearn.com

'프로그래밍 언어 > PHP' 카테고리의 다른 글

PHP: Thread Safe vs Non Thread Safe  (0) 2020.10.28
PHP: PHP 8 기능 정리 및 요약  (1) 2020.09.23
PHP: 게시판  (0) 2020.09.11
PHP: 회원가입과 로그인  (0) 2020.09.02
PHP: PSR(PHP Standard Recommendation)  (0) 2020.08.15
PHP: 의존성 관리자 — Composer  (0) 2020.08.14