웹서버를 만들자~ ::: 윈도우용 APM 설치하기

웹서버를 만들자~ ::: 윈도우용 APM 설치하기

PHP를 실행할 수 있는웹서버가 필요합니다.

리눅스 또는 유닉스 계정을 가지신분은 상관없지만.. (만약 그 서버에 PHP가 깔린 상태라면)

계정이 없으신 분은 웹서버를 구하시거나 아니면 자신의 컴퓨터에 웹서버를 만들어야 합니다.

웹서버니 유닉스니 하는 말을 모르시는 분과 웹서버를 가지고 계시지 않은 분은 다음 절차에 따라

자신의 컴퓨터에 웹서버를 설치하십시오. (권장)

1. 다운로드 --- 다운로드 합니다.
(이 프로그램은 리사파파님께서 만드신 WINAPM 1.1 설치버전입니다.)

2. apmsetup.exe 파일을 더블 클릭합니다.

* 예를 클릭합니다.

* 자동으로 설치가 됩니다. 설치장소는 C:\usr입니다. 이 디렉토리여야만 제대로 작동합니다.

* 경고창이 뜹니다. 잠시후에 뭔 이상한 창이 하나 뜰지도 모른다는 군요..^^;; 광고창 아니니 닫지 마세요.

* 어랏! 창이 하나 뜬다는데-_-;; 두 개가 뜨더니 하나는 사라져 버렸어요~ 어떻해요~~~~ ㅜ_ㅡ
위 창은 아파치(웹서버)가 동작중이라는 표시입니다.(닫으면 웹서버가 종료된답니다.)
사라진 창은 MySQL을 동작 시킨 창이죠. <== 원래 사라짐.. ^^ 걱정마세요.

* 설치가 다 되었습니다. 완료를 누르세요.

* 설치가 제대로 되었다면 다음과 같은 창이 뜨게 됩니다.

* 아파치 시작,종료 (웹서버를 시작,종료)

* MySQL 시작,종료 (데이터베이스 시작,종료)

* NT Service 는 WindowsNT,Windows2000,WindowsXP 인 경우 아파치를 서비스에 등록

하여 부팅시에 자동으로 아파치를 시작해 주는 기능입니다.

위 프로그램으로 설치 하셨다면 NT 계열의 컴퓨터에는 자동으로 등록합니다.

Windows98,ME 는 사용하 실 수 없습니다. (^^ 차별대우~가 아니라 어쩔 수 엄써여)

시작하는 방법은?

처음 인스톨시에는 테스트를 위해 제가 자동으로 아파치를 띄워드렸습니다.

그러나 다음부터는 자동으로 안뜨겠죠.

Windows98,ME 인 경우에는 MySQL 시작 누르고 아파치 시작 누르면 됩니다. (순서는 상관없음)

NT 계열이라면? 아까 위에서 자동으로 아파치를 띄워준다고 했으니 당연히 MySQL 시작만..

성공적으로 설치가 되었다면 다음과 같은 창이 하나 뜹니다. (98,ME만..)

NT 계열은 다음 부팅부터는 이 창을 안띄워도 자동으로 아파치가 실행됩니다.

이 창이 떠 있다는 것은 이제 우리 자신의 컴퓨터가 웹서버가 되었다는 것을 의미합니다.(98,ME)

웹 브라우저를 띄우신다음에 주소창에 http://localhost 라고 입력해보세요.

그러면 다음과 같은 화면이 나타납니다.

이제 왜 설치할 때 여러 창이 떠있었는지.. 왜 창을 닫아선 안되는 것이 있는지 아시겠죠? ^^

위 프로그램의 디렉토리

C:\usr (설치 디렉토리)

C:\usr\www 디렉토리가 홈디렉토리(홈페이지의 파일들이 있는)입니다.

여기다가 홈페이지를 만들 때 처럼 HTML 문서나 이미지 파일 등을 넣어두시면

localhost 라고 쳤을 때 보이게 됩니다.

( localhost라는 것은 자신의 컴퓨터라는 뜻으로 다른 사람에게는 적용되지 않습니다. )

이제 테스트도 끝나고 했으니 웹서버를 닫아 봅시다.

좀전에는 시작을 눌렀으니 이제는 종료를 누르면 되겠죠?

그러면 좀전에 떠 있던 창이 자동으로 닫혀집니다.

(NT 서비스로 등록하신분들은 별도의 작업이 필요없습니다.제어판->관리도구->서비스 에서 종료할 수 있습니다.)

굉장히 많은분이 PHP는 어떻게 테스트 하나요 하고 질문하셔서 이렇게 인스톨 가이드를 만들었습니다.

이 방법이 유일한 것은 아닙니다.


웹서버를 만들자~ ::: LINUX용 APM 설치하기

강좌 2. 웹서버를 만들자~ ::: LINUX용 APM 설치하기

리눅스에 APM을 설치하는 법을 배워보겠습니다.
윈도우에 APM을 설치하는 법이 여러 가지가 있듯이 리눅스에 설치하는 법도 여러 가지가 있는데요.

편의를 위해 김 호 규(dark1458@hotmail.com) 님께서 만드신 쉘스크립트를 이용해서
자동으로 설치하는 법을 소개해 드릴까 합니다.

일단 리눅스 서버를 소유하고 계시거나 아니면 관리자에 접근할 수 있는 사람이라는 뜻이니
리눅스에 대해 약간의 지식을 가지고 계시다는 전제하에 시작하겠습니다.
(참고로 레드햇 9 버전에서는 자동으로 설치되지 않을 수 있습니다.)

설치 파일 다운로드

  • 아파치 다운로드 --- 버전 1.3.27
  • PHP 다운로드 --- 버전 4.2.3
  • MySQL 다운로드 --- 버전 3.23.54
  • Zend Optimizer 다운로드 --- 버전 1.3.3
  • IMAP 다운로드
  • 자동설치 스크립트 다운로드

파일을 리눅스 서버에 다운로드 하여 /usr/local/src 디렉토리에 저장합니다.

아래의 모든 작업은 관리자의 권한이 있어야 합니다.

리눅스의 root 계정으로 로그인하여 시도하세요~

이미 설치된 APM 패키지 제거하기

[root@ezphp root]# rpm -qa | grep mysql
[root@ezphp root]# rpm -qa | grep apache
[root@ezphp root]# rpm -qa | grep php
[root@ezphp root]# rpm -qa | grep imap

위에서 하나라도 검색되는 값이 있다면 해당항목을 지우세요.

[root@ezphp root]# rpm -e --nodeps mysql
[root@ezphp root]# rpm -e --nodeps apache
[root@ezphp root]# rpm -e --nodeps php
[root@ezphp root]# rpm -e --nodeps imap

본격적으로 APM 설치하기

[root@ezphp root]# cd /usr/local/src
[root@ezphp  src]# ls
APMimapZend_AutoSetup.sh                                 imap-2001a.tar.Z
ZendOptimizer-1[1].3.3-Linux_glibc21-i386.tar.gz         mysql-3.23.54a.tar.gz
apache_1.3.27.tar.gz php-4.2.3.tar.gz
[root@ezphp src]# chmod 705 APMimapZend_AutoSetup.sh
[root@ezphp src]# ./APMimapZend_AutoSetup.sh

주루루루루루루룩~~~~~~~~~~~~~ 이상한 글자들이 뜹니다.
여유롭게 커피한잔 마시고 신문한번 쓰윽 훓어보고 오세요~

------------- 음 아직도 주루루루룩~~~ --------------
컴퓨터 성능이 의심스럽군요. ㅋㅋ 성능이 좋으면 빨리되요~

그동안 컴퓨터만 바라보다가 가족들과의 대화가 끊어졌었죠?
지금 당장 어머니에게 달려가서 "엄마~ 내끄야~ 사랑해~♡"
라고 말하세요. 안그러면 안깔릴거예욧~!! ㅋㅋㅋ

사랑하는 따뜻한 마음이 있으니 뭔가 변했어요~ 감동먹었나봐~

####################################################################
#                                                                  #
# 에러 방지를 위해 계정을 생성합니다.                              #
# mysql이란 계정을 생성 하였습니다. 비밀번호를 입력하세요.         #
# 경로는 /home/mysql 이지만 보안상 삭제 합니다.                    #
# 시스템 시작시 mysql의 소유권으로 데몬이 시작됩니다.              #
#                                                                  #
####################################################################

MYSQL 계정의 비밀번호를 넣어주세요.

Changing password for user mysql.

New password:

mysql 비밀번호를 넣어달라는군요. ^^
조금 복잡한 비밀번호를 넣어주세요~.
그래두 명색이 관리자인데..1111 이러면 섭해요~ >_<

bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
news:x:9:13:news:/etc/news:mysql:x:502:2001::/home/mysql:/bin/bash

주욱 내려가보면...  mysql 이라는게 보여요~~

mysql:x:502:2001::/home/mysql:/bin/bash <-- /bin/bash를 /sbin/nologin 으로 변경

"/etc/passwd" 48L, 2222C

수정했으면 저장하고 나오세요~ (vi 에디터에서 나오는법 아시죠? ESC :wq 입력하세요.)

#!/bin/sh
# Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
# This file is public domain and comes with NO WARRANTY of any kind
# MySQL daemon start/stop script.
# Usually this is put in /etc/init.d (at least on machines SYSV R4 based
# systems) and linked to /etc/rc3.d/S99mysql and /etc/rc0.d/K01mysql.
# When this is done the mysql server will be started when the machine is
# started and shut down when the systems goes down.

이번꺼는 아까꺼보다 더 기네요..에휴~~

134라인쯤까지 찾아가보세요~ ^^
헉~ 어떻게 134라인까지 찾아가냐구요? 일일이 세어가면서? ㅜ_ㅜ
그럴 필요없구요. 134 라고 치고는 엔터를 눌러보세요.
134라인으로 숑~~~ 하고 가 버리네요.

:set nu 라고 치면 라인번호가 나온답니다.~~ 리눅스 팁하나~

 $bindir/safe_mysqld --datadir=$datadir --pid-file=$pid_file &

요놈을 아래처럼 변경합니다.--language=korean을 추가하면 되죠? ^^
$bindir/safe_mysqld --pid-file=$pid_file --datadir=$datadir --language=korean &

수정했으면 저장하고 나오세요~ (^^ 이젠 아시죠? ^^)

오~~~ 저장하고 나오니 또 주루루루룩 나오는군요~~
기지개나 한번 쭉 펴봅시다~

어깨도 한번 휙휙~ 돌려보고~ 목도 좀 풀어보고~

또 새로운 창이 떴군요. Zend Optimizer를 설치하려고 하네요.
Zend Optimizer 는 PHP의 성능을 높여주는 프로그램입니다. ^^
이제부터는 OK 만 누르면 만사 OK~

OK~

O~~~~K~~

헉 이번엔 Yes네..^^;;;

Yes~

Yesssssss~

오~ 성공적으로 설치가 다 되었다는군요~ (물론 Zend 설치가..ㅋㅋㅋ)

#############################################################
#
#         MySql의 비밀번호를 rootroot로 변경합니다.
#
#############################################################

데이터베이스 관리자 암호가 rootroot 로 변경되었다는군요.

901 ?        S      0:00 /bin/sh /usr/local/mysql/bin/safe_mysqld --user=mysql
966 ?        S      0:00 /usr/local/mysql/libexec/mysqld --basedir=/usr/local/

#############################################################
#
#     mysqld & httpd 데몬이 보이는가요? 위에 보이죠? ^^
#     Mysql DB의 비밀번호를 rootroot 로 변경하였습니다.
#     Mysql의 비밀번호를 변경하세요.
#
#     mysqladmin -u 아이디 -p비번 password 바꿀비밀번호
#
#     브라우저 주소줄에 아래내용을 입력하세요.
#
#     http://127.0.0.1
#
#
#                       2003년 2월 7일
#
#     Write by 김 호 규    Mail : dark1458@hotmail.com
#
#############################################################"

[root@ezphp root]#/usr/local/mysql/bin/mysqladmin -u root -p rootroot password 새암호

마지막에 mysqladmin을 이용하여 새 비밀번호를 바꾸셨나요?
그럼 설치가 다 되었습니다.~~ 짝짝짝~~

브라우저를 띄우고 http://localhost 라고 입력해보세요~

수고하셨습니다~~~ (- -) (_ _)


PHP는 어떻게 짤까? ::: 에디터 설치하기

강좌 3. PHP는 어떻게 짤까? ::: 에디터 설치하기

PHP는 무엇으로 프로그램을 짜느냐?

단도 직입적으로 말씀드리면 텍스트에디터만 있으면 됩니다.

텍스트에디터란 말 그대로 글을 쓰고 수정하고 저장할 수 있는 프로그램을 말합니다.

즉, 메모장 같은 프로그램을 말합니다. ( 겁나게 둘러서 말했군요..^^ )

그런데.. 메모장은 소스가 짧을 때는 고치기 쉽지만..

소스가 굉장히 길어지면 상당한 불편을 느끼게 됩니다.

그러면 어떤 텍스트 에디터가 좋은 에디터인가?

이 문제는 한마디로 말씀드리기가 정말 힘듭니다.

왜냐하면 프로그래머마다 취향이 약간씩 다르기 때문이지요.

많은 프로그램을 이용해 보고 자신에게 맞는 프로그램을 찾는게 제일 좋은 방법입니다.

1. 찾기와 찾아서 고치기 기능이 있는 에디터

2. 구문 강조 기능이 있는 에디터 ( 구문 강조는 함수 명령등을 다른 색깔로 자동 표시해주는 기능을 말합니다. )

3. FTP 연결을 통한 수정, 저장 기능이 있는 에디터

4. 실행 취소와 다시 실행이 횟수에 상관없이 자유로운 에디터

5. 소스 앞에 몇 번째 줄인지 표시가 되는 에디터

이 다섯가지 기능을 가진 에디터라면 PHP 프로그래밍을 하는데 어떤 무리도 없을 것입니다.

가장 많은 사람이 쓰는 텍스트에디터는 무엇일까?

제가 뭐 시장조사를 해본 것은 아니지만..

울트라 에디트 (Ultra Edit) 란 프로그램이 가장 많은 사람이 애용하는 프로그램인 것 같구요,

에디트 플러스 ( EditPlus) 란 국산 프로그램도 굉장히 많은 인기를 끌고 있습니다.

(참고로 저는 울트라 에디트 보다는 에디트 플러스가 맘에 들더군요..^^ )

텍스트에디터 설치 및 세부 설정 방법

저는 에디트 플러스를 쓰기 때문에 에디트 플러스에 대해서만 말씀드리겠습니다.

다른 프로그램도 쉽게 인스톨해서 쓸 수 있으니 취향에 따라 골라서 써보도록 하세요^^

참고로 에디트 플러스는 쉐어웨어입니다. ( 정품 등록시 29,700원 )

다음 절차에 따라 에디트 플러스를 인스톨 합니다.

1. 다운로드 1 , [image] 다운로드 2 둘 중에 아무거나 다운로드합니다.

2. ep2setup.exe 란 파일을 더블 클릭합니다. ( 다운로드된 파일, 약 910kb )

setup을 눌러 인스톨을 시작합니다.

언어를 선택합니다. ^^ 영어가 익숙하신 분은 영어로..~ ^^;;;;

사용권 계약서를 한번 읽어봅니다. ^^ 저기 평가와 등록에 뭔가 써있네요.. 무료 소프트웨어가 아니라고..

동의 하시면 예를 누릅니다.

설치할 디렉토리는 자동으로 program Files 디렉토리로 지정됩니다. 다른 디렉토리로 저장하시려면

설치 디렉토리를 바꾸면 되겠죠?

( 근데 왠지 저의 속살을 보인 기분이 드네요.. ^^;;; 알집, 데이터맨. ^^;;; 별개 다 깔려있네.. ^^ )

윈도우 메뉴에 등록하는 부분입니다. 저는 이미 깔려 있어서 이미 보이네요..^^

( 이번에도 속살을... ^^ )

이제 설치가 되었습니다.

설치가 되면 다음과 같은 화면이 뜹니다.

자 그럼 이제 설정에 들어가 보도록 하겠습니다.

저는 원래 디폴트 설정보다 많이 바꿔서 쓰고 있는데..

대부분이 저의 개인적 성향에 따른거라 한가지만 추가 설정하시면 될겁니다..^^

설정에 앞서서 파일하나를 만들어 보도록 하죠..

그림과 같이 보통 문서를 선택합니다.

(단축키 몇 개는 좀 외워두시는 것이 훨씬 편리할 겁니다. 스타크래프트 단축키의 반만 외워도 충분^^ )

보통문서를 누르면 하얀색 창이 뜨는데.. 거기다가 위 그림과 같이

<?php ?> 라고 씁니다..

그리고 위에 디스켓 모양의 버튼이나 컨트롤 + S 를 눌러 저장을 합니다.

저장시 C:\Program files\Editplus 2 라는 디렉토리에 저장하게 되는데..

파일 이름을 template.php 라고 정해 저장합니다.

문서 템플릿 구성을 선택하면 다음과 같은 창이 뜹니다.

추가 버튼을 누른다음 메뉴 제목에 php 라고 적고

파일 경로 오른쪽에 있는 ... 버튼을 눌러서 좀전에 만들어둔 template.php 파일을 선택합니다.

확인 버튼을 눌르고 나면 다음과 같이 새 파일에 PHP라는 메뉴가 생기게 됩니다.

다음부터 PHP 문서를 만들 때는 저 메뉴를 선택해서 작성합니다.

그러면 함수부분 등이 구문강조가 되어 프로그램 짤 때 보다 쉽고 편리하게 작성할 수 있게 됩니다.

에디트 플러스에는 많은 기능이 있는데..

이 기능들은 한번씩 써보면 쉽게 익힐 수 있으니 아무거나 한번씩 눌러보면서

무얼 하는 기능인지 한번 확인해 보시기 바랍니다.

이제 텍스트 에디터를 다 깔았는데 그 다음은 어떻게 하죠?

이제 위에서 만든 PHP 메뉴를 이용해 거기다가 소스를 적어가면 됩니다.

저장할 때는 파일의 확장자가 php 나 html 로 저장합니다. ( 예) test.php , test.html 등등

텍스트 에디터로 저장한 PHP 문서는 어떻게 테스트를 할 수 있나요?

다음 강좌에 궁금증을 풀어 드리겠습니다. ^^


PHP 환경 테스트 ::: 준비 됐나~? 준비 됐~다!

강좌 4. PHP 환경 테스트 ::: 준비 됐나~? 준비 됐~다!

이제 테스트를 위한 환경이 모두 만들어 졌습니다.

프로그래밍을 할 에디터도 하나 구했고..

짠 프로그램을 테스트할 웹서버도 깔았습니다.

그럼 오늘은 직접 짠 소스를 테스트 해봐야겠죠?

이미 깔려진 APM 프로그램을 띄웁니다. ( 아파치 시작(98,ME), MySQL 시작 )

웹 브라우저에 localhost 라고 치면 아래와 같이 나옵니다.

자 이제 이 파일을 고쳐 보겠습니다.

C:\usr\www 디렉토리가 홈디렉토리입니다.

저 디렉토리로 한번 가볼까요?

index.html 이라는 파일이 있죠? 이 파일이 기본적으로 세팅되어 있는 시작파일입니다.

http://localhost/index.html 의 경로를 가지지만 기본 세팅상에서

http://localhost/ 라는 디렉토리만 쳐도 자동으로 index.html 이 인식됩니다.

http://localhost/test/index.html 은 http://localhost/test/ 와 똑같은 결과를 가져옵니다.

이해가 되시죠??

그럼 본격적으로 이 파일을 고쳐보도록 하겠습니다.

에디터에 저 파일을 불러 들입니다. ( 위와 같이 되겠져? )

위에 쓰여진 많은 글자들을 다 지워 버리고.. 아래와 같이 적습니다.

<?
    echo "첫번째 프로그램";
    echo "아싸~";
    echo "날짜 : " . date("Y-m-d");
?>

자 결과는?

음... PHP가 잘 돌아 가는 군요...

PHP 세상에 오신걸 환영합니다.

이제 여러분은 PHPer가 되셨습니다.

기분이 어떠신가요?

들뜨시나요? ( 아주 좋은 마음가짐입니다. )

조금 두려우신가요? ( 절대 두려워 할 것이 못됩니다. 자신감을 가지세요 ^^ )

PHP는 많이 어려운가요?

PHP는 어렵고 난해한 프로그래밍 언어가 아닙니다.

절 아는 사람들이 가끔 저에게 이렇게 질문을 하곤 합니다.

"PHP가 좋다던데 어떻게 공부하느냐... 어떤 책이 좋으냐...?"

제가 생각하기에는 공부 방법이나 책 어느 것도 그리 중요하지 않다고 봅니다.

제 주변의 많은 분들도 그저 저의 말에 따라 책만 사놓고 몇페이지 보다가는

" 어려워서 못하겠다.." 고 포기하고 말더라구요..

이런 분들은 PHP가 정말 어려워서가 아니라 시작할 때부터 맘에 두려움을 가지고 시작했기 때문입니다.

제가 " 자신감을 가지고 한번 무작정 도전해 보세요~ PHP는 정말 쉬워요.. " 하고 말을하면

정말 많은 사람들이 "원래 어느 정도 터득한 사람은 항상 저렇게 말하곤 한다" 며 고개를 저어대곤 했습니다.

물론 컴맹이 PHP를 바로 시작하는 것은 불가능하죠..

기본적인 툴도 다룰줄 모르는데 프로그래밍이라니..

그러나 컴퓨터를 좋아하고 컴퓨터와 친하게 지내는 사람이라면 충분히 소질이 있다고 생각하시면 됩니다.

PHP는 누군가 가르쳐주는 것을 익힌다고 되는 것이 아닙니다.

PHP는 자신이 스스로 공부하는 것입니다.

가끔 질문하시는 분들을 보면 하나에서 열까지 모두 가르쳐주기를 바라는 분들이 계십니다.

좀 냉정하지만 이런 질문은 거절합니다.

제가 PHP를 처음 시작했을 때 너무 모르는게 많아서 무작정 사람들에게 물어 보기 시작했습니다.

이게 머예요? 저게 뭐예요? 하는 식으로요..

메일도 보내보고 게시판에 글도 써봤지만 답변을 잘 안해 주시더라구요..

저는 그래서 오기로 이책 저책 찾아보고 인터넷도 뒤지고 하면서 나름대로의 해답을 찾았습니다.

그러고나서 사람들에게 다시 질문했죠..

"이건 어떤 원리인거 같은데 저는 이렇게 했거든요. 그런데 잘 안되네여. 혹시 이런 이유 때문인가요?"

이렇게 질문하니까 아주 친절한 말투로 질문한지 얼마 지나지 않아 답이 오곤 했습니다.

제가 어느정도 자신감이 생기고 누군가의 질문에 답을 할 수 있는 위치가 되었을 때..

누군가가 제게 "이게 머예요?" 하고 물었습니다.

처음에는 상세히 알려주곤 했는데..

시간이 지나니까 좀 짜증이 나더군요..

누워서 얻어먹으려고만 하는 것 같아서요..

제가 이야기 하나 해드리죠.. 언젠가...

제 친구 중에 한명이 PHP를 한다고 하루종일을 꼬박 컴터 앞에 앉아 있더라구요..

옆에 보고 있기가 뭐해서 도와줘야지 하고 친구에게 갔는데..

자기가 물어 볼 때까지는 어떤 도움도 주지 말라고 당부를 하더군요..

그래서 그냥 옆에서 친구가 하는 것을 물끄러미 보고만 있었는데..

밤이 늦어서야 질문을 하더라구요.. 도저히 왜 안되는지 모르겠다고..

그런데 그 녀석 끝까지 고집이더군요.. 해답은 싫으니까 힌트만 달라는 거 있죠..

그 녀석은 이틀만에 광소(정말 광소였음.. ㅡㅡ;; 뽀하하뿌헤헤크크헤케케 ㅡㅡ;;;; )를 터트렸습니다.

3일째 되던 날부터 인터넷에서 자료를 찾아서 MySQL 공부를 하더니..

MySQL을 이용한 북 마크 프로그램이라면서 제게 보여주더군요..

담번엔 방명록을 만들겠노라 하면서 말이죠..

저는 그녀석이 천재라고는 생각지 않습니다. (절대 아니죠 ㅡㅡ;; )

그 녀석은 그저 남들보다 PHP를 하고 싶은 열정이 많았을 뿐입니다.

PHP를 모두 배우는 데에는 정말 많은 시간이 듭니다.

한달 두달 가지고는 어림 반푼어치도 없죠..

그러나 왠만한 프로그램 하나 짜는데에는 그리 많은 시간이 필요 없습니다.

그러나 누워서 받아먹기만 하는 사람은 스스로 공부하는 사람보다 몇배 또는 몇십배 차이가 나겠죠.

오늘은 정말 사설이 길었습니다.

실질적으로 PHP 뿐만이 아니라 다른 언어나 스크립트도 마음가짐이 제일 중요합니다.

위에 예를든 친구 말고도.. 예전 홈페이지에 쓰던 게시판을 만드는.. ICAN 이란넘도..(2000년기준^^;;)

몇 달 전만해도 PHP가 어려울거 같아서 손도 못대던 넘이었습니다.

제가 하도 PHP 공부좀 해라 해라 해서 마지 못해 시작하더니..

며칠 있다가 "PHP 정말 쉽네..." 라고 하더라구요..

아마 지금이 PHP 배운지 두달정도? 많아도 3달 될까 말까 할겁니다.

여러분도 자신감을 가지고 열심히 해보세요..

분명 좋은 결과가 있을겁니다.


PHP 입문 ::: PHP는 어떻게 돌아가지?

강좌 5. PHP 입문 ::: PHP는 어떻게 돌아가지?

HTML 밖에 모르는 웹 브라우저 ?

HTML밖에 모르는 웹 브라우저라.... (물론 약간은 틀린 말입니다.)

바꿔서 말씀드리면 웹 브라우저는 HTML밖에 알아 듣지 못한다는 소리입니다.

HTML이 브라우저가 쓰는 언어라는 것이지요(요즘 브라우저는 약간의 외국어(자바스크립트 등)도 합니다.^^;;)

그래서 우리가 홈페이지를 만들려면 모든 문서를 HTML로 작성해야만 합니다.

HTML을 울려 버린 CGI의 등장

인터넷 초창기에는 대부분의 홈페이지가 모두 HTML로 만들어져 있었습니다. (선택의 여지가 없었죠)

HTML로 홈페이지를 만들어 보신 분은 아시겠지만 ...

HTML은 일방향적이고 수정하기 전에는 절대 변하지 않는 특성을 가지고 있습니다.

이러한 단점 때문에 사람들은 HTML 말고 다른 무언가가 필요함을 느꼈습니다.

그래서 생겨난 것이 바로 CGI (Common Gateway Interface)입니다.

CGI는 위와 같은 구조를 가지는데.. ( HTML은 1과 4의 과정만 있음 )

보시는 바와 같이 HTML 보다 한단계 더 처리를 함으로써 계산과 처리 기능이 추가되었습니다.

이로인해 우리는 정적인 변화 없는 웹 페이지에서 변화가 자유롭고 방문자와 홈페이지 제작자간에

서로 상호작용이 가능한 웹 페이지를 만들 수 있게 된 것입니다.

그러나 여기서 주의해야 할 점은 3번에서 보듯이 CGI로 처리된 값은 HTML로 전송되어 집니다.

웹 브라우저는 HTML밖에 모르니 HTML로 바꿔서 보여줘야 하는 것입니다.

( PHP를 하려면 당연히 HTML을 알고 있어야겠죠? )

그러면 CGI와 PHP는 어떤 관계인가?

PHP는 일종의 CGI라고 볼 수 있습니다.

물론 약간 다르기는 하지만요...

( 다른 점은 프로세스니 모듈이니 하는 말을 해야 하기 때문에 생략합니다. )

그래서 PHP도 저 위의 그림과 비슷한 구조를 가집니다.

HTML에 없는 계산 , 처리과정이란 도대체 어떤 것일까?

굉장히 많겠지만 지난시간에 테스트를 위해 만든 소스를 다시 이용해 보죠..

소스

<?
    echo "첫번째 프로그램";
    echo "아싸~";
    echo "날짜 : " . date("Y-m-d");
?>

이 소스는 2003년 4월 4일날 아래와 같은 결과였습니다.

그러나 똑같은 소스를 4월 5일에 똑같이 실행시켰는데.. 아래와 같은 결과가 나오네요..

이와같이 PHP는 사람이 바꾸지 않아도 알아서 처리하여 표시해 주는 것입니다.

여기에는 date 라는 날짜를 표시해주는 함수와 echo 라는 텍스트를 뿌려주는 함수 둘이 사용되었습니다.

위에서 말했듯이 우리는 결과를 HTML로 돌려주어야 한다고 했습니다.

위의 결과에 대해 소스보기를 하면...

첫번째 프로그램아싸~날짜 : 2003-04-05

이렇게 출력되어집니다.

위의 PHP코드는 일련의 처리과정을 거쳐 PHP 코드를 모두 지워 버리고

단지 HTML 코드만을 전송한 것이지요.

만약 PHP가 없었다면....

홈페이지에 날짜 표시 기능을 달기 위해서는

매일 매일 홈페이지에 들러서 제일 먼저 오늘의 날짜를 고쳐야 하는 수고를 했을 것입니다.

( 물론 자바 스크립트로 표시할 수 있기는 합니다. 허나 약간의 차이는 있음 )

물론 게시판 같은 것은 꿈도 못 꾸었겠죠..

이제부터 고민해야 할 것...

이제부터는 PHP 함수등을 배워가면서 어떻게 그 결과를 HTML로 뿌려줄 수 있느냐를 고민하는 것

그것밖에 남지 않았군요..


PHP 입문 ::: PHP는 무엇인가?

강좌 6. PHP 입문 ::: PHP는 무엇인가?

PHP는 무엇인가?

PHP (공식적 PHP Hypertext Preprocessor) 는 Server - side HTML-embedded 스크립트 언어입니다.

즉, PHP는 서버에서 실행되며 HTML을 포함한 스크립트 언어라는 말입니다.

HTML을 PHP 확장자 (.php )로 저장하여도 아무 지장없이 사용할 수 있습니다.

예제의 결과 ) /lect/39/example1-1.php

위처럼 보통 HTML 태그 사이에 특별한 PHP 시작과 끝 태그를 이용하여 HTML과 PHP를 구분합니다.

1 - 5 , 7 - 8 줄까지는 HTML로 인식하고 6번째 줄은 PHP 모드로 바뀌어 처리됩니다.

PHP는 무엇을 할 수 있는가?

PHP는 가장 기초적으로 어떤 CGI 프로그램을 만들 수 있고 다이나믹한 웹페이지를 만들 수 있습니다.

무엇보다도 PHP의 가장 두드러진 특징이라고 말할 수 있는 것은 매우 다양한 데이터베이스를 지원하고

또한 데이터베이스를 이용한 웹페이지를 만드는 작업이 놀랄 만큼이나 쉬어졌다는 것입니다.

아래는 PHP가 지원하는 데이터베이스입니다. ( 엄청나게 많죠.. 자주쓰는건 다섯손가락 안에 드네요. )

Adabas D InterBase Solid dBase mSQL Sybase

Empress MySQL Velocis FilePro Oracle Unix dbm

Informix PostgreSQL

그리고 PHP는 여러 프로토콜 ( POP3 ,NNTP ,IMAP 등 )을 이용할 수 있고 네트워크 소켓도 사용할 수 있습니다.

^^ 뭔말인지는 몰르겠지만... 암튼 무지무지 여러 가지 기능이 있구나~ 하고 생각하시면 됩니다. ㅋㅋㅋ

PHP의 간결한 역사

1994 by Rasmus Lerdorf ( mailto:rasmus@php.net )

( 정말 간결하죠? 그래두 핵심적인 부분이라우~ 1994년에 Rasmus 라는 사람이 맹글었음 )

오늘은 이렇게 간단하게만 하고 내일부터 PHP 기초 문법에 들어가겠습니다.


PHP 기초 문법 ::: 말을 배워보자~

강좌 7. PHP 기초 문법 ::: 말을 배워보자~

HTML 모드에서 PHP모드로 빠져 나오기

지난 강좌에서 말씀 드렸듯이 PHP는 HTML을 포함하고 있습니다.

그렇기 때문에 이 부분이 HTML 부분인지 PHP 부분인지 구분할 필요가 있죠.

PHP 모드로 빠져 나오는 방법에는 4가지가 있습니다.

가장 간단하면서 일반적인 방법인 1번 "<?" ( PHP의 시작), "?>" ( PHP의 끝 )

1번이 안될 경우에는 2번을 쓰세요.

3, 4번은 PHP 컴파일시에 추가하셔야만 쓰실 수 있습니다.

PHP에서 한 줄의 끝 구분하기

; (세미콜론) 이 그 줄의 끝임을 구분해 줍니다.

<?
    echo "테스트 입니다.";
?>

<? echo "만약 세미콜론이 없다면?"
    echo "이렇게 하면 에러가 나겠지요? 한줄에 두개의 커맨드가 올수는 없습니다."
?>

<? echo "그러나 이렇게 하면 됩니다."; echo "우리가 보는 엔터는 PHP에서 무의미 합니다.^^"; ?>

<? echo "한줄인 경우에는 세미콜론(;)을 하지 않아도 됩니다." ?>

닫는 태그(?>) 에는 세미콜론(;) 이 포함되어 있다고 보시면 됩니다.

위 소스는 다음과 같이 에러 메시지를 띄웁니다.

소스 코드의 6번째 줄이 틀렸다는 소리죠.. (대부분의 경우 6번째줄이 틀렸다고 하면 5,6,7줄을 보면 됩니다.)

PHP 자체 문법 체크에서 콤마(,)나 세미콜론(;)이 빠졌을 것 같다고 알려주네요.

정말 프로그램을 짜다보면 자주 보는 에러가 아닐 수 없습니다. ^^;;

<?
    echo "테스트 입니다.";
?>

<? echo "만약 세미콜론이 없다면?" ;
    echo "이렇게 하면 에러가 나겠지요? 한줄에 두개의 커맨드가 올수는 없습니다.";
