PHP 하우투 Al Dev (Alavoor Vasudevan) alavoor@yahoo.com v8.0, 26 Sep 2000 윤광호(KwangHo, Yun), airplanez@kldp.org PHP-HOWTO_kr.sgml, v0.01 2000/11/07 15:50 이문서는 어떻게 PHP 프로그램을 만드는지와 Windows 95 GUI 어플리케이션을 훌륭한 PHP + HTML + DHTML + XML + Java applets + Javascript 로 바꾸는 것을 설명할것이다. 이문서에 있는 정보는 PHP가 포팅 되었있는 Linux, Windows 95/NT, OS/2, Unix 계열의 Solaris, HPUX, AIX, SCO, Sinix, BSD, 등등의 운영체계에 적용된다. ______________________________________________________________________ 목차 1. 소개 2. PHP 내려받기AID CDATA PHP Download(LABEL)LABEL 2.1 Microsoft Windows 95/98/NT/2000에 PHP 설치AID CDATA PHP Installation(LABEL)LABEL 2.2 유닉스들과 다른 플렛폼에서 PHP 설치AID CDATA PHP Installation(LABEL)LABEL 3. PHP 튜토리얼 AID CDATA PHP Tutorial(LABEL)LABEL 4. PHP을 위한 IDE(통합환경) 도구 AID CDATA PHP IDE(LABEL)LABEL 5. 놀라운 !!! PHP를 위한 ctags ! AID CDATA ptags(LABEL)LABEL 6. PHP 디버깅 AID CDATA debugphp(LABEL)LABEL 7. PHP의 제한 8. 관계있는 URL들 9. 이문서의 다른 포멧 10. 저작권 11. 부록 A Database Wrapper 예제 AID CDATA Appendix A(LABEL)LABEL 12. 부록 B SQL abstraction Example AID CDATA Appendix B(LABEL)LABEL 13. 부록 C PostgreSQL large object 예제 AID CDATA Appendix C(LABEL)LABEL 14. 부록 D 사용자 인증 예제 AID CDATA Appendix D(LABEL)LABEL 15. 부록 E 네트워크 관리 예제 AID CDATA Appendix E(LABEL)LABEL 16. 부록 F PostgreSQL Database Wrapper 예제 AID CDATA Appendix F(LABEL)LABEL 17. 부록 G Microsoft SQL Server DB Wrapper 예제 AID CDATA mssql G(LABEL)LABEL 18. 부록 H Sybase SQL Server DB Wrapper 예제 AID CDATA sybase H(LABEL)LABEL 19. 부록 I phpDB.inc 예제 AID CDATA phpdb I(LABEL)LABEL 20. 부록 J phpDBTest.php3 예제 AID CDATA phpDBTest(LABEL)LABEL ______________________________________________________________________ 1. 소개 PHP 는 'Hypertext Pre-Processor'를 의미하고 서버사이드(server side) HTML 스크립팅/프로그래밍 언어이다. PHP는 동적인 웹페이지를 만들수 있게해준다. PHP가 사용된 웹페이지는 일반적인 HTML 처럼 취급되며 평범한 HTML 페이지처럼 생성과 수정을 할수 있다. 많은 회사들이 PHP는 "중요보안과 엄격한 비밀"을 유지할수 있는 컴퓨터 언어라고 말하지만, 그러나 지금은 잘알려지고 많이 쓰이는 웹, 인터넷, 전자상거래와 B2B(business-to-business) 프로젝트을 위한 스크립트 언어가 되었다. 그럼에도 불구하고 요즘 많은 경쟁회사들이 PHP언어를 보안에 대해서 안전하지않다고 한다(경쟁자들).(역주:번역이 영 이상하네..) PHP는 전세계에 돌풍을 일으킬 것이며 IT업계를 놀랍게 점유하게 될것이다!! PHP의 파워는 크로스-플랫폼 이고 어느곳에서도 실행된다!! PHP는 리눅스, 윈도 95/98/NT, 윈도 2000, 솔라리스, HPUX와 모든 유닉스 계열에서 실행된다. PHP는 한번작성 되면 어디서나 실행된다. PHP는 아파치, 마이크로소프트 IIS 등등의 많은 웹서버에서 실행된다. PHP는 자바보다 5에서 20배까지 빠르다!! PHP는 사용하는데 무척쉽고, 매우 복잡한 웹/전자상거래 어플리케이션을 매우 빠르고 짧은 시간에 개발할수 있다. PHP는 객체지향적인 특징과 자바, C++, PERL과 "C"로 부터 훌륭한 특징을 가져왔다. PHP언어는 자바, C++, PERL과 C의 훌륭한 특징의 결합체이다. PHP는 모든 스크립트/프로그램 언어의 진정한 보석이며 곧 전세계 프로그래머의 "메카"가 될것이다!! PHP는 윈도 95/NT 와 모든 유닉스에서 실행되기 때문에 거대한 사용자층과 많은 개발자층을 가진다. PHP는 보다 빠르게 실행되도록 젠옵티마이저(Zend Optimizer)를 사용하여 컴파일과 최적화(optimized)시킬수 있다. 젠옵티마이저(Zend Optimizer)는 PHP 버전 4.0에서 부터 PHP에 통합되었다. 당신은 전자상거래(e-commerce) 프로젝트를 하는데 보통 PHP (70% 코드) + HTML/DHTML/XML (25% 코드) + Javascript (5% 코드 클라이언트 측) 의 조합을 사용할것이다. 2. PHP 내려받기 o PHP 메인 사이트 o PHP 리소스 o PHP 코드 변환 - 2.1. Microsoft Windows 95/98/NT/2000에 PHP 설치 PHP는 Microsoft Windows 플렛폼에서 매우 인기있고 놀랍게도 MS 의 ASP 스트립트 언어보다 더 인기있다!! PHP의 가장큰 장점은 MS 윈도와 리눅스, 유닉스에서 개발할수 있고 반대로 사용할수도 있다는 것이다!! MS 윈도 98/NT/2000 에서 PHP의 수요가 많기 때문에 실행가능한 설치프로그램이 준비되어 있다. 단지 실행화일을 더블클릭 하는 것만으로 2분만에 PHP설치가 자동으로 이루어진다. 실행가능한 설치화일을 다운로드하라. o MS Windows의 PHP 설치 프로그램 o 많은 윈도 플렛폼의 PHP 정보 2.2. 유닉스들과 다른 플렛폼에서 PHP 설치 PHP 메인사이트 나 다운로드한 패키지의 설치파일 에서 설치가이드와 지시를 보라. 3. PHP 튜토리얼 여기에서는 당신의 서버가 PHP 가 가능하고 .php3로 끝나는 모든 화일이 PHP에 의해 실행된다고 가정한다. 첫번째 PHP가 가능한 페이지: 다음의 라인을 넣어서 hello.php3란 화일을 만들어라: ______________________________________________________________________ < head>< title >PHP Test< /title >< /head > < body> "; ?> < /body>< /html> ______________________________________________________________________ CGI 스크립트 처럼 보이지 않을것이다. 특별한 태그를 가지고 있는 보통 HTML 처럼 생각하라. 만약 이것을 실행했는데 아무런 결과도 나타나지 않으면, PHP가 실행되지 않은 것이다. 당신의 관리자에게 실행되게 해달고 요청하라. 이번 연습에서는 PHP의 특별한 태그를 보여주기 위한것이 목적이다. 이번 연습에서 우리는 PHP 태그의 시작을 알리는 < ?php를 사용하였다. 그리고 PHP 문장을 넣고 ? > 태그를 끝에 넣었다. 당신은 당신이 HTML 화일의 원하는 곳에 이렇게 함으로서 PHP 모드를 시작하고 끝낼수 있다. 우리는 페이지를 보는 사람이 어떤 브라우저를 사용하는지 검사해볼것이다. 그렇게 하기위해 우리는 브라우저가 보내온 요청에 대한 부분을 체크한다. 이 정보는 변수에 저장된다. 변수는 언제나 달러사인($)으로 시작한다. 우리가 관심을 가지는 변수는 $HTTP_USER_AGENT 이다. 이것을 보여주기 위해서 우리는 다음과 같이 할수 있다: ______________________________________________________________________ ______________________________________________________________________ 지금 당신이 이 페이지를 보기 위해 사용하는 브라우저에서는, 이렇게 나온다: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) 자신의 웹서버에 의해 자동으로 설정되는 많은 다른 변수들이 있다. 다음과 같은 화일을 만듦으로서 완전한 변수의 리스트를 얻을수 있다: ______________________________________________________________________ ______________________________________________________________________ 브라우저로 이화일을 읽어들이면 자신한데 가용한 모든 변수의 리스트를 화면가득 한 정보와 같이 볼수 있을것이다. PHP 태그안에 여러개의 PHP 문장을 집어넣을수 있으며 하나이상의 echo 문을 가지는 코드블럭을 만들수 있다. ______________________________________________________________________ "; } ?> ______________________________________________________________________ 여기에서는 PHP 블럭의 중간일지라고 PHP모드를 벗어나는 방법을 보여줄것이다: ______________________________________________________________________ < center>< b>You are using Internet Explorer< /b>< /center> < center>< b>You are not using Internet Explorer< /b>< /center> ______________________________________________________________________ PHP의 echo 문을 사용하는 대신 PHP 모드를 벗어나서 직접 HTML 을 넣을수 있다. 여기서 말하려고 하는 중요하고 강력한 점은 논리적인 흐름이 깨지지 않고 남아 있다는 것이다. 단지 HTML 블럭들은 결국 보는 사람에게만 보내지게 되는것이다. 스크립트를 실행시키면 결과는 다음과 같다 : You are using Internet Explorer 폼 다루기 PHP의 가장 유용한 기능중 하나가 HTML 폼(form)을 다루는 방법이다. 그것을 이해하는 중요한 기본적인 개념은 폼에 나온 모든 요소들이 자동적으로 폼에 있는 이름과 같은 변수로 자동적으로 바뀌어 불려진(target) 곳에서 사용 된다는 것이다. 복잡하게 들릴것이다. 그래서 여기 간단한 예제가 있다. 다음과 같은 폼을 가지는 페이지가 있다고 가정하라 : ______________________________________________________________________
Your name: You age: < /form> ______________________________________________________________________ 여기에 있는 폼에는 어떠한 특별한 것도없다. 어떤 특별한 태그도 없는 단지 HTML 폼에 불과 하다. 사용자가 폼을 입력하고 전송버튼을 누리면 action.php3가 불려진다. 불려진 화일에는 다음과 같은 것이 들어있을것이다: ______________________________________________________________________ Hi . You are years old. ______________________________________________________________________ 놀랍게도 $name과 $age 변수는 PHP에 의해 자동으로 정해진다!! 4. PHP을 위한 IDE(통합환경) 도구 많은 HTML 에디터들은 PHP를 지원한다 : o Soyal의 훌륭한 PHP 에디터 o Blue Fish o Coffee cup o 드림위버(Dreamweaver) o Amaya o Homesite o Hotdog o Zend Optimizers(전옵티마이져) o Zend Compilers(전컴파일러) o MS Windows 플렛폼용의 많은 PHP 정보 가까운 시일에 모든 HTML 에디터와 XML 에디터가 "빠른 어플리케이션 개발" 도구로 PHP를 지원할것이다. . 5. 놀라운 !!! PHP를 위한 ctags ! 이 태그들은 상당히 중요하고 vi, emacs, CRiSP, NEdit 등과 같은 에디터로 소스코드를 탐색(검색)하는데 쓰여진다. 만약 C, C++ 또는 자바로 프로그램한 것을 가지고 있다면 태그를 생성하기 위해 ctags 프로그램을 사용할수 있을것이다. 온라인 메뉴얼 페이지(online manual page)를 보기위해서는 리눅스/유닉스 bash prompt 에서 'man ctags'를 치면 된다. PHP를 위한 ptags 프로그램은 다음에 있다. 그것을 사용하면 PHP 소스코드를 위한 태그를 생성할수 있다. ptags를 사용하면 당신의 생산성은 3에서 4배까량 향상될것이다. 또한 에 있는 PHP, C, C++를 위한 Vim 컬러 텍스트 에디터를 참조하라. ______________________________________________________________________ // ptags.cpp로 이화일을 저장하고 // g++ -o ptags ptags.cpp 로 컴파일하라. //***************************************************************** // GNU/GPL 저작권을 따른다. 추가로 복사를 하게되면 저자의 이름, // 이메일을 포함시켜라. // 저자 : Al Dev Email: alavoor@yahoo.com // Usage : ptags *.php3 *.inc // This will generate a file called tags //***************************************************************** #include #include #include // for sprintf #include // for system #include // for memset #include // for isspace #define BUFF_LEN 1024 #define LOCATION 9 char *ltrim(char *dd); char *rtrim(char *ee); main(int argc, char **argv) { if (argc < 2) { cerr << "\nUsage: " << argv[0] << " file .... " << endl; exit(0); } char fname[100] = "tag_file.out"; FILE *fpout; ofstream fout(fname); if (fout.fail()) { cerr << "\nError opening file : " << fname << endl; exit(-1); } //fpout = fopen(fname, "w"); for (int ii = 1; ii < argc; ii++) { /* char buff[2024]; sprintf(buff, "\\rm -f %s; ls %s > %s 2>/dev/null", outfile, argv[1], outfile); cout << "\nbuff = " << buff << endl; system(buff); fclose(fp); */ FILE *fpin = NULL; fpin = fopen(argv[ii], "r"); if (fpin == NULL) { cerr << "\nError opening file : " << argv[ii] << endl; exit(-1); } char buff[BUFF_LEN + 100]; memset(buff, 0, BUFF_LEN +10); for ( ; fgets(buff, BUFF_LEN, fpin) != NULL; ) { char aa[BUFF_LEN + 100]; memset(aa, 0, BUFF_LEN +10); strcpy(aa, buff); ltrim(aa); // Remove the trailing new line.. { int tmpii = strlen(aa); if (aa[tmpii-1] == '\n') aa[tmpii-1] = 0; } //cout << "aa is : " << aa << endl; if (strncmp(aa, "function ", LOCATION) != 0) continue; //cout << buff << endl; // Example tags file output is like - // al2 al.c /^al2()$/;" f { char bb[BUFF_LEN + 100]; memset(bb, 0, BUFF_LEN +10); strcpy(bb, & aa[LOCATION]); char *cc = bb; while (cc != NULL && *cc != '(') *cc++; *cc = 0; cc = rtrim(bb); //cout << "bb is : " << bb << endl; //cout << cc << "\t" << argv[ii] << "\t" << "/^" << aa << "$/;\"\tf" << endl; fout << cc << "\t" << argv[ii] << "\t" << "/^" << aa << "$/;\"\tf" << endl; //fprintf(fpout, "%s\t%s\t/^%s$/;\"f\n", cc, argv[ii], aa ); } memset(buff, 0, BUFF_LEN +10); } fclose(fpin); } fout.flush(); fout.close(); //fclose(fpout); // Sort and generate the tag file { char tmpaa[1024]; sprintf(tmpaa, "sort %s > tags; \\rm -f %s", fname, fname); system(tmpaa); } } char *ltrim(char *dd) { if (dd == NULL) return NULL; while (isspace(*dd)) dd++; return dd; } char *rtrim(char *ee) { if (ee == NULL) return NULL; int tmpii = strlen(ee) - 1; for (; tmpii >= 0 ; tmpii--) { if (isspace(ee[tmpii]) ) { //cout << "\nis a space!!" << endl; ee[tmpii] = 0; } } return ee; } ______________________________________________________________________ 6. PHP 디버깅 PHP 프로그램을 디버깅 하려면 다음의 함수를 가지는 "debug2.inc"이란 화일을 만들어라 : ______________________________________________________________________ File open failed - global.var.inc"; exit; } function debug2_($fname, $lname, $debug_var, $debug_value=0) { global $fp_debug2; //print "
debug_value is : $debug_value
"; if (!$debug_value) { fwrite($fp_debug2, "\n ". $fname ." ". $lname .": $debug_var"); } else { fwrite($fp_debug2, "\n ". $fname . " ". $lname .": $debug_var = $debug_value"); } //print "
f_cookie is : $f_cookie
"; } // In your first page, which is generally index.php3 // truncate the debug2_logs file in beginning of code function init_debug_file() { global $fp_debug2; $fp_debug2 = fopen("/debug2_logs/debug.out", "w"); if ($fp_debug2 == false) { print "File open failed - global.var.inc"; exit; } system("chmod a+rwx /debug2_logs/debug.out"); } ?> ______________________________________________________________________ 보통 index.php3로 되는 시작페이지의 PHP 소스코드에 다음을 집어넣어라. ______________________________________________________________________ ______________________________________________________________________ 디버깅 값을 얻기위해 PHP 소스코드 파일에 debug2_() 란 호출을 아래와 같이 넣어라 ______________________________________________________________________ ______________________________________________________________________ PHP 프로그램을 실행하게 되면, 결과가 debug.out 이란 화일에 파일이름, 라인번호, 변수명 과 변수값이 나타난다. 일번적으로 debug2_()를 사용하라. 프로그램에서 debug2_()의 호출은 최종결과 코드에 어떠한 영향도 주지않으며 실행에도 아무런 영향을 주지않는다. 왜냐하면 아래에 기술한것 같이 필터링 되기 때문이다. debug2_()를 타이핑하는 시간을 줄이기 위해 복사(copy)와 붙여넣기(paste)를 사용할수 있다. 또한 Vi 에디터의 'yank to buffer' 기능을 이용해서 복사하라. 개발이 완료되면 테스트하고 서버에 올린 준비가 됐으면 소스코드에서 debug2_ 호출을 필터링 하라. 유닉스 프롬프트에서 - ______________________________________________________________________ bash$ mkdir production bash$ grep -v debug2_ filea.php3 > production/filea.php3 ______________________________________________________________________ 여러개의 화일이 있으면 - ______________________________________________________________________ bash$ mkdir production bash$ ls *.php3 | while read ans do grep -v debug2_ $ans > production/$ans done ______________________________________________________________________ 그리고 이제 production 에서 개발하는곳(영역)을 복사하라. 7. PHP의 제한 모든 사람이 한계와 단점이 있듯이 PHP도 예외가 아니다. 아래에 있는것은 PHP의 제약(한계)이다.(그래서 경고한다 !!) 1. PHP는 100% 순수한 객체지향 스크립트 언어가 아니다. PHP는 코드의 크기가 300,000 라인을 넘지 않으면 괜찬다. 300,000 라인이 넘는 PHP코드를 관리하기는 좀더 힘들어질것이다. 2. PHP는 "C"나 "C++" 언어의 성능을 주지 모한다. 왜냐하면 PHP는 스크립트 언어이고 실행방식이 인터프리터 형식이기 때문에 최적화된 "C++"보다 다소 느리다. 최고의 성능을 원한다면 "C++"과 커넥션 풀링(connection pooling)된 데이타베이스/웝서버와 연동된 빠른 CGI 를 사용하고 C++ 컴파일러 옵티마이져를 "-03" 옵션을 사용하라. PHP 4에 있는젠드옵티마이져는 PHP의 성능을 어느정도 향상시킬것이다. 한편으로는 PHP는 많은 장점을 가지고 그 장점은 제한을 보충할수 있다 - 1. PHP 스크립트 언어에서는 컴파일과 링크가 생략되기 때문에 매우 빠르게 웹어플리케이션을 개발할수있다. 2. PHP 에플리케이션은 매우 안정적이고 자바스크립트가 브라우져에 의존적인것과 다르게 브라아져의 기술에 의존적이지 않다. PHP는 어떤 서버 플렛폼과 어떤 브라우져를 선택해야하는 것에 대한 자유를 주고 브라우져는 HTML 이 PHP가 만들어냈다는 것을 모른다! 3. PHP는 모든 SQL 테이터베이스 서버와의 연결성이 뛰어나다. 4. PHP는 부분적으로 객체지향 특성을 가지고 있다. 5. PHP는 "C++", Perl, Javascript와 비슷한 문법을 가지고 소스코드를 탐색할수 있는 프로그램과 비슷한 'ptags/ctags'를 가지고 있다. 6. PHP는 속도를 향상시킬수 있는 젠드옵티마이져를 가지고 있다. 7. PHP는 모든 유닉스들, 리눅스, 윈도 95/NT/200 에서 실행되며 ASP, JSP와 다른것보다 성능이 좋다. 8. PHP는 많은 사용자층와 개발자층을 가지고 있다. 경고: 만약 100% 순수한 객체지향 스크립트 언어를 원한다면 "반드시" Python을 염두해라. 'Python'은 처음부터 객체지향 스크립트언어이다. 에 있다. 8. 관계있는 URL들 C, C++에 관계있는 다음 장소를 방문하라 - o C++, C을 위한 컬러 Vim 텍스트 에디터 o PHP PostgreSQL를 위한 SQL database server o C++ 프로그램을 위한 Source code control system CVS HOWTO o Linux goodies main site o Linux goodies mirror site 9. 이문서의 다른 포멧 이문서는 DVI, Postscript, Latex, Adobe Acrobat PDF, LyX, GNU-info, HTML, RTF(Rich Text Format), Plain-text, Unix man pages 와 SGML 11가지의 다른 포멧이 있다. o 이 HOWTO 문서을 HTML, DVI, Postscritp 또는 SGML 포멧으로 된 tar ball 파일을 에서 구할수 있다. o 단순한 텍스트 포멧은 에서 o 불어, 독어, 서반아어, 중국어, 일본어로 번역된 문서는 에서 구할수 있다. 다른 언어로 번역하실 분의 도움을 환영한다. 이문서는 에서 구할수 있는 "SGML-Tools"란 툴을 사용해서 작성되었다. 다음과 같은 명령을 사용해서 소스를 컴파일 할수 있다. o sgml2html CVS-HOWTO.sgml (html 화일을 만들기 위해) o sgml2rtf CVS-HOWTO.sgml (RTF 화일을 만들기 위해) o sgml2latex CVS-HOWTO.sgml (latex 화일을 만들기 위해) LaTex 문서는 sgml2latex (와 dvips) 그리고 아크로바트(Acrobat) distill ( ) 을 사용한 포스트스크립트 결과 처리로 PDF화일로 쉽게 바꿀수 있다. 다음음 명령들이다: ______________________________________________________________________ bash$ man sgml2latex bash$ sgml2latex filename.sgml bash$ man dvips bash$ dvips -o filename.ps filename.dvi bash$ distill filename.ps bash$ man ghostscript bash$ man ps2pdf bash$ ps2pdf input.ps output.pdf bash$ acroread output.pdf & ______________________________________________________________________ 또는 고스트스크립(Ghostscript) 명령 ps2pdf을 사용할수 있다. ps2pdf는 Adobe's Acrobat Distiller product 의 거의 모든 기능과 비슷하게 동작한다. 포스트스크립트 화일을 PDF(Portable Document Format)으로 바꾸어준다. ps2pdf는 명령 스크립트(command script/배치파일)가 Ghostscript를 불러내고 , pdfwrite라고 불리는 특별한 출력 디바이스를 선택하여 실행된다. ps2pdf를 사용하기 위해 Ghostscript를 컴파일 할때 pdfwrite 장치가 makefile에 포함되어야한다; 자세한 것은 Ghostscript 설치 문서를 보아라. 이문서는 다음에서 찾을수 있다 - o 또한 다음의 미러 사이트에서 이문서를 찾을수 있다 - o o o o o 다른 당신과 가까운 미러사이트(network-address-wise)는 에서 찾을수 있다. 사이트를 선택하고 /LDP/HOWTO/CVS-HOWTO.html 디렉토리고 가라. 그 dvi 포멧으로 되어있는 그 문서를 보기위해서는 xdvi란 프로그램을 사용하라. xdvi 프로그램은 래드햇 리눅스의 tetex-xdvi*.rpm 패키지에 있고 메뉴버튼 ControlPanel | Applications | Publishing | TeX 에 있다. dvi 문서를 읽기 위해 다음의 명령을 실행하라 - xdvi -geometry 80x90 howto.dvi man xdvi 그리고 마우스를 사용하여 윈도우 크기를 조절하라. 화살표키, Page Up, Page Down keys 와 위, 아래, 중간, 다음페이지, 전 페이지 등을 탐색할수 있다. 실행을 끝내려면 'x'를 눌러라. 화일을 읽을수 있다. 래드햇 리눅스에서 ghostscript 는 ghostscript*.rpm 패키지에 gv는 gv*.rpm 패키지에 있다. 그리고 ControlPanel | Applications | Graphics 메뉴 버튼에 위치한다. gv 가 ghostscript보다 더 친근한 프로그램이다. 그리고 ghostscript와 gv는 OS/2, Windows 95 와 NT 용도 존재한다. 그리고 그 운용체제에서 이 문서도 볼수 있다. o Get ghostscript for Windows 95, OS/2, and for all OSes from 포스트스크립트 문서를 읽기 위해 다음을 입력하라 - gv howto.ps ghostscript howto.ps 네스케이프 네비게이터, 마이크로소프트 인터넷 익스폴로러, 래드햇 바론 웹브라우져 또는 10가지 이상의 웹부라우져에서 HTML 포맷문서를 읽을수 있다. LyX 라는 X-Windows용 프로그램으로 latex 문서를 읽을수 있다. 10. 저작권 저작권정책은 LDP(리눅스 문서 프로젝트)의 GNU/GPL을 따른다. LDP는 GNU/GPL 프로젝트이다. 추가적인 요구 - 저작자의 이름, 이메일주소와 이 저작권사항을 유지하라. 만약 당신이 이문서에 어떠한 수정이나 첨가를 할경우 이문서의 저자에게 알려주어라. 11. 부록 A Database Wrapper 예제 제출자 : Barton Greg greg@createtech.com 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 pgsql.lib 라고 입력하시오. ______________________________________________________________________ 이것은 PostgresSQL을 위한 데이터베이스 랩퍼이지만 다른 형식의 데이터베이스를 위해 조금만 고치면 사용할수 있다. host; if(isset($parame[user])) $user = $parame[user]; else $user = $this->user; if(isset($parame[password])) $password = $parame[password]; else $password = $this->password; if(isset($parame[port])) $port = $parame[port]; else $port = $this->port; if(isset($parame[dbname])) $dbname = $parame[dbname]; else $dbname = $this->dbname; $this->conn = pg_Connect ( " host=$host user=$user password=$password port=$port dbname=$dbname "); } // Send SQL to database connection. // Return recordset object on success. // Return 0 on failure. function exec($SQL) { $this->resultset = pg_Exec($this->conn, $SQL); if ($this->resultset) { $recset = new recordset; $recset->init($this->resultset); return $recset; } else { return 0; } } function valid() { return $this->resultset; } // Close connection to database function free() { pg_close($this->conn); } }; /* ** This is a simple recordset class which can be ** traversed using next(), prev(), and current() methods. ** It is initialized from a resultset returned from the ** function "pg_Exec" or can be generated by a call to the ** exec method from the dbObj class given above. ** Below "Tuples" means rows. */ class recordset { var $resultset; var $index; var $numFields; var $numTuples; function init($newResultset) { $this->resultset = $newResultset; $this->index = 0; $this->numFields = pg_NumFields($this->resultset); $this->numTuples = pg_NumRows($this->resultset); } // Used in display() below function valid() { return $this->resultset; } // Get a value by row number and either // column name or column number function getVal($row, $col) { return pg_Result($this->resultset, $row, $col); } // Return an array of field names function getFields() { for ($i=0; $i < $this->numFields; $i++) $retArray[] = pg_FieldName($this->resultset, $i); return $retArray; } // Get number of columns in resultset function getNumFields() { return $this->numFields; } // Get a tuple (associative array of // column values) by row number function getTupleDirect($row) { for ($i=0; $i < $this->numFields; $i++) { $retArray[pg_FieldName($this->resultset, $i)] = pg_Result($this->resultset, $row, $i); } return $retArray; } // Get an array filled with all values in a column // (using either column name or column number) function getColumn($col) { for ($i=0; $i < $this->numTuples; $i++) $retArray[] = pg_Result($this->resultset, $i, $col); return $retArray; } // Return the number of records in the recordset function getNumTuples() { return $this->numTuples; } // Get tuple pointed to by the current index function getTuple() { if ($this->index >= 0 && $this->index < $this->numTuples) return $this->getTupleDirect($this->index); else return 0; } function valueof($col) { if ($col < $this->numFields) { return pg_Result($this->resultset, $this->index, $col); } else { return ""; } } // Reached last row - end of rows ? Used in display() below function eof() { return $this->index == $this->numTuples; } // Return 1 if index is within bounds of the recordset function current() { if ($this->index >= 0 && $this->index < $this->numTuples) return 1; else return 0; } // Increment index. Used in display() below function next() { if ($this->index < $this->numTuples) { $this->index++; return 1; } else { return 0; } } // Decrement index function prev() { if ($this->index >= 0) { $this->index--; return 1; } else { return 0; } } // Reset index to 0 - See also first() function reset() { $this->index = 0; } // See also reset(). Used in display() below function first() { $this->index = 0; } function last() { $this->index = $this->numTuples -1 ; } // Used in display() below function showheader($col, $fmt = "") { printf("\t< th %s>%s< /th >\n", $fmt, is_string($col) ? $col : pg_fieldname($this->resultset, $col)); } // Used in display() below function showvalue($col, $fmt = "", $def = " ") { $v = $this->valueof($col); printf( "\t< td %s>%s< /td>\n", $fmt, $v == "" ? $def : $v); } function showurl($col, $fmt = "") { $v = $this->valueof($col); if ( $v != "" ) { printf("\t< td %s> < /td>\n", $fmt); } else { printf( "\t< td %s>< a href=%s>%s< /a>< /td>\n", $fmt, $v, $v); } } function display() { if (!$this->valid() ) { return; } printf( "\n"); printf( "\n"); for ($c = 0; $c < $this->cols; $c++ ) { $this->showheader($c); } printf( "< /tr>\n"); $this->first(); while (!$this->eof()) { printf( "\n"); for ($c = 0; $c < $this->cols; $c++) { $this->showvalue($c); } printf( "< /tr>\n"); $this->next(); } printf("< /table\n"); } // Free memory allocated to recordset. function free() { pg_Freeresult($this->resultset); } }; } ?> ______________________________________________________________________ 12. 부록 B SQL abstraction Example 제출자 : Gianugo Rabellino nemorino@opera.it 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 sqlabst.lib 라고 입력하시오. ______________________________________________________________________ PX: PHP Code Exchange ______________________________________________________________________ 14. 부록 D 사용자 인증 예제 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 user_pw.lib 라고 입력하시오. PHP 3 메뉴얼에서 : PHP가 아파치 모듈일때만 작동한다. $PHP_AUTH_USER 와 $PHP_AUTH_PW 를 출력하는 대신, 사용자이름과 비밀번호를 확인만 하기을 원할지도 모른다. 아마도 데이터베이스에 쿼리를 보내거나 adm 화일에서 찾아보면 될것이다. ______________________________________________________________________ "; echo "You entered $PHP_AUTH_PW as your password.

