레이블이 PHP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 PHP인 게시물을 표시합니다. 모든 게시물 표시

2008년 7월 29일 화요일

Tidy

php에서 html을 파싱하여 특정 node의 innerHTML을 얻어내는 프로그램을 작성하려고 했습니다. 올빼미 님의 도움으로 Tidy라는 라이브러리를 알게되었는데요. 설치(윈도우, 한글 메뉴얼) 후

tidy_node->get_nodes(TIDY_TAG_DIV)

를 호출하자 다음과 같은 에러가 발생하더군요.

Fatal error: Call to undefined method tidyNode::get_nodes()

해결 방법은 못찾았습니다. -_-;;;;;; (Tidy의 php 5.1.2 버전의 dll에서는 발생하는 것 같습니다. 다른 버전은 모르겠구요.)

야근 내내 삽질(OTL)만했군요.

2008년 4월 23일 수요일

php, ImageMagick이 설치되어 있을 때, bmp를 gif로 바꾸기[허접;;]

php와 ImageMagick이 설치되어 있는 환경에서 bmp를 gif로 바꾸는 프로그램을 짜보았습니다. 쉽게 변환해주는 툴이 있을까해서 찾아봤는데 잘 안보여서요. 프로그램의 동작은 간단합니다.
  1. 이미지 파일들이 위치한 디렉토리의 파일들을 읽어옵니다.
  2. .bmp 파일이 있는 경우
  3. 해당하는 파일의 이름에 확장자를 바꾼 gif 파일을 만들어 준 다음에
  4. ImageMagick의 convert 명령어를 사용하여 file.bmp를 file.gif로 변경해줍니다.
// bmp 파일이 위치할 디렉토리입니다. 
$dir = "C:/workspace/resource/";
$fileList = scandir($dir) or die("scandir failed");

foreach ($fileList as $file) {
  	$index = strpos($file, '.bmp');
  	if ( $index !== false ) {
  		$fileName = substr($file, 0, strpos($file, '.'));
  		$cmd = 'convert '.$dir.$file.' '.$dir.$fileName.'.gif'; 

  		exec($cmd, $rtnarr, $rtnval);	
  		if($rtnval) {
			echo $cmd." - ".$rtnval."\n";
  		}
  	}
}
그냥 심심해서(?) 짜봤습니다. ^^;;; 짜다보니 얻은 교훈 exec 실행할 때 전체 경로를 포함하지 않으니 실행이 안되네요. ~~

2008년 2월 26일 화요일

PDT 간단한 정리;;;

  1. PDT란?
이클립스 플랫폼에서 PHP를 개발하기 위한 프레임워크입니다.
PHP Integrated Development Tool
  2. PDT 설치하기
이클립스 설치는 기본적으로 다 되어 있다고 가정하겠습니다.

  a. Update 기능을 사용하는 방법
Help > Software Updates > Find and Install을 누른다음에 나오는 창에서 Search for new features to install을 선택하고 Next를 누릅니다. 여기에서 New Remote Site를 누른 다음에 나오는 창에서 Name과 URL(URL은 pdt 업데이트 주소를 넣어줍니다.)을 입력하고 Finish를 누르면 자동으로 업데이트가 됩니다.

사용자 삽입 이미지


  b. 코드를 다운받아서 설치하는 방법
PDT project downloads에서 PDT를 다운로드 받으신 다음에 압축을 풀고 eclipse 폴더에 PDT의 내용을 복사해서 넣으시면 됩니다.

  3. PHP Project & PHP 파일만들기
PDT의 모든 기능을 사용하기 위해서는 PHP Project를 먼저 생성해야합니다.
메뉴에서 'File > New > PHP Project'를 선택하거나 PHP Explorer에서 마우스 오른쪽 버튼을 누르고 'New > PHP Project'를 누르셔도 됩니다. 그 다음에 나오는 창에서 프로젝트 명을 넣고 Finish를 누르면 PHP 프로젝트가 생성이 됩니다.
사용자 삽입 이미지

동일한 Project이름이 사용된 경우에는 그림과 같이 에러가 발생합니다.


PHP파일 만들기도 PHP Project 만드는 것과 비슷합니다. 'File > New > PHP' Project 또는 PHP Explorer에서 'New > PHP File'을 선택해도 됩니다. 먼저 파일명을 입력합니다.
사용자 삽입 이미지사용자 삽입 이미지

입력한 다음에 Finish를 누르는 경우에는 단순한 PHP파일이 생성되구요. Finish를 누르지 않고 Next로 이동하게 되면, PHP Template을 선택할 수도 있습니다.

  4. Code Assist
PDT에서는 코드 생성을 쉽게하기 위해서 여러가지 도움 기능을 제공하고 있습니다. 이런 도움 기능(말)들이 어떠한 역할을 하는지(function인지, class인지 등을 알리는)를 나타내기 위해서 아이콘을 사용하고 있습니다.
사용자 삽입 이미지
이러한 아이콘들은 Outline view에서나 입력창에서 보실 수 있습니다.

사용자 삽입 이미지

Outline view에서 본


PHP 파일 입력창에서 나온 도움말. 입력하는 도중 또는 Ctrl +Space를 누르는 경우에 나옵니다. Ctrl +Space는 JDT나 RDT, WTP등에서도 공통으로 code assist 기능이 동작하도록 하는 단축키입니다.  (윈도우의 경우이며, 리눅스나 맥의 경우 단축키가 다릅니다.)

사용자 삽입 이미지

코드 입력이 완료되었는데 코드에 대한 도움말을 보고 싶으시면 마우스를 해당 위치에 갖다 대면 보이게 됩니다. 도움말 창을 고정시키길 원하시면 이 때 F2를 누르시면 됩니다.

사용자 삽입 이미지

중괄호 {}를 사용해서 function이나 class를 정의하게 되는데요. 중괄호의 시작부분({)이나 끝부분(})에 마우스를 갖다대면 한 쌍을 이루는 반대 쪽에 내가 끝이다를 의미하는 표시가 나오게 됩니다.

사용자 삽입 이미지

위의 그림에서는 5번째 줄에 커서가 있었구요. 2번 째 줄에 사각형의 표시가 있는 것을 보실 수 있습니다. 이 둘의 중괄호를 이동하기 위해서는 Ctrl+Shift+P를 누르면 됩니다.

