기술빙자사기

리눅스 centos5에 오라클 10g 설치및 php 연동

권성재 2011. 8. 25. 18:01
### 쓴것 : 리눅스 centos5에 오라클 10g 설치및 php 연동 
### 쓴때 : 2011-07-04 
### 쓴이 : 권성재 (nonots@hanmail.net

1. 시작하며 

2002년 월드컵 이후 오라클과 인연이 더이상 없을줄 알았는데 
10g 짜리를 또 만지는 사태가 벌어졌다. 
다행히 옛날 8i 시절과는 다르게 엑스윈도우나 자바 가상머신등에 
신경쓰지 않고도 쉽게 설치가 되는 rpm 버전으로 배포가 된다는 점. 
또 php 연동도 아파치와 php 전체를 새로 컴파일 할 필요없이 
보통 DSO 로 모듈을 사용하므로 간단하게 phpize 해서 
oci8 모듈 추가가 가능하다는 점. 
그리고 요즘 서버 하드웨어 사양이 좋아져서 리눅스 커널 값 수정에 
그리 신경안써도 된다는 점 등등..  여러 가지가 좋은 점도 있지만 
오라클이란 건 한번 만지기 시작하면 사람을 열받게 하는 재주가 있다. 
어제 오늘, 장마철 열받으며 삽질한 이 기록으로 
다른 사람의 삽질량이 줄어 들지는 내 관심사 아니다. 


2. 사용환경 및 사전 작업 
- 서버 사양 : CPU 64비트, 2기가 메모리 
- OS 사양 : 리눅스 centos 5.6 x86_64, 아파치웹서버2.2, php 5.2.17(RPM 설치) 
- 오라클 : 다국어 rpm 버전 10.2.0.1 


2. 오라클 설치 

1) 사전 작업 
배포하는 오라클은 32비트환경에서 컴파일된 거라서 64비트 리눅스 서버에서는 
그냥 설치가 안된다. 서버가 32 비트라도 오라클을 컴퍼일한 glibc 버전등이 
오래되서 역시 문제가 될 소지가 있으므로 라이브러리 호환을 위한 별도 
rpm 패키지를 설치해야 한다. 
보통 compat- 으로 시작하는 패키지들이 필요하다. 

[root@home3 ~]# rpm -qa |grep -i compat- 
compat-libstdc++-33-3.2.3-61 
compat-glibc-2.3.4-2.26 
compat-libcom_err-1.0-7 
compat-db-4.2.52-5.1 
compat-libstdc++-296-2.96-138 
compat-glibc-headers-2.3.4-2.26 
compat-libgcc-296-2.96-138 
compat-gcc-34-3.4.6-4.1 
compat-glibc-2.3.4-2.26 
compat-libcom_err-1.0-7 
compat-gcc-34-c++-3.4.6-4.1 
compat-db-4.2.52-5.1 
compat-libstdc++-33-3.2.3-61 
이런 것들도 필요하고 libaio libaio-devel 도 필요하고 
기타 php 연동 컴파일을 위한 gcc, gcc-c++, make, glibc-devel, php-devel,php-pear 같은 
패키지도 당연히 있어야 한다. 
그리고 오라클에서 기본쉘로 사용하는 ksh 나 pdksh 도 설치한다. 
리눅스 설치시  최소 설치만 했다면 오라클 rpm 설치를 위해 의존성 걸리는거 
해결하기 위해 여러가지 추가 로 설치해야 할꺼다. 


2) 다운로드 : 
  http://www.oracle.com/technetwork/database/express-edition/downloads/102xelinsoft-102048.html 
에서 다국어 버전 oracle-xe-univ-10.2.0.1-1.0.i386.rpm  를 다운받는다 
그냥 rpm 설치하면 된다. 

[root@home3 ~]# rpm -Uvh oracle-xe-univ-10.2.0.1-1.0.i386.rpm 
준비 중...                  ########################################### [100%] 
  1:oracle-xe-univ        ########################################### [100%] 
Executing Post-install steps... 
You must run '/etc/init.d/oracle-xe configure' as the root user to 
configure the database. 