?>

<? echo "그러나 이렇게 하면 됩니다."; echo "우리가 보는 엔터는 PHP에서 무의미 합니다.^^"; ?>

<? echo "한줄인 경우에는 세미콜론(;)을 하지 않아도 됩니다." ?>

자 다음과 같이 5, 6번째에 세미콜론을 추가했습니다.

그 결과는 ....

( 에러를 보고 어느 부분이 틀렸는지를 확인하고 수정하는 작업이 아주 중요합니다.)

PHP 코드에 주석 달기 (소스 코드 설명)

PHP는 기본적으로 C와 Perl 과 같은 형식의 주석을 제공합니다.
주석 방법 | 설명
// | 한줄 주석 처리 ( 가장 일반적 )
# | 한줄 주석 처리
/* */ | 여러줄 주석 처리 ( /* 시작 */ 끝 )

<? echo "오늘은 비가 오네요<BR>"; // 2000-11-20 ?>

<? echo "비가 오면 생각나는 그사람~~~♬<BR>"; # 한줄 주석 ^^ ?>

<? echo "오늘 하루도 즐겁게 힘차게~ ^^<BR>";
  /* echo "아 여기부터는 주석처리되기 때문에 ";
     echo "결과에는 반영이 안되겠군요.. ㅜㅜ<BR>"; */
?>

주석 처리 하는 방법은 위와 같구요. 결과는 다음과 같습니다.

주석 처리된 부분은 결과에 출력되지 않습니다. ^^

주석은 소스 코드를 작성할 때 코드 옆에 설명을 붙여 놓아 나중에 디버그(수정) 하거나

새로운 기능을 추가할 때에 많은 도움이 되니..

주석을 다는 버릇을 들이시기 바랍니다.

참고로 다중 주석속에 다시 다중 주석 처리를 할 수는 없습니다.

/* 아자아자 /* 어~ 이러면 안돼~ */ 이러면 에러납니다.. */


PHP 기초 문법 ::: 변수의 형태 (정수,실수,문자열)

강좌 8. PHP 기초 문법 ::: 변수의 형태 (정수,실수,문자열)

Type

정수 , 실수 , 문자열 , 배열 , 객체

이 다섯가지 타입이 있습니다.

정수 ( Integer )

$a = 1234; # 십진수

$a = -123; # 음수

$a = 0123; # 8진수 ( 십진수의 83과 같습니다. )

  $a = 0x12; # 16 진수 ( 십진수의 18과 같다 )

실수 ( Doubles )

$a = 1.234; $a = 1.2e3;

문자열 ( String )

문자열은 " " (따옴표) 안에 써넣으며 다음과 같은 특수 문자를 넣을 수 있습니다.
특수문자 | 의미
\n | 개행문자 ( 줄 바꿈 )
\r | 캐리지 리턴
\\ | 역 슬래쉬
\t | 수평 탭
\" | 따옴표
\$ | 달러 표시

위에 말씀드렸듯이 문자열은 " " 안에 들어가고 또한 PHP 자체에서 지원하는 특수한 문자들 때문에

위와 같이 \( 역슬래쉬 ) 문자를 써서 특수 문자를 표현합니다. ( 무슨 말인지 모르시겠죠? ^^;;;; )

예로 보여 드리겠습니다.

1
2
3
4
5
6
7
8
         <?
    echo "나는 문자열이예요~ ^^*<BR>\n";
    echo "우히히 정말 특별하죠? <BR>\r";
    echo "역슬래쉬를 보이려면 역슬래쉬 두개를~ \\<BR>";
    echo "탭\t 탭2<BR>";
    echo "따옴표 안에 따옴표를 넣으려면 \" <BR>";
    echo "달러 표시도 \$ <BR>";
?>

위와 같은 소스로 실행을 하게되면

위와 같이 나타납니다.

3번째 줄에 \와 5번째 줄에 " 6번째 줄에 달러 ( $ )문자가 나온게 보이시죠?

그런데.. 개행문자와 캐리지 리턴, 그리고 탭은 된 건지 안 됐는지 모르겠군요. 그쵸? ^^;;

개행문자 등은 소스와 관계된 기능들입니다.

소스를 보기 좋게 정렬하는 등의 기능을 하기 위한거죠.

그럼 HTML 소스를 보겠습니다.

HTML 소스를 보시면 확실히 개행문자가 뭔지 보이시죠? 소스가 한 줄 바뀌었습니다.

캐리지 리턴은 커서를 제일 처음으로 보내기 때문에 개행문자와 같은 효과를 내게 되었습니다.

그리고 3번째 줄에 탭 부분을 보시면 빈 공간이 보이시죠? 그것이 탭이 먹힌 자리랍니다. ^^

프로그램을 짜다보면 소스가 잘 정리되어있으면 버그 수정도 편하고 이것 저것 정말 도움이 많이 됩니다.

그러니 여러분도 조금 귀찮으시더라도 되도록이면 소스를 보기 좋게 잘 정리하세요^^

만약 따옴표가 표함되어 있는 문자열인데 역슬래쉬(\)문자를 쓰지 않았다면 어떻게 될까요?

1
2
3
         <?
    echo "따옴표 안에 따옴표를 넣으려면 " <BR>";
?>

이렇게 소스를 짜면 에러가 나게 됩니다.

왜냐하면 "(따옴표)와 " 사이가 문자열이라고 인식하게 되는데..

문자열 안에 따옴표가 나와서 echo "따옴표 안에 따옴표를 넣으려면" 이만큼이 문자열이라고 인식합니다.

그렇게 되면 뒤에 <BR>"; 이 무슨 말인지 PHP는 인식하지 못하기 때문에 다음과 같은 에러를 냅니다.

조금은 이해하셨나요?

이 부분은 프로그램을 짜다보면 자연히 알게 되는 부분이니 가볍게 생각하시기 바랍니다. ^^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
         <?php
    $str = "문자열";
    $str = $str . " 좀더 붙여서..";
    $str .= " 나도 끼워줘~\n";

    echo $str . "<BR>";

    $num = 9;
    $str = "Number: $num";
    echo $str . "<BR>";
    $num = 9;
    $str = 'Number: $num';
    echo $str . "<BR>";
?>

위 소스에 대한 결과는 다음과 같습니다.

2,3,4 번을 보시면 문자열을 합치는 것( .(점)을 통해서 연결)을 배우실수 있을거구요.

8번부터 12까지는 따옴표 안에 변수가 들어갔을 때와 작은 따옴표 안에 변수가 들어갔을 때

어떻게 다른지 알 수 있습니다.

다음 시간에는 배열과 객채에 대해 배우겠습니다.


PHP 기초 문법 ::: 변수의 형태 (배열,객체)

강좌 9. PHP 기초 문법 ::: 변수의 형태 (배열,객체)

배열

배열을 생각할 때는 간단히 보따리라고 생각하세요..( 마땅히 떠오르는게 없어설^^;;;)

보따리에 하나이상의 물건을 넣을 수 있듯이 배열에도 하나 이상의 데이터를 넣을 수 있습니다.

우선 한번 배열이 어떻게 생겼는지 구경을 해봅시다..

1
2
3
4
5
6
7
         <?

    $a[0]="abc";
    $a[1] ="def";
    $b["foo"]=13;

?>

그림에서 보시다시피 배열은 $a[0] 이런식의 형태입니다.

변수는 대부분 하나의 변수에 하나의 값을 갖는게 기본인데..

배열은 위처럼 a라는 변수에 abc 와 def를 가질 수 있습니다.

두 값의 구분은 [0],[1] 등으로 몇 번째에 저장되어 있나로 구분 할 수 있구요.

5번처럼 처음부터 foo라는 구분자를 주어 그 값을 구분할 수도 있습니다.

배열은 다차원 배열을 지원하여 $a[0][0] 식의 배열을 만들 수 있습니다.

그러면 $a[0][0][0] 는 안되냐? 당연히 됩니다.^^

배열부분은 실제 프로그래밍할 때 많이 쓰이게 됩니다.

그러면 당연히 배열을 잘~~ 다룰줄 알아야겠지요. ^^

배열에 관련된 함수들이 많이 있으니 함수를 잘이용하면 쉽게 프로그램을 만들 수 있습니다.

배열함수 구경하기

객체

1
2
3
4
5
6
7
8
9
10
11
12
         <?

    class foo { //클래스를 정의 합니다.
        function do_foo () {     //클래스의 멤버 함수를 정의합니다.
            echo "나는 객체입니다."; //클래스 멤버 함수의 내용
        }
    }

    $bar = new foo; //foo 클래스를 생성합니다.
    $bar->do_foo(); //foo 클래스의 멤버함수를 실행합니다.

?>

객체는 위와 같이 class ... 로 정의를 합니다.

객체에는 함수도 포함할 수 있고 변수도 포함 할 수 있습니다.

클래스는 객체지향 프로그래밍에서 쓰는 기본단위로..

객체지향이 뭔지 모르시는 분들이 직접 쓰기에는 다소 부담이 있습니다.

그러나 좌절(^^;;;) 하실 필요는 없습니다.

객체를 안쓰고도 충분히 프로그램을 짤 수 있기 때문이지요.

그리고 PHP 자체가 완전한 객체지향 언어가 아니기 때문에

안쓰는 것이 나쁘다고 말 할 수는 없습니다.

그러나 요즘 추세가 객체 지향 프로그래밍 쪽으로 변하고 있기 때문에

한번씩 짜보면서 객체지향 프로그램이 어떠한 것인지 이해 하는게 좋습니다.

입문에서는 약간 부담스러우니 훗일(?)을 도모하시는 것이 좋을 듯 하옵니다. ^^

변수형의 변환

만약에 우리가 지금까지 배운 5가지 Type을 자신이 원하는 다른 타입으로 바꾸고 싶을 때는 다음과

같은 방법으로 바꿀수 있습니다.

$foo = (int) $bar;

  • (int), (integer) - 정수형으로 변환
  • (real), (double), (float) - 실수형으로 변환
  • (string) - 문자열로 변환
  • (array) - 배열로 변환
  • (object) - 객체로 변환

이번 시간에는 다소 설명이 자세하지 않아서 이해하기가 어려울지 모르겠습니다.

우선은 개략적으로 "아~ 그냥 배열은 이런 모양이고 객체는 이런모양이구나~" 정도만 이해 하셔도 됩니다.


변수 ::: 어떻게 만들고 어떻게 쓸까?

강좌 10. 변수 ::: 어떻게 만들고 어떻게 쓸까?

미리정의된 변수

변수에는 우리가 만들어 사용할 수 있는 변수와 미리 정의되어진 변수가 있습니다.

우선 미리 정의된 변수는 서버 종류, 버전 등이나 기타 환경에 따라 변하는 변수들입니다.

아파치와 PHP 각각 몇 개의 변수를 지정해 놓은 상태이며 이 변수들은 우리가 인위적으로 값을

수정하거나 일반 변수로 사용할 수 없습니다.

이 변수들은 아파치 홈페이지나 PHP의 phpinfo() 함수로 확인할 수 있습니다.

가장 기본적이고 자주 쓰이는 변수는 PHP_SELF입니다.

PHP_SELF 는 자기 자신의 파일을 뜻하며 한 파일로 여러 기능을 하게 하는 문서를 만들 때 유용하게 쓰입니다.

다음은 PHP_SELF를 이용한 프로그램 소스입니다.

참고. 이 소스는 register_globals=on 인 상태에서만 작동합니다.
이를 수정하시려면 서버의 php.ini 파일에서 위부분을 찾으시어 off 를 on 으로 바꾸시기 바랍니다.
혹은 $info 변수 대신에 $_POST["info"] 를 사용하셔도 무관합니다.

1
2
3
4
5
         <form action="<? echo $PHP_SELF ?>" method=post>
<input name=info>
<input type=submit value=보내기>
</form>
<? echo "폼을 이용해 전송된 값 : $info "; ?>

변수는 항상 $로 시작하며 미리 지정된 변수든 우리가 임의로 만든 변수든 모두 $를 붙여야만 사용가능합니다.

위 소스는 폼에 임의의 값을 입력받아 자신의 파일로 그 정보를 넘기는 프로그램입니다.

다음 그림을 보시면 이해가 쉽게 가실 것입니다.

이 그림이 위의 소스를 실행한 결과입니다.

자 그럼 abc라는 값을 보내 보겠습니다. 위에서 폼의 action(정보를 보낼 문서 경로 지정)에 PHP_SELF를

썼기 때문에 자기 자신 파일로 정보(abc)를 보내게 됩니다.

첫 번째 그림에서 없던 abc라는 값이 출력되었습니다.

abc라는 값은 위의 소스에서 info라는 이름의 input 박스를 통해 넘어온 값입니다.

이 값은 $info 라는 변수에 자동 저장되므로 $info 변수를 통해서 이 값을 출력했습니다.

테스트 : /lect/44/php_self.php

일반적인 변수 ( 프로그래머가 임의적으로 만들어 쓰는 변수 )

변수는 앞서 말씀드렸듯이 $ 표시를 시작으로 일정의 문자열을 덧붙여 만듭니다.

그런데 달러 표시 다음에 붙는 문자열에는 아무 문자나 올수 있는게 아니라

일정의 규칙을 위반하지 않아야만 변수로 이용할 수 있습니다.

이 규칙이 위배되지 않는 문자열을 식별자라고 합니다.

즉, 식별자는 변수나 클래스 함수등의 이름으로 쓰일 수 있는 문자열이지요.

첫째, 영문 소, 대문자 , 숫자 그리고 _ (밑줄)로 이루어 집니다. 이 이외의 문자를 포함하면 에러가 나게 됩니다.

둘쨰, 소문자 대문자의 구별이 있습니다. (PHP 내장함수 제외 예) print(""); 와 Print("");는 같음)

셋째, 변수는 항상 $로 시작한다.

마지막으로 식별자의 첫 자는 숫자가 올 수 없습니다. ( 7abc 는 식별자가 될 수 없음 )

허용가능한 식별자와 불가능한 식별자의 예를 비교해 보겠습니다.

허용 : babo , php4 , linux_apache_php_MySQL

불허 : babo? , 4php , linux-apache-php-MySQL

위의 비교를 유심히 살펴 보시면 어떤 것이 실별자로 사용 가능한지 아실 수 있을 것입니다.

그럼 이 식별자를 이용해 변수를 만들고 이 변수를 출력하는 프로그램을 만들어 보겠습니다.

1
2
3
4
5
6
7
         <?
$a = 1;
$b = 2;
$sum = $a + $b ;

echo "$a + $b = $sum";
?>

위 소스의 결과는 다음과 같습니다.

a와 b 그리고 sum 이라는 이름의 변수들을 만들어 이렇게 덧셈 계산을 해보았습니다.

쉽죠?

이제 변수가 어떤 것인지 조금 아시겠어요?

참고로 위에서 말씀드린 이미 지정된 변수와 똑같은 이름의 변수를 만들어 쓰지 않도록 유의하시기 바랍니다.


변수의 범위와 상수 ::: 쌍칼과 회칼(전국구,지역구)

강좌 11. 변수의 범위와 상수 ::: 쌍칼과 회칼(전국구,지역구)

변수의 사용 범위

변수에는 지역변수라느니 전역변수라느니 하는 것들이 있습니다.

말 그대로 지역변수는 어떠한 일부분 영역에서만 적용되는 변수이고,

전역변수는 프로그램의 시작부터 프로그램의 종료까지 유효한 변수입니다.

지역구와 전국구에 비교할 수 있죠.

목포의 회칼이 지역구라면 종로의 쌍칼은 전국구입니다.

회칼이 서울로 상경해서 "나 회칼이야~"라고 한들 누가 알아줄까요?

하지만 전국구인 쌍칼은 목포가서 "나 쌍칼이다"라고 하면 다들 벌벌 떨겠죠.^^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
         <?

function Hello1 () {
        $hello = "안녕하세요";
        echo $hello . " --> Hello1 의 결과<BR>\n";
}
function Hello2 () {
        echo $hello . " --> Hello2 의 결과<BR>\n";
}
function Hello3 () {
        global $hello;
        echo $hello . " --> Hello3 의 결과<BR>\n";
}

$hello = "방갑습네다";

Hello3(); // 함수를 실행
Hello1();
Hello2();
Hello3();

?>

위 소스와 결과를 비교하면서 보도록 합시다.

우리는 아직 함수라는 것을 배우지 않았기 때문에 소스가 다소 생소할 수 있을 것입니다.

함수를 간단히 살펴보면

function 함수이름( 파라미터 ) {

}

와 같은 형식으로 함수를 정의하며 정의된 함수는 ' 함수이름(파라미터); ' 식으로 실행합니다.

위의 소스는 Hello1,2,3 이 세 함수를 정의하고 Hello3,Hello1,Hello2,Hello3을 차례대로 실행시킨 것입니다.

그런데 결과를 보면 Hello2 함수만 결과가 없는 것을 볼 수 있습니다.

이는 15번째 줄에 정의된 변수 $hello 가 Hello2 함수까지 영향을 미치지 못하기 때문입니다.

즉, 변수의 범위가 한정되어 함수까지 적용이 안되었다는 말입니다.

함수 Hello1 과 비교해 보시면 함수 Hello1 은 함수 내부에 변수 $hello를 정의하였기 때문에

' 안녕하세요 ' 라는 글자가 출력되었습니다.

그렇다면 15번째 줄에 정의된 변수 $hello를 함수 속에서 쓰고 싶을 때는 어떻게 해야 할까요.

바로 함수 Hello3 과 같이 변수 $hello를 전역변수로 지정해주면 됩니다.

전역 변수 지정은 변수 앞에 global을 추가해 주면 됩니다.

( 전역변수를 이용하지 않고 함수에 파라미터로 $hello를 넘겨주는 방법도 있습니다. )

15번째 줄에 정의된 변수가 함수 내부에서 쓰일 수 없듯이..

함수 내부에서 정의된 변수도 함수 외부에서 쓰일 수 없습니다.

함수의 시작과 함께 생성되었다가 함수가 끝나면서 소멸되기 때문이지요.

그런데 가끔 함수 안의 변수를 다시 써야 할 때가 있습니다.

이런 경우 static 변수 (정적변수)를 사용하면 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
         <?
function test () {

    static $test;    // 정적변수로 선언

    if ($test==1) { // $test값이 1이면
        $test=0;        //$test에 0을 입력
    }

    else {        // $test 값이 1이 아니면
        $test=1; // $test 값에 1을 입력
    }

    return $test; // $test값을 test함수의 결과로 내 놓음
}

for ($i=0 ; $i<10 ; $i++) {     // i가 0부터 1씩 증가하여 그 값이 10보다 작으면
    $value = test();            // test함수의 결과값(return된 값)을 $value에 저장
    echo $value;         // 출력
}

?>

만약 $test를 정적변수로 지정을 하지 않았다면 모두 1인 값이 출력됩니다.

왜냐하면 test 함수가 실행되면 $test 변수가 새로 생성되니 그 값은 NULL( 0이라고 생각하세요..^^) 이 됩니다.

따라서 항상 $test값은 1이 아니므로 매번 $test에는 1이 저장되게 되지요.

상수

상수는 아주 간단합니다. 말 그대로 항상 똑같은 값을 가지는 수이지요.

그래서 딱 한번만 설정하면 전역변수처럼 사용할 수 있습니다.

상수는 대문자로 표기하는게 일반적입니다. 또한 변수처럼 $ 표시는 하지 않습니다.

1
2
3
4
5
6
         <?

define ("HELLO","안녕하세요");
echo HELLO;

?>

define 으로 상수를 설정할 수 있습니다.

define("상수명","상수에 저장될 값");

이런 식으로 사용되는데..

위의 예제에서 보듯이 define 이후의 HELLO는 "안녕하세요"를 나타냅니다.

그렇다고 echo "HELLO" 까지 "안녕하세요"라고 출력되는 것은 아닙니다.^^

PHP에서는 미리 일정의 상수를 정의해 두었습니다.

예를 들면 PHP_VERSION (현재 PHP 버전), PHP_OS (현 시스템의 운영체제), M_PI (원주율)등이 있습니다.


연산자 ::: 더하기 빼기 곱하기 나누기

강좌 12. 연산자 ::: 더하기 빼기 곱하기 나누기

산술 연산자

산술 연산은 흔히 우리가 접하는 더하기 빼기 곱하기 나누기를 말합니다.

어려운 말로 가감승제( 加減乘除 ) - 모처럼 오바했음 ... ^_^ (씨익) .... 퍼버벅.. @.# 지송..ㅜㅜ

    + | 더하기
- | 빼기
* | 곱하기
/ | 나누기
% | 나머지

더 이상 설명이 필요없죠? 모르시는 분은 초등학교 다니는 동생한테 물어 보세요. : Ð

대입 연산자

대학가는 연산자가 아닙니다. ㅡㅡ;; ( 오늘따라 무지 오바하는 군요.. 지송함돠.. 주의 할게요 .. )

기본 대입 연산자는 = 입니다.

일반적으로 = 기호는 같다라고 생각합니다.

그러나 a = b 는 a 와 b 는 같다가 아니라.. (PHP에서 실제 같다는 ==입니다.)

b 의 값을 a 에다가 대입한다 라는 뜻입니다.

그래서 대입 연산자이지요.. ^^

결과적으로는 a 와 b 가 같지만.. 의미상 아주 다릅니다. 특히 프로그램에서는 치명적이죠..

예) $a = ($b = 4) + 5; // $a는 9, $b는 4의 값을 가진다.

괄호 안이 가장 우선으로 처리됩니다. 따라서 $b 는 4 가 되고 4 가 된 $b에 5를 더한 그 값이

$a 에 입력됩니다. 결과는 $a 는 9 , $b 는 4입니다.

비교 연산자

비교 연산은 말 그대로 두 개의 값을 비교하는 것입니다

    < | 작다
> | 크다
<= | 작거나 같다
>= | 크거나 같다
== | 같다
!= | 같지 않다

증감 연산자

    ++ $a | $a를 1 증가후 $a를 반환
$a ++ | $a를 반환후 $a 에 1 증가
- - $a | $a를 1감소후 $a를 반환
$a - - | $a를 반환후 $a 에 1 감소

예제를 보면 이해가 갈겁니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
         <?
echo "<h4>후 증가</h4>";
$a = 5;
echo " \$a++: " . $a++ . "<br>\n";
echo " \$a : " . $a . "<br>\n";

echo "<h4>선 증가</h4>";
$a = 5;
echo " ++\$a: " . ++$a . "<br>\n";
echo " \$a : " . $a . "<br>\n";

echo "<h4>후 감소</h4>";
$a = 5;
echo " \$a--: " . $a-- . "<br>\n";
echo " \$a : " . $a . "<br>\n";

echo "<h4>선 감소</h4>";
$a = 5;
echo " --\$a: " . --$a . "<br>\n";
echo " \$a : " . $a . "<br>\n";
?>

문자열 연산자

문자열을 더할 때는 . (쩜) 연산자를 씁니다.

$a = " 안녕 ";

$b = " 하세요";

일 때 두 문자열을 더하고 싶으면 $c = $a . $b; 하시면 됩니다.

$c 에 한마디를 더 추가하고 싶을 때는..

$c .= " 반가워요~"; 하시면 됩니다.

결과적으로 $c = " 안녕 하세요 반가워요~"; 와 같습니다.


제어 구조 ::: if , while , do .. while

강좌 13. 제어 구조 ::: if , while , do .. while

if

if 문은 제어 구조의 가장 기초가 되는 부분입니다.

말그대로 만약 ~~ 이면 다음 내용을 실행하라는 것입니다.

1
2
3
4
5
6
7
8
         <?
    $a = 1;
    $b = 0;

    if ( $a > $b ) { //괄호안이 참이면 다음을 실행
        echo "$a 는 $b 보다 크다.";
    }
?>

소스에서 보듯이..

if 구문은

if ( .... ) { .... } 와 같은 형식으로 사용합니다..

괄호안이 참인 경우 중괄호 안을 실행하게 되는 것이지요..

참고. 위 소스처럼 중괄호 안이 한 줄인 경우 중괄호의 생략이 가능합니다.

else

else 구문은 if 문에서 괄호안의 결과가 FALSE 인 경우 즉, 거짓인 경우 실행합니다.

1
2
3
4
5
6
7
8
9
10
11
         <?
    $a = 1;
    $b = 0;

    if ( $a > $b ) { //괄호안이 참이면 다음을 실행
        echo "$a 는 $b 보다 크다.";
    }
    else { //괄호 안이 거짓인 경우
        echo "$a 는 $b 보다 작다.";
    }
?>

특별히 설명은 필요 없겠죠? ^^

elseif

elseif 구문은 else와 if를 합쳐놓은 것과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
         <?
    $a = 1;
    $b = 0;

    if ( $a > $b ) { //괄호안이 참이면 다음을 실행
        echo "$a 는 $b 보다 크다.";
    }
    elseif ($a == $b) { //위가 거짓이고 $a와 $b 가 같은경우
        echo "$a 는 $b 와 같다.";
    }
    else { //괄호 안이 거짓인 경우
        echo "$a 는 $b 보다 작다.";
    }
?>

elseif 는 반드시 위의 if 구문이 거짓이고 elseif 구문이 참일 때 중괄호가 실행됩니다.

if-elseif-else 구문은 위의 소스를 잘 보시면 충분히 이해 하시리라 생각됩니다.

while

1
2
3
4
5
6
7
         <?
    $i = 1;
    while ($i <= 10) { //구문이 참이면.. 중괄호부분을 무한반복
        echo $i++;
        //$i 가 1씩 계속 증가하니 10번 반복하면 끝나겠지요?
    }
?>

while은 루프라고 하며.. 조건절이 참일 경우 무한 반복하게 됩니다.

위의 소스에서 보시다시피 변수 $i는 실행시마다 1씩 증가하며..

구문은 변수 $i의 값을 매번 체크하여 참일 경우 다시 실행 시키게 됩니다.

따라서 while 구문은 10번 실행후 자동 종료됩니다. ^^

뭔소린지 아시겠죠? ^^;; 하핫..

do .. while

do .. while 구문은 while 문과 유사하며..

조건절이 뒤에 있기 때문에 반드시 한번은 실행을 한다는 차이가 있습니다.

1
2
3
4
5
6
         <?
    $i = 0;
    do { //우선 한번 무조건 실행하고 본다..
        echo $i;
    } while ( $i >0 ) // $i 가 0보다 크면 다시 반복
?>

무조건 한번 실행하고 조건절을 판단하므로 위와 같은 결과를 내게 됩니다.

만약 while 문을 썼다면 아무 결과도 안나왔겠죠.. 그냥 공허한 흰색 배경만이...... ^^


제어 구조 ::: for , continue, break, switch

강좌 14. 제어 구조 ::: for , continue, break, switch

for

for 문은 while과 같은 루프입니다.

for (expr1; expr2; expr3) statement

와 같은 형식을 가지며.. expr1 이 무조건 한번 실행된 후에..

expr2 조건을 검사합니다.

expr2가 참이면 statement를 실행하고 statement가 모두 실행되면 expr3를 실행합니다.

( 뭔말인지 모르시겠죠? ^^;;;; )

소스를 보시면 쉽게 이해하실 수 있을 것입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
         <?
    /* 아래는 모두 1 부터 10까지 출력하는 프로그램입니다.
        그 차이를 한번씩 생각해 보세요..
        가장 일반적인 방법은 첫번째 방법입니다.
    */

    for ($i=1; $i <=10; $i++) {
        echo $i;
    }

    for ($i = 1;;$i++) {
        if ($i >10 ) {
            break; // 루프를 빠져나감
        }
        echo $i;
    }

    $i=1;
    for (;;) {
        if ($i > 10) {
            break;
        }
        echo $i;
        $i++;
    }

    for ( $i = 1; $i <= 10; print $i,$i++ ) ;
    //print는 되는데.. echo는 안되네요...
?>

나머지 세 방법은 이렇게도 할 수 있구나 하는 것 정도만 이해하시면 됩니다.

break

break 문은 위에서 배운 for와 앞서 배운 while 같은 루프를 빠져나오는 명령입니다.

위의 소스에서 보듯이 (14번째줄) 변수 $i가 10보다 커지면.. break에 의해 for 문을 빠져나오게 됩니다.

( switch 문을 벗어날 때도 break를 씁니다.아래에서 배움)

continue

continue는 break와 달리 루프의 처음으로 돌려 보내는 명령입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
         <?
$i = 0;
while ($i++ < 3) { //세번만 실행해보도록 하겠습니다.
     echo "첫번째 루프<br>\n";
     while (1) {
        echo "  두번째 루프<br>\n";
         while (1) {
              echo "  세번째 루프<br>\n";
              continue 3;
         }
         echo "절대 안나오지롱~<br>\n";
    }
    echo "나도 나오게 해줘 제발~ ㅜㅜ<br>\n";
}
?>

위 소스에서 보듯이 (9째줄) continue 다음에 숫자 옵션을 추가하여..

루프를 몇 단계 벗어날지도 설정할 수 있습니다.

세단계 루프를 벗어나니까.. 11번째줄과 13번째줄은 절대 프린트가 안되겠죠? ^^

switch

다음은 switch 문을 if 문으로 표현한 것입니다. 소스를 보시면 쉽게 이해되실거예요^^

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
         <?
if ($i == 0) {
    print "i 는 0";
}
if ($i == 1) {
    print "i 는 1";
}
if ($i == 2) {
    print "i 는 2";
}

switch ($i) {
    case 0:
        print "i 는 0";
        break;
    case 1:
        print "i 는 1";
        break;
    case 2:
        print "i 는 2";
        break;
}
?>

위 소스에서 보듯이 switch 문은 if 문을 여러 개 정렬해놓은 것과 같습니다.

예를 들면 90점은 A 80점은 B 70은 C 같이 등급을 매길 때 유용하게 쓸 수 있습니다.

근데.. 50점 이하는 모두 F를 주고 싶은데.. 귀찮게 50 40 30 .. 모두 case를 만들기가 그렇죠?

이럴 때 default를 쓰면 됩니다. case로 지정안된 모든 값은 default 값으로 정해지는 거죠

case 처럼 default : 이렇게 쓰면 되구요.. break는 쓸 필요가 없습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
         <?
if ($i == 0) {
    print "i 는 0";
}
elseif ($i == 1) {
    print "i 는 1";
}
elseif ($i == 2) {
    print "i 는 2";
}
else {
    print "i는 0,1,2가 아니다";
}

switch ($i) {
    case 0:
        print "i 는 0";
        break;
    case 1:
        print "i 는 1";
        break;
    case 2:
        print "i 는 2";
        break;
    default :
        print "i는 0,1,2 가 아니다";
}
?>

if 구문과 비교하면서 잘 생각해 보세요..^^


제어 구조 ::: include , require

강좌 15. 제어 구조 ::: include , require

require()와 include()

이 두 구문은 외부 파일을 대체하는 기능을 합니다.

require('somefile.html');
include('somefile.html');

과 같은 형식으로 사용하는데.. 아래의 예를 보시면 쉽게 이해하실 수 있을것입니다.

head.html

main.php

결과 : main.php

include() 문 자리에 head.html의 소스가 고스란히 들어간 결과와 같게 됩니다.

그럼 이번엔 PHP 파일을 인클루드 해보겠습니다.

main.php

1
2
3
4
5
         <?
echo "다우니와 함께하는 PHP 따라잡기<BR>";
include "inc.php";
echo "지금 쓰는 이름과 예전에 쓰던 홈피 이름";
?>

inc.php

1
2
3
         <?
echo "나도 이제 PHPer - 피에치피어<BR>";
?>

결과 : main.php

여기서 주의해야 할 점이 있습니다.

include()문이 파일로 대체된다고 해서 inc.php 파일에 <? ?> 를 빼버린다면..

위의 결과처럼 PHP 소스가 아니라 그저 HTML인것으로 이해하게 됩니다.

이러한 결과를 내는 이유는 include()와 require()가 실행될때 자동으로 PHP 모드를 빠져나오고

구문이 끝남과 동시에 다시 PHP 모드로 돌아오기 때문입니다.

위의 예제들은 모두 require() 문으로 대체해도 똑같은 결과를 얻을 수 있습니다.

"그럼 왜 불필요하게 같은 기능을 하는게 두개가 있을까?" 하는 의문을 가지실 겁니다.

답부터 말씀드리면 둘은 똑같지는 않기때문입니다.

기능이 비슷하긴 하지만 엄연히 다른부분이 있습니다.

require()와 include()의 차이점

require()는 항상 실행됩니다.

만약 조건문에 싸여 있다 하더라도 실행되고 그 조건문이 절대로 실행되지 않는 구문이라도 실행됩니다.

반면 include()는 조건문에 싸여 있을 경우 조건에 맞을때만 실행됩니다.

따라서 조건문에 맞춰 특정 파일을 소스내에 포함시키고 싶다면 반드시 include()문을 사용해야 합니다.


카운터 만들기 ::: 뭘로 카운터를 만들까?

강좌 16. 카운터 만들기 ::: 뭘로 카운터를 만들까?

카운터

카운터는 홈페이지에 접속하는 사람들의 수를 나타내는 프로그램입니다.(다들 아시져?)

대부분의 경우 오늘의 접속자 수와 지금까지의 총 접속자 수를 표시하지요.

일반적으로 3가지 종류의 카운터가 있습니다.

1. 일반 카운터 : 카운터가 있는 페이지를 다시 읽을때마다 카운터가 올라감

2. 쿠키 카운터 : 쿠키라는 것을 이용해서 브라우저를 닫기전까지 단 1회만 올라감.

3. 세션 카운터 : 세션이라는 것을 이용해서 세션이 살아 있을때까지 단 1회만 올라감.

쿠키

쿠키란 무엇이냐? 과자라구요?

하하..무릎꿇고 두손 드십셔.. -_-;;

우리는 다음이나 다른 사이트에 들어갈때..
<오늘은 내가 주인공>

아이디와 패스워드를 넣고 들어가는 경우가 많습니다.이는 회원만 사이트를 이용할 수 있게 함이죠..

다른 일반인들이 아무나 들어오지 못하게 로그인 과정을 거치게 하는 겁니다.