코드의 의미를 구분하기 위해서 위와 같이 색상을 따로 정해주고 있는데요. 각 색의 의미는 다음과 같습니다.
사용자 삽입 이미지
위의 값은 디폴트이기 때문에 Window > Preferences > PHP > Editor > Syntax Coloring에서 수정이 가능합니다.
사용자 삽입 이미지

주석의 경우에도 //와 /* */ 모두 지원하고 있습니다. 주석을 쉽게 달기 위해서는 Ctrl +/를 누르시면 주석을 달아주구요. 이미 달려있는 경우에 다시 Ctrl+/를 누르시면 주석이 삭제됩니다.

  5. 에러 찾기
PDT에서는 실시간으로 에러를 잡아주는 기능이 있습니다. 코드를 입력하다 입력한 문구에 에러가 발생하면 다음과 같이 x자 모양의 에러를 표시해줍니다.

사용자 삽입 이미지

에러 마크위에 마우스를 갖다 대면 어떠한 에러가 났는지를 표시해 주기도 합니다.

또다른 방법으로는, Problems 뷰를 사용하는 방법인데요. Window > Show View > Others > General > Problems를 클릭해서 창을 띄울 수도 있습니다.

사용자 삽입 이미지

에러가 발생한 경우에는 에러를 모두 보여주구요. 리소스/경로/발생한 위치를 보여줍니다. 에러 위에서 마우스 오른쪽 클릭하면 해당하는 에러로 이동하거나 에러 내용을 보거나 복사할 수 있는 등의 기능을 제공합니다.

※ 해야할 일의 경우 @todo 또는 //주석 뒤에 TODO를 입력해주면 Tasks창에서 해당 내용을 쉽게 찾아 볼 수 있습니다.

 6. 디버깅하기
디버깅하기 위해서는 먼저, 디버깅할 줄의 옆(에디터 옆의 marker bar)을 더블클릭합니다. 더블클릭하는 경우 파란색 아이콘이 나오며 (breakpoint가 설정되며) 다시 이 아이콘을 더블클릭하면 해제가 됩니다.
사용자 삽입 이미지

벌래모양의 아이콘의 옆 삼각형을 클릭한 후 Open Debug Dialog를 클릭합니다. (벌래를 클릭하면 최근에 디버깅한 명령이 재실행됩니다.)

사용자 삽입 이미지

PHPScript > New를 클릭하면 로컬에 설치된 PHP 실행파일을 설정하라고 나오게 됩니다. 미리 설정되어 있는 경우는 상관이 없습니다. 이름/경로/php.ini파일 등을 설정해주고 Finish를 누릅니다. PHP 설정이 완료되면 아래와 같이 Debug 창이 나오게 됩니다.

사용자 삽입 이미지

여기에서 PHP File에 디버깅할 파일을 설정해주고 Debug를 누르게 되면, Debug Perspective로 바꿀지를 묻습니다. 선택을하게 되면 다음의 Perspective로 변경이 됩니다.

사용자 삽입 이미지

※ Xdebug 설치는 매우 쉽습니다. (Window의 경우구요.) Xdebug Download 페이지에서 자신의 로컬에 설치된 PHP 버전에 맞는 Xdebug를 받은 다음에 받은 파일을 적당한 곳에 놓고 php.ini 파일에 다운 받은 파일의 위치를 추가시켜주면 됩니다.
zend_extension_ts="c:/php/modules/php_xdebug-4.4.1-2.0.2.dll"
※※ 서버에 설치하는 것은 시간상 못해봤습니다. ^^;;; 자세한 Xdebug상요법은 검색하시면 많이 나와요

2008년 2월 13일 수요일

phpDocumentor

사용자 삽입 이미지
  개요
phpDocumentor(phpDoc)은 Java Documentor 처럼 PHP코드를 "문서화시키는 도구"입니다. php 코드의 주석에 들어있는 여러 태그들을 파싱하여 API 문서를 생성해주는 역할을 합니다.
(개인적으로는 주석없이 코드에 의도를 포함시키는 것을 더 선호 합니다;;;)

좋은 코드의 문서화를 하기 위해서는 사용자의 요구를 맞추는 게 중요합니다.
일반적인 소프트웨어 프로젝트를 바라보는 사용자들은 크게 두 분류로 나눌 수 있습니다.
  • 하나는, 오픈소스를 사용하는 사람들로 내부의 코드가 어떻게 돌아가기보다는 인터페이스만을 알기를 원하는 사람들입니다.
  • 또 다른 하나는, 오픈소스를 개발하는 사람들로 객체들이 어떻게 구성되어 있으며 어떻게 동작하는지를 확인하고 어떻게 확장할 지를 생각하는 사람들입니다.
각 사용자들의 요구에 맞추기 위해서 phpDoc은 html/chm/pdf 출력 포멧과 대상에 따른 출력 범위를 지정할 수 있습니다.
 
 특징
각 사용자들의 요구에 맞추기 위해서 phpDoc은 html/chm/pdf 출력 포멧과 대상에 따른 출력 범위를 지정할 수 있습니다.
  • HTML, PDF, CHM, XML DocBook 생성
  • 웹/커멘드 라인으로 실행가능
  • 다양한 템플릿 기능 제공
  • JavaDoc 포멧 뿐만 아니라 php를 위해 커스터마이징한 태그도 제공
  • 자동 링크 생성기능과 클래스 상속 다이어그램과 오버라이드 명시
  • README/CHANGELOG/INSTALL/FAQ 파일들을 파싱하여 문서안에 포함가능
  • @TODO 태그를 사용하여 문서안에 TODO리스트를 생성
  • @access, @internal 태그 사용 => 다중 문서 작성 가능
  • Phpxref와 @example을 사용문서 안에 예제 파일 삽입가능
  • 컨버터/usr.ini 사용 아웃풋 컨트롤 등
더 자세한 특징들은 tutorial을 참고해주세요.

 phpDocumentor 사용하기
