TIP게시판

제목 euc-kr 환경의 웹페이지 + oracle 바인딩 & 버그수정
글쓴이 초원을달리는유부남 작성시각 2010/01/14 14:19:48
댓글 : 2 추천 : 0 스크랩 : 0 조회수 : 22084   RSS

안녕하세요. 매일 질문만 던져서 답반 가져가는 초원을 달리는 유부남 인사드립니다. :)
사실 노하우를 오픈한다기 보다도 스스로 다음에 또 해결해야 할 일이 생길 것 같아서,
기록 형식으로 남기겠습니다.

CodeIgniter는 utf-8 환경에서 돌아가도록 되어 있습니다.
application/config/config.php 파일을 보게 되면, 다른 문자셋 환경을 지원하려는 방향성은 갖고 있지만, 결과적으로 아직 그 목적을 달성하진 못한 듯 합니다. 회사가 이미 시스템이 euc-kr 환경으로 구축되어져 있고, 공통된 무언가가 존재한다면, 공통된 무언가의 지원을 받기 위해서는, euc-kr 환경이 반드시 필요하며, 이런 경우에서만 아래 방법으로 해결할 수 있지만, 이런 경우가 아니라면 utf-8 환경에서 개발하는 것을 적극 추천하는 바입니다.


** 인코딩셋 관련 설정

    * application/config/config.php 내용 수정

        euc-kr 환경을 코드이그나이트 문서의 가이드에 따라 아래처럼 설정 합니다.

$config['charset'] = "euc-kr";



** 인코딩셋 관련 문제 해결

    * system/libraries/URI.php 생성자 함수(49라인)에 내용 추가

        URL은 kirrie 님이 이미 기록한 문서(http://codeigniter-kr.org/tip/view/240/page/1/q/euc-kr)에서도
        나타나듯이, 웹브라우저에서 utf-8 문자셋으로 변환하여, 웹서버에 전송하도록 되어 있습니다.
        따라서 전송된 정보에서 해당 내용을 모두 해당 문자셋으로 변경하도록 해야 합니다.
        왜냐하면, CodeIgniter는 URI를 GET으로 전달된 QUERY_STRING과 같은 의미로 사용하기 때문입니다.
        아래 구문을 생성자 함수에 추가합니다.

        if (($charset = $this->config->item('charset')) != 'utf-8')
        {
            if (isset($_SERVER['PATH_INFO'])) {
                $_SERVER['PATH_INFO'] = iconv('utf-8', $charset, $_SERVER['PATH_INFO']);
            }
            if (isset($_SERVER['PHP_SELF'])) {
                $_SERVER['PHP_SELF'] = iconv('utf-8', $charset, $_SERVER['PHP_SELF']);
            }
            if (isset($_SERVER['PATH_TRANSLATED'])) {
                $_SERVER['PATH_TRANSLATED'] = iconv('utf-8', $charset, $_SERVER['PATH_TRANSLATED']);
            }
            if (isset($_SERVER['REQUEST_URI'])) {
                $_SERVER['REQUEST_URI'] = iconv('utf-8', $charset, $_SERVER['REQUEST_URI']);
            }
        }



** 오라클 관련 버그 수정하기

    * system\database\drivers\oci8\oci8_driver.php

        ocierror() 함수는 한번 사용하면, 결과 리턴 후에는 해당 리소스가 사라지는 것에서 생긴 문제와,
        해당 함수에 들어가는 인자 부분이 연결정보가 아닌 stmt_id 정보가 아닌 부분에서 오류가 있었습니다.
 

        74라인에 전역변수 추가

        var $error = array();


        _error_message()와 _error_number() 메소드 수정하기

        function _error_message()
        {
                if (!isset($this->error[$this->stmt_id]))
                {
                    $this->error[$this->stmt_id] = ocierror($this->stmt_id);
                }
                return $this->error[$this->stmt_id]['message'];
        }

        function _error_number()
        {
            if (!isset($this->error[$this->stmt_id]))
            {
                $this->error[$this->stmt_id] = ocierror($this->stmt_id);
            }
            return $this->error[$this->stmt_id]['code'];
        }


    * system\database\drivers\oci8\oci8_driver.php

        escape_str() 메소드에서 escape 처리를 하고 있으나, 간단한 escape 조차도 하지 못하고 있음.

        409라인 교체

        $str = $CI->input->_remove_invisible_characters($str);
        $str = str_replace("'", "''", $CI->input->_remove_invisible_characters($str));


        414라인 교체 ( 왜 이걸 고쳤는지 기억이 안나네요. 치매 ~ ㅜ.ㅜ )

        $str = str_replace(    array('%', '_', $this->_like_escape_chr),
                                array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.$this->_like_escape_chr),
                                $str);
        $str = str_replace(    array('%', '_', '\'', $this->_like_escape_chr),
                                array($this->_like_escape_chr.'%', $this->_like_escape_chr.'_', $this->_like_escape_chr.'\'', $this->_like_escape_chr.$this->_like_escape_chr),
                                $str);




