'Web Dev/PHP'에 해당되는 글 12건
- 2006/11/30 php5의 정수 __autoload()활용하기 2 (2)
- 2006/11/10 php5의 정수 __autoload()활용하기 1 (4)
- 2006/11/07 PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기
- 2006/11/07 [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법;
- 2006/10/23 오픈소스 프로젝트에 참여하고 싶어요 (11)
- 2006/04/19 젠드 프레임워크 0.1.3
- 2006/04/06 The Oracle + PHP Cookbook :: Oracle/PHP 환경의 LOB 처리
- 2006/03/21 PHP를 Eclipse로 개발하기(PHPEclipse) - 2. 설정편 (7)
- 2006/03/13 Linux 및 Windows 환경을 위한 PHP, Oracle 10g Instant Client 설치 (1)
- 2006/02/24 PHP를 Eclipse로 개발하기(PHPEclipse) - 1. 설치편 (7)
- 2006/01/23 Upcoming changes in PHP 6.0
- 2006/01/23 AJAX-based site builder is built with PHP
include_path 개념
지금 리눅스/유닉스를 사용하고 계시거나, 예전에 DOS를 사용해 보셨다면, PATH환경 변수에 대해서 알고 있을 겁니다.
파일을 include시 꼭 현재 스크립트로 부터 시작되는 상대경로가 아니더라도, include path안에 있는 경로이면 알아서 include를 시켜줍니다.
메뉴얼에 따르면
즉, 자동으로 파일을 찾아 include시켜준다는 의미 입니다. 이것을 조작하는 방법은 몇가지가 있는데,
ini_get과 ini_set은 설정 옵션을 조정할 수 있도록 하는 범용함수이고, get_include_path와 set_include_path는 php4.3이상에서 지원하는 include_path를 위한 전용함수 입니다. 사용 예는 메뉴얼에서 확인 하실 수 있습니다.
아래 코드에서는 set_include_path와 get_include_path를 사용합니다.
그러면 include_path을 지정하면서 __autoload가 실행되는 것을 보겠습니다.
하.지.만 이 방법도 문제가 있습니다. 상황에 따라 다르겠지만 저의 경우는 패키지 내에서 include할 때(cohesion)를 제외하고는 거의 include를 사용하지 않으므로 한 스크립트가 실행될 때 __autoload가 여러번 실행되게 됩니다.
그래서 위와 같은 방법으로는 include_path를 지정해주는 코드가 여러번 실행되는 것을 피할 수가 없게 됩니다.
그래서 정적(static)변수를 사용해 아래와 같이 개선해보았습니다.
제가 지금 사용하는 코드가 바로 위와 비슷한 코드 입니다. 파일이 존재하지 않을 때를 대비한 예외처리까지 합하면 조금 더 길어지기는 하지만.. 예외처리가 쉽게 가능하도록 아래에 팁을 마련합니다. 참고하시고 잘 사용하셨으면 좋겠습니다^^
지금 리눅스/유닉스를 사용하고 계시거나, 예전에 DOS를 사용해 보셨다면, PATH환경 변수에 대해서 알고 있을 겁니다.
파일을 include시 꼭 현재 스크립트로 부터 시작되는 상대경로가 아니더라도, include path안에 있는 경로이면 알아서 include를 시켜줍니다.
메뉴얼에 따르면
require()와 include(), fopen_with_path() 함수들이 사용하는 파일을 찾을 위치(path)를 지정한다. string의 형식은 시스템 환경변수 PATH의 설정과 비슷하다. UNIX에서는 콜론으로 나뉘어진 디렉토리들의 리스트이고, Windows에서는 세미콜론을 사용한다. (이하 생략)
즉, 자동으로 파일을 찾아 include시켜준다는 의미 입니다. 이것을 조작하는 방법은 몇가지가 있는데,
- php.ini에서 직접 변경
- ini_get, ini_set 함수
- get_include_path, set_include_path 함수
ini_get과 ini_set은 설정 옵션을 조정할 수 있도록 하는 범용함수이고, get_include_path와 set_include_path는 php4.3이상에서 지원하는 include_path를 위한 전용함수 입니다. 사용 예는 메뉴얼에서 확인 하실 수 있습니다.
아래 코드에서는 set_include_path와 get_include_path를 사용합니다.
그러면 include_path을 지정하면서 __autoload가 실행되는 것을 보겠습니다.
하.지.만 이 방법도 문제가 있습니다. 상황에 따라 다르겠지만 저의 경우는 패키지 내에서 include할 때(cohesion)를 제외하고는 거의 include를 사용하지 않으므로 한 스크립트가 실행될 때 __autoload가 여러번 실행되게 됩니다.
그래서 위와 같은 방법으로는 include_path를 지정해주는 코드가 여러번 실행되는 것을 피할 수가 없게 됩니다.
그래서 정적(static)변수를 사용해 아래와 같이 개선해보았습니다.
제가 지금 사용하는 코드가 바로 위와 비슷한 코드 입니다. 파일이 존재하지 않을 때를 대비한 예외처리까지 합하면 조금 더 길어지기는 하지만.. 예외처리가 쉽게 가능하도록 아래에 팁을 마련합니다. 참고하시고 잘 사용하셨으면 좋겠습니다^^
include_path에서 파일이 있는지 없는지 어떻게 알 수 있을까?
file_exists를 이용한 노가다를 할 수도 있지만.. 조금더 elegant한 방법은,
fopen을 실행시켜 리턴값이 resource인지를 확인하는 방법이다. 많이 사용되지 않는 fopen의 세번째 인자는 include_path를 활용할 것인가 하는 boolean값이다.(기본값은 false다)
'Web Dev > PHP' 카테고리의 다른 글
| php5의 정수 __autoload()활용하기 2 (2) | 2006/11/30 |
|---|---|
| php5의 정수 __autoload()활용하기 1 (4) | 2006/11/10 |
| PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기 (0) | 2006/11/07 |
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
php6의 발표를 앞두고 이제서야 포스팅을 올리는 것이 쑥스럽지만 php5에서 추가된 __autoload()에 대해 이야기 해보도록 하겠습니다.
__autoload()는 PHP5에서 추가된 'intercepter'로 필요한 클래스가 로딩 되지 않았을 때 자동으로 실행되는 함수입니다.
특히 네임스페이스라는 개념이 아직 없는 PHP에서 __autoload는 아주 유용하게 활용됩니다. (가장 많이 개발되는 형태에서) PHP4에서는 클래스의 로딩을 위해 include에 몇 라인씩을 할애해야했지만, PHP5의 __autoload를 활용하면 그런 라인들이 최소화 될 수 있습니다.
사용예는
[CODE type=php]
function __autoload( $className ){
require_once $className.'.php';
}
[/CODE]
이렇습니다.
$className에 필요한 클래스 네임이 들어가고, 그것을 규칙에 맞도록 파일이름으로 변경시켜 인클루드 시켜주는 것으로 작업이 끝납니다.
아주 간단하게 사용을 할 수가 있겠죠?
하지만 한가지 더 생각해 보아야 할 주제는 바로 패키지 개념 적용입니다. 패키지는 관련있는 클래스들의 모음이고 어떤 방법으로든 그룹화 됩니다. 지금부터는 이 그룹화에 대해 말씀드리려고 합니다.
PEAR를 한번이라도 활용해보셨다면, 이름짓기규칙(Naming Convention)에 대해서도 아실 텐데요. DB_Common이라는 클래스는 DB/Common.php 에 저장되어 있습니다.또 Zend Framework에서 Zend_Controller_Action이라는 클래스는 Zend/Controller/Action.php에 저장되어 있습니다. _(언더바)가 /(디렉토리 분리기호)로 변경시켜 디렉토리 단위로 패키지로 묶는 것이 PHP에서의 대세 입니다.
이것을 활용한 __autoload()의 코드의 예는 이렇습니다.
[CODE type=php]
function __autoload($className)
{
$path = str_replace('_',DIRECTORY_SEPARATOR,$className).'.php'; /*DIRECTORY SEPARATOR는 윈도환경에서는 \으로, xNIX환경에서는 / 이 저장되어 있는 php기본 상수 입니다. */
require_once $path;
}
[/CODE]
다음 포스팅에서 include_path를 잘 활용하는 방법과 앞서 언급한 것을 모두 적용시킨, 제가 사용하는 __autoload코드를 공개합니다~
__autoload()는 PHP5에서 추가된 'intercepter'로 필요한 클래스가 로딩 되지 않았을 때 자동으로 실행되는 함수입니다.
특히 네임스페이스라는 개념이 아직 없는 PHP에서 __autoload는 아주 유용하게 활용됩니다. (가장 많이 개발되는 형태에서) PHP4에서는 클래스의 로딩을 위해 include에 몇 라인씩을 할애해야했지만, PHP5의 __autoload를 활용하면 그런 라인들이 최소화 될 수 있습니다.
사용예는
[CODE type=php]
function __autoload( $className ){
require_once $className.'.php';
}
[/CODE]
이렇습니다.
$className에 필요한 클래스 네임이 들어가고, 그것을 규칙에 맞도록 파일이름으로 변경시켜 인클루드 시켜주는 것으로 작업이 끝납니다.
아주 간단하게 사용을 할 수가 있겠죠?
하지만 한가지 더 생각해 보아야 할 주제는 바로 패키지 개념 적용입니다. 패키지는 관련있는 클래스들의 모음이고 어떤 방법으로든 그룹화 됩니다. 지금부터는 이 그룹화에 대해 말씀드리려고 합니다.
PEAR를 한번이라도 활용해보셨다면, 이름짓기규칙(Naming Convention)에 대해서도 아실 텐데요. DB_Common이라는 클래스는 DB/Common.php 에 저장되어 있습니다.또 Zend Framework에서 Zend_Controller_Action이라는 클래스는 Zend/Controller/Action.php에 저장되어 있습니다. _(언더바)가 /(디렉토리 분리기호)로 변경시켜 디렉토리 단위로 패키지로 묶는 것이 PHP에서의 대세 입니다.
이것을 활용한 __autoload()의 코드의 예는 이렇습니다.
[CODE type=php]
function __autoload($className)
{
$path = str_replace('_',DIRECTORY_SEPARATOR,$className).'.php'; /*DIRECTORY SEPARATOR는 윈도환경에서는 \으로, xNIX환경에서는 / 이 저장되어 있는 php기본 상수 입니다. */
require_once $path;
}
[/CODE]
다음 포스팅에서 include_path를 잘 활용하는 방법과 앞서 언급한 것을 모두 적용시킨, 제가 사용하는 __autoload코드를 공개합니다~
'Web Dev > PHP' 카테고리의 다른 글
| php5의 정수 __autoload()활용하기 2 (2) | 2006/11/30 |
|---|---|
| php5의 정수 __autoload()활용하기 1 (4) | 2006/11/10 |
| PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기 (0) | 2006/11/07 |
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
오늘은 PHP-CLI를 통해 이클립스 콘솔창에서 php파일을 실행하는 방법을 알아보도록 하겠습니다.
사실 개발 중에는 브라우져에서 보지 않아도 될 일들이 상당히 많습니다. 타임스탬프를 많이 사용하는 저같은 경우 DB에서 읽어온 타임 스탬프 검토를 위해 date()함수를 쓰는 일이 종종 있습니다. 그런경우 콘솔에서 바로 찍어보면 브라우져에서 여는 것보다 상당히 편하게 열 수 있습니다. 또 var_export의 경우는 구분자로 개행문자(\n)을 출력하므로 브라우져에서 보면 문자열들이 정렬되지 않고 주르륵 붙어나오게 되는데, 이런경우도 콘솔을 사용하면 편합니다. ^^
마우스로 브라우져로 가서 주소를 찍고 할 필요 없이 단축키로 손가락만 움직여 열 수 있으니 편리하구요.
우선 이클립스를 켜야겠죠? 그다음 상단 메뉴의 Run - External Tools - External Tools로 들어가 외부 툴을 연결 시킬 수 있는 곳으로 들어갑니다. External Tools라는 창이 하나 열릴거구요. 왼편에 보면 Configuration이라고 되어 있는데 사람이 달리는 아이콘으로 되어 있는 것도 있고, 플레이 아이콘 처럼 생긴것도 있죠? 사람이 달리는 아이콘으로 되어 있는 것은 Run이고, 플레이 아이콘처럼 생긴것은 Program이라고 붙어있을 겁니다.
php콘솔을 '제대로' 열려고 하면 Program을 선택해야 합니다. 둘이 뭐가 다른지는 잘 모르겠지만, Run은 working directory를 설정하는 것이 힘들어서 Program으로 추가합니다;
Program을 선택하고 왼쪽하단의 New를 클릭하세요.
그러면 오른쪽에 New_Configuration이라고 하면서 새로운 설정을 추가할 수 있는 form이 나올 겁니다.
이제 여기에 php를 실행시킬 인자라던가 php가 실행될 working디렉토리를 설정해주어야 합니다.
Location에는 php파일의 경로를 적어주셔야 합니다. 저는 xampp를 사용중이어서 경로가 c:\Program Files\xampp\php\php.exe 이렇게 됩니다.
Working Directory에는 ${container_loc} 이렇게 적어주세요. 이것은 실행시킬 파일이 담긴 디렉토리의 절대경로를 working directory로 사용하겠다는 뜻입니다. 이외에 다른 변수를 찾아보시려면 Variables버튼을 클릭해보세요.
Arguments에는 -f "${resource_loc}" -c "c:\Program Files\xampp\apache\bin\php.ini"
이렇게 적어줍니다. 이 때에도 php.ini경로를 맞추어서 적어주시면 됩니다. 이것은 우리가 커맨드라인에서 php -f "디렉토리/파일명" -c "c:\Program Files\xampp\apache\bin\php.ini" 라고 적는것과 같이 인자를 전달해주는 역할을 합니다.
중간 중간의 큰 따옴표는 윈도 파일시스템에서 스페이스가 포함되어 있더라도 경로로 인식시켜주기 위한 장치입니다.
이제 거의 다 왔습니다. Apply를 눌러보시지요. 창이 닫기고 다시 workspace로 돌아왔죠?
프로젝트를 하나 추가하시고 echo "hello world"를 입력해보세요. 그 다음 한번 실행을 시켜보시지요. 실행은 Run-External Tools-방금 추가한 php를 클릭 해주시면 됩니다.
간단하게 실행이 되죠? 단축키는 Alt + R + E + 숫자 정도가 되겠네요 ^^
이것으로 이번 강좌는 마치도록 하겠습니다. PHPDocumentor도 달 수 있으니 참고하세요.
PHPDocumentor 추가하기
사실 개발 중에는 브라우져에서 보지 않아도 될 일들이 상당히 많습니다. 타임스탬프를 많이 사용하는 저같은 경우 DB에서 읽어온 타임 스탬프 검토를 위해 date()함수를 쓰는 일이 종종 있습니다. 그런경우 콘솔에서 바로 찍어보면 브라우져에서 여는 것보다 상당히 편하게 열 수 있습니다. 또 var_export의 경우는 구분자로 개행문자(\n)을 출력하므로 브라우져에서 보면 문자열들이 정렬되지 않고 주르륵 붙어나오게 되는데, 이런경우도 콘솔을 사용하면 편합니다. ^^
마우스로 브라우져로 가서 주소를 찍고 할 필요 없이 단축키로 손가락만 움직여 열 수 있으니 편리하구요.
우선 이클립스를 켜야겠죠? 그다음 상단 메뉴의 Run - External Tools - External Tools로 들어가 외부 툴을 연결 시킬 수 있는 곳으로 들어갑니다. External Tools라는 창이 하나 열릴거구요. 왼편에 보면 Configuration이라고 되어 있는데 사람이 달리는 아이콘으로 되어 있는 것도 있고, 플레이 아이콘 처럼 생긴것도 있죠? 사람이 달리는 아이콘으로 되어 있는 것은 Run이고, 플레이 아이콘처럼 생긴것은 Program이라고 붙어있을 겁니다.
php콘솔을 '제대로' 열려고 하면 Program을 선택해야 합니다. 둘이 뭐가 다른지는 잘 모르겠지만, Run은 working directory를 설정하는 것이 힘들어서 Program으로 추가합니다;
Program을 선택하고 왼쪽하단의 New를 클릭하세요.
그러면 오른쪽에 New_Configuration이라고 하면서 새로운 설정을 추가할 수 있는 form이 나올 겁니다.
이제 여기에 php를 실행시킬 인자라던가 php가 실행될 working디렉토리를 설정해주어야 합니다.
Location에는 php파일의 경로를 적어주셔야 합니다. 저는 xampp를 사용중이어서 경로가 c:\Program Files\xampp\php\php.exe 이렇게 됩니다.
Working Directory에는 ${container_loc} 이렇게 적어주세요. 이것은 실행시킬 파일이 담긴 디렉토리의 절대경로를 working directory로 사용하겠다는 뜻입니다. 이외에 다른 변수를 찾아보시려면 Variables버튼을 클릭해보세요.
Arguments에는 -f "${resource_loc}" -c "c:\Program Files\xampp\apache\bin\php.ini"
이렇게 적어줍니다. 이 때에도 php.ini경로를 맞추어서 적어주시면 됩니다. 이것은 우리가 커맨드라인에서 php -f "디렉토리/파일명" -c "c:\Program Files\xampp\apache\bin\php.ini" 라고 적는것과 같이 인자를 전달해주는 역할을 합니다.
중간 중간의 큰 따옴표는 윈도 파일시스템에서 스페이스가 포함되어 있더라도 경로로 인식시켜주기 위한 장치입니다.
이제 거의 다 왔습니다. Apply를 눌러보시지요. 창이 닫기고 다시 workspace로 돌아왔죠?
프로젝트를 하나 추가하시고 echo "hello world"를 입력해보세요. 그 다음 한번 실행을 시켜보시지요. 실행은 Run-External Tools-방금 추가한 php를 클릭 해주시면 됩니다.
간단하게 실행이 되죠? 단축키는 Alt + R + E + 숫자 정도가 되겠네요 ^^
이것으로 이번 강좌는 마치도록 하겠습니다. PHPDocumentor도 달 수 있으니 참고하세요.
PHPDocumentor 추가하기
'Web Dev > PHP' 카테고리의 다른 글
| php5의 정수 __autoload()활용하기 2 (2) | 2006/11/30 |
|---|---|
| php5의 정수 __autoload()활용하기 1 (4) | 2006/11/10 |
| PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기 (0) | 2006/11/07 |
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
일러두기 : 이미 있는 팁인지는 검토해보지 않았습니다;
php는 scriptlet 언어 입니다. 초보 때 누구나 한번쯤은 <html>로 시작해서 <table>사이에 <?php ~~~ ?> 이런 php코드를 심어 넣어보셨으리라 믿습니다.
또 모듈화 때문에 쉴새 없이 require혹은 include를 해주고 있으리라 생각됩니다.
이럴 때 require의 대상 파일이 ?> 로 끝나고, 그 후에 빈줄이라던지 빈칸이 삽입되어 있으면 그 후 세션을컨트롤한다던지 redirect로 헤더값을 적어주어야 하는경우 header already sent오류가 발생하게 됩니다.
이럴때는 php파일의 ?>을 삭제해버리면 그런 실수를 방지할 수 있습니다;
?>는 생략가능 하기 때문입니다;
돌던지지 마세요 -_-;
php는 scriptlet 언어 입니다. 초보 때 누구나 한번쯤은 <html>로 시작해서 <table>사이에 <?php ~~~ ?> 이런 php코드를 심어 넣어보셨으리라 믿습니다.
또 모듈화 때문에 쉴새 없이 require혹은 include를 해주고 있으리라 생각됩니다.
이럴 때 require의 대상 파일이 ?> 로 끝나고, 그 후에 빈줄이라던지 빈칸이 삽입되어 있으면 그 후 세션을컨트롤한다던지 redirect로 헤더값을 적어주어야 하는경우 header already sent오류가 발생하게 됩니다.
이럴때는 php파일의 ?>을 삭제해버리면 그런 실수를 방지할 수 있습니다;
?>는 생략가능 하기 때문입니다;
돌던지지 마세요 -_-;
'Web Dev > PHP' 카테고리의 다른 글
| php5의 정수 __autoload()활용하기 1 (4) | 2006/11/10 |
|---|---|
| PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기 (0) | 2006/11/07 |
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
| The Oracle + PHP Cookbook :: Oracle/PHP 환경의 LOB 처리 (0) | 2006/04/06 |
전 인천대학교 동북아통상대학 러시아통상학과를 다니다 입대했구요, 97년경에 처음홈페이지를 만들어보고(네띠앙과 같이 사라졌습니다 ㅡㅜ) 2002년에 영웅시대라는 사이트를 제로보드를 이용해서 만들어보았습니다.(지금보면 많이 창피합니다)
그리고 04년에 공군 전산병으로 입대해서 2년간 머리박고 php로 sw개발'만' 했습니다. 각종 시스템 4개(아직 밝힐 수는 없군요;) 포탈 홈페이지 1개(이것도 밝힐 수가 없지만 군 인트라넷 내에서는 몇손가락 안에 드는 규모였습니다)의 선임 프로그래머로 참여했었습니다.
이제 곧 제대합니다. 그런데 제 전공이 문과계열이라 전산하는 분들과의 교류가 참 적었고, 앞으로도 군대에서 만난 사람들 외에는 전산계열분들과 이야기해볼 기회가 참 적을것 같아요. 전산을 좋아하는데 같이 교류할 만한 사람이 적다는 것이 제 고민입니다.
그래서 생각한 것이 오픈소스 프로젝트로 인맥을 좀 넓혀보고, 안목도 좀 키워보고 싶다는 겁니다. kldp.net에는 이미 가보았지만, 활발한 프로젝트도 없고 하더니 멤버구함은 아예 한개도 안나오는군요 ㅡㅜ; 이미 시작된 프로젝트이면 더 좋구요, 아이디어만 가지신 분이라도 저와 함께 해보실분 있으시면 댓글로 남겨주셨으면 좋겠습니다. 제가 더 배울것이 많았으면 좋겠습니다;
관심분야는 PHP, Javascript, Ajax, 웹표준/CSS 입니다;
감사합니다;
그리고 04년에 공군 전산병으로 입대해서 2년간 머리박고 php로 sw개발'만' 했습니다. 각종 시스템 4개(아직 밝힐 수는 없군요;) 포탈 홈페이지 1개(이것도 밝힐 수가 없지만 군 인트라넷 내에서는 몇손가락 안에 드는 규모였습니다)의 선임 프로그래머로 참여했었습니다.
이제 곧 제대합니다. 그런데 제 전공이 문과계열이라 전산하는 분들과의 교류가 참 적었고, 앞으로도 군대에서 만난 사람들 외에는 전산계열분들과 이야기해볼 기회가 참 적을것 같아요. 전산을 좋아하는데 같이 교류할 만한 사람이 적다는 것이 제 고민입니다.
그래서 생각한 것이 오픈소스 프로젝트로 인맥을 좀 넓혀보고, 안목도 좀 키워보고 싶다는 겁니다. kldp.net에는 이미 가보았지만, 활발한 프로젝트도 없고 하더니 멤버구함은 아예 한개도 안나오는군요 ㅡㅜ; 이미 시작된 프로젝트이면 더 좋구요, 아이디어만 가지신 분이라도 저와 함께 해보실분 있으시면 댓글로 남겨주셨으면 좋겠습니다. 제가 더 배울것이 많았으면 좋겠습니다;
관심분야는 PHP, Javascript, Ajax, 웹표준/CSS 입니다;
감사합니다;
php스쿨에 올린 글입니다. 이글을 보는 당신도 저를 좀 도와주시지요-_-
'Web Dev > PHP' 카테고리의 다른 글
| PHP 이클립스(PHPEclipse) - 콘솔창에 실행하기 (0) | 2006/11/07 |
|---|---|
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
| The Oracle + PHP Cookbook :: Oracle/PHP 환경의 LOB 처리 (0) | 2006/04/06 |
| PHP를 Eclipse로 개발하기(PHPEclipse) - 2. 설정편 (7) | 2006/03/21 |
젠드 프레임워크가 0.0.1 업그레이드 되었습니다;;;
방금 들어온 따끈따끈한 소식입니다; 젠드프레임워크 이용해 개발중인데 빨리 적용시켜봐야겠군요 ^^;
역시나 영어는 눈치로 하는지라 원문을 그대로 올립니다.
-------------------------------------------------------------------------------------------------------------------
ZEND FRAMEWORK PREVIEW RELEASE 0.1.3
by John Herren (staff) · Tuesday, April 18, 2006 · 12:30PM PDT · 0 comments
Today the Zend Framework team has launched a shiny new website and tagged another minor version release of the framework. Since the last release in early March, the codebase features some module additions and several bug fixes, as well as updated documentation. The latest preview release is available for download from the framework website, or developers can access the Subversion repository directly for bleeding-edge checkouts.
To stay on top of important changes in the framework, visit the framework website or follow changes to the NEWS.txt file in the Subversion repository for release notes. Up-to-the-minute commit notifications are also available. To subscribe, simply send an e-mail to fw-svn-subscribe@lists.zend.com.
Zend is actively seeking contributions to the framework for various code modules. To get involved, visit the FAQ page on the framework website to learn more about the contribution process and requirements. Those wishing to be involved in the development process are highly encouraged to participate in the framework mailing list, as it is currently the preferred forum for collaboration. Send an e-mail to fw-general-subscribe@lists.zend.com to subscribe to the framework mailing list.
Framework documentation translations have begun for French, German, Dutch, Chinese, and Japanese.
Bug tracking is still being managed through the mailing list. Alternately, developers can submit bug reports to framework-feedback@zend.com.
Release Notes for 0.1.3
Zend_Filter is* methods return strictly TRUE or FALSE. (Chris)
Zend_InputFilter has test* methods for retrieving valid data. (Chris)
Fixed bug in Zend_View_Abstract::__isset(). Reported by James Simmons. (Mike)
Zend_Db_Adapter_Pdo_Mysql::limit() now compatible with MySQL versions prior to 4.0. Reported by Greg Neustaetter (Mike)
Fixed bug in Zend_Controller_Dispatcher_Token::setParams(). Reported by Rob Allen. (Chris)
Fixed bug in Zend_Log::log(). Reported by Mislav. (Mike)
Updated Zend_Filter::isFloat() and Zend_Filter::isInt() to respect locale. (Chris)
Improved Zend_Db_Adapter_Pdo_Mssql contributed by Rob Allen. (Mike)
Fixed bug in Zend_Controller_Dispatcher::_formatName. Reported by Arpad Ray. (Chris)
Zend::dump() now works from CLI (Rob Allen)
Improved support for XML-RPC namespaces (Mike, Chuck)
Registry can now be tested with Zend::isRegistered (Shekar C. Reddy, Mike)
Zend_Search_Lucene promoted from incubator (Alex)
Zend_Cache has been accepted to the incubator (Fabien, Mislav)
Zend_Json testing expanded; covers all major cases (Matthew)
Fixed Zend_Json encoding of empty values (Matthew, Davey)
Fixed Zend_Json encoding of associative arrays (Matthew, Davey)
Fixed Zend_Json encoding of numeric indices in associative arrays (Matthew)
Removed formatting (newlines, tabs) from Zend_Json encoding methods (Matthew)
Fixed escaping in Zend_Json_Encoder (Matthew)
Zend_HttpClient moved to Zend_Http_Client (Mike)
Zend_Console_Args in the incubator but not yet refactored (Jason Garber)
Zend_Mail enhancements in the incubator by Austria Telekom (Nico, Clez)
Zend_Service classes no longer subclass Zend_Service_Rest (Davey, Andi, et al)
Zend_Service classes now use new Zend_InputFilter (Davey)
Fixed bug in Zend_Service_Amazon::itemLookup() (Davey)
Fixed bug in Zend_Service_Flickr::userSearch() (Davey)
Fixed bug in Zend_Uri_Http::__construct(). Reported by Adrian Gheorghe. (Mike)
Improved some not well-formed PDF processing with Zend_Pdf. (Alexander)
Minor Zend_Pdf documentation fixes. (Alexander)
Fixed Zend_Pdf processing of inherited page attributes. (Alexander)
Fixed Zend_Pdf umlauts support for standard fonts. (Alexander)
방금 들어온 따끈따끈한 소식입니다; 젠드프레임워크 이용해 개발중인데 빨리 적용시켜봐야겠군요 ^^;
역시나 영어는 눈치로 하는지라 원문을 그대로 올립니다.
-------------------------------------------------------------------------------------------------------------------
ZEND FRAMEWORK PREVIEW RELEASE 0.1.3
by John Herren (staff) · Tuesday, April 18, 2006 · 12:30PM PDT · 0 comments
Today the Zend Framework team has launched a shiny new website and tagged another minor version release of the framework. Since the last release in early March, the codebase features some module additions and several bug fixes, as well as updated documentation. The latest preview release is available for download from the framework website, or developers can access the Subversion repository directly for bleeding-edge checkouts.
To stay on top of important changes in the framework, visit the framework website or follow changes to the NEWS.txt file in the Subversion repository for release notes. Up-to-the-minute commit notifications are also available. To subscribe, simply send an e-mail to fw-svn-subscribe@lists.zend.com.
Zend is actively seeking contributions to the framework for various code modules. To get involved, visit the FAQ page on the framework website to learn more about the contribution process and requirements. Those wishing to be involved in the development process are highly encouraged to participate in the framework mailing list, as it is currently the preferred forum for collaboration. Send an e-mail to fw-general-subscribe@lists.zend.com to subscribe to the framework mailing list.
Framework documentation translations have begun for French, German, Dutch, Chinese, and Japanese.
Bug tracking is still being managed through the mailing list. Alternately, developers can submit bug reports to framework-feedback@zend.com.
Release Notes for 0.1.3
Zend_Filter is* methods return strictly TRUE or FALSE. (Chris)
Zend_InputFilter has test* methods for retrieving valid data. (Chris)
Fixed bug in Zend_View_Abstract::__isset(). Reported by James Simmons. (Mike)
Zend_Db_Adapter_Pdo_Mysql::limit() now compatible with MySQL versions prior to 4.0. Reported by Greg Neustaetter (Mike)
Fixed bug in Zend_Controller_Dispatcher_Token::setParams(). Reported by Rob Allen. (Chris)
Fixed bug in Zend_Log::log(). Reported by Mislav. (Mike)
Updated Zend_Filter::isFloat() and Zend_Filter::isInt() to respect locale. (Chris)
Improved Zend_Db_Adapter_Pdo_Mssql contributed by Rob Allen. (Mike)
Fixed bug in Zend_Controller_Dispatcher::_formatName. Reported by Arpad Ray. (Chris)
Zend::dump() now works from CLI (Rob Allen)
Improved support for XML-RPC namespaces (Mike, Chuck)
Registry can now be tested with Zend::isRegistered (Shekar C. Reddy, Mike)
Zend_Search_Lucene promoted from incubator (Alex)
Zend_Cache has been accepted to the incubator (Fabien, Mislav)
Zend_Json testing expanded; covers all major cases (Matthew)
Fixed Zend_Json encoding of empty values (Matthew, Davey)
Fixed Zend_Json encoding of associative arrays (Matthew, Davey)
Fixed Zend_Json encoding of numeric indices in associative arrays (Matthew)
Removed formatting (newlines, tabs) from Zend_Json encoding methods (Matthew)
Fixed escaping in Zend_Json_Encoder (Matthew)
Zend_HttpClient moved to Zend_Http_Client (Mike)
Zend_Console_Args in the incubator but not yet refactored (Jason Garber)
Zend_Mail enhancements in the incubator by Austria Telekom (Nico, Clez)
Zend_Service classes no longer subclass Zend_Service_Rest (Davey, Andi, et al)
Zend_Service classes now use new Zend_InputFilter (Davey)
Fixed bug in Zend_Service_Amazon::itemLookup() (Davey)
Fixed bug in Zend_Service_Flickr::userSearch() (Davey)
Fixed bug in Zend_Uri_Http::__construct(). Reported by Adrian Gheorghe. (Mike)
Improved some not well-formed PDF processing with Zend_Pdf. (Alexander)
Minor Zend_Pdf documentation fixes. (Alexander)
Fixed Zend_Pdf processing of inherited page attributes. (Alexander)
Fixed Zend_Pdf umlauts support for standard fonts. (Alexander)
'Web Dev > PHP' 카테고리의 다른 글
| [1원짜리 팁] 찾기힘든 실수 - header already sent를 막는방법; (0) | 2006/11/07 |
|---|---|
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
| The Oracle + PHP Cookbook :: Oracle/PHP 환경의 LOB 처리 (0) | 2006/04/06 |
| PHP를 Eclipse로 개발하기(PHPEclipse) - 2. 설정편 (7) | 2006/03/21 |
| Linux 및 Windows 환경을 위한 PHP, Oracle 10g Instant Client 설치 (1) | 2006/03/13 |
출처: http://www.oracle.com/technology/global/kr/pub/articles/oracle_php_cookbook/fuecks_lobs.html저자 Harry Fuecks
4,000 바이트 제한이 문제가 되십니까? LOB를 활용하십시오...
Downloads for this article:
Oracle Database 10g
Zend Core for Oracle
Apache HTTP Server 1.3 (및 이후 버전)
VARCHAR2와 같은 오라클 데이터 타입은 유용하게 활용됩니다. 하지만 4,000 바이트 이상의 데이터를 저장하려면 어떻게 해야 할까요? 바로 오라클이 지원하는 Long Object (LOB) 데이터 타입이 필요합니다. 또 LOB와 호환하는 PHP API의 사용법을 알고 있어야 합니다. 이에 필요한 지식을 갖고 있지 않은 개발자에게는 무척 까다로운 과제가 될 수 있습니다
이번 “Oracle+PHP Cookbook” 시리즈 연재에서는, LOB 데이터 타입과 PHP에서 LOB를 다루는 방법을 예제를 통해 알아보기로 합니다.
오라클의 Long Object
오라클은 다음과 같은 LOB 데이터 타입을 지원합니다:
BLOB - 바이너리 데이터의 저장에 사용
CLOB - 데이터베이스 문자 셋 인코딩을 이용한 문자 데이터 저장에 사용
NCLOB - 국가별 문자 셋을 이용한 유니코드 문자 데이터 저장에 사용. (본 문서에서 사용되는 PHP OCI8 익스텐션은 NCLOB을 지원하지 않음을 참고하십시오.)
BFILE - 운영체제 파일시스템에 저장된 외부 파일의 참조에 사용
그 밖에도 temporary LOB가 있습니다. temporary LOB는 BLOB, CLOB 또는 NCLOB 등의 형태를 취할 수 있으며, 해제되기 전까지 임시 테이블스페이스에 저장됩니다.
이전 버전의 오라클에서는 문자 및 바이너리 데이터의 저장을 위해 LONG, LONG RAW 타입을 지원했습니다. 이 두 가지 타입은 Oracle9i에서 LOB로 대체되었습니다.
LOB 데이터의 저장. Oracle Database 10g는 BLOB, CLOB, NCLOB 타입에 대해 단일 레코드 당 최대 128TB의 용량을 지원합니다 (실제 최대 용량은 데이터베이스 블록 사이즈와 LOB의 “chunk” 설정에 따라 달라질 수 있습니다.
LOB는 LOB 컨텐트와 LOB 로케이터(locator)의 두 가지 요소로 구성됩니다. LOB 로케이터는 LOB에 대한 “포인터”로 활용됩니다. LOB 로케이터는 LOB 데이터를 효과적으로 저장하고 관리하기 위한 목적에서 설계되었으며, PHP API의 INSERT, UPDATE, SELECT 에도 반영되어 있습니다 (아래 설명 참고)..
오라클은 LOB 레코드의 크기가 4KB를 넘지 않는 경우 LOB 컨텐트를 테이블 내부에 “인라인(in-line)” 형태로 저장합니다. 4KB를 초과하는 LOB는 테이블의 테이블스페이스 내에 아웃오브라인(out-of-line)” 형태로 저장됩니다. 이러한 방법으로 작은 크기의 LOB를 신속하게 조회하는 한편, 큰 LOB 때문에 테이블 스캔 성능이 저하되는 것을 방지할 수 있습니다.
LOB 저장 및 액세스를 위해 메모리 캐싱, 버퍼링과 같은 테크닉을 사용하여 애플리케이션의 성능을 개선할 수 있습니다. 자세한 정보는 오라클 제품문서의 LOB Performance Guidelines와 Oracle Database Application Developer's Guide - Large Objects를 참고하시기 바랍니다.
LOB 관련 제약사항. LOB 타입의 활용에 관련한 몇 가지 제약사항이 존재합니다. 특히 SQL 구문과 관련한 제약사항은 주의할 필요가 있습니다. 아래와 같은 쿼리에서는 LOB 타입을 사용할 수 없습니다.
SELECT DISTINCT
ORDER BY
GROUP BY
또 테이블 JOIN,UNION, INTERSECTION, MINUS 등의 구문에서도 LOB 타입 컬럼을 사용하는 것이 금지되어 있습니다.
그 밖에도 LOB를 프라이머리 키 컬럼으로 사용할 수 없는 등의 여러 가지 제약사항이 존재합니다. 자세한 정보는 Oracle Database Application Developer's Guide - Large Objects를 참고하십시오.
CLOB과 문자 셋
데이터베이스의 디폴트 문자 셋(character set)은 NLS_CHARACTERSET 매개변수를 통해 설정되며, CLOB 타입으로 저장된 텍스트는 이 문자 셋을 이용하여 인코딩 됩니다. 아래 SQL 구문을 이용하여 데이터베이스 문자 셋을 설정하시기 바랍니다:
SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET'
현재로서는 PHP가 NCLOB을 지원하지 않으므로, 아래와 같은 방법으로 UTF-8과 같은 유니코드 인코딩을 기본 데이터베이스 문자 셋으로 설정하는 것을 고려해 볼 수 있습니다:
ALTER DATABASE CHARACTER SET UTF8
참고: 기존 데이터 또는 애플리케이션 코드가 다른 문자 셋을 사용하고 있는 경우, 변경 작업이 전체 환경에 미치는 영향을 미리 감안하여야 합니다. 자세한 정보는 Oracle Globalization Support Guide와 An Overview on Globalizing Oracle PHP Applications를 참고하시기 바랍니다.
LOB 데이터의 처리
본 문서에서는 PHP의 OCI8 익스텐션에 초점을 맞추어 설명합니다. 또 오라클에 포함된 DBMS_LOB 패키지는 PL/SQL을 이용한 LOB 처리를 위한 병렬 프로시저 및 함수를 제공하고 있음을 참고하시기 바랍니다.
PHP OCI8 익스텐션은 글로벌 PHP 네임스페이스에 “OCI-Lob”이라 불리는 PHP 클래스를 등록합니다. LOB 타입의 컬럼이 포함된 SELECT 구문이 실행된 경우, PHP는 이 구문을 OCI-Lob 오브젝트 인스턴스에 자동으로 바인딩합니다. OCI-Lob 오브젝트에 대한 참조가 확보되면 load(), save()등의 메소드를 이용하여 LOB 컨텐트를 조회, 수정할 수 있습니다.
사용 가능한 OCI-Lob 메소드는 PHP 버전에 따라 달라집니다. PHP5는 read(), seek(), 그리고 append()등의 메소드를 지원합니다. 이에 대한 PHP Manual 의 설명이 다소 불충분한 감이 있으므로, 지원되는 버전 넘버가 궁금한 경우 아래와 같은 스크립트를 사용해서 검증해 보시기 바랍니다.
foreach (get_class_methods('OCI-Lob') as $method ) {
print "OCI-Lob::$method()\n";
}
?>
PHP 5.0.5가 실행 중인 필자의 시스템에서는 아래와 같은 메소드 리스트가 출력되었습니다:
OCI-Lob::load()
OCI-Lob::tell()
OCI-Lob::truncate()
OCI-Lob::erase()
OCI-Lob::flush()
OCI-Lob::setbuffering()
OCI-Lob::getbuffering()
OCI-Lob::rewind()
OCI-Lob::read()
OCI-Lob::eof()
OCI-Lob::seek()
OCI-Lob::write()
OCI-Lob::append()
OCI-Lob::size()
OCI-Lob::writetofile()
OCI-Lob::writetemporary()
OCI-Lob::close()
OCI-Lob::save()
OCI-Lob::savefile()
OCI-Lob::free()
PHP 4.x OCI8 익스텐션은 전체 LOB의 일괄적인 읽기 및 쓰기만을 지원합니다. PHP5에서는 LOB의 일부 “청크(chung)”만을 읽거나 쓸 수 있으며 setBuffering(),getBuffering() 메소드를 이용한 LOB 버퍼링을 지원합니다. 또 PHP5는 스탠드얼론 함수로 oci_lob_is_equal(), oci_lob_copy()를 지원합니다.
본 문서에서 사용된 예제들은 새로운 PHP5 OCI 함수명을 사용하고 있습니다 (예: oci_parse 대신 OCIParse 사용)예제에서 공통적으로 사용되는 시퀀스와 테이블이 아래와 같습니다:
CREATE SEQUENCE mylobs_id_seq
NOMINVALUE
NOMAXVALUE
NOCYCLE
CACHE 20
NOORDER
INCREMENT BY 1;
CREATE TABLE mylobs (
id NUMBER PRIMARY KEY,
mylob CLOB
)
본 문서의 예제는 대부분 CLOB을 사용하고 있지만, 동일한 로직이 BLOB에도 적용 가능함을 참고하시기 바랍니다.
LOB의 INSERT
LOB의 INSERT 작업을 수행하려면, 먼저 오라클의 EMPTY_BLOB 또는 EMPTY_CLOB 함수를 이용하여 LOB를 초기화해야 합니다. NULL 값을 포함한 LOB는 업데이트할 수 없습니다.
초기화가 완료되면, 컬럼을 PHP OCI-Lob 오브젝트에 바인딩하고 오브젝트의 save() 메소드를 이용하여 LOB 컨텐트를 업데이트합니다.
아래 스크립트는 LOB 타입 데이터의 INSERT 쿼리 수행을 위한 예를 보여주고 있습니다:
// connect to DB etc...
$sql = "INSERT INTO
mylobs
(
id,
mylob
)
VALUES
(
mylobs_id_seq.NEXTVAL,
--Initialize as an empty CLOB
EMPTY_CLOB()
)
RETURNING
--Return the LOB locator
mylob INTO :mylob_loc";
$stmt = oci_parse($conn, $sql);
// Creates an "empty" OCI-Lob object to bind to the locator
$myLOB = oci_new_descriptor($conn, OCI_D_LOB);
// Bind the returned Oracle LOB locator to the PHP LOB object
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_CLOB);
// Execute the statement using , OCI_DEFAULT - as a transaction
oci_execute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
// Now save a value to the LOB
if ( !$myLOB->save('INSERT: '.date('H:i:s',time())) ) {
// On error, rollback the transaction
oci_rollback($conn);
} else {
// On success, commit the transaction
oci_commit($conn);
}
// Free resources
oci_free_statement($stmt);
$myLOB->free();
// disconnect from DB etc.
?>
위 예제에서 트랜잭션을 사용하고 있으며, oci_execute 의 실행과정에서 OCI_DEFAULT 상수를 통해 an oci_commit 또는 oci_rollback를 대기할 것을 지시하고 있습니다. 이는 INSERT 작업이 두 단계(로우의 생성, LOB의 업데이트)로 실행되기 때문입니다.
참고 위에서는 BLOB 타입이 사용되고 있으므로oci_bind_by_name 함수를 호출하는 작업만이 필요합니다:
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_BLOB);
마찬가지로, LOB 타입을 명시하지 않고 문자열을 바인딩할 수도 있습니다;
// etc.
$sql = "INSERT INTO
mylobs
(
id,
mylob
)
VALUES
(
mylobs_id_seq.NEXTVAL,
:string
)
";
$stmt = oci_parse($conn, $sql);
$string = 'INSERT: '.date('H:i:s',time());
oci_bind_by_name($stmt, ':string', $string);
oci_execute($stmt)
or die ("Unable to execute query\n");
// etc.
?>
위와 같은 방법을 사용하면 코드를 대폭적으로 단순화할 수 있습니다. 이러한 방식은 LOB에 기록되는 데이터의 크기가 비교적 작은 경우에 유용합니다. 큰 용량의 파일 컨텐트를 LOB에 스트리밍하고자 하는 경우에는, PHP LOB 오브젝트에 대해 write(), flush() 함수를 호출하고 (전체 파일을 하나의 인스턴스로 메모리에 보관하는 대신) 작은 청크(chunk) 단위로 루프를 돌려 컨텐트를 처리하는 것이 좋습니다.
LOB의 SELECT
LOB 컬럼을 포함하는 데이터를 SELECT 쿼리로 조회하는 경우, PHP는 해당 컬럼을 OCI-Lob 오브젝트에 자동으로 바인딩합니다. 그 예가 다음과 같습니다:
// etc.
$sql = "SELECT
*
FROM
mylobs
ORDER BY
Id
";
$stmt = oci_parse($conn, $sql);
oci_execute($stmt)
or die ("Unable to execute query\n");
while ( $row = oci_fetch_assoc($stmt) ) {
print "ID: {$row['ID']}, ";
// Call the load() method to get the contents of the LOB
print $row['MYLOB']->load()."\n";
}
// etc.
?>
OCI_RETURN_LOBS 상수와 oci_fetch_array()를 함께 사용하여 LOB 오브젝트를 그 값으로 대치하도록 함으로써 작업을 한층 단순화할 수 있습니다:
while ( $row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_LOBS) ) {
print "ID: {$row['ID']}, {$row['MYLOB']}\n";
}
LOB의 UPDATE
LOB를 업데이트하는 경우, 위의 INSERT 구문 예와 마찬가지로 "RETURNING" 커맨드를 사용할 수도 있습니다. 하지만 “SELECT ... FOR UPDATE” 구문을 사용하는 편이 훨씬 간단합니다:
// etc.
$sql = "SELECT
mylob
FROM
mylobs
WHERE
id = 3
FOR UPDATE /* locks the row */
";
$stmt = oci_parse($conn, $sql);
// Execute the statement using OCI_DEFAULT (begin a transaction)
oci_execute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
// Fetch the SELECTed row
if ( FALSE === ($row = oci_fetch_assoc($stmt) ) ) {
oci_rollback($conn);
die ("Unable to fetch row\n");
}
// Discard the existing LOB contents
if ( !$row['MYLOB']->truncate() ) {
oci_rollback($conn);
die ("Failed to truncate LOB\n");
}
// Now save a value to the LOB
if ( !$row['MYLOB']->save('UPDATE: '.date('H:i:s',time()) ) ) {
// On error, rollback the transaction
oci_rollback($conn);
} else {
// On success, commit the transaction
oci_commit($conn);
}
// Free resources
oci_free_statement($stmt);
$row['MYLOB']->free();
// etc.
?>
INSERT의 경우와 마찬가지로, 위 코드는 UPDATE 수행을 위해 트랜잭션을 이용하고 있습니다. 특히 주목해야 할 부분이 truncate()함수를 호출하는 부분입니다. save()를 이용해서 LOB를 업데이트하는 경우, save() 함수는 LOB 컨텐트의 시작 부분에서부터 새로운 데이터의 길이에 해당되는 부분까지만을 업데이트합니다. 따라서 이전의 컨텐트가 여전히 LOB에 남아 있을 수도 있습니다.
PHP 4.x, truncate()함수가 지원되지 않습니다. 따라서 새로운 데이터를 업데이트하기 전에 LOB의 기존 컨텐트를 지우려면 오라클의 EMPTY_CLOB() 함수를 사용해야 합니다.
$sql = "UPDATE
mylobs
SET
mylob = EMPTY_CLOB()
WHERE
id = 2403
RETURNING
mylob INTO :mylob
";
$stmt = OCIParse($conn, $sql);
$mylob = OCINewDescriptor($conn,OCI_D_LOB);
OCIBindByName($stmt,':mylob',$mylob, -1, OCI_B_CLOB);
// Execute the statement using OCI_DEFAULT (begin a transaction)
OCIExecute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
if ( !$mylob->save( 'UPDATE: '.date('H:i:s',time()) ) ) {
OCIRollback($conn);
die("Unable to update lob\n");
}
OCICommit($conn);
$mylob->free();
OCIFreeStatement($stmt);
BFILE에 대한 작업 수행
BFILE 타입에 대해 INSERT 또는 UPDATE를 수행하는 경우, 오라클은 (웹 서버가 아닌) 데이터베이스 서버 운영체제의 파일시스템에서 저장된 파일의 위치를 지정하는 작업을 수행하게 됩니다. 또 SELECT 구문을 이용하여 BILE의 컨텐트를 읽어 들이거나, 필요한 경우 DBMS_LOB 패키지의 함수와 프로시저를 호출하여 파일에 대한 정보만을 확인할 수도 있습니다.
BFILE은 파일시스템에 저장된 파일을 직접 액세스하는 한편으로 SQL 구문을 이용하여 파일의 위치를 확인할 수 있게 한다는 장점을 제공합니다. 예를 들어 웹 서버에서 이미지를 직접 제공하면서, BFILE을 포함한 테이블과 다른 테이블과의 관계 정보를 추적하는 것이 가능합니다 (한 예로, 어떤 사용자가 어떤 파일을 업로드했는지 확인할 수 있습니다).
위에서 사용된 테이블 스키마를 먼저 업데이트해 보겠습니다;
ALTER TABLE mylobs ADD( mybfile BFILE )
그런 다음, 오라클에 디렉토리 앨리어스(alias)를 등록하고(이 과정에서 관리자 권한이 필요합니다), 테이블에 대한 읽기 권한을 할당합니다:
CREATE DIRECTORY IMAGES_DIR AS '/home/harryf/public_html/images'
GRANT READ ON DIRECTORY IMAGES_DIR TO scott
이제 아래와 같이 BFILE의 INSERT 작업을 수행할 수 있습니다:
// etc.
// Build an INSERT for the BFILE names
$sql = "INSERT INTO
mylobs
(
id,
mybfile
)
VALUES
(
mylobs_id_seq.NEXTVAL,
/*
Pass the file name using the Oracle directory reference
I created called IMAGES_DIR
*/
BFILENAME('IMAGES_DIR',:filename)
)";
$stmt = oci_parse($conn, $sql);
// Open the directory
$dir = '/home/harryf/public_html/images';
$dh = opendir($dir)
or die("Unable to open $dir");
// Loop through the contents of the directory
while (false !== ( $entry = readdir($dh) ) ) {
// Match only files with the extension .jpg, .gif or .png
if ( is_file($dir.'/'.$entry) && preg_match('/\.(jpg|gif|png)$/',$entry) ) {
// Bind the filename of the statement
oci_bind_by_name($stmt, ":filename", $entry);
// Execute the statement
if ( oci_execute($stmt) ) {
print "$entry added\n";
}
}
}
필요한 경우, CLOB을 조회한 것과 동일한 방법으로 오라클에서 BFILE을 읽어 들일 수 있습니다. 또는 아래와 같이 DBMS_LOB.FILEGETNAME 프로시저를 통해 파일 이름만을 확인한 후 파일시스템에서 직접 액세스하는 방법을 사용할 수도 있습니다:
// etc.
$sql = "SELECT
id
FROM
mylobs
WHERE
-- Select only BFILES which are not null
mybfile IS NOT NULL;
$stmt1 = oci_parse($conn, $sql);
oci_execute($stmt1)
or die ("Unable to execute query\n");
$sql = "DECLARE
locator BFILE;
diralias VARCHAR2(30);
filename VARCHAR2(30);
BEGIN
SELECT
mybfile INTO locator
FROM
mylobs
WHERE
id = :id;
-- Get the filename from the BFILE
DBMS_LOB.FILEGETNAME(locator, diralias, filename);
-- Assign OUT params to bind parameters
:diralias:=diralias;
:filename:=filename;
END;";
$stmt2 = oci_parse($conn, $sql);
while ( $row = oci_fetch_assoc ($stmt1) ) {
oci_bind_by_name($stmt2, ":id", $row['ID']);
oci_bind_by_name ($stmt2, ":diralias", $diralias,30);
oci_bind_by_name ($stmt2, ":filename", $filename,30);
oci_execute($stmt2);
print "{$row['ID']}: $diralias/$filename\n";
}
// etc.
?>
또, DBMS_LOB.FILEEXISTS 함수를 사용하면 운영체제에서 삭제되었음에도 불구하고 여전히 데이터베이스에서 참조되고 있는 파일이 무엇인지 확인할 수 있습니다.
결론
이번 연재에서는 Oracle Database 10g에서 사용되는 다양한 종류의 LOB에 대해 설명했습니다. 이제 데이터베이스에 대용량의 데이터를 효과적으로 저장하기 위해 각각의 LOB 타입이 어떻게 활용되는지 이해하셨을 것입니다. 또 PHP OCI8 API를 이용하여 LOB 데이터를 처리하는 방법과, Oracle/PHP 환경에서 자주 발생하는 개발 관련 이슈에 대해서 설명을 드렸습니다.
--------------------------------------------------------------------------------
Harry Fuecks [http://www.phppatterns.com]는 1999년 이후 PHP 개발자 및 기고가로써 활동해 왔습니다. Harry는 Sitepoint 웹 개발자 네트워크와 The PHP Anthology를 통해 PHP에 관련한 기술문서를 기고하고 있습니다.
여러분의 의견을 보내 주십시오
4,000 바이트 제한이 문제가 되십니까? LOB를 활용하십시오...
Downloads for this article:
Oracle Database 10g
Zend Core for Oracle
Apache HTTP Server 1.3 (및 이후 버전)
VARCHAR2와 같은 오라클 데이터 타입은 유용하게 활용됩니다. 하지만 4,000 바이트 이상의 데이터를 저장하려면 어떻게 해야 할까요? 바로 오라클이 지원하는 Long Object (LOB) 데이터 타입이 필요합니다. 또 LOB와 호환하는 PHP API의 사용법을 알고 있어야 합니다. 이에 필요한 지식을 갖고 있지 않은 개발자에게는 무척 까다로운 과제가 될 수 있습니다
이번 “Oracle+PHP Cookbook” 시리즈 연재에서는, LOB 데이터 타입과 PHP에서 LOB를 다루는 방법을 예제를 통해 알아보기로 합니다.
오라클의 Long Object
오라클은 다음과 같은 LOB 데이터 타입을 지원합니다:
BLOB - 바이너리 데이터의 저장에 사용
CLOB - 데이터베이스 문자 셋 인코딩을 이용한 문자 데이터 저장에 사용
NCLOB - 국가별 문자 셋을 이용한 유니코드 문자 데이터 저장에 사용. (본 문서에서 사용되는 PHP OCI8 익스텐션은 NCLOB을 지원하지 않음을 참고하십시오.)
BFILE - 운영체제 파일시스템에 저장된 외부 파일의 참조에 사용
그 밖에도 temporary LOB가 있습니다. temporary LOB는 BLOB, CLOB 또는 NCLOB 등의 형태를 취할 수 있으며, 해제되기 전까지 임시 테이블스페이스에 저장됩니다.
이전 버전의 오라클에서는 문자 및 바이너리 데이터의 저장을 위해 LONG, LONG RAW 타입을 지원했습니다. 이 두 가지 타입은 Oracle9i에서 LOB로 대체되었습니다.
LOB 데이터의 저장. Oracle Database 10g는 BLOB, CLOB, NCLOB 타입에 대해 단일 레코드 당 최대 128TB의 용량을 지원합니다 (실제 최대 용량은 데이터베이스 블록 사이즈와 LOB의 “chunk” 설정에 따라 달라질 수 있습니다.
LOB는 LOB 컨텐트와 LOB 로케이터(locator)의 두 가지 요소로 구성됩니다. LOB 로케이터는 LOB에 대한 “포인터”로 활용됩니다. LOB 로케이터는 LOB 데이터를 효과적으로 저장하고 관리하기 위한 목적에서 설계되었으며, PHP API의 INSERT, UPDATE, SELECT 에도 반영되어 있습니다 (아래 설명 참고)..
오라클은 LOB 레코드의 크기가 4KB를 넘지 않는 경우 LOB 컨텐트를 테이블 내부에 “인라인(in-line)” 형태로 저장합니다. 4KB를 초과하는 LOB는 테이블의 테이블스페이스 내에 아웃오브라인(out-of-line)” 형태로 저장됩니다. 이러한 방법으로 작은 크기의 LOB를 신속하게 조회하는 한편, 큰 LOB 때문에 테이블 스캔 성능이 저하되는 것을 방지할 수 있습니다.
LOB 저장 및 액세스를 위해 메모리 캐싱, 버퍼링과 같은 테크닉을 사용하여 애플리케이션의 성능을 개선할 수 있습니다. 자세한 정보는 오라클 제품문서의 LOB Performance Guidelines와 Oracle Database Application Developer's Guide - Large Objects를 참고하시기 바랍니다.
LOB 관련 제약사항. LOB 타입의 활용에 관련한 몇 가지 제약사항이 존재합니다. 특히 SQL 구문과 관련한 제약사항은 주의할 필요가 있습니다. 아래와 같은 쿼리에서는 LOB 타입을 사용할 수 없습니다.
SELECT DISTINCT
ORDER BY
GROUP BY
또 테이블 JOIN,UNION, INTERSECTION, MINUS 등의 구문에서도 LOB 타입 컬럼을 사용하는 것이 금지되어 있습니다.
그 밖에도 LOB를 프라이머리 키 컬럼으로 사용할 수 없는 등의 여러 가지 제약사항이 존재합니다. 자세한 정보는 Oracle Database Application Developer's Guide - Large Objects를 참고하십시오.
CLOB과 문자 셋
데이터베이스의 디폴트 문자 셋(character set)은 NLS_CHARACTERSET 매개변수를 통해 설정되며, CLOB 타입으로 저장된 텍스트는 이 문자 셋을 이용하여 인코딩 됩니다. 아래 SQL 구문을 이용하여 데이터베이스 문자 셋을 설정하시기 바랍니다:
SELECT value FROM nls_database_parameters WHERE parameter = 'NLS_CHARACTERSET'
현재로서는 PHP가 NCLOB을 지원하지 않으므로, 아래와 같은 방법으로 UTF-8과 같은 유니코드 인코딩을 기본 데이터베이스 문자 셋으로 설정하는 것을 고려해 볼 수 있습니다:
ALTER DATABASE CHARACTER SET UTF8
참고: 기존 데이터 또는 애플리케이션 코드가 다른 문자 셋을 사용하고 있는 경우, 변경 작업이 전체 환경에 미치는 영향을 미리 감안하여야 합니다. 자세한 정보는 Oracle Globalization Support Guide와 An Overview on Globalizing Oracle PHP Applications를 참고하시기 바랍니다.
LOB 데이터의 처리
본 문서에서는 PHP의 OCI8 익스텐션에 초점을 맞추어 설명합니다. 또 오라클에 포함된 DBMS_LOB 패키지는 PL/SQL을 이용한 LOB 처리를 위한 병렬 프로시저 및 함수를 제공하고 있음을 참고하시기 바랍니다.
PHP OCI8 익스텐션은 글로벌 PHP 네임스페이스에 “OCI-Lob”이라 불리는 PHP 클래스를 등록합니다. LOB 타입의 컬럼이 포함된 SELECT 구문이 실행된 경우, PHP는 이 구문을 OCI-Lob 오브젝트 인스턴스에 자동으로 바인딩합니다. OCI-Lob 오브젝트에 대한 참조가 확보되면 load(), save()등의 메소드를 이용하여 LOB 컨텐트를 조회, 수정할 수 있습니다.
사용 가능한 OCI-Lob 메소드는 PHP 버전에 따라 달라집니다. PHP5는 read(), seek(), 그리고 append()등의 메소드를 지원합니다. 이에 대한 PHP Manual 의 설명이 다소 불충분한 감이 있으므로, 지원되는 버전 넘버가 궁금한 경우 아래와 같은 스크립트를 사용해서 검증해 보시기 바랍니다.
foreach (get_class_methods('OCI-Lob') as $method ) {
print "OCI-Lob::$method()\n";
}
?>
PHP 5.0.5가 실행 중인 필자의 시스템에서는 아래와 같은 메소드 리스트가 출력되었습니다:
OCI-Lob::load()
OCI-Lob::tell()
OCI-Lob::truncate()
OCI-Lob::erase()
OCI-Lob::flush()
OCI-Lob::setbuffering()
OCI-Lob::getbuffering()
OCI-Lob::rewind()
OCI-Lob::read()
OCI-Lob::eof()
OCI-Lob::seek()
OCI-Lob::write()
OCI-Lob::append()
OCI-Lob::size()
OCI-Lob::writetofile()
OCI-Lob::writetemporary()
OCI-Lob::close()
OCI-Lob::save()
OCI-Lob::savefile()
OCI-Lob::free()
PHP 4.x OCI8 익스텐션은 전체 LOB의 일괄적인 읽기 및 쓰기만을 지원합니다. PHP5에서는 LOB의 일부 “청크(chung)”만을 읽거나 쓸 수 있으며 setBuffering(),getBuffering() 메소드를 이용한 LOB 버퍼링을 지원합니다. 또 PHP5는 스탠드얼론 함수로 oci_lob_is_equal(), oci_lob_copy()를 지원합니다.
본 문서에서 사용된 예제들은 새로운 PHP5 OCI 함수명을 사용하고 있습니다 (예: oci_parse 대신 OCIParse 사용)예제에서 공통적으로 사용되는 시퀀스와 테이블이 아래와 같습니다:
CREATE SEQUENCE mylobs_id_seq
NOMINVALUE
NOMAXVALUE
NOCYCLE
CACHE 20
NOORDER
INCREMENT BY 1;
CREATE TABLE mylobs (
id NUMBER PRIMARY KEY,
mylob CLOB
)
본 문서의 예제는 대부분 CLOB을 사용하고 있지만, 동일한 로직이 BLOB에도 적용 가능함을 참고하시기 바랍니다.
LOB의 INSERT
LOB의 INSERT 작업을 수행하려면, 먼저 오라클의 EMPTY_BLOB 또는 EMPTY_CLOB 함수를 이용하여 LOB를 초기화해야 합니다. NULL 값을 포함한 LOB는 업데이트할 수 없습니다.
초기화가 완료되면, 컬럼을 PHP OCI-Lob 오브젝트에 바인딩하고 오브젝트의 save() 메소드를 이용하여 LOB 컨텐트를 업데이트합니다.
아래 스크립트는 LOB 타입 데이터의 INSERT 쿼리 수행을 위한 예를 보여주고 있습니다:
// connect to DB etc...
$sql = "INSERT INTO
mylobs
(
id,
mylob
)
VALUES
(
mylobs_id_seq.NEXTVAL,
--Initialize as an empty CLOB
EMPTY_CLOB()
)
RETURNING
--Return the LOB locator
mylob INTO :mylob_loc";
$stmt = oci_parse($conn, $sql);
// Creates an "empty" OCI-Lob object to bind to the locator
$myLOB = oci_new_descriptor($conn, OCI_D_LOB);
// Bind the returned Oracle LOB locator to the PHP LOB object
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_CLOB);
// Execute the statement using , OCI_DEFAULT - as a transaction
oci_execute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
// Now save a value to the LOB
if ( !$myLOB->save('INSERT: '.date('H:i:s',time())) ) {
// On error, rollback the transaction
oci_rollback($conn);
} else {
// On success, commit the transaction
oci_commit($conn);
}
// Free resources
oci_free_statement($stmt);
$myLOB->free();
// disconnect from DB etc.
?>
위 예제에서 트랜잭션을 사용하고 있으며, oci_execute 의 실행과정에서 OCI_DEFAULT 상수를 통해 an oci_commit 또는 oci_rollback를 대기할 것을 지시하고 있습니다. 이는 INSERT 작업이 두 단계(로우의 생성, LOB의 업데이트)로 실행되기 때문입니다.
참고 위에서는 BLOB 타입이 사용되고 있으므로oci_bind_by_name 함수를 호출하는 작업만이 필요합니다:
oci_bind_by_name($stmt, ":mylob_loc", $myLOB, -1, OCI_B_BLOB);
마찬가지로, LOB 타입을 명시하지 않고 문자열을 바인딩할 수도 있습니다;
// etc.
$sql = "INSERT INTO
mylobs
(
id,
mylob
)
VALUES
(
mylobs_id_seq.NEXTVAL,
:string
)
";
$stmt = oci_parse($conn, $sql);
$string = 'INSERT: '.date('H:i:s',time());
oci_bind_by_name($stmt, ':string', $string);
oci_execute($stmt)
or die ("Unable to execute query\n");
// etc.
?>
위와 같은 방법을 사용하면 코드를 대폭적으로 단순화할 수 있습니다. 이러한 방식은 LOB에 기록되는 데이터의 크기가 비교적 작은 경우에 유용합니다. 큰 용량의 파일 컨텐트를 LOB에 스트리밍하고자 하는 경우에는, PHP LOB 오브젝트에 대해 write(), flush() 함수를 호출하고 (전체 파일을 하나의 인스턴스로 메모리에 보관하는 대신) 작은 청크(chunk) 단위로 루프를 돌려 컨텐트를 처리하는 것이 좋습니다.
LOB의 SELECT
LOB 컬럼을 포함하는 데이터를 SELECT 쿼리로 조회하는 경우, PHP는 해당 컬럼을 OCI-Lob 오브젝트에 자동으로 바인딩합니다. 그 예가 다음과 같습니다:
// etc.
$sql = "SELECT
*
FROM
mylobs
ORDER BY
Id
";
$stmt = oci_parse($conn, $sql);
oci_execute($stmt)
or die ("Unable to execute query\n");
while ( $row = oci_fetch_assoc($stmt) ) {
print "ID: {$row['ID']}, ";
// Call the load() method to get the contents of the LOB
print $row['MYLOB']->load()."\n";
}
// etc.
?>
OCI_RETURN_LOBS 상수와 oci_fetch_array()를 함께 사용하여 LOB 오브젝트를 그 값으로 대치하도록 함으로써 작업을 한층 단순화할 수 있습니다:
while ( $row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_LOBS) ) {
print "ID: {$row['ID']}, {$row['MYLOB']}\n";
}
LOB의 UPDATE
LOB를 업데이트하는 경우, 위의 INSERT 구문 예와 마찬가지로 "RETURNING" 커맨드를 사용할 수도 있습니다. 하지만 “SELECT ... FOR UPDATE” 구문을 사용하는 편이 훨씬 간단합니다:
// etc.
$sql = "SELECT
mylob
FROM
mylobs
WHERE
id = 3
FOR UPDATE /* locks the row */
";
$stmt = oci_parse($conn, $sql);
// Execute the statement using OCI_DEFAULT (begin a transaction)
oci_execute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
// Fetch the SELECTed row
if ( FALSE === ($row = oci_fetch_assoc($stmt) ) ) {
oci_rollback($conn);
die ("Unable to fetch row\n");
}
// Discard the existing LOB contents
if ( !$row['MYLOB']->truncate() ) {
oci_rollback($conn);
die ("Failed to truncate LOB\n");
}
// Now save a value to the LOB
if ( !$row['MYLOB']->save('UPDATE: '.date('H:i:s',time()) ) ) {
// On error, rollback the transaction
oci_rollback($conn);
} else {
// On success, commit the transaction
oci_commit($conn);
}
// Free resources
oci_free_statement($stmt);
$row['MYLOB']->free();
// etc.
?>
INSERT의 경우와 마찬가지로, 위 코드는 UPDATE 수행을 위해 트랜잭션을 이용하고 있습니다. 특히 주목해야 할 부분이 truncate()함수를 호출하는 부분입니다. save()를 이용해서 LOB를 업데이트하는 경우, save() 함수는 LOB 컨텐트의 시작 부분에서부터 새로운 데이터의 길이에 해당되는 부분까지만을 업데이트합니다. 따라서 이전의 컨텐트가 여전히 LOB에 남아 있을 수도 있습니다.
PHP 4.x, truncate()함수가 지원되지 않습니다. 따라서 새로운 데이터를 업데이트하기 전에 LOB의 기존 컨텐트를 지우려면 오라클의 EMPTY_CLOB() 함수를 사용해야 합니다.
$sql = "UPDATE
mylobs
SET
mylob = EMPTY_CLOB()
WHERE
id = 2403
RETURNING
mylob INTO :mylob
";
$stmt = OCIParse($conn, $sql);
$mylob = OCINewDescriptor($conn,OCI_D_LOB);
OCIBindByName($stmt,':mylob',$mylob, -1, OCI_B_CLOB);
// Execute the statement using OCI_DEFAULT (begin a transaction)
OCIExecute($stmt, OCI_DEFAULT)
or die ("Unable to execute query\n");
if ( !$mylob->save( 'UPDATE: '.date('H:i:s',time()) ) ) {
OCIRollback($conn);
die("Unable to update lob\n");
}
OCICommit($conn);
$mylob->free();
OCIFreeStatement($stmt);
BFILE에 대한 작업 수행
BFILE 타입에 대해 INSERT 또는 UPDATE를 수행하는 경우, 오라클은 (웹 서버가 아닌) 데이터베이스 서버 운영체제의 파일시스템에서 저장된 파일의 위치를 지정하는 작업을 수행하게 됩니다. 또 SELECT 구문을 이용하여 BILE의 컨텐트를 읽어 들이거나, 필요한 경우 DBMS_LOB 패키지의 함수와 프로시저를 호출하여 파일에 대한 정보만을 확인할 수도 있습니다.
BFILE은 파일시스템에 저장된 파일을 직접 액세스하는 한편으로 SQL 구문을 이용하여 파일의 위치를 확인할 수 있게 한다는 장점을 제공합니다. 예를 들어 웹 서버에서 이미지를 직접 제공하면서, BFILE을 포함한 테이블과 다른 테이블과의 관계 정보를 추적하는 것이 가능합니다 (한 예로, 어떤 사용자가 어떤 파일을 업로드했는지 확인할 수 있습니다).
위에서 사용된 테이블 스키마를 먼저 업데이트해 보겠습니다;
ALTER TABLE mylobs ADD( mybfile BFILE )
그런 다음, 오라클에 디렉토리 앨리어스(alias)를 등록하고(이 과정에서 관리자 권한이 필요합니다), 테이블에 대한 읽기 권한을 할당합니다:
CREATE DIRECTORY IMAGES_DIR AS '/home/harryf/public_html/images'
GRANT READ ON DIRECTORY IMAGES_DIR TO scott
이제 아래와 같이 BFILE의 INSERT 작업을 수행할 수 있습니다:
// etc.
// Build an INSERT for the BFILE names
$sql = "INSERT INTO
mylobs
(
id,
mybfile
)
VALUES
(
mylobs_id_seq.NEXTVAL,
/*
Pass the file name using the Oracle directory reference
I created called IMAGES_DIR
*/
BFILENAME('IMAGES_DIR',:filename)
)";
$stmt = oci_parse($conn, $sql);
// Open the directory
$dir = '/home/harryf/public_html/images';
$dh = opendir($dir)
or die("Unable to open $dir");
// Loop through the contents of the directory
while (false !== ( $entry = readdir($dh) ) ) {
// Match only files with the extension .jpg, .gif or .png
if ( is_file($dir.'/'.$entry) && preg_match('/\.(jpg|gif|png)$/',$entry) ) {
// Bind the filename of the statement
oci_bind_by_name($stmt, ":filename", $entry);
// Execute the statement
if ( oci_execute($stmt) ) {
print "$entry added\n";
}
}
}
필요한 경우, CLOB을 조회한 것과 동일한 방법으로 오라클에서 BFILE을 읽어 들일 수 있습니다. 또는 아래와 같이 DBMS_LOB.FILEGETNAME 프로시저를 통해 파일 이름만을 확인한 후 파일시스템에서 직접 액세스하는 방법을 사용할 수도 있습니다:
// etc.
$sql = "SELECT
id
FROM
mylobs
WHERE
-- Select only BFILES which are not null
mybfile IS NOT NULL;
$stmt1 = oci_parse($conn, $sql);
oci_execute($stmt1)
or die ("Unable to execute query\n");
$sql = "DECLARE
locator BFILE;
diralias VARCHAR2(30);
filename VARCHAR2(30);
BEGIN
SELECT
mybfile INTO locator
FROM
mylobs
WHERE
id = :id;
-- Get the filename from the BFILE
DBMS_LOB.FILEGETNAME(locator, diralias, filename);
-- Assign OUT params to bind parameters
:diralias:=diralias;
:filename:=filename;
END;";
$stmt2 = oci_parse($conn, $sql);
while ( $row = oci_fetch_assoc ($stmt1) ) {
oci_bind_by_name($stmt2, ":id", $row['ID']);
oci_bind_by_name ($stmt2, ":diralias", $diralias,30);
oci_bind_by_name ($stmt2, ":filename", $filename,30);
oci_execute($stmt2);
print "{$row['ID']}: $diralias/$filename\n";
}
// etc.
?>
또, DBMS_LOB.FILEEXISTS 함수를 사용하면 운영체제에서 삭제되었음에도 불구하고 여전히 데이터베이스에서 참조되고 있는 파일이 무엇인지 확인할 수 있습니다.
결론
이번 연재에서는 Oracle Database 10g에서 사용되는 다양한 종류의 LOB에 대해 설명했습니다. 이제 데이터베이스에 대용량의 데이터를 효과적으로 저장하기 위해 각각의 LOB 타입이 어떻게 활용되는지 이해하셨을 것입니다. 또 PHP OCI8 API를 이용하여 LOB 데이터를 처리하는 방법과, Oracle/PHP 환경에서 자주 발생하는 개발 관련 이슈에 대해서 설명을 드렸습니다.
--------------------------------------------------------------------------------
Harry Fuecks [http://www.phppatterns.com]는 1999년 이후 PHP 개발자 및 기고가로써 활동해 왔습니다. Harry는 Sitepoint 웹 개발자 네트워크와 The PHP Anthology를 통해 PHP에 관련한 기술문서를 기고하고 있습니다.
여러분의 의견을 보내 주십시오
'Web Dev > PHP' 카테고리의 다른 글
| 오픈소스 프로젝트에 참여하고 싶어요 (11) | 2006/10/23 |
|---|---|
| 젠드 프레임워크 0.1.3 (0) | 2006/04/19 |
| The Oracle + PHP Cookbook :: Oracle/PHP 환경의 LOB 처리 (0) | 2006/04/06 |
| PHP를 Eclipse로 개발하기(PHPEclipse) - 2. 설정편 (7) | 2006/03/21 |
| Linux 및 Windows 환경을 위한 PHP, Oracle 10g Instant Client 설치 (1) | 2006/03/13 |
| PHP를 Eclipse로 개발하기(PHPEclipse) - 1. 설치편 (7) | 2006/02/24 |
주의! 이 포스트는 오래되어 최근의 환경과 맞지 않을 수 있습니다. 또한 퍼가기를 허락하지 않으니 링크로 걸어주시기 바랍니다.
들어가기 앞서저의 짧은 글 실력과 대충 날림으로 적은 강좌에 많은 분들의 호응에 감사드립니다. 이번 강좌도 이전것과 별반 다르지는 않지만, 기다리시는 분들이 있는것 같아 주저주저하면서도 올리게됩니다. 많은 분들이 이클립스를 사용해 개발시간을 줄이고 또 함께 피드백 하면서 PHP를 발전시켜나갔으면 좋겠습니다. 감사합니다. 강좌에서는 1편과 같이 존칭을 생략합니다.
PHP를 Eclipse로 개발하기 - 2 설정편
1. 폰트 변경하기
PHPSchool에 올라온 글 중에 '프로그래머에게 적합한 폰트' 이라는 글이 있었다. 개발자들이 가장 많이 쓴다는 BitStream vera sans Mono 로 폰트를 변경해보자. [다운로드]
압축을 풀고 VeraMono.ttf 파일을 설치한다. (설치 방법은 생략)
Window->Preferences항목을 선택하면 Preferences창이 열린다. 앞으로의 모든 설정은 이곳에서 하게될 것이다.
가장 위의 General - Appearance - Color and fonts를 선택하면 이클립스 플러그인 들의 폰트나 색상을 지정해 줄 수 있는 화면이 나온다.
가장 위의 Basic에서 Text Font를 선택하고 Change Font버튼을 누른다. 글꼴 창에서 Bitstream VeraSans Mono를 고르고 확인을 눌러주면 폰트가 바뀐다. 그 후 OK를 눌러준다.
기본 에디터 폰트 바꾸기
간단하게 에디터의 폰트가 바뀐것을 확인할 수 있을 것이다.
2. 코드 템플릿 바꾸기
새로운 PHP파일을 생성하면,
<php
/*
* Created on 2006. 3. 6
*
* To change the template for this generated file go to
* Window - Preferences - PHPeclipse - PHP - Code Templates
*/
?>
이런 식의 주석이 붙어있을 것이다. 이 문구는 주석에 나와있는 대로 Window - Preferences - PHPeclipse WebDevelopment - PHP - Code Templates 에서 바꿀 수 있다. 한번 바꿔보도록 하자.
Filter를 이용해 빨리 찾아가기.
이번에는 클릭을 반복하여 여는 대신, Filter를 이용해 빠르게 열어보도록 한다. 우선 Windows - Preferences를 열어보면 가장 상단에 type filter text 라는 텍스트박스를 볼 수 있다. 여기에 code template이라고 입력하면 트리메뉴가 필터링 되면서 빠르게 찾아지게된다. code template이라는 이름을 가진 것이 자바에 1개, PHP 에 1개가 있을 것이다. PHPeclipse 아래에 있는 code template을 선택한다.
코드템플릿 찾아가기
오른쪽의 트리 중 New PHP files를 선택하고 Edit버튼을 눌러주면 템플릿을 수정할 수 있는 창이 나온다. 이곳에서 자신이 원하는 템플릿을 넣어줄 수 있다. 나의 경우에는
<?php
/**
* Created on ${date}
* Author: Kim HyunJin (loveisfunny-at-gmail.com)
*/
?>
이렇게 넣었다.
코드템플릿 변경완료!
3. 레퍼런스 연결하기
개발 중에 가장 많이 들춰보아야 하는 것이 바로 레퍼런스가 아닐까 싶다. PHP 레퍼펀스는 이곳에서 얻을 수 있다.
파일을 다운로드 했으면 이제 레퍼런스를 이클립스에 연결시켜 빠르게 열 수 있는 방법을 알아보자.
..
레퍼런스는 이렇게 설정해준다.
Preferences 창에서 Help(WIN_32 *.chm format) 항목을 클릭한다. 그리고 방금 다운받은 chm파일의 경로를 적어주면 된다. 물론 Browse버튼을 클릭하면 탐색기에서 찾아 넣을 수 있다. 경로 위의 Show help in *.chm format? 이라는 체크박스를 선택해주면 chm파일을 직접 열어서 참고 할 수 있으므로 체크해두도록 하자. 체크 하지 않으면 이클립스 도움말 안에 삽입되어 같이 보여진다.(조금 불편하다) 이같이 설정해두면 앞으로 레퍼런스 파일은 Ctrl+Shift+h단축키로 열어볼 수 있다.
4. XAMPP와 연결하기
PHPEclipse에서 공식 지원하는 아파치 웹서버인 XAMPP를 설정해보겠다. XAMPP는 아파치재단에서 공식 후원하는 프로그램(Apache Friends)이다. 기본적으로 Apache 2.X, PHP 5.X, PHP 4.3.X, MySQL 5.X대를 지원한다. 특히나 PHP는 4와 5버젼이 동시에 설치되어 언제라도 다른 버전을 띄울 수 있도록 Switcher를 제공한다. 마지막으로 모든 (Stable) PEAR패키지를 한꺼번에 제공하므로 따로 다운로드 받을 필요가 없다는 장점이 있다. 연결되게되면 서버를 이클립스에서 아이콘 클릭만으로 시작/정지 할 수 있다.
지금까지 APMSETUP으로만 작업해왔던 개발자라면 한번쯤 바꿔보는 것도 좋다는 생각이 들어 장황하게 설명했다;;
글을 올린 시점의 XAMPP 사양은 이렇게 된다.
MySQL 5.0.18
Apache 2.2.0
PHP 5.1.1
phpMyAdmin 2.7.0 pl1
XAMPP 윈도우용은 이곳에서 다운받을 수 있다. [다운받기]
주의! 기존에 운용하던 아파치 서버(APMSETUP 등)가 있다면 끄고 XAMPP 서버를 켜도록 하자. 두개를 동시에 실행시키면 포트 충돌이 일어날것이다.
설치과정은 무척 간단하다. Next를 계속클릭하고 Finish를 날려주면 끝난다. 설치가 끝났으면 연결해보자.
xampp와 연결하기
Preferences - PHPeclipse WebDevelopment - PHP external tools 의 XAMPP를 선택한다. XAMPP설치 시에 경로 설정을 따로 하지 않았다면 기본적으로 XAMPP는 c:\Program Files\xampp\에 설치된다. XAMPP start는 c:\Program Files\xampp\xampp_start.exe 로 설정해 주고, XAMPP stop은 c:\Program Files\xampp\xampp_stop.exe로 설정해 준다.
이제는 기본 아이콘에 있는 XAMPP START/XAMPP STOP 만으로 XAMPP를 시작/정지 할 수 있다. 두 버튼 모두 클릭 후에 콘솔이 열리면서 정상실행, 종료를 확인 할 수 있다.
5. UTF-8환경 만들기
요즘 프로젝트의 대세는 UTF-8이라 생각한다. UTF-8이 EUC-KR갖는 장점은 참 많지만 여기서는 논외로 하자. (사실은 논란에 휩싸이기 싫다..) 이클립스가 처음 설치되었을 때 인코딩은 MS949인데, 이것을 변경시켜보자. 인코딩 변경은 세곳에서 가능하다. 1. Preferences에서의 이클립스 기본 인코딩을 변경시키기. 2. Project속성에서 프로젝트 만의 기본인코딩을 변경시키기. 3. 파일 속성에서 파일만의 인코딩을 변화시키기. 눈치 챘겠지만 레벨 개념과 비슷하다. 1번을 변경시키면 앞으로 생성되는 모든