기본적인 순서는 다음과 같습니다.
  1. php 코드에 phpDoc으로 출력하기 위한 내용들을 주석에 작성을 합니다.
  2. phpDoc을 생성하기 위한 입/출력 폴더를 지정합니다.
  3. 프로그램을 시작하면, php파일을 컴파일 하면서
  4. php 소스안에 정의되어 있는 tag들을 파싱하여서 문서로 생성합니다.
실행하는 방법에는 두 가지가 있습니다. 웹에서 실행하는 방법과 커맨드 상에서 phpdoc을 실행시키는 방법 두가지가 있습니다. (먼저, php가 설치되어 있어야하구요. 웹에서 실행하려면 apache가 설치되어 있어야 합니다.)

커맨드 상(윈도우 기준)에서 실행하려면 다음과 같이 명령어를 입력하면 됩니다.
C:\> phpdoc -o HTML:frames:earthli -f sample1.php -t docs
여기서 -o는 '출력 포멧'을 지정하며 -f는 '문서 생성 대상인 php 코드'명 -t는 '저장할 대상 폴더'를 지정합니다. 만약, 도움말이 필요하시다면 -h 또는 -help 옵션을 사용하면 상세하게 보실 수 있습니다.
C:\> php.exe phpdoc -h
C:\> php.exe phpdoc -help

웹상에서 실행하려면 phpdoc이 설치 된 폴더의 index.html을 브라우져로 엽니다.
사용자 삽입 이미지
상위의 메뉴를 보면 Config, Files, Output, Options, Credits, Links가 보이는데요. 각각은 phpDoc의 설정과 변환할 파일 경로 설정, 출력물 설정, 옵션 설정, 만든 사람들, 관련 링크가 들어있습니다.

실행을 하기 위해서는 다음과 같이 Files 옵션에서 변환할 코드의 경로를 입력합니다.
사용자 삽입 이미지
출력할 포멧 설정과 경로를 설정한 다음에 아래 쪽의 Create 버튼을 누르면 설정한 포멧 별로 html/pdf/chm(실제로는 chm 형태에 맞춰진 html이 생성)이 생성이 됩니다.

사용자 삽입 이미지

 주의할 점
phpDoc을 사용하여 문서를 작성할 때 주의하여야할 점들이 몇 가지 있습니다.
  1. 기본 charset이 iso-8859-1로 설정되어 있어서 utf-8로 작성된 소스코드의 주석이 깨지는 문제가 있습니다. *.tpl 파일 들을 검색해서 utf-8로 변경해줘야 합니다. (phpDocumentor/Converters 아래의 파일들이 변환에 사용되는 템플릿 들입니다.)
  2. 주석을 사용할 때 /* 로 시작되는 주석들은 문서로 생성이 되지 않습니다. /** 로 시작되어야지만 문서에 포함이 됩니다.
  3. class에 속하는 주석은 class 바로 윗 줄에 작성되어져야 합니다. 떨어져 있는 경우 (주석과 class 키워드 사이에 다른 코드가 들어있는 경우) 해당하는 주석으로 처리되지 않고 생략이 됩니다.
    /**
     * 주석
     */
    class Test ...
  4. 코드를 설명하는 글을 먼저 작성하고 태그가 나와야 합니다.
    /**
     * 이 코드는 어떤 코드입니다. Blah Blah~
     * @var string ...
     */
  5. todo의 경우, @todo로 태그를 작성해야하며 class,function,var의 주석안에 포함되어야지만 보여집니다. 수정해야 될 코드에 @todo를 입력하는 경우 처리되지 않습니다.
  6. php 코드 선언 부가 <? ?> 가 아닌 <?php ?>로 모두 선언되어야 합니다. 경우에 따라서는 안나오는 경우도 있네요.
관련 링크

2008년 2월 3일 일요일

PHP 파일처리

파일과 관련된 PHP 함수 정리
1. file_exists []
파일을 옮기거나, 복사하거나 파일의 내용을 읽을 때, 파일이 존재하는 지 여부를 체크하는 함수
bool file_exists ( string $filename )
$filename은 파일의 경로와 이름을 인자로 받으며, $filename이 유효한지 여부를 리턴합니다.

2. file Information를 얻고 싶을 때
  • array stat ( string $filename ) [] - 파일의 통계정보를 리턴
  • string filetype ( string $filename ) [] - 파일타입을 리턴합니다. 리턴되는 타입은 fifo, char, dir, block, link, file, socket and unknown 이 리턴됩니다.
  • int filesize ( string $filename ) [] - 파일크기를 리턴합니다.
  • bool is_readable ( string $filename ) [] - 인자로 받은 파일을 읽을 수 있는 지 여부를 리턴합니다.
  • bool is_writable ( string $filename ) [] - 인자로 받는 $filename이 존재하고 쓸 수 있는 경우에 true를 리턴합니다.
  • bool is_executable ( string $filename ) [] - 파일이 실행될 수 있는 지 여부를 리턴합니다.
3. Reading Files, 파일을 읽고 싶을 때
<?php
  $filename = "sample.txt";
  $fileArr = file($filename);
  // or
  $fileStr = file_get_contents($filename);
?>
  • array file ( string $filename [, int $flags [, resource $context ]] ) [] - 전체 파일의 내용을 배열형태로 리턴합니다.
  • string file_get_contents ( string $filename [, int $flags [, resource $context [, int $offset [, int $maxlen ]]]] ) [] - 전체 파일의 내용을 string으로 리턴합니다.
file_get_contents()가 없는 오래된 PHP에서는 fread를 사용하여서 파일을 읽을 수 있습니다.
<?php
  $filename = "sample.txt"
  $fp = fopen($filename, "rb") or die("fopen failed");
  // 전체 파일을 읽을 때
  $fileStr = fread($fp, filesize($filename));

  // 또는 네트웤을 통해서 파일을 단위별로 읽어들일 때
  while(!feof($fp)) {
    $fileStr .= fgets($fp, 1024);
  }
  fclose($fp) or die("fclose failed");