근데 한번 로그인을 하고 나면 브라우저를 없애거나 로그아웃을 하기 전까지는

어느 페이지에 가더라도 다시 로그인 하라는 창은 뜨지 않습니다.(특별한 경우 제외)

그 이유는 로그인 후에 접속자에게 쿠키라는것을 만들어 주었기 때문입니다.(사용자컴에)

쉽게 생각해서 우리가 들어갈려고 하는 사이트를 놀이동산이라고 하면.

쿠키는 자유이용권입니다.

처음에 놀이동산에 들어갈때 자유이용권을 사면..(쿠키는 무료지만..^^;;)

어느 놀이기구를 타더라도 그것만 보여주면 다 탈 수 있지요. ^^

대충 이해가 되시나요?

참고. 쿠키는 브라우저를 닫거나 로그아웃하면 삭제됩니다.

세션

세션은 쿠키의 한단계 발전된 개념입니다.

쿠키는 사용자가 들어오는건 알 수 있어도 말없이 나가 버리면

나간것에 대해 알지 못합니다.
<조연 - 세션맨들>
세션이 한 수 위라고 했죠? ^^

세션은 사용자가 나가버리면 조금 있다가 "어 이녀석 나가버렸군."하고 세션을 삭제합니다.

그리고 세션은 특이한 기능이 하나 더 있습니다.

놀이 동산에서 놀이기구를 안타고 그냥 멀뚱거리기만하면 ..

"넌 20분동안 놀이기구를 안타고 있으니 세션이 필요없나보구나." 하면서

세션을 삭제해 버립니다. (호홋.. 좀 잔인하져? ^^)

하지만 세션도 단점은 있습니다.

세션이 사용자의 접속상태를 확인하는 등 별도의 작업을 하기때문에 서버를 힘들게 하거든요.

PHP에서도 PHP4가 되면서 세션을 지원하기 시작했습니다.

그래서 아직은 많이 쓰진 않습니다.

우리의 선택.

그럼 우리는 일반 카운터를 선택할것이냐 쿠키 카운터를 쓸것이냐 그것도 아니면

세션 카운터를 쓸 것이냐에 대한 고민에 빠질것입니다.

(제목에도 있듯이 쿠키카운터 쓸겁니다. 고민하지 마십시오.)

일반 카운터는 페이지를 볼때마다 무조건 올라가기 때문에 좀 부정확하져.

세션 카운터를 쓰자니 서버가 부담스럽고.

그래서 젤루 무난한 쿠키를 선택했습니다.

대부분의 카운터가 바로 이 쿠키를 써서 만들어진 것입니다.

쿠키를 가지고 있나 없나 여부를 확인해서 프로그램을 짜면

브라우저를 닫거나 쿠키를 삭제하기 전까진 카운터가 1밖에 안올라가게 되죠.

쿠키를 이용한 카운터 만들기 1부 끝...


카운터 만들기 ::: 만인의 선택 쿠키

강좌 17. 카운터 만들기 ::: 만인의 선택 쿠키

만인의 선택 "쿠키"

우리가 앞선 강좌에서 선택한 것은(사실은 제가 선택했지요..^^) 쿠키였습니다.

자 그러면 이제 쿠키로 카운터를 만들어야 할터인데..

카운터에 왜 쿠키가 필요한지는 알아야겠죠?

쿠키는 카운터에서 무슨일을 하나?

카운터는 홈페이지를 방문한 사용자의 수가 정확히 얼마나 되는가를 알고 싶은게 목적입니다.

대개 카운터는 메인페이지에 넣기 마련인데..

(물론 프레임등을 이용하여 항상 보이는 곳에 두기도 합니다.)

만약 메인페이지를 브라우저에서 불러 들일때마다 카운터가 하나씩 증가한다면

엽기적인 방문자(메인페이지에서 F5를 마구 눌러대는 사람)나 수시로 메인페이지로

가는 Home 버튼을 누르는 사람들에게 걸리면 실질적인 방문자가 10명임에도

하루방문자가 100에서 심하게는 1000까지 이르는걸로 나오게 됩니다.

이래서는 안되겠지요?

물론 홈지기를 다소 흥분시키기에는 충분하지만요..

이를 방지하기 위해서 방문자가 홈페이지에 접속해서 구석 구석을 구경하는 동안은

카운터가 안올라가게 해야한다는 생각을 누군가가 가지게 되었습니다.

그 사람은 고민을 했겠죠..

어느 순간 그 사람의 머리에 "쿠키"란 단어가 떠올랐을 겁니다.

쿠키는 브라우저를 닫거나 일부러 삭제하지 않으면 절대로 안없어지니까요.

방문자가 홈페이지에 접속하면 쿠키를 손에다 쥐어주고 카운터를 하나 올립니다.

방문자가 다시 Home 버튼을 누르거나 F5(새로고침) 버튼을 눌르면 쿠키를 가지고 있는지

확인을 해서 쿠키를 가지고 있으면 카운터를 무시하고 쿠키가 없으면 새로 접속한

사람으로 인식하고 새로 카운터를 올립니다.

이게 바로 쿠키를 이용한 카운터의 원리입니다.

그럼 쿠키가 어떻게 생겼는지 한번 볼까요?

쿠키의 생김새

SetCookie ("쿠키이름", "쿠키값");

쿠키의 모양은 대충 이렇습니다. (실은 가장 간단한 쿠키의 모양입니다.)

그럼 실제로 우리가 카운터에서 쓰게될 진짜 모습을 구경해 봅시다.

SetCookie("ip",$REMOTE_ADDR);

크헉..
<쿠키의 실제 모양(?)>
처음부터 모르는게 나와서 당황스러우시죠?

자 그럼 하나씩 알아봅시다.

위에서 보듯이 ..

쿠키이름 = ip -> 변수

쿠키값 = $REMOTE_ADDR -> 변수값

입니다.

변수의 모양은 많이 보셨죠?

다들 아시다시피 변수는 $로 시작합니다.

따라서 $ip에는 $REMOTE_ADDR 이라는 값이 들어가게 됩니다.

그럼 도대체 $REMOTE_ADDR은 뭔가하는 궁금증이 자연스레 생기게 됩니다.

$REMOTE_ADDR은 방문자의 IP Address를 알려주는 환경변수같은 겁니다.

제 IP가 211.45.255.123 이라면..

echo $ip 의 결과는 211.45.255.123 이 나오게 됩니다.

쿠키에 꼭 IP 주소값을 가지고 있어야 하나?

결론적으로 아닙니다.

어떠한 값을 가지고 있어도 됩니다.

제가 여기서 IP 주소를 굳이 선택한 이유는 접속자에 대한 로그파일을 만들어 놓기 때문입니다.


카운터 만들기 ::: 소스 분석 및 테스트

강좌 18. 카운터 만들기 ::: 소스 분석 및 테스트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 		<?
// <? <-- 이 표시 이전에 공백이나 어떤 HTML 이 들어가도 안됩니다.
//수동으로 count.txt 란 파일을 같은 디렉토리에 만들어놓는다.
// 물론 퍼미션은 777 (모든사람이 읽기 쓰기 접근이 가능하게..

$count = file( "count.txt"); //------------- ①
// file 함수는 count.txt 파일의 데이터를 배열로 저장합니다.
// 한줄 한줄 배열로 저장하기 때문에 $count[0]은 첫줄 $count[1] 둘째줄

$count = chop($count[0]); //------------ ②
// chop 함수는 문자열 끝의 의미없는 공백을 지워주는 함수입니다.
// 'abc          '  이와같이 데이터가 있을 경우 'abc' 로 뒤에 불필요한 공백을
//삭제 합니다.

if (!$ip){ //----------------------------- ③
// $ip는 쿠키로 지정된 값입니다.
// 즉, 한번 들어오면 쿠키값으로 인해 리프레쉬 하여도 카운터는 올라가지 않습니다

    $count++; //------------------------- ④
    // 쿠키값이 없을 경우 카운터를 1 증가 시킵니다.

    $fp = fopen( "count.txt",  "w");  // 파일 열고 ----- ⑤
    fwrite($fp,  "$count");  // 파일에다 $count 값을 저장합니다. ------⑥
    fclose($fp);  // 파일을 닫습니다. ----- ⑦

SetCookie( "ip",$REMOTE_ADDR); //-----  ⑧
// 또는 SetCookie("ip",$REMOTE_ADDR,0,"/"); 처럼 하세요.
// 카운터가 추가 되었으므로 쿠키를 설정해 브라우저를 제거하기 이전에는
// 카운터가 더 이상 올라가지 않게 합니다.

} //---------- ⑨
echo ($count); //-------------- ⑩
// 카운트 값을 출력합니다.
?>

예제 보기

소스 파일 보기

이 카운터의 전체적인 흐름은 다음과 같습니다.

[카운터를 달기위한 선행작업]

1. 카운터가 들어갈 페이지와 동일한 디렉토리에 count.txt 라는 파일을 만듭니다.

2. 퍼미션(파일의 권한설정)을 777로 맞춥니다.
텔넷 : chmod 777 count.txt
FTP : 파일을 클릭하고 오른쪽 버튼을 누르면 chmod 설정메뉴가 있습니다. WS_FTP 의 예)

위 그림과 같이 체크 박스를 모두 클릭하시거나 numeric을 777로 수정하면 됩니다.

[카운터의 흐름도]

1. 현재까지의 방문자수를 알기 위해 count.txt 파일을 열어 적혀있는 값을 가져옵니다.

2. 파일에서 가져온 값에 쓰레기값(빈공간)을 없앱니다.
그럼 현재까지의 방문자 수를 구한 샘이군요.
$count 에 저장되어 있습니다.

3. 첫번째 접속인지 아니면 이미 접속되어있는 상태인지 확인합니다.
매번 페이지를 볼때마다 카운터가 올라가는 것을 방지하기 위함입니다.
이미 접속되어 있다면 쿠키값을 가지고 있겠죠? 쿠키가 저장된 변수는 $ip 입니다.
$ip의 값을 확인하면 되겠네요.
if (!$ip) -> $ip 값이 비어 있을때.. 즉 처음 접속했을때 입니다.

4. 만약 쿠키값이 있다면 다시 카운터를 올릴 필요가 없으니 현재 방문자수를 보여주면 될테고..
쿠키값이 없으면 처음 접속하는 것이니 카운터를 올려주도록 합시다.
위에서 카운터는 $count 변수에 저장되어 있다고 했습니다.
그럼 $count ++; 로 $count 값에 1을 더합니다.

5. 자 그럼 카운터값을 저장해야겠지요?
다시 count.txt 파일을 엽니다.
이번엔 fopen 이란 함수가 쓰였네요.
fopen(파일 이름,파일모드) 형식으로 쓰는 겁니다.
파일모드는 w,r,w+,r+ 등등이 있는데..
write(쓰기)할거냐 read(읽기)할거냐를 지정해 주는 것입니다.
우리는 파일을 쓸거니깐 w를 쓰면 되겠죠?

6. 파일을 열었으니 값을 저장해 봅시다.
fwrite 눈치채셨겟지만..
file을 write 하겠다는 함수입니다.
fwrite(열려진 파일의 핸들,저장하고자 하는 값) 이러한 형식입니다.
핸들이 뭔지 궁금하실텐데.. 아래에 보충설명이 있습니다.

7. 자 파일을 열어 저장했으니 열었던 파일을 닫습니다.
fclose 파일을 닫겠다는 거겠죠?
fclose(열려진 파일의 핸들) 형식입니다.

8. 카운터도 저장하고 했으니 접속했다는 의미로 쿠키를 하나 줍시다.
홈피를 방문해 줬는데 얼마나 이뻐요..^^;;
쿠키하나 아니 열개라도 주고 싶은데.. ^^;;;
SetCookie(쿠키를 저장할 변수,저장될 값) 의 형식으로 쓰여집니다.
물론 SetCookie 함수는 이외에 더 많은 설정을 할 수 있습니다.
가장 간단한 모양이라고 저번에 말씀드렸죠?
$REMOTE_ADDR 은 환경변수의 일종으로 브라우저가 제공해주는 값입니다.
접속자의 접속 IP를 알려주는 거지요. ^^

9. 자 그럼 쿠키도 하나 줬으니 이제 카운터를 보여주면 되겠네요.
카운터를 출력할 부분에다가 $count 값을 뿌려주면 끝!!!

* 파일 핸들에 대한 추가 설명은 다음글에 있습니다.


파일 열고 닫고?? 왜 그렇게 귀찮게하지? 핸들은 또 모야?

강좌 19. 파일 열고 닫고?? 왜 그렇게 귀찮게하지? 핸들은 또 모야?

[파일 열고 닫고?? 왜 그렇게 귀찮게하지? 핸들은 또 모야?]

그냥 fwrite(파일이름,저장값) 과 같은 형식으로 만들었으면 간단할거라 생각되는데
왜 무슨 핸들이 어쩌구 파일을 열고 닫고 이 난리법썩을 피워야 하는지 궁금하실 겁니다.

자 그럼 상상을 나래를 펴볼까요? -_-;;

앞에 일기장이 하나 있습니다.
일기장에다가 오늘의 일기를(그럼 무얼쓰겠습니까마는..-_-) 쓸겁니다.
"오늘 순이를 만났다." 식으로 말이죠.-_-;; (제가 좀 단순합니다.)
일기쓸때 우선 이 일기장이 나의 일기장인지 남의 일기장인지 확인해야 합니다.
뭐 별도로 이리저리 뒤적거리지 않아도 자기 일기장이라면 바로 알수있겠죠?
위에서 chmod 머라고 한게.. count.txt 라는 일기장을 내것으로 만드는 것입니다.
자 그럼 이게 내 일기장이라는 건 확실하네요.
그럼 일기를 써봅시다.
우리의 소망대로 일기장을 딱 잡고 펜으로 갈깁니다.(fwrite를 위처럼 할경우)
이런-_-;;
일기장 표지에다 일기를 써버렸군요..ㅡ_ㅡ;; (실제로 안된다는 소립니다.)
에고.. 그럼 표지를 넘겨야 겠군요. (fopen을 합니다.)
일기를 쓸것이기 때문에 손에는 펜을 들고 있어야 겠지요? (파일모드는 w)
자 원하는 페이지를 열어 일기를 씁니다.
"오늘 순이를" 까지 썼는데 갑자기 순이 사진이 보고 싶어졌습니다.-_-;
일기쓰던걸 멈추고 서랍에서 옛날 일기장을 꺼냅니다.
옛날 일기장에 순이 사진을 꽂아 두었거든요.. ^^v
일기장을 펴고 순이 사진을 보면서 느끼한 미소를 날립니다.ㅡ_ㅡ
아~ 감정이 북받치는군요. 일기가 왠지 잘 써질것 같습니다.
다시 일기를 씁니다.
어..일기장이 그러고 보니 두개가 있네요. 옛날 일기장과 요즘쓰는 일기장.
우리가 이 일기장을 구분할 수 있는건 각각의 일기장에 대한 기억을 가지고 있기 때문입니다.
그렇다고 일기장의 모든 내용을 기억해서 둘을 구분하는건 아닙니다.
단지 일기장의 모양으로도 일기장 표지의 그림으로도 쉽게 구분 할 수 있는것이지요.
그리고 내가 어디쯤에 일기를 쓰고 있었다 하는 기억도 있겠죠.
이 기억이란게 핸들입니다.
자 각설하고.. 마저 일기를 씁시다.
"만났다."
아.. 일기를 다썼네요..
일기장을 덮습니다.(fclose)
뭐 일기장을 안덮을 수도 있습니다.
나중에 일기를 더 쓰고 싶을 수도 있으니까요..
하지만..
누가 그사이에 와서 내 일기장을 훔쳐 볼수도 있으니..
나중에 또 쓸게 아니라면 왠만하면 닫는게 좋겠죠?

이 개념을 설명하기위해 약간 억지스레 쓴것 같기도 합니다.
이 예가 이해가 잘되는건지도 모르겠네요.^^;;;


방명록 만들기 ::: 방명록을 파헤쳐보자

강좌 20. 방명록 만들기 ::: 방명록을 파헤쳐보자

[방명록을 파헤쳐보자]

* 방명록이 먼가?

방명록을 만들려는데 방명록이 뭔지 몰라서는 안될테니 방명록이 무엇인지부터 알아보도록 합시다.

방명-록 (芳名錄) [-녹]
행사장·식장·기념관 등에서, 방문하거나 참석한 사람의 이름을 적어 기념이 되도록 하기 위해
마련해 둔 공책.
¶ ∼에 서명하다. (야후에서 발췌..^^;)

그렇습니다.
방명록이란 내 홈페이지에 들어와서 구경잘했으면 소감 한자 적고 나가라는 것입니다.
대개의 홈피 운영자들은 공손하게 "한자 적어주시고 가세여~" 하지만..
가끔 우리는 "안적고 가면 주거~ ㅡ_ㅡ oOoo" 라며 (조금 과격한가?) 협박하는 홈피도
보고는 하지요.

각설하고..(이말은 어떤 소설에서 많이 본것같은..)
방명록이 먼지 알았으니 다음단계로 넘어갑시다.

* 방명록을 만들려면 뭐가 필요한가?

방명록을 만들려면 필요한것이 많습니다.

1. PHP를 지원하는 서버 ( 첫번째 강좌 )
2. MySQL을 지원하는 서버 ( 이것또한 첫번째 강좌 )
3. 메모장 또는 텍스트 에디터 ( 이건 두번쨰 강좐가? )
4. 한글을 이해하고 영어를 읽을 수 있는 머리-_-;;

* 그래도 막막하다 뭘 어디서부터 해야 하나?

"내가 이 방명록 소스하나는 반드시 통달하고 만다!"는 생각을 가지고
그냥 강좌를 따라오면 됩니다.

* 사설이 무지 긴데 본론으로 들어가면 안되냐?

에헴.. 그럼 본론으로 들어가지요 뭐.

[방명록의 구조]

방명록을 만들려면 그 구조를 알아야겠죠?
방명록을 많이들 보아 왔으니 말만으로도 잘 이해 하리라 믿지만..
그래도 강좌에 그림하나 없으면 딱딱할거 같아 그림 한번 넣어봅니다.

- 우선 글 보기 -

- 다음으로 글 올리기 -

이거 외에 글 삭제하기를 추가하면 방명록은 완성!!

간단하게 정리하면 글을 보고 글을 쓰고 글을 지울수 있는 기능만 있으면 된다는 얘기!

딱 세가지 기능밖에 없는데... 벌써 기죽은건 아니겠죠?

자 그럼 다음 글을 보시지요..^^


방명록 만들기 - 만들기 앞서 해야할 작업

강좌 21. 방명록 따라 만들기 2부 - 방명록을 만들기 앞서 해야할 작업

우리는 앞의 강좌에서 PHP와 MySQL을 이용하여 방명록을 만들거라고 했습니다.
MySQL을 이용하기 때문에 MySQL에서 좀 작업해야 할게 있습니다.

* 근데 MySQL은 뭐지?

MySQL을 이용할 거니깐 MySQL에 대해 조금만 알아 보도록 합시다.
(자세히 알려면 이것만으로도 수십 또는 수백개의 강좌가 생길수도 있으니..^^)

예전의 게시판이나 방명록의 (CGI 같은) 데이터는 대개 파일에 저장하고는 했습니다.
예를 들면 누군가 글을 쓰면 sample.txt 라는 파일을 만들고 거기다가 이름 이메일
글의 내용등을 써 넣어서 저장을 한거죠.
그래서 글을 볼때면 이 파일을 읽어 들여서 뿌려주고는 했습니다.

근데..
글의 수와 입력 값등이 많아지자 이 데이터들 중에서 정말 원하는 데이터를 찾기가
어려워졌습니다.
데이터 관리가 어려워진거죠.
그래서 보다 많은 데이터를 보다 효율적으로 관리하고자 해서 데이터베이스라는 것을
만들게 되었습니다.
MySQL도 이런 데이터베이스의 하나입니다.
우리는 방명록의 데이터를 보다 효율적으로 관리하기 위해 MySQL을 쓰기로 한것입니다.

* MySQL을 하나도 모르는데 방명록을 만들수 있을까?

물론 만들 수 있습니다.
단, MySQL과 관련된 부분은 시키는대로 따라해야만 한다는 (많이 어렵진 않지만)
것만 염두해 주시면 됩니다.
MySQL을 자세히 다루지는 않을 겁니다.

* 위에서 MySQL 작업이 필요하다고 했는데 그건 뭔가요?
MySQL에 데이터를 저장하기 위해서는 우선 가장먼저 디비를 쓸 수 있는 User를 등록하고
그 유저가 사용할 db(데이터 베이스)와 table을 만들어야 합니다.
( db 를 책장이라고 보면 table 은 책장안의 책들입니다. )

다음 그림과 같은 방법으로 유저와 테이블을 만들 수 있습니다.

C:\>cd usr

C:\usr>cd bin

C:\usr\bin>mysql mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1 to server version: 3.23.49

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.
데이터베이스 관리 서버에 사용자를 등록합니다.
mysql> insert into user
    -> values ('localhost','testuser',password('mypass'),
    -> 'N','N','N','N','N','N','N','N','N','N','N','N','N','N');
Query OK, 1 row affected (0.04 sec)