"; } ?> ______________________________________________________________________ 15. 부록 E 네트워크 관리 예제 이 화일을 얻으려면 웹브라우저에서 network.lib란 이름의 '텍스트(Text)' 형태로 저장하라. PHP: network adminstrator's best friend from 웹개발자로서 아마 ping, whois, nslookup 등등의 유용한 툴을 사용할것이다. 그러나 고객의 사무실에서 그 툴중 하나를 사용해야되는데 telnet을 사용할수 없다면 어떻게할것인가? PHP 매뉴얼의 '네트워크'에서 function을 찾아보는 것이 대안이다. 소켓 작동 : 가장 중요한 함수는 fsockopen()이다. 이함수를 사용하면 서버의 열려진 어떤 포트로도 접속할수 있고 소켓의 연결을 설정할수 있다. 함수의 문법은 다음과 같다 : ______________________________________________________________________ int fsockopen(string hostname, int port, int [errno], string [errstr]); ______________________________________________________________________ 앞의 2개의 변수는 쉽게 알수 있고, 다음의 2개의 변수는 옵션이고, 에러를 처리하기 위해 쓰인다. "errno"과 "errstr"은 참조를 통해서 이루어져야 한다. "참조를 통해 이루어진다"는 말의 의미는 원래의 변수가 변한다는 말이다. 보통, 함수가 실행되더라도 변수의 내용은 변하지 않는다. 그래서, 웹서버에 연결하기 위해 이함수를 사용하고 헤더를 프린트하라 : ______________________________________________________________________ function get_headers($host, $path = "/") { $fp = fsockopen ("$host", 80, &$errnr, &$errstr) or die("$errno: $errstr"); fputs($fp,"GET $path HTTP/1.0\n\n"); while (!$end) { $line = fgets($fp, 2048); if (trim($line) == "") $end = true; else echo $line; } fclose($fp); } ______________________________________________________________________ 이 예제에서는 fsockopen()을 호출해서 얻은 파일포인터와 파일처리에 관한응용을 알아볼것이다.(fred, fwrite 등등) HTTP/1.0 클라이언트에서만 구현된다는것을 명심하라. - name-based 가상호스트에서는 동작하지 않는다. 지시: 일반적으로 다른 포트로 연결 할수 있다. PHP로 작은 핑거 클라이언트를 만든것은 쉬게 할수 있다. 핑거 데몬에 쿼리(질문)하기 위해 아래에 있는 예제를 수정하라. ______________________________________________________________________ function finger ($host, $user) { $fp = fsockopen($host, 79, &$errno, &$errstr) or die("$errno: $errstr"); fputs($fp, "$user\n"); while (!feof($fp)) echo fgets($fp, 128); fclose($fp); } ______________________________________________________________________ Whois: 후이스(whois) 서버에 질문하는것도 같은 개념이다: ______________________________________________________________________ // domain is like "phpwizard.net" function whois($domain, $server="whois.internic.net") { $fp = fsockopen ($server, 43, &$errnr, &$errstr) or die("$errno: $errstr"); fputs($fp, "$domain\n"); while (!feof($fp)) echo fgets($fp, 2048); fclose($fp); } ______________________________________________________________________ 블럭킹, 넌블록킹 제어 : 그러나 이함수를 사용하는데 문제가 있다. 다음과 같을때만 잘작동한다. 1. 호출시간이 작은 연결일때와 2. 연결하고 있는 서버가 살아있고 작동할때. 그렇지 않으면, 당신의 스크립트는 종료될때까지 작동한다. 그렇게 되는 이유는 소켓연결은 블럭킹되며 종료가 되지않기 때문이다. set_socket_blocking()이란 함수는 다음과 같이 동작한다: 함수는 모든동작을 소켓(첫번째 인수:소켓 포인터)에 블럭킹(두번재 인수:true)나 폴스(false)(세번째 인수:false)로 설정한다. 넌블럭킹제어를 사용하면, 핑거(finger)함수는 다음과 같을것이다:(역주:무슨말인지 번역이 이상하네요) ______________________________________________________________________ $fp = fsockopen($host, 79, &$errno, &$errstr) or die("$errno: [ ] $errstr"); set_socket_blocking($fp, 0); fputs($fp, "$user\n"); $stop = time() + $timeout; while (!feof($fp) && time() < $stop ) echo fgets($fp, 128); fclose($fp); ______________________________________________________________________ 넌블러킹 소켓콜(socket calls)을 사용하기 위한 3개의 함수의 수정은 당신의 연습을 위해 남겨둔다. 16. 부록 F PostgreSQL Database Wrapper 예제 제출자 : Joe Thong darkjoe@softhome.net 사이트 URL: 설명: 여러가지 데이터베이스 서버에서 결과 조작을 위한 강력한 PHP 데이타베이스 랩퍼. 데이터베이스의 결과가 phpDB에 의해 자동으로 나오게 된다. 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 phpDB- postgresql.lib 라고 입력하시오. ______________________________________________________________________ databaseType = $dbType; break; default: return false; } } // Returns: A positive link identifier on success, or // false on error. Connect to the server with the provided // arguments. The connection to the server will be closed // when the script terminates, unless close() function is // called beforehand function connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $connString = ""; $hostPieces = array(); /* Must specify the database argument */ if (!$argDatabaseName) { return false; } if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $hostPieces = split(":", $this->hostname); if ($hostPieces[0]) { $connString .= "host=$hostPieces[0]"; if (isset($hostPieces[1])) { $connString .= " port=$hostPieces[1]"; } } if ($this->username) { $connString .= " user=$this->username"; } if ($this->password) { $connString .= " password=$this->password"; } $connString .= " dbname=$this->databaseName"; $this->_connectionID = @pg_Connect($connString); return $this->_connectionID; } // Returns: A positive link identifier on success, or // false on error. Connect to the server with the // provided arguments. The connection to the server will // not be closed when the script terminates. Instead it // will be kept for later future use function pconnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $connString = ""; $hostPieces = array(); /* Must specify the database argument */ if (!$argDatabaseName) { return false; } if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $hostPieces = split(":", $this->hostname); if ($hostPieces[0]) { $connString .= "host=$hostPieces[0]"; if (isset($hostPieces[1])) { $connString .= " port=$hostPieces[1]"; } } if ($this->username) { $connString .= " user=$this->username"; } if ($this->password) { $connString .= " password=$this->password"; } $connString .= " dbname=$this->databaseName"; $this->_connectionID = @pg_pConnect($connString); if ($this->_connectionID) { $this->_isPersistentConnection = true; } return $this->_connectionID; } // Returns: true on success, false on error Select // the database name to be used PostgreSQL // Note: function Not available function selectDB($dbName) { return false; } // Returns: the Recordset object disregard success // or failure Send the sql statement to the database server function execute($sql = "") { // Instantiate an object without considering whether // the query return any results or not $this->_queryID = @pg_Exec($this->_connectionID, $sql); $this->_tempResultObj = new Recordset($this->_queryID); $this->_insertQuery($this->_queryID); return $this->_tempResultObj; } // Returns: the last error message from previous // database operation function errorMsg() { $this->_errorMsg = @pg_errormessage($this->_connectionID); return $this->_errorMsg; } // Returns: true on success, false on failure // Close the database connection function close() { if ($this->_queryIDList && sizeof($this->_queryIDList > 0)) { while(list($_key, $_resultID) = each($this->_queryIDList)) { @pg_freeresult($_resultID); } } // If its not a persistent connection, then // only the connection needs to be closed if ($this->_isPersistentConnection != true) { return @pg_close($this->_connectionID); } else { return true; } } // A PRIVATE function used by the constructor function // of the query object. insert the successful returned // query id to the query id list. Used for later results // cleanup. A private function that's never meant to // be used directly function _insertQuery($query_id) { $this->_queryIDList[] = $query_id; } } //------------------------------ Class Name: Recordset //------------------------------ class Recordset { /* public variables */ var $fields; // indicates that the current record position is before // the first record in a Recordset object var $BOF = null; // indicates that the current record position is after // the last record in a Recordset object var $EOF = null; /* private variables */ var $_numOfRows = -1; // NEVER change the value! READ-ONLY! var $_numOfFields = -1; // NEVER change the value! READ-ONLY! // Holds anything that was returned from the database specific functions var $_tempResult = ''; // This variable keeps the result link identifier var $_queryID = -1; // This variable keeps the current row in the Recordset var $_currentRow = -1; // Returns: query id on success and false if // failed Constructor function function Recordset($queryID) { $this->_queryID = $queryID; if ($queryID) { $this->_numOfRows = @pg_numrows($this->_queryID); /* pg_numrows() returns -1 on error */ if ($this->_numOfRows == -1) { $this->_numOfRows = 0; } $this->_numOfFields = @pg_numfields($this->_queryID); /* pg_numfields() returns -1 on error */ if ($this->_numOfFields == -1) { $this->_numOfFields = 0; } } else { $this->_numOfRows = 0; $this->_numOfFields = 0; } /* If result set contains rows */ if ($this->_numOfRows > 0 && $this->_currentRow == -1) { $this->_currentRow = 0; $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow); $this->EOF = false; $this->BOF = false; } return $this->_queryID; } // Returns: true if successful, false if fail Set the Recordset // pointer to a specified field offset. If the next call to // fetchField() won't include a field offset, this field would // be returned. PostgreSQL Note: function Not available function fieldSeek($fieldOffset = -1) { $this->_tempResult = false; return $this->_tempResult; } // Returns: an object containing field information. Get column // information in the Recordset object. fetchField() can be used // in order to obtain information about fields in a certain query // result. If the field offset isn't specified, the next field // that wasn't yet retrieved by fetchField() is retrieved. // PostgreSQL Note: function Not available function fetchField($fieldOffset = -1) { $this->_tempResult = false; return $this->_tempResult; } // Returns: true if there still rows available, or false if there // are no more rows. Moves to the next row in a specified Recordset // object and makes that record the current row and the data // corresponding to the row will be retrieved into the fields // collection. Note: Unlike the moveRow() method, when _currentRow // is getNumOfRows() - 1, EOF will immediately be true. If row number // is not provided, the function will point to the // first row automatically function nextRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow++; $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow); /* This is not working. True all the time */ if ($this->fields) { $this->_checkAndChangeEOF($this->_currentRow - 1); return true; } } $this->EOF = true; return false; } // Returns: true on success, false on failure moveRow() moves // the internal row pointer of the Recordset object to point // to the specified row number and the data corresponding to // the row will be retrieved into the fields collection. If // row number is not provided, the function will point to // the first row automatically function moveRow($rowNumber = 0) { if ($rowNumber == 0) { return $this->firstRow(); } else if ($rowNumber == ($this->getNumOfRows() - 1)) { return $this->lastRow(); } if ($this->getNumOfRows() > 0 && $rowNumber < $this->getNumOfRows()) { $this->fields = null; $this->_currentRow = $rowNumber; $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow); /* This is not working. True all the time */ if ($this->fields) { // No need to call _checkAndChangeEOF() because // the possibility of moving to the last row // has been handled by the above code $this->EOF = false; return true; } } $this->EOF = true; return false; } // Returns: true on success, false on failure firstRow() // moves the internal row pointer of the Recordset object // to the first row and the data corresponding to the row // will be retrieved into the fields collection function firstRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow = 0; $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow); $this->EOF = true; /* This is not working. True all the time */ if ($this->fields) { return true; } } $this->EOF = true; return false; } // Returns: true on success, false on failure lastRow() // moves the internal row pointer of the Recordset object // to the last row and the data corresponding to the row // will be retrieved into the fields collection function lastRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $num_of_rows = $this->getNumOfRows(); /* $num_of_rows decemented at above */ $this->_currentRow = --$num_of_rows; $this->fields = @pg_fetch_array($this->_queryID, $this->_currentRow); /* This is not working. True all the time */ if ($this->fields) { /* Special case for making EOF false. */ $this->EOF = false; return true; } } $this->EOF = true; return false; } // close() only needs to be called if you are worried about // using too much memory while your script is running. All // associated result memory for the specified result identifier // will automatically be freed function close() { $this->_tempResult = @pg_freeresult($this->_queryID); return $this->_tempResult; } // Returns: the number of rows in a result set. // Get number of rows in result function getNumOfRows() { return $this->_numOfRows; } // Returns: the number of fields in a result set. // Get number of fields in result function getNumOfFields() { return $this->_numOfFields; } /* Check and change the status of EOF. */ function _checkAndChangeEOF($currentRow) { if ($currentRow >= ($this->_numOfRows - 1)) { $this->EOF = true; } else { $this->EOF = false; } } } ?> ______________________________________________________________________ 17. 부록 G Microsoft SQL Server DB Wrapper 예제 제출자 : Joe Thong darkjoe@softhome.net Site URL: 설명: 여러가지 데이터베이스 서버에서 결과 조작을 위한 강력한 PHP 데이타베이스 랩퍼. 데이터베이스의 결과가 phpDB에 의해 자동으로 나오게 된다. 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 phpDB- msql.lib 라고 입력하시오. ______________________________________________________________________ databaseType = $dbType; break; default: return false; } } // Returns: A positive link identifier on success, // or false on error. Connect to the server with // the provided arguments. The connection to the server // will be closed when the script terminates, unless // close() function is called beforehand. function connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $boolDBSelected; if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $this->_connectionID = @mssql_connect($this->hostname, $this->username, $this->password); if ($this->databaseName && $this->_connectionID) { $boolDBSelected = @mssql_select_db($this->databaseName); if(!$boolDBSelected) { /* If DB selection fails */ @mssql_close($this->_connectionID); /* Close the current connection */ return false; } } return $this->_connectionID; } // Returns: A positive link identifier on success, or // false on error Connect to the server with the provided // arguments. The connection to the server will not be closed // when the script terminates. Instead it will be kept for // later future use function pconnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $boolDBSelected; if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $this->_connectionID = @mssql_pconnect($this->hostname, $this->username, $this->password); if ($this->_connectionID) { $this->_isPersistentConnection = true; } if ($this->databaseName && $this->_connectionID) { $boolDBSelected = @mssql_select_db($this->databaseName); if(!$boolDBSelected) { /* if DB selection fails */ return false; /* Persistent connection can't be closed */ } } return $this->_connectionID; } // Returns: true on success, false on error Select the // database name to be used function selectDB($dbName) { $this->databaseName = $dbName; if ($this->_connectionID) { return @mssql_select_db($dbName); } else { /* No database selected */ return false; } } // Returns: the Recordset object disregard success or // failure Send the sql statement to the database server function execute($sql = "") { $this->_queryID = @mssql_query($sql, $this->_connectionID); // Instantiate an object without considering whether // the query return any results or not $this->_tempResultObj = new Recordset($this->_queryID); $this->_insertQuery($this->_queryID); return $this->_tempResultObj; } // Returns: the last error message from previous database // operation Note: This function is NOT available for // Microsoft SQL Server function errorMsg() { $this->_errorMsg = "errorMsg() is not available for Microsoft SQL Server"; return $this->_errorMsg; } /* Returns: true on success, false on failure Close the database connection. */ function close() { if ($this->_queryIDList && sizeof($this->_queryIDList > 0)) { while(list($_key, $_resultID) = each($this->_queryIDList)) { @mssql_free_result($_resultID); } } // If its not a persistent connection, then // only the connection needs to be closed if ($this->_isPersistentConnection != true) { return @mssql_close($this->_connectionID); } else { return true; } } // A PRIVATE function used by the constructor function of // the query object. insert the successful returned // query id to the query id list. Used for later results // cleanup. A private function that's never meant to be // used directly function _insertQuery($query_id) { $this->_queryIDList[] = $query_id; } } //--------------------------------------- Class Name: Recordset //--------------------------------------- class Recordset { /* public variables */ var $fields; // indicates that the current record position is // before the first record in a Recordset object var $BOF = null; // indicates that the current record position is // after the last record in a Recordset object var $EOF = null; // Private variables var $_numOfRows = -1; // NEVER change the value! READ-ONLY! var $_numOfFields = -1; // NEVER change the value! READ-ONLY! // Holds anything that was returned from the // database specific functions var $_tempResult = ''; // This variable keeps the result link identifier var $_queryID = -1; // This variable keeps the current row in the Recordset var $_currentRow = -1; // Returns: query id on success and false if // failed Constructor function function Recordset($queryID) { $this->_queryID = $queryID; if ($queryID) { $this->_numOfRows = @mssql_num_rows($this->_queryID); $this->_numOfFields = @mssql_num_fields($this->_queryID); } else { $this->_numOfRows = 0; $this->_numOfFields = 0; } // If result set contains rows if ($this->_numOfRows > 0 && $this->_currentRow == -1) { $this->_currentRow = 0; $this->fields = @mssql_fetch_array($this->_queryID); $this->EOF = false; $this->BOF = false; } return $this->_queryID; } // Returns: true if successful, false if fail Set // the Recordset pointer to a specified field offset. // If the next call to fetchField() won't include a // field offset, this field would be returned function fieldSeek($fieldOffset = -1) { $this->_tempResult = @mssql_field_seek($this->_queryID, $fieldOffset); return $this->_tempResult; } // Returns: an object containing field information. // Get column information in the Recordset object. // fetchField() can be used in order to obtain information // about fields in a certain query result. If the field // offset isn't specified, the next field that wasn't yet // retrieved by fetchField() is retrieved function fetchField($fieldOffset = -1) { if ($fieldOffset != -1) { $this->_tempResult = @mssql_fetch_field($this->_queryID, $fieldOffset); } // The $fieldOffset argument is not provided thus its -1 else if ($fieldOffset == -1) { $this->_tempResult = @mssql_fetch_field($this->_queryID); } return $this->_tempResult; } // Returns: true if there still rows available, or false // if there are no more rows. Moves to the next row in a // specified Recordset object and makes that record the current // row and the data corresponding to the row will be retrieved // into the fields collection. Note: Unlike the moveRow() method, // when _currentRow is getNumOfRows() - 1, EOF will immediately be // true. If row number is not provided, the function will point // to the first row automatically function nextRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow++; $this->fields = @mssql_fetch_array($this->_queryID); // This is not working. True all the time if ($this->fields) { $this->_checkAndChangeEOF($this->_currentRow - 1); return true; } } $this->EOF = true; return false; } // Returns: true on success, false on failure moveRow() // moves the internal row pointer of the Recordset object // to point to the specified row number and the data // corresponding to the row will be retrieved into the fields // collection. If row number is not provided, the function will // point to the first row automatically function moveRow($rowNumber = 0) { if ($rowNumber == 0) { return $this->firstRow(); } else if ($rowNumber == ($this->getNumOfRows() - 1)) { return $this->lastRow(); } if ($this->getNumOfRows() > 0 && $rowNumber < $this->getNumOfRows()) { $this->fields = null; $this->_currentRow = $rowNumber; if(@mssql_data_seek($this->_queryID, $this->_currentRow)) { $this->fields = @mssql_fetch_array($this->_queryID); /* This is not working. True all the time */ if ($this->fields) { // No need to call _checkAndChangeEOF() because // the possibility of moving to the last row has // been handled by the above code $this->EOF = false; return true; } } } $this->EOF = true; return false; } // Returns: true on success, false on failure firstRow() moves // the internal row pointer of the Recordset object to the first // row and the data corresponding to the row will be retrieved // into the fields collection function firstRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow = 0; if (@mssql_data_seek($this->_queryID, $this->_currentRow)) { $this->fields = @mssql_fetch_array($this->_queryID); $this->EOF = false; /* This is not working. True all the time */ if ($this->fields) { return true; } } } $this->EOF = true; return false; } // Returns: true on success, false on failure lastRow() moves // the internal row pointer of the Recordset object to the last // row and the data corresponding to the row will be retrieved // into the fields collection function lastRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $num_of_rows = $this->getNumOfRows(); $this->_tempResult = @mssql_data_seek($this->_queryID, --$num_of_rows); if ($this->_tempResult) { /* $num_of_rows decemented at above */ $this->_currentRow = $num_of_rows; $this->fields = @mssql_fetch_array($this->_queryID); /* This is not working. True all the time */ if ($this->fields) { /* Special case for making EOF false. */ $this->EOF = false; return true; } } } $this->EOF = true; return false; } // close() only needs to be called if you are worried about using // too much memory while your script is running. All associated // result memory for the specified result identifier will // automatically be freed function close() { $this->_tempResult = @mssql_free_result($this->_queryID); return $this->_tempResult; } // Returns: the number of rows in a result set. Get // number of rows in result function getNumOfRows() { return $this->_numOfRows; } /* Returns: the number of fields in a result set. Get number of fields in result. */ function getNumOfFields() { return $this->_numOfFields; } /* Check and change the status of EOF. */ function _checkAndChangeEOF($currentRow) { if ($currentRow >= ($this->_numOfRows - 1)) { $this->EOF = true; } else { $this->EOF = false; } } } ?> ______________________________________________________________________ 18. 부록 H Sybase SQL Server DB Wrapper 예제 제출자 : Joe Thong darkjoe@softhome.net Site URL: 설명: 여러가지 데이터베이스 서버에서 결과 조작을 위한 강력한 PHP 데이타베이스 랩퍼. 데이터베이스의 결과가 phpDB에 의해 자동으로 나오게 된다. 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 phpDB- sybase.lib 라고 입력하시오. ______________________________________________________________________ databaseType = $dbType; break; default: return false; } } // Returns: A positive link identifier on success, or // false on error. Connect to the server with the // provided arguments. The connection to the server will be // closed when the script terminates, unless close() // function is called beforehand function connect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $boolDBSelected; if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $this->_connectionID = @sybase_connect($this->hostname, $this->username, $this->password); if ($this->databaseName && $this->_connectionID) { $boolDBSelected = @sybase_select_db($this->databaseName); /* If DB selection fails */ if(!$boolDBSelected) { /* Close the current connection */ @sybase_close($this->_connectionID); return false; } } return $this->_connectionID; } // Returns: A positive link identifier on success, or false // on error. Connect to the server with the provided // arguments. The connection to the server will not be closed // when the script terminates. Instead it will be kept for later future use function pconnect($argHostname = "", $argUsername = "", $argPassword = "", $argDatabaseName = "") { $boolDBSelected; if ($argHostname != "") { $this->hostname = $argHostname; } if ($argUsername != "") { $this->username = $argUsername; } if ($argPassword != "") { $this->password = $argPassword; } if ($argDatabaseName != "") { $this->databaseName = $argDatabaseName; } $this->_connectionID = @sybase_pconnect($this->hostname, $this->username, $this->password); if ($this->_connectionID) { $this->_isPersistentConnection = true; } if ($this->databaseName && $this->_connectionID) { $boolDBSelected = @sybase_select_db($this->databaseName); /* if DB selection fails */ if(!$boolDBSelected) { /* Persistent connection can't be closed */ return false; } } return $this->_connectionID; } /* Returns: true on success, false on error Select the database name to be used */ function selectDB($dbName) { $this->databaseName = $dbName; if ($this->_connectionID) { return @sybase_select_db($dbName); } else { /* No database selected */ return false; } } /* Returns: the Recordset object disregard success or failure Send the sql statement to the database server. */ function execute($sql = "") { $this->_queryID = @sybase_query($sql, $this->_connectionID); // Instantiate an object without considering whether // the query return any results or not $this->_tempResultObj = new Recordset($this->_queryID); $this->_insertQuery($this->_queryID); return $this->_tempResultObj; } /* Returns: the last error message from previous database operation Note: This function is NOT available for Sybase. */ function errorMsg() { $this->_errorMsg = "errorMsg() is not available for Sybase"; return $this->_errorMsg; } /* Returns: true on success, false on failure Close the database connection. */ function close() { if ($this->_queryIDList && sizeof($this->_queryIDList > 0)) { while(list($_key, $_resultID) = each($this->_queryIDList)) { @sybase_free_result($_resultID); } } // If its not a persistent connection, then // only the connection needs to be closed if ($this->_isPersistentConnection != true) { return @sybase_close($this->_connectionID); } else { return true; } } // A PRIVATE function used by the constructor function // of the query object. insert the successful returned // query id to the query id list. Used for later results // cleanup. A private function that's never meant // to be used directly function _insertQuery($query_id) { $this->_queryIDList[] = $query_id; } } //---------------------------------- Class Name: Recordset //---------------------------------- class Recordset { /* public variables */ var $fields; // indicates that the current record position is // before the first record in a Recordset object var $BOF = null; // indicates that the current record position // is after the last record in a Recordset object var $EOF = null; // Private variables - starts with underscore var $_numOfRows = -1; // NEVER change the value! READ-ONLY! var $_numOfFields = -1; // NEVER change the value! READ-ONLY! // Holds anything that was returned from // the database specific functions var $_tempResult = ''; // This variable keeps the result link identifier var $_queryID = -1; // This variable keeps the current row in the Recordset var $_currentRow = -1; // Returns: query id on success and false if // failed Constructor function function Recordset($queryID) { $this->_queryID = $queryID; if ($queryID) { $this->_numOfRows = @sybase_num_rows($this->_queryID); $this->_numOfFields = @sybase_num_fields($this->_queryID); } else { $this->_numOfRows = 0; $this->_numOfFields = 0; } /* If result set contains rows */ if ($this->_numOfRows > 0 && $this->_currentRow == -1) { $this->_currentRow = 0; $this->fields = @sybase_fetch_array($this->_queryID); $this->EOF = false; $this->BOF = false; } return $this->_queryID; } // Returns: true if successful, false if fail Set // the Recordset pointer to a specified field offset. // If the next call to fetchField() won't include a // field offset, this field would be returned function fieldSeek($fieldOffset = -1) { $this->_tempResult = @sybase_field_seek($this->_queryID, $fieldOffset); return $this->_tempResult; } // Returns: an object containing field information. // Get column information in the Recordset object. // fetchField() can be used in order to obtain information // about fields in a certain query result. If the field // offset isn't specified, the next field that wasn't yet // retrieved by fetchField() is retrieved function fetchField($fieldOffset = -1) { if ($fieldOffset != -1) { $this->_tempResult = @sybase_fetch_field($this->_queryID, $fieldOffset); } /* The $fieldOffset argument is not provided thus its -1 */ else if ($fieldOffset == -1) { $this->_tempResult = @sybase_fetch_field($this->_queryID); } return $this->_tempResult; } // Returns: true if there still rows available, or // false if there are no more rows. Moves to the next // row in a specified Recordset object and makes that record // the current row and the data corresponding to the row will // be retrieved into the fields collection. Note: Unlike // the moveRow() method, when _currentRow is getNumOfRows() - 1, // EOF will immediately be true. If row number is not // provided, the function will point to the // first row automatically function nextRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow++; $this->fields = @sybase_fetch_array($this->_queryID); /* This is not working. True all the time */ if ($this->fields) { $this->_checkAndChangeEOF($this->_currentRow - 1); return true; } } $this->EOF = true; return false; } // Returns: true on success, false on failure moveRow() // moves the internal row pointer of the Recordset object // to point to the specified row number and the data // corresponding to the row will be retrieved into the // fields collection. If row number is not provided, the // function will point to the first row automatically function moveRow($rowNumber = 0) { if ($rowNumber == 0) { return $this->firstRow(); } else if ($rowNumber == ($this->getNumOfRows() - 1)) { return $this->lastRow(); } if ($this->getNumOfRows() > 0 && $rowNumber < $this->getNumOfRows()) { $this->fields = null; $this->_currentRow = $rowNumber; if(@sybase_data_seek($this->_queryID, $this->_currentRow)) { $this->fields = @sybase_fetch_array($this->_queryID); /* This is not working. True all the time */ if ($this->fields) { // No need to call _checkAndChangeEOF() // because the possibility of moving to the // last row has been handled by the above code $this->EOF = false; return true; } } } $this->EOF = true; return false; } // Returns: true on success, false on failure firstRow() // moves the internal row pointer of the Recordset object // to the first row and the data corresponding to the row // will be retrieved into the fields collection function firstRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $this->_currentRow = 0; if (@sybase_data_seek($this->_queryID, $this->_currentRow)) { $this->fields = @sybase_fetch_array($this->_queryID); $this->EOF = false; /* This is not working. True all the time */ if ($this->fields) { return true; } } } $this->EOF = true; return false; } // Returns: true on success, false on failure lastRow() // moves the internal row pointer of the Recordset object // to the last row and the data corresponding to the row // will be retrieved into the fields collection function lastRow() { if ($this->getNumOfRows() > 0) { $this->fields = array(); $num_of_rows = $this->getNumOfRows(); $this->_tempResult = @sybase_data_seek($this->_queryID, --$num_of_rows); if ($this->_tempResult) { /* $num_of_rows decemented at above */ $this->_currentRow = $num_of_rows; $this->fields = @sybase_fetch_array($this->_queryID); /* This is not working. True all the time */ if ($this->fields) { /* Special case for making EOF false. */ $this->EOF = false; return true; } } } $this->EOF = true; return false; } // close() only needs to be called if you are worried // about using too much memory while your script is // running. All associated result memory for the // specified result identifier will automatically be freed function close() { $this->_tempResult = @sybase_free_result($this->_queryID); return $this->_tempResult; } /* Returns: the number of rows in a result set. Get number of rows in result. */ function getNumOfRows() { return $this->_numOfRows; } /* Returns: the number of fields in a result set. Get number of fields in result. */ function getNumOfFields() { return $this->_numOfFields; } /* Check and change the status of EOF. */ function _checkAndChangeEOF($currentRow) { if ($currentRow >= ($this->_numOfRows - 1)) { $this->EOF = true; } else { $this->EOF = false; } } } ?> ______________________________________________________________________ 19. 부록 I phpDB.inc 예제 제출자 : Joe Thong darkjoe@softhome.net Site URL: Description: 여러가지 데이터베이스 서버에서 결과 조작을 위한 강력한 PHP 데이타베이스 랩퍼. 데이터베이스의 결과가 phpDB에 의해 자동으로 나오게 된다. 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 phpDB.inc 라고 입력하시오. ______________________________________________________________________ ______________________________________________________________________ 20. 부록 J phpDBTest.php3 예제 제출자 : Joe Thong darkjoe@softhome.net Site URL: 설명: 여러가지 데이터베이스 서버에서 결과 조작을 위한 강력한 PHP 데이타베이스 랩퍼. 데이터베이스의 결과가 phpDB에 의해 자동으로 나오게 된다. 이화일을 얻으려면 웹브라우져에서 '다른이름으로 저장'을 누르고 phpDB- mssql.lib 라고 입력하시오.(역주: phpDB-mssql.lib 가 아니고. phpDBTest.php3 라고해야합니다.) ______________________________________________________________________ < head> < title>Untitled< /title> < /head> < body> pconnect("hostName", "userName", "passWord", "databaseName") or die ("Can't connect to database server or select database"); $rs = $db->execute("SELECT * FROM Items"); $numOfRows = $rs->getNumOfRows(); echo "Number of Rows: $numOfRows"; $rs->firstRow(); // 선택사항이나, 추천합니다. while (!$rs->EOF) { // Fields collection accessible as associative arrays too echo "
" . $rs->fields[0]; $rs->nextRow(); // NOTE: nextRow() is placed at below } $rs->close(); $db->close(); // 선택사항 ?> < /body> < /html> ______________________________________________________________________