?>
  • resource fopen ( string $filename , string $mode [, bool $use_include_path [, resource $context ]] ) [] - 파일을 열고 파일 스트림을 리턴합니다.
  • string fread ( resource $handle , int $length ) [] - 인자로 받은 $handle 파일의 내용을 $length만 큼 읽어들입니다.
  • bool fclose ( resource $handle ) [] - 인자로 받은 파일 포인터(스트림)를 닫습니다.
  • bool feof ( resource $handle ) [] - 파일 포인터가 eof(end of file)인 지를 체크합니다.
  • string fgets ( resource $handle [, int $length ] ) [] - 파일포인터로부터 특정 길이만큼 파일의 내용을 읽어들입니다.
4. Writing Files, 파일 쓰기
<?php
  $data = "file Data...";
  file_put_contents('sample.txt', $data) or die("file_put_contents failed");
?>
  • int file_put_contents ( string $filename , mixed $data [, int $flags [, resource $context ]] ) [] - 파일 이름과 파일이 데이타를 인자로 받아서 파일에 데이타를 쓰는 함수입니다. 세 번째 인자로 FILE_APPEND 플래그를 사용하면, 데이타를 덮어쓰는게 아니라 덧붙여 써넣을 수 있습니다.
file_get_contents()와 fopen()처럼 fwirte()를 사용하여 파일을 쓸 수도 있습니다.
<?php
  $data = "file Data...";
  $fp = fopen("sample.txt", wb+) or die("fopen failed");
  if(flock($fp, LOCK_EX)) {
    fwrite($fp, $data) or die("fwrite failed");
    flock($fp, LOCK_UN);
  }
  fclose($fp) or die("fclose failed");
?>
  • int fwrite ( resource $handle , string $string [, int $length ] ) [] - 파일 스트림과 파일에 쓸 데이타를 인자로 받아서 파일에 데이타를 씁니다. 세 번째 인자가 주어진 경우 주어진 길이까지만 파일이 써지게 됩니다.
  • bool flock ( resource $handle , int $operation [, int &$wouldblock ] ) [] - 파일의 스트림과 $operation을 인자로 받아서 파일 락을 설정합니다. LOCK_EX(exclusive lock), LOCK_SH(shared lock), LOCK_UN(unlock), LOCK_NB를 설정할 수 있습니다.

    파일을 쓸 때 다른 프로그램이 동시에 하나의 파일에 엑세스해서 파일이 헝클어지는 것을 방지하기 위해서 lock을 설정합니다. php에서의 lock만 해당하며 php 외의 다른 프로그램에서 접근하는 것까지 lock을 걸지는 못합니다.
5. Removing file lines. 파일의 라인을 삭제하기
<?php
  $filename = "sample.txt";
  //file을 읽어들여서 배열형태로 $data를 읽어들입니다.
  $data = file($filename) or die("file failed"); 
  // 배열의 세 번째 라인을 삭제합니다.
  unset($data[2]); 
  // 배열을 인덱스를 새로 생성합니다.
  $data = array_values($data);
  file_put_contents($filename, implode($data)) or die("fipe_put_contents failed");
?>
  • void unset ( mixed $var [, mixed $var [, mixed $... ]] ) [] - 값을 삭제하는 함수로 인자의 타입에 따라서 다르게 동작합니다.
  • array array_values ( array $input ) [] - 입력 배열의 모든 값을 숫자 키값과 함께 리턴합니다.
6. Processing Directories 디렉토리 다루기
<?php
  $dir = "./sample";
  // 디렉토리에 들어있는 파일/디렉토리들을 배열형태로 리턴합니다.
  $fileList = scandir($dir) or die("scandir failed");
  // 배열을 루프로 돌면서 디렉토리에 들어있는 파일들에 작업을 수행합니다.
  foreach ($fileList as $file) {
    // 실제 파일인지 여부를 체크합니다.
    if( is_file("$dir/$file") && $file != '.' && $file != '..') {
      //...
    }
  }
?>
  • array scandir ( string $directory [, int $sorting_order [, resource $context ]] ) [] - 디렉토리안에 있는 파일과 디렉토리를 배열로 리턴합니다.
<?php
  $dir = "./sample";
  // DirectoryIterator를 생성합니다.
  $iterator = new DirectoryIterator($dir);
  // 내부의 iterator를 첫 element로 이동시킵니다.
  $iterator->rewind();
  // current element가 있는 지 여부를 확인한 후
  while($iterator->vaild()) {
    // 디렉토리가 아닌 실제 파일인지를 확인한 후 실제 작업을 수행합니다.
    if($iterator->isFile() && !$iterator->isDot()) {
      // ...
    }
    // 다음 element로 iterator를 넘깁니다.
    $iterator->next();
  }
?>
DirectoryIterator($path)는 $path를 인자로 받아서 생성하며 디렉토리의 파일/디렉토리를 이동하며 파일정보를 확인하거나 작업을 할 수 있는 클래스입니다.

7. Renaming  Files and Directories 디렉토리 다루기
<?php
   $oldFileName = "oldName.txt";
   $newFileName = "newName.txt";

   // 파일이 있는 지 여부를 체크합니다.
   if(file_exists($oldFileName)) {
     // 대상 파일의 이름을 수정합니다.
     rename($oldFileName, $newFileName) or die("Renaming file is failed.");
   } else {
      die("Cannot find file '$oldFileName'");
   }
?>
rename()은 파일이름 변경 및 파일의 위치 이동을 동시에 실행할 수 있는 함수입니다. 인자는 변경할 원 파일의 이름과 변경 대상이 되는 파일 두 개를 인자로 받습니다.

관련자료: PHP Programming SOLUTIONS 6장 "Working with Files and Directories" 책 보면서 정리한 내용입니다.
PHP Programming SOLUTIONS 상세보기
Vaswani, Vikram 지음 | McGraw-Hill 펴냄
Provides SOLUTIONS, functional code, and usage tips on creating Web applications using PHP.


P.S>
1. mixed end ( array &$array ) [] - Array의 내부 포인터를 마지막 element로 이동시킵니다. end($arr)를 출력하면 Array의 마지막 값이 출력됩니다.
2. $arr[] = 4; // array에 index 없이 값을 할당하는 경우 array의 마지막 index로 값이 할당되네요.

2008년 1월 3일 목요일

Zend Studio for Eclipse 버전 설치 시 JVM terminated. Exit code=-1이 발생한다면?