이렇게 별 문제 없이 설치가 되면 oracle-xe configure 를 실행하라고 나온다. 
실행한다. 

[root@home3 ~]# /etc/init.d/oracle-xe configure 

Oracle Database 10g Express Edition Configuration 
------------------------------------------------- 
This will configure on-boot properties of Oracle Database 10g Express 
Edition.  The following questions will determine whether the database should 
be starting upon system boot, the ports it will use, and the passwords that 
will be used for database accounts.  Press <Enter> to accept the defaults. 
Ctrl-C will abort. 

Specify the HTTP port that will be used for Oracle Application Express [8080]: (엔터) 
Specify a port that will be used for the database listener [1521]: (엔터) 
Specify a password to be used for database accounts.  Note that the same 
password will be used for SYS and SYSTEM.  Oracle recommends the use of 
different passwords for each database account.  This can be done after 
initial configuration: (시스템 비밀번호 입력) 
Confirm the password:  (비번 재입력) 
Do you want Oracle Database 10g Express Edition to be started on boot (y/n) 
[y]: y 

Starting Oracle Net Listener...Done 
Configuring Database...Done 
Starting Oracle Database 10g Express Edition Instance...Done 
Installation Completed Successfully. 
To access the Database Home Page go to "http://127.0.0.1:8080/apex" 
[root@home3 ~]# 

오라클이 설치가 되면 기본 $ORACLE_HOME 위치는 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server 가 된다. 
나중에 php 컴파일을 위한 $LD_LIBRARY_PATH 는 $ORACLE_HOME/lib 디렉토리가 된다. 
오라클을 사용하려면 이런 환경변수를 인식해야 한다. 
이 환경변수는 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/oracle_env.sh 파일을 
읽어들여한다. 

[root@home3 ~]#cd /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin 
[root@home3 bin]# . ./oracle_env.sh 
와 같이 한번 해주고. 
루트가 로그인할 때 자동인식하려면 
[root@home3 bin]# cat ./oracle_env.sh  >> ~/.bashrc 
와 같이 파일에 추가해준다. 
.bashrc 뿐만 아니라 나중에 아파치 웹서버와도 연동해야하므로 
/etc/init.d/httpd 파일 상단 적당한 곳에 oracle_env.sh 파일의 내용을 
적어주는 것도 좋다. 

이제 아래 방식으로 오라클을 중시,시작하면 된다. 다시 중지 후 시작해본다. 
시작시 좀 오래 걸린다. 
[root@home3 ~]# /etc/init.d/oracle-xe stop 
Shutting down Oracle Database 10g Express Edition Instance. 
Stopping Oracle Net Listener. 
[root@home3 ~]# /etc/init.d/oracle-xe start 
Starting Oracle Net Listener. 
Starting Oracle Database 10g Express Edition Instance. 

이제 sqlplus 접속을 해본다. 

[root@home3 ~]# sqlplus sys/비번 as sysdba 
SQL*Plus: Release 10.2.0.1.0 - Production on 화 7월 5 12:18:34 2011 
Copyright (c) 1982, 2005, Oracle.  All rights reserved. 
다음에 접속됨: 
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production 
SQL> select * from tab; 
.. 
FLOW_SQLAREA     VIEW 
FLOW_SGA     VIEW 
3528 개의 행이 선택되었습니다. 
SQL> exit;  
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production에서 
분리되었습니다. 

위와같이 되면 일단 오라클 설치는 된거다. 
그런데 간혹 sqlplus 실행을하면 

ORA-27121: unable to determine size of shared memory segment 
SVR4 Error: 13: Permission denied 
이런 에러가 나고 sqlplus 접속이 안되는 경우가 있다 이때는 

chmod 6751 $ORACLE_HOME/bin/oracle 
와 같이 oracle 이라는 명령어 자체의 퍼미션을 변경해 준다. 

그리고 위에서 "http://127.0.0.1:8080/apex" 웹브라우저로 접속 
가능하다고 했는데 이건 로컬에서만 가능하다. 
원격에서 접속하려면, 
만약 방화벽 있다면 방화벽에서 8080 포트 열어주고 
sqlplus 에 접속해서 