사용자가 쓸 데이터베이스를 등록합니다.
mysql> insert into db values ('localhost','testdb','testuser',
    -> 'Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
Query OK, 1 row affected (0.01 sec)

mysql> \q
Bye

C:\usr\bin>myadmin create testdb <-- 데이터베이스를 생성합니다.

C:\usr\bin>myadmin reload <-- 데이터베이스 설정을 다시 로드합니다.

C:\usr\bin>mysql -utestuser -pmypass testdb <-- 등록한 아이디로 접속
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 5 to server version: 3.23.49

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> show databases; <-- 데이터베이스를 봅시다~ 어떤 것들이 있나?
+----------+
| Database |
+----------+
| mysql    | <-- MySQL 관리 데이터베이스
| test     | <-- 설치와 동시에 만들어진 테스트용 데이터베이스
| testdb   | <-- 방금 생성한 사용자의 데이터베이스
+----------+
3 rows in set (0.00 sec)

mysql> show tables; <-- 테이블이 뭐가 있는지 봅시다.
Empty set (0.00 sec) <-- 아무것도 없네요~ 당연히 방금만들었으니 없겠죠.

mysql> create table testtable( <-- 그럼 하나 만들어 봅시다.
    -> id int,
    -> name char(10)
    -> );
Query OK, 0 rows affected (0.02 sec)

mysql> show tables; <-- 다시 한번 테이블을 확인해 볼까요?
+------------------+
| Tables_in_testdb |
+------------------+
| testtable        |
+------------------+
1 row in set (0.00 sec) <-- 하나가 생겼네요. 방금 생성한 testtable!!

mysql> desc testtable; <-- 그럼 testtable 의 생김새는?
+-------+----------+------+-----+---------+-------+
| Field | Type     | Null | Key | Default | Extra |
+-------+----------+------+-----+---------+-------+
| id    | int(11)  | YES  |     | NULL    |       |
| name  | char(10) | YES  |     | NULL    |       |
+-------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql> select * from testtable; <-- 테이블안에 내용을 검색해 봅시다.
Empty set (0.00 sec) <-- 이런~ 테이블안에 데이터가 없군요.

mysql> insert into testtable values (1,'brown'); <-- 테이블에 데이터 추가
Query OK, 1 row affected (0.01 sec)

mysql> select * from testtable; <-- 다시 한번 테이블안의 내용 검색
+------+-------+
| id   | name  |
+------+-------+
|    1 | brown |
+------+-------+
1 row in set (0.00 sec) <-- 오옷~ 하나가 입력되어 있네요~ ㅋㅋㅋ

mysql>

계정을 받은 서버에서는 User와 DB를 만들 수 없음으로 시스템 관리자에게 문의하시고
중간부분의 mysql -u유저아이디 -p유저패스워드 유저DB 부분 부터 시작하시면 됩니다.

자 그럼 우리가 실제로 만들어야 하는 테이블의 구조를 살펴봅시다.

이 부분은 다음 강좌에 다시 다루기로 하고 우선은 테이블을 만들어 봅시다.

CREATE TABLE guestbook (
id int(11) DEFAULT '0' NOT NULL auto_increment,
name varchar(20),
home varchar(40),
email varchar(35),
comment text,
ip varchar(17),
reg_date datetime,
PRIMARY KEY (id)
);

위는 테이블을 만드는 명령입니다. (SQL 쿼리라고 합니다.)

일단 커맨드창을 띄웁니다. (실행에서 cmd - NT 계열,command - 98/ME)
cd C:\usr\bin
C:\usr\bin>mysql test
(아이디 등록시 - C:\usr\bin>mysql -u유저아이디 -p유저패스워드 디비이름)

Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 1865436 to server version: 3.23.37-log

Type 'help;' or '\h' for help. Type '\c' to clear the buffer

mysql> CREATE TABLE guestbook (
-> id int(11) DEFAULT '0' NOT NULL auto_increment,
-> name varchar(20),
-> home varchar(40),
-> email varchar(35),
-> comment text,
-> ip varchar(17),
-> reg_date datetime,
-> PRIMARY KEY (id)
-> );
Query OK, 0 rows affected (0.02 sec)
mysql> desc guestbook;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int(11)     |      | PRI | NULL    | auto_increment |
| name     | varchar(20) | YES  |     | NULL    |                |
| home     | varchar(40) | YES  |     | NULL    |                |
| email    | varchar(35) | YES  |     | NULL    |                |
| comment  | text        | YES  |     | NULL    |                |
| ip       | varchar(17) | YES  |     | NULL    |                |
| reg_date | datetime    | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
7 rows in set (0.01 sec)

처음이라 다소 어렵게 느껴 지실지도 모르겠지만..
충분히 따라 오실 수 있으리라 생각됩니다.

위의 이미지를 참조해 가면서 User랑 DB, Table 도 자기에 맞게 만들어 보시기 바랍니다.


방명록 만들기 - 소스를 뒤벼보자

강좌 22. 방명록 만들기 - 소스를 뒤벼보자
guestbook.php 소스코드
<HTML>
<HEAD>
<TITLE>GuestBook</TITLE>
</HEAD>

<BODY BGCOLOR="#006699" LINK="#99CCFF" VLINK="#99CCCC" TEXT="#FFFFFF">
<center>
<br><p>

<?php

// ====================================================================================
// DB 접속에 필요한 사항을 설정합니다.
// mysql_connect 함수는 말그대로 MySQL 디비에 접속하는 것입니다.
// 온라인 게임을 하려면 게임서버에 접속해야 하는것과 마찬가지로 디비를 쓰려면
// 우선 접속을 해야겠지요.
//
// Host (서버주소 - localhost를 쓰면 됩니다.)
// User (디비를 쓸 수 있는 권한을 가진 유저 아이디를 씁니다.)
// Passwd (등록된 유저의 비밀번호를 씁니다.)
//
// mysql_select_db 함수는 등록된 유저가 쓸 수 있는 디비를 선택하는 것입니다.
// MySQL에는 여러개의 DB를 만들 수 있거든요.그중 쓰고자 하는 하나를 선택하는 것입니다.
//
// 앞시간에 만든 디비와 비교해보면...
// Host = localhost , User = testuser , Passwd = mypass , DB = testdb 입니다.
// 위처럼 자신의 설정에 맞게 host,user,passwd,user_db 를 바꾸어 줍니다.
// ===================================================================================

$connect = mysql_connect("localhost","user","pass") or die("SQL server에 연결할 수 없습니다.");
mysql_select_db("user_db",$connect);

// ===================================================================================
// die 는 말그대로 죽었단 뜻이죠. DB 가 죽어버렸는지-_- 응답을 안한다는 소리입니다.
// $connect 변수를 유심히 보세요. mysql_connect 함수의 결과가 $connect 변수에 저장되죠?
// 그런데 다음 mysql_select_db 에서도 $connect 변수가 쓰이고 있습니다.
// 이것은 $connect 변수가 MySQL에 들어가도 좋다는 출입증과 같은 역할이기 때문입니다.
// 그리고 만약 또 다른 MySQL 서버에 접속했다면(혹은 다른 아이디로)
// 이 연결과 위의 연결을 구별하기 위한 구별자역할도 합니다.
// ===================================================================================

// ================
// 게시판 환경설정
// ================

$scale = 5; // 한 페이지당 자료 수
$admin_ip = '127.0.0.1';  // 삭제시 필요한 관리자 IP
$allow_html = 0; // HTML 허용 여부(1 -> yes, 0 -> no)

// 방명록의 테이블 이름은 guestbook 입니다.

// ===================================================================================
// $mode 는 new, up, del 또는 NULL 의 값을 가집니다. ( NULL = 無 )
// $mode 가 new 라는 값을 가지면 새 글을 입력할 때
// $mode 가 up 이라는 값을 가지면 글을 DB에 저장할 때
// $mode 가 del 이라는 값을 가지면 글을 지울때 입니다.
// ===================================================================================

// ==========
// 글 지우기
// ==========

if ($mode == 'del') {

   if ($REMOTE_ADDR != $admin_ip) //$REMOTE_ADDR 은 접속자의 IP정보입니다.
   { // 관리자 IP와 접속자 IP가 다르므로 글 삭제 권한이 없다.
         echo("
         <script>
            window.alert('관리자만 지울 수 있습니다.')
         </script>");
      echo("<meta http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
      exit;
   }
   else { //접속자 IP가 관리자 IP와 같으면 글을 지울 수 있는 권리가 있다.
      $que1 = "delete from guestbook where id=$id"; //SQL문을 만들고
      $result = mysql_query($que1,$connect); //SQL문을 실행한다.
   }
}

// =============
// 새 글 올리기
// =============

if ($mode == 'up') {
   if (!$name || !$comment) { //이름과 내용을 적으란 말야!! 적어!!!
      echo("
         <script>
            window.alert('이름과 남기실 말씀을 적어 주세요');
        history.go(-1);
     </script>");
      exit;
   }

   if (!$allow_html) { //HTML 입력을 허용하지 않으면
      $name = htmlspecialchars($name);              // HTML코드를 특수문자로 바꾸어버림
      $comment = htmlspecialchars($comment); // 예) <b> -> &lt;b&gt;
   }

// ===================================================================================
// htmlspecialchars 함수를 쓰면 HTML 코드가 적용되지 아니하고 코드를 그대로 출력해준다.
// addslashes 함수는 DB에 데이터를 입력할때 ' (작은따옴표) 같은 값들이 SQL 문에서
// 에러가 나지않고 입력되게 하기위한 배려이다.
// ===================================================================================

   $name = addslashes($name);
   $home = addslashes($home);
   $email = addslashes($email);
   $comment = addslashes($comment);

   $que1 = "insert into guestbook values ";
   $que1 .= "('','$name','$home','$email','$comment','$REMOTE_ADDR',now())";
   $result = mysql_query($que1,$connect);

   if ($result) { // DB에 입력이 잘되었다면..
      echo("<META http-equiv='Refresh' content='0; URL=$PHP_SELF'>");
      exit;
   }
   else { // DB에 데이터 입력중 오류가 발생한경우..
      echo("
         <script>
        window.alert('DB 오류가 발생하였습니다.');
        history.go(-1);
         </script>");
      exit;
   }
} //up end

// ==============
// 새 글 쓰기 폼
// ==============

if ($mode == 'new') { //새글쓰기 폼을 출력한다.

   echo("
      <FORM name='form' method='post' action='$PHP_SELF'>
      <TABLE border='0' cellspacing='1'>
      <TR>
      <TD width='109' bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
        이름</FONT></TD>
      <TD width='541'><P>&nbsp;<INPUT type='text' name='name' SIZE=6 MAXLENGTHTH='20'></TD>
      </TR>
      <TR>
      <TD bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
          HOMEPAGE</FONT></TD>
      <TD><P>&nbsp;http://<INPUT type='text' name='home' maxlength='40'></TD>
      </TR>
      <TR>
      <TD bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
          Email 주소</FONT></TD>
      <TD><P>&nbsp;<INPUT type='text' name='email' size=20  maxlength='40'></TD>
      </TR>
      <TR>
      <TD bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
          남기실 말씀</FONT></TD>
      <TD><P><TEXTAREA name='comment' rows='4' cols='35'></TEXTAREA></TD>
      </TR>
      <TR>
      <TD><P>&nbsp;</TD>
      <TD><P>&nbsp;<INPUT type='submit' name='submit' value='글올리기'></TD>
      </TR>
      </TABLE>
      <input type=hidden name=mode value='up'>
      </FORM>");
}

// =============
// 내용보여주기
// =============

if (!$mode || $result) { //$mode 변수가 NULL 이면 입력된 내용을 출력한다.

      if (!$start) { $start = 0; }

       $que1 = "select DATE_FORMAT(reg_date,'%Y.%m.%d') as date,reg_date,id,comment,name";
       $que1 .= ",home,email,ip from guestbook order by id DESC";
       $result = mysql_query($que1,$connect);
       $total = mysql_affected_rows();

       // ================================================================
       // $que1  이라는 SQL문을 작성하고 SQL문을 실행한다.
       // $total 에는 검색된 자료의 수가 입력된다.
       // ================================================================

       for($i=$start ; $i<$start+$scale ; $i++) {  //  start 에서 scale 까지 만

          if ($i < $total) { // 전체 자료 개수까지만 출력
         mysql_data_seek($result,$i); //검색된 자료중 $i 번째글을 찾고
         $row = mysql_fetch_array($result); //$i번째글의 내용을 $row 변수에 배열로 저장합니다.

         $row[comment] = stripslashes($row[comment]) ; //addslashes 한값을 제거
             echo("
         <TABLE border='0' cellspacing='1'>
         <TR>
         <TD width='109' bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
             <a href=$PHP_SELF?mode=del&id=$row[id]>
             <IMG src='./img/del.gif' width='22' height='13' border='0' alt='지우기'></a></FONT></TD>
         <TD width='541'><P><FONT face='굴림' size='2' color='#FAF1C7'>$row[0] from $row[ip]</FONT></TD>
         </TR>
         <TR>
             <TD width='109' bgcolor='#5485B6'><P align='center'>
             <FONT face='굴림' size='2' color='#CDDAE4'>Name</FONT></TD>
         <TD width='541'><P><FONT face='굴림' size='2' color='#E7EEF5'>$row[name]</FONT></TD>
         </TR>
             <TR>
         <TD width='109' bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
             Home / Email</FONT></TD>
         <TD width='541'><P><FONT face='굴림' size='2' color='#E7EEF5'>&nbsp;</FONT>");
         if ($row[email]) echo("<A href='mailto:$row[email]'>
         <IMG SRC=./img/mail.gif BORDER=0 ALT='편지쓰기' align=center><FONT face='굴림' size='2'
         color='#E7EEF5'>$row[email]</FONT></A> &nbsp;");
         if ($row[home]) echo("<a href=http://$row[home]><IMG SRC=./img/home.gif BORDER=0 ALT='홈페이지'
        align=center><FONT face='굴림' size='2' color='#E7EEF5'>http://$row[home]</FONT></a>");
         echo("
             </TD>
         </TR>
         <TR>
         <TD width='109' bgcolor='#5485B6'><P align='center'><FONT face='굴림' size='2' color='#CDDAE4'>
                 Comment&nbsp;</FONT></TD>
         <TD width='541'><P><FONT face='굴림' size='2' color='#E7EEF5'>$row[comment]</FONT></TD>
         </TR>
         <TR>
         <TD width='109'><P><HR size='1' noshade></TD>
         <TD width='541'><P><HR size='1' noshade></TD>
         </TR></TABLE>");
          }
      }
}

// ===================== 내용 보여주기 끝 ===========

if (!$mode || $result) {  // ==================== 하단 버튼 ==============
   echo("
   <center>
   <a href=$PHP_SELF?mode=new><IMG HEIGHT=30 WIDTH=30 SRC='./img/write.gif'
       VSPACE=0 HSPACE=0 ALIGN='TOP' BORDER=0 alt='방명록에 글쓰기'></a> ");

   $p_p = $start - $scale ; // 이전 페이지는 시작 글에서 $scale을 뺀값부터
   $n_p = $start + $scale ; // 다음 페이지는 시작 글에서 $scale을 더한값부터

   if ($p_p >= 0 && $mode != 'new') {
      echo("<a href='$PHP_SELF?start=$p_p'><IMG HEIGHT=30 WIDTH=30 SRC='./img/p-doc.gif' VSPACE=0
      HSPACE=0 ALIGN='TOP' BORDER=0 alt='이전 페이지'></a> ");
   }

   if ($n_p < $total && $mode != 'new') {
      echo("<a href='$PHP_SELF?start=$n_p'><IMG HEIGHT=30 WIDTH=30 SRC='./img/n-doc.gif' VSPACE=0
      HSPACE=0 ALIGN='TOP' BORDER=0 alt='다음 페이지'></a></center>");
   }
}

echo("
<p>
</BODY>
</HTML>");

?>

처음엔 잘 이해가 안가더라도 두세번 훓어보면 충분히 이해하실 수 있을거예요.
제가 SQL 관련된 부분은 설명을 별루 안드렸는데...
SQL의 기본은 추가,검색,수정,삭제 입니다.

* 추가,수정,삭제의 절차
1. SQL문 작성 (Insert into testtable .... , update testtable set ... , delete from testtable ... )
2. SQL문의 실행 (mysql_query( SQL문 , 연결정보 ))

* 검색의 절차 (데이터베이스의 핵심)
1. SQL문 작성 (select * from testtable ....)
2. SQL문의 실행 (mysql_query( SQL문 , 연결정보 ))
3. 검색된 값을 출력

소스를 잘 보면 충분히 이해할 수 있습니다.
그럼 멋진 방명록을 기대하겠습니다.

프로그램 보기

방명록 이미지 파일


게시판 만들기 - 방명록만 별거냐 게시판도 별거닷!

강좌 23. 게시판 만들기 1부 - 방명록만 별거냐 게시판도 별거닷!

지금 만들고자 하는 게시판은 제로보드 같은 거창한 게시판이 아닙니다.
그야말로 게시판계의 햇뼝아리 수준의 게시판이랍니다.
(오랜만에 강좌를 하니 말빨이 안습니다. 양해를..^^a)

앞서 우리는 방명록을 만드는 법을 배웠습니다. 방명록도 게시판의 일종이지요.
즉, 우리는 이미 게시판을 만들어 본 사람들이라 이겁니다. (쫄지맙시다!)

[게시판을 파헤쳐보자]

1. 글 목록 보기

2. 글 보기

3. 글 쓰기

4. 글 수정하기

5. 글 삭제하기

6. 검색하기,답글달기 등등

위 처럼 게시판의 구조는 아주 간단합니다.
방명록과의 차이는 글 목록을 보고 글을 읽느냐 (게시판) 아니면 글목록 자체가 바로 글이냐
정도의 차이입니다.
딱 보고 별거 없다는 생각이 드시나요? ^^

자 이제 게시판이 어떻게 생겨 먹은 지는 알았는데 어떻게 만들어야 하는지가 남았네요.

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

* 이 게시판은 일부러 많은 버그와 미비한 점을 가지게 만들었습니다.
* 이런 것들을 같이 고쳐나가는게 공부에 많이 도움이 될 거 같네요.


게시판 만들기 - 게시판을 만들 준비하기

게시판 만들기 2부 - 게시판을 만들 준비하기

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

위에서 예제소스를 다운받습니다.
새로운 디렉토리를 하나 만들고 거기에 압축을 풉니다.

<파일 리스트>

위와 같이 11개의 파일이 있습니다. (9개의 PHP파일,1개의 SQL 파일,1개의 도움말파일)

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
list.php | 글 목록
read.php | 글 읽기
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
predel.php | 글 삭제시 암호 입력
del.php | 글 삭제
testboard.sql | 테이블 생성문(쿼리)

위 표를 보시면 대충 어떤 파일이 무슨 역할을 하는지 알 수 있을겁니다.
자세한 내용은 각 부분별 강좌에 설명이 될테지만요..^^

* 테이블을 만들어 봅시다.

앞서 방명록 강좌에서 배웠듯이 이 게시판은 MySQL 이라는 데이터베이스를 씁니다.
강좌에서 테이블 만드는 법두 배우셨죠? ^^
(기억이 안나시는 분은 방명록강좌 참조하세요.)

* 테이블 저장 목록 정하기

테이블에 저장할 정보 목록
예를 들어 주소록을 만든다고 한다면 테이블에 {이름,나이,전화번호,주소} 등등의 정보를
저장하면 되겠죠.

우리는 여기서 게시판을 만들거니깐 저장해야할 목록들을 생각해 보면..
1. 글쓴이
2. 이메일 주소
3. 글의 비밀번호 (수정과 삭제를 위해서)
4. 글의 제목
5. 글의 내용
6. 글쓴 날짜
정도를 떠 올릴 수 있겠네요.

뭐 더 있을 수 있습니다.

글을 사람들이 몇 번봤는가? 하는 조회수도 있음 좋고
혹시 모르니깐 글쓴사람의 IP 주소 정도도 남겨주고요.
뭐 글쓴이의 홈페이지 주소도 저장할 수 있음 좋겠네요.

방금 말한 이러한 것들이 바로 테이블의 각 항목이 됩니다.

* 테이블 저장 목록을 간단한 영어로 바꾸기

한글은 지원이 안되니깐 영어두다가 바꿔봅시다.
(일단 위에 빨간색으로 체크한것만)

항 목 | 간단하게 영어로 변환한 항목
글쓴이 | name
이메일 주소 | email
글의 비밀번호 | pass
글의 제목 | title
글의 내용 | comment
글쓴 날짜 | wdate
IP 주소 | ip
조회수 | see

자 영어 목록 까지는 만들었네요.

그런데 하나 빠진게 있습니다.
글을 구분하는 구분자가 필요하거든요.
글을 읽거나 지우거나 수정하고자 할 때 어떤 글을 가르키는지 알려줘야 하잖아요.
그래서 글의 번호가 있어야 합니다.
그리고 그 글번호는 반드시 유일해야 하죠. 중복되면 안되겠죠? ^^

그래서 id 라는 글 번호를 하나더 추가합니다.

<완성된 테이블 저장 정보>
항 목 | 간단하게 영어로 변환한 항목
글의 번호 | id
글쓴이 | name
이메일 주소 | email
글의 비밀번호 | pass
글의 제목 | title
글의 내용 | comment
글쓴 날짜 | wdate
IP 주소 | ip
조회수 | see

* 저장 항목 타입과 크기 결정하기

우리는 PHP를 배우면서 변수의 타입(변수형)을 배운적이 있습니다.
문자는 Char 숫자는 int ,float 이런식으로 말입니다.
디스크와 메모리의 효율적 사용 (MySQL에서는 속도 향상까지..)을 위해서
타입과 그 크기를 설정해 주어야 합니다.

항 목 | 영어 항목 | 변수형 | 크기 | 비 고
글의 번호 | id | int | 11 | 글의 번호는 숫자
글쓴이 | name | varchar | 20 | varchar는 많이 길지 않는 문자열
이메일 주소 | email | varchar | 30 |
글의 비밀번호 | pass | varchar | 10 |
글의 제목 | title | varchar | 70 |
글의 내용 | comment | text |  | 충분히 긴 문자열
글쓴 날짜 | wdate | datetime |  | 날짜 및 시간
IP 주소 | ip | varchar | 16 |
조회수 | see | int | 11 |

위 처럼 항목에 따라 알맞은 변수형을 택하고 적당한 크기를 지정해주면 됩니다.

예)
글의 번호는 숫자이면서 11자리 정도의 수로 표현가능하니 int 형에 크기는 11이면됩니다.
(설마 인기가 좋아서 11자리가 넘는 글번호가 생성될리가..999억개의 글이..^^;;;)

글쓴이는 사람이름이니까 길어야 한글로 10자를 넘지 않고 넘더라도 다 보여줄 필요가 없습니다.
따라서 문자이니 varchar 형 (MySQL에서 문자열은 Varchar가 기본) 크기는 20 정도로 잡습니다.

text 타입은 varchar로는 표현할 수 없는 아주 긴 문자열을 쓸 때,
datetime 타입은 날짜와 시간 정보를 저장할 때 쓰입니다.

(자세한건 SQL 입문서를 찾아 보세요.)

* 테이블 생성문 만들기

testboard.sql 파일을 열어 보시면 테이블 생성문이 있습니다.

CREATE TABLE testboard (
id int(11) unsigned NOT NULL auto_increment,
name varchar(20) NULL,
email varchar(30) NULL,
pass varchar(10) NULL,
title varchar(70) NULL,
comment text,
wdate datetime NULL,
ip varchar(16) NULL,
see int(11) NULL,
PRIMARY KEY (id)
);

CREATE TABLE testboard 라는 것은 testboard 라는 이름의 테이블을 만들겠다는 뜻입니다.
testboard 뒤에 ( .... ); 가 있는데 그것은 괄호 안의 정보로 테이블을 만든 다는 것이죠.

괄호안은 위에서 만든 표와 동일한 정보로 SQL 문법에 맞추어 만든 것입니다.
대충 어떻게 만드는지 감이 오시죠? ^^

unsigned 는 '부호가 없는' 이란 뜻으로 0을 포함하는 양수만을 가진다는 뜻입니다.
NOT NULL 은 빈값이 들어가면 안된다는 뜻이구요.
NULL 은 당연히 빈값이 들어가도 된다는 뜻이겠지요.^^
auto_increment 는 자동으로 1씩 증가시키겠단 말입니다.

즉 id 값만 보면 0을 포함한 양수이면서 빈값이 들어가면 안되고 자동으로 1씩 증가합니다.
자동으로 1씩 등가한다는 것은 우리가 임의의 값을 입력하지 않아도 알아서 마지막값 + 1을 해서
저장한다는 뜻입니다.

마지막에 PRIMARY KEY (id) 라는게 있는데요.
이것은 이 테이블에서 기준이 되는 값이 id 라는 것입니다.
(글을 구분하기 위해 id 가 제일 중요하다고 말씀드렸죠? ^^)

* 데이터베이스에 테이블 만들기

앞서 방명록을 만들면서 배운 테이블 만드는 방법을 이용하여 위의 SQL문을 실행합니다.

mysql> desc testboard;
+---------+-------------+------+-----+----------------+
| Field   | Type        | Null | Key | Extra          |
+---------+-------------+------+-----+----------------+
| id      | int(11)     |      | PRI |  auto_increment|
| name    | varchar(20) | YES  |     |                |
| email   | varchar(30) | YES  |     |                |
| pass    | varchar(10) | YES  |     |                |
| title   | varchar(70) | YES  |     |                |
| comment | text        | YES  |     |                |
| wdate   | datetime    | YES  |     |                |
| ip      | varchar(16) | YES  |     |                |
| see     | int(11)     | YES  |     |                |
+---------+-------------+------+-----+----------------+
9 rows in set (0.00 sec)

축하합니다. 테이블이 만들어 졌습니다. ^^

* db_info.php 설정하기

db_info.php 파일은 데이터베이스 접속 정보를 가지고 있는 파일입니다.
이 파일을 데이터베이스를 사용하는 페이지 상단에 include 시켜주면 됩니다.
(물론 아이디와 패스워드 데이터베이스 이름을 자신에게 맞게 수정해서요..^^)


게시판 만들기 - 데이터베이스 정보

강좌 25. 게시판 만들기 - 데이터베이스 정보

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

게시판이 위와 같은 파일로 구성되어 있다는 것은 지난 강좌에서 알 게 되셨을 것입니다.

그럼 이번 강좌에서는 파일 하나 하나를 분석해 보도록 하죠.

* 데이터베이스 정보가 내손안에.. db_info.php

<?
$conn=mysql_connect("localhost","여기다 아이디","여기다 패스워드");
mysql_select_db("여기다 데이터베이스", $conn);
?>

우와~ 네줄밖에 안되네요~

<? 와 ?>을 빼면 딱 두줄... 자 그럼 파헤쳐볼까요?

위 코드에는 우리가 몰랐던 두 개의 함수가 있습니다.

mysql_connect 와 mysql_select_db입니다.

물론 우리가 방명록을 만들면서 한번 만나긴 했지만요.

* MySQL 이냐? 나 접속한다. 알쮜?

데이터베이스( DB)를 사용하려면 일단 사용할 수 있는 권한이 있어야 됩니다.

그래서 앞서 우리는 데이터베이스에 우리가 사용할 아이디를 등록했습니다.

그리고 우리가 사용할 DB를 만들어줬죠.

mysql_connect 함수는 말 그대로 mysql 에 접속하는 함수입니다.

데이터베이스가 존재하는 주소와 아이디 그리고 비밀번호를 입력하여 접속을 하는 것이지요.

mysql_connect("DB의 주소","아이디","패스워드"); 와 같은 형식으로 접속하게 됩니다.

DB의 주소에 localhost를 입력하는 이유는 같은 컴퓨터에 웹서버(우리는 아파치서버를 설치했습니다)와

데이터베이스(MySQL)이 같이 존재함을 의미합니다.

즉, 자기 자신의 주소에서 데이터베이스를 찾는다는 말이되죠.

기본적으로는 웹서버와 데이터베이스를 한 서버에 두지만 서비스 규모가 커지면 웹서버와 데이터베이스를 분리하기도 합니다. 데이터베이스 전용 서버와 웹서버 이렇게 나누는 것이지요. 만약 이렇게 나눴다면 localhost 대신에 데이터베이스가 존재하는 서버의 IP 주소나 도메인을 적어줘야겠지요.

사용자 아이디와 패스워드가 맞다면 접속이 되었음을 알려줍니다.

일종의 번호표를 달아주는 겁니다.

이 사람은 인증이 된 사람이니 MySQL을 사용할 수 있다라는 의미로요.

따라서 이 번호표는 매우 중요한 구실을 합니다.

뷔페에 가면 스티커 붙여주잖아요. ^^;; 잃어 버리면 큰일납니다.

이 번호표는 $conn 에 저장되게 됩니다.

이제 왜 $conn=mysql_connect 라고 하는지 이해 되시나요? (번호표를 $conn에 저장하겠다는 것이죠?)

* 내가 사용할 데이터베이스 선택

MySQL에 접속하면 이제 어느 데이터베이스를 사용할지 선택을 해야 합니다.

우리는 앞서 사용자가 사용할 데이터베이스를 등록해 주었지요?

이런 데이터베이스가 여러개라면 MySQL은 어떤 것을 사용해야 되는지 잘 모를테니..

서버에 알려주는 절차가 필요하게 됩니다.

mysql_select_db 말 그대로 사용할 데이터베이스를 선택하는 함수입니다.

함수명을 입력해 주면 되겠죠? ^^

근데 여기서 앞에서 나온 번호표를 이용합니다.

왜냐하면 사용자가 사용할 수 있는 데이터베이스인지 권한이 없는 다른 사람의 데이터베이스 인지를 구분하기 위해서지요.

권한이 맞다면 이제 부터는 맘껏 데이터베이스를 사용 할 수 있습니다.

* db_info.php 파일을 만든 이유?

게시판은 여러 페이지에서 데이터베이스를 이용하게 됩니다.

글읽기에도 사용되고 글저장할 때도 리스트를 뿌려줄 때도 너무너무 많이 사용하게 되지요.

그러면 매 페이지마다 MySQL 에 접속하는 위와같은 소스를 적어줘야 될까요?

매번 그렇게 적어준다면 귀찮을거 아녜요.

만약 사용자 아이디와 비밀번호가 바뀐다면?

모든 페이지에서 위 소스를 찾아 바꾸어주는 불편한 일이 생기게 됩니다.

따라서 앞서 배운 include를 이용하여 데이터베이스가 필요한 페이지에 추가해주면 되겠죠?


게시판 만들기 - 글 쓰기

강좌 26. 게시판 만들기 - 글 쓰기

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장 (쓰기 및 수정시)
edit.php | 글 수정
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 글을 입력해보자 - write.php

write.php 소스코드
<html>
<head>
<title>초 허접 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=insert.php method=post>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 align=center bgcolor=#999999>
<font color=white><B>글 쓰 기</B></font>
</td>
</tr>

<!-- 입력 부분 -->
<tr>
<td bgcolor=white>&nbsp;
<table>
<tr>
<td width=60 align=left >이름</td>
<td align=left >
<INPUT type=text name=name size=20 maxlength=10>
</td>
</tr>
<tr>
<td width=60 align=left >이메일</td>
<td align=left >
<INPUT type=text name=email size=20 maxlength=25>
</td>
</tr>
<tr>
<td width=60 align=left >비밀번호</td>
<td align=left >
<INPUT type=password name=pass size=8 maxlength=8> (수정,삭제시 반드시 필요)
</td>
</tr>
<tr>
<td width=60 align=left >제 목</td>
<td align=left >
<INPUT type=text name=title size=60 maxlength=35>
</td>
</tr>
<tr>
<td width=60 align=left >내용</td>
<td align=left >
<TEXTAREA name=comment cols=65 rows=15></TEXTAREA>
</td>
</tr>
<tr>
<td colspan=10 align=center>
<INPUT type=submit value="글 저장하기">
&nbsp;&nbsp;
<INPUT type=reset value="다시 쓰기">
&nbsp;&nbsp;
<INPUT type=button value="되돌아가기" onclick="history.back(-1)">
</td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>
</form>
</center>
</body>
</html>

이 페이지는 단순히 HTML로 구성되었습니다

PHP 코드가 한부분도 없죠?

왜 그럴까요?

이 페이지는 그저 글의 내용을 입력받는 부분만을 위한 것이기 때문입니다.

그냥 위 페이지를 HTML로 구현한 것일 뿐입니다. (물론 몇가지 정보를 입력해야 하지만^^)

PHP를 공부하시는 분이라면 이미 HTML을 터득하셨을거라 생각하지만 글 입력에서 중요한 몇부분을

다르게 표시해 두었습니다.

색깔로 표시된 부분 외는 그저 디자인을 위한 것일뿐입니다.

실제로는 색칠된 부분만 있어도 사용하는데는 무리가 없습니다.

위 그림을 보시면 우리가 글을 쓰기 위해 입력받는 항목을 알 수 있습니다.

  • 이름
  • 이메일
  • 비밀번호
  • 제목
  • 내용

이렇게 다섯가지를 입력 받습니다.

앞서 배운 문법 강좌에서 우리는 폼을 통해서 다음페이지로 어떻게 정보를 전달하는지 배웠습니다.

그것과 똑같은 방법으로 우리는 위와같은 항목을 다음페이지로 전달하면 되겠죠?

열심히 공부하신 분이라면 벌써부터 "아하~"하시면서 "다음강좌~!!"를 외치실지도 모르겠습니다.^^

<form action=insert.php method=post>

폼 정보를 입력합니다. 우리는 입력된 정보를 insert.php 라는 파일로 넘겨주어야 합니다.

insert.php 파일이 넘겨받은 정보를 데이터베이스에 저장하는 기능을 가지고 있기 때문입니다.

method=post 는 POST 방식으로 정보를 전달하겠다는 의미입니다.

POST vs GET
둘은 모두 정보를 다른 페이지로 전달하는 방식입니다.

GET 방식은 URL을 통해서 전달하는 방식으로 /index.php?name=brown 과 같이
파일이름 다음에 "?"를 통해서 ?변수명=전달될값 과 같은 식으로 전달하는 방식입니다.
두 개 이상의 값을 전달하고자 할 때는 &를 통해서 ?name=brown&homepage= http://ezphp.net 과 같이 전달합니다.

POST 방식은 HTTP 헤더라는 것을 통해서 전달하는 방식으로 GET 방식보다 안전한 방식입니다.

정보를 넘겨받을 페이지를 설정해 주었으니 이제 넘겨줄 항목들을 설정해 주도록 합시다.

우리가 넘겨줄 항목은 아래 처럼 다섯가지입니다.

  • 이름
  • 이메일
  • 비밀번호
  • 제목
  • 내용

이 항목들을 어떤 이름으로 전달해야 할지를 정해야겠군요.

정보를 넘겨줄 때 받는 쪽에서 구분할 수 있게 이름을 붙여주는 것이지요.

  • 이름 - name
  • 이메일 - email
  • 비밀번호 - pass
  • 제목 - title
  • 내용 - comment

저는 위와같은 이름을 정해 주었습니다. (이름은 영문과 지정된 특수문자 몇 개만 가능한거 아시죠?)

알아보기 쉽게 이름을 정해주는게 중요하겠죵~ ^^

(한번 이름을 asdajsdu23h89w8hefowah 라고 정해보시죠-_- 다음페이지에서 고생할겁니다-_-)

이름,이메일,비밀번호,제목은 몇자만 입력하니까 INPUT 폼을 이용하고

내용은 몇페이지가 될지도 모르니 TEXTAREA 폼을 이용하였습니다.

특히 비밀번호는 입력시에 별표로 표시되게끔 type을 password 로 지정하였습니다.

<INPUT type=text name=name size=20 maxlength=10>
<INPUT type=text name=email size=20 maxlength=25>
<INPUT type=password name=pass size=8 maxlength=8>
<INPUT type=text name=title size=60 maxlength=35>
<TEXTAREA name=comment cols=65 rows=15></TEXTAREA>

위가 무슨말인지 모르겠다 하시는 분들은 어서가서 HTML 공부하고 오세욧!!!ㅋㅋㅋ

자 이제 전달될 항목설정도 다 끝났으니 글 입력 버튼을 추가하면 되겠죠?

이번강좌는 거의 HTML 강좌였군요.^^

다음 강좌는 넘겨받은 정보를 데이터베이스에 저장하는걸 배워보도록 하겠습니다.


게시판 만들기 - 글 저장

강좌 27. 게시판 만들기 - 글 저장

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 글을 데이터베이스에 저장해보자! - insert.php

글을 입력받았으니 입력된 정보를 데이터베이스에 저장해 보도록합시다.

insert.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

$query = "insert into testboard values ('','$name','$email','$pass','$title','$comment',now(),'$REMOTE_ADDR',0)";
$result=mysql_query($query, $conn);

//데이터베이스와의 연결 종료
mysql_close($conn);

// 새 글 쓰기인 경우 리스트로..
echo ("<meta http-equiv='Refresh' content='1; URL=list.php'>");

?>
<center>
<font size=2>정상적으로 저장되었습니다.</font>

앞서 db_info.php 파일을 분석하면서 말씀드렸듯이 db_info.php 파일은 데이터베이스에 연결하는 기능을 합니다.

글을 저장하거나 수정하거나 하는 등의 데이터베이스 관련 페이지라면 반드시 데이터베이스에 연결해야 하기에

번거로움을 막고자 db_info.php 라는 파일을 만들어 필요할 때마다 include 하기로 했지요.

* 데이터베이스도 연결했고하니... 본격적으로 글을 저장해 볼까나?

우리는 앞서 데이터베이스와 이야기를 할 때 쿼리라는 것을 쓴다고 했습니다.

글을 저장해야 하니 글을 저장하는 쿼리를 만들면 되겠네요.

저장한다는 것은 테이블에 새로운 글을 추가한다는 이야기인 듯 하니..

그렇다면? 우리가 써야할 쿼리는?

그렇습니다! INSERT !!!. (^^ 퀴즈정답자에게는 소정의 상품이 없습니다-_-)

다시한번 복습을 해보도록 합시다.

INSERT 구문은 어떻게 쓴다고 했더라???? (곰곰히 생각해 보시길..)

INSERT INTO 테이블명 (입력될 항목1,항목2 .... ) VALUES ('입력값1','값2', ....);

혹은

INSERT INTO 테이블명 VALUES ('입력값1','값2', ...); <-- 이 경우는 모든값을 순서대로 입력해야 합니다.

그렇다면.. 입력받은 데이터를 한번 저장해 볼까나?

저장해야할 항목을 한번 뽑아보자.

항 목 | 이름
글번호 | id
글쓴이 | name
이메일 주소 | email
글의 비밀번호 | pass
글의 제목 | title
글의 내용 | comment
글쓴 날짜 | wdate
IP 주소 | ip
조회수 | see

위는 우리가 만든 게시판 테이블의 모양입니다.

저장되어야할 항목이 위처럼 9개군요.

앞서 글 쓰기 페이지에서 넘어온 값이 글쓴이,이메일,비밀번호,제목,내용 이렇게 5개니까

나머지 값들은 직접 입력을 해주어야 될 것 같습니다.

자 그럼 쿼리를 만들어 볼까요?

insert into testboard (id,name,email,pass,title,comment,wdate,ip,see)
values ('','$name','$email','$pass','$title','$comment',now(),'$REMOTE_ADDR',0);

쿼리를 완성했습니다.

항 목 | 이름 | 저장된 값
글번호 | id | 자동으로 1 증가 (입력값 없음)
글쓴이 | name | $name
이메일 주소 | email | $email
글의 비밀번호 | pass | $pass
글의 제목 | title | $title
글의 내용 | comment | $comment
글쓴 날짜 | wdate | now() - 현재 날짜와 시간 함수
IP 주소 | ip | $REMOTE_ADDR - IP 정보를 가진 변수
조회수 | see | 0 (최초 조회수를 0으로 설정)

완성된 쿼리를 $query 변수에 저장을 합니다.

그런데 위와 다르게 간소화를 했습니다.

모든 항목을 순서대로 입력을 하는 조건으로 항목명을 빼 버린 것입니다.

$result=mysql_query($query, $conn);

mysql_query 라는 함수를 통해서 데이터베이스에 우리가 만든 쿼리를 넘겨줍니다.

만약 쿼리에 문제가 없다면 데이터베이스에게 INSERT 쿼리를 넘겨줬으니 해당 테이블에

새로운 글을 추가했을 것입니다.

그 결과는 $result 에 저장되겠죠.^^

너무나 간단하게 글 입력이 끝나 버렸습니다.

데이터베이스를 열었으니 닫는일만 남았네요.

mysql_close 함수를 통해 데이터베이스를 닫습니다.

나머지 부분은 글이 잘 저장되었음을 알려주고 글 목록으로 보내는 일을 하는 HTML입니다.

글을 저장하는 부분은 현재 너무 문제가 많이 남아있습니다.

그저 글을 입력하는 것에는 부족함이 없지만 너무나 순수하기에...

때묻는 현실에서는 살아남기가 힘든점이 많습니다.

이는 나중에 하나씩 고쳐나가도록 합시다.


게시판 만들기 - 글 수정

강좌 28. 게시판 만들기 - 글 수정

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 글을 수정해보자! - edit.php

입력된 글을 수정해야 할 때가 많습니다.

특히 저같이 글을 잘 못쓰는 사람인 경우엔 더 한데요.

한번 글을 써놓고 다시한번 읽어보다가 수정하곤 하는게 습관이 되는 경우도 있죠^^

edit.php 소스코드
<html>
<head>
<title>초 허접 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=update.php?id=<?=$id?> method=post>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 align=center bgcolor=#999999>
<font color=white><B>글 수 정 하 기</B></font>
</td>
</tr>
<?
//데이터 베이스 연결하기
include "db_info.php";

// 먼저 쓴 글의 정보를 가져온다.
$result=mysql_query("select id,name,email,title,comment,ip from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);
?>

<!-- 입력 부분 -->
<tr>
<td bgcolor=white>&nbsp;
<table>
<tr>
<td width=60 align=left >이름</td>
<td align=left >
<INPUT type=text name=name size=20 maxlength=10 value=<?=$row[name]?>>
</td>
</tr>
<tr>
<td width=60 align=left >이메일</td>
<td align=left >
<INPUT type=text name=email size=20 maxlength=25 value=<?=$row[email]?>>
</td>
</tr>
<tr>
<td width=60 align=left >비밀번호</td>
<td align=left >
<INPUT type=password name=pass size=8 maxlength=8> (비밀번호가 맞아야 수정가능)
</td>
</tr>
<tr>
<td width=60 align=left >제 목</td>
<td align=left >
<INPUT type=text name=title size=60 maxlength=35 value=<?=$row[title]?>>
</td>
</tr>
<tr>
<td width=60 align=left >내용</td>
<td align=left >
<TEXTAREA name=comment cols=65 rows=15><?=$row[comment]?></TEXTAREA>
</td>
</tr>
<tr>
<td colspan=10 align=center>
<INPUT type=submit value="글 저장하기">
&nbsp;&nbsp;
<INPUT type=reset value="다시 쓰기">
&nbsp;&nbsp;
<INPUT type=button value="되돌아가기" onclick="history.back(-1)">
</td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>
</form>
</center>
</body>
</html>

이 파일은 앞서 배운 write.php 파일과 거의 흡사합니다.

왜냐하면 어차피 글을 수정한다는 것 자체도 글을 입력하는 것과 유사하기 때문이지요.

단지 다른 것이라면 입력폼에 기존에 입력한 글이 출력이 되어야 한다는 것 정도랄까요?

* 쓸데없는 부분을 없애고 알짜배기 코드만 보자.

<form action=update.php?id=<?=$id?> method=post>
<?
//데이터 베이스 연결하기
include "db_info.php";

// 먼저 쓴 글의 정보를 가져온다.
$result=mysql_query("select id,name,email,title,comment,ip from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);
?>

<!-- 입력 부분 -->
<INPUT type=text name=name size=20 maxlength=10 value=<?=$row[name]?>>
<INPUT type=text name=email size=20 maxlength=25 value=<?=$row[email]?>>
<INPUT type=password name=pass size=8 maxlength=8> (비밀번호가 맞아야 수정가능)
<INPUT type=text name=title size=60 maxlength=35 value=<?=$row[title]?>>
<TEXTAREA name=comment cols=65 rows=15><?=$row[comment]?></TEXTAREA>

필요없는 부분을 지우고나니 이번에도 소스는 별로 안되네요.

<form action=update.php?id=<?=$id?> method=post>

일단 action 설정을 합니다.

update.php 파일은 수정된 정보를 데이터베이스에 저장하는 기능을 합니다.

그러나 한가지 달라진 점이라면 GET 방식으로 id 값을 넘겨주고 있습니다.

왜그럴까요?

그렇습니다. 글을 수정한다는 것은 수정되어야할 어떤 글이 있다는 것이고 update.php 에게

어떤 글이 수정되어야 하는지를 알려주어야 하기 때문입니다.

id 는 앞서 글의 번호라고 정했습니다. 따라서 글 번호를 알려주는군요. ^^

글번호는 유일한 값이니 다른 글이 수정되는 경우는 없겠네요.^^

* 데이터베이스 연결

이 파일은 데이터베이스에 접근을 합니다.

기존 글의 정보를 가져와야 하기 때문이지요.

처음부터 새로 글을 쓴다면 얼마나 귀찮고 어렵겠습니까?

그래서 미리 기존의 글을 가져와서 보여주는 것이지요.

그렇기에 db_info.php를 include 합니다.

* 쿼리를 작성해 보자

글 수정에는 위에서 말씀드린대로 기존의 글을 불러와야 합니다.

따라서 기존글을 불러오는 쿼리를 작성해야 하겠네요.

INSERT,UPDATE,DELETE,SELECT 중에 어떤 것일까요?

네~ 정답입니다~.

SELECT를 이용하면 됩니다.(DELETE 라고 하신분들은 죄송합니다만 영어공부부터 다시 시작을....)

SELECT 출력될 값들 FROM 테이블명 WHERE 검색조건 과 같은 방법으로 쿼리를 작성하면 됩니다.

select id,name,email,title,comment,ip from testboard where id=$id;

위 쿼리를 번역하면 "testboard 테이블에서 id항목의 값으로 $id 값을 가지는 글이 있으면

id,name,email,title,comment,ip를 알려달라!" 라는 것입니다.

id는 글의 번호인데 유일한 값이니 딱 한 글만 검색되겠네요.

$result=mysql_query("select id,name,email,title,comment,ip from testboard where id=$id", $conn);

앞서 글 저장에서 써먹었듯이 mysql_query를 이용해 테이터베이스에게 쿼리를 전달합니다.

이번에는 $query 라는 변수를 이용하지 않고 그냥 그대로 입력하게 했습니다.

이렇게도 할 수 있다는 것을 보여드리기 위해서입니다.

절대로 두서없이 만드느라 그런 것이 아닙니다. 절대로..!! 믿어주십시오.

* 검색된 결과를 출력해보자.

$row=mysql_fetch_array($result);

mysql_fetch_array 함수를 이용하여 검색된 결과를 배열 형태로 받아옵니다.

위에서 id,name,email,title,comment,ip를 요구했기 때문에 $row[id],$row[name] 과 같은 방법으로

검색된 결과를 가져올 수 있습니다.

그러면 이제는 필요한 곳에다가 출력하면 되겠네요.

이하 코드들은 전부 각 폼에다가 해당 값을 출력하는 부분입니다.

그런데 한부분 유념하셔야 할것은 비밀번호까지 이전글에서 불러오면 안된다는것입니다.

수정버튼을 눌렀을때 비밀번호가 자동으로 입력되어 있다면 누구든지 글을 수정할 수 있을테니까요.

비밀번호를 비워두는것은 글쓴이가 맞는지 확인하기 위해서 반드시 공백으로 두셔야 합니다. ^^

* 글을 수정한후에는?

글을 수정하고 난 다음에 글 저장하기 버튼을 클릭하면 위에서 설정한 폼 정보를 보고

입력된 글을 update.php 파일로 넘겨줍니다.

update.php 파일은 넘겨받은 정보를 데이터베이스에 입력하면 되구요.

다음시간에는 어떻게 수정된 정보를 데이터베이스에 등록하는지 배우겠습니다.


게시판 만들기 - 수정된 글 저장

강좌 29. 게시판 만들기 - 수정된 글 저장

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 수정된 글을 저장해보자! - update.php

update.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

// 글의 비밀번호를 가져온다.
$result=mysql_query("select pass from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);

//입력된 값과 비교한다.
if ($pass==$row[pass]) { //비밀번호가 일치하는 경우

$query = "update testboard set name='$name',title='$title',email='$email',comment='$comment' where id=$id ";
$result=mysql_query($query, $conn);
}
else { // 비밀번호가 일치하지 않는 경우
echo ("
<script>
alert('비밀번호가 틀립니다.');
history.go(-1);
</script>
");
exit;
}

//데이터베이스와의 연결 종료
mysql_close($conn);

//수정하기인 경우 수정된 글로..
echo ("<meta http-equiv='Refresh' content='1; URL=read.php?id=$id'>");

?>
<center>
<font size=2>정상적으로 수정되었습니다.</font>

수정된 글을 저장하는 것에 대해 생각해 봅시다.

글 하나는 하나의 번호를 가지어야합니다.

그런데 수정된 글을 다시 그 번호랑 똑같이 추가한다면 분명 문제가 생길 것입니다.

그렇다면 기존의 글을 지우고 추가하면 된다는 생각이 듭니다.

물론 이것도 하나의 방법이겠습니다만..

update 라는 쿼리가 있으니 말그대로 수정이라는 방법을 쓸 수 있겠네요.

* 데이터베이스 연결

글을 수정하기 위해서 데이터베이스에 접근해야 합니다.

이제는 당연히 db_info.php를 include 해야겠다고 생각하시죠?

* 글쓴이가 맞는지 확인

이전 페이지에서 비밀번호를 전달해주었습니다.

수정전 글의 비밀번호와 입력된 비밀번호가 같은지 체크를 해서 글쓴이가 맞는지 확인을 할 수 있겠네요.

$result=mysql_query("select pass from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);

이 부분이 바로 글 번호를 통해 이전 글의 비밀번호를 가져오는 부분입니다.

이제는 간단한 쿼리 번역은 하실수 있겠죠? ^^

가져온 비밀번호와 입력된 비밀번호를 비교하면 되겠네요.

//입력된 값과 비교한다.
if ($pass==$row[pass]) { //비밀번호가 일치하는 경우

이 부분이 바로 비밀번호를 비교하는 부분입니다.

이해 되시죠? ^^

글의 패스워드를 비교하는 방법은 몇가지가 있을 수 있습니다.

위는 그저 한가지 방법일뿐입니다.

또 다른 방법을 한번 잘 생각해보세요.

* 쿼리를 작성해 보자

앞서 update를 이용해서 쿼리를 작성할거라고 말씀드렸습니다.

UPDATE 테이블명 SET 수정될항목=수정될값,항목2=값2 WHERE 수정 조건 과 같은 방법으로 쿼리를 작성하면 됩니다.

update testboard set name='$name',title='$title',email='$email',comment='$comment' where id=$id;

위 쿼리를 번역하면 "testboard 테이블에서 id항목의 값으로 $id 값을 가지는 글이 있으면

name,email,title,comment를 해당값으로 변경하라!" 라는 것입니다.

id는 글의 번호인데 유일한 값이니 딱 한 글만 수정 되겠네요.^^

자 쿼리를 작성했다면? 그렇습니다. 쿼리를 데이터베이스에 전달해야죠?

mysql_query를 통해 데이터베이스에 쿼리를 전달합니다.

update 도 insert 와 마찬가지로 쿼리를 전달하는 것만으로 수행이 끝나버립니다.

* 뒤치닥거리

나머지는 글쓴이 확인이 되면 글을 수정하고 아닌 경우에는 에러 메시지를 보여주는 부분입니다.

데이터베이스 닫는 것도 잊지 마세요~


게시판 만들기 - 글 읽기

강좌 30. 게시판 만들기 - 글 읽기

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 저장된 글을 출력해 보자 - read.php

read.php 소스코드
<html>
<head>
<title>초 허접 게시판</title>
<style>
<!--
    td  { font-size : 9pt;   }
    A:link  { font : 9pt;      color : black;     text-decoration : none;    font-family : 굴림;    font-size : 9pt;  }
    A:visited  {   text-decoration : none; color : black;    font-size : 9pt;  }
    A:hover  {     text-decoration : underline; color : black; font-size : 9pt;  }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>
<center>
<BR>
<?
//데이터 베이스 연결하기
include "db_info.php";

// 조회수 업데이트
$result=mysql_query("update testboard set see=see+1 where id=$id", $conn);

// 글 정보 가져오기
$result=mysql_query("select id,name,email,title,wdate,see,comment,ip from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);

?>

<table width=580 border=0  cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
    <td height=20 colspan=4 align=center bgcolor=#999999>
        <font color=white><B><?=$row[title]?></B></font>
    </td>
</tr>
<tr>
    <td width=50 height=20 align=center bgcolor=#EEEEEE>글쓴이</td><td width=240 bgcolor=white><?=$row[name]?></td>
    <td width=50 height=20 align=center bgcolor=#EEEEEE>이메일</td><td width=240 bgcolor=white><?=$row[email]?></td>
</tr>
<tr>
    <td width=50 height=20 align=center bgcolor=#EEEEEE>날&nbsp;&nbsp;&nbsp;짜</td><td width=240 bgcolor=white><?=$row[wdate]?></td>
    <td width=50 height=20 align=center bgcolor=#EEEEEE>조회수</td><td width=240 bgcolor=white><?=$row[see]?></td>
</tr>
<tr>
    <td bgcolor=white colspan=4>
        <font color=black>
            <pre><?=$row[comment]?></pre>
        </font>
    </td>
</tr>
<!-- 기타 버튼 들 -->
<tr>
    <td colspan=4 bgcolor=#999999>
        <table width=100%>
            <tr>
                <td width=200 align=left height=20>
                    <a href=list.php?no=<?=$no?>><font color=white>[목록보기]</font></a>
                    <a href=write.php><font color=white>[글쓰기]</font></a>
                    <a href=edit.php?id=<?=$id?>><font color=white>[수정]</font></a>
                    <a href=predel.php?id=<?=$id?>><font color=white>[삭제]</font></a>
                </td>

<!-- 기타 버튼 끝 -->

<!-- 이전 다음 표시 -->
                <td align=right>
                <?

                //  현재 글보다 id 값이 큰 글 중 가장 작은 것을 가져온다. 즉 바로 이전 글
                $query=mysql_query("select id from testboard where id > $id limit 1", $conn);
                $prev_id=mysql_fetch_array($query);

                    if ($prev_id[id]) // 이전 글이 있을 경우
                    {
                         echo "<a href=read.php?id=$prev_id[id]><font color=white>[이전]</font></a>";
                    }
                    else
                    {
                        echo "[이전]";
                    }

                $query=mysql_query("select id from testboard where id < $id order by id desc limit 1", $conn);
                $next_id=mysql_fetch_array($query);

                    if ($next_id[id])
                    {
                         echo "<a href=read.php?id=$next_id[id]><font color=white>[다음]</font></a>";
                    }
                    else
                    {
                        echo "[다음]";
                    }

                ?>
                </td>
            </tr>
        </table>
</b></font>
</td>
</tr>
</table>

<?
mysql_close($conn);
?>

</center>
</body>
</html>

저장된 글을 출력하는 페이지입니다.

* 글 읽기 파일의 구성

글 읽기 파일은 크게 두부분으로 나눌 수 있습니다.

위의 스크린샷을 통해 보이듯이

  1. 글의 내용을 출력하는 부분
  2. 목록보기 글쓰기 수정 등과 같은 버튼 부분

* 글의 내용 출력 부분

글의 내용을 가져와야 하니까 db_info.php를 include 시켰습니다.

// 조회수 업데이트
$result=mysql_query("update testboard set see=see+1 where id=$id", $conn);

// 글 정보 가져오기
$result=mysql_query("select id,name,email,title,wdate,see,comment,ip from testboard
where id=$id", $conn);
$row=mysql_fetch_array($result);

글을 읽었으니 조회수를 올려주고 글 번호를 통해 글의 내용을 비롯한 정보를 가져옵니다.

가져온 정보를 알맞은 위치에 <?=$row[title]?> 와 같은 방법으로 출력을 합니다.

여기까지 문제 없으시죠? ^^

* 그외 버튼 부분

버 튼 | 기 능 |
목록보기 | 글의 목록 페이지로 돌아갑니다. | list.php?no=$no , $no는 페이지 구분을 위한 값
글쓰기 | 글 쓰기 페이지로 갑니다. | write.php , 전달값없음
수정 | 글 수정 페이지로 갑니다. | edit.php?id=$id , 수정될 현재 글 번호를 넘겨줌
삭제 | 글 삭제 페이지로 갑니다. | predel.php?id=$id , 삭제될 현재 글 번호를 넘겨줌
이전 | 이전글이 있다면 이전글을 링크 | read.php?id=이전글번호 , 이전글 번호를 넘겨줌
다음 | 다음글이 있다면 다음글을 링크 | read.php?id=다음글번호 , 다음글 번호를 넘겨줌

글쓰기는 어차피 새로운 글을 쓰는 것이라 넘겨주는 값이 없습니다.

수정과 삭제는 현재 글에대한 수정과 삭제 버튼이므로 현재 글 번호를 해당 파일로 전달해줍니다.

목록보기는 $no 이란 값을 넘겨주는데 $no 변수는 목록 강좌에서 자세히 배우겠지만

페이지를 구분하는 인자가 되는 값입니다.

즉, $no 값에따라 첫 번째 페이지로 돌아갈런지 아니면 두 번째 페이지로 돌아갈건지가 결정이 됩니다.

그런데 현재 글을 보기전에 있던 목록으로 돌아가는게 맞겠죠?

페이지 정보는 위와같이 글을 읽기위해 글의 제목을 클릭하면 글 번호와 함께 같이 전달됩니다.

따라서 글을 읽고 난 후에는 목록보기를 통해 다시 이 페이지로 돌아오게끔 되는 것이지요.

*이전과 다음 버튼

이전과 다음의 기준은 첫 번째 페이지의 첫 글부터 읽는다고 했을 때 아래쪽의 글이 다음글이 되고 위쪽의 글이 이전 글이 됩니다.

그렇다면 이전글과 다음글은 어떻게 알 수 있을까요?

글 번호가 1씩 순차적으로 증가한다고 했으니 현재 글 번호를 기준으로 ±1 씩하면 되겠습니다.

이 방법은 너무 간단하고 좋은 반면에 극악무도한 복병이 있으니 그것은 바로 삭제입니다.

글을 삭제해 버린다면 그 번호는 사라져 버리게 됩니다.

따라서 다음글이 되었을 글이 이미 삭제되고 없다면 없는 글을 읽게 되는 상태가 됩니다.

자~ 어떻게 하면 이 문제를 해결할 수 있을까요? 답을 보시기 전에 한번쯤 생각해보시기 바랍니다.

현재 글을 기준으로 ...

이전글들은 현재 글 번호보다는 큰 값을 가지는 글입니다.

다음글들이란 놈들은 현재 글 번호보다는 작은 값을 가지는 글이죠.

그렇다면 현재 글 바로 이전의 글과 바로 다음의 글이란 것은 다음과 같이 생각할 수 있겠네요.

이전글 : 현재 글번호보다는 크되 번호가 큰 글들 중에서 가장 작은 번호의 글

다음글 : 현재 글번호보다는 작되 번호가 작은 글들 중에서 가장 큰 번호의 글

한번 맞는지 곰곰히 생각해 보세요.

위의 정의대로 이전글과 다음글을 구현하면 끝입니다.

방법은 여러 가지가 있을 수 있겠네요.

위의 소스는 그중 한가지 방법을 제시하고 있습니다. (최선의 선택은 아닌 듯)

//  현재 글보다 id 값이 큰 글 중 가장 작은 것을 가져온다. 즉 바로 이전 글
$query=mysql_query("select id from testboard where id > $id limit 1", $conn);

limit 1은 한 개의 결과만 가져오라는 뜻입니다.

$id 값보다 큰 글이 여러개가 있을 수도 있지만 큰 글중 id가 가장 작은글 하나만 검색하라는 말이죠.

이 쿼리는 order by id asc를 함축하고 있습니다.

order by 항목 이라는 것은 항목을 기준으로 정렬하라는 것입니다.

정렬에는 오름차순(1,2,3,4 식으로 정렬)과 내림차순(4,3,2,1 식으로 정렬) 정렬이 있습니다.

오름차순은 ASC 내림차순은 DESC 라는 키워드를 사용합니다.

즉 order by id asc 는 id값을 기준으로 오름차순으로 정렬하라는 말이죠.

(오름차순 정렬이 기본적인 정렬이기 때문에 사용하지 않아도 자동으로 정렬이 되게 됩니다.)

따라서 ..

1,3,6,4,2,5,7,9 번의 글들이 있고 현재 글이 5번이라고 했을 때 위의 쿼리를 실행하면 6,7,9 와 같이 정렬이되고

그중 제일 첫 번째로 검색된 6이 결과로 나오게 됩니다.

그렇다면 다음글은 어떻게 될까요?

$query=mysql_query("select id from testboard where id < $id order by id desc limit 1", $conn);

1,3,6,4,2,5,7,9 번의 글들중에 5번보다 작은 글들은 1,2,3,4 이렇게 4개의 글입니다.

desc 키워드가 있으니 이를 내림차순으로 정렬하면 4,3,2,1 과 같이 검색이 되겠죠.

그중에 첫 번째 검색된 4가 결과로 나오게 됩니다.


게시판 만들기 - 글 삭제

강좌 31. 게시판 만들기 - 글 삭제

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 글을 삭제해 보자

글을 삭제한다고 하면 제일 먼저 글쓴이인지 아닌지에대한 판단이 필요합니다.

글 삭제 버튼을 누름과 동시에 바로 삭제가 되어 진다면..

어느 누구나 내글을 지울 수 있다는 이야기가 되니까요.

그래서 글쓴이인지를 판단하고나서 글쓴이라고 밝혀진 후에 삭제하는 것이 맞겠네요.

(물론 그전에 로그인등과 같은 방법을 통해서 글쓴이라고 인증이 되었다면 이런 절차가 필요없겠지요.)

* 글쓴이인지에 대한 판단?

그렇다면 글쓴이 인지 아닌지는 어떻게 판단할 수 있을까요?

지문인식시스템을 통해서? 망막인증? 손등의 정맥검사를 통해서?

우리는 앞서 글을 쓸 때 비밀번호를 입력하게 했습니다.

바로 이 비밀번호란게 있으니 이것을 통해서 글쓴이인지 판단할 수 있습니다.

* 비밀번호는 어떻게 입력을 받나?

비밀번호를 이용하면 된다는 것은 알아냈는데..

그러면 어떻게 비밀번호를 입력받아야 할까요?

비밀번호를 입력받는다는 것은 폼(form)을 이용한다는 이야기인데..

글삭제 버튼 옆에다가 덩그러니 INPUT BOX를 달아놓을 수도 없고..

그래서 결국 어쩔 수 없이 비밀번호를 입력받는 페이지를 하나 만들었습니다.

* 비밀번호를 입력받자 - predel.php

predel.php 소스코드
<html>
<head>
<title>초 허접 게시판</title>
<style>
<!--
    td  { font-size : 9pt;   }
    A:link  { font : 9pt;color : black;text-decoration : none;font-family : 굴림;font-size : 9pt;  }
    A:visited  {   text-decoration : none; color : black;    font-size : 9pt;  }
    A:hover  {     text-decoration : underline; color : black; font-size : 9pt;  }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=del.php?id=<?=$id?> method=post>

<table width=300 border=0  cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
    <td height=20 align=center bgcolor=#999999>
        <font color=white><B>비 밀 번 호 확 인</B></font>
    </td>
</tr>
<tr>
    <td align=center >
        <font color=white><B>비밀번호 : </b>
        <INPUT type=password name=pass size=8 maxlength=8>
        <INPUT type=submit value="확 인">
        <INPUT type=button value="취 소" onclick="history.back(-1)">
    </td>
</tr>
</table>

소스를 보시면 아시겠지만 predel.php 파일은 그저 비밀번호를 입력받는 부분이기 때문에 PHP 소스코드는 거의 보이지 않습니다.

딱한군데 있네요. (색깔있는부분)

* predel.php에서 주의해야할 사항

글을 삭제하기위해 삭제버튼을 클릭하는 모습입니다.

삭제버튼의 링크가 predel.php 로 향하는 것을 알 수 있고 id 값을 전해주고 있음을 알 수 있습니다.

왜 일까요?

네.. 이제 하산하셔도 될 것같습니다.

해당하는 글만 삭제하기 위해 id 값(글번호)을 넘겨주는 것입니다.

삭제버튼을 클릭하면 위 처럼 predel.php 파일로 이동을 합니다.

앞서 넘겨준 글 번호가 따라다니는 군요.

자~ 그럼 비밀번호(1111)를 입력하고 확인 버튼을 눌러봅시다. (아직 del.php 파일을 만들지는 않았지만요^^)

(위는 테스트를 위해 Form 의 전송방식을 GET 으로 바꾸었습니다.)

pass 값이 1111 이라고 넘어왔네요.

근데 뭔가 이상합니다.

페이지를 찾을 수 없습니다. 라고 나온거 말구요-_-;;

자세히 보니 id 값이 사라져 버렸네요.

글번호가 없으면 글을 삭제하질 못하는데 말이죠.

왜 사라졌을까?

predel.php 까지는 잘 넘어왔는데..

del.php 에서는 사라졌다?

그렇다면 predel.php에서 값을 못넘겨준거군요.^^

아하~!

id 값을 넘겨주어야 하는데 비밀번호 넘겨주는 것만 신경쓰다가 미쳐 생각을 못했군요.

<form action=del.php?id=<?=$id?> method=post>

소스코드는 위와 같은 방식으로 action 값에 직접 id 값을 넣어주었습니다.

새로운 방식이죠? POST 와 GET을 동시에 쓰다니.. ^^

기억해 두세요. 가끔 유용하게 쓰입니다.

이 방법 말고도

<input type=hidden name=id value="<?=$id?>">

처럼 넘길 수도 있겠네요. ( Type 이 hidden 이니까 눈에는 안보이지만 값은 넘겨줄 수 있습니다. )

그리고 하나더..

앞서 위의 테스트를 위해 POST를 GET 으로 바꾸었다고 말씀드렸습니다.

왜 비밀번호를 POST로 전송했을까요?

네. 위 처럼 비밀번호가 URL을 통해 드러나면 안좋겠죠?

여럿이쓰는 컴퓨터라면 누군가 엿볼수도 있을테니까요.

그러니까 비밀번호와 같은 숨기고 싶은것들을 전송할때는 POST를 사용해야겠죠? ^^

우아~ 이렇게 이야기 하다보니 어느덧 소스설명이 끝나 버렸네요.

나머지 부분은 HTML 이잖아요. 그쵸? 이해되시죠? ^^

* 진짜로 삭제를 해보자. - del.php

del.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

$result=mysql_query("select pass from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);

if ($pass==$row[pass] )
{
     $conndel = "delete from testboard where id=$id ";
     $result=mysql_query($conndel, $conn);
}
else
{
    echo ("
    <script>
    alert('비밀번호가 틀립니다.');
    history.go(-1);
    </script>
    ");
    exit;
}
?>
<center>
<meta http-equiv='Refresh' content='0; URL=list.php'>
<FONT size=2 >삭제되었습니다.</font>

del.php 파일은 데이터베이스에서 글을 삭제하는 기능을 합니다.

글 수정에서도 배우셨듯이 일단 먼저 글쓴이인지 인증을 해야겠네요.

데이터베이스에서 글번호를 통해 글의 비밀번호를 알아냅니다.

$result=mysql_query("select pass from testboard where id=$id", $conn);
$row=mysql_fetch_array($result);

* 삭제 쿼리를 만들어보자.

비밀번호를 확인하고 맞으면 글을 삭제하면 됩니다.

그렇다면 이번에는 어떤 쿼리를 쓰면 될까요?

DELETE FROM 테이블명 WHERE 삭제조건

과 같은 방식으로 글을 지울 수가 있겠네요.

삭제조건으로는 지워야할 글을 구분할 수 있는 것이면 되는데 우리는 글번호가 있으니

글번호를 통해 지울 수가 있겠습니다.

delete from testboard where id=$id

이제 쿼리 만드는 것도 쉽죠?

* 삭제해 볼까나?

넘어온 글번호를 통해 글의 비밀번호를 가져온 다음

if ($pass==$row[pass]
)
{
$conndel =
"delete from testboard where id=$id ";
$result=mysql_query($conndel,
$conn);
}

predel.php를 통해 전달된 비밀번호와 데이터베이스를 통해 알아낸 비밀번호를 비교해서

일치한다면 앞서만든 쿼리를 데이터베이스에 전달해주면 되겠네요.

만약 다르다면? 비밀번호가 틀렸으니 다시 입력하라고 해야겠네요.

else
{
    echo ("
    <script>
    alert('비밀번호가 틀립니다.');
    history.go(-1);
    </script>
    ");
    exit;
}

이제 list.php 파일 하나만 남았습니다.

지금까지는 쉽게 잘 따라 오셨으리라 생각되네요.

생각보다 게시판이 어렵지 않죠?

마지막 파워를 끌어올려~~~ 러쉬합시다!!


게시판 만들기 - 글 목록

강좌 32. 게시판 만들기 - 글 목록

예제소스 : http://ezphp.net/lect/55/board.exe
예제보기 : http://ezphp.net/lect/55/list.php

<파일 리스트>

파일 이름 | 파일의 역할
db_info.php | 데이터베이스 접속 정보
write.php | 글 쓰기
insert.php | 글 저장
edit.php | 글 수정
update.php | 수정된 글 저장
read.php | 글 읽기
del.php | 글 삭제
predel.php | 글 삭제시 암호 입력
list.php | 글 목록
testboard.sql | 테이블 생성문(쿼리)

* 글 목록을 출력해보자 - list.php

list.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

#########################################################################
# LIST 설정
# 1. 한 페이지에 보여질 게시물의 수

$page_size=10;

# 2. 페이지 나누기에 표시될 페이지의 수

$page_list_size = 10;

#########################################################################

if (!$no || $no < 0) $no=0; //$no 값이 안넘어 오거나 잘못된(음수)값이 넘어오는 경우 0으로 처리

#########################################################################

// 데이터베이스에서 페이지의 첫번째 글($no)부터 $page_size 만큼의 글을 가져온다.
$query = "select id,name,email,title,DATE_FORMAT(wdate,'%Y-%m-%d') as date,see from testboard order by id desc limit $no,$page_size";
$result = mysql_query($query, $conn);

// 총 게시물 수 를 구한다.
// count 를 통해 구할 수 있는데 count(항목) 과 같은 방법으로 사용한다. * 는 모든 항목을 뜻한다.
// 총 해당 항목의 값을 가지는 게시물의 개수가 얼마인가를 묻는것이다.
// 따라서 전체 글수가 된다. count(id) 와 같은 방법도 가능하지만 이례적으로 count(*)가 조금 빠르다.
// 일반적으로는 * 가 느리다.
$result_count=mysql_query("select count(*) from testboard",$conn);
$result_row=mysql_fetch_row($result_count);
$total_row = $result_row[0];
//결과의 첫번째 열이 count(*) 의 결과다.

#########################################################################
# 총 페이지 계산

if ($total_row <= 0) $total_row = 0; // 총게시물의 값이 없거나 할경우 기본값으로 세팅

$total_page = floor(($total_row - 1) / $page_size); // 총게시물을 페이지 사이즈로 나눈뒤 내림을 한다.

# 총페이지는 총 게시물의 수를 $page_size 로 나누면 알수있다.
# 총페이지는 총 게시물의 수를 $page_size 로 나누면 알수있다.
# 총 게시물이 12개(1을 빼서 11이된다)이고 페이지 사이즈가 10이라면 결과는 1.1 이 나올것이다.
# 1.1 라는 페이지수는 한 페이지를 다 표시하고도 글이 더 남아있다는 뜻이다.
# 따라서 실제의 페이지수는 2가된다. 한 페이지는 2개의 글만 표시될것이다.
# 그러나 내림을 해주는 이유는 페이지수가 0부터 시작하기 때문이다. 따라서 1은 두번째 페이지이다.
# 총 게시물에 1을 빼주는 이유는 10페이지가 되면 10/10 = 1 이기 때문이다.
# 앞에서도 말했지만 1은 2번째 페이지를 뜻한다.
# 그러나 총게시물이 10개인 경우 한페이지에 모두 출력이 되어야 한다.
# 그래서 1을 빼서 10개인 경우 (10-1) / 10 = 0.9 로 한페이지에 출력하게 한다.
# 글이 0개가 있는 경우는 결과가 -1 이 되지만 -1은 무시된다.
# ( floor 는 내림을 하는 수학함수이다.)
#########################################################################
# 현재 페이지 계산

$current_page = floor($no/$page_size);

# $no 을 통해서 페이지의 첫번째 글이 몇번째 글인지 전달된다.
# 따라서 페이지 사이즈로 나누면 현재가 몇번째 페이지인지 알수있다.
# $no 이 10이고 페이지사이즈가 10 이라면 결과는 1이다. 앞서 페이지는 0부터 시작이라고 했으니 두번째 페이지임을 나타낸다.
# 그렇다면 $no 이 11이라면 1.1 이 되어버린다. 11번째 글도 두번째 페이지에 존재하므로 0.1은 무의미하니 버린다.
# 그런데 $no 이란 값이 $page_size 만큼씩 증가되는 값이기때문에 (0,10,20,30 과 같은 등차수열) 내림을 하는것 또한 무의미하다.
# 그러나 내림을 하는 이유는 $no 값에 11과 같은 값이 들어와도 제대로 출력되기를 바라는 마음에서 해놓은것이다.
?>

<html>
<head>
<title>초 허접 게시판</title>
<style>
<!--
    td  { font-size : 9pt;   }
    A:link  { font : 9pt;color : black;text-decoration : none;    font-family : 굴림;font-size : 9pt;  }
    A:visited  {   text-decoration : none; color : black;    font-size : 9pt;  }
    A:hover  {     text-decoration : underline; color : black; font-size : 9pt;  }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>
<center>
<BR>
<!-- 게시판 타이틀 -->
<font size=2>자~ 버그를 찾읍시다~ 버그를~~</a>
<BR>
<BR>

<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=580 border=0  cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=20 bgcolor=#999999>
    <td width=30 align=center>
        <font color=white>번호</font>
    </td>
    <td width=370  align=center>
        <font color=white>제 목</font>
    </td>
    <td width=50 align=center>
        <font color=white>글쓴이</font>
    </td>
    <td width=60 align=center>
        <font color=white>날 짜</font>
    </td>
    <td width=40 align=center>
        <font  color=white>조회수</font>
    </td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
while($row=mysql_fetch_array($result))
{

?>
<!-- 행 시작 -->
<tr>
    <!-- 번호 -->
    <td height=20  bgcolor=white align=center>
        <a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=$row[id]?></a>
    </td>
    <!-- 번호 끝 -->
    <!-- 제목 -->
    <td height=20  bgcolor=white>&nbsp;
        <a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=strip_tags($row[title], '<b><i>');?></a>
    </td>
    <!-- 제목 끝 -->
    <!-- 이름 -->
    <td align=center height=20 bgcolor=white>
        <font  color=black>
            <a href="mailto:<?=$row[email]?>"><?=$row[name]?></a>
        </font>
    </td>
    <!-- 이름 끝 -->
    <!-- 날짜 -->
    <td align=center height=20 bgcolor=white>
        <font  color=black><?=$row[date]?></font>
    </td>
    <!-- 날짜 끝 -->
    <!-- 조회수 -->
    <td align=center height=20 bgcolor=white>
        <font  color=black><?=$row[see]?></font>
    </td>
    <!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
} // end While

//데이터베이스와의 연결을 끝는다.
mysql_close($conn);
?>
</table>
<!-- 게시물 리스트를 보이기 위한 테이블 끝-->

<!-- 페이지를 표시하기 위한 테이블 -->
<table border=0>
<tr>
<td width=600 height=20 align=center rowspan=4>
<font  color=gray>
&nbsp;
<?
#########################################################################
# 페이지 리스트
# 페이지 리스트의 첫번째로 표시될 페이지가 몇번째 페이지인지 구하는 부분이다.

$start_page = (int)($current_page / $page_list_size) * $page_list_size;

#현재 페이지를 페이지 리스트 수로 나누면 현재 페이지가 몇번째 페이지리스트에 있는지 알게된다.
# 이또한 0을 기준으로 하기에 형변환(타입 캐스팅)을 해주었다.
# 형변환은 앞 강좌에서 배웠지만 위의 나누어지는 수가 1.2와 같이 유리수로 표시되기때문에
# int(정수) 형으로 형변환을 하게되면 소수점자리가 사라지게 된다.
# 즉, 위에서 사용한 floor 랑 같은 효과를 하게 되는 것이다.
# 여기에 floor 함수를 취하거나 위의 floor 를 형변환을 해도 상관없다.

# 페이지 리스트의 마지막 페이지가 몇번째 페이지인지 구하는 부분이다.
$end_page = $start_page + $page_list_size - 1;
if ($total_page < $end_page) $end_page = $total_page;

# 보여주는 페이지 리스트중에서 마지막 페이지가 되는 경우는 두가지이다.
# 1. 페이지가 페이지리스트 크기보다 더 많이 남아있을때
# 10개씩 뿌려주는데 총 11페이지가 존재한다면 11페이지는 두번째 목록페이지에 뿌려진다.
# 그렇다면 마지막 페이지 리스트는 10페이지 즉, 첫번째 페이지 + 9 번째 페이지이다.
# 2. 10개씩 뿌려주는데 5페이지 밖에 없다면?
# 마지막 리스트 페이지는 5 페이지가 된다.

#########################################################################
# 이전 페이지 리스트 보여주기
# 페이지 리스트가 10인데 13번째 페이지에 있다면 두번째 목록페이지를 보고 있는것이다.
# 이전 목록페이지로 가고 싶을 때 사용한다.

# 이전 페이지 리스트가 필요할때는 페이지 리스트의 첫 페이지가 페이지 리스트 수보다 클때다.
# 페이지가 적어도 페이지 리스트 수보다는 커야 이전 페이지 리스트가 존재할테니까 말이다.
# 페이지 리스트의 수가 10인데 총 5페이지밖에 없다면 이전 페이지 리스트는 존재하지 않는다.
if ($start_page >= $page_list_size) {

    # 이전 페이지 리스트값은 첫 번째 페이지에서 한 페이지 감소하면 된다.
    # $page_size 를 곱해주는 이유는 글번호로 표시하기 위해서이다.
    $prev_list = ($start_page - 1)*$page_size;
    echo  "<a href=\"$PHP_SELF?no=$prev_list\">◀</a>\n";
}

# 페이지 리스트를 출력
for ($i=$start_page;$i <= $end_page;$i++) {

$page=$page_size*$i; // 페이지값을 no 값으로 변환.
$page_num = $i+1; // 실제 페이지 값이 0부터 시작하므로 표시할때는 1을 더해준다. 페이지 0 -> 1

    if ($no!=$page){ //현재 페이지가 아닐 경우만 링크를 표시
        echo "<a href=\"$PHP_SELF?no=$page\">";
     }

    echo " $page_num "; //페이지를 표시

    if ($no!=$page){
        echo "</a>";
    }

}

# 다음 페이지 리스트가 필요할때는 총 페이지가 마지막 리스트보다 클 때이다.
# 리스트를 다 뿌리고도 더 뿌려줄 페이지가 남았을때 다음 버튼이 필요할 것이다.

if($total_page > $end_page)
{
    # 다음 페이지 리스트는 마지막 리스트 페이지보다 한 페이지 증가하면 된다.
    $next_list = ($end_page + 1)* $page_size;
    echo "<a href=$PHP_SELF?no=$next_list>▶</a><p>";
}
?>

</font>
</td>
</tr>
</table>

<a href=write.php>글쓰기</a>
</center>
</body>
</html>

소스코드에 주석을 많이 달아서 코드가 많이 길어보이지만 실제로는 그리 길지 않으니 너무 염려마세요^^

* list.php 의 역할

목록페이지가 어떤 일을 하는 것인지 알아보겠습니다.

  1. 말그대로 글의 목록을 보여준다.
  2. 다음 페이지로 이동할 수 있는 페이지 리스트를 보여준다.
  3. 글을 쓸 수 있는 버튼을 보여준다.

크게 이렇게 세가지 일을 하는 것을 알 수 있습니다.

* 목록을 출력해 보자.

list.php는 많은 글의 목록이면서 글을 볼 수 있게 해주는 다리입니다.

전체의 글을 다 보여주는 방명록과는 달리 글의 제목을 보여주면서 읽어볼 글을 선택할 수 있게 한 것이지요.

일반적으로 게시판의 목록은 위 그림의 구조처럼 생겼습니다.

글의 번호 제목 글쓴이 등등의 간략화된 정보를 보여주는 것이지요.

* 쿼리를 작성해 보자.

그렇다면 쿼리를 한번 만들어 봅시다.

목적은 글의 제목과 같은 몇 개의 항목을 가져오는 것이네요.

select id,name,email,title,DATE_FORMAT(wdate,'%Y-%m-%d') as date,see from testboard order by id desc

와 같은 쿼리를 통해 글 목록을 가져올 수 있겠습니다.

"testboard 테이블에서 id를 기준으로 내림차순으로 정열한후 모든 글에 대한 해당 항목을 가져오겠다"라는 의미입니다.

WHERE가 빠지므로해서 검색 조건이 사라졌습니다.

그렇다는 것은 모든 글들이 다 검색이 된다는 뜻이 되겠네요.

그런데 새로운 것이 보이는군요.

DATE_FORMAT(wdate,'%Y-%m-%d') as date

기존에는 wdate 라고만 썼었는데 DATE_FORMAT 이라는 것이 덧붙여졌습니다.

이는 날짜 형식을 변환하는 MySQL 내부 함수(프로시저)입니다.

PHP 함수가 아니라는 말이죠. ^^

데이터베이스에서 날짜를 가져올 때 %Y-%m-%d 와 같은 형식으로 보내 달라는 것입니다.

Y 는 year , m 은 month , d 는 day 의 약자입니다.

즉 연-월-일로 표시를 하겠다는 것이지요.

근데 Y는 대문자인데 나머지는 소문자군요.

Y는 4자리수의 연도를 뜻합니다. 03년도 이런 것이 아니라 정확히 2003년으로 표시 하고자 하는 것이죠.

m은 2자리수의 월을 뜻합니다. 두자리수의 월이란 01,02,03, ... 9,10,11,12 처럼 표시하겠다는 뜻입니다.

d도 마찬가지로 2자리수의 일을 뜻합니다. 01,02,03,04 .. 처럼 표시가 되겠죠. ^^

as date 라는 것은 DATE_FORMAT(wdate,'%Y-%m-%d') 의 별명을 date 라고 이름짓겠다라는 의미입니다.

우리가 mysql_fetch_array 와 같은 함수로 값을 가져올 때 $row[date] 라고 써서 값을 가져가라는 의미이죠.

* 목록 출력하면서 문제가 생겼어요!!

위처럼 목록을 출력했더니 심각한 문제가 생겼습니다.

처음에 글이 5개 10개 이렇게 있을 때는 문제가 없었는데..

100개가 되고 나니 글 목록이 100개가 되어 버려서 느리기도 하고 보기도 불편해졌습니다.

100개의 목록이라..

스크롤의 압박이 느껴지네요.^^;;

* 그럼 페이지를 나눠볼까?

100개의 글 1000개의 글을 한페이지에다가 모두 출력한다는 것은 너무나 어리석은 일입니다.

느리기도하고 글을 보는 사람들도 짜증이 나겠지요.

그래서 페이지를 나눠 한페이지당 몇 개의 글만을 보여주기로 해봅시다.

일단 글 10개만 가져오는 쿼리를 만들어야겠네요.

select * from testboard order by id desc limit 0,10;

다행히 limit 라는 것이 있었습니다. 앞에서 이전글 다음글을 표시할 때 배웠지요.

limit 1 은 한글만 가져오는 것이라고 배웠습니다.

그렇다면 limit 5는 5개의 글만 가져오는 것이겠네요.

근데 이번에는 limit 0,10 과 같이 두 개가 붙었습니다.

이것은 limit 시작,가져올개수 의 형태로 된 것입니다.

limit 0,10 이라는 것은 "0번 글부터 10개를 가져오라"는 뜻이됩니다.

limit 100,10 은 "100번 글부터 10개를 가져오라"는 뜻이 되겠지요.

근데.. 100번째 글이란건 어떤걸 기준으로 100번째란 말일까요?

그것은 검색조건이나 정렬에 따른 순서입니다.

그럼.. 완성된 쿼리는..

select id,name,email,title,DATE_FORMAT(wdate,'%Y-%m-%d') as date,see from testboard order by id desc limit 0,10

위 쿼리를 이용하면 가장 최근에 올라온 글 10개가 검색이 되겠네요.

그런데 지금까지는 하나의 글에 대해서만 검색을 했었는데..

여러개가 검색되면 어떻게 해야 할까 하는 생각이 듭니다.

그럴 때는 ..

while($row=mysql_fetch_array($result)) {
 echo $row[id];
}

와 같은 방법으로 검색된 글 모두를 출력할 수 있습니다.

그럼 이제 목록을 출력하는 것은 어떻게 해결이 되겠네요.

* 제목에 글 읽기 링크달기

목록은 뿌려줬지만 제목만 보면 뭐하겠습니까? ^^

이제 글을 읽을 수 있게 이미 앞에서 만든 글 읽기 페이지로 링크를 걸어주어야겠죠?

read.php에서 글을 읽을 때 글을 구분하는 기준은 글의 번호(id)였습니다.

따라서 글을 읽기 위해선 반드시 글 번호를 넘겨 주어야겠지요?

페이지 정보또한 넘겨주는 이유는 글을 읽다가 다시 목록으로 돌아오고자 할 때

그 글이 있던 목록페이지로 이동하기 위해서입니다.

페이지 정보가 없다면 항상 제일 첫 번째 페이지로 돌아갈테니까요.

네 번째 페이지의 목록을 보고 있었는데 첫 번째 페이지로 가 버린다면 귀찮아지겠죠?

* 페이지 리스트를 구현해 보자.

이제 머리를 조금 써야하는 부분에 도달했습니다.

사실 이번 게시판 강좌에서 가장 어려운부분이라고 할 수 있겠네요.

먼저 이 글을 보시기 전에 어떻게 페이지 리스트를 구현할지 한번 생각해보세요.

우리는 위와 같은 것을 만들 것입니다.

1~10,11~20,21~30 과 같은 페이지 리스트를 뿌려주고자 하는 것이지요.

그러기 위해서는 일단 페이지에 대한 정의를 먼저 해야 합니다.

변수명 | 역 할
$no | 페이지가 시작되는 첫 글의 순번
$page_size | 한페이지당 보여줄 게시물의 수
$page_list_size | 페이지 리스트에 보여줄 페이지의 수
$total_row | 총 게시물의 수
$total_page | 총 페이지수
$current_page | 현재 페이지 (0부터 시작)
$start_page | 페이지 리스트에서 첫 번째 페이지 (0부터 시작)
$end_page | 페이지 리스트에서 마지막 페이지 (0부터 시작)
$prev_list | 이전 페이지 리스트
$next_list | 다음 페이지 리스트

* no 에 대해 알아보자.

no 는 페이지 마다의 첫 번째 게시물의 순번을 뜻합니다.

여기서 순번은 글의 번호가 아니라 가장 최신 글에 대한 순서입니다.

즉 621번이 0번이 되고 611번은 9번 게시판의 가장 마지막 글은 1000번 과 같은식으로 되는 것이죠.

왜 no 란 값이 생겼는지는 앞서 만든 목록을 뿌려주는 쿼리를 보면 알 수 있습니다..

우리는 총 100개의 글이 있으면 그중 10개만 뿌려주고 싶었는데 그러기 위해서 limit 0,10 과 같은 것을 이용하였죠.

위에서 $page_size 라는 값을 정의 하였으니 limit 0,$page_size 가 되는 샘입니다.

그렇다면 두 번째 페이지도 세 번째 페이지도 0번부터 9번까지만 보여지는 사태가 생겨버립니다.

두 번째 페이지는 10번부터 보여져야하는데 말이죠.

결국 limit 0,$page_size에서 0의 값을 매 페이지마다 다르게 설정을 해주어야 한다는 결론이 납니다.

첫 번째 페이지는 0번이 첫글이 맞고 두 번째 페이지는 10번이, 세 번째 페이지는 20번이 첫글이 될 것입니다.

매 페이지마다 이렇게 목록의 첫 번째 글의 순번을 알고 있다면 페이지 나누기가 제대로 돌아가겠네요.

그래서 $no 값이 생겼습니다. 이해되시죠?

그럼 limit 0,$page_size 는 limit $no,$page_size 가 되면 되겠네요.

select id,name,email,title,DATE_FORMAT(wdate,'%Y-%m-%d') as date,see from testboard order by id desc limit $no,$page_size

* 목록 설정

#########################################################################
# LIST 설정
# 1. 한 페이지에 보여질 게시물의 수

$page_size=10;

# 2. 페이지 나누기에 표시될 페이지의 수

$page_list_size = 10;

#########################################################################

자 먼저 한페이지에 보여질 게시물의 수와 페이지 리스트에 보여질 페이지수를 정의합시다.

이 숫자를 변수로 만든이유는 한페이지에 20개의 글을 보여주고 싶을 때 혹은 리스트에 20개의 페이지를 보여주고 싶을 때

유용하게 사용할 수 있기 때문입니다.

* no 값 설정

no 값은 기본적으로 지정해 줄 것입니다.

그러나 처음 게시판으로 들어왔을 때 즉, http://ezphp.net/lect/55/list.php 라고 들어왔을 때는 no 값이 존재하지 않습니다.

따라서 no 값이 존재하지 않거나 이상한 값이 들어올 경우를 대비해서 기본값을 설정해야 합니다.

if (!$no || $no < 0) $no=0; //$no 값이 안넘어 오거나 잘못된(음수)값이 넘어오는 경우 0으로 처리

$no 값이 없거나 0보다 작다면(0부터 시작인데 있을 수 없는 값입니다.) 0으로 처리를 하는 부분입니다.

* 목록을 보여주기 위한 쿼리 실행

//
데이터베이스에서 페이지의 첫번째 글($no)부터 $page_size 만큼의 글을 가져온다.
$query = "select id,name,email,title,DATE_FORMAT(wdate,'%Y-%m-%d') as
date,see from testboard order by id desc limit $no,$page_size";
$result = mysql_query($query,
$conn);

데이터베이스에 현재 페이지에 대한 글을 요청하는 쿼리를 전달합니다.

* 총 게시물의 수

// 총 게시물 수 를 구한다.
$result_count=mysql_query("select count(*) from testboard",$conn);
$result_row=mysql_fetch_row($result_count);
$total_row = $result_row[0];
//결과의 첫번째 열이 count(*) 의
결과다.

총 게시물의 수를 구하는 이유는 총 페이지 수를 구하기 위함입니다.

그러나 총 게시물이 몇 개나 있는지 게시판에 보여줄 때도 사용할 수 있겠네요.

* 총 페이지의 수

#########################################################################
# 총 페이지 계산
if ($total_row <= 0) $total_row = 0; // 총게시물의 값이 없거나 할경우 기본값으로 세팅
$total_page = floor(($total_row - 1) / $page_size); // 총게시물에 1을 뺀후 페이지 사이즈로 나누고 내림을 한다.
# 총페이지는 총 게시물의 수를 $page_size 로 나누면 알수있다.
# 총 게시물이 12개(1을 빼서 11이된다)이고 페이지 사이즈가 10이라면 결과는 1.1 이 나올것이다.
# 1.1 라는 페이지수는 한 페이지를 다 표시하고도 글이 더 남아있다는 뜻이다.
# 따라서 실제의 페이지수는 2가된다. 한 페이지는 2개의 글만 표시될것이다.
# 그러나 내림을 해주는 이유는 페이지수가 0부터 시작하기 때문이다. 따라서 1은 두번째 페이지이다.
# 총 게시물에 1을 빼주는 이유는 10페이지가 되면 10/10 = 1 이기 때문이다.
# 앞에서도 말했지만 1은 2번째 페이지를 뜻한다.
# 그러나 총게시물이 10개인 경우 한페이지에 모두 출력이 되어야 한다.
# 그래서 1을 빼서 10개인 경우 (10-1) / 10 = 0.9 로 한페이지에 출력하게 한다.
# 글이 0개가 있는 경우는 결과가 -1 이 되지만 -1은 무시된다.
# ( floor 는 내림을 하는 수학함수이다.)

총 페이지는 총 게시물의 수를 통해 알 수 있습니다.

한 페이지에 보여지는 글의 수로 나누면 몇 개의 페이지가 존재하는지 나오겠죠?

* 현재 페이지의 수

#########################################################################
# 현재 페이지 계산

$current_page = floor($no/$page_size);

# $no 을 통해서 페이지의 첫번째 글이 몇번째 글인지 전달된다.
# 따라서 페이지 사이즈로 나누면 현재가 몇번째 페이지인지 알수있다.
# $no 이 10이고 페이지사이즈가 10 이라면 결과는 1이다. 앞서 페이지는 0부터 시작이라고 했으니 두번째 페이지임을 나타낸다.
# 그렇다면 $no 이 11이라면 1.1 이 되어버린다. 11번째 글도 두번째 페이지에 존재하므로 0.1은 무의미하니 버린다.
# 그런데 $no 이란 값이 $page_size 만큼씩 증가되는 값이기때문에 (0,10,20,30 과 같은 등차수열) 내림을 하는것 또한 무의미하다.
# 그러나 내림을 하는 이유는 $no 값에 11과 같은 값이 들어와도 제대로 출력되기를 바라는 마음에서 해놓은것이다.

현재 페이지는 중요한 역할을 합니다.

페이지 리스트를 뿌려줄 때 요긴하게 쓰이게 되거든요.

페이지 리스트의 첫 번째 페이지와 마지막 페이지가 어떻게 될 것인지 결정하는 놈이 바로 요놈입니다.

현재 페이지가 13페이지라면 페이지 리스트는 11 ~ 20 까지 출력을 해주어야 할테니까요.

* 페이지 리스트의 첫번째 페이지 구하기

$start_page = (int)($current_page / $page_list_size) * $page_list_size;

#현재 페이지를 페이지 리스트 수로 나누면 현재 페이지가 몇번째 페이지리스트에 있는지 알게된다.
# 이또한 0을 기준으로 하기에 형변환(타입 캐스팅)을 해주었다.
# 형변환은 앞 강좌에서 배웠지만 위의 나누어지는 수가 1.2와 같이 유리수로 표시되기때문에
# int(정수) 형으로 형변환을 하게되면 소수점자리가 사라지게 된다.
# 즉, 위에서 사용한 floor 랑 같은 효과를 하게 되는 것이다.
# 여기에 floor 함수를 취하거나 위의 floor 를 형변환을 해도 상관없다.

현재 페이지를 통해 페이지 리스트가 몇 페이지부터 시작해야되는지를 결정합니다.

현재 페이지의 범위(A) | $page_list_size(B) | A / B |  | (int)(A/B) * B | 첫 번째 | 마지막
0 ~ 9 | 10 | 0 ~ 0.9 | (int) 0 | 0 | 0 | 9
10 ~ 19 | 10 | 1 ~ 1.9 | (int) 1 | 10 | 10 | 19
20 ~ 29 | 10 | 2 ~ 2.9 | (int) 2 | 20 | 20 | 29
30 ~ 39 | 10 | 3 ~ 3.9 | (int) 3 | 30 | 30 | 39
0 ~ 9 | 20 | 0 ~ 0.45 | (int) 0 | 0 | 0 | 19
10 ~ 19 | 20 | 0.5 ~ 0.9 | (int) 0 | 0 | 0 | 19
20 ~ 29 | 20 | 1 ~ 1.45 | (int) 1 | 10 | 20 | 39
30 ~ 39 | 20 | 1.5 ~ 1.9 | (int) 1 | 10 | 20 | 39

위와 같은 표대로 첫 번째 페이지가 결정이 됩니다.

* 페이지 리스트의 마지막 페이지 구하기

# 페이지 리스트의 마지막 페이지가 몇번째 페이지인지 구하는 부분이다.
$end_page = $start_page + $page_list_size - 1;
if ($total_page < $end_page) $end_page = $total_page;

# 보여주는 페이지 리스트중에서 마지막 페이지가 되는 경우는 두가지이다.
# 1. 페이지가 페이지리스트 크기보다 더 많이 남아있을때
# 10개씩 뿌려주는데 총 11페이지가 존재한다면 11페이지는 두번째 목록페이지에 뿌려진다.
# 그렇다면 마지막 페이지 리스트는 10페이지 즉, 첫번째 페이지 + 9 번째 페이지이다.
# 2. 10개씩 뿌려주는데 5페이지 밖에 없다면?
# 마지막 리스트 페이지는 5 페이지가 된다.

현재 페이지의 범위(A) | 첫 번째(A) | $page_list_size(B) | A + B - 1 | 마지막
0 ~ 9 | 0 | 10 | 0 + 10 - 1 = 9 | 9
10 ~ 19 | 10 | 10 | 10+ 10 -1 = 19 | 19
20 ~ 29 | 20 | 10 | 20 + 10 - 1 = 29 | 29
30 ~ 39 | 30 | 10 | 30 + 10 - 1 = 39 | 39
0 ~ 9 | 0 | 20 | 0 + 20 - 1 = 19 | 19
10 ~ 19 | 0 | 20 | 0 + 20 - 1 = 19 | 19
20 ~ 29 | 20 | 20 | 20 + 20 - 1 = 39 | 39
30 ~ 39 | 20 | 20 | 20 + 20 - 1 = 39 | 39

마지막 페이지는 첫 번째 페이지에서 (페이지리스트의 수 - 1) 만큼을 더하게되면 됩니다.

그냥 페이지리스트의 수를 더해 버렸다면? 다음 목록 페이지의 첫 번째 페이지값이 되어 버리겠네요.

* 이전 페이지

#########################################################################
# 이전 페이지 리스트 보여주기
# 페이지 리스트가 10인데 13번째 페이지에 있다면 두번째 목록페이지를 보고 있는것이다.
# 이전 목록페이지로 가고 싶을 때 사용한다.

# 이전 페이지 리스트가 필요할때는 페이지 리스트의 첫 페이지가 페이지 리스트 수보다 클때다.
# 페이지가 적어도 페이지 리스트 수보다는 커야 이전 페이지 리스트가 존재할테니까 말이다.
# 페이지 리스트의 수가 10인데 총 5페이지밖에 없다면 이전 페이지 리스트는 존재하지 않는다.
if ($start_page >= $page_list_size) {

    # 이전 페이지 리스트값은 첫번째 페이지 리스트에서 한페이지 감소하면 된다.
    # $page_size 를 곱해주는 이유는 글번호로 표시하기 위해서이다.
    $prev_list = ($start_page - 1)*$page_size;
    echo  "<a href=\"$PHP_SELF?no=$prev_list\">◀</a>\n";
}

이전 페이지는 첫 번째 페이지의 바로 전 페이지입니다.

시작페이지값에서 1을 빼주면 바로 전 페이지가 되겠죠?

$page_size 값을 곱해주는 이유는 no 값으로 바꾸기 위해서 입니다.

시작페이지가 10일 때 10 - 1 = 9가 되고 9번 페이지는 0부터 시작햇으므로 실제로 10번째 페이지가 됩니다.

첫 번째 페이지는 no 이 0 이었고 두 번째 페이지는 no 이 10 이었으니 10번째 페이지는 90이 되겠네요.

그래서 $start_page - 1 에다가 $page_size를 곱해주면 90이 되어 버리니 no 값으로 자동으로 바뀌게 되네요.

* 페이지 리스트

# 페이지 리스트를 출력
for ($i=$start_page;$i <= $end_page;$i++) {

$page=$page_size*$i; // 페이지값을 no 값으로 변환.
$page_num = $i+1; // 실제 페이지 값이 0부터 시작하므로 표시할때는 1을 더해준다. 페이지 0 -> 1

    if ($no!=$page){ //현재 페이지가 아닐 경우만 링크를 표시
        echo "<a href=\"$PHP_SELF?no=$page\">";
     }

    echo " $page_num "; //페이지를 표시

    if ($no!=$page){
        echo "</a>";
    }

}

페이지 리스트는 $start_page부터 시작하여 $end_page 까지 출력하면 됩니다.

앞에서도 그랬지만 페이지를 구분할 때는 no 값을 이용해야 하니까 페이지 값을 no 으로 변환해야겠네요.

10 페이지의(0부터 시작) 첫 번째 글의 no 값은 10*10($page_size)입니다.

바로 전 페이지까지 총 10개씩 10개의 페이지가 있었다는 의미이지요.

그래서 11번째 페이지인 10번 페이지의 첫 번째 글은 101번재 글이 되는 셈입니다.

그런데 no 값은 0부터 시작되니까 100 번이 되는군요.

페이지값은 0부터 시작하지만 게시판에 보여줄 때도 0페이지 1페이지 이렇게 보여줄 수는 없겠죠?

그래서 보여줄 때 1씩 더해서 보여줍니다. 1부터 시작하는 값인 것처럼요.

* 다음 페이지

# 다음 페이지 리스트가 필요할때는 총 페이지가 마지막 리스트보다 클 때이다.
# 리스트를 다 뿌리고도 더 뿌려줄 페이지가 남았을때 다음 버튼이 필요할 것이다.

if($total_page > $end_page)
{
    # 다음 페이지 리스트는 마지막 리스트 페이지보다 한 페이지 증가하면 된다.
    $next_list = ($end_page + 1)* $page_size;
    echo "<a href=$PHP_SELF?no=$next_list>▶</a><p>";
}

다음페이지는 이전 페이지와 마찬가지로 마지막 페이지의 바로 다음페이지가 됩니다.

따라서 1을 더해주면 되겠죠?

* 글쓰기

이제 목록과 페이지 나누기 모두를 만들었습니다.

글쓰기 버튼만 추가해 주면 끝이네요.

* 초 허접 게시판 강좌는 여기서 끝나는 건가요?

아닙니다.

이제부터 시작이라고 할 수가 있겠네요.

지금까지는 너무나 단순한 모양의 게시판이었습니다.

버그도 많이 있고 기능도 너무 없죠.

이는 제가 원한 바입니다.

이제 다음강좌는 이 게시판을 어떻게 업그레이드하는지에 대한 강좌가 되겠습니다.

초 허접 게시판을 멋드러진 게시판으로 만드는 "Upgade 대작전"을 기대하세요~ ^^

* 여담

이렇게 어느덧 허접하지만 게시판을 만들 수 있는 실력이 되셨습니다.

게시판이란거 처음에 너무 어렵게만 느끼다가 이렇게 직접 만들어 보시니깐

어렵지만은 않다고 생각하시죠?

모든일이 다 그렇습니다. 해보지 않고 두려움을 느낄 필요가 없는 것이지요.

방학기간이라 시간이 되는대로 최대한 많은 강좌를 추가할 예정입니다.

배워야할 것이 너무 많거든요.

우리는 지금 PHP의 더 넓은 바다의 한켠에 와 있습니다.

이제 돛을 펴고 넒은 대양으로 같이 나가봅시다.

제가 부족하지만 나침반이 되어 드리겠습니다.


PHP 디버깅 :: 버그,디버그,에러

강좌 33. PHP 디버깅 :: 버그,디버그,에러

버그

버그는 프로그램의 오류를 뜻하는 말입니다. (더 정확히하면 오류를 일으키는 부분을 뜻합니다.)

근데 버그는 우리나라말로 벌레란 뜻이지요.

오류 = 벌레??? (PHP 문법상으로는 오류 == 벌레 라고 해야겠군요..^^)

언뜻보기엔 왜 오류를 벌레라는 단어로 정의했는지 이해가 안됩니다.

여기엔 사연이있는데요.

1940년쯤 컴퓨터를 통해 작업을 하는데 오류가 생겼답니다.

오류가 날 상황이 아니었는데도 말이죠.

그래서 기술자들이 컴퓨터를 조사해본 결과 벌레(모기) 한 마리가 그 오류의 주범이었습니다.

이 사건이 있은후 프로그램상의 오류를 버그라는 용어로 쓰기 시작했다는군요.

디버그

중학교때 de 라는 접두사를 배운적이 있을겁니다. (고등학교땐가?)

제가 고등학교때는 능X 보케블러리란 책이 인기가 있었는데..

어휘력을 기르는데 접두사와 접미사등을 잘 이해하고 있으면 모르는 단어도 뜻을 짐작할 수 있다는

발상으로 만든 책이었습니다.

de 라는 접두사는 un 등과 함께 반대(?)를 뜻하는 말이죠. (하하 영어를 한지 오래되서 확신이 안서네요-_-)

debug 는 "벌레를 잡는다"라는 뜻입니다.

즉, 프로그램의 오류를 찾아서 수정하는 것을 말합니다.

(다우니의 영어강좌였습니다-_-;;;)

에러

에러는 프로그램이 사용자가 기대하는 바와 다르게 다른 결과로 되는 것을 말합니다.

즉 앞서 말한 버그같은 것을 통해서 생기거나 사용자의 실수를 통해서 생기는 현상입니다.

에러에는 여러 가지 종류가 있습니다.

  1. Syntex Error (문법 에러)
  2. Run-Time Error (실행시간 에러)
  3. Logic Error (논리 에러)
  4. System Error (컴퓨터 환경에 따른 에러)

뭔가 말이 어려워 보이죠? ^^

하나씩 짚어가보겠습니다.

Syntex Error - 문법 에러

이는 말 그대로 문법을 잘못 이해하거나 잘못 사용해서 생기는 에러를 말합니다.

PHP 문법에서 세미콜론(;)의 중요성을 아시죠?

실수로 문장의 끝에 세미콜론을 붙이지 않았다면 문법이 틀렸기 때문에 Syntex Error 가 납니다.

문법 에러는 에러 메시지를 통해 쉽게 찾을 수 있습니다.

Run-Time Error - 실행시간 에러

Run-Time Error 는 프로그램을 실행하면서 생기는 에러를 뜻합니다.

PHP는 코딩후에 바로 실행을 통해 확인하기 때문에 Run-Time Error 의 구분이 좀 모호한데요.

주로 어떤값을 0으로 나누던가 하는 등의 에러가 Run-Time Error입니다.

Logic Error - 논리 에러

논리상의 에러를 말합니다.

문법상으로는 틀린 것이 없지만 더해야 할 부분을 뺀다거나 빼야할부분을 곱한다거나 하는 등의 에러가 논리 에러입니다.

주로 부주의나 잘못된 이해를 통해 생기게 됩니다.

System Error - 컴퓨터 환경에 따른 에러

컴퓨터 환경에 따라 생겨나는 에러를 말합니다.

PHP는 리눅스계열의 서버에 맞게 개발이 되어왔기 때문에 윈도우용 PHP 에서는 지원되지 않는 함수들이 있습니다.

만약 리눅스에서만 작동하는 함수를 윈도우에서 사용한다면 에러가 생기겠죠?

정리

프로그램을 만들고 사용하다보면 의도한 대로 작동하지 않을 때가 있습니다.

이럴 때 프로그램에 에러가 생겼다라고 하지요.

에러가 생긴 원인중에는 사용자의 실수도 있을 것이고 프로그램 자체의 오류도 있을 것입니다.

이때 프로그램 자체의 오류를 버그라고 합니다.

버그가 있으면 수정을 해야겠죠.

버그를 찾아서 수정하는 것을 디버그라고 합니다.


PHP 디버깅 :: 에러의 예

강좌 34. PHP 디버깅 :: 에러의 예

Syntex Error

문법 에러를 일으키는 주범 세녀석을 공개 수배합니다.

문법 에러는 문법을 잘못 이해하고 있거나 잘못 사용함으로해서 생기는 에러입니다.

주로 위 세녀석을 통해서 생기는데..

1. 세미콜론을 잊은 경우

<?
    echo "이 에러가 문법에러의 주범" // <-- 여기 세미콜론이 빠졌어요.
    echo "세미콜론을 잊지말아요~~";
?>

Parse error 라네요. 문법 에러를 말합니다.

해당 파일의 세 번째 줄에서 콤마(,)나 세미콜론(;)을 요구한다는군요. (참 똑똑합니다.^^)

PHP는 세미콜론을 통해 한문장이 끝났음을 나타냅니다.

그런데 세미콜론이 없어서 두 문장이 한문장으로 되어 버렸기 때문에

echo "이 에러가 문법에러의 주범" echo "세미콜론을 잊지 말아요~~";

가 한줄이라고 생각한 것이죠.

위 문법이 왜 틀린줄은 아시겠죠?? ^^

2. 중괄호를 안 닫은 경우

<?
    echo "이 에러가 문법에러의 또 다른 주범";
    if ($name=="조명진") {
        echo "내 이름은 " . $name;
        // <-- 여기에 } 요놈이 있어야 되는데 없군요.
?>

또 문법에러가 뜨네요.

중괄호를 안닫았기 때문에 생긴 에러입니다.

PHP에서 중괄호는 중요한 의미를 가집니다.

함수를 구분짓기도 하고 위처럼 논리적인 제어구조에도 사용이 됩니다.

{ 로 시작을 하게되면 PHP는 계속해서 다음에 } 나올 때까지 한 묶음으로 생각합니다.

그런데 아무리 기다려도 } 나타나지 않으니 마지막 줄에 에러를 나타낸 것입니다.

3. 따옴표를 안 닫은 경우

<?
    echo "이 에러가 문법에러의 또 다른 주범;
    $sum = $a + $b;
?>

echo 제일뒤에 따옴표가 빠졌네요.

잘못된 코드

올바른 코드

<?
    echo "이 에러가 문법에러의 또 다른 주범;
    $sum = $a + $b;
?>
<?
    echo "이 에러가 문법에러의 또 다른 주범";
    $sum = $a + $b;
?>

자 왼쪽 코드와 오른쪽 코드를 비교해 보세요.

뭔가 다르죠? 아 코드가 틀리고 맞다는거 말구요.

색깔을 한번 보세요.

왼쪽은 아랫부분이 전부 빨간색인데 비해 오른쪽은 파란색으로 되어 있네요.

이렇게 코드를 구분하기 쉽게 색깔 변화를 주는 것을 Syntex Highlight(문법강조) 라고 하는데

왼쪽부분은 따옴표가 안닫혀지면서 문법강조가 되어야할 부분이 강조가 되지 않았습니다.

이걸 통하면 색깔 만으로도 문법 에러 하나는 잡을 수 있겠네요.^^

4. 기타

<?
    /* 주석처리를 해놓고 닫지 않으면 전부 주석처리 되요!!
    $sum = $a + $b;
?>

<?
    $sum = $a + $b;
<? // 닫지않고 PHP 시작 태그를 사용했을때.

?>

Run-Time Error

<?
    $a = 5;
    $b = $a - 5;
    $c = $a / $b; //0으로 나누어지게 된다.
?>

문법적으로 에러는 없지만 실행하면서 $b값에 0이 들어가기 때문에 결과적으로 0으로 나누는 상태가 되어 버립니다.

$a 라는 값이 이전 페이지에서 넘어온 변수라면 변수값에 따라서 에러가 생길 수도 안생길 수도 있게 되는거죠

Logic Error

위 두 에러는 그래도 비교적 쉽게 고칠 수 있습니다.

그러나 Logic Error 는 어느부분이 틀렸는지 잘 찾을 수가 없어 며칠동안 디버깅을 하는 경우가 많습니다.

그 이유는 문법에러나 실행시간 에러처럼 에러 메세지가 나타나는 것이 아니기 때문입니다.

논리적으로 잘못된 것이기 때문에 컴퓨터는 이것을 찾아낼 수가 없습니다.

더해야할 부분에서 빼기를 해 버렸다면..

컴퓨터는 문법상 에러가 없으니까 맞다고 생각하고 넘어갑니다.

왜냐하면 더해야할지 빼야할지는 프로그래머 자신만 알고 있기 때문이지요.

논리 에러는 주로 프로그래머의 부주의나 프로그램에 대한 잘못된 이해가 불러 일으킵니다.

1. 대입연산자와 비교연산자의 혼동

<?
    $name = "조맹진";
    if ($name = "조명진") echo $name;
    else echo "내 이름은 조맹진이 아니라 조명진이야!!! 버럭!";
?>

분명히 $name 값에 조맹진(고향에선 저를 이렇게 부릅니다-_-;; "명" 발음이 안되나 봅니다-_-)이라고

넣었는데 조명진 이라는 결과가 나와 버렸습니다.

분명히 내 이름은 조맹진이 아니라 조명진이야!!! 버럭! 이렇게 출력되어야 하는데 말이죠.

이는 대입 연산자(=)와 비교 연산자(==)를 혼동해서 나타난 에러입니다.

$name=="조명진" 이어야 하는데 $name="조명진" 이 되면서 $name 값에 조명진이란 값이 저장이 되어 버렸습니다.

$name 변수에는 값이 있으므로 True 가 되어 조명진이 출력되게 된것이지요.

2. 부주의로인한 에러

<?
    for ($i=1;$i<10;$i++) $sum = $sum + $i; //9까지만 더한다.
    echo "1부터 10까지의 합은 " . $sum;
?>

1부터 10까지 더해야 하는데 부주의로 인해 1부터 9까지밖에 더하지 않아서 생긴 논리적 에러입니다.


Form을 사용해 보자 :: Form에는 어떤 것이 있나?

방명록이나 게시판등을 만들면서 우리는 HTML 페이지를 통해 PHP로 데이터를 전달하였습니다.

여기서는 PHP로 데이터를 전달하는 방법중에 Form을 이용한 방법을 정리하여 보았습니다.

Ext.1 폼에는 어떤 것이 있나?

1) <FORM>...</FORM>

폼의 시작과 끝을 나타냅니다. Form 태그의 사용은 다음과 같은 방법으로 가능합니다.
<FORM NAME="폼이름" ACTION="데이터를 보낼 주소" METHOD="전송방식">
여기에 HTML 및 기타 폼 요소들...
</FORM>

HTML은 아시다시피 대문자와 소문자를 구분하지 않습니다. ( PHP는 구분하지만 )
따라서 소문자로 쓰거나 혼용해서 사용하여도 무방합니다.

그러면 본격적으로 Form 태그의 속성을 들여다 볼까요?

NAME 이라함은 요즘은 초등학생 아니 유치원생도 아는 단어입니다.
네~ 그렇습니다. 폼의 이름을 나타내는 것이죠.
사람을 부르거나 구분할 때 이름을 사용하듯이 여러 폼이 있을 때 폼을 구분짓기위해 사용합니다.

ACTION 은 데이터를 보낼 주소를 가르쳐주는 부분입니다.
HTML에서 PHP로 데이터를 전송하려면 전송받을 페이지를 알려주어야겠지요?
짜장면 배달할 때 주소 안가르쳐주면 배달 안합니다. ^^;;;

METHOD 는 데이터를 전달하는 방식을 정의하는 부분입니다.
그렇다면? 전달하는 방식이 여러 가지가 있다는 말을 의미하네요. (똑똑하십니다.^^;;)
전송방식에는 POST와 GET 방식이 있습니다. (둘밖에 안되니 외우기 쉽네~)

POST vs GET
둘은 모두 정보를 다른 페이지로 전달하는 방식입니다.

GET 방식은 URL을 통해서 전달하는 방식으로 /index.php?name=brown 과 같이
파일이름 다음에 "?"를 통해서 ?변수명=전달될값 과 같은 식으로 전달하는 방식입니다.
두 개 이상의 값을 전달하고자 할 때는 &를 통해서 ?name=brown&homepage= http://ezphp.net 과 같이 전달합니다.

POST 방식은 HTTP 헤더라는 것을 통해서 전달하는 방식으로 GET 방식보다 안전한 방식입니다.

이외에 ENTYPE 이라는 것이 있습니다.
ENTYPE="MULTIPART/FORM-DATA"을 위의 폼에 덧붙여서 폼과 함께 파일을 업로드 하거나 할 때 사용합니다.

2) <INPUT>

모 양 | TYPE | 설 명
 | TEXT | 일반 텍스트 입력 상자
 | PASSWORD | 패스워드 입력 상자
 | FILE | 파일 입력 상자
 | CHECKBOX | 체크 박스
 | RADIO | 라디오 상자
 | BUTTON | 일반 버튼
 | SUBMIT | 보내기(Submit) 버튼
 | RESET | 리셋 버튼
 | IMAGE | 이미지 버튼
 | HIDDEN | 숨겨진 필드

(1) 일반 텍스트 입력 상자

일반적인 텍스트를 입력할 수 있는 상자입니다. 게시판 등에서 이름이나 제목등을 넣을 때 쓰는 상자입니다.

<input type="text" name="variable" size="10" maxlength="10" value="일반 텍스트 입력 상자">

Property :
type : INPUT 의 스타일을 정하는 속성 (일반 텍스트 입력 상자는 text)
name : 이 이름을 통해 데이터가 전송됩니다. (데이터를 받는 페이지에서 변수명)
size : 입력상자의 크기를 정하는 속성
maxlength : 입력 상자에 입력가능한 최대 글자수를 정하는 속성
value : 전송될 데이터 값 (초기값을 넣을 때 사용한다.)

이외에 readonly 라고 추가하게되면 글을 입력할 수 없게된다.
( , )

(2) 패스워드 상자

일반 텍스트 상자와 거의 같으나 입력한 글자가 모두 *로 보이게 됩니다. 이름그대로 패스워드를 입력할 때 사용하는 상자입니다.

<input type="password" name="variable" size="10" maxlength="10">

단, 한글을 입력하여도 영문으로 입력이 됩니다. 따라서 한글 전송이 불가능합니다.

(3) 파일 입력 상자

파일 입력 상자는 폼 데이터와 함께 파일을 업로드 하고자 할 때 사용하는 폼입니다.

<input type="file" name="variable" size="20" >

단, 파일 전송을 하려면 METHOD가 반드시 POST 이어야 합니다.

(4) 체크 박스

항목에 대해 선택 여부를 묻기 위한 상자입니다. email 수신을 하겠습니까? 에 대한 대답으로 체크(수신을 원합니다)를 하거나 체크하지 않을(수신을 원하지 않습니다) 수 있습니다.

<input type="checkbox" name="variable" value="Yes" checked>

체크를 하게되면 value 속성에 입력된 값이 name 값을 통해 전달됩니다.
checked 를 추가하는 경우 기본적으로 체크가 됩니다.

(5) 라디오 상자

라디오 버튼은 체크 박스와 비슷하나 여러개 중에 하나를 선택할 때 쓰는 상자입니다.

<input type="radio" name="variable" value="1" checked>

3개의 항목 중에 하나를 선택하게 만들기 위해서는 3개의 라디오 버튼 모두 name 이 같아야 합니다. 그래야만 어떤 것이 같은 그룹인지 알 수 있겠죠?

(6) 일반 버튼

일반적인 버튼 모양을 만들어 주는 폼입니다.

<input type="button" name="ButtonName" value="버튼">

일반 버튼은 클릭이 가능한 버튼 모양을 만들어주며 value 값이 버튼위에 글자로 나타나게 됩니다. 또한 자바스크립트의 onclick 이벤트 등을 통하여 여러 가지 작업이 가능합니다.

(7) 보내기 버튼 (Submit Button)

보내기 버튼은 폼에 입력된 데이터를 Action 페이지로 전송할 때 사용하는 버튼입니다.

<input type="submit" name="SubmitButton" value="보내기">

게시판등에서 글을 다 입력한후 글을 저장하기 위해 누르는 확인 버튼과 같은 버튼입니다.
버튼과 같이 value 값이 버튼 위에 글자로 나타나게 됩니다.

(8) 리셋 버튼

폼에 입력된 값을 처음 상태로 되돌리는 버튼입니다.

<input type="reset" name="ResetButton" value="취소">

게시판에서 글을 입력하다가 지우고 다시 글을 입력하려고 할 때 사용하는 버튼입니다.
리셋버튼이 포함된 폼 전체 항목이 전부 초기화 되어집니다.

(9) 이미지 버튼

그림 파일을 통해서 버튼을 생성할 때 사용합니다.

<input type="image" name="ImageButton" src="이미지의 주소">
<IMG> 태그와 비슷하게 src 속성을 이용하여 이미지를 가져올 수 있습니다.

(10) 숨겨진 필드

숨겨진 필드는 사용자로 하여금 값을 입력 받게하는 것이 아니라 비밀쪽지를 건네듯이 보이지 않게 전달하는 폼입니다.

<input type="hidden" name="variable" value="비밀스레 전달되는 값">

텍스트 입력 상자와 속성이 동일하나 브라우저 상에 보이지 않고 HTML 코드 상으로 값이 전달되는 폼입니다.
주로 자동으로 생성되는 값이나 꼭 필요한 값이지만 사용자에게 보여줄 필요가 없는 값들을 전달할 때 사용합니다.

3) <SELECT> ... </SELECT>

리스트에 등록된 값중에서 하나 또는 여러개의 값을 선택할 때 사용하는 폼으로 두가지 형태가 있습니다.

(1) 콤보 박스

모양의 형태가 콤보 박스입니다.

드롭다운 리스트라고도 불리는 이 폼은 등록된 리스트 중에서 하나의 값을 선택할 때 사용됩니다.

<select name=SelectBox size=1>

위와 같은 방식으로 사용하며 size 값이 1인 경우 콤보 박스가 됩니다.
여기서 size는 다른 폼과 달리 가로 크기가 아니라 한번에 보여질 리스트의 수입니다.

(2) 리스트 박스

이런 모양의 형태가 리스트 박스라고 불리는 폼입니다.

<select name=SelectBox size=4 multiple>

콤보박스와 달리 하나가 아닌 여러개의 리스트가 보여지며 리스트가 많은 경우 스크롤을 통해 나머지 리스트를 볼 수 있습니다.
size 가 1보다 큰 값인 경우 리스트 박스 형태로 출력되며 multiple 을 추가하게되면 하나이상의 값을 선택할 수 있습니다.

(3) <OPTION> ... </OPTION>

<OPTION>은 콤보 박스나 리스트 박스를 구성하고 있는 각 리스트를 만드는 태그입니다.

<select name=SelectBox size=1 >
<option value="내가 일등!">첫번째 리스트</option>
</select>

위와 같은 방식으로 하나의 리스트를 구성 할 수 있으며 하나 이상을 원할 경우 위 <OPTION> 태그를 여러줄 사용하면 됩니다.

<select name=SelectBox size=1>
<option value="내가 1등!">첫번째 리스트</option>
<option value="난 2등!" selected>두번째 리스트</option>
<option value="아쉽게 3등!">첫번째 리스트</option>
</select>

또한 selected를 이용해서 특정 리스트가 초기값으로 설정되게 만들 수 있습니다.

4) <TEXTAREA>... </TEXTAREA>

TEXTAREA 태그는 게시판 등에서 본문을 입력하는 데 사용하는 폼입니다.

<textarea name="context" rows="5" cols="40">아뵤~~~</textarea>

rows 는 세로 크기(줄단위 - 5면 5줄)이고 cols 는 가로 크기(글자단위 - 40이면 40자)입니다.

위 처럼 <textarea></textarea> 태그 사이에 글자가 들어가면 초기값으로 작용합니다.^^


계층형 게시판 만들기 - 계층형 게시판이 뭘까?

계층형 게시판이란?

이미 우리는 앞선 강좌에서 가장 기초가 되는 게시판을 만드는 법을 배웠습니다.
게시판을 처음 만들어보는 사람에게는 더할나위없이 공부가 되는 게시판이지만
실상 실제로 적용하기에는 너무 부족함이 많은 게시판이었습니다.
그래서 "아~ 기다리고 기다리던" (아기 다리 고기 다리 가 아닌-_-;;)
계층형 게시판 강좌를 준비했습니다.
실은 제가 게을러서 좀 늦었습니다. 네? 많이 늦었다구요? 죄송합니다. ㅜ_ㅜ

그런데 계층형 게시판은 뭔가 대단한거냐구요?
이해하느라 머리 뽀개지는게 아니냐구요?

미리부터 겁먹으실 필요없습니다.
우리는 이미 충분한 실력이 있습니다.
그리고 하나 더!
앞선 게시판 강좌에서 사용한 소스를 몇부분 수정하는 것으로 계층형 게시판을 만들것입니다.

오옷!! 이말과 함께 눈에서 빛이 나시는군욧!!!
자~ 그럼 이 기세를 몰아 한번 도전해 볼까요?

1. 계층형 게시판의 형태

계층형 게시판이란 말 그대로 글이 계층을 이룬다는 말입니다.
뭔가 말이 어렵죠? -_-;;;
근데 사실 별루 어려울거 없습니다.
그냥 답변 기능이 있는 게시판입니다-_- 유식한척 해서 죄송~ ^^*
(그래서 응답형 게시판,답변형 게시판 등으로 불립니다. 영어로는 쑤뤠드(Thread) 보드 ^^)

그럼 고놈이 오또코롬 생겨부렀는지 한번 보십시다!

두둥~
그놈한번 실하구랴~ ^^

이제 이해가 팍!팍! 되시죠?
위처럼 답변이 달리면서 글이 계층을 이루게 된다하여 계층형 게시판입니다.
(어랏~ 디자인이 마니 보던거구만? -_-;;;)

2. 계층형 게시판의 종류

종류라고 하기엔 뭣하지만 계층형 게시판도 세대가 있습니다.
(제가 임의로 정의한 세대이며 세대별로 예를 든것은 유일한 방법이 아니라 여러방법중 한가지입니다.)

a) 할아버지세대 (0세대) : 답변도 그냥 새글 처럼 (계층형이 아님)

번호 | 제목 | 종류
4 | RE : 두 번째 글 | 답변글
3 | 세 번째 글 | 새글
2 | 두 번째 글 | 새글
1 | 첫 번째 글 | 새글

이 게시판은 계층형 게시판은 아니고 응답형 게시판의 시작입니다.
답변의 필요성으로 생기긴 하였지만 새글처럼 등록이 되었다는 문제가 있습니다.

b) 아버지세대 (1세대) : 답변글이 어찌 새글이여~ 답변은 답변답게!! (업데이트형)

번호 | 제목 | 종류
4 | 세 번째 글 | 새글
3 | 두 번째 글 | 새글
2 | RE : 두 번째 글 | 답변글
1 | 첫 번째 글 | 새글

초기의 계층형 게시판입니다. 현재랑 모습은 같지만 구현방법이 다른데요.
업데이트형이라고 불리는 이 게시판의 원리는 다음과 같습니다.
글이 1,2,3 이렇게 세 개의 글이 있고 2번글에 답변이 달리게 되면
2번글 이상(2,3번글)은 +1 씩 해서 2,3 -> 3,4 번 글이 되게 하고
답변글을 2번글로 저장하는 방법입니다.
글번호를 기준으로 정렬을 하면 위와 같은 모양이 되겠죠?

대충 이해가 되시나요? 왜 업데이트형이라고 불리는지?
어떤글에 답변이 달리게 되면 답변달리는 글부터 그 이후 글들 모두를
글 번호에 1씩 증가(업데이트)를 시켜줘야 합니다.
그래서 업데이트형이라고 불립니다.

그렇지만 글이 10000개가 있는데 10번째 글에 답변을 달게되면 9990개를 업데이트해야 하니
성능에 문제가 있습니다.
물론 대부분의 경우 답변이 최근글에 달리기 때문에 이런일은 드물지만
그렇다고 무시할수만은 없지요.

c) 우리세대 (2세대) : 답변도 답변이지만 성능도 고려해야지~ (반업데이트형)

번호 | 깊이 | 제목 | 종류
300 | 0 | 세 번째 글 | 새글
200 | 0 | 두 번째 글 | 새글
199 | 1 | RE : 두 번째 글 | 답변글
100 | 0 | 첫 번째 글 | 새글

1세대의 업데이트로 인해 부하가 많이 걸리는 단점을 보완하고자 만든 게시판입니다.
반업데이트형이라는 말에서부터 업데이트를 하고 있음을 알 수 있는데요.
1세대와 다른점은 부분적으로만 업데이트를 한다는 것입니다.
예를 들면 위처럼 글 번호를 100의 간격으로 등록을 하고 200번의 글에 답변이 달리게 되면
그 답변글을 199번으로 만드는 것입니다.

번호 | 깊이 | 제목 | 종류
300 | 0 | 세 번째 글 | 새글
200 | 0 | 두 번째 글 | 새글
199 | 1 | RE : 두 번째 글의 두 번째 답변 | 답변글
198 | 1 | RE : 두 번째 글 | 답변글
100 | 0 | 첫 번째 글 | 새글

200번 글에 다시 답변이 달린다고 하면 199번글을 198번글로 바꾼다음에 199번글로 등록을 합니다.

번호 | 깊이 | 제목 | 종류
300 | 0 | 세 번째 글 | 새글
200 | 0 | 두 번째 글 | 새글
199 | 1 | RE : 두 번째 글의 두 번째 답변 | 답변글
198 | 2 | RE : 두 번째 글의 두 번째 답변의 답변 | 답변글
197 | 1 | RE : 두 번째 글 | 답변글
100 | 0 | 첫 번째 글 | 새글

199번 글에 답변이 달리면 100번과 199번 사이에 있는 글들을 모두 -1씩 업데이트 해줍니다.
만약 198번 글이 있었다면 197번 글이 되었을테니 198번 자리가 비게 되지요?
그 자리에 답변글을 추가해서 넣습니다.
이렇게 되면 이전 방식과 달리 전체를 업데이트 하는게 아니라 이 경우에선 최대 99개만 업데이트가 됩니다.
새글과 새글 사이만 업데이트가 되기 때문이죠.(답변글들만 업데이트가 됨)

이러한 방법으로 성능을 좀 더 향상시키면서 계층형 게시판을 구현할 수 있습니다.
그러나 눈치채신 분들도 계시겠지만 여기는 제약이 존재합니다.
어떤 새글에 대한 답변의 수가 한정되어 있다는 것이지요.
번호의 차이를 100이 아닌 1000으로 바꾼다면 답변의 수가 늘어나겠지만요.
하지만 한 글에 대한 답변이 100개가 달리기란 정말 어려운 일입니다.
그러나 불가능한 일은 아니지요.
그래서 적당한 수를 생각해서 그것을 기준으로 프로그래밍을 하면 됩니다.

깊이는 단지 제목에서 들여쓰기를 하기 위해 만든 것입니다.
답변글이 새글과 구분되기 위해 새글에 대한 답변인지 답변에 대한 답변인지를 깊이로 나타냅니다.
이를 통해 1칸의 여백을 둘지 2칸의 여백을 둘지가 결정이 됩니다.

우리는 이 방식을 사용하여 계층형 게시판을 구현할 것입니다.
다음 세대 게시판이 있는데 이 게시판을 구현하는 것은
첫째, 알고리즘이 간단하고
둘째, 구현이 간단하고
셋째, 비교적 훌륭한 성능이기 때문입니다.

d) 아들,딸 세대(3세대) : 부분 업데이트도 부담된다~ 업데이트 반대!! (비업데이트형)

이 방법은 여러 가지 형태로 구현이 가능합니다.
문자열을 사용하여 구현하거나 소숫점을 이용하는 등의 방법이 있습니다.
그러나 이 방법은 비교적 간단하지 않고 복잡한 알고리즘을 요구합니다.
많은 알고리즘이 연구되고 있으나 그중에는 반업데이트형보다 성능이 안나는 경우도 많습니다.
하지만 좋은 알고리즘과 개발 환경에서의 좋은 뒷받침이 있다면 충분히 기대해볼 만합니다.

이외에도 재귀적용법을 이용한 계층형 게시판 같은게 있으며 여기에 정의된 세대는 제가 임의로 정의한 것입니다.

참고. 게시판계(?)의 흐름을 보면 점차적으로 답변달기가 없어지고 코멘트로 대체될거 같네요.
코멘트로 충분히 답변기능을 대체할 수 있기때문에 그런듯 합니다.
그렇다면 다음세대는 코멘트형 게시판인가? ^^;;

예제소스 : 준비중
예제보기 : http://ezphp.net/lect/101/list.php


계층형 게시판 만들기 - 테이블 설계

계층형 게시판 만들기 - 테이블 설계

1) 테이블 설계

a) 이전 게시판의 스키마

항 목 | 영어 항목 | 변수형 | 크기 | 비 고
글의 번호 | id | int | 11 | 글의 번호는 숫자
글쓴이 | name | varchar | 20 | varchar는 많이 길지 않는 문자열
이메일 주소 | email | varchar | 30 |
글의 비밀번호 | pass | varchar | 10 |
글의 제목 | title | varchar | 70 |
글의 내용 | comment | text |  | 충분히 긴 문자열
글쓴 날짜 | wdate | datetime |  | 날짜 및 시간
IP 주소 | ip | varchar | 16 |
조회수 | see | int | 11 |

자 여기다가 몇가지를 덭붙여 계층형 게시판으로 만들어 보겠습니다.
첫 번째 강좌에서 우리는 반업데이트형 게시판을 만들거라고 했습니다.
반업데이트형 게시판 설명하면서 이야기 한 것이 두가지가 있습니다.
일정 간격(100 또는 1000 등등)으로 증가되는 글 번호와 답변의 경우 들여쓰기를 위한 깊이입니다.
그렇기 때문에 이부분을 추가 해줘야겠죠?

b) 수정된 계층형 게시판의 스키마

항 목 | 영어 항목 | 변수형 | 크기 | 비 고
글의 번호 | id | int | 11 | 글의 번호는 숫자
내부 번호 | thread | int | 11 | 일정값으로 증가하는 값
글의 깊이 | depth | int | 11 | 들여쓰기를 위한 값
글쓴이 | name | varchar | 20 | varchar는 많이 길지 않는 문자열
이메일 주소 | email | varchar | 30 |
글의 비밀번호 | pass | varchar | 10 |
글의 제목 | title | varchar | 70 |
글의 내용 | comment | text |  | 충분히 긴 문자열
글쓴 날짜 | wdate | int |  | 시간을 UnixTime으로 저장
IP 주소 | ip | varchar | 16 |
조회수 | see | int | 11 |

색깔로 된 부분이 추가되거나 수정된 부분입니다.
일단 추가된 부분은 두 개로 thread 라는 내부적인 글 번호로 앞서 말한 1000씩 증가되는
값이고 depth는 들여쓰기를 위한 값입니다.
수정된 부분은 날짜부분인데 반드시 수정해야 하는건 아니고 날짜를 다루는 다른 방식을 배우기 위해
일부러 수정하였습니다.
datetime 형이 아니라 int 형으로 변환시킨후 유닉스타임이라 불리는 값을 입력할 것입니다.
유닉스타임이란 1970년 1월 1일부터 현재 시간까지를 초단위로 계산한 값입니다.
즉, 1970년 1월 1일부터 몇초가 흘렀느냐 하는 값입니다.
이 값을 쓰는 것은 날짜를 다루거나 할 때 여러 가지로 쉽게 변환이 가능하기때문입니다.

2) 테이블 생성문 만들기

테이블 스키마를 만들었으니 테이블 생성문을 만들 수 있을 것입니다.

CREATE TABLE threadboard (
id int(11) unsigned NOT NULL auto_increment,
thread int(11) unsigned NOT NULL,
depth int(11) unsigned NOT NULL default '0',
name varchar(20) NULL,
email varchar(30) NULL,
pass varchar(10) NULL,
title varchar(70) NULL,
comment text,
wdate int(11) NULL,
ip varchar(16) NULL,
see int(11) NULL,
PRIMARY KEY (id)
);

default '0' 값이 입력되지 않은 경우 기본적으로 0을 입력하겠다는 말입니다.
지난 강좌에서 만드는 방법을 배웠으니 문제없으리라 봅니다.

테이블을 데이터베이스에 생성하고 확인해 보면..

mysql> desc threadboard;
+---------+-------------+------+-----+----------+----------------+
| Field   | Type        | Null | Key | Default  | Extra          |
+---------+-------------+------+-----+----------+----------------+
| id      | int(11)     |      | PRI |  NULL    | auto_increment |
| thread  | int(11)     |      |     |  NULL    |                |
| depth   | int(11)     |      |     |  0       |                |
| name    | varchar(20) | YES  |     |          |                |
| email   | varchar(30) | YES  |     |          |                |
| pass    | varchar(10) | YES  |     |          |                |
| title   | varchar(70) | YES  |     |          |                |
| comment | text        | YES  |     |          |                |
| wdate   | int(11)     | YES  |     |          |                |
| ip      | varchar(16) | YES  |     |          |                |
| see     | int(11)     | YES  |     |          |                |
+---------+-------------+------+-----+---------------------------+
11 rows in set (0.00 sec)

축하합니다. 테이블이 만들어 졌습니다. ^^


계층형 게시판 만들기 - 데이터베이스 정보

계층형 게시판 만들기 - 데이터베이스 정보

이미 지난 강좌를 통해 db_info.php 가 어떠한 역할을 하고 왜 만들어졌는지를 배웠습니다.
여기에 코드 하나를 더 추가하도록 하겠습니다.

<?
$board="threadboard";
$conn=mysql_connect("localhost","아이디","패스워드");
mysql_select_db("데이터베이스이름", $conn);
?>

추가된 코드만 설명하겠습니다.
$board 라는 변수가 하나 늘었네요.
이제 부터는 이 변수를 통해 게시판 테이블 이름을 대신해서 사용하겠습니다.
즉, select * from threadboard 라고 하지 않고 select * from $board 라고 할 것이라는 말입니다. ^^

벌써 끝났나요? ^^;;;


계층형 게시판 만들기 - 글 쓰기

계층형 게시판 만들기 - 글 쓰기

1) 글을 입력해보자 - write.php

write.php 소스코드
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
    td  { font-size : 9pt;   }
    A:link  { font : 9pt;  	color : black; 	text-decoration : none;	font-family : 굴림;	font-size : 9pt;  }
    A:visited  {   text-decoration : none; color : black;	font-size : 9pt;  }
    A:hover  { 	text-decoration : underline; color : black; font-size : 9pt;  }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=insert.php method=post>

<table width=580 border=0  cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
    <td height=20 align=center bgcolor=#999999>
        <font color=white><B>글 쓰 기</B></font>
    </td>
</tr>

<!-- 입력 부분 -->
<tr>
    <td  bgcolor=white>&nbsp;
        <table>
            <tr>
                <td width=60 align=left >이름</td>
                <td align=left >
                    <INPUT type=text name=name size=20 maxlength=10>
                </td>
            </tr>
            <tr>
                <td width=60 align=left >이메일</td>
                <td align=left >
                    <INPUT type=text name=email size=20 maxlength=25>
                </td>
            </tr>
            <tr>
                <td width=60 align=left >비밀번호</td>
                <td align=left >
                    <INPUT type=password name=pass size=8 maxlength=8> (수정,삭제시 반드시 필요)
                </td>
            </tr>
            <tr>
                <td width=60 align=left >제 목</td>
                <td align=left >
                    <INPUT type=text name=title size=60 maxlength=35>
                </td>
            </tr>
            <tr>
                <td width=60 align=left >내용</td>
                <td align=left >
                    <TEXTAREA name=comment cols=65 rows=15></TEXTAREA>
                </td>
            </tr>
            <tr>
                <td colspan=10 align=center>
                    <INPUT type=submit value="글 저장하기">
                    &nbsp;&nbsp;
                    <INPUT type=reset value="다시 쓰기">
                    &nbsp;&nbsp;
                    <INPUT type=button value="되돌아가기" onclick="history.back(-1)">
                </td>
            </tr>
        </TABLE>
    </td>
</tr>
<!-- 입력 부분 끝 -->
</table>

</center>
</body>
</html>

뭔가 기대하셨나요? 그러셨다구요? 뭔가 허전하시다구요? 왜요? ^^
기존의 파일과 동일합니다.

끝~!!!


계층형 게시판 만들기 - 글 저장

계층형 게시판 만들기 - 글 저장

1) 글을 데이터베이스에 저장해보자! - insert.php

글을 입력받았으니 입력된 정보를 데이터베이스에 저장해 보도록합시다.

소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

//현재 글중에서 가장 큰 값을 가져온다.
$max_thread_result = mysql_query("select max(thread) from $board",$conn);
$max_thread_fetch = mysql_fetch_row($max_thread_result);

//가져온 값을 올림한뒤에 1000을 더한다.
//올림(ceil)하는 이유는 원래 글이 삭제된 경우 1999 와 같은 값이 최대값이 된다.
//그냥 1000만 더하게 되면 2999 라는 번호로 새글이 저장되게 된다.
//1000 은 변경가능하며 999개의 답글이 가능함
$max_thread = ceil($max_thread_fetch[0]/1000)*1000+1000;

//depth는 새글이므로 0이다.
//시간에는 time 함수를 이용하여 Unix Timestamp를 입력한다.
$query = "insert into $board (id,thread,depth,name,pass,email,title,see,wdate,ip,comment) ";
$query .= "values ('',$max_thread,0,'$name','$pass','$email','$title',0," . time() . ",'$REMOTE_ADDR','$comment')";
$result=mysql_query($query, $conn);

//데이터베이스와의 연결 종료
mysql_close($conn);

// 새 글 쓰기인 경우 리스트로..
echo ("<meta http-equiv='Refresh' content='1; URL=list.php'>");

?>
<center>
<font size=2>정상적으로 저장되었습니다.</font>

기존의 write.php 와는 몇가지 다른점이 있습니다.
당연한 결과죠?
thread 값과 depth 값이 있으므로 당연히 소스가 변경되었을 것입니다.

a) thread 값 구하기

//현재 글중에서 가장 큰 값을 가져온다.
$max_thread_result = mysql_query("select max(thread) from $board",$conn);
$max_thread_fetch = mysql_fetch_row($max_thread_result);

//가져온 값을 올림한뒤에 1000을 더한다.
//올림(ceil)하는 이유는 원래 글이 삭제된 경우 1999 와 같은 값이 최대값이 된다.
//그냥 1000만 더하게 되면 2999 라는 번호로 새글이 저장되게 된다.
//1000 은 변경가능하며 999개의 답글이 가능함
$max_thread = ceil($max_thread_fetch[0]/1000)*1000+1000;

새로이 thread 라는 값이 생겼습니다.
이 값은 1000씩 증가하는 값입니다.
1000,2000,3000 과 같이 말이죠.
따라서 새글을 쓸 때 기존에 등록된 글 중에서 가장 큰 thread 값을 가진걸 가져와 4000으로 등록해야 하는지
5000으로 등록해야 하는지를 구해야 합니다.

가져온 값은 반드시 1000의 배수인 값일거라는 편견을 버려~ ^^;;
3000번의 글에 2999번인 답변 글이 있는데 3000번이 지워지면 최대값은 2999가 됩니다.
2999+1000 =??? 이해 되시죠? 새글은 반드시 1000의 배수로만 등록되어야 합니다.
그렇기 때문에 올림을 해준 것이죠.

b) depth
새글이니 depth 는 0이겠죠? ^^;;;

나머지는 모두 동일합니다. ^^;; 끝~


계층형 게시판 만들기 - 답변 달기

계층형 게시판 만들기 - 답변 달기

1) 답변을 달아보자 - reply.php

reply.php 소스코드
<?
include "db_info.php";

//답변글이므로 원본의 제목과 내용을 보여주어야 한다.
//thread,depth 값은 저장시에 이용되므로 미리 가져와서 넘겨준다.
$select_parent = mysql_query("select thread,depth,title,comment from $board where id=$id",$conn);
$parent_fetch = mysql_fetch_row($select_parent);
$parent_thread = $parent_fetch[0];
$parent_depth = $parent_fetch[1];
$parent_title = $parent_fetch[2];

//아래 부분은 원본 내용에 > 표시를 붙이는 부분이다.
$parent_comment = "\n" . $parent_fetch[3];
$parent_comment = "\n" . str_replace("\n","\n>",$parent_comment);
?>
<html>
<head>
<title>ThreadBoard</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=insert_reply.php method=post>
<input type=hidden name=parent value=<?=$id?>>
<input type=hidden name=parent_depth value=<?=$parent_depth?>>
<input type=hidden name=parent_thread value=<?=$parent_thread?>>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 align=center bgcolor=#999999>
<font color=white><B>글 쓰 기</B></font>
</td>
</tr>

<!-- 입력 부분 -->
<tr>
<td bgcolor=white>&nbsp;
<table>
<tr>
<td width=60 align=left >이름</td>
<td align=left >
<INPUT type=text name=name size=20 maxlength=10>
</td>
</tr>
<tr>
<td width=60 align=left >이메일</td>
<td align=left >
<INPUT type=text name=email size=20 maxlength=25>
</td>
</tr>
<tr>
<td width=60 align=left >비밀번호</td>
<td align=left >
<INPUT type=password name=pass size=8 maxlength=8> (수정,삭제시 반드시 필요)
</td>
</tr>
<tr>
<td width=60 align=left >제 목</td>
<td align=left >
<INPUT type=text name=title size=60 maxlength=35 value="RE:<?=$parent_title?>">
</td>
</tr>
<tr>
<td width=60 align=left >내용</td>
<td align=left >
<TEXTAREA name=comment cols=65 rows=15><?=$parent_comment?></TEXTAREA>
</td>
</tr>
<tr>
<td colspan=10 align=center>
<INPUT type=submit value="글 저장하기">
&nbsp;&nbsp;
<INPUT type=reset value="다시 쓰기">
&nbsp;&nbsp;
<INPUT type=button value="되돌아가기" onclick="history.back(-1)">
</td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>

</center>
</body>
</html>

이 부분 또한 몇부분을 제외하곤 대부분 write.php 소스와 동일합니다.

<?
include "db_info.php";

//답변글이므로 원본의 제목과 내용을 보여주어야 한다.
//thread,depth 값은 저장시에 이용되므로 미리 가져와서 넘겨준다.
$select_parent = mysql_query("select thread,depth,title,comment from $board where id=$id",$conn);
$parent_fetch = mysql_fetch_row($select_parent);
$parent_thread = $parent_fetch[0];
$parent_depth = $parent_fetch[1];
$parent_title = $parent_fetch[2];

//아래 부분은 원본 내용에 > 표시를 붙이는 부분이다.
$parent_comment = "\n" . $parent_fetch[3];
$parent_comment = "\n" . str_replace("\n","\n>",$parent_comment);
?>

답변 글이기 때문에 원본의 내용을 보여주기 위한 부분입니다.
id 값을 통해서 원본글의 정보를 가져옵니다.
여기서 두가지 값 (thread,depth)을 더 가져오는 이유는 이 다음페이지인 insert_reply.php에서 이 값을
사용하기 때문입니다.
쿼리는 되도록 적게하는게 좋기 때문에 이 페이지에서 내용을 가져오는 김에 이들 정보를 가져와
폼을 통해 넘겨주는 것입니다.

str_replace 함수는
str_replace(A,B,C) C안에 있는 문자중에 A를 B로 바꾸는 역할을 합니다.

<form action=insert_reply.php method=post>
<input type=hidden name=parent value=<?=$id?>>
<input type=hidden name=parent_depth value=<?=$parent_depth?>>
<input type=hidden name=parent_thread value=<?=$parent_thread?>>

action정보가 바뀌고 다음페이지에서 사용될 세가지 값을 hidden 폼을 통해 보내기 위한 부분이 추가되었습니다.

나머지 부분은 원본 정보를 폼에다가 보여주는 부분입니다.
문제 없으시겠죠? ^^


계층형 게시판 만들기 - 답변 저장

계층형 게시판 만들기 - 답변 저장

1) 답변 글을 저장해보자! - insert_reply.php

reply.php를 통해 입력된 값을 저장해 보도록합시다.

insert_reply.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

//1000의 배수의 글들은 모두 새글로 등록된 것이다. 이하 새글
//3000에 답글이 달려지면 2999이 될것이다. 그렇다면 어떤 값이 업데이트(-1) 되어야 할까?
//2000보다는 크고 3000보다는 작은 값이 업데이트 되어야 한다.
//2998번 글에 답글이 달려지면 2000보다 크고 2998번보다 작은 값이 업데이트 되어야 한다.

//(답글이 달려질) 원본글보다 thread 값이 작은것중에서 제일 큰 새글의 thread 값(1000의 배수다)
//원본글의 값이 1999면 1.999를 내림하여 1이 된다. 여기에 1000을 곱하니 1000이다.
//그럼 1000이란 값은 1999번 보다는 작지만 작은 수들중에 가장 큰 1000의 배수가 맞나? 아~ 맞네.
$prev_parent_thread = floor($parent_thread/1000)*1000;
//원본글보다는 작고 위값보다는 큰 글들의 thread 값을 모두 1씩 낮춘다.
$update_thread = mysql_query("update $board set thread=thread-1 where thread > $prev_parent_thread and thread < $parent_thread ",$conn);

//원본글보다는 1작은 값으로 답글을 등록한다.
//원본글의 바로 밑에 등록되게 된다.
//depth는 원본글의 depth + 1 이다. 원본글이 3(이글도 답글이군)이면 답글은 4가된다.
$query = "insert into $board values ('','" . ($parent_thread-1) . "'";
$query .= ",'" . ($parent_depth+1) ."','$name','$pass','$email','$title',0,";
$query .= time() . ",'$REMOTE_ADDR','$comment')";
$result=mysql_query($query, $conn);

//데이터베이스와의 연결 종료
mysql_close($conn);

// 새 글 쓰기인 경우 리스트로..
echo ("<meta http-equiv='Refresh' content='1; URL=list.php'>");

?>
<center>
<font size=2>정상적으로 저장되었습니다.</font>

어쩌면 이번 강좌에서 제일 핵심적인 부분인지도 모르겠습니다. ^^
반업데이트형 알고리즘을 실제로 적용하는 부분입니다.

번호 | 깊이 | 제목 | 종류
3000 | 0 | 세 번째 글 | 새글
2000 | 0 | 두 번째 글 | 새글
1000 | 0 | 첫 번째 글 | 새글

처음엔 새글이 등록되어 있습니다.
여기에 2000번의 글에 답글이 달린다면..

번호 | 깊이 | 제목 | 종류
3000 | 0 | 세 번째 글 | 새글
2000 | 0 | 두 번째 글 | 새글
1999 | 1 | →두 번째 글의 답변 | 답변
1000 | 0 | 첫 번째 글 | 새글

와 같이 될 것입니다.
2000번보다는 작고 1000번 보다는 큰 숫자를 글번호로 하면 글번호로 정렬하면 위처럼 보여질 것입니다.
2000번의 글에 하나더 답변이 달립니다..

번호 | 깊이 | 제목 | 종류
3000 | 0 | 세 번째 글 | 새글
2000 | 0 | 두 번째 글 | 새글
1999 | 1 | →두 번째 글의 두 번째 답변 | 답변
1998 | 1 | →두 번째 글의 답변 | 답변
1000 | 0 | 첫 번째 글 | 새글

두 번째 글이 등록되려면 두가지 방법이 있습니다.
1998번으로 등록되거나 1999번이되고 1999번을 1998번으로 밀어내는 것이죠.
지금은 1998번에 등록하는 것이 편해보이지만 실제로는 정반대입니다.
(왜 그럴지는 한번 생각해 보세요. 힌트는 답글이 여러개가 달릴경우)
그렇기 때문에 제로보드를 비롯한 많은 게시판들이 위와같이 위쪽에 답변을 다는 방법을 선택합니다.
굴러 들어온 돌이 박힌 돌 빼내는 격입니다. ^^

그렇다면 박힌돌들을 전부 빼내서 다른 자리로 옮겨야 한다는건데..
어떤 방법이 있을까요?
1000과 2000 사이에 있는 값인 1999에 1을 빼 버리면 되겠죠.
1999번은 1998번이 되었으니 1999번 자리가 비었습니다.
낼름 저 자리를 낚아챕니다. ^^
위와 같은 모양이 되었네요.

그럼 답글에 답글을 달아봅시다.

번호 | 깊이 | 제목 | 종류
3000 | 0 | 세 번째 글 | 새글
2000 | 0 | 두 번째 글 | 새글
1999 | 1 | →두 번째 글의 두 번째 답변 | 답변
1998 | 2 | →두 번째 글의 두 번째 답변의 답변 | 답변
1997 | 1 | →두 번째 글의 답변 | 답변
1000 | 0 | 첫 번째 글 | 새글

새로운 답변글은 위처럼 1998번이 되어야 합니다.
1998번이 되기 위해선 위처럼 박힌돌 빼내야 겠죠?
이번에도 1000번에서 2000번 사이의 값에 -1을 해볼까요?
어!어!어! -_-;;;;

번호 | 깊이 | 제목 | 종류
3000 | 0 | 세 번째 글 | 새글
2000 | 0 | 두 번째 글 | 새글
1998 | 1 | →두 번째 글의 두 번째 답변 | 답변
1998 | 2 | →두 번째 글의 두 번째 답변의 답변 | 답변
1997 | 1 | →두 번째 글의 답변 | 답변
1000 | 0 | 첫 번째 글 | 새글

1998번이 두 개가 되어 버렸습니다.
왜 이렇게 되었을까요?
원래 1999번이던 글이 1998번이 되었기 때문입니다.
실상 1999번은 바뀔 필요가 없었는데 바뀌었기 때문에 1998이 두 개가 된것입니다.

아하~ 뭔가 감이 잡히네요~.
1000 ~ 2000 사이의 값을 업데이트 할 것이 아니라 1000 ~ 1999 사이 값을 업데이트 해야 하는 군요.
왜 2000번에서 1999번으로 바뀌었을까요?
그 해답은!!! 이미 아신다구요? Greate!!!
1999번이냐 2000번이냐는 1999번에 답변을 다느냐 2000번에 답변을 다느냐에 따라 결정되는 것입니다.

이해 하셨나요? ^^
그렇다면 여러분은 계층형 게시판의 핵심을 파악하신겁니다.

나머지 부분은 위의 소스에대한 주석을 보시면 이해가 가실 겁니다.

참고. 답변글이 999개를 초과하는 경우에 대한 에러핸들링 부분이 없습니다.
999개의 답변이 불가능하다는 전제하에 그런것인데.. 이부분을 생각해서 구현해보세요~


계층형 게시판 만들기 - 글 수정

계층형 게시판 만들기 - 글 수정

1) 글을 수정해보자 - edit.php

edit.php 소스코드
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=update.php?id=<?=$id?> method=post>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 align=center bgcolor=#999999>
<font color=white><B>글 수 정 하 기</B></font>
</td>
</tr>
<?
//데이터 베이스 연결하기
include "db_info.php";

// 먼저 쓴 글의 정보를 가져온다.
$result=mysql_query("select id,name,email,title,comment,ip from $board where id=$id", $conn);
$row=mysql_fetch_array($result);
?>

<!-- 입력 부분 -->
<tr>
<td bgcolor=white>&nbsp;
<table>
<tr>
<td width=60 align=left >이름</td>
<td align=left >
<INPUT type=text name=name size=20 maxlength=10 value="<?=$row[name]?>">
</td>
</tr>
<tr>
<td width=60 align=left >이메일</td>
<td align=left >
<INPUT type=text name=email size=20 maxlength=25 value="<?=$row[email]?>">
</td>
</tr>
<tr>
<td width=60 align=left >비밀번호</td>
<td align=left >
<INPUT type=password name=pass size=8 maxlength=8> (비밀번호가 맞아야 수정가능)
</td>
</tr>
<tr>
<td width=60 align=left >제 목</td>
<td align=left >
<INPUT type=text name=title size=60 maxlength=35 value="<?=$row[title]?>">
</td>
</tr>
<tr>
<td width=60 align=left >내용</td>
<td align=left >
<TEXTAREA name=comment cols=65 rows=15><?=$row[comment]?></TEXTAREA>
</td>
</tr>
<tr>
<td colspan=10 align=center>
<INPUT type=submit value="글 저장하기">
&nbsp;&nbsp;
<INPUT type=reset value="다시 쓰기">
&nbsp;&nbsp;
<INPUT type=button value="되돌아가기" onclick="history.back(-1)">
</td>
</tr>
</TABLE>
</td>
</tr>
<!-- 입력 부분 끝 -->
</table>

</center>
</body>
</html>

이번에도 기대하셨나요? 이번엔 기대 안하셨다구요? ^^
이번에도 기존의 파일과 동일합니다.

끝~!!!


계층형 게시판 만들기 - 수정된 글 저장

계층형 게시판 만들기 - 수정된 글 저장

1) 수정된 글을 저장해보자 - update.php

update.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

// 글의 비밀번호를 가져온다.
$result=mysql_query("select pass from $board where id=$id", $conn);
$row=mysql_fetch_array($result);

//입력된 값과 비교한다.
if ($pass==$row[pass]) { //비밀번호가 일치하는 경우

$query = "update $board set name='$name',title='$title',email='$email',comment='$comment' where id=$id ";
$result=mysql_query($query, $conn);
}
else { // 비밀번호가 일치하지 않는 경우
echo ("
<script>
alert('비밀번호가 틀립니다.');
history.go(-1);
</script>
");
exit;
}

//데이터베이스와의 연결 종료
mysql_close($conn);

//수정하기인 경우 수정된 글로..
echo ("<meta http-equiv='Refresh' content='1; URL=read.php?id=$id'>");

?>
<center>
<font size=2>정상적으로 수정되었습니다.</font>

진짜 솔직히 이번엔 기대하셨죠? ^^
이번에도 기존의 파일과 동일합니다.

끝~!!!


계층형 게시판 만들기 - 글 읽기

계층형 게시판 만들기 - 글 읽기

1) 저장된 글을 출력해 보자 - read.php

read.php 소스코드
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>
<center>
<BR>
<?
//데이터 베이스 연결하기
include "db_info.php";

// 조회수 업데이트
$result=mysql_query("update $board set see=see+1 where id=$id", $conn);

// 글 정보 가져오기
$result=mysql_query("select * from $board where id=$id", $conn);
$row=mysql_fetch_array($result);

?>

<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 colspan=4 align=center bgcolor=#999999>
<font color=white><B><?=strip_tags($row[title], '<b><i>');?></B></font>
</td>
</tr>
<tr>
<td width=50 height=20 align=center bgcolor=#EEEEEE>글쓴이</td><td width=240 bgcolor=white><?=$row[name]?></td>
<td width=50 height=20 align=center bgcolor=#EEEEEE>이메일</td><td width=240 bgcolor=white><?=$row[email]?></td>
</tr>
<tr>
<td width=50 height=20 align=center bgcolor=#EEEEEE>날&nbsp;&nbsp;&nbsp;짜</td><td width=240 bgcolor=white><?=date("Y-m-d",$row[wdate])?></td>
<td width=50 height=20 align=center bgcolor=#EEEEEE>조회수</td><td width=240 bgcolor=white><?=$row[see]?></td>
</tr>
<tr>
<td bgcolor=white colspan=4 style="word-break:break-all;">
<font color=black>
<pre><?=strip_tags($row[comment], '<b><i><img><a>');?></pre>
</font>
</td>
</tr>
<!-- 기타 버튼 들 -->
<tr>
<td colspan=4 bgcolor=#999999>
<table width=100%>
<tr>
<td width=280 align=left height=20>
<a href=list.php?no=<?=$no?>><font color=white>[목록보기]</font></a>
<a href=reply.php?id=<?=$id?>><font color=white>[답글달기]</font></a>
<a href=write.php><font color=white>[글쓰기]</font></a>
<a href=edit.php?id=<?=$id?>><font color=white>[수정]</font></a>
<a href=predel.php?id=<?=$id?>><font color=white>[삭제]</font></a>
</td>

<!-- 기타 버튼 끝 -->

<!-- 이전 다음 표시 -->
<td align=right>
<?

// 현재 글보다 thread 값이 큰 글 중 가장 작은 것의 id를 가져온다. 즉 바로 이전 글
$query=mysql_query("select id from $board where thread > $row[thread] limit 1", $conn);
$prev_id=mysql_fetch_array($query);

if ($prev_id[id]) // 이전 글이 있을 경우
{
echo "<a href=read.php?id=$prev_id[id]><font color=white>[이전]</font></a>";
}
else
{
echo "[이전]";
}
// 현재 글보다 thread 값이 작은 글 중 가장 큰 것의 id를 가져온다. 바로 다음 글
$query=mysql_query("select id from $board where thread < $row[thread] order by thread desc limit 1", $conn);
$next_id=mysql_fetch_array($query);

if ($next_id[id])
{
echo "<a href=read.php?id=$next_id[id]><font color=white>[다음]</font></a>";
}
else
{
echo "[다음]";
}

?>
</td>
</tr>
</table>
</b></font>
</td>
</tr>
</table>
<BR>
<?
//리스트 출력을 위해 thread를 계산한다.
//출력될 리스트는 글 전체 리스트가 아니라
//1000의 배수인 새글과 이를 포함한 답변글들의 리스트이다.
//답변글이 없는 경우 원본글만 리스트에 나오고
//답변글이 있으면 답변글 모두가 다 나오게된다.
//현재 글이 답변글이어도 새글부터 전체 답변글까지 나온다.
//그럴려면 1000~2000 과 같이 새글사이에 글들을 모두 뿌려주면 된다.
$thread_start = (ceil($row[thread]/1000)-1)*1000;
$thread_end = ceil($row[thread]/1000)*1000;
$query = "select * from $board where thread <= $thread_end and thread > $thread_start order by thread desc";
$result = mysql_query($query, $conn);
?>
<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=20 bgcolor=#999999>
<td width=30 align=center>
<font color=white>번호</font>
</td>
<td width=370 align=center>
<font color=white>제 목</font>
</td>
<td width=50 align=center>
<font color=white>글쓴이</font>
</td>
<td width=60 align=center>
<font color=white>날 짜</font>
</td>
<td width=40 align=center>
<font color=white>조회수</font>
</td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
while($row=mysql_fetch_array($result))
{

?>
<!-- 행 시작 -->
<tr>
<!-- 번호 -->
<td height=20 bgcolor=white align=center>
<a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=$row[id]?></a>
</td>
<!-- 번호 끝 -->
<!-- 제목 -->
<td height=20 bgcolor=white>&nbsp;
<? //depth 값을 통해서 들여쓰기를 한다. 투명이미지의 가로사이즈를 늘이는 방법
if ($row[depth] > 0) echo "<img src=img/dot.gif height=1 width=" . $row[depth]*7 . ">->";
?><a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=strip_tags($row[title], '<b><i>');?></a>
</td>
<!-- 제목 끝 -->
<!-- 이름 -->
<td align=center height=20 bgcolor=white>
<font color=black>
<a href="mailto:<?=$row[email]?>"><?=$row[name]?></a>
</font>
</td>
<!-- 이름 끝 -->
<!-- 날짜 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=date("Y-m-d",$row[wdate])?></font>
</td>
<!-- 날짜 끝 -->
<!-- 조회수 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=$row[see]?></font>
</td>
<!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
} // end While
mysql_close($conn);
?>

</center>
</body>
</html>

저장된 글을 출력하는 페이지입니다.

2) 글 읽기 파일의 구성

글 읽기 파일은 크게 세부분으로 나눌 수 있습니다.

위의 스크린샷을 통해 보이듯이

  1. 글의 내용을 출력하는 부분
  2. 목록보기 글쓰기 수정 등과 같은 버튼 부분
  3. 출력된 글과 연관된 글의 목록

a) 글의 내용 출력 부분

이부분은 기존의 내용과 동일합니다.
달라진게 있다면 ..

<?=strip_tags($row[title], '<b><i>');?>
<?=strip_tags($row[comment], '<b><i><img><a>');?>
<?=date("Y-m-d",$row[wdate])?>

이정도네요.
strip_tags는 문자열에서 HTML이나 PHP태그를 없애는 역할을 합니다.
두번째 문자열은 허용할 태그입니다.
이 외의 태그는 모두 무시하겠다는 뜻이죠.
대충 이해되시죠? 왜 저런걸 썼는지?
필요에 따라 다른것을 추가하거나 아예 태그가 안되게 막는 방법을 사용할 수 있습니다.

다른하나는 앞서 날짜를 Unix Timestamp 값으로 저장한다고 했는데 바로 이부분이 그값을
우리가 보기 좋게 변환하는 부분입니다.

date("형식",UnixTimestamp); 방식으로 사용하시면 됩니다.

b) 버튼 부분

버 튼 | 기 능 |
이전 | 이전글이 있다면 이전글을 링크 | read.php?id=이전글번호 , 이전글 번호를 넘겨줌
다음 | 다음글이 있다면 다음글을 링크 | read.php?id=다음글번호 , 다음글 번호를 넘겨줌

*이전과 다음 버튼

앞선 강좌에서도 이전,다음에 대해서 배웠지만 계층형에서는 이전,다음이 약간 다릅니다.
이전 강좌에선 id가 기준이었던 반면에 계층형에서는 thread 가 기준이 되죠.

이전글 : 현재 thread보다는 크되 큰 글들 중에서 가장 작은 thread의 글

다음글 : 현재 thread보다는 작되 작은 글들 중에서 가장 큰 thread의 글

select id from $board where thread > $row[thread] limit 1
select id from $board where thread < $row[thread] order by thread desc limit 1

중요한 것은 thread 값을 가져오는 것이 아니라 글의 번호인 id 값을 가져오는 것입니다.

참고. 제로 보드에서는 이전 다음이 새글만 적용합니다.
예를들면 3000번의 글에 2999,2998,2997이란 답변글이 있어도 3000번의 이전글은 2999번이 아닌 2000번입니다.
이렇게도 한번 구현해 보세요.^^

c) 관련 글 목록 부분

<?
//리스트 출력을 위해 thread를 계산한다.
//출력될 리스트는 글 전체 리스트가 아니라
//1000의 배수인 새글과 이를 포함한 답변글들의 리스트이다.
//답변글이 없는 경우 원본글만 리스트에 나오고
//답변글이 있으면 답변글 모두가 다 나오게된다.
//현재 글이 답변글이어도 새글부터 전체 답변글까지 나온다.
//그럴려면 1000~2000 과 같이 새글사이에 글들을 모두 뿌려주면 된다.
$thread_start = (ceil($row[thread]/1000)-1)*1000;
$thread_end = ceil($row[thread]/1000)*1000;
$query = "select * from $board where thread <= $thread_end and thread > $thread_start order by thread desc";
$result = mysql_query($query, $conn);
?>
<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=20 bgcolor=#999999>
<td width=30 align=center>
<font color=white>번호</font>
</td>
<td width=370 align=center>
<font color=white>제 목</font>
</td>
<td width=50 align=center>
<font color=white>글쓴이</font>
</td>
<td width=60 align=center>
<font color=white>날 짜</font>
</td>
<td width=40 align=center>
<font color=white>조회수</font>
</td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
while($row=mysql_fetch_array($result))
{

?>
<!-- 행 시작 -->
<tr>
<!-- 번호 -->
<td height=20 bgcolor=white align=center>
<a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=$row[id]?></a>
</td>
<!-- 번호 끝 -->
<!-- 제목 -->
<td height=20 bgcolor=white>&nbsp;
<? //depth 값을 통해서 들여쓰기를 한다. 투명이미지의 가로사이즈를 늘이는 방법
if ($row[depth] > 0) echo "<img src=img/dot.gif height=1 width=" . $row[depth]*7 . ">->";
?><a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=strip_tags($row[title], '<b><i>');?></a>
</td>
<!-- 제목 끝 -->
<!-- 이름 -->
<td align=center height=20 bgcolor=white>
<font color=black>
<a href="mailto:<?=$row[email]?>"><?=$row[name]?></a>
</font>
</td>
<!-- 이름 끝 -->
<!-- 날짜 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=date("Y-m-d",$row[wdate])?></font>
</td>
<!-- 날짜 끝 -->
<!-- 조회수 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=$row[see]?></font>
</td>
<!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
} // end While
mysql_close($conn);
?>

관련 글의 목록을 표시하는 부분입니다.
이부분의 소스는 list.php 의 일부를 가져온 것이며 다른점은 전체 리스트를 보여주는 것이 아니라
관련 글의 목록만 보여준다는 것입니다.
즉, 어떤 글과 그 글을 포함한 답변글 모두를 말하는 것입니다.
이부분은 의외로 간단합니다.
3000번과 관련된 글들은 3000번을 포함해서 2999,2998 과 같은 글들입니다.
따라서 2000보다는 크고 3000번 보다는 작거나 같은 글들을 보여주면 됩니다.

$thread_start = (ceil($row[thread]/1000)-1)*1000;
$thread_end = ceil($row[thread]/1000)*1000;
$query = "select * from $board where thread <= $thread_end and thread > $thread_start order by thread desc";

이외에 depth를 이용해 답변의 깊이를 표현하는 부분이 추가되었습니다.

<? //depth 값을 통해서 들여쓰기를 한다. 투명이미지의 가로사이즈를 늘이는 방법
   if ($row[depth] > 0) echo "<img src=img/dot.gif height=1 width=" . $row[depth]*7 . ">->";
?>

투명이미지를 이용하여 depth의 값에따라 가로크기가 변하게 하여 들여쓰기 효과를 낼 수 있습니다.


계층형 게시판 만들기 - 글 삭제

계층형 게시판 만들기 - 글 삭제

1) 저장된 글을 삭제해보자 - predel.php , del.php

predel.php 소스코드
<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>

<center>
<BR>

<!-- 입력된 값을 다음 페이지로 넘기기 위해 FORM을 만든다. -->
<form action=del.php?id=<?=$id?> method=post>

<table width=300 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<tr>
<td height=20 align=center bgcolor=#999999>
<font color=white><B>비 밀 번 호 확 인</B></font>
</td>
</tr>
<tr>
<td align=center >
<font color=white><B>비밀번호 : </b>
<INPUT type=password name=pass size=8 maxlength=8>
<INPUT type=submit value="확 인">
<INPUT type=button value="취 소" onclick="history.back(-1)">
</td>
</tr>
</table>

del.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

$result=mysql_query("select pass from $board where id=$id", $conn);
$row=mysql_fetch_array($result);

if ($pass==$row[pass] )
{
$conndel = "delete from $board where id=$id ";
$result=mysql_query($conndel, $conn);
}
else
{
echo ("
<script>
alert('비밀번호가 틀립니다.');
history.go(-1);
</script>
");
exit;
}
?>
<center>
<meta http-equiv='Refresh' content='0; URL=list.php'>
<FONT size=2 >삭제되었습니다.</font>

이번이 마지막입니다. ^^
이번에도 기존의 파일과 동일합니다.

끝~!!!


계층형 게시판 만들기 - 글 목록

계층형게시판 만들기 - 글 목록

1) 글 목록을 출력해보자 - list.php

list.php 소스코드
<?
//데이터 베이스 연결하기
include "db_info.php";

#########################################################################
# LIST 설정
# 1. 한 페이지에 보여질 게시물의 수

$page_size=10;

# 2. 페이지 나누기에 표시될 페이지의 수

$page_list_size = 10;

#########################################################################

if (!$no || $no < 0) $no=0; //$no 값이 안넘어 오거나 잘못된(음수)값이 넘어오는 경우 0으로 처리

#########################################################################

// 데이터베이스에서 페이지의 첫번째 글($no)부터 $page_size 만큼의 글을 가져온다.
$query = "select * from $board order by thread desc limit $no,$page_size";
$result = mysql_query($query, $conn);

// 총 게시물 수 를 구한다.
//count 를 통해 구할 수 있는데 count(항목) 과 같은 방법으로 사용한다. * 는 모든 항목을 뜻한다.
//총 해당 항목의 값을 가지는 게시물의 개수가 얼마인가를 묻는것이다.
//따라서 전체 글수가 된다. count(id) 와 같은 방법도 가능하지만 이례적으로 count(*)가 조금 빠르다. 일반적으로는 * 가 느리다.
$result_count=mysql_query("select count(*) from $board",$conn);
$result_row=mysql_fetch_row($result_count);
$total_row = $result_row[0];
//결과의 첫번째 열이 count(*) 의 결과다.

#########################################################################
# 총 페이지 계산

if ($total_row <= 0) $total_row = 0; // 총게시물의 값이 없거나 할경우 기본값으로 세팅

// 총게시물에 1을 뺀뒤 페이지 사이즈로 나누고 소수점이하를 버린다.
$total_page = floor(($total_row - 1) / $page_size); #2003/11/2 (bug report by guy209)

# 총페이지는 총 게시물의 수를 $page_size 로 나누면 알수있다.
# 총 게시물이 12개(1을 빼서 11이된다)이고 페이지 사이즈가 10이라면 결과는 1.1 이 나올것이다.
# 1.1 라는 페이지수는 한 페이지를 다 표시하고도 글이 더 남아있다는 뜻이다.
# 따라서 실제의 페이지수는 2가된다. 한 페이지는 2개의 글만 표시될것이다.
# 그러나 내림을 해주는 이유는 페이지수가 0부터 시작하기 때문이다. 따라서 1은 두번째 페이지이다.
# 총 게시물에 1을 빼주는 이유는 10페이지가 되면 10/10 = 1 이기 때문이다.
# 앞에서도 말했지만 1은 2번째 페이지를 뜻한다.
# 그러나 총게시물이 10개인 경우 한페이지에 모두 출력이 되어야 한다.
# 그래서 1을 빼서 10개인 경우 (10-1) / 10 = 0.9 로 한페이지에 출력하게 한다.
# 글이 0개가 있는 경우는 결과가 -1 이 되지만 -1은 무시된다.
# ( floor 는 내림을 하는 수학함수이다.)
#########################################################################
# 현재 페이지 계산

$current_page = floor($no/$page_size);

# $no 을 통해서 페이지의 첫번째 글이 몇번째 글인지 전달된다.
# 따라서 페이지 사이즈로 나누면 현재가 몇번째 페이지인지 알수있다.
# $no 이 10이고 페이지사이즈가 10 이라면 결과는 1이다. 앞서 페이지는 0부터 시작이라고 했으니 두번째 페이지임을 나타낸다.
# 그렇다면 $no 이 11이라면 1.1 이 되어버린다. 11번째 글도 두번째 페이지에 존재하므로 0.1은 무의미하니 버린다.
# 그런데 $no 이란 값이 $page_size 만큼씩 증가되는 값이기때문에 (0,10,20,30 과 같은 등차수열) 내림을 하는것 또한 무의미하다.
# 그러나 내림을 하는 이유는 $no 값에 11과 같은 값이 들어와도 제대로 출력되기를 바라는 마음에서 해놓은것이다.
?>

<html>
<head>
<title>계층형 게시판</title>
<style>
<!--
td { font-size : 9pt; }
A:link { font : 9pt; color : black; text-decoration : none; font-family : 굴림; font-size : 9pt; }
A:visited { text-decoration : none; color : black; font-size : 9pt; }
A:hover { text-decoration : underline; color : black; font-size : 9pt; }

-->
</style>
</head>

<body topmargin=0 leftmargin=0 text=#464646>
<center>
<BR>
<!-- 게시물 리스트를 보이기 위한 테이블 -->
<table width=580 border=0 cellpadding=2 cellspacing=1 bgcolor=#777777>
<!-- 리스트 타이틀 부분 -->
<tr height=20 bgcolor=#999999>
<td width=30 align=center>
<font color=white>번호</font>
</td>
<td width=370 align=center>
<font color=white>제 목</font>
</td>
<td width=50 align=center>
<font color=white>글쓴이</font>
</td>
<td width=60 align=center>
<font color=white>날 짜</font>
</td>
<td width=40 align=center>
<font color=white>조회수</font>
</td>
</tr>
<!-- 리스트 타이틀 끝 -->
<!-- 리스트 부분 시작 -->
<?
while($row=mysql_fetch_array($result))
{

?>
<!-- 행 시작 -->
<tr>
<!-- 번호 -->
<td height=20 bgcolor=white align=center>
<a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=$row[id]?></a>
</td>
<!-- 번호 끝 -->
<!-- 제목 -->
<td height=20 bgcolor=white>&nbsp;
<? if ($row[depth] > 0) echo "<img src=img/dot.gif height=1 width=" . $row[depth]*7 . ">→"?><a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=strip_tags($row[title], '<b><i>');?></a>
</td>
<!-- 제목 끝 -->
<!-- 이름 -->
<td align=center height=20 bgcolor=white>
<font color=black>
<a href="mailto:<?=$row[email]?>"><?=$row[name]?></a>
</font>
</td>
<!-- 이름 끝 -->
<!-- 날짜 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=date("Y-m-d",$row[wdate])?></font>
</td>
<!-- 날짜 끝 -->
<!-- 조회수 -->
<td align=center height=20 bgcolor=white>
<font color=black><?=$row[see]?></font>
</td>
<!-- 조회수 끝 -->
</tr>
<!-- 행 끝 -->
<?
} // end While

//데이터베이스와의 연결을 끝는다.
mysql_close($conn);
?>
</table>
<!-- 게시물 리스트를 보이기 위한 테이블 끝-->

<!-- 페이지를 표시하기 위한 테이블 -->
<table border=0>
<tr>
<td width=600 height=20 align=center rowspan=4>
<font color=gray>
&nbsp;
<?
#########################################################################
# 페이지 리스트
# 페이지 리스트의 첫번째로 표시될 페이지가 몇번째 페이지인지 구하는 부분이다.

$start_page = (int)($current_page / $page_list_size) * $page_list_size;

#현재 페이지를 페이지 리스트 수로 나누면 현재 페이지가 몇번째 페이지리스트에 있는지 알게된다.
# 이또한 0을 기준으로 하기에 형변환(타입 캐스팅)을 해주었다.
# 형변환은 앞 강좌에서 배웠지만 위의 나누어지는 수가 1.2와 같이 유리수로 표시되기때문에
# int(정수) 형으로 형변환을 하게되면 소수점자리가 사라지게 된다.
# 즉, 위에서 사용한 floor 랑 같은 효과를 하게 되는 것이다.
# 여기에 floor 함수를 취하거나 위의 floor 를 형변환을 해도 상관없다.

# 페이지 리스트의 마지막 페이지가 몇번째 페이지인지 구하는 부분이다.
$end_page = $start_page + $page_list_size - 1;
if ($total_page < $end_page) $end_page = $total_page;

# 보여주는 페이지 리스트중에서 마지막 페이지가 되는 경우는 두가지이다.
# 1. 페이지가 페이지리스트 크기보다 더 많이 남아있을때
# 10개씩 뿌려주는데 총 11페이지가 존재한다면 11페이지는 두번째 목록페이지에 뿌려진다.
# 그렇다면 마지막 페이지 리스트는 10페이지 즉, 첫번째 페이지 + 9 번째 페이지이다.
# 2. 10개씩 뿌려주는데 5페이지 밖에 없다면?
# 마지막 리스트 페이지는 5 페이지가 된다.

#########################################################################
# 이전 페이지 리스트 보여주기
# 페이지 리스트가 10인데 13번째 페이지에 있다면 두번째 목록페이지를 보고 있는것이다.
# 이전 목록페이지로 가고 싶을 때 사용한다.

# 이전 페이지 리스트가 필요할때는 페이지 리스트의 첫 페이지가 페이지 리스트 수보다 클때다.
# 페이지가 적어도 페이지 리스트 수보다는 커야 이전 페이지 리스트가 존재할테니까 말이다.
# 페이지 리스트의 수가 10인데 총 5페이지밖에 없다면 이전 페이지 리스트는 존재하지 않는다.
if ($start_page >= $page_list_size) {

# 이전 페이지 리스트값은 첫번째 페이지 리스트에서 뒤로 리스트의 수만큼 이동하면된다.
# $page_size 를 곱해주는 이유는 글번호로 표시하기 위해서이다.
$prev_list = ($start_page - 1)*$page_size;
echo "<a href=\"$PHP_SELF?no=$prev_list\">◀</a>\n";
}

# 페이지 리스트를 출력
for ($i=$start_page;$i <= $end_page;$i++) {

$page=$page_size*$i; // 페이지값을 no 값으로 변환.
$page_num = $i+1; // 실제 페이지 값이 0부터 시작하므로 표시할때는 1을 더해준다. 페이지 0 -> 1

if ($no!=$page){ //현재 페이지가 아닐 경우만 링크를 표시
echo "<a href=\"$PHP_SELF?no=$page\">";
}

echo " $page_num "; //페이지를 표시

if ($no!=$page){
echo "</a>";
}

}

# 다음 페이지 리스트가 필요할때는 총 페이지가 마지막 리스트보다 클 때이다.
# 리스트를 다 뿌리고도 더 뿌려줄 페이지가 남았을때 다음 버튼이 필요할 것이다.

if($total_page > $end_page)
{
# 다음 페이지 리스트는 마지막 리스트 페이지보다 한 페이지 뒤로 이동하면 된다.
$next_list = ($end_page + 1)* $page_size;
echo "<a href=$PHP_SELF?no=$next_list>▶</a><p>";
}
?>

</font>
</td>
</tr>
</table>

<a href=write.php>글쓰기</a>
</center>
</body>
</html>

실제로 소스가 많아보이지만 바뀐부분은 밑줄그은 부분뿐입니다.

$query = "select * from $board order by thread desc limit $no,$page_size";

이 부분은 기존의 id로 정렬하던 것을 thread로 정렬하게끔 바꾸었습니다.

<? if ($row[depth] > 0) echo "<img src=img/dot.gif height=1 width=" . $row[depth]*7 . ">→"?><a href=read.php?id=<?=$row[id]?>&no=<?=$no?>><?=strip_tags($row[title], '<b><i>');?></a>

이 부분은 read.php와 마찬가지로 depth를 투명이미지를 통해 들여쓰기한 부분입니다.
strip_tags도 보이는 군요.

<?=date("Y-m-d",$row[wdate])?>

이 부분은 아시죠? ^^

2) 계층형 게시판도 정복!!

이제 계층형 게시판도 정복했습니다.
실제로 많이 한 것 같지만 기존 소스에서 수정한 부분은 얼마 되지 않습니다.
약간의 수정으로 계층형 게시판으로 거듭난 것이지요.

이처럼 실제로 어려워보이던 부분도 별 게 아닌 경우가 많습니다.
두려움을 가지기전에 자신감을 가지시면 보다 쉽게 보다 크게 발전할 수 있을거라 생각합니다.

모두들 수고하셨습니다.

참고. 이 게시판 소스는 급조된 것입니다-_-;;
따라서 버그가 존재할 지 모르니 발견즉시 국번없이 111 아니 ^^;;; 게시판에 신고해 주십시오.