강력한 PHP 툴인 Zend Studio for Eclipse를 사용해보려 하는데 계속 에러가 나더군요. 그래서 JVM 재설치도 해보고 (Zend Studio for Eclipse 패키지에 jre가 같이 배포됩니다.) 삭제 재설치도 몇 번 해봤는데 안되서 eclipse 옵션이 잘못되었나 수정을 해봤는데요.
사용자 삽입 이미지

ini 파일의 --launcher.XXMaxPermSize 256m(뒷 부분은 다른 줄에 있었습니다.) 의 뒷부분 256m를 같은 줄로 옮기니 Zend Studio for Eclipse 런칭이 가능하더군요. -_-;;;;;;;; 정확한 해결책은 아니지만 Zend.com 검색결과로는 해결책이 나오지는 않네요. 다른 컴퓨터에도 설치해봤는데 거기에선 정상적으로 바로 런칭이 가능했습니다.

2008년 1월 1일 화요일

htmlspecialchars()

PHP의 htmlspecialchars() 함수는 html에서 사용되면 안되는(html 태그로 인식되거나 html, js에서 문제가 될 수 있는 문자열)들을 변환해주는 함수입니다. (변환되는 항목은 php manual을 참고)
string htmlspecialchars ( string $string [, int $quote_style [, string $charset [, bool $double_encode ]]] )
첫 번째 인자는 변환할 문자열을 받구요.
두 번째 인자는 ' 또는 " (single quote 또는 double quote)를 어떻게 처리할 지에 대한 여부를 결정합니다.
  • ENT_COMPAT - " (double quote)만 변환합니다.
  • ENT_QUOTES - '와 "(single, double quote) 모두 변환합니다.
  • ENT_NOQUOTES - 아무것도 변환하지 않습니다. (quote에 대해서)
세 번째 인자는 변환 결과에 대한 charset이며
네 번째 인자는 인자로 받는 문자열에 html 태그가 있는 경우 이를 변환할 지 말지에 대한 flag를 받습니다.

htmlspecialchars()와 반대되는 함수인 htmlspecialchars_decode()도 있습니다. 역으로 변환했던 내용들을 다시 변환해줍니다. 첫 번째, 두 번째 인자는 htmlspecialchars()와 동일합니다.
string htmlspecialchars_decode ( string $string [, int $quote_style ] )
만약, 주어진 문자열이 htmlspecialchars()로 변환 되었을 수도 있고 아닐 수도 있는 경우에 정상적으로 페이지를 보여주려면 어떻게 해야할까요?

정답(?): htmlspecialchars_decode()를 호출해 준 다음에 다시 htmlspecialchars()를 호출해줍니다. (입력된 태그를 태그로 처리한다면 답은 아니겠죠;;;;;;;;)

관련자료

2007년 11월 14일 수요일

Apache의 Default Host

403 Forbidden You don't have permission to access
Apache 설치 후 http.conf 파일에 VirtualHost를 설정하여서 사용하고 있었는데 *.domain.com 주소가 동작을 하지 않더군요. 이것저것 다 설정해보고 동료 분의 http.conf와 비교도 해봤는데 원인을 찾지 못했었는데 방금 '올빼미'님의 도움으로 해결했습니다. 해결방법은...(Virtual Host에서 주소를 찾지 못할 때도 403이 발생하더군요)

'http.conf의 VirtualHost들이 정의되어 있는 리스트에서 디폴트 동작을하는 VirtualHost 정의는 맨 처음에 위치해야 한다'입니다. (As a consequence, the first listed virtual host is the default virtual host.)

   NameVirtualHost *

<VirtualHost *>
ServerName *.domain.tld
DocumentRoot /www/domain
</VirtualHost>

<VirtualHost *>
ServerName www.otherdomain.tld
DocumentRoot /www/otherdomain
</VirtualHost>
관련 링크 : Named-based Virtual Host Support

2007년 11월 5일 월요일

Apache/PHP 재설치할 때 발생한 문제들

여러가지 이유로 인하여 Apache와 PHP를 재설치하게 되었습니다. 이 과정에서 몇 가지 문제가 발생하였는데요.

1. Apache를 설치했을 때 이전과 달리 서비스에 등록이 되지 않더군요. '올빼미'님의 도움으로 확인해보니 서비스가 설치되지 않아서 발생한 문제라고 하더군요. 서비스 설치는 다음의 -k install을 사용하여 command 상에서 설치가 가능합니다.
Apache.exe -k install
2. 우여곡절 끝에 설치한 Apache에 PHP를 설치하다가 삽질을 또 하였습니다. php.net에서 Windows 버전의 인스톨러를 받아서 설치하는 경우 extension 설치 메시지가 나오는데요. 메시지에서 설치할 목록을 선택한 후 설치를 하였슴에도 불구하고 설치가 되지 않더군요. 그래서 5.0 버전대의 ext 버전을 사용했는데 버전이 달라서 에러가 나더군요.
사용자 삽입 이미지

버전 확인은 dll파일을 선택한 후 마우스 오른쪽 버튼을 눌러서 버전을 확인 할 수 있습니다.

3. 그리고, dll을 로딩하지 못한다는 메시지가 나온다면 php.ini의 include_path와 extension의 이름도 확인하는 것도 좋은 방법일 것 같습니다. (2에서 안되길래 모두 삭제한 후 5.0대 버전을 설치하였는데 php.ini를 5.2.4를 사용하니까 에러가 발생하더군요. 5.2.4에서는 php_http.dll이 php_http_5_2_3.dll로 이름이 바뀌어서 발생한 문제였습니다. -_-)

P.S. 정보공유 차원에서 올렸습니다. ^^;;;

2007년 10월 29일 월요일

escapeshellcmd

Description

string escapeshellcmd ( string $command )

escapeshellcmd()는 인자로 받는 $command가 실행되었을 때, 의도하지 않았던 shell 명령어를 실행하게하는 트릭을 방지하기위해서 트릭을 실행할 수 있는 특정 문자들을 제거하는 함수입니다. 이 함수는 사용자가 입력한 내용이 exec()system() 또는 backtick operator로 실행되기 전에 호출되어야하는 함수입니다.

호출이 되는 경우 다음의 문자들 앞에 backslash가 추가됩니다.