SQL>EXEC DBMS_XDB.SETLISTENERLOCALACCESS(FALSE); 

와 같이 외부 접속을 가능하게 해줘야 한다. 
만약  8080 포트가 아니라 다른 포트 쓰려면 
SQL>EXEC DBMS_XDB.SETHTTPPORT(원하는포트번호); 
와 같이 해주고 
오라클을 재시작하면 이제 외부에서 웹브라우저로 접속가능하다. 
마치 phpmyadmin 같이 오라클을 관리가능하다. 참 편리한 기능이다. 

여기까지 됐다면 거의 다 된거다. 
만약 원인 모를 에러가 있다면 로그파일을 보고 해결한다. 
로그파일은 
$ORACLE_HOME/log 
$ORACLE_HOME/config/log 
$ORACLE_HOME/network/log 
특히 network/log 에 있는건 리스너 로그이다. 잘 본다. 

서버 프로세스를 보면 
[root@home3 ~]# ps aux |grep -i ora 
oracle  11151  0.0  0.1  66076  6128 ?        Ss  12:33  0:00 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin/tnslsnr LISTENER 
-inherit 
oracle  11159  0.0  0.3 870304 10244 ?        Ss  12:33  0:00 xe_pmon_XE 
oracle  11161  0.0  0.2 869732  8852 ?        Ss  12:33  0:00 xe_psp0_XE 
oracle  11163  0.0  0.7 869732 24224 ?        Ss  12:33  0:00 xe_mman_XE 
oracle  11165  0.0  0.3 871804 11472 ?        Ss  12:33  0:00 xe_dbw0_XE 
oracle  11167  0.0  0.9 885284 28240 ?        Ss  12:33  0:00 xe_lgwr_XE 
oracle  11169  0.0  0.4 869736 14108 ?        Ss  12:33  0:00 xe_ckpt_XE 
oracle  11171  0.0  1.4 870268 44372 ?        Ss  12:33  0:00 xe_smon_XE 
oracle  11173  0.0  0.4 869732 14108 ?        Ss  12:33  0:00 xe_reco_XE 
oracle  11175  0.0  0.6 871336 20504 ?        Ss  12:33  0:00 xe_cjq0_XE 
oracle  11177  0.1  1.3 872388 42844 ?        Ss  12:33  0:00 xe_mmon_XE 
oracle  11179  0.0  0.3 869732  9892 ?        Ss  12:33  0:00 xe_mmnl_XE 
oracle  11181  0.0  0.2 870240  9000 ?        Ss  12:33  0:00 xe_d000_XE 
oracle  11183  0.0  0.2 870300  8692 ?        Ss  12:33  0:00 xe_s000_XE 
oracle  11185  0.0  0.2 870300  8684 ?        Ss  12:33  0:00 xe_s001_XE 
oracle  11187  0.0  0.2 870300  8684 ?        Ss  12:33  0:00 xe_s002_XE 
oracle  11189  0.0  0.2 870300  8688 ?        Ss  12:33  0:00 xe_s003_XE 
oracle  11212  0.0  0.3 869732  9952 ?        Ss  12:33  0:00 xe_qmnc_XE 
oracle  11225  0.0  0.3 869728 11024 ?        Ss  12:33  0:00 xe_q000_XE 
oracle  11238  0.0  0.3 869728  9272 ?        Ss  12:34  0:00 xe_q001_XE 

와 같고 서버 포트는 
[root@home3 ~]# lsof -i 
.. 
tnslsnr  11151  oracle  12u  IPv4 573561      TCP *:ncube-lm (LISTEN) 
tnslsnr  11151  oracle  14u  IPv4 573787      TCP home3.aaa.co.kr:ncube-lm->home3.aaa.co.kr:12630 (ESTABLISHED) 
tnslsnr  11151  oracle  15u  IPv4 573995      TCP *:webcache (LISTEN) 
oracle    11159  oracle  16u  IPv4 573655      UDP localhost.localdomain:elad 
oracle    11159  oracle  17u  IPv4 573786      TCP home3.aaa.co.kr:12630->home3.aaa.co.kr:ncube-lm (ESTABLISHED) 
oracle    11181  oracle  15u  IPv4 573777      UDP localhost.localdomain:52881 
oracle    11181  oracle  187u  IPv4 573780      TCP *:64308 (LISTEN) 
oracle    11183  oracle  15u  IPv4 573795      UDP 