** 오라클 바인딩 기능 사용하기

    오라클 바인딩 기능은 escape 문제로 인해 반드시 필요한 기능이라고 생각합니다.
    제 능력으로는 escape 에 관련된 모든 문자열을 찾아낼수도 없었고, 그런게 있었다면 애초부터,
    oci8_escape_string() 같은 함수가 지원되었겠죠.
    어딘가 문제가 있으니까 oci8_escape_string() 같은걸로 지원안하고 있지 않나 하는
    개인적인 생각도 들었습니다.
    그냥 모두 제 생각입니다. ^^ 제대로 알고 계신 분은 코멘트 남겨 주세요.

    바인딩 사용 방법

// 기존 바인딩 사용방법 (? 이용한)
$sql = "select ? from dual";
$bind_array[0] = '검색값';
$result = $this->db->query($sql, $bind_array);

// 오라클 바인드 기능 사용방법
$sql = "select :search_key from dual";
$bind_array[':search_key'] = '검색값';
$result = $this->db->parse($sql, $bind_array);

    * system/database/DB_driver.php 파일 수정하기

        $this->db->query() 대신 $this->db->parse() 를 사용했다는 표시 부분을 추가하면,
        기존 기능을 그대로 모두 사용할 수 있을 뿐만 아니라, 바인드 기능도 추가로 사용 가능합니다.
        

        244라인 교체

            function query($sql, $binds = FALSE, $return_object = TRUE) 
            function query($sql, $binds = FALSE, $return_object = TRUE, $pre_parse = FALSE)


        293라인 교체

            if (FALSE === ($this->result_id = $this->simple_query($sql)))
            if (FALSE === ($this->result_id = $this->simple_query($sql, $pre_parse)))

        440라인 교체

            function simple_query($sql)
            function simple_query($sql, $pre_parse = FALSE)

        447라인 교체

            return $this->_execute($sql);
            return $this->_execute($sql, $pre_parse);


   
* system\database\drivers\oci8\oci8_driver.php 파일 수정하기


        parse() 메소드 추가

        function parse($sql, $binds, $return_object = TRUE)
        {
            $params = array();
            foreach ($binds as $name => $param)
            {
                if (!is_array($param))
                {
                    $params[] = array('name' => $name, 'value' => $param);
                }
                else
                {
                    if (!isset($param[1])) {
                        $param[1] = '';
                    }
                    if (!isset($param[2])) {
                        $param[2] = '';
                    }
                    $params[] = array('name' => $name, 'value' => $param[0], 'type' => $param[1], 'length' => $param[2]);
                }
            }

            $this->stmt_id = FALSE;
            $this->_set_stmt_id($sql);
            $this->_bind_params($params);
            return $this->query($sql, FALSE, $return_object, TRUE);
        }


        _execute() 수정

        function _execute($sql, $pre_parse = FALSE)
        {
            // oracle must parse the query before it is run. All of the actions with
            // the query are based on the statement id returned by ociparse
            if ($pre_parse === FALSE)
            {
                $this->stmt_id = FALSE;
                $this->_set_stmt_id($sql);
            }
            ocisetprefetch($this->stmt_id, 1000);
            return @ociexecute($this->stmt_id, $this->_commit);
        }


        _bind_params() 수정

function _bind_params($params)
        {
            if ( ! is_array($params) OR ! is_resource($this->stmt_id))
            {
                return;
            }

            foreach ($params as $param)
            {
                foreach (array('name', 'value', 'type', 'length') as $val)
                {
                    if ( ! isset($param[$val]))
                    {
                        $param[$val] = '';
                    }
                }

                if ($param['type'] != '')
                {
                    ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length'], $param['type']);
                }
                elseif ($param['length'] != '')
                {
                    ocibindbyname($this->stmt_id, $param['name'], $param['value'], $param['length']);
                }
                else
                {
                    ocibindbyname($this->stmt_id, $param['name'], $param['value']);
                }
            }
        }

 다음글 [펌]editplus에서 자주 활용하는 기능 (4)
 이전글 드디어 쓸만한 PHP IDE가 있네요. (8)

댓글

변종원(웅파) / 2010/01/14 14:45:31 / 추천 0

좋은 정보 감사합니다.

양승현 / 2010/01/22 09:34:51 / 추천 0
좋은 정보네요..