#&;`|*?~<>^()[]{}$\, \x0A and \xFF
'" 는 두 개가 쌍으로 사용되지 않은 경우에만 처리됩니다. 윈도우에서는 위의 문자들과 %가 공백으로 바뀝니다.

Parameters

command

금지된 문자들을 제거하기 위한 명령어를 인자로 받습니다.

Return Values

금지된 문자들이 제거된 명령어가 리턴됩니다.

2007년 9월 9일 일요일

Alternative syntax for control structures

PHP에는 Alternative syntax for control structures가 제공되고 있습니다. Alternative syntax란 Control Structure의 복잡한 표현을 쉽게 표현하는 방법입니다.
열리는 {를 :으로 표현하고 닫치는 }를 endif; endwhile; endfor; endforeach; endswitch; 로 표현할 수 있는 방법입니다.
그렇다면, 어떤 면에서 쉽게 표현해주는 것일까요? 다음의 코드를 먼저 보겠습니다.
<?php
if(isAdmin()) {
    echo "<div class=\"admin_link\">";
    echo "   <a href=\"form.php\" class=\"add_link\">Add Link</a>";
    echo "</div>";
}
?>
일반적인 php의 관점으로 짜여진 코드이지만, php 코드와 HTML마크업이 섞여서 HTML마크업의 관점으로 보기 힘든 면이 있습니다.
이를 Alternative syntax로 표현하면 다음과 같이됩니다.
<?php if(isAdmin()): ?>
  <div class="admin_link">
     <a href="form.php" class="add_link">Add Link</a>
  </div>
<?php endif; ?>
php의 대부분 제어로직을 클래스 또는 function으로 분리한 다음에 View에 해당하는 php 및 html 마크업 코드를 분리했을 때, Alternative syntax를 사용한다면 명확하게 어떤 HTML 코드를 사용했는 지, 또는 디자인 변경에 따른 HTML수정도 쉽게 가능하겠죠.


출처 :  SimpleTest  via Manning, PHP in Action - 11장

2007년 7월 29일 일요일

SimpleTest(Unit Testing for PHP)

SimpleTest는 PHP에서 사용할 수 있는 Unit Testing 툴로서 이클립스 플러그인으로 사용할 수 있습니다.

설치하는 방법
  1. SimpleTest에서 이클립스 플러그인을 다운로드 받습니다.
  2. 적당한 장소에 다운로드 받은 소스의 압축을 풉니다.
  3. 이클립스를 실행시킨 다음에 Help > Software Updates > Find and install을 실행합니다.
  4. Search for new features to install > New Local Site을 클릭해서 설치할 프로그램의 위치를 설정합니다.

    사용자 삽입 이미지

  5. Finish를 눌러서 설치를 합니다. (설치가 완료된 후에 이클립스가 재시작됩니다.)
  6. 재시작한 이클립스에서 Window > Preferences를 클릭해서 Preferences 다이얼로그를 띄웁니다.
  7. SimpleTest항목을 찾은 다음에 PHP.exe file의 위치와 php.ini 파일의 위치, 그리고 Test File Suffix를 설정해줍니다. (Suffix를 설정하면 플러그인이 테스트 파일을 찾는데 도움을 줍니다. - 저의 경우에는 .test.php로 설정하였습니다.)
    사용자 삽입 이미지

  8. OK를 눌러서 창을 닫습니다.
사용하는 방법
PHP파일을 생성한 후 UnitTestCase를 상속받은 테스트 클래스를 작성해주면 됩니다. 테스트할 메소드는 test로 시작하여야만 됩니다.
<?php
    class test1 extends UnitTestCase {
        function test_pass(){
            $x = 1;
            $y = 2;
            $total = $x + $y;
            // 기대하는 결과값인 3과 메소드의 수행결과인 $total을 비교하여 비교치가
             // 다른 경우 세 번째 argument를 test fail과 함께 출력하게 됩니다.
            $this->assertEqual(3,$total, "This should pass");
        }
    }
?>
작성한 파일을 실행하기는 간단합니다. Run > Open Run Dialog를 띄운 다음에 SimpleTest를 실행시켜주거나 실행할 파일을 설정한 후 실행시켜주면됩니다.
사용자 삽입 이미지

※ 테스트를 추가하는 방법도 간단합니다. UnitTestCase를 상속받은 클래스에서 test...()를 추가하거나 UnitTestCase를 상속받는 테스트 클래스를 추가한 후 GroupTest를 생성하여 테스트가 가능합니다.
<?php
    class myGroupTest extends GroupTest {
        function myGroupTest() {
            parent::GroupTest('');
            $this->addTestFile(dirname(__FILE__).'/test1.php');
            $this->addTestFile(dirname(__FILE__).'/test2.php');
        }
    }
?>
※※ setUp() 메소드와 tearDown() 메소드를 사용하여 테스트 클래스가 로딩하기 전에 실행되는 작업을 수행하고, 테스트 종료한 다음에 마무리 작업을 수행할 수 있습니다. (다른 단위 테스트와 동일합니다.)

※※※ Mockup 생성도 가능합니다. Mockup을 생성하는 목적은 내부와 외부를 연결해주는 게이트웨이에 해당하는 부분을 만들 때 사용합니다.
// mock_objects를 포함시킵니다.
require_once('simpletest/mock_objects.php');

// Mockup으로 만들 클래스 파일이 따로 있다면 require_once를 호출하여 포함시킵니다.
// 또는 클래스를 동일 테스트 파일에 선언해줍니다. (인터페이스만 선언해주면 됩니다.)
...
// Mock 클래스를 생성합니다.
Mock::generate('Sample');

// 이렇게 생성된 Mock 클래스는 Mock~으로 시작되는 이름의 클래스로 생성할 수 있습니다.
sample = new MockSample();

// 생성된 클래스의 메소드가 호출될 때의 동작을 정의하기 위해서 expect
// 또는 setReturnReference() 를 사용하여서 어떤 메소드가 호출될 때 어떤
// 리턴결과가 돌아올지에 대해서 정의가 가능합니다.
sample->expect(...);
출처 :  SimpleTest  via Manning, PHP in Action(Objects, Design, Agility)- 9,10장