와 같이 열려있음을 알수 있다.  여기까지 대강 설치가 됐다. 
사용자 추가와 테스트 테이블 사용은 위의 apex 웹모드를 사용해도 되고 
sqlplus 로 직접 입력해도 된다. 간단한 nonots 사용자를 추가하고 
member 이라는 테이블을 만들어 본다. 

[root@home3 bin]# sqlplus sys/비번 as sysdba 
SQL*Plus: Release 10.2.0.1.0 - Production on 월 7월 4 20:45:27 2011 
Copyright (c) 1982, 2005, Oracle.  All rights reserved. 
다음에 접속됨: 
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production 
SQL> create user nonots identified by mypassword 
default tablespace users 
temporary tablespace temp; 
사용자가 생성되었습니다. 
SQL> grant connect,resource to nonots; 
권한이 부여되었습니다. 
SQL> commit; 
커밋이 완료되었습니다. 
SQL> quit 
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production에서 
분리되었습니다. 

[root@home3 bin]# sqlplus nonots/mypassword 
SQL*Plus: Release 10.2.0.1.0 - Production on 월 7월 4 20:46:13 2011 
Copyright (c) 1982, 2005, Oracle.  All rights reserved. 
다음에 접속됨: 
Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production 
SQL> create table member ( id number ,username varchar2(30)); 
테이블이 생성되었습니다. 

SQL> insert into member (id,username) values(1,'일좀해라'); 
1 개의 행이 만들어졌습니다. 
SQL> insert into member ( id,username) values(2,'PHP슥훌만세'); 
1 개의 행이 만들어졌습니다. 
SQL> select * from member;  
ID USERNAME 
---------- ------------------------------------------------------------ 
1 일좀해라 
2 PHP슥훌만세 
SQL> 


3. PHP 연동 
차라리 오라클 설치는 쉽다. php 모듈만 컴파일해서 추가하는게 
의외로 사람 열받게 했다. 
방법은 http://pecl.php.net/package/oci8  여기서 
최신 소스를 가져와서 컴파일해서 oci8.so 파일을 만든후 
php.ini 등에서 extention 항목에 추가해 주고 웹서버 재시작하면 된다. 

그런데 가장 큰 문제가, 설치한 오라클의 라이브러리로는 최근 
php 모듈 컴파일이 안된다는 점이다. 이걸 해결하기 위해서는 
http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html 
에서 환경에 맞는 인스턴트 클라이언트라는 걸 다운받아야 한다. 
위 링크에서 리눅스 64 비트에서 오라클 버전 10 에서 최신인 
Version 10.2.0.5  에 있는 
basic-10.2.0.5.0-linux-x64.zip, sdk-10.2.0.5.0-linux-x64.zip 
2개 파일을 다운받는다. 둘다 압축을 풀면 동일하게 
instantclient_10_2 디렉토리가 생긴다. 날짜를 보면 오라클 lib에 있는 .so파일들 보다 
더 최근에 생성된 것을 알수 있다. 
이 디렉토리를 적당한 곳으로 옮긴다.  예를 들면, 이 instantclient_10_2 를 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib_tmp 
라고 변경한다. 
즉 오라클 자체는 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib/libclntsh.so 등을 사용하고 
php 모듈 컴파일을 위해서는 다운받은 instantclient의 
/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib_tmp/libclntsh.so 
같은 so 파일을 사용한다는 뜻이다. 
아래에서 php  oci8 컴파일을 할때 --with-oci8 옵션을 이 위치로 지정해 준다. 

1)방법 :  pecl install oci8 
보통 이 방법이 가장 간단한데 내 경우 안됐다. 

[root@home3 tmp]# pecl install oci8 
downloading oci8-1.4.5.tgz ... 
Starting to download oci8-1.4.5.tgz (154,284 bytes) 
.........................done: 154,284 bytes 
10 source files, building 
running: phpize 
Configuring for: 
PHP Api Version:        20041225 
Zend Module Api No:      20060613 
Zend Extension Api No:  220060519 
/usr/bin/phpize: /tmp/tmpLFrGmq/oci8-1.4.5/build/shtool: /bin/sh: bad 
interpreter: 허가 거부됨 
Cannot find autoconf. Please check your autoconf installation and the 
$PHP_AUTOCONF environment variable. Then, rerun this script. 
ERROR: `phpize' failed 

와 같이 에러가 나면서 실패했는데. 
원인은 서버 보안을 위해서 /tmp 를 별로 파티션으로 잡고 마운트했는데 
보안때문에 마운트할 때 noexec 니 nosuid 같은 옵션을 줘서 
/tmp 에서 컴파일 등이 제한된다. pecl 이 이 다운받은 파일을 /tmp 
아래에서 압축풀어 컴파일하려고 하기 때문에 실패한것으로 추정된다. 
이런 제한없는 다른 서버에서는 간단하게 모듈 컴파일 될것이다. 
아님말고. 


2)방법 :  직접 컴파일 
위 경로에서 최신버전 oci-81.4.5.tgz 을 가져와 
압축을 풀고  phpize 를 실행한다. 
[root@home3 oci8-1.4.5]# phpize 
[root@home3 oci8-1.4.5]# ./configure --with-oci8=instantclient,/usr/lib/oracle/xe/app/oracle/product/10.2.0/server/lib_tmp 
[root@home3 oci8-1.4.5]# make 혹은 make install 

정상적으로 컴파일 된다면 ./modules/oci8.so 라는 파일이 만들어 진다. 
이 파일을 php 모듈디렉토리에 
복사하고 php.ini 에서 extension항목에 넣어준다. 
make install 하면 저절로 oci8.so 를 복사할 것이다. 

이제 웹서버를 재시작한다. 에러 로그파일을 보고 특별한 이상이 없으면 
된거다.  확인하려면 phpinfo() 화면을 보거나 

[root@home3 ~]# php -i |grep oci8 
/etc/php.d/oci8.ini, 
oci8 
oci8.connection_class => no value => no value 
oci8.default_prefetch => 100 => 100 
oci8.events => Off => Off 
oci8.max_persistent => -1 => -1 
oci8.old_oci_close_semantics => Off => Off 
oci8.persistent_timeout => -1 => -1 
oci8.ping_interval => 60 => 60 
oci8.privileged_connect => Off => Off 
oci8.statement_cache_size => 20 => 20 

와 같이 나오면 된거다.  이제 oci php 함수로 사용하면 된다. 
위에서 nonots 사용자가 만든 MEMBER 테이블을 불러와 보면 

[root@home3 tmp]# cat ora.php 
<?php 
// 아래 127.0.0.1/XE 이부분은 리스너 참조, 다를수 있음 
$conn = oci_connect('nonots', 'mypassword', '127.0.0.1/XE'); 
if (!$conn) { 
$e = oci_error(); 
trigger_error(htmlentities($e['message'], ENT_QUOTES), E_USER_ERROR); 

$stid = oci_parse($conn, 'SELECT * FROM MEMBER WHERE ROWNUM < 3'); 
oci_execute($stid); 
$nrows = oci_fetch_all($stid, $res); 
echo "$nrows rows fetched<br>\n"; 
echo '<pre>'; 
var_dump($res); 
?> 

실행 결과는 
2 rows fetched 
array(2) { 
  ["ID"]=> 
  array(2) { 
[0]=> 
string(1) "1" 
[1]=> 
string(1) "2" 
  } 
  ["USERNAME"]=> 
  array(2) { 
[0]=> 
string(8) "일좀해라" 
[1]=> 
string(8) "PHP슥훌만세" 
  } 

와 같이 되면 성공한거다. 


4. 마무리 
덜 마른 빨래에서 쿰쿰한 역겨운 냄새가 난다. 
다시 하나 마나.