※ SimpleTest의 API는 여기로 -> http://simpletest.org/api/

6. Object-oriented pinciples

1. The open-closed principle(OCP)
확장에는 열려있고, 수정에는 닫쳐있어야 한다.(open to extension, closed to modification)
// 수정전
function hello() {
   echo "Hello, Dolly!\n";
}

// 수정 후, 변경 가능한 요소인 이름을 인자로 받아 출력, 코드 수정없이 출력 범위를 확장함
function hello($name) {
   echo "Hello, ".$name."!";
}
2. The single-responsibility principle(SRP)
하나의 클래스에는 하나의 책임만을 져야한다. (변화 가능한 요소가 하나만 있어야 한다. -A class should have only one reason to change)

템플릿 엔진(Template engine)의 기본적인 특징은 다음과 같습니다.
  • 변수들의 집합을 저장할 수 있어야 합니다. (Storing a set of variables)
  • 템플릿 파일을 읽을 수 있어야 합니다. (Reading a template file)
  • 템플릿 파일과 변수 집합을 통하여 출력물을 생성할 수 있어야 합니다. (Combining the first two to generate output)
이러한 특징을 바탕으로 Template을 생성하면 다음과 같은 클래스를 만들 수 있을 것입니다.
class Template {
   private $vars;
   private $file;

   // 생성자에서 파일을 인자로 받아서 템플릿 파일에 사용될 파일을 저장합니다.
   public function __construct($file) {
     $this->$file = $file;
   }

   // 이름과 값 쌍으로 받아서 변수를 저장합니다.
   public function set($var, $value) {
     $this->vars[$var] = $value;
   }
  
   /* HTML로 출력합니다.
    * 1. 설정된 변수들의 집합을 현재의 심볼로 임포트합니다.
    * 2. 출력 버퍼에 템플릿 파일을 출력합니다.
    * 3. 출력 버퍼의 내용을 $string으로 리턴한 다음에 버퍼를 끕니다.
    * 4. 출력 버퍼를 클리어한다음 $string을 리턴합니다.
    */
   public function asHtml() {
     extract($this->vars);
     ob_start();
     include $this->file;
     $string = ob_get_contents();
     ob_end_clean();
     return $string;
   }
}
(관점에 따라 다를 수 있습니다만,) SRP의 원칙에서 봤을 때는 변수를 저장하는 부분과 템플릿 파일을 읽어들이는 부분과 템플릿으로 생성하는 부분 세 개의 책임을 가지는 클래스로 볼 수 있습니다. 따라서 이들을 분리할 수도 있겠죠.
// File을 읽어들이고 처리하는 클래스입니다.
class File {
   public function __construct($name) {
     $this->name = $name;
   }
   // File의 내용을 스트링으로 리턴합니다.
   function getContents() {
     return file_get_contents($this->name);
   }
}

// Template에서 사용하기 위한 변수들을 설정합니다.
// 디폴트 값을 설정하는 기능을 여기에서 할 수 있겠죠.
class TemplateData {
   private $vars;
   public function set($var, $value) {
     $this->vars[$var] = $value;
   }
   public function getArray() {
     return $this->vars;
   }
}

// TemplateData와 File에 템플릿 변수/파일을 처리하는 기능을 위임한 클래스입니다.
class Template {
   private $data;
   private $file;

   public function __construct($file) {
     $this->file = new File($file);
     $this->data = new TemplateData;
   }

   public function set($var, $value) {
     $this->data->set($var, $value);
   }

   private function processTemplate() {
     extract($this->data->getArray());
     $string = $this->file->getContents();
    // 파일처리와 템플릿 생성을 분리하여 include를 사용할  수 없어서 eval을 사용
     eval('?>'.$string);
   }

   public function asHtml() {
     ob_start();
     $this->processTemplate();
     $string = ob_get_contents();
     ob_end_clean();
     return $string;
   }
}
※ 그 외에도 The Dependency-inversion principle(DIP)와 Layered designs가 소개되어있는데 생략합니다~
※※ 4,5 장도 읽어봤는데.. 아는 내용이라 생략합니다~ ^^;;;

출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

2007년 7월 24일 화요일

3. Using PHP classes effectively

1. visibility: 메소드나 프로퍼티에 대해서 접근 권한 설정이 가능합니다.
  • public
  • private
  • protected - 디폴트로 설정됩니다. 부모나 자식 클래스에서만 접근이 가능합니다.
2. getter/setter 메소드 __get()__set()를 사용하여 접근 메소드를 만들면 getProperty()나 setProperty() 메소드 같은 메소드를 만들 필요없이 다음과 같은 형태로 사용할 수 있습니다.
$ClassInstance->property;
※ getter/setter의 경우 실험적으로 도입된 성격이 강하다고 합니다.

3. final - 자식 클래스에서 클래스 또는 메소드의 오버라이딩을 막습니다. (deprecated를 나타내기 위해서 사용할 수 있습니다.)

4. ::(double colon)은 클래스의 변수, 메소드 또는 상수를 접근하기 위해서 사용됩니다.
$product = Product::find($productCode);
5. 클래스 메소드는 static을 사용하여 정의합니다.
static public function encryptPassword(...){}
클래스 밖에서는 ::를 사용하여 접근하나 클래스안에서는 self를 사용하여 접근이 가능합니다.
self::encryptPassword();
※ 클래스 메소드, 변수에 대한 접근은 $this를 사용할 수가 없습니다.
※※ 언제 클래스 메소드를 사용하는가?
  • Creation methods and factory methods
  • Finder methods
  • Procedural code
  • Replacement for constants
6. 상수(constant)는 const로 정의합니다. 상수를 정의할 때는 $를 사용하지 않습니다.

7. abatract 선언을 사용할 수 있습니다.
  • abstract로 정의된 클래스 또는 메소드를 바로 사용할 때 에러가 발생합니다.
  • abstract로 정의된 메소드가 포함되어 있는 클래스는 abstract 클래스가 되어야 합니다.
abstract class HtmlDocument{
    public function getHtml() {...}
    abstract public function getContent();
}
8. CLASS Type Hints, 인자로 넘어오는 파라미터의 타입을 체크할 수 있습니다.
public function addDocument(Document $document) {}
  • Documnet의 인스턴스 또는 이를 상속받은 클래스의 인스턴스의 경우 정상통과가 되나 문자열(string)이나 다른 객체(Object)를 통과시킬 때 경고(Warning)을 발생시킵니다.
  • 그러나, 통과된 후에Document에 정의되어 있지 않은 메소드를 호출해도 에러메시지가 발생하지는 않습니다.
  • 객체들과 배열들만 체크가 가능하며 일반적인 데이타 타입(plain data type)을 체크하지는 않습니다.(예를 들면 문자열)
  • Type Hint의 단점으로는 체크를 위해 사용된 클래스가 변경되는 경우 관련된 Type Hint를 모두 변경해줘야 하는 의존(dependency)이 생긴다는 점입니다.
  • Type Hint가 실패한 경우 nonExistentmethod()가 호출됩니다.
9. instanceof를 사용해서 타입 체크가 가능합니다.
public function addDocument($document) {
    if(!($document instanceof Document)) {
        ...
    }
}
10. 인터페이스(interface)
interface Template {
   public function __constuct();
   public function execute();
   ...
}
자바의 인터페이스와 비슷합니다.
  • 클래스는 여러 인터페이스를 동시에 구현하는 것이 가능합니다 .
  • 동적언어에서는 인터페이스가 없는 것과 반대로 php에서는 이를 지원합니다.
    • 생성비용으로는 인터페이스 파일을 여는 비용을 제외하고는 거의 없습니다.
    • 디자인을 좀 더 명확하게 나타내고 실수를 막을 수 있습니다.
  • abstract와 동일한 역할을 합니다.
  • 두 개의 인터페이스를 구현하는 경우, 각각의 인터페이스가 동일한 메소드를 갖지 못합니다.
  • 인터페이스는 다른 인터페이스를 상속할 수 있습니다.
  • 생성자(__construct())를 인터페이스에서 선언할 수 있습니다.)
클래스에서 인터페이스를 구현하도록 선언하는 것도 비슷합니다.
class SmartyTemplate implements Template()
출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

2. Objects in PHP

1. PHP5에 들어오면서 객체 지향적 설계가 가능하게 되었습니다.

2. PHP 클래스 형태
// 상속은 extends를 사용합니다.
class HelloWorld extends ParentClass{
       
private $world;
       
public $hello;
       
       
// 생성자입니다.
       
function __construct($world) {
               
// 자신의 프로퍼티나 메소드를 호출하는 경우 $this를 사용합니다.  
                $this
->world = $world;

               
// 부모의 생성자를 호출할 때는 parent를 사용할 수 있습니다.
                parent
::__construct();
       
}
       
       
function getHtml() {
               
return "Hello, ".$this->world."!";
       
}
}
3. PHP4와 달리 객체를 나타낼 때 레퍼런스를 사용합니다. PHP4에서 &를 사용하여 레퍼런스를 지정할 수 있어나 내부에서 symbol table alias를 가지고 있습니다.

4. 메소드의 Override를 지원합니다.

5. 기존에 exception이 발생하는 경우 die()를 사용하여 처리했습니다. PHP5에서는 throw를 사용하여 Exception을 발생시킬 수 있고,
throw new Exception('...');
try/catch를 사용하여 Exception을 잡을 수 있습니다.
try {
   ...
}catch(Exception $e) {
   print($e->getMessage());
}
6. 디버깅하는 경우 스택을 따라가고 싶을 때 debug_trace()와 debug_print_backtrace()를 사용할 수 있습니다.

7. 예외를 사용하는 것보다는 예외 상황에서 이를 처리하는 코드를 사용하는것이 더 좋습니다.

8. 사용자 정의 예외도 만들 수 있습니다. 그러나, 사용자 정의 예외는 최대 5~7개정도가 좋으며 내부에서 예외를 구분하는 코드를 사용하는 편이 더 낳습니다.
class UserException extends Exception{}
9. PHP에서 제공하는 예외를 사용자 정의로 바꾸는 것도 가능합니다.
class ErrorFromPHPException extends Exception{}
function PHPErrorHandler($errno, $errstr, $errfile, $errline) {
   throw new ErrorFromPHPException($errstr, $errno);
}
...
$oldhandler = set_error_handler('PHPErrorHandler');
fopen('/tmp/non-existent', 'r');
...
원상 복귀할 때도 set_error_handler를 사용하면 됩니다.
set_error_handler($oldhandler)
10. PHP에서 클래스를 생성하고 메소드를 호출할 때, 메소드가 없는 경우 __call()가 호출됩니다. (책에서는 오버로딩 시 사용합니다. 메소드 매개변수가 다른 경우 내부에서 __call()에서 적절한 메소드를 체크하여 호출시킵니다.)

11. __autoload() 정의되어 있지않은 클래스를 초기화하려는 경우 호출됩니다. (include되지 않은 클래스를 자동으로 호출하려고 하는 경우)


출처: Manning, PHP in Action(Objects, Design, Agility) 보면서 요약한 내용입니다.

2007년 6월 22일 금요일

array_fill - 특정 값들로 채워진 배열을 생성합니다.

array_fill
(PHP 4 >= 4.2.0, PHP 5) - 특정 값들로 채워진  배열을 생성합니다.

Description


    array array_fill ( int $start_index, int $num, mixed $values )

배열의 시작위치($start_index)부터 주어진 크기($num)만큼의 배열을 생성하고 인자로 받는 값($values)으로 배열을 채웁니다.

Parameters
start_index - Array의 시작인덱스를 인자로 받습니다.
num - 삽입할 배열 인자의 개수를 받습니다.
values - 배열에 채울 값을 인자로 받습니다.

출처 : php.net - array_fill

2007년 6월 21일 목요일

implode - 배열의 값을 스트링으로 합쳐주는 메소드입니다.

implode
(PHP 4, PHP 5) - Array에 들어있는 값들을 스트링으로 합쳐주는 메소드입니다.

Description


    string implode ( string $glue, array $pieces )

Parameters
glue - Array에 들어있는 값들을 연결시켜주는 스트링입니다.
pieces - 연결시켜서 보여주기 위한 Array를 인자로 받습니다.

출처: PHP-implode