mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-04 01:01:41 +09:00
삭제
git-svn-id: http://xe-core.googlecode.com/svn/sandbox@2327 201d5d3c-b55e-5fd7-737f-ddc643e51545
This commit is contained in:
commit
8326004cb2
2773 changed files with 91485 additions and 0 deletions
923
classes/context/Context.class.php
Normal file
923
classes/context/Context.class.php
Normal file
|
|
@ -0,0 +1,923 @@
|
|||
<?php
|
||||
/**
|
||||
* @class Context
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief Request Argument/환경변수등의 모든 Context를 관리
|
||||
*
|
||||
* Context 클래스는 Context::methodname() 처럼 쉽게 사용하기 위해 만들어진 객체를 받아서
|
||||
* 호출하는 구조를 위해 이중 method 구조를 가지고 있다.
|
||||
* php5에서 static variables를 사용하게 된다면 불필요한 구조를 제거할 수 있다.
|
||||
* php5 쓰고 싶당.. ㅡ.ㅜ
|
||||
**/
|
||||
|
||||
class Context {
|
||||
|
||||
var $request_method = 'GET'; ///< @brief GET/POST/XMLRPC 중 어떤 방식으로 요청이 왔는지에 대한 값이 세팅. GET/POST/XML 3가지가 있음
|
||||
var $response_method = ''; ///< @brief HTML/XMLRPC 중 어떤 방식으로 결과를 출력할지 결정. (강제 지정전까지는 request_method를 따름)
|
||||
|
||||
var $context = NULL; ///< @brief request parameter 및 각종 환경 변수등을 정리하여 담을 변수
|
||||
|
||||
var $db_info = NULL; ///< @brief DB 정보
|
||||
|
||||
var $js_files = array(); ///< @brief display시에 사용하게 되는 js files의 목록
|
||||
|
||||
var $css_files = array(); ///< @brief display시에 사용하게 되는 css files의 목록
|
||||
|
||||
var $html_header = NULL; ///< @brief display시에 사용하게 되는 <head>..</head>내의 스크립트코드
|
||||
var $html_footer = NULL; ///< @brief display시에 사용하게 되는 </body> 바로 앞에 추가될 코드
|
||||
|
||||
var $path = ''; ///< zbxe의 경로
|
||||
|
||||
/**
|
||||
* @brief 언어 정보
|
||||
*
|
||||
* 기본으로 ko. HTTP_USER_AGENT나 사용자의 직접 세팅(쿠키이용)등을 통해 변경됨
|
||||
**/
|
||||
var $lang_type = ''; ///< 언어 종류
|
||||
var $lang = NULL; ///< 언어 데이터를 담고 있는 변수
|
||||
var $loaded_lang_files = array(); ///< 로딩된 언어파일의 목록 (재로딩을 피하기 위함)
|
||||
|
||||
var $site_title = ''; ///< @brief 현 사이트의 browser title. Context::setBrowserTitle() 로 변경 가능
|
||||
|
||||
var $get_vars = NULL; ///< @brief form이나 get으로 요청이 들어온 변수만 별도로 관리
|
||||
|
||||
var $is_uploaded = false; ///< @brief 첨부파일이 업로드 된 요청이였는지에 대한 체크 플래그
|
||||
|
||||
/**
|
||||
* @brief Context 객체를 GLOBALS 변수에 생성
|
||||
*
|
||||
* Context는 어디서든 객체 선언없이 사용하기 위해서 static 하게 사용\n
|
||||
* php5라면 GLOBALS가 아닌 static으로 처리 가능
|
||||
**/
|
||||
function &getInstance() {
|
||||
if(!$GLOBALS['__ContextInstance__']) $GLOBALS['__ContextInstance__'] = new Context();
|
||||
return $GLOBALS['__ContextInstance__'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보, Request Argument등을 세팅
|
||||
*
|
||||
* Context::init()은 단 한번만 호출되어야 하며 init()시에
|
||||
* Request Argument, DB/언어/세션정보등의 모든 정보를 세팅한다
|
||||
**/
|
||||
function init() {
|
||||
// context 변수를 $GLOBALS의 변수로 지정
|
||||
$this->context = &$GLOBALS['__Context__'];
|
||||
$this->context->lang = &$GLOBALS['lang'];
|
||||
$this->context->_COOKIE = $_COOKIE;
|
||||
|
||||
// 기본적인 DB정보 세팅
|
||||
$this->_loadDBInfo();
|
||||
|
||||
// 쿠키로 설정된 언어타입 가져오기
|
||||
if($_COOKIE['lang_type']) $this->lang_type = $_COOKIE['lang_type'];
|
||||
else $this->lang_type = $this->db_info->lang_type;
|
||||
|
||||
// 등록된 기본 언어파일 찾기
|
||||
$lang_files = FileHandler::readDir('./common/lang');
|
||||
$accept_lang = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']);
|
||||
foreach($lang_files as $key => $val) {
|
||||
list($lang_prefix) = explode('.',$val);
|
||||
$lang_supported[] = $lang_prefix;
|
||||
if(!$this->lang_type && ereg($lang_prefix, strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']))) {
|
||||
$this->lang_type = $lang_prefix;
|
||||
setcookie('lang_type', $this->lang_type, time()+60*60*24*365, '/');
|
||||
}
|
||||
}
|
||||
|
||||
if(!in_array($this->lang_type, $lang_supported)) $this->lang_type = $this->db_info->lang_type;
|
||||
if(!$this->lang_type) $this->lang_type = "en";
|
||||
|
||||
Context::set('lang_supported', $lang_supported);
|
||||
|
||||
$this->setLangType($this->lang_type);
|
||||
|
||||
// 기본 언어파일 로드
|
||||
$this->lang = &$GLOBALS['lang'];
|
||||
$this->_loadLang("./common/lang/");
|
||||
|
||||
// Request Method 설정
|
||||
$this->_setRequestMethod();
|
||||
|
||||
// Request Argument 설정
|
||||
$this->_setXmlRpcArgument();
|
||||
$this->_setRequestArgument();
|
||||
$this->_setUploadedArgument();
|
||||
|
||||
// 인증관련 데이터를 Context에 설정
|
||||
$oMember = getModel('member');
|
||||
if($oMember->isLogged()) {
|
||||
$this->_set('is_logged', true);
|
||||
$this->_set('logged_info', $_SESSION['logged_info']);
|
||||
} else {
|
||||
$this->_set('is_logged', false);
|
||||
$this->_set('logged_info', NULL);
|
||||
}
|
||||
|
||||
// rewrite 모듈사용 상태 체크
|
||||
if(file_exists('./.htaccess')&&$this->db_info->use_rewrite == 'Y') $this->allow_rewrite = true;
|
||||
else $this->allow_rewrite = false;
|
||||
|
||||
// 상대 경로 설정
|
||||
$this->path = $this->getRequestUri();
|
||||
|
||||
// rewrite module때문에 javascript에서 location.href 문제 해결을 위해 직접 실제 경로 설정
|
||||
if($_SERVER['REQUEST_METHOD'] == 'GET') {
|
||||
if($this->get_vars) {
|
||||
foreach($this->get_vars as $key => $val) {
|
||||
if(!$val) continue;
|
||||
$url .= ($url?'&':'').$key.'='.$val;
|
||||
}
|
||||
Context::set('current_url',sprintf('%s?%s',$this->path, $url));
|
||||
} else {
|
||||
Context::set('current_url',$this->getUrl());
|
||||
}
|
||||
} else {
|
||||
Context::set('current_url',$this->getRequestUri());
|
||||
}
|
||||
Context::set('request_uri',Context::getRequestUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB및 기타 자원들의 close
|
||||
**/
|
||||
function close() {
|
||||
// DB close
|
||||
$oDB = &DB::getInstance();
|
||||
if(is_object($oDB)&&method_exists($oDB, 'close')) $oDB->close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 정보를 설정하고 DB Type과 DB 정보를 return
|
||||
**/
|
||||
function _loadDBInfo() {
|
||||
if(!$this->isInstalled()) return;
|
||||
|
||||
// db 정보 설정
|
||||
$db_config_file = $this->getConfigFile();
|
||||
if(file_exists($db_config_file)) @include($db_config_file);
|
||||
|
||||
if(!$db_info->time_zone) $db_info->time_zone = date("O");
|
||||
|
||||
$this->_setDBInfo($db_info);
|
||||
|
||||
$GLOBALS['_time_zone'] = $db_info->time_zone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB의 db_type을 return
|
||||
**/
|
||||
function getDBType() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getDBType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB의 db_type을 return
|
||||
**/
|
||||
function _getDBType() {
|
||||
return $this->db_info->db_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 정보가 담긴 object를 return
|
||||
**/
|
||||
function setDBInfo($db_info) {
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_setDBInfo($db_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 정보가 담긴 object를 return
|
||||
**/
|
||||
function _setDBInfo($db_info) {
|
||||
$this->db_info = $db_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 정보가 담긴 object를 return
|
||||
**/
|
||||
function getDBInfo() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getDBInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 정보가 담긴 object를 return
|
||||
**/
|
||||
function _getDBInfo() {
|
||||
return $this->db_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 사이트 title setting
|
||||
**/
|
||||
function setBrowserTitle($site_title) {
|
||||
if(!$site_title) return;
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_setBrowserTitle($site_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 사이트 title setting
|
||||
**/
|
||||
function _setBrowserTitle($site_title) {
|
||||
$this->site_title = htmlspecialchars($site_title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 사이트 title return
|
||||
**/
|
||||
function getBrowserTitle() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getBrowserTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 사이트 title return
|
||||
**/
|
||||
function _getBrowserTitle() {
|
||||
return $this->site_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지정된 언어파일 로드
|
||||
**/
|
||||
function loadLang($path) {
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_loadLang($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지정된 언어파일 로드
|
||||
*
|
||||
* loaded_lang_files 변수를 이용하여 한번 로드된 파일을 다시 로드하지 않음
|
||||
**/
|
||||
function _loadLang($path) {
|
||||
global $lang;
|
||||
if(substr($path,-1)!='/') $path .= '/';
|
||||
$filename = sprintf('%s%s.lang.php', $path, $this->lang_type);
|
||||
if(!file_exists($filename)) $filename = sprintf('%s%s.lang.php', $path, 'ko');
|
||||
if(!file_exists($filename)) return;
|
||||
if(!is_array($this->loaded_lang_files)) $this->loaded_lang_files = array();
|
||||
if(in_array($filename, $this->loaded_lang_files)) return;
|
||||
$this->loaded_lang_files[] = $filename;
|
||||
include($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lang_type을 세팅 (기본 ko)
|
||||
**/
|
||||
function setLangType($lang_type = 'ko') {
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_setLangType($lang_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lang_type을 세팅 (기본 ko)
|
||||
**/
|
||||
function _setLangType($lang_type = 'ko') {
|
||||
$this->lang_type = $lang_type;
|
||||
$this->_set('lang_type',$lang_type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lang_type을 return
|
||||
**/
|
||||
function getLangType() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getLangType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lang_type을 return
|
||||
**/
|
||||
function _getLangType() {
|
||||
return $this->lang_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief code에 해당하는 문자열을 return
|
||||
*
|
||||
* 만약 code에 해당하는 문자열이 없다면 code를 그대로 리턴
|
||||
**/
|
||||
function getLang($code) {
|
||||
if(!$code) return;
|
||||
if($GLOBALS['lang']->{$code}) return $GLOBALS['lang']->{$code};
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 직접 lang 변수에 데이터를 추가
|
||||
**/
|
||||
function setLang($code, $val) {
|
||||
$GLOBALS['lang']->{$code} = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief object내의 variables의 문자열을 utf8로 변경
|
||||
**/
|
||||
function convertEncoding($source_obj) {
|
||||
$charset_list = array(
|
||||
'UTF-8', 'EUC-KR', 'CP949', 'ISO-8859-1', 'EUC-JP', 'SHIFT_JIS', 'CP932',
|
||||
'EUC-CN', 'HZ', 'GBK', 'GB18030', 'EUC-TW', 'BIG5', 'CP950', 'BIG5-HKSCS',
|
||||
'ISO-2022-CN', 'ISO-2022-CN-EXT', 'ISO-2022-JP', 'ISO-2022-JP-2', 'ISO-2022-JP-1',
|
||||
'ISO-8859-6', 'ISO-8859-8', 'JOHAB', 'ISO-2022-KR', 'CP1255', 'CP1256', 'CP862',
|
||||
'ASCII', 'ISO-8859-1', 'ISO-8850-2', 'ISO-8850-3', 'ISO-8850-4', 'ISO-8850-5',
|
||||
'ISO-8850-7', 'ISO-8850-9', 'ISO-8850-10', 'ISO-8850-13', 'ISO-8850-14',
|
||||
'ISO-8850-15', 'ISO-8850-16', 'CP1250', 'CP1251', 'CP1252', 'CP1253', 'CP1254',
|
||||
'CP1257', 'CP850', 'CP866',
|
||||
);
|
||||
|
||||
$obj = clone($source_obj);
|
||||
|
||||
for($i=0;$i<count($charset_list);$i++) {
|
||||
$charset = $charset_list[$i];
|
||||
$flag = true;
|
||||
foreach($obj as $key=>$val) {
|
||||
if(!$val) continue;
|
||||
if($val && !iconv($charset,'UTF-8',$val)) $flag = false;
|
||||
}
|
||||
if($flag == true) {
|
||||
foreach($obj as $key => $val) $obj->{$key} = iconv($charset,'UTF-8',$val);
|
||||
return $obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief response method를 강제로 지정 (기본으로는 request method를 이용함)
|
||||
*
|
||||
* method의 종류에는 HTML/ TEXT/ XMLRPC가 있음
|
||||
**/
|
||||
function setResponseMethod($method = "HTML") {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_setResponseMethod($method);
|
||||
}
|
||||
|
||||
function _setResponseMethod($method = "HTML") {
|
||||
$this->response_method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief response method 값을 return
|
||||
*
|
||||
* method의 종류에는 HTML/ TEXT/ XMLRPC가 있음
|
||||
* 별도로 response method를 지정하지 않았다면 request method로 판단하여 결과 return
|
||||
**/
|
||||
function getResponseMethod() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getResponseMethod();
|
||||
}
|
||||
|
||||
function _getResponseMethod() {
|
||||
if($this->response_method) return $this->response_method;
|
||||
|
||||
if($this->_getRequestMethod()=="XMLRPC") return "XMLRPC";
|
||||
return "HTML";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC)
|
||||
**/
|
||||
function setRequestMethod($type) {
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_setRequestMethod($type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC)
|
||||
**/
|
||||
function _setRequestMethod($type = '') {
|
||||
if($type) return $this->request_method = $type;
|
||||
|
||||
if($GLOBALS['HTTP_RAW_POST_DATA']) return $this->request_method = "XMLRPC";
|
||||
|
||||
$this->request_method = $_SERVER['REQUEST_METHOD'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GET/POST방식일 경우 처리
|
||||
**/
|
||||
function _setRequestArgument() {
|
||||
if($this->_getRequestMethod() == 'XMLRPC') return;
|
||||
if(!count($_REQUEST)) return;
|
||||
|
||||
foreach($_REQUEST as $key => $val) {
|
||||
if($key == "page" || substr($key,-3)=="srl") $val = (int)$val;
|
||||
if(is_array($val)) {
|
||||
for($i=0;$i<count($val);$i++) {
|
||||
if(get_magic_quotes_gpc()) $val[$i] = stripslashes($val[$i]);
|
||||
$val[$i] = trim($val[$i]);
|
||||
}
|
||||
} else {
|
||||
if(get_magic_quotes_gpc()) $val = stripslashes($val);
|
||||
$val = trim($val);
|
||||
}
|
||||
if(!$val) continue;
|
||||
|
||||
if($this->_getRequestMethod()=='GET'&&$_GET[$key]) $set_to_vars = true;
|
||||
elseif($this->_getRequestMethod()=='POST'&&$_POST[$key]) $set_to_vars = true;
|
||||
else $set_to_vars = false;
|
||||
$this->_set($key, $val, $set_to_vars);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief XML RPC일때
|
||||
**/
|
||||
function _setXmlRpcArgument() {
|
||||
if($this->_getRequestMethod() != 'XMLRPC') return;
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse();
|
||||
|
||||
$params = $xml_obj->methodcall->params;
|
||||
unset($params->node_name);
|
||||
|
||||
unset($params->attrs);
|
||||
if(!count($params)) return;
|
||||
|
||||
foreach($params as $key => $obj) {
|
||||
$val = trim($obj->body);
|
||||
$this->_set($key, $val, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 업로드 되었을 경우 return true
|
||||
**/
|
||||
function isUploaded() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_isUploaded();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 업로드 되었을 경우 return true
|
||||
**/
|
||||
function _isUploaded() {
|
||||
return $this->is_uploaded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 업로드된 파일이 있을 경우도 역시 context에 통합 처리 (단 정상적인 업로드인지 체크)
|
||||
**/
|
||||
function _setUploadedArgument() {
|
||||
if($this->_getRequestMethod() != 'POST') return;
|
||||
if(!eregi("^multipart\/form-data", $_SERVER['CONTENT_TYPE'])) return;
|
||||
if(!$_FILES) return;
|
||||
|
||||
foreach($_FILES as $key => $val) {
|
||||
$tmp_name = $val['tmp_name'];
|
||||
if(!$tmp_name || !is_uploaded_file($tmp_name)) continue;
|
||||
$this->_set($key, $val, true);
|
||||
$this->is_uploaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request Method값을 return (GET/POST/XMLRPC);
|
||||
**/
|
||||
function getRequestMethod() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getRequestMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Request Method값을 return (GET/POST/XMLRPC);
|
||||
**/
|
||||
function _getRequestMethod() {
|
||||
return $this->request_method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 요청받은 url에 args_list를 적용하여 return
|
||||
**/
|
||||
function getUrl($num_args=0, $args_list=array()) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getUrl($num_args, $args_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 요청받은 url에 args_list를 적용하여 return
|
||||
**/
|
||||
function _getUrl($num_args=0, $args_list=array()) {
|
||||
if(!$this->get_vars || $args_list[0]=='') {
|
||||
$get_vars = null;
|
||||
if($args_list[0]=='') {
|
||||
array_shift($args_list);
|
||||
$num_args = count($args_list);
|
||||
}
|
||||
} else {
|
||||
$get_vars = get_object_vars($this->get_vars);
|
||||
}
|
||||
|
||||
for($i=0;$i<$num_args;$i=$i+2) {
|
||||
$key = $args_list[$i];
|
||||
$val = trim($args_list[$i+1]);
|
||||
if(!$val) unset($get_vars[$key]);
|
||||
else $get_vars[$key] = $val;
|
||||
}
|
||||
|
||||
$var_count = count($get_vars);
|
||||
if(!$var_count) return '';
|
||||
|
||||
// rewrite모듈을 사용하고 인자의 값이 4개 이하일 경우
|
||||
if($this->allow_rewrite && $var_count < 4) {
|
||||
$var_keys = array_keys($get_vars);
|
||||
|
||||
if($var_count == 1) {
|
||||
if($var_keys[0]=='mid') return $this->path.$get_vars['mid'];
|
||||
elseif($var_keys[0]=='document_srl') return $this->path.$get_vars['document_srl'];
|
||||
} elseif($var_count == 2) {
|
||||
asort($var_keys);
|
||||
$target = implode('.',$var_keys);
|
||||
if($target=='act.mid' && !ereg('([A-Z]+)',$get_vars['act'])) return sprintf('%s%s/%s',$this->path,$get_vars['mid'],$get_vars['act']);
|
||||
elseif($target=='document_srl.mid') return sprintf('%s%s/%s',$this->path,$get_vars['mid'],$get_vars['document_srl']);
|
||||
elseif($target=='act.document_srl') return sprintf('%s%s/%s',$this->path,$get_vars['document_srl'],$get_vars['act']);
|
||||
elseif($target=='mid.page') return sprintf('%s%s/page/%s',$this->path,$get_vars['mid'],$get_vars['page']);
|
||||
elseif($target=='category.mid') return sprintf('%s%s/category/%s',$this->path,$get_vars['mid'],$get_vars['category']);
|
||||
} elseif($var_count == 3) {
|
||||
asort($var_keys);
|
||||
$target = implode('.',$var_keys);
|
||||
if($target=='category.mid.page') {
|
||||
return sprintf('%s%s/category/%s/page/%s',$this->path,$get_vars['mid'],$get_vars['category'],$get_vars['page']);
|
||||
} elseif($target=='mid.search_keyword.search_target' && $get_vars['search_target']=='tag') {
|
||||
return sprintf('%s%s/tag/%s',$this->path,$get_vars['mid'],str_replace(' ','-',$get_vars['search_keyword']));
|
||||
} elseif($target=='mid.search_keyword.search_target' && $get_vars['search_target']=='regdate') {
|
||||
if(strlen($get_vars['search_keyword'])==8) return sprintf('%s%s/%04d/%02d/%02d',$this->path,$get_vars['mid'],substr($get_vars['search_keyword'],0,4),substr($get_vars['search_keyword'],4,2),substr($get_vars['search_keyword'],6,2));
|
||||
elseif(strlen($get_vars['search_keyword'])==6) return sprintf('%s%s/%04d/%02d',$this->path,$get_vars['mid'],substr($get_vars['search_keyword'],0,4),substr($get_vars['search_keyword'],4,2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rewrite 모듈을 사용하지 않고 인자의 값이 2개 이상이거나 rewrite모듈을 위한 인자로 적당하지 않을 경우
|
||||
foreach($get_vars as $key => $val) {
|
||||
if(!$val) continue;
|
||||
$url .= ($url?'&':'').$key.'='.$val;
|
||||
}
|
||||
|
||||
return $this->path.'?'.htmlspecialchars($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 요청이 들어온 URL에서 argument를 제거하여 return
|
||||
**/
|
||||
function getRequestUri() {
|
||||
$hostname = $_SERVER['HTTP_HOST'];
|
||||
$port = $_SERVER['SERVER_PORT'];
|
||||
if($port!=80) $hostname .= ":{$port}";
|
||||
$path = str_replace('index.php','',$_SERVER['SCRIPT_NAME']);
|
||||
return sprintf("http://%s%s",$hostname,$path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief key/val로 context vars 세팅
|
||||
**/
|
||||
function set($key, $val, $set_to_get_vars = false) {
|
||||
$oContext = &Context::getInstance();
|
||||
$oContext->_set($key, $val, $set_to_get_vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief key/val로 context vars 세팅
|
||||
**/
|
||||
function _set($key, $val, $set_to_get_vars = false) {
|
||||
$this->context->{$key} = $val;
|
||||
if($set_to_get_vars || $this->get_vars->{$key}) $this->get_vars->{$key} = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief key값에 해당하는 값을 return
|
||||
**/
|
||||
function get($key) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_get($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief key값에 해당하는 값을 return
|
||||
**/
|
||||
function _get($key) {
|
||||
return $this->context->{$key};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 받고자 하는 변수만 object에 입력하여 받음
|
||||
*
|
||||
* key1, key2, key3 .. 등의 인자를 주어 여러개의 변수를 object vars로 세팅하여 받을 수 있음
|
||||
**/
|
||||
function gets() {
|
||||
$num_args = func_num_args();
|
||||
if($num_args<1) return;
|
||||
$args_list = func_get_args();
|
||||
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_gets($num_args, $args_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 받고자 하는 변수만 object에 입력하여 받음
|
||||
*
|
||||
* key1, key2, key3 .. 등의 인자를 주어 여러개의 변수를 object vars로 세팅하여 받을 수 있음
|
||||
**/
|
||||
function _gets($num_args, $args_list) {
|
||||
for($i=0;$i<$num_args;$i++) {
|
||||
$args = $args_list[$i];
|
||||
$output->{$args} = $this->_get($args);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모든 데이터를 return
|
||||
**/
|
||||
function getAll() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모든 데이터를 return
|
||||
**/
|
||||
function _getAll() {
|
||||
return $this->context;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GET/POST/XMLRPC에서 넘어온 변수값을 return
|
||||
**/
|
||||
function getRequestVars() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getRequestVars();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief GET/POST/XMLRPC에서 넘어온 변수값을 return
|
||||
**/
|
||||
function _getRequestVars() {
|
||||
return clone($this->get_vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief js file을 추가
|
||||
**/
|
||||
function addJsFile($file) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_addJsFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief js file을 추가
|
||||
**/
|
||||
function _addJsFile($file) {
|
||||
if(in_array($file, $this->js_files)) return;
|
||||
$this->js_files[] = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief js file 목록을 return
|
||||
**/
|
||||
function getJsFile() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getJsFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief js file 목록을 return
|
||||
**/
|
||||
function _getJsFile() {
|
||||
return $this->js_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CSS file 추가
|
||||
**/
|
||||
function addCSSFile($file) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_addCSSFile($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CSS file 추가
|
||||
**/
|
||||
function _addCSSFile($file) {
|
||||
if(in_array($file, $this->css_files)) return;
|
||||
$this->css_files[] = $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CSS file 목록 return
|
||||
**/
|
||||
function getCSSFile() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getCSSFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief CSS file 목록 return
|
||||
**/
|
||||
function _getCSSFile() {
|
||||
return $this->css_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlHeader 추가
|
||||
**/
|
||||
function addHtmlHeader($header) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_addHtmlHeader($header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlHeader 추가
|
||||
**/
|
||||
function _addHtmlHeader($header) {
|
||||
$this->html_header .= "\n".$header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlHeader return
|
||||
**/
|
||||
function getHtmlHeader() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getHtmlHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlHeader return
|
||||
**/
|
||||
function _getHtmlHeader() {
|
||||
return $this->html_header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlFooter 추가
|
||||
**/
|
||||
function addHtmlFooter($footer) {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_addHtmlFooter($footer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlFooter 추가
|
||||
**/
|
||||
function _addHtmlFooter ($footer) {
|
||||
$this->html_footer .= ($this->Htmlfooter?"\n":"").$footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlFooter return
|
||||
**/
|
||||
function getHtmlFooter() {
|
||||
$oContext = &Context::getInstance();
|
||||
return $oContext->_getHtmlFooter();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief HtmlFooter return
|
||||
**/
|
||||
function _getHtmlFooter() {
|
||||
return $this->html_footer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief db설정내용이 저장되어 있는 config file의 path를 return
|
||||
**/
|
||||
function getConfigFile() {
|
||||
return "./files/config/db.config.php";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치가 되어 있는지에 대한 체크
|
||||
*
|
||||
* 단순히 db config 파일의 존재 유무로 설치 여부를 체크한다
|
||||
**/
|
||||
function isInstalled() {
|
||||
return file_exists(Context::getConfigFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 내용의 위젯이나 기타 기능에 대한 code를 실제 code로 변경
|
||||
**/
|
||||
function transContent($content) {
|
||||
// 위젯 코드 변경
|
||||
$content = preg_replace_callback('!<img([^\>]*)widget=([^\>]*?)\>!is', array($this,'_transWidget'), $content);
|
||||
|
||||
// 메타 파일 변경
|
||||
$content = preg_replace_callback('!<\!\-\-Meta:([^\-]*?)\-\->!is', array($this,'_transMeta'), $content);
|
||||
|
||||
// 에디터 컴포넌트를 찾아서 결과 코드로 변환
|
||||
$content = preg_replace_callback('!<div([^\>]*)editor_component=([^\>]*)>(.*?)\<\/div\>!is', array($this,'_transEditorComponent'), $content);
|
||||
$content = preg_replace_callback('!<img([^\>]*)editor_component=([^\>]*?)\>!is', array($this,'_transEditorComponent'), $content);
|
||||
|
||||
// body 내의 <style ..></style>를 header로 이동
|
||||
$content = preg_replace_callback('!<style(.*?)<\/style>!is', array($this,'_moveStyleToHeader'), $content);
|
||||
|
||||
// <br> 코드 변환
|
||||
$content = preg_replace('/<br([^>\/]*)(\/>|>)/i','<br$1 />', $content);
|
||||
|
||||
// 몇가지 대문자 태그를 소문자로 변경
|
||||
//$content = preg_replace_callback('!<(\/){0,1}([A-Z]+)([^>]*?)>!s',array($this,'_transTagToLowerCase'), $content);
|
||||
|
||||
// <img ...> 코드를 <img ... /> 코드로 변환
|
||||
$content = preg_replace('/<img(.*?)(\/){0,1}>/i','<img$1 />', $content);
|
||||
|
||||
// blogapi tool에서 삽입된 코드 삭제
|
||||
//$content = str_replace('atomicselection="true"','',$content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief IE위지윅에디터에서 태그가 대문자로 사용되기에 이를 소문자로 치환
|
||||
**/
|
||||
function _transTagToLowerCase($matches) {
|
||||
return sprintf('<%s%s%s>', $matches[1], strtolower($matches[2]), $matches[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief <!--Meta:파일이름.(css|js)-->를 변경
|
||||
**/
|
||||
function _transMeta($matches) {
|
||||
if(eregi('\.css$', $matches[1])) $this->addCSSFile($matches[1]);
|
||||
elseif(eregi('\.js$', $matches[1])) $this->addJSFile($matches[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief <body>내의 <style태그를 header로 이동
|
||||
**/
|
||||
function _moveStyleToHeader($matches) {
|
||||
$this->addHtmlHeader($matches[0]);
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 내용의 에디터 컴포넌트 코드를 변환
|
||||
**/
|
||||
function _fixQuotation($matches) {
|
||||
$key = $matches[1];
|
||||
$val = $matches[2];
|
||||
if(substr($val,0,1)!='"') $val = '"'.$val.'"';
|
||||
return sprintf('%s=%s', $key, $val);
|
||||
}
|
||||
|
||||
function _transEditorComponent($matches) {
|
||||
// IE에서는 태그의 특성중에서 " 를 빼어 버리는 경우가 있기에 정규표현식으로 추가해줌
|
||||
$buff = $matches[0];
|
||||
$buff = preg_replace_callback('/([^=^"^ ]*)=([^ ]*)/i', array($this, _fixQuotation), $buff);
|
||||
$buff = str_replace("&","&",$buff);
|
||||
|
||||
// 위젯에서 생성된 코드 (img, div태그내에 editor_widget코드 존재)의 parameter를 추출
|
||||
$oXmlParser = new XmlParser();
|
||||
$xml_doc = $oXmlParser->parse($buff);
|
||||
if($xml_doc->div) $xml_doc = $xml_doc->div;
|
||||
|
||||
$xml_doc->body = $matches[3];
|
||||
|
||||
// attribute가 없으면 return
|
||||
$editor_component = $xml_doc->attrs->editor_component;
|
||||
if(!$editor_component) return $matches[0];
|
||||
|
||||
// component::transHTML() 을 이용하여 변환된 코드를 받음
|
||||
$oEditorModel = &getModel('editor');
|
||||
$oComponent = &$oEditorModel->getComponentObject($editor_component, 0);
|
||||
if(!is_object($oComponent)||!method_exists($oComponent, 'transHTML')) return $matches[0];
|
||||
|
||||
return $oComponent->transHTML($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 위젯 코드를 실제 php코드로 변경
|
||||
**/
|
||||
function _transWidget($matches) {
|
||||
// IE에서는 태그의 특성중에서 " 를 빼어 버리는 경우가 있기에 정규표현식으로 추가해줌
|
||||
$buff = $matches[0];
|
||||
$buff = preg_replace('/([^=^"^ ]*)=([^"])([^=^ ]*)/i', '$1="$2$3"', $buff);
|
||||
$buff = str_replace("&","&",$buff);
|
||||
|
||||
$oXmlParser = new XmlParser();
|
||||
$xml_doc = $oXmlParser->parse(trim($buff));
|
||||
|
||||
if($xml_doc->img) $vars = $xml_doc->img->attrs;
|
||||
else $vars = $xml_doc->attrs;
|
||||
|
||||
if(!$vars->widget) return "";
|
||||
|
||||
// 캐시 체크
|
||||
$widget_sequence = $vars->widget_sequence;
|
||||
$widget_cache = $vars->widget_cache;
|
||||
if($widget_cache && $widget_sequence) {
|
||||
$output = WidgetHandler::getCache($widget_sequence, $widget_cache);
|
||||
if($output) return $output;
|
||||
}
|
||||
|
||||
// 위젯의 이름을 구함
|
||||
$widget = $vars->widget;
|
||||
unset($vars->widget);
|
||||
|
||||
return WidgetHandler::execute($widget, $vars);
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
369
classes/db/DB.class.php
Normal file
369
classes/db/DB.class.php
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DB
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief DB*의 상위 클래스
|
||||
* @version 0.1
|
||||
*
|
||||
* 제로보드의 DB 사용은 xml을 이용하여 이루어짐을 원칙으로 한다.
|
||||
* xml의 종류에는 query xml, schema xml이 있다.
|
||||
* query xml의 경우 DB::executeQuery() method를 이용하여 xml파일을 php code로 compile한 후에 실행이 된다.
|
||||
* query xml은 고유한 query id를 가지며 생성은 module에서 이루어진다.
|
||||
*
|
||||
* queryid = 모듈.쿼리명
|
||||
**/
|
||||
|
||||
class DB {
|
||||
|
||||
var $cond_operation = array( ///< 조건문에서 조건을 등호로 표시하는 변수
|
||||
'equal' => '=',
|
||||
'more' => '>=',
|
||||
'excess' => '>',
|
||||
'less' => '<=',
|
||||
'below' => '<',
|
||||
'notequal' => '<>',
|
||||
'notnull' => 'is not null',
|
||||
'null' => 'is null',
|
||||
);
|
||||
|
||||
var $fd = NULL; ///< connector resource or file description
|
||||
|
||||
var $result = NULL; ///< result
|
||||
|
||||
var $errno = 0; ///< 에러 발생시 에러 코드 (0이면 에러가 없다고 정의)
|
||||
var $errstr = ''; ///< 에러 발생시 에러 메세지
|
||||
var $query = ''; ///< 가장 최근에 수행된 query string
|
||||
|
||||
var $transaction_started = false; ///< 트랙잭션 처리 flag
|
||||
|
||||
var $is_connected = false; ///< DB에 접속이 되었는지에 대한 flag
|
||||
|
||||
var $supported_list = array(); ///< 지원하는 DB의 종류, classes/DB/DB***.class.php 를 이용하여 동적으로 작성됨
|
||||
|
||||
var $cache_file = './files/cache/queries/'; ///< query cache파일의 위치
|
||||
|
||||
/**
|
||||
* @brief DB를 상속받는 특정 db type의 instance를 생성 후 return
|
||||
**/
|
||||
function &getInstance($db_type = NULL) {
|
||||
if(!$db_type) $db_type = Context::getDBType();
|
||||
if(!$db_type) return new Object(-1, 'msg_db_not_setted');
|
||||
|
||||
if(!$GLOBALS['__DB__']) {
|
||||
$class_name = sprintf("DB%s%s", strtoupper(substr($db_type,0,1)), strtolower(substr($db_type,1)));
|
||||
$class_file = sprintf("./classes/db/%s.class.php", $class_name);
|
||||
if(!file_exists($class_file)) new Object(-1, 'msg_db_not_setted');
|
||||
|
||||
require_once($class_file);
|
||||
$eval_str = sprintf('$GLOBALS[\'__DB__\'] = new %s();', $class_name);
|
||||
eval($eval_str);
|
||||
}
|
||||
|
||||
return $GLOBALS['__DB__'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지원 가능한 DB 목록을 return
|
||||
**/
|
||||
function getSupportedList() {
|
||||
$oDB = new DB();
|
||||
return $oDB->_getSupportedList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지원 가능한 DB 목록을 return
|
||||
**/
|
||||
function _getSupportedList() {
|
||||
$db_classes_path = "./classes/db/";
|
||||
$filter = "/^DB([^\.]+)\.class\.php/i";
|
||||
$supported_list = FileHandler::readDir($db_classes_path, $filter, true);
|
||||
sort($supported_list);
|
||||
|
||||
// 구해진 클래스의 객체 생성후 isSupported method를 통해 지원 여부를 판단
|
||||
for($i=0;$i<count($supported_list);$i++) {
|
||||
$db_type = $supported_list[$i];
|
||||
|
||||
if(version_compare(phpversion(), '5.0') < 0 && eregi('pdo',$db_type)) continue;
|
||||
|
||||
$class_name = sprintf("DB%s%s", strtoupper(substr($db_type,0,1)), strtolower(substr($db_type,1)));
|
||||
$class_file = sprintf("./classes/db/%s.class.php", $class_name);
|
||||
if(!file_exists($class_file)) continue;
|
||||
|
||||
unset($oDB);
|
||||
require_once($class_file);
|
||||
$eval_str = sprintf('$oDB = new %s();', $class_name);
|
||||
eval($eval_str);
|
||||
|
||||
if(!$oDB || !$oDB->isSupported()) continue;
|
||||
|
||||
$this->supported_list[] = $db_type;
|
||||
}
|
||||
|
||||
return $this->supported_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지원하는 DB인지에 대한 check
|
||||
**/
|
||||
function isSupported($db_type) {
|
||||
$supported_list = DB::getSupportedList();
|
||||
return in_array($db_type, $supported_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 접속되었는지 return
|
||||
**/
|
||||
function isConnected() {
|
||||
return $this->is_connected?true:false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 로그 남김
|
||||
**/
|
||||
function actStart($query) {
|
||||
$this->setError(0,'success');
|
||||
$this->query = $query;
|
||||
$this->act_start = getMicroTime();
|
||||
}
|
||||
|
||||
function actFinish() {
|
||||
if(!$this->query ) return;
|
||||
$this->act_finish = getMicroTime();
|
||||
$elapsed_time = $this->act_finish - $this->act_start;
|
||||
$GLOBALS['__db_elapsed_time__'] += $elapsed_time;
|
||||
|
||||
$str = sprintf("\t%02d. %s (%0.6f sec)\n", ++$GLOBALS['__dbcnt'], $this->query, $elapsed_time);
|
||||
|
||||
if($this->isError()) {
|
||||
$str .= sprintf("\t Query Failed : %d\n\t\t\t %s\n", $this->errno, $this->errstr);
|
||||
|
||||
if(__DEBUG_DB_OUTPUT__==1) {
|
||||
$debug_file = "./files/_debug_db_query.php";
|
||||
$buff = sprintf("%s\n",print_r($str,true));
|
||||
|
||||
if($display_line) $buff = "\n====================================\n".$buff."------------------------------------\n";
|
||||
|
||||
if(@!$fp = fopen($debug_file,"a")) return;
|
||||
fwrite($fp, $buff);
|
||||
fclose($fp);
|
||||
}
|
||||
} else {
|
||||
$str .= "\t Query Success\n";
|
||||
}
|
||||
$GLOBALS['__db_queries__'] .= $str;
|
||||
$this->query = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 에러발생시 에러 메세지를 남기고 debug 모드일때는 GLOBALS 변수에 에러 로깅
|
||||
**/
|
||||
function setError($errno = 0, $errstr = 'success') {
|
||||
$this->errno = $errno;
|
||||
$this->errstr = $errstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 오류가 발생하였는지 return
|
||||
**/
|
||||
function isError() {
|
||||
return $this->errno===0?false:true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 에러결과를 Object 객체로 return
|
||||
**/
|
||||
function getError() {
|
||||
return new Object($this->errno, $this->errstr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief query xml 파일을 실행하여 결과를 return
|
||||
*
|
||||
* query_id = module.queryname
|
||||
* query_id에 해당하는 xml문(or 캐싱파일)을 찾아서 컴파일 후 실행
|
||||
**/
|
||||
function executeQuery($query_id, $args = NULL) {
|
||||
if(!$query_id) return new Object(-1, 'msg_invalid_queryid');
|
||||
|
||||
list($module, $id) = explode('.',$query_id);
|
||||
if(!$module || !$id) return new Object(-1, 'msg_invalid_queryid');
|
||||
|
||||
$xml_file = sprintf('./modules/%s/queries/%s.xml', $module, $id);
|
||||
if(!file_exists($xml_file)) return new Object(-1, 'msg_invalid_queryid');
|
||||
|
||||
// 일단 cache 파일을 찾아본다
|
||||
$cache_file = sprintf('%s%s.cache.php', $this->cache_file, $query_id);
|
||||
|
||||
// 없으면 원본 쿼리 xml파일을 찾아서 파싱을 한다
|
||||
if(!file_exists($cache_file)||filectime($cache_file)<filectime($xml_file)) {
|
||||
require_once('./classes/xml/XmlQueryParser.class.php');
|
||||
$oParser = new XmlQueryParser();
|
||||
$oParser->parse($query_id, $xml_file, $cache_file);
|
||||
}
|
||||
|
||||
// 쿼리를 실행한다
|
||||
return $this->_executeQuery($cache_file, $args, $query_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리문을 실행하고 결과를 return한다
|
||||
**/
|
||||
function _executeQuery($cache_file, $source_args, $query_id) {
|
||||
global $lang;
|
||||
|
||||
if(!file_exists($cache_file)) return new Object(-1, 'msg_invalid_queryid');
|
||||
|
||||
if($source_args) $args = clone($source_args);
|
||||
|
||||
$output = @include($cache_file);
|
||||
|
||||
if( (is_a($output, 'Object')||is_subclass_of($output,'Object'))&&!$output->toBool()) return $output;
|
||||
|
||||
// action값에 따라서 쿼리 생성으로 돌입
|
||||
switch($output->action) {
|
||||
case 'insert' :
|
||||
$output = $this->_executeInsertAct($output);
|
||||
break;
|
||||
case 'update' :
|
||||
$output = $this->_executeUpdateAct($output);
|
||||
break;
|
||||
case 'delete' :
|
||||
$output = $this->_executeDeleteAct($output);
|
||||
break;
|
||||
case 'select' :
|
||||
$output = $this->_executeSelectAct($output);
|
||||
break;
|
||||
}
|
||||
|
||||
if($this->errno !=0 ) return new Object($this->errno, $this->errstr);
|
||||
if(is_a($output, 'Object') || is_subclass_of($output, 'Object')) return $output;
|
||||
return new Object();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief $val을 $filter_type으로 검사
|
||||
* XmlQueryParser에서 사용하도록 함
|
||||
**/
|
||||
function checkFilter($key, $val, $filter_type) {
|
||||
global $lang;
|
||||
|
||||
switch($filter_type) {
|
||||
case 'email' :
|
||||
case 'email_address' :
|
||||
if(!eregi('^[_0-9a-z-]+(\.[_0-9a-z-]+)*@[0-9a-z-]+(\.[0-9a-z-]+)*$', $val)) return new Object(-1, sprintf($lang->filter->invalid_email, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
case 'homepage' :
|
||||
if(!eregi('^(http|https)+(:\/\/)+[0-9a-z_-]+\.[^ ]+$', $val)) return new Object(-1, sprintf($lang->filter->invalid_homepage, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
case 'userid' :
|
||||
case 'user_id' :
|
||||
if(!eregi('^[a-zA-Z]+([_0-9a-zA-Z]+)*$', $val)) return new Object(-1, sprintf($lang->filter->invalid_userid, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
case 'number' :
|
||||
if(!eregi('^[0-9]+$', $val)) return new Object(-1, sprintf($lang->filter->invalid_number, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
case 'alpha' :
|
||||
if(!eregi('^[a-z]+$', $val)) return new Object(-1, sprintf($lang->filter->invalid_alpha, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
case 'alpha_number' :
|
||||
if(!eregi('^[0-9a-z]+$', $val)) return new Object(-1, sprintf($lang->filter->invalid_alpha_number, $lang->{$key}?$lang->{$key}:$key));
|
||||
break;
|
||||
}
|
||||
|
||||
return new Object();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 컬럼의 타입을 구해옴
|
||||
* 컬럼의 경우 a.b 와 같이 되어 있는 경우가 있어서 별도 함수가 필요
|
||||
**/
|
||||
function getColumnType($column_type_list, $name) {
|
||||
if(strpos($name,'.')===false) return $column_type_list[$name];
|
||||
list($prefix, $name) = explode('.',$name);
|
||||
return $column_type_list[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 이름, 값, operation, type으로 값을 변경
|
||||
* like, like_prefix의 경우 value자체가 변경됨
|
||||
* type == number가 아니면 addQuotes()를 하고 ' ' 로 묶음
|
||||
**/
|
||||
function getConditionValue($name, $value, $operation, $type) {
|
||||
if($type == 'number') {
|
||||
if(strpos($value,',')===false && strpos($value,'(')===false) return (int)$value;
|
||||
return $value;
|
||||
}
|
||||
|
||||
$value = preg_replace('/(^\'|\'$){1}/','',$value);
|
||||
|
||||
switch($operation) {
|
||||
case 'like_prefix' :
|
||||
$value = $value.'%';
|
||||
break;
|
||||
case 'like_tail' :
|
||||
$value = '%'.$value;
|
||||
break;
|
||||
case 'like' :
|
||||
$value = '%'.$value.'%';
|
||||
break;
|
||||
case 'in' :
|
||||
return "'".$value."'";
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
if(strpos($name,'.')!==false && strpos($value,'.')!==false) return $value;
|
||||
|
||||
return "'".$this->addQuotes($value)."'";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 이름, 값, operation으로 조건절 작성
|
||||
* 조건절을 완성하기 위해 세부 조건절 마다 정리를 해서 return
|
||||
**/
|
||||
function getConditionPart($name, $value, $operation) {
|
||||
switch($operation) {
|
||||
case 'equal' :
|
||||
if(!$value) return;
|
||||
return $name.' = '.$value;
|
||||
break;
|
||||
case 'more' :
|
||||
if(!$value) return;
|
||||
return $name.' >= '.$value;
|
||||
break;
|
||||
case 'excess' :
|
||||
if(!$value) return;
|
||||
return $name.' > '.$value;
|
||||
break;
|
||||
case 'less' :
|
||||
if(!$value) return;
|
||||
return $name.' <= '.$value;
|
||||
break;
|
||||
case 'below' :
|
||||
if(!$value) return;
|
||||
return $name.' < '.$value;
|
||||
break;
|
||||
case 'like_tail' :
|
||||
case 'like_prefix' :
|
||||
case 'like' :
|
||||
if(!$value) return;
|
||||
return $name.' like '.$value;
|
||||
break;
|
||||
case 'in' :
|
||||
if(!$value) return;
|
||||
return $name.' in ('.$value.')';
|
||||
break;
|
||||
case 'notequal' :
|
||||
if(!$value) return;
|
||||
return $name.' <> '.$value;
|
||||
break;
|
||||
case 'notnull' :
|
||||
return $name.' is not null';
|
||||
break;
|
||||
case 'null' :
|
||||
return $name.' is null';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
688
classes/db/DBCubrid.class.php
Normal file
688
classes/db/DBCubrid.class.php
Normal file
|
|
@ -0,0 +1,688 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DBCubrid
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief Cubrid DBMS를 이용하기 위한 class
|
||||
* @version 0.1
|
||||
*
|
||||
* cubrid 7.0 에서 테스트 하였음.
|
||||
* 기본 쿼리만 사용하였기에 특화된 튜닝이 필요
|
||||
**/
|
||||
|
||||
class DBCubrid extends DB {
|
||||
|
||||
/**
|
||||
* @brief Cubrid DB에 접속하기 위한 정보
|
||||
**/
|
||||
var $hostname = '127.0.0.1'; ///< hostname
|
||||
var $userid = NULL; ///< user id
|
||||
var $password = NULL; ///< password
|
||||
var $database = NULL; ///< database
|
||||
var $port = 33000; ///< db server port
|
||||
var $prefix = 'xe'; ///< 제로보드에서 사용할 테이블들의 prefix (한 DB에서 여러개의 제로보드 설치 가능)
|
||||
var $cutlen = 12000; ///< 큐브리드의 최대 상수 크기(스트링이 이보다 크면 '...'+'...' 방식을 사용해야 한다
|
||||
|
||||
/**
|
||||
* @brief cubrid에서 사용될 column type
|
||||
*
|
||||
* column_type은 schema/query xml에서 공통 선언된 type을 이용하기 때문에
|
||||
* 각 DBMS에 맞게 replace 해주어야 한다
|
||||
**/
|
||||
var $column_type = array(
|
||||
'bignumber' => 'numeric(20)',
|
||||
'number' => 'integer',
|
||||
'varchar' => 'character varying',
|
||||
'char' => 'character',
|
||||
'text' => 'character varying(1073741823)',
|
||||
'bigtext' => 'character varying(1073741823)',
|
||||
'date' => 'character varying(14)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function DBCubrid() {
|
||||
$this->_setDBInfo();
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치 가능 여부를 return
|
||||
**/
|
||||
function isSupported() {
|
||||
if(!function_exists('cubrid_connect')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보 설정 및 connect/ close
|
||||
**/
|
||||
function _setDBInfo() {
|
||||
$db_info = Context::getDBInfo();
|
||||
$this->hostname = $db_info->db_hostname;
|
||||
$this->userid = $db_info->db_userid;
|
||||
$this->password = $db_info->db_password;
|
||||
$this->database = $db_info->db_database;
|
||||
$this->port = $db_info->db_port;
|
||||
$this->prefix = $db_info->db_table_prefix;
|
||||
if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 접속
|
||||
**/
|
||||
function _connect() {
|
||||
// db 정보가 없으면 무시
|
||||
if(!$this->hostname || !$this->userid || !$this->password || !$this->database || !$this->port) return;
|
||||
|
||||
// 접속시도
|
||||
$this->fd = @cubrid_connect($this->hostname, $this->port, $this->database, $this->userid, $this->password);
|
||||
|
||||
// 접속체크
|
||||
if(!$this->fd) {
|
||||
$this->setError(-1, 'database connect fail');
|
||||
return $this->is_connected = false;
|
||||
}
|
||||
|
||||
$this->is_connected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB접속 해제
|
||||
**/
|
||||
function close() {
|
||||
if(!$this->isConnected()) return;
|
||||
@cubrid_commit($this->fd);
|
||||
@cubrid_disconnect($this->fd);
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리에서 입력되는 문자열 변수들의 quotation 조절
|
||||
**/
|
||||
function addQuotes($string) {
|
||||
if(!$this->fd) return $string;
|
||||
if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
|
||||
if(!is_numeric($string)) $string = str_replace("'","''",$string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 트랜잭션 시작
|
||||
**/
|
||||
function begin() {
|
||||
if(!$this->isConnected() || $this->transaction_started) return;
|
||||
$this->transaction_started = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 롤백
|
||||
**/
|
||||
function rollback() {
|
||||
if(!$this->isConnected() || !$this->transaction_started) return;
|
||||
@cubrid_rollback($this->fd);
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 커밋
|
||||
**/
|
||||
function commit() {
|
||||
if(!$force && (!$this->isConnected() || !$this->transaction_started)) return;
|
||||
@cubrid_commit($this->fd);
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief : 쿼리문의 실행 및 결과의 fetch 처리
|
||||
*
|
||||
* query : query문 실행하고 result return\n
|
||||
* fetch : reutrn 된 값이 없으면 NULL\n
|
||||
* rows이면 array object\n
|
||||
* row이면 object\n
|
||||
* return\n
|
||||
**/
|
||||
function _query($query) {
|
||||
//echo "(((".$this->backtrace().")))";
|
||||
if(!$query || !$this->isConnected()) return;
|
||||
|
||||
// 쿼리 시작을 알림
|
||||
$this->actStart($query);
|
||||
|
||||
// 쿼리 문 실행
|
||||
$result = @cubrid_execute($this->fd, $query);
|
||||
|
||||
// 오류 체크
|
||||
if(cubrid_error_code()) $this->setError(cubrid_error_code(), cubrid_error_msg());
|
||||
|
||||
// 쿼리 실행 종료를 알림
|
||||
$this->actFinish();
|
||||
|
||||
// 결과 리턴
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 결과를 fetch
|
||||
**/
|
||||
function _fetch($result) {
|
||||
if(!$this->isConnected() || $this->isError() || !$result) return;
|
||||
|
||||
while($tmp = cubrid_fetch($result, CUBRID_OBJECT)) {
|
||||
$output[] = $tmp;
|
||||
}
|
||||
|
||||
if($result) cubrid_close_request($result);
|
||||
|
||||
if(count($output)==1) return $output[0];
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 1씩 증가되는 sequence값을 return (cubrid의 auto_increment는 sequence테이블에서만 사용)
|
||||
**/
|
||||
function getNextSequence() {
|
||||
$query = sprintf("select %ssequence.nextval as seq from db_root", $this->prefix);
|
||||
$result = $this->_query($query);
|
||||
$output = $this->_fetch($result);
|
||||
return $output->seq;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 테이블 기생성 여부 return
|
||||
**/
|
||||
function isTableExists($target_name) {
|
||||
if($target_name == 'sequence')
|
||||
$query = sprintf("select * from db_serial where name = '%s%s'", $this->prefix, $target_name);
|
||||
else
|
||||
$query = sprintf("select * from db_class where class_name = '%s%s'", $this->prefix, $target_name);
|
||||
$result = $this->_query($query);
|
||||
|
||||
if(cubrid_num_rows($result)>0) $output = true;
|
||||
else $output = false;
|
||||
|
||||
if($result) cubrid_close_request($result);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블에 특정 column 추가
|
||||
**/
|
||||
function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
|
||||
$type = $this->column_type[$type];
|
||||
if(strtoupper($type)=='INTEGER') $size = '';
|
||||
|
||||
$query = sprintf("alter class %s%s add %s ", $this->prefix, $table_name, $column_name);
|
||||
if($size) $query .= sprintf(" %s(%s) ", $type, $size);
|
||||
else $query .= sprintf(" %s ", $type);
|
||||
if($default) $query .= sprintf(" default '%s' ", $default);
|
||||
if($notnull) $query .= " not null ";
|
||||
|
||||
$this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블의 column의 정보를 return
|
||||
**/
|
||||
function isColumnExists($table_name, $column_name) {
|
||||
$query = sprintf("select * from db_attribute where attr_name ='%s' and class_name = '%s%s'",
|
||||
$column_name, $this->prefix, $table_name);
|
||||
$result = $this->_query($query);
|
||||
if(cubrid_num_rows($result)>0) $output = true;
|
||||
else $output = false;
|
||||
|
||||
if($result) cubrid_close_request($result);
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXml($xml_doc) {
|
||||
return $this->_createTable($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXmlFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($file_name);
|
||||
return $this->_createTable($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief schema xml을 이용하여 create class query생성
|
||||
*
|
||||
* type : number, varchar, text, char, date, \n
|
||||
* opt : notnull, default, size\n
|
||||
* index : primary key, index, unique\n
|
||||
**/
|
||||
function _createTable($xml_doc) {
|
||||
// xml parsing
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse($xml_doc);
|
||||
|
||||
// 테이블 생성 schema 작성
|
||||
$table_name = $xml_obj->table->attrs->name;
|
||||
|
||||
// 만약 테이블 이름이 sequence라면 serial 생성
|
||||
if($table_name == 'sequence') {
|
||||
|
||||
$query = sprintf('create serial %s start with 1 increment by 1 minvalue 1 maxvalue 10000000000000000000000000000000000000 nocycle;', $this->prefix.$table_name);
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
if($this->isTableExists($table_name)) return;
|
||||
|
||||
$table_name = $this->prefix.$table_name;
|
||||
|
||||
$query = sprintf('create class %s;', $table_name);
|
||||
$this->_query($query);
|
||||
|
||||
$query = sprintf("call change_owner('%s','%s') on class db_root;", $table_name, $this->userid);
|
||||
$this->_query($query);
|
||||
|
||||
if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
|
||||
else $columns = $xml_obj->table->column;
|
||||
|
||||
$query = sprintf("alter class %s add attribute ", $table_name);
|
||||
|
||||
foreach($columns as $column) {
|
||||
$name = $column->attrs->name;
|
||||
$type = $column->attrs->type;
|
||||
$size = $column->attrs->size;
|
||||
$notnull = $column->attrs->notnull;
|
||||
$primary_key = $column->attrs->primary_key;
|
||||
$index = $column->attrs->index;
|
||||
$unique = $column->attrs->unique;
|
||||
$default = $column->attrs->default;
|
||||
|
||||
switch($this->column_type[$type]) {
|
||||
case 'integer' :
|
||||
$size = null;
|
||||
break;
|
||||
case 'text' :
|
||||
$size = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if($default && !is_numeric($default)) $default = "'".$default."'";
|
||||
|
||||
$column_schema[] = sprintf('"%s" %s%s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$size?'('.$size.')':'',
|
||||
$default?"default ".$default:'',
|
||||
$notnull?'not null':''
|
||||
);
|
||||
|
||||
if($primary_key) $primary_list[] = $name;
|
||||
else if($unique) $unique_list[$unique][] = $name;
|
||||
else if($index) $index_list[$index][] = $name;
|
||||
}
|
||||
|
||||
$query .= implode(',', $column_schema).';';
|
||||
$this->_query($query);
|
||||
|
||||
if(count($primary_list)) {
|
||||
$query = sprintf("alter class %s add attribute constraint \"pkey_%s\" PRIMARY KEY(%s);", $table_name, $table_name, '"'.implode('","',$primary_list).'"');
|
||||
$this->_query($query);
|
||||
}
|
||||
|
||||
if(count($unique_list)) {
|
||||
foreach($unique_list as $key => $val) {
|
||||
$query = sprintf("create unique index %s_%s on %s (%s);", $table_name, $key, $table_name, '"'.implode('","',$val).'"');
|
||||
$this->_query($query);
|
||||
}
|
||||
}
|
||||
|
||||
if(count($index_list)) {
|
||||
foreach($index_list as $key => $val) {
|
||||
$query = sprintf("create index %s_%s on %s (%s);", $table_name, $key, $table_name, '"'.implode('","',$val).'"');
|
||||
$this->_query($query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 조건문 작성하여 return
|
||||
**/
|
||||
function getCondition($output) {
|
||||
if(!$output->conditions) return;
|
||||
|
||||
$condition = "";
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$sub_condition = '';
|
||||
foreach($val['condition'] as $k =>$v) {
|
||||
if(!$v['value']) continue;
|
||||
|
||||
$name = $v['column'];
|
||||
$operation = $v['operation'];
|
||||
$value = $v['value'];
|
||||
$type = $this->getColumnType($output->column_type,$name);
|
||||
$pipe = $v['pipe'];
|
||||
|
||||
$value = $this->getConditionValue($name, $value, $operation, $type);
|
||||
if(!$value) $value = $v['value'];
|
||||
if(strpos($name,'.')===false) $name = '"'.$name.'"';
|
||||
|
||||
$str = $this->getConditionPart($name, $value, $operation);
|
||||
|
||||
if($sub_condition) $sub_condition .= ' '.$pipe.' ';
|
||||
$sub_condition .= $str;
|
||||
}
|
||||
|
||||
if($sub_condition) {
|
||||
if($condition && $val['pipe']) $condition .= ' '.$val['pipe'].' ';
|
||||
$condition .= '('.$sub_condition.')';
|
||||
}
|
||||
}
|
||||
|
||||
if($condition) $condition = ' where '.$condition;
|
||||
return $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insertAct 처리
|
||||
**/
|
||||
function _executeInsertAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '"'.$this->prefix.$key.'"';
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if($this->getColumnType($output->column_type,$name)!='number') {
|
||||
$clen=strlen($value);
|
||||
if ($clen <= $this->cutlen)
|
||||
$value = "'".$this->addQuotes($value)."'";
|
||||
else {
|
||||
$wrk="";
|
||||
$off=0;
|
||||
while ($off<$clen) {
|
||||
$wlen=$clen-$off;
|
||||
if ($wlen>$this->cutlen) $wlen=$this->cutlen;
|
||||
if ($off>0) $wrk .= "+\n";
|
||||
$wrk .= "'".$this->addQuotes(substr($value, $off, $wlen))."'";
|
||||
$off += $wlen;
|
||||
}
|
||||
$value = $wrk;
|
||||
}
|
||||
if(!$value) $value = 'null';
|
||||
} elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
if(strpos($name,'.')===false) $column_list[] = '"'.$name.'"';
|
||||
else $column_list[] = $name;
|
||||
$value_list[] = $value;
|
||||
}
|
||||
|
||||
$query = sprintf("insert into %s (%s) values (%s);", implode(',',$table_list), implode(',',$column_list), implode(',', $value_list));
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief updateAct 처리
|
||||
**/
|
||||
function _executeUpdateAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = "\"".$this->prefix.$key."\" as ".$val;
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if(strpos($name,'.')!==false&&strpos($value,'.')!==false) $column_list[] = $name.' = '.$value;
|
||||
else {
|
||||
if($output->column_type[$name]!='number') {
|
||||
$clen=strlen($value);
|
||||
if ($clen <= $this->cutlen)
|
||||
$value = "'".$this->addQuotes($value)."'";
|
||||
else {
|
||||
$wrk="";
|
||||
$off=0;
|
||||
while ($off<$clen) {
|
||||
$wlen=$clen-$off;
|
||||
if ($wlen>$this->cutlen) $wlen=$this->cutlen;
|
||||
if ($off>0) $wrk .= "+\n";
|
||||
$wrk .= "'".$this->addQuotes(substr($value, $off, $wlen))."'";
|
||||
$off += $wlen;
|
||||
}
|
||||
$value = $wrk;
|
||||
}
|
||||
}
|
||||
elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = sprintf("\"%s\" = %s", $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("update %s set %s %s", implode(',',$table_list), implode(',',$column_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deleteAct 처리
|
||||
**/
|
||||
function _executeDeleteAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '"'.$this->prefix.$key.'"';
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("delete from %s %s", implode(',',$table_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief selectAct 처리
|
||||
*
|
||||
* select의 경우 특정 페이지의 목록을 가져오는 것을 편하게 하기 위해\n
|
||||
* navigation이라는 method를 제공
|
||||
**/
|
||||
function _executeSelectAct($output) {
|
||||
// 테이블 정리
|
||||
$table_list = array();
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '"'.$this->prefix.$key.'" as '.$val;
|
||||
}
|
||||
|
||||
if(!$output->columns) {
|
||||
$columns = '*';
|
||||
} else {
|
||||
$column_list = array();
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$alias = $val['alias'];
|
||||
if($name == '*') {
|
||||
$column_list[] = '*';
|
||||
} elseif(strpos($name,'.')===false && strpos($name,'(')===false) {
|
||||
if($alias) $column_list[] = sprintf('"%s" as "%s"', $name, $alias);
|
||||
else $column_list[] = sprintf('"%s"',$name);
|
||||
} else {
|
||||
if(strpos($name,'.')!=false) {
|
||||
list($prefix, $name) = explode('.',$name);
|
||||
$deli=($name == '*') ? "" : "\"";
|
||||
if($alias) $column_list[] = sprintf("%s.$deli%s$deli as \"%s\"", $prefix, $name, $alias);
|
||||
else $column_list[] = sprintf("%s.$deli%s$deli",$prefix,$name);
|
||||
} else {
|
||||
if($alias) $column_list[] = sprintf('%s as "%s"', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
}
|
||||
}
|
||||
}
|
||||
$columns = implode(',',$column_list);
|
||||
}
|
||||
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output);
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$data = $this->_fetch($result);
|
||||
|
||||
$buff = new Object();
|
||||
$buff->data = $data;
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 현재 시점의 Stack trace를 보여줌.결과를 fetch
|
||||
**/
|
||||
function backtrace()
|
||||
{
|
||||
$output = "<div style='text-align: left;'>\n";
|
||||
$output .= "<b>Backtrace:</b><br />\n";
|
||||
$backtrace = debug_backtrace();
|
||||
|
||||
foreach ($backtrace as $bt) {
|
||||
$args = '';
|
||||
foreach ($bt['args'] as $a) {
|
||||
if (!empty($args)) {
|
||||
$args .= ', ';
|
||||
}
|
||||
switch (gettype($a)) {
|
||||
case 'integer':
|
||||
case 'double':
|
||||
$args .= $a;
|
||||
break;
|
||||
case 'string':
|
||||
$a = htmlspecialchars(substr($a, 0, 64)).((strlen($a) > 64) ? '...' : '');
|
||||
$args .= "\"$a\"";
|
||||
break;
|
||||
case 'array':
|
||||
$args .= 'Array('.count($a).')';
|
||||
break;
|
||||
case 'object':
|
||||
$args .= 'Object('.get_class($a).')';
|
||||
break;
|
||||
case 'resource':
|
||||
$args .= 'Resource('.strstr($a, '#').')';
|
||||
break;
|
||||
case 'boolean':
|
||||
$args .= $a ? 'True' : 'False';
|
||||
break;
|
||||
case 'NULL':
|
||||
$args .= 'Null';
|
||||
break;
|
||||
default:
|
||||
$args .= 'Unknown';
|
||||
}
|
||||
}
|
||||
$output .= "<br />\n";
|
||||
$output .= "<b>file:</b> {$bt['line']} - {$bt['file']}<br />\n";
|
||||
$output .= "<b>call:</b> {$bt['class']}{$bt['type']}{$bt['function']}($args)<br />\n";
|
||||
}
|
||||
$output .= "</div>\n";
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다
|
||||
*
|
||||
* 그닥 좋지는 않은 구조이지만 편리하다.. -_-;
|
||||
**/
|
||||
function _getNavigationData($table_list, $columns, $condition, $output) {
|
||||
require_once('./classes/page/PageHandler.class.php');
|
||||
|
||||
// 전체 개수를 구함
|
||||
$count_query = sprintf('select count(*) as "count" from %s %s', implode(',',$table_list), $condition);
|
||||
$result = $this->_query($count_query);
|
||||
$count_output = $this->_fetch($result);
|
||||
$total_count = (int)$count_output->count;
|
||||
|
||||
$list_count = $output->list_count['value'];
|
||||
if(!$list_count) $list_count = 20;
|
||||
$page_count = $output->page_count['value'];
|
||||
if(!$page_count) $page_count = 10;
|
||||
$page = $output->page['value'];
|
||||
if(!$page) $page = 1;
|
||||
|
||||
// 전체 페이지를 구함
|
||||
if($total_count) $total_page = (int)( ($total_count-1) / $list_count) + 1;
|
||||
else $total_page = 1;
|
||||
|
||||
// 페이지 변수를 체크
|
||||
if($page > $total_page) $page = $total_page;
|
||||
$start_count = ($page-1)*$list_count;
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if ($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
$query = sprintf('%s for orderby_num() between %d and %d', $query, $start_count, $list_count);
|
||||
}
|
||||
else {
|
||||
if (count($output->groups))
|
||||
$query = sprintf('%s having groupby_num() between %d and %d', $query, $start_count, $list_count);
|
||||
else {
|
||||
if ($condition)
|
||||
$query = sprintf('%s and inst_num() between %d and %d', $query, $start_count, $list_count);
|
||||
else
|
||||
$query = sprintf('%s where inst_num() between %d and %d', $query, $start_count, $list_count);
|
||||
}
|
||||
}
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) {
|
||||
$buff = new Object();
|
||||
$buff->total_count = 0;
|
||||
$buff->total_page = 0;
|
||||
$buff->page = 1;
|
||||
$buff->data = array();
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
|
||||
$virtual_no = $total_count - ($page-1)*$list_count;
|
||||
while($tmp = cubrid_fetch($result, CUBRID_OBJECT)) {
|
||||
$data[$virtual_no--] = $tmp;
|
||||
}
|
||||
|
||||
$buff = new Object();
|
||||
$buff->total_count = $total_count;
|
||||
$buff->total_page = $total_page;
|
||||
$buff->page = $page;
|
||||
$buff->data = $data;
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
}
|
||||
?>
|
||||
552
classes/db/DBMysql.class.php
Normal file
552
classes/db/DBMysql.class.php
Normal file
|
|
@ -0,0 +1,552 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DBMysql
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief MySQL DBMS를 이용하기 위한 class
|
||||
* @version 0.1
|
||||
*
|
||||
* mysql handling class
|
||||
**/
|
||||
|
||||
class DBMysql extends DB {
|
||||
|
||||
/**
|
||||
* @brief Mysql DB에 접속하기 위한 정보
|
||||
**/
|
||||
var $hostname = '127.0.0.1'; ///< hostname
|
||||
var $userid = NULL; ///< user id
|
||||
var $password = NULL; ///< password
|
||||
var $database = NULL; ///< database
|
||||
var $prefix = 'xe'; ///< 제로보드에서 사용할 테이블들의 prefix (한 DB에서 여러개의 제로보드 설치 가능)
|
||||
|
||||
/**
|
||||
* @brief mysql에서 사용될 column type
|
||||
*
|
||||
* column_type은 schema/query xml에서 공통 선언된 type을 이용하기 때문에
|
||||
* 각 DBMS에 맞게 replace 해주어야 한다
|
||||
**/
|
||||
var $column_type = array(
|
||||
'bignumber' => 'bigint',
|
||||
'number' => 'bigint',
|
||||
'varchar' => 'varchar',
|
||||
'char' => 'char',
|
||||
'text' => 'text',
|
||||
'bigtext' => 'longtext',
|
||||
'date' => 'varchar(14)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function DBMysql() {
|
||||
$this->_setDBInfo();
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치 가능 여부를 return
|
||||
**/
|
||||
function isSupported() {
|
||||
if(!function_exists('mysql_connect')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보 설정 및 connect/ close
|
||||
**/
|
||||
function _setDBInfo() {
|
||||
$db_info = Context::getDBInfo();
|
||||
$this->hostname = $db_info->db_hostname;
|
||||
$this->userid = $db_info->db_userid;
|
||||
$this->password = $db_info->db_password;
|
||||
$this->database = $db_info->db_database;
|
||||
$this->prefix = $db_info->db_table_prefix;
|
||||
if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 접속
|
||||
**/
|
||||
function _connect() {
|
||||
// db 정보가 없으면 무시
|
||||
if(!$this->hostname || !$this->userid || !$this->password || !$this->database) return;
|
||||
|
||||
// 접속시도
|
||||
$this->fd = @mysql_connect($this->hostname, $this->userid, $this->password);
|
||||
if(mysql_error()) {
|
||||
$this->setError(mysql_errno(), mysql_error());
|
||||
return;
|
||||
}
|
||||
|
||||
// 버전 확인후 4.1 이하면 오류 표시
|
||||
if(mysql_get_server_info($this->fd)<"4.1") {
|
||||
$this->setError(-1, "zeroboard xe can not install under mysql 4.1. Current mysql version is ".mysql_get_server_info());
|
||||
return;
|
||||
}
|
||||
|
||||
// db 선택
|
||||
@mysql_select_db($this->database, $this->fd);
|
||||
if(mysql_error()) {
|
||||
$this->setError(mysql_errno(), mysql_error());
|
||||
return;
|
||||
}
|
||||
|
||||
// 접속체크
|
||||
$this->is_connected = true;
|
||||
|
||||
// mysql의 경우 utf8임을 지정
|
||||
$this->_query("set names 'utf8'");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB접속 해제
|
||||
**/
|
||||
function close() {
|
||||
if(!$this->isConnected()) return;
|
||||
@mysql_close($this->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리에서 입력되는 문자열 변수들의 quotation 조절
|
||||
**/
|
||||
function addQuotes($string) {
|
||||
if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
|
||||
if(!is_numeric($string)) $string = @mysql_escape_string($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 트랜잭션 시작
|
||||
**/
|
||||
function begin() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 롤백
|
||||
**/
|
||||
function rollback() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 커밋
|
||||
**/
|
||||
function commit() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : 쿼리문의 실행 및 결과의 fetch 처리
|
||||
*
|
||||
* query : query문 실행하고 result return\n
|
||||
* fetch : reutrn 된 값이 없으면 NULL\n
|
||||
* rows이면 array object\n
|
||||
* row이면 object\n
|
||||
* return\n
|
||||
**/
|
||||
function _query($query) {
|
||||
if(!$this->isConnected()) return;
|
||||
|
||||
// 쿼리 시작을 알림
|
||||
$this->actStart($query);
|
||||
|
||||
// 쿼리 문 실행
|
||||
$result = @mysql_query($query, $this->fd);
|
||||
|
||||
// 오류 체크
|
||||
if(mysql_error($this->fd)) $this->setError(mysql_errno($this->fd), mysql_error($this->fd));
|
||||
|
||||
// 쿼리 실행 종료를 알림
|
||||
$this->actFinish();
|
||||
|
||||
// 결과 리턴
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 결과를 fetch
|
||||
**/
|
||||
function _fetch($result) {
|
||||
if(!$this->isConnected() || $this->isError() || !$result) return;
|
||||
while($tmp = mysql_fetch_object($result)) {
|
||||
$output[] = $tmp;
|
||||
}
|
||||
if(count($output)==1) return $output[0];
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 1씩 증가되는 sequence값을 return (mysql의 auto_increment는 sequence테이블에서만 사용)
|
||||
**/
|
||||
function getNextSequence() {
|
||||
$query = sprintf("insert into `%ssequence` (seq) values ('')", $this->prefix);
|
||||
$this->_query($query);
|
||||
$sequence = mysql_insert_id();
|
||||
$query = sprintf("delete from `%ssequence` where seq < %d", $this->prefix, $sequence);
|
||||
$this->_query($query);
|
||||
|
||||
return $sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 테이블 기생성 여부 return
|
||||
**/
|
||||
function isTableExists($target_name) {
|
||||
$query = sprintf("show tables like '%s%s'", $this->prefix, $this->addQuotes($target_name));
|
||||
$result = $this->_query($query);
|
||||
$tmp = $this->_fetch($result);
|
||||
if(!$tmp) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블에 특정 column 추가
|
||||
**/
|
||||
function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
|
||||
$type = $this->column_type[$type];
|
||||
if(strtoupper($type)=='INTEGER') $size = '';
|
||||
|
||||
$query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name);
|
||||
if($size) $query .= sprintf(" %s(%s) ", $type, $size);
|
||||
else $query .= sprintf(" %s ", $type);
|
||||
if($default) $query .= sprintf(" default '%s' ", $default);
|
||||
if($notnull) $query .= " not null ";
|
||||
|
||||
$this->_query($query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블의 column의 정보를 return
|
||||
**/
|
||||
function isColumnExists($table_name, $column_name) {
|
||||
$query = sprintf("show fields from %s%s", $this->prefix, $table_name);
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$output = $this->_fetch($result);
|
||||
if($output) {
|
||||
$column_name = strtolower($column_name);
|
||||
foreach($output as $key => $val) {
|
||||
$name = strtolower($val->Field);
|
||||
if($column_name == $name) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXml($xml_doc) {
|
||||
return $this->_createTable($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXmlFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($file_name);
|
||||
return $this->_createTable($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief schema xml을 이용하여 create table query생성
|
||||
*
|
||||
* type : number, varchar, text, char, date, \n
|
||||
* opt : notnull, default, size\n
|
||||
* index : primary key, index, unique\n
|
||||
**/
|
||||
function _createTable($xml_doc) {
|
||||
// xml parsing
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse($xml_doc);
|
||||
|
||||
// 테이블 생성 schema 작성
|
||||
$table_name = $xml_obj->table->attrs->name;
|
||||
if($this->isTableExists($table_name)) return;
|
||||
$table_name = $this->prefix.$table_name;
|
||||
|
||||
if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
|
||||
else $columns = $xml_obj->table->column;
|
||||
|
||||
foreach($columns as $column) {
|
||||
$name = $column->attrs->name;
|
||||
$type = $column->attrs->type;
|
||||
$size = $column->attrs->size;
|
||||
$notnull = $column->attrs->notnull;
|
||||
$primary_key = $column->attrs->primary_key;
|
||||
$index = $column->attrs->index;
|
||||
$unique = $column->attrs->unique;
|
||||
$default = $column->attrs->default;
|
||||
$auto_increment = $column->attrs->auto_increment;
|
||||
|
||||
$column_schema[] = sprintf('`%s` %s%s %s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$size?'('.$size.')':'',
|
||||
$default?"default '".$default."'":'',
|
||||
$notnull?'not null':'',
|
||||
$auto_increment?'auto_increment':''
|
||||
);
|
||||
|
||||
if($primary_key) $primary_list[] = $name;
|
||||
else if($unique) $unique_list[$unique][] = $name;
|
||||
else if($index) $index_list[$index][] = $name;
|
||||
}
|
||||
|
||||
if(count($primary_list)) {
|
||||
$column_schema[] = sprintf("primary key (%s)", '`'.implode($primary_list,'`,`').'`');
|
||||
}
|
||||
|
||||
if(count($unique_list)) {
|
||||
foreach($unique_list as $key => $val) {
|
||||
$column_schema[] = sprintf("unique %s (%s)", $key, '`'.implode($val,'`,`').'`');
|
||||
}
|
||||
}
|
||||
|
||||
if(count($index_list)) {
|
||||
foreach($index_list as $key => $val) {
|
||||
$column_schema[] = sprintf("index %s (%s)", $key, '`'.implode($val,'`,`').'`');
|
||||
}
|
||||
}
|
||||
|
||||
$schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema,",\n"), "ENGINE = MYISAM CHARACTER SET utf8 COLLATE utf8_general_ci");
|
||||
|
||||
$output = $this->_query($schema);
|
||||
if(!$output) return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 조건문 작성하여 return
|
||||
**/
|
||||
function getCondition($output) {
|
||||
if(!$output->conditions) return;
|
||||
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$sub_condition = '';
|
||||
foreach($val['condition'] as $k =>$v) {
|
||||
if(!$v['value']) continue;
|
||||
|
||||
$name = $v['column'];
|
||||
$operation = $v['operation'];
|
||||
$value = $v['value'];
|
||||
$type = $this->getColumnType($output->column_type,$name);
|
||||
$pipe = $v['pipe'];
|
||||
|
||||
$value = $this->getConditionValue($name, $value, $operation, $type);
|
||||
if(!$value) $value = $v['value'];
|
||||
$str = $this->getConditionPart($name, $value, $operation);
|
||||
if($sub_condition) $sub_condition .= ' '.$pipe.' ';
|
||||
$sub_condition .= $str;
|
||||
}
|
||||
if($sub_condition) {
|
||||
if($condition && $val['pipe']) $condition .= ' '.$val['pipe'].' ';
|
||||
$condition .= '('.$sub_condition.')';
|
||||
}
|
||||
}
|
||||
|
||||
if($condition) $condition = ' where '.$condition;
|
||||
return $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insertAct 처리
|
||||
**/
|
||||
function _executeInsertAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'`';
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if($output->column_type[$name]!='number') {
|
||||
$value = "'".$this->addQuotes($value)."'";
|
||||
if(!$value) $value = 'null';
|
||||
} elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = '`'.$name.'`';
|
||||
$value_list[] = $value;
|
||||
}
|
||||
|
||||
$query = sprintf("insert into %s (%s) values (%s);", implode(',',$table_list), implode(',',$column_list), implode(',', $value_list));
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief updateAct 처리
|
||||
**/
|
||||
function _executeUpdateAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'` as '.$val;
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if(strpos($name,'.')!==false&&strpos($value,'.')!==false) $column_list[] = $name.' = '.$value;
|
||||
else {
|
||||
if($output->column_type[$name]!='number') $value = "'".$this->addQuotes($value)."'";
|
||||
elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = sprintf("`%s` = %s", $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("update %s set %s %s", implode(',',$table_list), implode(',',$column_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deleteAct 처리
|
||||
**/
|
||||
function _executeDeleteAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'`';
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("delete from %s %s", implode(',',$table_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief selectAct 처리
|
||||
*
|
||||
* select의 경우 특정 페이지의 목록을 가져오는 것을 편하게 하기 위해\n
|
||||
* navigation이라는 method를 제공
|
||||
**/
|
||||
function _executeSelectAct($output) {
|
||||
// 테이블 정리
|
||||
$table_list = array();
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'` as '.$val;
|
||||
}
|
||||
|
||||
if(!$output->columns) {
|
||||
$columns = '*';
|
||||
} else {
|
||||
$column_list = array();
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$alias = $val['alias'];
|
||||
if($name == '*') {
|
||||
$column_list[] = '*';
|
||||
} elseif(strpos($name,'.')===false && strpos($name,'(')===false) {
|
||||
if($alias) $column_list[] = sprintf('`%s` as `%s`', $name, $alias);
|
||||
else $column_list[] = sprintf('`%s`',$name);
|
||||
} else {
|
||||
if($alias) $column_list[] = sprintf('%s as `%s`', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
}
|
||||
}
|
||||
$columns = implode(',',$column_list);
|
||||
}
|
||||
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output);
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$data = $this->_fetch($result);
|
||||
|
||||
$buff = new Object();
|
||||
$buff->data = $data;
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다
|
||||
*
|
||||
* 그닥 좋지는 않은 구조이지만 편리하다.. -_-;
|
||||
**/
|
||||
function _getNavigationData($table_list, $columns, $condition, $output) {
|
||||
require_once('./classes/page/PageHandler.class.php');
|
||||
|
||||
// 전체 개수를 구함
|
||||
$count_query = sprintf("select count(*) as count from %s %s", implode(',',$table_list), $condition);
|
||||
$result = $this->_query($count_query);
|
||||
$count_output = $this->_fetch($result);
|
||||
$total_count = (int)$count_output->count;
|
||||
|
||||
$list_count = $output->list_count['value'];
|
||||
if(!$list_count) $list_count = 20;
|
||||
$page_count = $output->page_count['value'];
|
||||
if(!$page_count) $page_count = 10;
|
||||
$page = $output->page['value'];
|
||||
if(!$page) $page = 1;
|
||||
|
||||
// 전체 페이지를 구함
|
||||
if($total_count) $total_page = (int)( ($total_count-1) / $list_count) + 1;
|
||||
else $total_page = 1;
|
||||
|
||||
// 페이지 변수를 체크
|
||||
if($page > $total_page) $page = $total_page;
|
||||
$start_count = ($page-1)*$list_count;
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if(count($output->order)) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$query = sprintf('%s limit %d, %d', $query, $start_count, $list_count);
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) {
|
||||
$buff = new Object();
|
||||
$buff->total_count = 0;
|
||||
$buff->total_page = 0;
|
||||
$buff->page = 1;
|
||||
$buff->data = array();
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
|
||||
$virtual_no = $total_count - ($page-1)*$list_count;
|
||||
while($tmp = mysql_fetch_object($result)) {
|
||||
$data[$virtual_no--] = $tmp;
|
||||
}
|
||||
|
||||
$buff = new Object();
|
||||
$buff->total_count = $total_count;
|
||||
$buff->total_page = $total_page;
|
||||
$buff->page = $page;
|
||||
$buff->data = $data;
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
}
|
||||
?>
|
||||
562
classes/db/DBMysql_innodb.class.php
Normal file
562
classes/db/DBMysql_innodb.class.php
Normal file
|
|
@ -0,0 +1,562 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DBMysql_innodb
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief MySQL DBMS를 이용하기 위한 class
|
||||
* @version 0.1
|
||||
*
|
||||
* mysql innodb handling class
|
||||
**/
|
||||
|
||||
class DBMysql_innodb extends DB {
|
||||
|
||||
/**
|
||||
* @brief Mysql DB에 접속하기 위한 정보
|
||||
**/
|
||||
var $hostname = '127.0.0.1'; ///< hostname
|
||||
var $userid = NULL; ///< user id
|
||||
var $password = NULL; ///< password
|
||||
var $database = NULL; ///< database
|
||||
var $prefix = 'xe'; ///< 제로보드에서 사용할 테이블들의 prefix (한 DB에서 여러개의 제로보드 설치 가능)
|
||||
|
||||
/**
|
||||
* @brief mysql에서 사용될 column type
|
||||
*
|
||||
* column_type은 schema/query xml에서 공통 선언된 type을 이용하기 때문에
|
||||
* 각 DBMS에 맞게 replace 해주어야 한다
|
||||
**/
|
||||
var $column_type = array(
|
||||
'bignumber' => 'bigint',
|
||||
'number' => 'bigint',
|
||||
'varchar' => 'varchar',
|
||||
'char' => 'char',
|
||||
'text' => 'text',
|
||||
'bigtext' => 'longtext',
|
||||
'date' => 'varchar(14)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function DBMysql_innodb() {
|
||||
$this->_setDBInfo();
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치 가능 여부를 return
|
||||
**/
|
||||
function isSupported() {
|
||||
if(!function_exists('mysql_connect')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보 설정 및 connect/ close
|
||||
**/
|
||||
function _setDBInfo() {
|
||||
$db_info = Context::getDBInfo();
|
||||
$this->hostname = $db_info->db_hostname;
|
||||
$this->userid = $db_info->db_userid;
|
||||
$this->password = $db_info->db_password;
|
||||
$this->database = $db_info->db_database;
|
||||
$this->prefix = $db_info->db_table_prefix;
|
||||
if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 접속
|
||||
**/
|
||||
function _connect() {
|
||||
// db 정보가 없으면 무시
|
||||
if(!$this->hostname || !$this->userid || !$this->password || !$this->database) return;
|
||||
|
||||
// 접속시도
|
||||
$this->fd = @mysql_connect($this->hostname, $this->userid, $this->password);
|
||||
if(mysql_error()) {
|
||||
$this->setError(mysql_errno(), mysql_error());
|
||||
return;
|
||||
}
|
||||
|
||||
// 버전 확인후 4.1 이하면 오류 표시
|
||||
if(mysql_get_server_info($this->fd)<"4.1") {
|
||||
$this->setError(-1, "zeroboard xe can not install under mysql 4.1. Current mysql version is ".mysql_get_server_info());
|
||||
return;
|
||||
}
|
||||
|
||||
// db 선택
|
||||
@mysql_select_db($this->database, $this->fd);
|
||||
if(mysql_error()) {
|
||||
$this->setError(mysql_errno(), mysql_error());
|
||||
return;
|
||||
}
|
||||
|
||||
// 접속체크
|
||||
$this->is_connected = true;
|
||||
|
||||
// mysql의 경우 utf8임을 지정
|
||||
$this->_query("set names 'utf8'");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB접속 해제
|
||||
**/
|
||||
function close() {
|
||||
if(!$this->isConnected()) return;
|
||||
$this->_query("commit");
|
||||
@mysql_close($this->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리에서 입력되는 문자열 변수들의 quotation 조절
|
||||
**/
|
||||
function addQuotes($string) {
|
||||
if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
|
||||
if(!is_numeric($string)) $string = @mysql_escape_string($string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 트랜잭션 시작
|
||||
**/
|
||||
function begin() {
|
||||
if(!$this->isConnected() || $this->transaction_started) return;
|
||||
$this->_query("begin");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 롤백
|
||||
**/
|
||||
function rollback() {
|
||||
if(!$this->isConnected() || !$this->transaction_started) return;
|
||||
$this->_query("rollback");
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 커밋
|
||||
**/
|
||||
function commit($force = false) {
|
||||
if(!$force && (!$this->isConnected() || !$this->transaction_started)) return;
|
||||
$this->_query("commit");
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : 쿼리문의 실행 및 결과의 fetch 처리
|
||||
*
|
||||
* query : query문 실행하고 result return\n
|
||||
* fetch : reutrn 된 값이 없으면 NULL\n
|
||||
* rows이면 array object\n
|
||||
* row이면 object\n
|
||||
* return\n
|
||||
**/
|
||||
function _query($query) {
|
||||
if(!$this->isConnected()) return;
|
||||
|
||||
// 쿼리 시작을 알림
|
||||
$this->actStart($query);
|
||||
|
||||
// 쿼리 문 실행
|
||||
$result = @mysql_query($query, $this->fd);
|
||||
|
||||
// 오류 체크
|
||||
if(mysql_error($this->fd)) $this->setError(mysql_errno($this->fd), mysql_error($this->fd));
|
||||
|
||||
// 쿼리 실행 종료를 알림
|
||||
$this->actFinish();
|
||||
|
||||
// 결과 리턴
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 결과를 fetch
|
||||
**/
|
||||
function _fetch($result) {
|
||||
if(!$this->isConnected() || $this->isError() || !$result) return;
|
||||
while($tmp = mysql_fetch_object($result)) {
|
||||
$output[] = $tmp;
|
||||
}
|
||||
if(count($output)==1) return $output[0];
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 1씩 증가되는 sequence값을 return (mysql의 auto_increment는 sequence테이블에서만 사용)
|
||||
**/
|
||||
function getNextSequence() {
|
||||
$query = sprintf("insert into `%ssequence` (seq) values ('')", $this->prefix);
|
||||
$this->_query($query);
|
||||
$sequence = mysql_insert_id();
|
||||
$query = sprintf("delete from `%ssequence` where seq < %d", $this->prefix, $sequence);
|
||||
$this->_query($query);
|
||||
|
||||
return $sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 테이블 기생성 여부 return
|
||||
**/
|
||||
function isTableExists($target_name) {
|
||||
$query = sprintf("show tables like '%s%s'", $this->prefix, $this->addQuotes($target_name));
|
||||
$result = $this->_query($query);
|
||||
$tmp = $this->_fetch($result);
|
||||
if(!$tmp) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블에 특정 column 추가
|
||||
**/
|
||||
function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
|
||||
$type = $this->column_type[$type];
|
||||
if(strtoupper($type)=='INTEGER') $size = '';
|
||||
|
||||
$query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name);
|
||||
if($size) $query .= sprintf(" %s(%s) ", $type, $size);
|
||||
else $query .= sprintf(" %s ", $type);
|
||||
if($default) $query .= sprintf(" default '%s' ", $default);
|
||||
if($notnull) $query .= " not null ";
|
||||
|
||||
$this->_query($query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블의 column의 정보를 return
|
||||
**/
|
||||
function isColumnExists($table_name, $column_name) {
|
||||
$query = sprintf("show fields from %s%s", $this->prefix, $table_name);
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$output = $this->_fetch($result);
|
||||
if($output) {
|
||||
$column_name = strtolower($column_name);
|
||||
foreach($output as $key => $val) {
|
||||
$name = strtolower($val->Field);
|
||||
if($column_name == $name) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXml($xml_doc) {
|
||||
return $this->_createTable($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXmlFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($file_name);
|
||||
return $this->_createTable($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief schema xml을 이용하여 create table query생성
|
||||
*
|
||||
* type : number, varchar, text, char, date, \n
|
||||
* opt : notnull, default, size\n
|
||||
* index : primary key, index, unique\n
|
||||
**/
|
||||
function _createTable($xml_doc) {
|
||||
// xml parsing
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse($xml_doc);
|
||||
|
||||
// 테이블 생성 schema 작성
|
||||
$table_name = $xml_obj->table->attrs->name;
|
||||
if($this->isTableExists($table_name)) return;
|
||||
$table_name = $this->prefix.$table_name;
|
||||
|
||||
if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
|
||||
else $columns = $xml_obj->table->column;
|
||||
|
||||
foreach($columns as $column) {
|
||||
$name = $column->attrs->name;
|
||||
$type = $column->attrs->type;
|
||||
$size = $column->attrs->size;
|
||||
$notnull = $column->attrs->notnull;
|
||||
$primary_key = $column->attrs->primary_key;
|
||||
$index = $column->attrs->index;
|
||||
$unique = $column->attrs->unique;
|
||||
$default = $column->attrs->default;
|
||||
$auto_increment = $column->attrs->auto_increment;
|
||||
|
||||
$column_schema[] = sprintf('`%s` %s%s %s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$size?'('.$size.')':'',
|
||||
$default?"default '".$default."'":'',
|
||||
$notnull?'not null':'',
|
||||
$auto_increment?'auto_increment':''
|
||||
);
|
||||
|
||||
if($primary_key) $primary_list[] = $name;
|
||||
else if($unique) $unique_list[$unique][] = $name;
|
||||
else if($index) $index_list[$index][] = $name;
|
||||
}
|
||||
|
||||
if(count($primary_list)) {
|
||||
$column_schema[] = sprintf("primary key (%s)", '`'.implode($primary_list,'`,`').'`');
|
||||
}
|
||||
|
||||
if(count($unique_list)) {
|
||||
foreach($unique_list as $key => $val) {
|
||||
$column_schema[] = sprintf("unique %s (%s)", $key, '`'.implode($val,'`,`').'`');
|
||||
}
|
||||
}
|
||||
|
||||
if(count($index_list)) {
|
||||
foreach($index_list as $key => $val) {
|
||||
$column_schema[] = sprintf("index %s (%s)", $key, '`'.implode($val,'`,`').'`');
|
||||
}
|
||||
}
|
||||
|
||||
$schema = sprintf('create table `%s` (%s%s) %s;', $this->addQuotes($table_name), "\n", implode($column_schema,",\n"), "ENGINE = INNODB CHARACTER SET utf8 COLLATE utf8_general_ci");
|
||||
|
||||
$output = $this->_query($schema);
|
||||
if(!$output) return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 조건문 작성하여 return
|
||||
**/
|
||||
function getCondition($output) {
|
||||
if(!$output->conditions) return;
|
||||
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$sub_condition = '';
|
||||
foreach($val['condition'] as $k =>$v) {
|
||||
if(!$v['value']) continue;
|
||||
|
||||
$name = $v['column'];
|
||||
$operation = $v['operation'];
|
||||
$value = $v['value'];
|
||||
$type = $this->getColumnType($output->column_type,$name);
|
||||
$pipe = $v['pipe'];
|
||||
|
||||
$value = $this->getConditionValue($name, $value, $operation, $type);
|
||||
if(!$value) $value = $v['value'];
|
||||
$str = $this->getConditionPart($name, $value, $operation);
|
||||
if($sub_condition) $sub_condition .= ' '.$pipe.' ';
|
||||
$sub_condition .= $str;
|
||||
}
|
||||
if($sub_condition) {
|
||||
if($condition && $val['pipe']) $condition .= ' '.$val['pipe'].' ';
|
||||
$condition .= '('.$sub_condition.')';
|
||||
}
|
||||
}
|
||||
|
||||
if($condition) $condition = ' where '.$condition;
|
||||
return $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insertAct 처리
|
||||
**/
|
||||
function _executeInsertAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'`';
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if($output->column_type[$name]!='number') {
|
||||
$value = "'".$this->addQuotes($value)."'";
|
||||
if(!$value) $value = 'null';
|
||||
} elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = '`'.$name.'`';
|
||||
$value_list[] = $value;
|
||||
}
|
||||
|
||||
$query = sprintf("insert into %s (%s) values (%s);", implode(',',$table_list), implode(',',$column_list), implode(',', $value_list));
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief updateAct 처리
|
||||
**/
|
||||
function _executeUpdateAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'` as '.$val;
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if(strpos($name,'.')!==false&&strpos($value,'.')!==false) $column_list[] = $name.' = '.$value;
|
||||
else {
|
||||
if($output->column_type[$name]!='number') $value = "'".$this->addQuotes($value)."'";
|
||||
elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = sprintf("`%s` = %s", $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("update %s set %s %s", implode(',',$table_list), implode(',',$column_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deleteAct 처리
|
||||
**/
|
||||
function _executeDeleteAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'`';
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("delete from %s %s", implode(',',$table_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief selectAct 처리
|
||||
*
|
||||
* select의 경우 특정 페이지의 목록을 가져오는 것을 편하게 하기 위해\n
|
||||
* navigation이라는 method를 제공
|
||||
**/
|
||||
function _executeSelectAct($output) {
|
||||
// 테이블 정리
|
||||
$table_list = array();
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = '`'.$this->prefix.$key.'` as '.$val;
|
||||
}
|
||||
|
||||
if(!$output->columns) {
|
||||
$columns = '*';
|
||||
} else {
|
||||
$column_list = array();
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$alias = $val['alias'];
|
||||
if($name == '*') {
|
||||
$column_list[] = '*';
|
||||
} elseif(strpos($name,'.')===false && strpos($name,'(')===false) {
|
||||
if($alias) $column_list[] = sprintf('`%s` as `%s`', $name, $alias);
|
||||
else $column_list[] = sprintf('`%s`',$name);
|
||||
} else {
|
||||
if($alias) $column_list[] = sprintf('%s as `%s`', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
}
|
||||
}
|
||||
$columns = implode(',',$column_list);
|
||||
}
|
||||
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output);
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$data = $this->_fetch($result);
|
||||
|
||||
$buff = new Object();
|
||||
$buff->data = $data;
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다
|
||||
*
|
||||
* 그닥 좋지는 않은 구조이지만 편리하다.. -_-;
|
||||
**/
|
||||
function _getNavigationData($table_list, $columns, $condition, $output) {
|
||||
require_once('./classes/page/PageHandler.class.php');
|
||||
|
||||
// 전체 개수를 구함
|
||||
$count_query = sprintf("select count(*) as count from %s %s", implode(',',$table_list), $condition);
|
||||
$result = $this->_query($count_query);
|
||||
$count_output = $this->_fetch($result);
|
||||
$total_count = (int)$count_output->count;
|
||||
|
||||
$list_count = $output->list_count['value'];
|
||||
if(!$list_count) $list_count = 20;
|
||||
$page_count = $output->page_count['value'];
|
||||
if(!$page_count) $page_count = 10;
|
||||
$page = $output->page['value'];
|
||||
if(!$page) $page = 1;
|
||||
|
||||
// 전체 페이지를 구함
|
||||
if($total_count) $total_page = (int)( ($total_count-1) / $list_count) + 1;
|
||||
else $total_page = 1;
|
||||
|
||||
// 페이지 변수를 체크
|
||||
if($page > $total_page) $page = $total_page;
|
||||
$start_count = ($page-1)*$list_count;
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$query = sprintf('%s limit %d, %d', $query, $start_count, $list_count);
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) {
|
||||
$buff = new Object();
|
||||
$buff->total_count = 0;
|
||||
$buff->total_page = 0;
|
||||
$buff->page = 1;
|
||||
$buff->data = array();
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
|
||||
$virtual_no = $total_count - ($page-1)*$list_count;
|
||||
while($tmp = mysql_fetch_object($result)) {
|
||||
$data[$virtual_no--] = $tmp;
|
||||
}
|
||||
|
||||
$buff = new Object();
|
||||
$buff->total_count = $total_count;
|
||||
$buff->total_page = $total_page;
|
||||
$buff->page = $page;
|
||||
$buff->data = $data;
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
}
|
||||
?>
|
||||
593
classes/db/DBSqlite2.class.php
Normal file
593
classes/db/DBSqlite2.class.php
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DBSqlite2
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief SQLite ver 2.x 를 이용하기 위한 class
|
||||
* @version 0.1
|
||||
*
|
||||
* sqlite handling class (sqlite ver 2.x)
|
||||
**/
|
||||
|
||||
class DBSqlite2 extends DB {
|
||||
|
||||
/**
|
||||
* DB를 이용하기 위한 정보
|
||||
**/
|
||||
var $database = NULL; ///< database
|
||||
var $prefix = 'xe'; ///< 제로보드에서 사용할 테이블들의 prefix (한 DB에서 여러개의 제로보드 설치 가능)
|
||||
|
||||
/**
|
||||
* @brief sqlite 에서 사용될 column type
|
||||
*
|
||||
* column_type은 schema/query xml에서 공통 선언된 type을 이용하기 때문에
|
||||
* 각 DBMS에 맞게 replace 해주어야 한다
|
||||
**/
|
||||
var $column_type = array(
|
||||
'bignumber' => 'INTEGER',
|
||||
'number' => 'INTEGER',
|
||||
'varchar' => 'VARHAR',
|
||||
'char' => 'CHAR',
|
||||
'text' => 'TEXT',
|
||||
'bigtext' => 'TEXT',
|
||||
'date' => 'VARCHAR(14)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function DBSqlite2() {
|
||||
$this->_setDBInfo();
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치 가능 여부를 return
|
||||
**/
|
||||
function isSupported() {
|
||||
if(!function_exists('sqlite_open')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보 설정 및 connect/ close
|
||||
**/
|
||||
function _setDBInfo() {
|
||||
$db_info = Context::getDBInfo();
|
||||
$this->database = $db_info->db_database;
|
||||
$this->prefix = $db_info->db_table_prefix;
|
||||
if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 접속
|
||||
**/
|
||||
function _connect() {
|
||||
// db 정보가 없으면 무시
|
||||
if(!$this->database) return;
|
||||
|
||||
// 데이터 베이스 파일 접속 시도
|
||||
$this->fd = sqlite_open($this->database, 0666, &$error);
|
||||
if(!file_exists($this->database) || $error) {
|
||||
$this->setError(-1,$error);
|
||||
$this->is_connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 접속체크
|
||||
$this->is_connected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB접속 해제
|
||||
**/
|
||||
function close() {
|
||||
if(!$this->isConnected()) return;
|
||||
sqlite_close($this->fd);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 트랜잭션 시작
|
||||
**/
|
||||
function begin() {
|
||||
if(!$this->is_connected || $this->transaction_started) return;
|
||||
if($this->_query("BEGIN;")) $this->transaction_started = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 롤백
|
||||
**/
|
||||
function rollback() {
|
||||
if(!$this->is_connected || !$this->transaction_started) return;
|
||||
$this->_query("ROLLBACK;");
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 커밋
|
||||
**/
|
||||
function commit($force = false) {
|
||||
if(!$force && (!$this->isConnected() || !$this->transaction_started)) return;
|
||||
if(!$this->is_connected || !$this->transaction_started) return;
|
||||
$this->_query("COMMIT;");
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리에서 입력되는 문자열 변수들의 quotation 조절
|
||||
**/
|
||||
function addQuotes($string) {
|
||||
if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
|
||||
if(!is_numeric($string)) $string = str_replace("'","''", $string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : 쿼리문의 실행 및 결과의 fetch 처리
|
||||
*
|
||||
* query : query문 실행하고 result return\n
|
||||
* fetch : reutrn 된 값이 없으면 NULL\n
|
||||
* rows이면 array object\n
|
||||
* row이면 object\n
|
||||
* return\n
|
||||
**/
|
||||
function _query($query) {
|
||||
if(!$this->isConnected()) return;
|
||||
|
||||
// 쿼리 시작을 알림
|
||||
$this->actStart($query);
|
||||
|
||||
// 쿼리 문 실행
|
||||
$result = @sqlite_query($query, $this->fd);
|
||||
|
||||
// 오류 체크
|
||||
if(sqlite_last_error($this->fd)) $this->setError(sqlite_last_error($this->fd), sqlite_error_string(sqlite_last_error($this->fd)));
|
||||
|
||||
// 쿼리 실행 알림
|
||||
$this->actFinish();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 결과를 fetch
|
||||
**/
|
||||
function _fetch($result) {
|
||||
if($this->isError() || !$result) return;
|
||||
|
||||
while($tmp = sqlite_fetch_array($result, SQLITE_ASSOC)) {
|
||||
unset($obj);
|
||||
foreach($tmp as $key => $val) {
|
||||
$pos = strpos($key, '.');
|
||||
if($pos) $key = substr($key, $pos+1);
|
||||
$obj->{$key} = $val;
|
||||
}
|
||||
$output[] = $obj;
|
||||
}
|
||||
|
||||
if(count($output)==1) return $output[0];
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 1씩 증가되는 sequence값을 return
|
||||
**/
|
||||
function getNextSequence() {
|
||||
$query = sprintf("insert into %ssequence (seq) values ('')", $this->prefix);
|
||||
$this->_query($query);
|
||||
$sequence = sqlite_last_insert_rowid($this->fd);
|
||||
$query = sprintf("delete from %ssequence where seq < %d", $this->prefix, $sequence);
|
||||
$this->_query($query);
|
||||
|
||||
return $sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 테이블 기생성 여부 return
|
||||
**/
|
||||
function isTableExists($target_name) {
|
||||
$query = sprintf('pragma table_info(%s%s)', $this->prefix, $this->addQuotes($target_name));
|
||||
$result = $this->_query($query);
|
||||
if(sqlite_num_rows($result)==0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블에 특정 column 추가
|
||||
**/
|
||||
function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
|
||||
$type = $this->column_type[$type];
|
||||
if(strtoupper($type)=='INTEGER') $size = '';
|
||||
|
||||
$query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name);
|
||||
if($size) $query .= sprintf(" %s(%s) ", $type, $size);
|
||||
else $query .= sprintf(" %s ", $type);
|
||||
if($default) $query .= sprintf(" default '%s' ", $default);
|
||||
if($notnull) $query .= " not null ";
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블의 column의 정보를 return
|
||||
**/
|
||||
function isColumnExists($table_name, $column_name) {
|
||||
$query = sprintf("pragma table_info(%s%s)", $this->prefix, $table_name);
|
||||
$result = $this->_query($query);
|
||||
$output = $this->_fetch($result);
|
||||
if($output) {
|
||||
$column_name = strtolower($column_name);
|
||||
foreach($output as $key => $val) {
|
||||
$name = strtolower($val->name);
|
||||
if($column_name == $name) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXml($xml_doc) {
|
||||
return $this->_createTable($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXmlFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($file_name);
|
||||
return $this->_createTable($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief schema xml을 이용하여 create table query생성
|
||||
*
|
||||
* type : number, varchar, text, char, date, \n
|
||||
* opt : notnull, default, size\n
|
||||
* index : primary key, index, unique\n
|
||||
**/
|
||||
function _createTable($xml_doc) {
|
||||
// xml parsing
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse($xml_doc);
|
||||
|
||||
// 테이블 생성 schema 작성
|
||||
$table_name = $xml_obj->table->attrs->name;
|
||||
if($this->isTableExists($table_name)) return;
|
||||
$table_name = $this->prefix.$table_name;
|
||||
|
||||
if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
|
||||
else $columns = $xml_obj->table->column;
|
||||
|
||||
foreach($columns as $column) {
|
||||
$name = $column->attrs->name;
|
||||
$type = $column->attrs->type;
|
||||
if(strtoupper($this->column_type[$type])=='INTEGER') $size = '';
|
||||
else $size = $column->attrs->size;
|
||||
$notnull = $column->attrs->notnull;
|
||||
$primary_key = $column->attrs->primary_key;
|
||||
$index = $column->attrs->index;
|
||||
$unique = $column->attrs->unique;
|
||||
$default = $column->attrs->default;
|
||||
$auto_increment = $column->attrs->auto_increment;
|
||||
|
||||
if($auto_increment) {
|
||||
$column_schema[] = sprintf('%s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$auto_increment?'AUTOINCREMENT':''
|
||||
);
|
||||
} else {
|
||||
$column_schema[] = sprintf('%s %s%s %s %s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$size?'('.$size.')':'',
|
||||
$notnull?'NOT NULL':'',
|
||||
$primary_key?'PRIMARY KEY':'',
|
||||
$default?"DEFAULT '".$default."'":'',
|
||||
$auto_increment?'AUTOINCREMENT':''
|
||||
);
|
||||
}
|
||||
|
||||
if($unique) $unique_list[$unique][] = $name;
|
||||
else if($index) $index_list[$index][] = $name;
|
||||
}
|
||||
|
||||
$schema = sprintf('CREATE TABLE %s (%s%s) ;', $this->addQuotes($table_name)," ", implode($column_schema,", "));
|
||||
$this->_query($schema);
|
||||
|
||||
if(count($unique_list)) {
|
||||
foreach($unique_list as $key => $val) {
|
||||
$query = sprintf('CREATE UNIQUE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
|
||||
$this->_query($query);
|
||||
}
|
||||
}
|
||||
|
||||
if(count($index_list)) {
|
||||
foreach($index_list as $key => $val) {
|
||||
$query = sprintf('CREATE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
|
||||
$this->_query($query);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 조건문 작성하여 return
|
||||
**/
|
||||
function getCondition($output) {
|
||||
if(!$output->conditions) return;
|
||||
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$sub_condition = '';
|
||||
foreach($val['condition'] as $k =>$v) {
|
||||
if(!$v['value']) continue;
|
||||
|
||||
$name = $v['column'];
|
||||
$operation = $v['operation'];
|
||||
$value = $v['value'];
|
||||
$type = $this->getColumnType($output->column_type,$name);
|
||||
$pipe = $v['pipe'];
|
||||
|
||||
$value = $this->getConditionValue($name, $value, $operation, $type);
|
||||
if(!$value) $value = $v['value'];
|
||||
$str = $this->getConditionPart($name, $value, $operation);
|
||||
if($sub_condition) $sub_condition .= ' '.$pipe.' ';
|
||||
$sub_condition .= $str;
|
||||
}
|
||||
if($sub_condition) {
|
||||
if($condition && $val['pipe']) $condition .= ' '.$val['pipe'].' ';
|
||||
$condition .= '('.$sub_condition.')';
|
||||
}
|
||||
}
|
||||
|
||||
if($condition) $condition = ' where '.$condition;
|
||||
return $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insertAct 처리
|
||||
**/
|
||||
function _executeInsertAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key;
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if($output->column_type[$name]!='number') {
|
||||
$value = "'".$this->addQuotes($value)."'";
|
||||
if(!$value) $value = 'null';
|
||||
} elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = $name;
|
||||
$value_list[] = $value;
|
||||
}
|
||||
|
||||
$query = sprintf("insert into %s (%s) values (%s);", implode(',',$table_list), implode(',',$column_list), implode(',', $value_list));
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief updateAct 처리
|
||||
**/
|
||||
function _executeUpdateAct($output) {
|
||||
$table_count = count(array_values($output->tables));
|
||||
|
||||
// 대상 테이블이 1개일 경우
|
||||
if($table_count == 1) {
|
||||
// 테이블 정리
|
||||
list($target_table) = array_keys($output->tables);
|
||||
$target_table = $this->prefix.$target_table;
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if(strpos($name,'.')!==false&&strpos($value,'.')!==false) $column_list[] = $name.' = '.$value;
|
||||
else {
|
||||
if($output->column_type[$name]!='number') $value = "'".$this->addQuotes($value)."'";
|
||||
elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = sprintf("%s = %s", $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("update %s set %s %s", $target_table, implode(',',$column_list), $condition);
|
||||
|
||||
// 대상 테이블이 2개일 경우 (sqlite에서 update 테이블을 1개 이상 지정 못해서 이렇게 꽁수로... 다른 방법이 있으려나..)
|
||||
} elseif($table_count == 2) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[$val] = $this->prefix.$val;
|
||||
}
|
||||
list($source_table, $target_table) = array_values($table_list);
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
foreach($table_list as $key => $val) {
|
||||
$condition = eregi_replace($key.'\\.', $val.'.', $condition);
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
list($s_prefix, $s_column) = explode('.',$name);
|
||||
list($t_prefix, $t_column) = explode('.',$value);
|
||||
|
||||
$s_table = $table_list[$s_prefix];
|
||||
$t_table = $table_list[$t_prefix];
|
||||
$column_list[] = sprintf(' %s = (select %s from %s %s) ', $s_column, $t_column, $t_table, $condition);
|
||||
}
|
||||
|
||||
$query = sprintf('update %s set %s where exists(select * from %s %s)', $source_table, implode(',', $column_list), $target_table, $condition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deleteAct 처리
|
||||
**/
|
||||
function _executeDeleteAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key;
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("delete from %s %s", implode(',',$table_list), $condition);
|
||||
|
||||
return $this->_query($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief selectAct 처리
|
||||
*
|
||||
* select의 경우 특정 페이지의 목록을 가져오는 것을 편하게 하기 위해\n
|
||||
* navigation이라는 method를 제공
|
||||
**/
|
||||
function _executeSelectAct($output) {
|
||||
// 테이블 정리
|
||||
$table_list = array();
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key.' as '.$val;
|
||||
}
|
||||
|
||||
if(!$output->columns) {
|
||||
$columns = '*';
|
||||
} else {
|
||||
$column_list = array();
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$alias = $val['alias'];
|
||||
if($name == '*') {
|
||||
$column_list[] = '*';
|
||||
} elseif(strpos($name,'.')===false && strpos($name,'(')===false) {
|
||||
if($alias) $column_list[] = sprintf('%s as %s', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
} else {
|
||||
if($alias) $column_list[] = sprintf('%s as %s', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
}
|
||||
}
|
||||
$columns = implode(',',$column_list);
|
||||
}
|
||||
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output);
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) return;
|
||||
$data = $this->_fetch($result);
|
||||
|
||||
$buff = new Object();
|
||||
$buff->data = $data;
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다
|
||||
*
|
||||
* 그닥 좋지는 않은 구조이지만 편리하다.. -_-;
|
||||
**/
|
||||
function _getNavigationData($table_list, $columns, $condition, $output) {
|
||||
require_once('./classes/page/PageHandler.class.php');
|
||||
|
||||
// 전체 개수를 구함
|
||||
$count_query = sprintf("select count(*) as count from %s %s", implode(',',$table_list), $condition);
|
||||
$result = $this->_query($count_query);
|
||||
$count_output = $this->_fetch($result);
|
||||
$total_count = (int)$count_output->count;
|
||||
|
||||
$list_count = $output->list_count['value'];
|
||||
if(!$list_count) $list_count = 20;
|
||||
$page_count = $output->page_count['value'];
|
||||
if(!$page_count) $page_count = 10;
|
||||
$page = $output->page['value'];
|
||||
if(!$page) $page = 1;
|
||||
|
||||
// 전체 페이지를 구함
|
||||
if($total_count) $total_page = (int)( ($total_count-1) / $list_count) + 1;
|
||||
else $total_page = 1;
|
||||
|
||||
// 페이지 변수를 체크
|
||||
if($page > $total_page) $page = $total_page;
|
||||
$start_count = ($page-1)*$list_count;
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$query = sprintf('%s limit %d, %d', $query, $start_count, $list_count);
|
||||
|
||||
$result = $this->_query($query);
|
||||
if($this->isError()) {
|
||||
$buff = new Object();
|
||||
$buff->total_count = 0;
|
||||
$buff->total_page = 0;
|
||||
$buff->page = 1;
|
||||
$buff->data = array();
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
|
||||
if($result) {
|
||||
$virtual_no = $total_count - ($page-1)*$list_count;
|
||||
while($tmp = sqlite_fetch_array($result, SQLITE_ASSOC)) {
|
||||
unset($obj);
|
||||
foreach($tmp as $key => $val) {
|
||||
$pos = strpos($key, '.');
|
||||
if($pos) $key = substr($key, $pos+1);
|
||||
$obj->{$key} = $val;
|
||||
}
|
||||
$data[$virtual_no--] = $obj;
|
||||
}
|
||||
}
|
||||
|
||||
$buff = new Object();
|
||||
$buff->total_count = $total_count;
|
||||
$buff->total_page = $total_page;
|
||||
$buff->page = $page;
|
||||
$buff->data = $data;
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
}
|
||||
?>
|
||||
647
classes/db/DBSqlite3_pdo.class.php
Normal file
647
classes/db/DBSqlite3_pdo.class.php
Normal file
|
|
@ -0,0 +1,647 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DBSqlite3_pdo
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief SQLite3를 PDO로 이용하여 class
|
||||
* @version 0.1
|
||||
**/
|
||||
|
||||
class DBSqlite3_pdo extends DB {
|
||||
|
||||
/**
|
||||
* DB를 이용하기 위한 정보
|
||||
**/
|
||||
var $database = NULL; ///< database
|
||||
var $prefix = 'xe'; ///< 제로보드에서 사용할 테이블들의 prefix (한 DB에서 여러개의 제로보드 설치 가능)
|
||||
|
||||
/**
|
||||
* PDO 사용시 필요한 변수들
|
||||
**/
|
||||
var $handler = NULL;
|
||||
var $stmt = NULL;
|
||||
var $bind_idx = 0;
|
||||
var $bind_vars = array();
|
||||
|
||||
/**
|
||||
* @brief sqlite3 에서 사용될 column type
|
||||
*
|
||||
* column_type은 schema/query xml에서 공통 선언된 type을 이용하기 때문에
|
||||
* 각 DBMS에 맞게 replace 해주어야 한다
|
||||
**/
|
||||
var $column_type = array(
|
||||
'bignumber' => 'INTEGER',
|
||||
'number' => 'INTEGER',
|
||||
'varchar' => 'VARHAR',
|
||||
'char' => 'CHAR',
|
||||
'text' => 'TEXT',
|
||||
'bigtext' => 'TEXT',
|
||||
'date' => 'VARCHAR(14)',
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function DBSqlite3_pdo() {
|
||||
$this->_setDBInfo();
|
||||
$this->_connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 설치 가능 여부를 return
|
||||
**/
|
||||
function isSupported() {
|
||||
if(!class_exists('PDO')) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB정보 설정 및 connect/ close
|
||||
**/
|
||||
function _setDBInfo() {
|
||||
$db_info = Context::getDBInfo();
|
||||
$this->database = $db_info->db_database;
|
||||
$this->prefix = $db_info->db_table_prefix;
|
||||
if(!substr($this->prefix,-1)!='_') $this->prefix .= '_';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB 접속
|
||||
**/
|
||||
function _connect() {
|
||||
// db 정보가 없으면 무시
|
||||
if(!$this->database) return;
|
||||
|
||||
// 데이터 베이스 파일 접속 시도
|
||||
$this->handler = new PDO('sqlite:'.$this->database);
|
||||
|
||||
if(!file_exists($this->database) || $error) {
|
||||
$this->setError(-1,'permission denied to access database');
|
||||
//$this->setError(-1,$error);
|
||||
$this->is_connected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 접속체크
|
||||
$this->is_connected = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DB접속 해제
|
||||
**/
|
||||
function close() {
|
||||
if(!$this->isConnected()) return;
|
||||
$this->commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 트랜잭션 시작
|
||||
**/
|
||||
function begin() {
|
||||
if(!$this->isConnected() || $this->transaction_started) return;
|
||||
if($this->handler->beginTransaction()) $this->transaction_started = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 롤백
|
||||
**/
|
||||
function rollback() {
|
||||
if(!$this->isConnected() || !$this->transaction_started) return;
|
||||
$this->handler->rollBack();
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 커밋
|
||||
**/
|
||||
function commit($force = false) {
|
||||
if(!$force && (!$this->isConnected() || !$this->transaction_started)) return;
|
||||
$this->handler->commit();
|
||||
$this->transaction_started = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 쿼리에서 입력되는 문자열 변수들의 quotation 조절
|
||||
**/
|
||||
function addQuotes($string) {
|
||||
if(get_magic_quotes_gpc()) $string = stripslashes(str_replace("\\","\\\\",$string));
|
||||
if(!is_numeric($string)) $string = str_replace("'","''",$string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : 쿼리문의 prepare
|
||||
**/
|
||||
function _prepare($query) {
|
||||
if(!$this->isConnected()) return;
|
||||
|
||||
// 쿼리 시작을 알림
|
||||
$this->actStart($query);
|
||||
|
||||
$this->stmt = $this->handler->prepare($query);
|
||||
|
||||
if($this->handler->errorCode() != '00000') {
|
||||
$this->setError($this->handler->errorCode(), print_r($this->handler->errorInfo(),true));
|
||||
$this->actFinish();
|
||||
}
|
||||
$this->bind_idx = 0;
|
||||
$this->bind_vars = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : stmt에 binding params
|
||||
**/
|
||||
function _bind($val) {
|
||||
if(!$this->isConnected() || !$this->stmt) return;
|
||||
|
||||
$this->bind_idx ++;
|
||||
$this->bind_vars[] = $val;
|
||||
$this->stmt->bindParam($this->bind_idx, $val);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief : prepare된 쿼리의 execute
|
||||
**/
|
||||
function _execute() {
|
||||
if(!$this->isConnected() || !$this->stmt) return;
|
||||
|
||||
$this->stmt->execute();
|
||||
|
||||
if($this->stmt->errorCode() === '00000') {
|
||||
$output = null;
|
||||
while($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
unset($obj);
|
||||
foreach($tmp as $key => $val) {
|
||||
$pos = strpos($key, '.');
|
||||
if($pos) $key = substr($key, $pos+1);
|
||||
$obj->{$key} = str_replace("''","'",$val);
|
||||
}
|
||||
$output[] = $obj;
|
||||
}
|
||||
} else {
|
||||
$this->setError($this->stmt->errorCode(),print_r($this->stmt->errorInfo(),true));
|
||||
}
|
||||
|
||||
$this->stmt = null;
|
||||
$this->actFinish();
|
||||
|
||||
if(is_array($output) && count($output)==1) return $output[0];
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 1씩 증가되는 sequence값을 return
|
||||
**/
|
||||
function getNextSequence() {
|
||||
$query = sprintf("insert into %ssequence (seq) values (NULL)", $this->prefix);
|
||||
$this->_prepare($query);
|
||||
$result = $this->_execute();
|
||||
$sequence = $this->handler->lastInsertId();
|
||||
$query = sprintf("delete from %ssequence where seq < %d", $this->prefix, $sequence);
|
||||
$this->_prepare($query);
|
||||
$result = $this->_execute();
|
||||
|
||||
return $sequence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 테이블 기생성 여부 return
|
||||
**/
|
||||
function isTableExists($target_name) {
|
||||
$query = sprintf('pragma table_info(%s%s)', $this->prefix, $target_name);
|
||||
$this->_prepare($query);
|
||||
if(!$this->_execute()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블에 특정 column 추가
|
||||
**/
|
||||
function addColumn($table_name, $column_name, $type='number', $size='', $default = '', $notnull=false) {
|
||||
$type = $this->column_type[$type];
|
||||
if(strtoupper($type)=='INTEGER') $size = '';
|
||||
|
||||
$query = sprintf("alter table %s%s add %s ", $this->prefix, $table_name, $column_name);
|
||||
if($size) $query .= sprintf(" %s(%s) ", $type, $size);
|
||||
else $query .= sprintf(" %s ", $type);
|
||||
if($default) $query .= sprintf(" default '%s' ", $default);
|
||||
if($notnull) $query .= " not null ";
|
||||
|
||||
$this->_prepare($query);
|
||||
return $this->_execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 테이블의 column의 정보를 return
|
||||
**/
|
||||
function isColumnExists($table_name, $column_name) {
|
||||
$query = sprintf("pragma table_info(%s%s)", $this->prefix, $table_name);
|
||||
$this->_prepare($query);
|
||||
$output = $this->_execute();
|
||||
|
||||
if($output) {
|
||||
$column_name = strtolower($column_name);
|
||||
foreach($output as $key => $val) {
|
||||
$name = strtolower($val->name);
|
||||
if($column_name == $name) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXml($xml_doc) {
|
||||
return $this->_createTable($xml_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 을 받아서 테이블을 생성
|
||||
**/
|
||||
function createTableByXmlFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($file_name);
|
||||
return $this->_createTable($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief schema xml을 이용하여 create table query생성
|
||||
*
|
||||
* type : number, varchar, text, char, date, \n
|
||||
* opt : notnull, default, size\n
|
||||
* index : primary key, index, unique\n
|
||||
**/
|
||||
function _createTable($xml_doc) {
|
||||
// xml parsing
|
||||
$oXml = new XmlParser();
|
||||
$xml_obj = $oXml->parse($xml_doc);
|
||||
|
||||
// 테이블 생성 schema 작성
|
||||
$table_name = $xml_obj->table->attrs->name;
|
||||
if($this->isTableExists($table_name)) return;
|
||||
$table_name = $this->prefix.$table_name;
|
||||
|
||||
if(!is_array($xml_obj->table->column)) $columns[] = $xml_obj->table->column;
|
||||
else $columns = $xml_obj->table->column;
|
||||
|
||||
foreach($columns as $column) {
|
||||
$name = $column->attrs->name;
|
||||
$type = $column->attrs->type;
|
||||
if(strtoupper($this->column_type[$type])=='INTEGER') $size = '';
|
||||
else $size = $column->attrs->size;
|
||||
$notnull = $column->attrs->notnull;
|
||||
$primary_key = $column->attrs->primary_key;
|
||||
$index = $column->attrs->index;
|
||||
$unique = $column->attrs->unique;
|
||||
$default = $column->attrs->default;
|
||||
$auto_increment = $column->attrs->auto_increment;
|
||||
|
||||
if($auto_increment) {
|
||||
$column_schema[] = sprintf('%s %s PRIMARY KEY %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$auto_increment?'AUTOINCREMENT':''
|
||||
);
|
||||
} else {
|
||||
$column_schema[] = sprintf('%s %s%s %s %s %s',
|
||||
$name,
|
||||
$this->column_type[$type],
|
||||
$size?'('.$size.')':'',
|
||||
$notnull?'NOT NULL':'',
|
||||
$primary_key?'PRIMARY KEY':'',
|
||||
$default?"DEFAULT '".$default."'":''
|
||||
);
|
||||
}
|
||||
|
||||
if($unique) $unique_list[$unique][] = $name;
|
||||
else if($index) $index_list[$index][] = $name;
|
||||
}
|
||||
|
||||
$schema = sprintf('CREATE TABLE %s (%s%s) ;', $table_name," ", implode($column_schema,", "));
|
||||
$this->_prepare($schema);
|
||||
$this->_execute();
|
||||
if($this->isError()) return;
|
||||
|
||||
if(count($unique_list)) {
|
||||
foreach($unique_list as $key => $val) {
|
||||
$query = sprintf('CREATE UNIQUE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
|
||||
$this->_prepare($query);
|
||||
$this->_execute();
|
||||
if($this->isError()) $this->rollback();
|
||||
}
|
||||
}
|
||||
|
||||
if(count($index_list)) {
|
||||
foreach($index_list as $key => $val) {
|
||||
$query = sprintf('CREATE INDEX %s_%s ON %s (%s)', $this->addQuotes($table_name), $key, $this->addQuotes($table_name), implode(',',$val));
|
||||
$this->_prepare($query);
|
||||
$this->_execute();
|
||||
if($this->isError()) $this->rollback();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 조건문 작성하여 return
|
||||
**/
|
||||
function getCondition($output) {
|
||||
if(!$output->conditions) return;
|
||||
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$sub_condition = '';
|
||||
foreach($val['condition'] as $k =>$v) {
|
||||
if(!$v['value']) continue;
|
||||
|
||||
$name = $v['column'];
|
||||
$operation = $v['operation'];
|
||||
$value = $v['value'];
|
||||
$type = $this->getColumnType($output->column_type,$name);
|
||||
$pipe = $v['pipe'];
|
||||
|
||||
$value = $this->getConditionValue($name, $value, $operation, $type);
|
||||
if(!$value) $value = $v['value'];
|
||||
|
||||
$str = $this->getConditionPart($name, $value, $operation);
|
||||
if($sub_condition) $sub_condition .= ' '.$pipe.' ';
|
||||
$sub_condition .= $str;
|
||||
}
|
||||
if($sub_condition) {
|
||||
if($condition && $val['pipe']) $condition .= ' '.$val['pipe'].' ';
|
||||
$condition .= '('.$sub_condition.')';
|
||||
}
|
||||
}
|
||||
|
||||
if($condition) $condition = ' where '.$condition;
|
||||
return $condition;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief insertAct 처리
|
||||
**/
|
||||
function _executeInsertAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key;
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
|
||||
$key_list[] = $name;
|
||||
|
||||
if($output->column_type[$name]!='number') $val_list[] = $this->addQuotes($value);
|
||||
else {
|
||||
if(!$value || is_numeric($value)) $value = (int)$value;
|
||||
$val_list[] = $value;
|
||||
}
|
||||
|
||||
$prepare_list[] = '?';
|
||||
}
|
||||
|
||||
$query = sprintf("INSERT INTO %s (%s) VALUES (%s);", implode(',',$table_list), implode(',',$key_list), implode(',',$prepare_list));
|
||||
|
||||
$this->_prepare($query);
|
||||
|
||||
$val_count = count($val_list);
|
||||
for($i=0;$i<$val_count;$i++) $this->_bind($val_list[$i]);
|
||||
|
||||
return $this->_execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief updateAct 처리
|
||||
**/
|
||||
function _executeUpdateAct($output) {
|
||||
$table_count = count(array_values($output->tables));
|
||||
|
||||
// 대상 테이블이 1개일 경우
|
||||
if($table_count == 1) {
|
||||
// 테이블 정리
|
||||
list($target_table) = array_keys($output->tables);
|
||||
$target_table = $this->prefix.$target_table;
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
if(strpos($name,'.')!==false&&strpos($value,'.')!==false) $column_list[] = $name.' = '.$value;
|
||||
else {
|
||||
if($output->column_type[$name]!='number') $value = "'".$this->addQuotes($value)."'";
|
||||
elseif(!$value || is_numeric($value)) $value = (int)$value;
|
||||
|
||||
$column_list[] = sprintf("%s = %s", $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("update %s set %s %s", $target_table, implode(',',$column_list), $condition);
|
||||
|
||||
// 대상 테이블이 2개일 경우 (sqlite에서 update 테이블을 1개 이상 지정 못해서 이렇게 꽁수로... 다른 방법이 있으려나..)
|
||||
} elseif($table_count == 2) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[$val] = $this->prefix.$val;
|
||||
}
|
||||
list($source_table, $target_table) = array_values($table_list);
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
foreach($table_list as $key => $val) {
|
||||
$condition = eregi_replace($key.'\\.', $val.'.', $condition);
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
foreach($output->columns as $key => $val) {
|
||||
if(!isset($val['value'])) continue;
|
||||
$name = $val['name'];
|
||||
$value = $val['value'];
|
||||
list($s_prefix, $s_column) = explode('.',$name);
|
||||
list($t_prefix, $t_column) = explode('.',$value);
|
||||
|
||||
$s_table = $table_list[$s_prefix];
|
||||
$t_table = $table_list[$t_prefix];
|
||||
$column_list[] = sprintf(' %s = (select %s from %s %s) ', $s_column, $t_column, $t_table, $condition);
|
||||
}
|
||||
|
||||
$query = sprintf('update %s set %s where exists(select * from %s %s)', $source_table, implode(',', $column_list), $target_table, $condition);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->_prepare($query);
|
||||
return $this->_execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief deleteAct 처리
|
||||
**/
|
||||
function _executeDeleteAct($output) {
|
||||
// 테이블 정리
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key;
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
$query = sprintf("delete from %s %s", implode(',',$table_list), $condition);
|
||||
|
||||
$this->_prepare($query);
|
||||
return $this->_execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief selectAct 처리
|
||||
*
|
||||
* select의 경우 특정 페이지의 목록을 가져오는 것을 편하게 하기 위해\n
|
||||
* navigation이라는 method를 제공
|
||||
**/
|
||||
function _executeSelectAct($output) {
|
||||
// 테이블 정리
|
||||
$table_list = array();
|
||||
foreach($output->tables as $key => $val) {
|
||||
$table_list[] = $this->prefix.$key.' as '.$val;
|
||||
}
|
||||
|
||||
if(!$output->columns) {
|
||||
$columns = '*';
|
||||
} else {
|
||||
$column_list = array();
|
||||
foreach($output->columns as $key => $val) {
|
||||
$name = $val['name'];
|
||||
$alias = $val['alias'];
|
||||
if($name == '*') {
|
||||
$column_list[] = '*';
|
||||
} elseif(strpos($name,'.')===false && strpos($name,'(')===false) {
|
||||
if($alias) $column_list[] = sprintf('%s as %s', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
} else {
|
||||
if($alias) $column_list[] = sprintf('%s as %s', $name, $alias);
|
||||
else $column_list[] = sprintf('%s',$name);
|
||||
}
|
||||
}
|
||||
$columns = implode(',',$column_list);
|
||||
}
|
||||
|
||||
$condition = $this->getCondition($output);
|
||||
|
||||
if($output->list_count) return $this->_getNavigationData($table_list, $columns, $condition, $output);
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
$this->_prepare($query);
|
||||
$data = $this->_execute();
|
||||
if($this->isError()) return;
|
||||
|
||||
$buff = new Object();
|
||||
$buff->data = $data;
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief query xml에 navigation 정보가 있을 경우 페이징 관련 작업을 처리한다
|
||||
*
|
||||
* 그닥 좋지는 않은 구조이지만 편리하다.. -_-;
|
||||
**/
|
||||
function _getNavigationData($table_list, $columns, $condition, $output) {
|
||||
require_once('./classes/page/PageHandler.class.php');
|
||||
|
||||
// 전체 개수를 구함
|
||||
$count_query = sprintf("select count(*) as count from %s %s", implode(',',$table_list), $condition);
|
||||
$this->_prepare($count_query);
|
||||
$count_output = $this->_execute();
|
||||
$total_count = (int)$count_output->count;
|
||||
|
||||
$list_count = $output->list_count['value'];
|
||||
if(!$list_count) $list_count = 20;
|
||||
$page_count = $output->page_count['value'];
|
||||
if(!$page_count) $page_count = 10;
|
||||
$page = $output->page['value'];
|
||||
if(!$page) $page = 1;
|
||||
|
||||
// 전체 페이지를 구함
|
||||
if($total_count) $total_page = (int)( ($total_count-1) / $list_count) + 1;
|
||||
else $total_page = 1;
|
||||
|
||||
// 페이지 변수를 체크
|
||||
if($page > $total_page) $page = $total_page;
|
||||
$start_count = ($page-1)*$list_count;
|
||||
|
||||
$query = sprintf("select %s from %s %s", $columns, implode(',',$table_list), $condition);
|
||||
|
||||
if(count($output->groups)) $query .= sprintf(' group by %s', implode(',',$output->groups));
|
||||
|
||||
if($output->order) {
|
||||
foreach($output->order as $key => $val) {
|
||||
$index_list[] = sprintf('%s %s', $val[0], $val[1]);
|
||||
}
|
||||
if(count($index_list)) $query .= ' order by '.implode(',',$index_list);
|
||||
}
|
||||
|
||||
// return 결과물 생성
|
||||
$buff = new Object();
|
||||
$buff->total_count = 0;
|
||||
$buff->total_page = 0;
|
||||
$buff->page = 1;
|
||||
$buff->data = array();
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
|
||||
// 쿼리 실행
|
||||
$query = sprintf('%s limit %d, %d', $query, $start_count, $list_count);
|
||||
$this->_prepare($query);
|
||||
|
||||
if($this->isError()) {
|
||||
$this->setError($this->handler->errorCode(), print_r($this->handler->errorInfo(),true));
|
||||
$this->actFinish();
|
||||
return $buff;
|
||||
}
|
||||
|
||||
$this->stmt->execute();
|
||||
|
||||
if($this->stmt->errorCode() != '00000') {
|
||||
$this->setError($this->stmt->errorCode(), print_r($this->stmt->errorInfo(),true));
|
||||
$this->actFinish();
|
||||
return $buff;
|
||||
}
|
||||
|
||||
$output = null;
|
||||
$virtual_no = $total_count - ($page-1)*$list_count;
|
||||
while($tmp = $this->stmt->fetch(PDO::FETCH_ASSOC)) {
|
||||
unset($obj);
|
||||
foreach($tmp as $key => $val) {
|
||||
$pos = strpos($key, '.');
|
||||
if($pos) $key = substr($key, $pos+1);
|
||||
$obj->{$key} = $val;
|
||||
}
|
||||
$data[$virtual_no--] = $obj;
|
||||
}
|
||||
|
||||
$this->stmt = null;
|
||||
$this->actFinish();
|
||||
|
||||
$buff = new Object();
|
||||
$buff->total_count = $total_count;
|
||||
$buff->total_page = $total_page;
|
||||
$buff->page = $page;
|
||||
$buff->data = $data;
|
||||
|
||||
$buff->page_navigation = new PageHandler($total_count, $total_page, $page, $page_count);
|
||||
return $buff;
|
||||
}
|
||||
}
|
||||
?>
|
||||
237
classes/display/DisplayHandler.class.php
Normal file
237
classes/display/DisplayHandler.class.php
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
<?php
|
||||
/**
|
||||
* @class DisplayHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 데이터 출력을 위한 class (XML/HTML 데이터를 구분하여 출력)
|
||||
*
|
||||
* Response Method에 따라서 html or xml 출력방법을 결정한다
|
||||
* xml : oModule의 variables를 simple xml 로 출력
|
||||
* html : oModule의 template/variables로 html을 만들고 contents_html로 처리
|
||||
* widget이나 layout의 html과 연동하여 출력
|
||||
**/
|
||||
|
||||
class DisplayHandler extends Handler {
|
||||
|
||||
var $content_size = 0; ///< 출력하는 컨텐츠의 사이즈
|
||||
|
||||
/**
|
||||
* @brief 모듈객체를 받아서 content 출력
|
||||
**/
|
||||
function printContent(&$oModule) {
|
||||
|
||||
// header 출력
|
||||
$this->_printHeader();
|
||||
|
||||
// request method에 따른 처리
|
||||
$content = $this->getContent($oModule);
|
||||
|
||||
// 요청방식에 따라 출력을 별도로
|
||||
if(Context::getResponseMethod()!="XMLRPC") {
|
||||
|
||||
Context::set('content', $content);
|
||||
|
||||
// 레이아웃을 컴파일
|
||||
if(__DEBUG__==3) $start = getMicroTime();
|
||||
$oTemplate = &TemplateHandler::getInstance();
|
||||
|
||||
if(Context::get('layout') != 'none') {
|
||||
$layout_path = $oModule->getLayoutPath();
|
||||
$layout_file = $oModule->getLayoutFile();
|
||||
$edited_layout_file = $oModule->getEditedLayoutFile();
|
||||
}
|
||||
|
||||
if(!$layout_path) $layout_path = './common/tpl/';
|
||||
if(!$layout_file) $layout_file = 'default_layout.html';
|
||||
|
||||
$zbxe_final_content = $oTemplate->compile($layout_path, $layout_file, $edited_layout_file);
|
||||
|
||||
if(__DEBUG__==3) $GLOBALS['__layout_compile_elapsed__'] = getMicroTime()-$start;
|
||||
|
||||
// 각 위젯, 에디터 컴포넌트의 코드 변경
|
||||
if(__DEBUG__==3) $start = getMicroTime();
|
||||
|
||||
$oContext = &Context::getInstance();
|
||||
$zbxe_final_content= $oContext->transContent($zbxe_final_content);
|
||||
|
||||
if(__DEBUG__==3) $GLOBALS['__trans_widget_editor_elapsed__'] = getMicroTime()-$start;
|
||||
|
||||
// 최종 결과를 common_layout에 넣어버림
|
||||
Context::set('zbxe_final_content', $zbxe_final_content);
|
||||
$output = $oTemplate->compile('./common/tpl', 'common_layout');
|
||||
|
||||
} else {
|
||||
|
||||
$output = $content;
|
||||
|
||||
}
|
||||
|
||||
// 애드온 실행
|
||||
$called_position = 'before_display_content';
|
||||
@include("./files/cache/activated_addons.cache.php");
|
||||
|
||||
$this->content_size = strlen($output);
|
||||
|
||||
// 컨텐츠 출력
|
||||
$this->display($output);
|
||||
|
||||
// 디버깅 데이터 출력
|
||||
$this->_debugOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 최종 결과물의 출력
|
||||
**/
|
||||
function display($content) {
|
||||
$path = str_replace('index.php','',$_SERVER['SCRIPT_NAME']);
|
||||
|
||||
// files로 시작되는 src나 href의 값을 절대경로로 변경
|
||||
$content = preg_replace('!(href|src)=("|\'){0,1}files!is', '\\1=\\2'.$path.'files', $content);
|
||||
print preg_replace('!(href|src)=("|\'){0,1}\.\/([a-zA-Z0-9\_^\/]+)\/!is', '\\1=\\2'.$path.'$3/', $content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈 객체의 content return
|
||||
**/
|
||||
function getContent(&$oModule) {
|
||||
return $this->_toDoc($oModule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈 객체의 content return
|
||||
**/
|
||||
function _toDoc(&$oModule) {
|
||||
if(Context::getRequestMethod() == 'XMLRPC') $content = $this->_toXmlDoc($oModule);
|
||||
else $content = $this->_toHTMLDoc($oModule);
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RequestMethod가 XML이면 XML 데이터로 컨텐츠 생성
|
||||
**/
|
||||
function _toXmlDoc(&$oModule) {
|
||||
$xmlDoc = "<response>\n";
|
||||
$xmlDoc .= sprintf("<error>%s</error>\n",$oModule->getError());
|
||||
$xmlDoc .= sprintf("<message>%s</message>\n",str_replace(array('<','>','&'),array('<','>','&'),$oModule->getMessage()));
|
||||
|
||||
$variables = $oModule->getVariables();
|
||||
|
||||
if(count($variables)) {
|
||||
foreach($variables as $key => $val) {
|
||||
if(is_string($val)) $val = '<![CDATA['.$val.']]>';
|
||||
$xmlDoc .= "<{$key}>{$val}</{$key}>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$xmlDoc .= "</response>";
|
||||
|
||||
return $xmlDoc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RequestMethod가 XML이 아니면 html 컨텐츠 생성
|
||||
**/
|
||||
function _toHTMLDoc(&$oModule) {
|
||||
// template handler 객체 생성
|
||||
$oTemplate = &TemplateHandler::getInstance();
|
||||
|
||||
// module tpl 변환
|
||||
$template_path = $oModule->getTemplatePath();
|
||||
$tpl_file = $oModule->getTemplateFile();
|
||||
return $oTemplate->compile($template_path, $tpl_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief content size return
|
||||
**/
|
||||
function getContentSize() {
|
||||
return $this->content_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 디버그 모드일 경우 디버기 메세지 출력
|
||||
*
|
||||
* __DEBUG__가 1이상일 경우 각 부분의 실행시간등을 debugPrint 함수를 이용해서 출력\n
|
||||
* 개발시나 테스트시에 config/config.inc.php의 __DEBUG__를 세팅하고\n
|
||||
* tail -f ./files/_debug_message.php로 하여 console로 확인하면 편리함\n
|
||||
**/
|
||||
function _debugOutput() {
|
||||
if(!__DEBUG__ || (__DEBUG_OUTPUT!=0 && Context::getResponseMethod()!='HTML') ) return;
|
||||
$end = getMicroTime();
|
||||
|
||||
// debug string 작성 시작
|
||||
$buff = "\n\n** Debug at ".date('Y-m-d H:i:s')." ************************************************************\n";
|
||||
|
||||
// Request/Response 정보 작성
|
||||
$buff .= "\n- Request/ Response info\n";
|
||||
$buff .= sprintf("\tRequest URI \t\t\t: %s:%s%s%s%s\n", $_SERVER['SERVER_NAME'], $_SERVER['SERVER_PORT'], $_SERVER['PHP_SELF'], $_SERVER['QUERY_STRING']?'?':'', $_SERVER['QUERY_STRING']);
|
||||
$buff .= sprintf("\tRequest method \t\t\t: %s\n", $_SERVER['REQUEST_METHOD']);
|
||||
$buff .= sprintf("\tResponse method \t\t: %s\n", Context::getResponseMethod());
|
||||
$buff .= sprintf("\tResponse contents size\t\t: %d byte\n", $this->getContentSize());
|
||||
|
||||
// DB 로그 작성
|
||||
if(__DEBUG__>1) {
|
||||
if($GLOBALS['__db_queries__']) {
|
||||
$buff .= "\n- DB Queries\n";
|
||||
$buff .= $GLOBALS['__db_queries__'];
|
||||
}
|
||||
$buff .= "\n- Elapsed time\n";
|
||||
|
||||
if($GLOBALS['__db_elapsed_time__']) $buff .= sprintf("\tDB queries elapsed time\t\t: %0.5f sec\n", $GLOBALS['__db_elapsed_time__']);
|
||||
}
|
||||
|
||||
// 기타 로그 작성
|
||||
if(__DEBUG__==3) {
|
||||
$buff .= sprintf("\tclass file load elapsed time \t: %0.5f sec\n", $GLOBALS['__elapsed_class_load__']);
|
||||
$buff .= sprintf("\tTemplate compile elapsed time\t: %0.5f sec (%d called)\n", $GLOBALS['__template_elapsed__'], $GLOBALS['__TemplateHandlerCalled__']);
|
||||
$buff .= sprintf("\tXmlParse compile elapsed time\t: %0.5f sec\n", $GLOBALS['__xmlparse_elapsed__']);
|
||||
$buff .= sprintf("\tPHP elapsed time \t\t: %0.5f sec\n", $end-__StartTime__-$GLOBALS['__template_elapsed__']-$GLOBALS['__xmlparse_elapsed__']-$GLOBALS['__db_elapsed_time__']-$GLOBALS['__elapsed_class_load__']);
|
||||
|
||||
// 위젯 실행 시간 작성
|
||||
$buff .= sprintf("\n\tWidgets elapsed time \t\t: %0.5f sec", $GLOBALS['__widget_excute_elapsed__']);
|
||||
|
||||
// 레이아웃 실행 시간
|
||||
$buff .= sprintf("\n\tLayout compile elapsed time \t: %0.5f sec", $GLOBALS['__layout_compile_elapsed__']);
|
||||
|
||||
// 위젯, 에디터 컴포넌트 치환 시간
|
||||
$buff .= sprintf("\n\tTrans widget&editor elapsed time: %0.5f sec\n\n", $GLOBALS['__trans_widget_editor_elapsed__']);
|
||||
}
|
||||
|
||||
// 전체 실행 시간 작성
|
||||
$buff .= sprintf("\tTotal elapsed time \t\t: %0.5f sec", $end-__StartTime__);
|
||||
|
||||
debugPrint($buff, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RequestMethod에 맞춰 헤더 출력
|
||||
***/
|
||||
function _printHeader() {
|
||||
if(Context::getResponseMethod() != 'HTML') return $this->_printXMLHeader();
|
||||
else return $this->_printHTMLHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml header 출력 (utf8 고정)
|
||||
**/
|
||||
function _printXMLHeader() {
|
||||
header("Content-Type: text/xml; charset=UTF-8");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief html header 출력 (utf8 고정)
|
||||
**/
|
||||
function _printHTMLHeader() {
|
||||
header("Content-Type: text/html; charset=UTF-8");
|
||||
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
||||
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate");
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache");
|
||||
}
|
||||
}
|
||||
?>
|
||||
27
classes/editor/EditorHandler.class.php
Normal file
27
classes/editor/EditorHandler.class.php
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
/**
|
||||
* @class EditorHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief edit component의 상위 클래스임
|
||||
*
|
||||
* 주로 하는 일은 컴포넌트 요청시 컴포넌트에서 필요로 하는 변수를 세팅해준다
|
||||
**/
|
||||
|
||||
class EditorHandler extends Object {
|
||||
|
||||
/**
|
||||
* @brief 컴포넌트의 xml및 관련 정보들을 설정
|
||||
**/
|
||||
function setInfo($info) {
|
||||
Context::set('component_info', $info);
|
||||
|
||||
if(!$info->extra_vars) return;
|
||||
|
||||
foreach($info->extra_vars as $key => $val) {
|
||||
$this->{$key} = trim($val->value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
276
classes/file/FileHandler.class.php
Normal file
276
classes/file/FileHandler.class.php
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
<?php
|
||||
/**
|
||||
* @class FileHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 파일시스템을 쉽게 사용하기 위한 method를 모은 클래스
|
||||
*
|
||||
* 굳이 class로 만들필요는 없는데.. 소스 코드의 관리를 위하여..
|
||||
**/
|
||||
|
||||
class FileHandler extends Handler {
|
||||
|
||||
/**
|
||||
* @brief 파일의 내용을 읽어서 return
|
||||
**/
|
||||
function readFile($file_name) {
|
||||
if(!file_exists($file_name)) return;
|
||||
|
||||
$filesize = filesize($file_name);
|
||||
|
||||
if($filesize<1) return;
|
||||
|
||||
$fp = fopen($file_name, "r");
|
||||
$buff = '';
|
||||
if($fp) {
|
||||
while(!feof($fp) && strlen($buff)<=$filesize) {
|
||||
$str = fgets($fp, 1024);
|
||||
$buff .= $str;
|
||||
}
|
||||
fclose($fp);
|
||||
}
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief $buff의 내용을 파일에 쓰기
|
||||
**/
|
||||
function writeFile($file_name, $buff, $mode = "w") {
|
||||
$mode = strtolower($mode);
|
||||
if($mode != "a") $mode = "w";
|
||||
if(@!$fp = fopen($file_name,$mode)) return false;
|
||||
fwrite($fp, $buff);
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 디렉토리를 이동
|
||||
**/
|
||||
function moveDir($source_dir, $target_dir) {
|
||||
if(!is_dir($source_dir)) return;
|
||||
|
||||
if(!is_dir($target_dir)) {
|
||||
FileHandler::makeDir($target_dir);
|
||||
@unlink($target_dir);
|
||||
}
|
||||
|
||||
@rename($source_dir, $target_dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief $path내의 파일들을 return ('.', '..', '.로 시작하는' 파일들은 제외)
|
||||
**/
|
||||
function readDir($path, $filter = '', $to_lower = false, $concat_prefix = false) {
|
||||
if(substr($path,-1)!='/') $path .= '/';
|
||||
if(!is_dir($path)) return array();
|
||||
$oDir = dir($path);
|
||||
while($file = $oDir->read()) {
|
||||
if(substr($file,0,1)=='.') continue;
|
||||
if($filter && !preg_match($filter, $file)) continue;
|
||||
if($to_lower) $file = strtolower($file);
|
||||
if($filter) $file = preg_replace($filter, '$1', $file);
|
||||
else $file = $file;
|
||||
|
||||
if($concat_prefix) $file = $path.$file;
|
||||
$output[] = $file;
|
||||
}
|
||||
if(!$output) return array();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 디렉토리 생성
|
||||
*
|
||||
* 주어진 경로를 단계별로 접근하여 recursive하게 디렉토리 생성
|
||||
**/
|
||||
function makeDir($path_string) {
|
||||
$path_list = explode('/', $path_string);
|
||||
|
||||
for($i=0;$i<count($path_list);$i++) {
|
||||
if(!$path_list[$i]) continue;
|
||||
$path .= $path_list[$i].'/';
|
||||
if(!is_dir($path)) {
|
||||
@mkdir($path, 0777);
|
||||
@chmod($path, 0777);
|
||||
}
|
||||
}
|
||||
|
||||
return is_dir($path_string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 지정된 디렉토리 이하 모두 파일을 삭제
|
||||
**/
|
||||
function removeDir($path) {
|
||||
if(!is_dir($path)) return;
|
||||
$directory = dir($path);
|
||||
while($entry = $directory->read()) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
if (is_dir($path."/".$entry)) {
|
||||
FileHandler::removeDir($path."/".$entry);
|
||||
} else {
|
||||
@unlink($path."/".$entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
$directory->close();
|
||||
@rmdir($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief byte단위의 파일크기를 적절하게 변환해서 return
|
||||
**/
|
||||
function filesize($size) {
|
||||
if(!$size) return "0Byte";
|
||||
if($size<1024) return ($size."Byte");
|
||||
if($size >1024 && $size< 1024 *1024) return sprintf("%0.1fKB",$size / 1024);
|
||||
return sprintf("%0.2fMB",$size / (1024*1024));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 원격파일을 다운받아서 특정 위치에 저장
|
||||
**/
|
||||
function getRemoteFile($url, $target_filename) {
|
||||
$url_info = parse_url($url);
|
||||
|
||||
if(!$url_info['port']) $url_info['port'] = 80;
|
||||
|
||||
$fp = @fsockopen($url_info['host'], $url_info['port']);
|
||||
if(!$fp) return;
|
||||
|
||||
// 한글 파일이 있으면 한글파일 부분만 urlencode하여 처리 (iconv 필수)
|
||||
$path = $url_info['path'];
|
||||
if(preg_match('/[\xEA-\xED][\x80-\xFF]{2}/', $path)&&function_exists('iconv')) {
|
||||
$path_list = explode('/',$path);
|
||||
$cnt = count($path_list);
|
||||
$filename = $path_list[$cnt-1];
|
||||
$filename = urlencode(iconv("UTF-8","EUC-KR",$filename));
|
||||
$path_list[$cnt-1] = $filename;
|
||||
$path = implode('/',$path_list);
|
||||
$url_info['path'] = $path;
|
||||
}
|
||||
|
||||
$header = sprintf("GET %s HTTP/2.0\r\nHost: %s\r\nReferer: %s://%s\r\nRequestUrl: %s\r\nConnection: Close\r\n\r\n", $url_info['path'], $url_info['host'], $url_info['scheme'], $url_info['host'], Context::getRequestUri());
|
||||
|
||||
@fwrite($fp, $header);
|
||||
|
||||
$ft = @fopen($target_filename, 'w');
|
||||
if(!$ft) return;
|
||||
|
||||
$begin = false;
|
||||
while(!feof($fp)) {
|
||||
$str = fgets($fp, 1024);
|
||||
if($begin) @fwrite($ft, $str);
|
||||
if(!trim($str)) $begin = true;
|
||||
}
|
||||
@fclose($ft);
|
||||
@fclose($fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 특정 이미지 파일을 특정 위치로 옮김 (옮길때 이미지의 크기를 리사이징할 수 있음..)
|
||||
**/
|
||||
function createImageFile($source_file, $target_file, $resize_width = 0, $resize_height = 0, $target_type = '') {
|
||||
if(!file_exists($source_file)) return;
|
||||
|
||||
// 이미지 정보를 구함
|
||||
list($width, $height, $type, $attrs) = @getimagesize($source_file);
|
||||
if($width<1 || $height<1) return;
|
||||
|
||||
switch($type) {
|
||||
case '1' :
|
||||
$type = 'gif';
|
||||
break;
|
||||
case '2' :
|
||||
$type = 'jpg';
|
||||
break;
|
||||
case '3' :
|
||||
$type = 'png';
|
||||
break;
|
||||
case '6' :
|
||||
$type = 'bmp';
|
||||
break;
|
||||
default :
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
// 타겟 파일의 type을 구함
|
||||
if(!$target_type) $target_type = $type;
|
||||
$target_type = strtolower($target_type);
|
||||
|
||||
// 리사이즈를 원하는 크기의 임시 이미지를 만듬
|
||||
if(function_exists('imagecreatetruecolor')) $thumb = @imagecreatetruecolor($resize_width, $resize_height);
|
||||
else $thumb = @imagecreate($resize_width, $resize_height);
|
||||
|
||||
$white = @imagecolorallocate($thumb, 255,255,255);
|
||||
@imagefilledrectangle($thumb,0,0,$resize_width-1,$resize_height-1,$white);
|
||||
|
||||
// 이미지 정보가 정해진 크기보다 크면 크기를 바꿈 (%를 구해서 처리)
|
||||
if($resize_width>0 && $width >= $resize_width) $width_per = $resize_width / $width;
|
||||
if($resize_height>0 && $height >= $resize_height) $height_per = $resize_height / $height;
|
||||
if($width_per < $height_per) $per = $height_per;
|
||||
else $per = $width_per;
|
||||
|
||||
// 원본 이미지의 타입으로 임시 이미지 생성
|
||||
switch($type) {
|
||||
case 'gif' :
|
||||
$source = @imagecreatefromgif($source_file);
|
||||
break;
|
||||
// jpg
|
||||
case 'jpeg' :
|
||||
case 'jpg' :
|
||||
$source = @imagecreatefromjpeg($source_file);
|
||||
break;
|
||||
// png
|
||||
case 'png' :
|
||||
$source = @imagecreatefrompng($source_file);
|
||||
break;
|
||||
// bmp
|
||||
case 'wbmp' :
|
||||
case 'bmp' :
|
||||
$source = @imagecreatefromwbmp($source_file);
|
||||
break;
|
||||
default :
|
||||
return;
|
||||
}
|
||||
|
||||
// 디렉토리 생성
|
||||
$path = preg_replace('/\/([^\.^\/]*)\.(gif|png|jpeg|bmp|wbmp)$/i','',$target_file);
|
||||
FileHandler::makeDir($path);
|
||||
|
||||
// 원본 이미지의 크기를 조절해서 임시 이미지에 넣음
|
||||
$new_width = (int)($width * $per);
|
||||
$new_height = (int)($height * $per);
|
||||
|
||||
$x = ($resize_width/2 - $new_width/2);
|
||||
$y = ($resize_height/2 - $new_height/2);
|
||||
|
||||
if($source) {
|
||||
if($new_width != $width || $new_height != $height) {
|
||||
if(function_exists('imagecopyresampled')) @imagecopyresampled($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height);
|
||||
else @imagecopyresized($thumb, $source, $x, $y, 0, 0, $new_width, $new_height, $width, $height);
|
||||
} else $thumb = $source;
|
||||
}
|
||||
|
||||
// 파일을 쓰고 끝냄
|
||||
switch($target_type) {
|
||||
case 'gif' :
|
||||
@imagegif($thumb, $target_file, 100);
|
||||
break;
|
||||
case 'jpeg' :
|
||||
case 'jpg' :
|
||||
@imagejpeg($thumb, $target_file, 100);
|
||||
break;
|
||||
case 'png' :
|
||||
@imagepng($thumb, $target_file, 100);
|
||||
break;
|
||||
case 'wbmp' :
|
||||
case 'bmp' :
|
||||
@imagewbmp($thumb, $target_file, 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
11
classes/handler/Handler.class.php
Normal file
11
classes/handler/Handler.class.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* @class Handler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief (*)Handler 클래스의 추상화 클래스
|
||||
**/
|
||||
|
||||
class Handler {
|
||||
|
||||
}
|
||||
?>
|
||||
326
classes/module/ModuleHandler.class.php
Normal file
326
classes/module/ModuleHandler.class.php
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
<?php
|
||||
/**
|
||||
* @class ModuleHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 모듈 핸들링을 위한 Handler
|
||||
*
|
||||
* 모듈을 실행시키기 위한 클래스.
|
||||
* constructor에 아무 인자 없이 객체를 생성하면 현재 요청받은
|
||||
* 상태를 바탕으로 적절한 모듈을 찾게 되고,
|
||||
* 별도의 인자 값을 줄 경우 그에 맞는 모듈을 찾아서 실행한다.
|
||||
* 만약 찾아진 모듈의 요청된 act 가 없으면 action_foward를 참조하여 다른 모듈의 act를 실행한다.
|
||||
**/
|
||||
|
||||
class ModuleHandler extends Handler {
|
||||
|
||||
var $oModule = NULL; ///< 모듈 객체
|
||||
|
||||
var $module = NULL; ///< 모듈
|
||||
var $act = NULL; ///< action
|
||||
var $mid = NULL; ///< 모듈의 객체명
|
||||
var $document_srl = NULL; ///< 문서 번호
|
||||
|
||||
var $module_info = NULL; ///< 모듈의 정보
|
||||
|
||||
var $error = NULL; ///< 진행 도중 에러 발생시 에러 코드를 정의, message 모듈을 호출시 사용
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* ModuleHandler에서 사용할 변수를 미리 세팅
|
||||
* 인자를 넘겨주지 않으면 현 페이지 요청받은 Request Arguments를 이용하여
|
||||
* 변수를 세팅한다.
|
||||
**/
|
||||
function ModuleHandler($module = '', $act = '', $mid = '', $document_srl = '') {
|
||||
// 설치가 안되어 있다면 install module을 지정
|
||||
if(!Context::isInstalled()) {
|
||||
$this->module = 'install';
|
||||
$this->act = Context::get('act');
|
||||
return;
|
||||
}
|
||||
|
||||
// Request Argument중 모듈을 찾을 수 있는 변수를 구함
|
||||
if(!$module) $this->module = Context::get('module');
|
||||
else $this->module = $module;
|
||||
|
||||
if(!$act) $this->act = Context::get('act');
|
||||
else $this->act = $act;
|
||||
|
||||
if(!$mid) $this->mid = Context::get('mid');
|
||||
else $this->mid = $mid;
|
||||
|
||||
if(!$document_srl) $this->document_srl = (int)Context::get('document_srl');
|
||||
else $this->document_srl = (int)$document_srl;
|
||||
|
||||
// 기본 변수들의 검사 (XSS방지를 위한 기초적 검사)
|
||||
if($this->module && !eregi("^([a-z0-9\_\-]+)$",$this->module)) die(Context::getLang("msg_invalid_request"));
|
||||
if($this->mid && !eregi("^([a-z0-9\_\-]+)$",$this->mid)) die(Context::getLang("msg_invalid_request"));
|
||||
if($this->act && !eregi("^([a-z0-9\_\-]+)$",$this->act)) die(Context::getLang("msg_invalid_request"));
|
||||
|
||||
// 애드온 실행 (모듈 실행 전)
|
||||
$called_position = 'before_module_init';
|
||||
@include("./files/cache/activated_addons.cache.php");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief module, mid, document_srl을 이용하여 모듈을 찾고 act를 실행하기 위한 준비를 함
|
||||
**/
|
||||
function init() {
|
||||
// ModuleModel 객체 생성
|
||||
$oModuleModel = &getModel('module');
|
||||
|
||||
// document_srl이 있으면 document_srl로 모듈과 모듈 정보를 구함
|
||||
if($this->document_srl && !$this->mid) $module_info = $oModuleModel->getModuleInfoByDocumentSrl($this->document_srl);
|
||||
if($this->module && $module_info->module != $this->module) unset($module_info);
|
||||
|
||||
// 아직 모듈을 못 찾았고 $mid값이 있으면 $mid로 모듈을 구함
|
||||
if(!$module_info && $this->mid) $module_info = $oModuleModel->getModuleInfoByMid($this->mid);
|
||||
if($this->module && $module_info->module != $this->module) unset($module_info);
|
||||
|
||||
// 역시 모듈을 못 찾았고 $module이 없다면 기본 모듈을 찾아봄
|
||||
if(!$module_info && !$this->module) $module_info = $oModuleModel->getModuleInfoByMid();
|
||||
|
||||
// 모듈 정보가 찾아졌을 경우 모듈 정보에서 기본 변수들을 구함, 모듈 정보에서 module 이름을 구해움
|
||||
if($module_info) {
|
||||
$this->module = $module_info->module;
|
||||
$this->mid = $module_info->mid;
|
||||
$this->module_info = $module_info;
|
||||
Context::setBrowserTitle($module_info->browser_title);
|
||||
}
|
||||
|
||||
// 여기까지도 모듈 정보를 찾지 못했다면 깔끔하게 시스템 오류 표시
|
||||
if(!$this->module) $this->error = 'msg_module_is_not_exists';
|
||||
|
||||
// mid값이 있을 경우 mid값을 세팅
|
||||
if($this->mid) Context::set('mid', $this->mid, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈과 관련된 정보를 이용하여 객체를 구하고 act 실행까지 진행시킴
|
||||
**/
|
||||
function procModule() {
|
||||
// 에러가 있으면 return
|
||||
if($this->error) return;
|
||||
|
||||
// ModuleModel 객체 생성
|
||||
$oModuleModel = &getModel('module');
|
||||
|
||||
// 해당 모듈의 conf/action.xml 을 분석하여 action 정보를 얻어옴
|
||||
$xml_info = $oModuleModel->getModuleActionXml($this->module);
|
||||
|
||||
// 미설치시에는 act값을 강제로 변경
|
||||
if($this->module=="install") {
|
||||
if(!$this->act || !$xml_info->action->{$this->act}) $this->act = $xml_info->default_index_act;
|
||||
}
|
||||
|
||||
// 현재 요청된 act가 있으면 $xml_info에서 type을 찾음, 없다면 기본 action을 이용
|
||||
if(!$this->act) $this->act = $xml_info->default_index_act;
|
||||
|
||||
// act값이 지정이 안되어 있으면 오류 표시
|
||||
if(!$this->act) {
|
||||
$this->error = 'msg_module_is_not_exists';
|
||||
return;
|
||||
}
|
||||
|
||||
// 설정된 mid가 없을 경우 요청된 act의 standalone 여부 체크
|
||||
/*
|
||||
if(!$this->mid && !$xml_info->action->{$this->act}->standalone) {
|
||||
$this->error = 'msg_module_is_not_standalone';
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// type, grant 값 구함
|
||||
$type = $xml_info->action->{$this->act}->type;
|
||||
$grant = $xml_info->action->{$this->act}->grant;
|
||||
$kind = strpos(strtolower($this->act),'admin')!==false?'admin':'';
|
||||
if(!$kind && $this->module == 'admin') $kind = 'admin';
|
||||
|
||||
// 모듈 객체 생성
|
||||
$oModule = &$this->getModuleInstance($this->module, $type, $kind);
|
||||
if(!is_object($oModule)) {
|
||||
$this->error = 'msg_module_is_not_exists';
|
||||
return;
|
||||
}
|
||||
|
||||
// 모듈에 act값을 세팅
|
||||
$oModule->setAct($this->act);
|
||||
|
||||
// 모듈 정보 세팅
|
||||
$oModule->setModuleInfo($this->module_info, $xml_info);
|
||||
|
||||
// 모듈을 수행하고 결과가 false이면 message 모듈 호출 지정
|
||||
if(!$oModule->proc()) $this->error = $oModule->getMessage();
|
||||
|
||||
return $oModule;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ 실행된 모듈의 컨텐츠를 출력
|
||||
**/
|
||||
function displayContent($oModule = NULL) {
|
||||
// 설정된 모듈이 정상이지 않을 경우 message 모듈 객체 생성
|
||||
if(!$oModule || !is_object($oModule)) {
|
||||
$this->error = 'msg_module_is_not_exists';
|
||||
}
|
||||
|
||||
// 에러가 발생하였을시 처리
|
||||
if($this->error) {
|
||||
// message 모듈 객체를 생성해서 컨텐츠 생성
|
||||
$oMessageView = &getView('message');
|
||||
$oMessageView->setError(-1);
|
||||
$oMessageView->setMessage($this->error);
|
||||
$oMessageView->dispMessage();
|
||||
|
||||
// 정상적으로 호출된 객체가 있을 경우 해당 객체의 template를 변경
|
||||
if($oModule) {
|
||||
$oModule->setTemplatePath($oMessageView->getTemplatePath());
|
||||
$oModule->setTemplateFile($oMessageView->getTemplateFile());
|
||||
|
||||
// 그렇지 않으면 message 객체를 호출된 객체로 지정
|
||||
} else {
|
||||
$oModule = $oMessageView;
|
||||
}
|
||||
}
|
||||
|
||||
// 해당 모듈에 layout_srl이 있는지 확인
|
||||
if($oModule->module_info->layout_srl && !$oModule->getLayoutFile()) {
|
||||
// layout_srl이 있으면 해당 레이아웃 정보를 가져와 layout_path/ layout_file 위치 변경
|
||||
$oLayoutModel = &getModel('layout');
|
||||
$layout_info = $oLayoutModel->getLayout($oModule->module_info->layout_srl);
|
||||
|
||||
if($layout_info) {
|
||||
|
||||
// 레이아웃 정보중 extra_vars의 이름과 값을 $layout_info에 입력
|
||||
if($layout_info->extra_var_count) {
|
||||
foreach($layout_info->extra_var as $var_id => $val) {
|
||||
$layout_info->{$var_id} = $val->value;
|
||||
}
|
||||
}
|
||||
|
||||
// 레이아웃 정보중 menu를 Context::set
|
||||
if($layout_info->menu_count) {
|
||||
foreach($layout_info->menu as $menu_id => $menu) {
|
||||
if(file_exists($menu->php_file)) @include($menu->php_file);
|
||||
Context::set($menu_id, $menu);
|
||||
}
|
||||
}
|
||||
|
||||
// 레이아웃 정보를 Context::set
|
||||
Context::set('layout_info', $layout_info);
|
||||
|
||||
$oModule->setLayoutPath($layout_info->path);
|
||||
$oModule->setLayoutFile('layout');
|
||||
|
||||
// 레이아웃이 수정되었을 경우 수정본을 지정
|
||||
$edited_layout = sprintf('./files/cache/layout/%d.html', $layout_info->layout_srl);
|
||||
if(file_exists($edited_layout)) $oModule->setEditedLayoutFile($edited_layout);
|
||||
}
|
||||
}
|
||||
|
||||
// 컨텐츠 출력
|
||||
$oDisplayHandler = new DisplayHandler();
|
||||
$oDisplayHandler->printContent($oModule);
|
||||
|
||||
// DB 및 기타 자원의 종결 처리
|
||||
Context::close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief module의 위치를 찾아서 return
|
||||
**/
|
||||
function getModulePath($module) {
|
||||
$class_path = sprintf('./modules/%s/', $module);
|
||||
if(is_dir($class_path)) return $class_path;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈 객체를 생성함
|
||||
**/
|
||||
function &getModuleInstance($module, $type = 'view', $kind = '') {
|
||||
$class_path = ModuleHandler::getModulePath($module);
|
||||
if(!$class_path) return NULL;
|
||||
|
||||
if(__DEBUG__==3) $start_time = getMicroTime();
|
||||
|
||||
if($kind != 'admin') $kind = 'svc';
|
||||
|
||||
// global 변수에 미리 생성해 둔 객체가 없으면 새로 생성
|
||||
if(!$GLOBALS['_loaded_module'][$module][$type][$kind]) {
|
||||
|
||||
/**
|
||||
* 모듈의 위치를 파악
|
||||
**/
|
||||
|
||||
// 상위 클래스명 구함
|
||||
if(!class_exists($module)) {
|
||||
$high_class_file = sprintf('%s%s.class.php', $class_path, $module);
|
||||
if(!file_exists($high_class_file)) return NULL;
|
||||
require_once($high_class_file);
|
||||
}
|
||||
|
||||
// 객체의 이름을 구함
|
||||
switch($type) {
|
||||
case 'controller' :
|
||||
if($kind == 'admin') {
|
||||
$instance_name = sprintf("%sAdmin%s",$module,"Controller");
|
||||
$class_file = sprintf('%s%s.admin.%s.php', $class_path, $module, $type);
|
||||
} else {
|
||||
$instance_name = sprintf("%s%s",$module,"Controller");
|
||||
$class_file = sprintf('%s%s.%s.php', $class_path, $module, $type);
|
||||
}
|
||||
break;
|
||||
case 'model' :
|
||||
if($kind == 'admin') {
|
||||
$instance_name = sprintf("%sAdmin%s",$module,"Model");
|
||||
$class_file = sprintf('%s%s.admin.%s.php', $class_path, $module, $type);
|
||||
} else {
|
||||
$instance_name = sprintf("%s%s",$module,"Model");
|
||||
$class_file = sprintf('%s%s.%s.php', $class_path, $module, $type);
|
||||
}
|
||||
break;
|
||||
case 'class' :
|
||||
$instance_name = $module;
|
||||
$class_file = sprintf('%s%s.class.php', $class_path, $module);
|
||||
break;
|
||||
default :
|
||||
$type = 'view';
|
||||
if($kind == 'admin') {
|
||||
$instance_name = sprintf("%sAdmin%s",$module,"View");
|
||||
$class_file = sprintf('%s%s.admin.view.php', $class_path, $module, $type);
|
||||
} else {
|
||||
$instance_name = sprintf("%s%s",$module,"View");
|
||||
$class_file = sprintf('%s%s.view.php', $class_path, $module, $type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 클래스 파일의 이름을 구함
|
||||
if(!file_exists($class_file)) return NULL;
|
||||
|
||||
// eval로 객체 생성
|
||||
require_once($class_file);
|
||||
$eval_str = sprintf('$oModule = new %s();', $instance_name);
|
||||
@eval($eval_str);
|
||||
if(!is_object($oModule)) return NULL;
|
||||
|
||||
// 해당 위치에 속한 lang 파일을 읽음
|
||||
Context::loadLang($class_path.'lang');
|
||||
|
||||
// 생성된 객체에 자신이 호출된 위치를 세팅해줌
|
||||
$oModule->setModule($module);
|
||||
$oModule->setModulePath($class_path);
|
||||
|
||||
// GLOBALS 변수에 생성된 객체 저장
|
||||
$GLOBALS['_loaded_module'][$module][$type][$kind] = $oModule;
|
||||
}
|
||||
|
||||
if(__DEBUG__==3) $GLOBALS['__elapsed_class_load__'] += getMicroTime() - $start_time;
|
||||
|
||||
// 객체 리턴
|
||||
return $GLOBALS['_loaded_module'][$module][$type][$kind];
|
||||
}
|
||||
}
|
||||
?>
|
||||
342
classes/module/ModuleObject.class.php
Normal file
342
classes/module/ModuleObject.class.php
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
<?php
|
||||
/**
|
||||
* @class ModuleObject
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief module의 상위 클래스
|
||||
**/
|
||||
|
||||
class ModuleObject extends Object {
|
||||
|
||||
var $mid = NULL; ///< module로 생성한 instance(관리상)의 값
|
||||
var $module = NULL; ///< mid로 찾아서 생성한 모듈 class 이름
|
||||
var $module_srl = NULL; ///< 모듈 객체의 고유값인 module_srl
|
||||
var $module_info = NULL; ///< 모듈의 설정 정보
|
||||
var $xml_info = NULL; ///< 모듈 자체 정보
|
||||
|
||||
var $module_path = NULL; ///< 모듈 class file의 실행 위치
|
||||
|
||||
var $act = NULL; ///< act 값
|
||||
|
||||
var $template_path = NULL; ///< template 경로
|
||||
var $template_file = NULL; ///< template 파일
|
||||
|
||||
var $layout_path = ''; ///< 레이아웃 경로
|
||||
var $layout_file = ''; ///< 레이아웃 파일
|
||||
var $edited_layout_file = ''; ///< 관리자 모드에서 수정된 레이아웃 파일
|
||||
|
||||
var $stop_proc = false; ///< action 수행중 stop()를 호출하면 ModuleObject::proc()를 수행하지 않음
|
||||
|
||||
/**
|
||||
* @brief 현재 모듈의 이름을 지정
|
||||
**/
|
||||
function setModule($module) {
|
||||
$this->module = $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 현재 모듈의 path를 지정
|
||||
**/
|
||||
function setModulePath($path) {
|
||||
if(substr($path,-1)!='/') $path.='/';
|
||||
$this->module_path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief redirect_url을 정함
|
||||
*
|
||||
* redirect_url의 경우 ajax로 request를 받았을 경우에 사용하면 됨...
|
||||
**/
|
||||
function setRedirectUrl($url='./') {
|
||||
$this->add('redirect_url', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 현재 페이지를 refresh시킴
|
||||
*
|
||||
* 공통 tpl중 refresh.html을 실행할 뿐..
|
||||
**/
|
||||
function setRefreshPage() {
|
||||
$this->setTemplatePath('./common/tpl');
|
||||
$this->setTemplateFile('refresh');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief act값 지정
|
||||
**/
|
||||
function setAct($act) {
|
||||
$this->act = $act;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈의 정보 세팅
|
||||
**/
|
||||
function setModuleInfo($module_info, $xml_info) {
|
||||
// 기본 변수 설정
|
||||
$this->mid = $module_info->mid;
|
||||
$this->module_srl = $module_info->module_srl;
|
||||
$this->module_info = $module_info;
|
||||
$this->xml_info = $xml_info;
|
||||
$this->skin_vars = $module_info->skin_vars;
|
||||
|
||||
// 웹서비스에서 꼭 필요한 인증 정보와 권한 설정 체크
|
||||
$is_logged = Context::get('is_logged');
|
||||
$logged_info = Context::get('logged_info');
|
||||
$user_id = $logged_info->user_id;
|
||||
$user_group = $logged_info->group_list;
|
||||
|
||||
// 로그인되어 있다면 admin 체크
|
||||
if($is_logged && ($logged_info->is_admin == 'Y' || (is_array($this->module_info->admin_id)&&in_array($user_id, $this->module_info->admin_id) )) ) {
|
||||
$grant->is_admin = true;
|
||||
} else {
|
||||
$grant->is_admin = false;
|
||||
}
|
||||
|
||||
// act값에 admin이 들어 있는데 관리자가 아닌 경우 오류 표시
|
||||
if(substr_count($this->act, 'Admin')) {
|
||||
if(!$is_logged) {
|
||||
$this->setAct("dispMemberLoginForm");
|
||||
} elseif(!$grant->is_admin) {
|
||||
return $this->stop('msg_not_permitted_act');
|
||||
}
|
||||
}
|
||||
|
||||
if($module_info->grants) {
|
||||
foreach($module_info->grants as $key => $val) {
|
||||
if(!$xml_info->grant->{$key}) {
|
||||
$xml_info->grant->{$key}->title = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 권한 설정
|
||||
if($xml_info->grant) {
|
||||
|
||||
// 이 모듈에 action.xml에서 선언된 권한 목록을 루프
|
||||
foreach($xml_info->grant as $grant_name => $grant_item) {
|
||||
|
||||
// 제목과 기타 설정 없을 경우의 기본 권한(guest, member, root)에 대한 변수 설정
|
||||
$title = $grant_item->title;
|
||||
$default = $grant_item->default;
|
||||
|
||||
// 관리자이면 모든 권한에 대해 true 설정
|
||||
if($grant->is_admin) {
|
||||
$grant->{$grant_name} = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 일단 현재 권한에 대해 false 지정
|
||||
$grant->{$grant_name} = false;
|
||||
|
||||
// 모듈의 개별 설정에서 이 권한에 대한 그룹 지정이 있으면 체크
|
||||
if(count($this->module_info->grants[$grant_name])) {
|
||||
$group_srls = $this->module_info->grants[$grant_name];
|
||||
if(!is_array($group_srls)) $group_srls = array($group_srls);
|
||||
|
||||
if(count($user_group)) {
|
||||
foreach($user_group as $group_srl => $group_title) {
|
||||
if(in_array($group_srl, $group_srls)) {
|
||||
$grant->{$grant_name} = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 별도의 지정이 없으면 default값으로 권한 체크
|
||||
} else {
|
||||
switch($default) {
|
||||
case 'member' :
|
||||
if($is_logged) $grant->{$grant_name} = true;
|
||||
break;
|
||||
case 'root' :
|
||||
if($grant->is_admin) $grant->{$grant_name} = true;
|
||||
break;
|
||||
default :
|
||||
$grant->{$grant_name} = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 권한변수 설정
|
||||
$this->grant = $grant;
|
||||
Context::set('grant', $grant);
|
||||
|
||||
if(method_exists($this, 'init')) $this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 메세지 출력
|
||||
**/
|
||||
function stop($msg_code) {
|
||||
// proc 수행을 중지 시키기 위한 플래그 세팅
|
||||
$this->stop_proc = true;
|
||||
|
||||
// 에러 처리
|
||||
$this->setError(-1);
|
||||
$this->setMessage($msg_code);
|
||||
|
||||
// message 모듈의 에러 표시
|
||||
$oMessageView = &getView('message');
|
||||
$oMessageView->setError(-1);
|
||||
$oMessageView->setMessage($msg_code);
|
||||
$oMessageView->dispMessage();
|
||||
|
||||
$this->setTemplatePath($oMessageView->getTemplatePath());
|
||||
$this->setTemplateFile($oMessageView->getTemplateFile());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief template 파일 지정
|
||||
**/
|
||||
function setTemplateFile($filename) {
|
||||
if(substr($filename,-5)!='.html') $filename .= '.html';
|
||||
$this->template_file = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief template 파일 return
|
||||
**/
|
||||
function getTemplateFile() {
|
||||
return $this->template_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief template 경로 지정
|
||||
**/
|
||||
function setTemplatePath($path) {
|
||||
if(substr($path,0,2)!='./') $path = './'.$path;
|
||||
if(substr($path,-1)!='/') $path .= '/';
|
||||
$this->template_path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief template 경로 return
|
||||
**/
|
||||
function getTemplatePath() {
|
||||
return $this->template_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief edited layout 파일 지정
|
||||
**/
|
||||
function setEditedLayoutFile($filename) {
|
||||
if(substr($filename,-5)!='.html') $filename .= '.html';
|
||||
$this->edited_layout_file = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief layout 파일 return
|
||||
**/
|
||||
function getEditedLayoutFile() {
|
||||
return $this->edited_layout_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief layout 파일 지정
|
||||
**/
|
||||
function setLayoutFile($filename) {
|
||||
if(substr($filename,-5)!='.html') $filename .= '.html';
|
||||
$this->layout_file = $filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief layout 파일 return
|
||||
**/
|
||||
function getLayoutFile() {
|
||||
return $this->layout_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief layout 경로 지정
|
||||
**/
|
||||
function setLayoutPath($path) {
|
||||
if(substr($path,-1)!='/') $path .= '/';
|
||||
if(substr($path,0,2)!='./') $path = './'.$path;
|
||||
$this->layout_path = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief layout 경로 return
|
||||
**/
|
||||
function getLayoutPath() {
|
||||
return $this->layout_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 모듈의 action에 해당하는 method를 실행
|
||||
*
|
||||
* $act값에 의해서 $action_list에 선언된 것들을 실행한다
|
||||
**/
|
||||
function proc() {
|
||||
// stop_proc==true이면 그냥 패스
|
||||
if($this->stop_proc==true) return false;
|
||||
|
||||
// addon 실행(called_position 를 before_module_proc로 하여 호출)
|
||||
$called_position = 'before_module_proc';
|
||||
@include("./files/cache/activated_addons.cache.php");
|
||||
|
||||
// 지금까지 이상이 없었다면 action 실행
|
||||
if(!$this->stop_proc) {
|
||||
// 현재 모듈에 act값이 있으면 해당 act를 실행
|
||||
if(method_exists($this, $this->act)) {
|
||||
//$output = call_user_method($this->act, $this);
|
||||
//$output = call_user_func(array($this, $this->act));
|
||||
$output = $this->{$this->act}();
|
||||
|
||||
// act가 없으면 action_forward에서 해당하는 act가 있는지 찾아서 대신 실행
|
||||
} else if(Context::isInstalled()) {
|
||||
|
||||
$oModuleModel = &getModel('module');
|
||||
$forward = $oModuleModel->getActionForward($this->act);
|
||||
if($forward->module && $forward->type && $forward->act) {
|
||||
|
||||
$kind = strpos(strtolower($forward->act),'admin')!==false?'admin':'';
|
||||
$oModule = &getModule($forward->module, $forward->type, $kind);
|
||||
$xml_info = $oModuleModel->getModuleActionXml($forward->module);
|
||||
$oModule->setAct($forward->act);
|
||||
$oModule->init();
|
||||
$oModule->setModuleInfo($this->module_info, $xml_info);
|
||||
|
||||
//$output = call_user_method($forward->act, $oModule);
|
||||
//$output = call_user_func(array($oModule, $forward->act));
|
||||
$output = $oModule->{$forward->act}();
|
||||
|
||||
$this->setTemplatePath($oModule->getTemplatePath());
|
||||
$this->setTemplateFile($oModule->getTemplateFile());
|
||||
|
||||
} else {
|
||||
if($this->xml_info->default_index_act) {
|
||||
//$output = call_user_method($this->xml_info->default_index_act, $this);
|
||||
//$output = call_user_func(array($this, $this->xml_info->default_index_act));
|
||||
if(method_exists($this, $this->xml_info->default_index_act)) {
|
||||
$output = $this->{$this->xml_info->default_index_act}();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// addon 실행(called_position 를 after_module_proc로 하여 호출)
|
||||
$called_position = 'after_module_proc';
|
||||
@include("./files/cache/activated_addons.cache.php");
|
||||
|
||||
if(is_a($output, 'Object') || is_subclass_of($output, 'Object')) {
|
||||
$this->setError($output->getError());
|
||||
$this->setMessage($output->getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
||||
120
classes/object/Object.class.php
Normal file
120
classes/object/Object.class.php
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
/**
|
||||
* @class Object
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 모듈간의 데이터를 주고 받기 위한 클래스
|
||||
*
|
||||
* 모든 모듈은 Object를 상속하며 Object의 error, message, variables 를 이용하여 통신을 하게 된다
|
||||
**/
|
||||
|
||||
class Object {
|
||||
|
||||
var $error = 0; ///< 에러 코드 (0이면 에러 아님)
|
||||
var $message = 'success'; ///< 에러 메세지 (success이면 에러 아님)
|
||||
|
||||
var $variables = array(); ///< 추가 변수
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function Object($error = 0, $message = 'success') {
|
||||
$this->setError($error);
|
||||
$this->setMessage($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief error 코드를 지정
|
||||
**/
|
||||
function setError($error = 0) {
|
||||
$this->error = $error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief error 코드를 return
|
||||
**/
|
||||
function getError() {
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 에러 메세지 지정
|
||||
**/
|
||||
function setMessage($message = 'success') {
|
||||
if(Context::getLang($message)) $message = Context::getLang($message);
|
||||
$this->message = $message;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 에러 메세지 return
|
||||
**/
|
||||
function getMessage() {
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 추가 변수
|
||||
**/
|
||||
function add($key, $val) {
|
||||
$this->variables[$key] = $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 추가된 변수의 key, value들을 추가
|
||||
**/
|
||||
function adds($object) {
|
||||
if(is_object($object)) {
|
||||
$vars = get_object_vars($object);
|
||||
foreach($vars as $key => $val) $this->add($key, $val);
|
||||
} elseif(is_array($object)) {
|
||||
foreach($object as $key => $val) $this->add($key, $val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 추가된 변수의 key에 해당하는 값을 return
|
||||
**/
|
||||
function get($key) {
|
||||
return $this->variables[$key];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 추가된 변수의 key들에 해당하는 값을 return
|
||||
**/
|
||||
function gets() {
|
||||
$num_args = func_num_args();
|
||||
$args_list = func_get_args();
|
||||
for($i=0;$i<$num_args;$i++) {
|
||||
$key = $args_list[$i];
|
||||
$output->{$key} = $this->gets($key);
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 추가변수 전체 return
|
||||
**/
|
||||
function getVariables() {
|
||||
return $this->variables;
|
||||
}
|
||||
|
||||
function getObjectVars() {
|
||||
foreach($this->variables as $key => $val) $output->{$key} = $val;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief error값이 0이 아니면 오류
|
||||
**/
|
||||
function toBool() {
|
||||
return $this->error==0?true:false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief error값이 0이 아니면 오류 (Object::toBool()의 aliasing)
|
||||
**/
|
||||
function toBoolean() {
|
||||
return $this->toBool();
|
||||
}
|
||||
}
|
||||
?>
|
||||
52
classes/page/PageHandler.class.php
Normal file
52
classes/page/PageHandler.class.php
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* @class PageHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 페이지 네비게이션 담당
|
||||
* @version 0.1
|
||||
*
|
||||
* 전체갯수, 전체페이지, 현재페이지, 페이지당 목록의 수를 넘겨주면 \n
|
||||
* 페이지 네비게이션에 필요한 variables와 method를 구현\n
|
||||
**/
|
||||
|
||||
class PageHandler extends Handler {
|
||||
|
||||
var $total_count = 0; ///< 전체 item의 갯수
|
||||
var $total_page = 0; ///< 전체 페이지 수
|
||||
var $cur_page = 0; ///< 현 페이지
|
||||
var $page_count = 10; ///< 한번에 보일 페이지의 수
|
||||
var $first_page = 1; ///< 첫 페이지
|
||||
var $last_page = 1; ///< 마지막 페이지
|
||||
var $point = 0; ///< getNextPage() 호출시 증가하는 값
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function PageHandler($total_count, $total_page, $cur_page, $page_count = 10) {
|
||||
$this->total_count = $total_count;
|
||||
$this->total_page = $total_page;
|
||||
$this->cur_page = $cur_page;
|
||||
$this->page_count = $page_count;
|
||||
$this->point = 0;
|
||||
|
||||
$first_page = $cur_page - (int)($page_count/2);
|
||||
if($first_page<1) $first_page = 1;
|
||||
$last_page = $total_page;
|
||||
if($last_page>$total_page) $last_page = $total_page;
|
||||
|
||||
$this->first_page = $first_page;
|
||||
$this->last_page = $last_page;
|
||||
|
||||
if($total_page < $this->page_count) $this->page_count = $total_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 다음 페이지 요청
|
||||
**/
|
||||
function getNextPage() {
|
||||
$page = $this->first_page+$this->point++;
|
||||
if($this->point > $this->page_count || $page > $this->last_page) $page = 0;
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
?>
|
||||
339
classes/template/TemplateHandler.class.php
Normal file
339
classes/template/TemplateHandler.class.php
Normal file
|
|
@ -0,0 +1,339 @@
|
|||
<?php
|
||||
/**
|
||||
* @class TemplateHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 템플릿 컴파일러
|
||||
* @version 0.1
|
||||
*
|
||||
* 정규표현식을 이용하여 템플릿 파일을 컴파일하여 php코드로 변경하고 이 파일을 caching하여 사용할 수 있도록 하는 템플릿 컴파일러
|
||||
**/
|
||||
|
||||
class TemplateHandler extends Handler {
|
||||
|
||||
var $compiled_path = './files/cache/template_compiled/'; ///< 컴파일된 캐쉬 파일이 놓일 위치
|
||||
|
||||
var $tpl_path = ''; ///< 컴파일 대상 경로
|
||||
var $tpl_file = ''; ///< 컴파일 대상 파일
|
||||
|
||||
/**
|
||||
* @brief TemplateHandler의 기생성된 객체를 return
|
||||
**/
|
||||
function &getInstance() {
|
||||
if(__DEBUG__==3 ) {
|
||||
if(!isset($GLOBALS['__TemplateHandlerCalled__'])) $GLOBALS['__TemplateHandlerCalled__']=1;
|
||||
else $GLOBALS['__TemplateHandlerCalled__']++;
|
||||
}
|
||||
|
||||
if(!$GLOBALS['__TemplateHandler__']) {
|
||||
$GLOBALS['__TemplateHandler__'] = new TemplateHandler();
|
||||
}
|
||||
return $GLOBALS['__TemplateHandler__'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 주어진 tpl파일의 컴파일
|
||||
**/
|
||||
function compile($tpl_path, $tpl_filename, $tpl_file = '') {
|
||||
// 디버그를 위한 컴파일 시작 시간 저장
|
||||
if(__DEBUG__==3 ) $start = getMicroTime();
|
||||
|
||||
// 변수 체크
|
||||
$tpl_path = ereg_replace('(\/+)$', '', $tpl_path).'/';
|
||||
if(substr($tpl_filename,-5)!='.html') $tpl_filename .= '.html';
|
||||
|
||||
// tpl_file 변수 생성
|
||||
if(!$tpl_file) $tpl_file = $tpl_path.$tpl_filename;
|
||||
|
||||
// tpl_file이 비어 있거나 해당 파일이 없으면 return
|
||||
if(!$tpl_file || !file_exists($tpl_file)) return;
|
||||
|
||||
$this->tpl_path = $tpl_path;
|
||||
$this->tpl_file = $tpl_file;
|
||||
|
||||
// compiled된(or 될) 파일이름을 구함
|
||||
$compiled_tpl_file = $this->_getCompiledFileName($tpl_file);
|
||||
|
||||
// 일단 컴파일
|
||||
$buff = $this->_compile($tpl_file, $compiled_tpl_file);
|
||||
|
||||
// Context와 compiled_tpl_file로 컨텐츠 생성
|
||||
$output = $this->_fetch($compiled_tpl_file, $buff, $tpl_path);
|
||||
|
||||
if(__DEBUG__==3 ) $GLOBALS['__template_elapsed__'] += getMicroTime() - $start;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tpl_file이 컴파일이 되어 있는 것이 있는지 체크
|
||||
**/
|
||||
function _compile($tpl_file, $compiled_tpl_file) {
|
||||
if(!file_exists($compiled_tpl_file)) return $this->_compileTplFile($tpl_file, $compiled_tpl_file);
|
||||
|
||||
$source_ftime = filectime($tpl_file);
|
||||
$target_ftime = filectime($compiled_tpl_file);
|
||||
if($source_ftime>$target_ftime) return $this->_compileTplFile($tpl_file, $compiled_tpl_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief tpl_file을 compile
|
||||
**/
|
||||
function _compileTplFile($tpl_file, $compiled_tpl_file) {
|
||||
|
||||
// tpl 파일을 읽음
|
||||
$buff = FileHandler::readFile($tpl_file);
|
||||
if(!$buff) return;
|
||||
|
||||
// include 변경 <!--#include($filename)-->
|
||||
$buff = preg_replace_callback('!<\!--#include\(([^\)]*?)\)-->!is', array($this, '_compileIncludeToCode'), $buff);
|
||||
|
||||
// include 변경 <!--#include($filename)-->
|
||||
$buff = preg_replace_callback('!<\!--#include\(([^\)]*?)\)-->!is', array($this, '_compileIncludeToCode'), $buff);
|
||||
|
||||
// 이미지 태그 img의 src의 값이 http:// 나 / 로 시작하지 않으면 제로보드의 root경로부터 시작하도록 변경
|
||||
$buff = preg_replace_callback('!(img|input)([^>]*)src=[\'"]{1}(.*?)[\'"]{1}!is', array($this, '_compileImgPath'), $buff);
|
||||
|
||||
// 변수를 변경
|
||||
$buff = preg_replace_callback('/\{[^@^ ]([^\}]+)\}/i', array($this, '_compileVarToContext'), $buff);
|
||||
|
||||
// 결과를 출력하지 않는 구문 변경
|
||||
$buff = preg_replace_callback('/\{\@([^\}]+)\}/i', array($this, '_compileVarToSilenceExecute'), $buff);
|
||||
|
||||
// <!--@, --> 의 변경
|
||||
$buff = preg_replace_callback('!<\!--@(.*?)-->!is', array($this, '_compileFuncToCode'), $buff);
|
||||
|
||||
// import xml filter/ css/ js/ 언어파일 <!--%filename-->
|
||||
$buff = preg_replace_callback('!<\!--%import\(\"([^\"]*?)\"\)-->!is', array($this, '_compileImportCode'), $buff);
|
||||
|
||||
// 파일에 쓰기 전에 직접 호출되는 것을 방지
|
||||
$buff = sprintf('%s%s%s','<?php if(!defined("__ZBXE__")) exit();?>',"\n",$buff);
|
||||
|
||||
// strip white spaces..
|
||||
// $buff = preg_replace('/ +/', ' ', $buff);
|
||||
|
||||
// 컴파일된 코드를 파일에 저장
|
||||
FileHandler::writeFile($compiled_tpl_file, $buff);
|
||||
|
||||
return $buff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {$와 } 안의 $... 변수를 Context::get(...) 으로 변경
|
||||
**/
|
||||
function _compileVarToContext($matches) {
|
||||
$str = trim(substr($matches[0],1,strlen($matches[0])-2));
|
||||
return '<?php print('.preg_replace('/\$([a-zA-Z0-9\_\-\>]+)/i','$__Context->\\1', $str).');?>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {$와 } 안의 $... 변수를 Context::get(...) 으로 변경
|
||||
**/
|
||||
function _compileImgPath($matches) {
|
||||
$str1 = $matches[0];
|
||||
$str2 = $path = $matches[3];
|
||||
|
||||
if(!eregi("^([a-z0-9\_\.])",$path)) return $str1;
|
||||
|
||||
$path = preg_replace('/^(\.\/|\/)/','',$path);
|
||||
$path = '<?=$this->tpl_path?>'.$path;
|
||||
$output = str_replace($str2, $path, $str1);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief {@와 } 안의 @... 함수를 print func(..)로 변경
|
||||
**/
|
||||
function _compileVarToSilenceExecute($matches) {
|
||||
return '<?php @'.preg_replace('/\$([a-zA-Z0-9\_\-\>]+)/i','$__Context->\\1', trim($matches[1])).';?>';
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief <!--@, --> 사이의 구문을 php코드로 변경
|
||||
**/
|
||||
function _compileFuncToCode($matches) {
|
||||
$code = trim($matches[1]);
|
||||
if(!$code) return;
|
||||
|
||||
switch(strtolower($code)) {
|
||||
case 'else' :
|
||||
$output = '}else{';
|
||||
break;
|
||||
case 'end' :
|
||||
case 'endif' :
|
||||
case 'endfor' :
|
||||
case 'endforeach' :
|
||||
$output = '}';
|
||||
break;
|
||||
default :
|
||||
if(substr($code,0,4)=='else') {
|
||||
$code = '}'.$code;
|
||||
} elseif(substr($code,0,7)=='foreach') {
|
||||
$tmp_str = substr($code,8);
|
||||
$tmp_arr = explode(' ', $tmp_str);
|
||||
$var_name = $tmp_arr[0];
|
||||
if(substr($var_name,0,1)=='$') $prefix = sprintf('if(count($__Context->%s)) ', substr($var_name,1));
|
||||
else $prefix = sprintf('if(count(%s)) ', $var_name);
|
||||
}
|
||||
$output = preg_replace('/\$([a-zA-Z0-9\_\-]+)/i','$__Context->\\1', $code).'{';
|
||||
break;
|
||||
}
|
||||
|
||||
return sprintf('<?php %s %s ?>', $prefix, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief <!--#include $path-->를 변환
|
||||
**/
|
||||
function _compileIncludeToCode($matches) {
|
||||
// include하려는 대상문자열에 변수가 있으면 변수 처리
|
||||
$arg = str_replace(array('"','\''), '', $matches[1]);
|
||||
if(!$arg) return;
|
||||
|
||||
$tmp_arr = explode("/", $arg);
|
||||
for($i=0;$i<count($tmp_arr);$i++) {
|
||||
$item1 = trim($tmp_arr[$i]);
|
||||
if($item1=='.'||eregi("\.html$",$item1)) continue;
|
||||
|
||||
$tmp2_arr = explode(".",$item1);
|
||||
for($j=0;$j<count($tmp2_arr);$j++) {
|
||||
$item = trim($tmp2_arr[$j]);
|
||||
if(substr($item,0,1)=='$') $item = Context::get(substr($item,1));
|
||||
$tmp2_arr[$j] = $item;
|
||||
}
|
||||
$tmp_arr[$i] = implode(".",$tmp2_arr);
|
||||
}
|
||||
$arg = implode("/",$tmp_arr);
|
||||
if(substr($arg,0,2)=='./') $arg = substr($arg,2);
|
||||
|
||||
// 1단계로 해당 tpl 내의 파일을 체크
|
||||
$source_filename = sprintf("%s/%s", dirname($this->tpl_file), $arg);
|
||||
|
||||
// 2단계로 root로부터 경로를 체크
|
||||
if(!file_exists($source_filename)) $source_filename = './'.$arg;
|
||||
if(!file_exists($source_filename)) return;
|
||||
|
||||
// path, filename으로 분리
|
||||
$tmp_arr = explode('/', $source_filename);
|
||||
$filename = array_pop($tmp_arr);
|
||||
$path = implode('/', $tmp_arr).'/';
|
||||
|
||||
// include 시도
|
||||
$output = sprintf(
|
||||
'<?php%s'.
|
||||
'$oTemplate = &TemplateHandler::getInstance();%s'.
|
||||
'print $oTemplate->compile(\'%s\',\'%s\');%s'.
|
||||
'?>%s',
|
||||
|
||||
"\n",
|
||||
|
||||
"\n",
|
||||
|
||||
$path, $filename, "\n",
|
||||
|
||||
"\n"
|
||||
);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief <!--%filename-->의 확장자를 봐서 js filter/ css/ js 파일을 include하도록 수정
|
||||
**/
|
||||
function _compileImportCode($matches) {
|
||||
// 현재 tpl 파일의 위치를 구해서 $base_path에 저장하여 적용하려는 xml file을 찾음
|
||||
//$base_path = dirname($this->tpl_file).'/';
|
||||
$base_path = $this->tpl_path;
|
||||
$given_file = trim($matches[1]);
|
||||
if(!$given_file) return;
|
||||
|
||||
// given_file이 lang으로 끝나게 되면 언어팩을 읽도록 함
|
||||
if(ereg('lang$', $given_file)) {
|
||||
if(substr($given_file,0,2)=='./') $given_file = substr($given_file, 2);
|
||||
$lang_dir = sprintf('%s%s', $this->tpl_path, $given_file);
|
||||
if(is_dir($lang_dir)) $output = sprintf('<?php Context::loadLang("%s"); ?>', $lang_dir);
|
||||
|
||||
// load lang이 아니라면 xml, css, js파일을 읽도록 시도
|
||||
} else {
|
||||
$filename = sprintf("%s%s",$base_path, $given_file);
|
||||
|
||||
// path와 파일이름을 구함
|
||||
$tmp_arr = explode("/",$filename);
|
||||
$filename = array_pop($tmp_arr);
|
||||
|
||||
$base_path = implode("/",$tmp_arr)."/";
|
||||
|
||||
// 확장자를 구함
|
||||
$tmp_arr = explode(".",$filename);
|
||||
$ext = strtolower(array_pop($tmp_arr));
|
||||
|
||||
// 확장자에 따라서 파일 import를 별도로
|
||||
switch($ext) {
|
||||
// xml js filter
|
||||
case 'xml' :
|
||||
// XmlJSFilter 클래스의 객체 생성후 js파일을 만들고 Context::addJsFile처리
|
||||
$output = sprintf(
|
||||
'<?php%s'.
|
||||
'require_once("./classes/xml/XmlJsFilter.class.php");%s'.
|
||||
'$oXmlFilter = new XmlJSFilter("%s","%s");%s'.
|
||||
'$oXmlFilter->compile();%s'.
|
||||
'?>%s',
|
||||
"\n",
|
||||
"\n",
|
||||
$base_path,
|
||||
$filename,
|
||||
"\n",
|
||||
"\n",
|
||||
"\n"
|
||||
);
|
||||
break;
|
||||
// css file
|
||||
case 'css' :
|
||||
$meta_file = sprintf('%s%s', $base_path, $filename);
|
||||
$output = sprintf('<?php Context::addCSSFile("%s%s"); ?>', $base_path, $filename);
|
||||
break;
|
||||
// js file
|
||||
case 'js' :
|
||||
$meta_file = sprintf('%s%s', $base_path, $filename);
|
||||
$output = sprintf('<?php Context::addJsFile("%s%s"); ?>', $base_path, $filename);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$output = '<!--Meta:'.$meta_file.'-->'.$output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief $tpl_file로 compiled_tpl_file이름을 return
|
||||
**/
|
||||
function _getCompiledFileName($tpl_file) {
|
||||
return sprintf('%s%s.compiled.php',$this->compiled_path, md5($tpl_file));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ob_* 함수를 이용하여 fetch...
|
||||
**/
|
||||
function _fetch($compiled_tpl_file, $buff = NULL, $tpl_path = '') {
|
||||
$__Context = &$GLOBALS['__Context__'];
|
||||
$__Context->tpl_path = $tpl_path;
|
||||
|
||||
if($_SESSION['is_logged']) $__Context->logged_info = $_SESSION['logged_info'];
|
||||
|
||||
// ob_start를 시킨후 컴파일된 tpl파일을 include하고 결과를 return
|
||||
ob_start();
|
||||
|
||||
// tpl파일을 compile하지 못할 경우 $buff로 넘어온 값을 eval시킴 (미설치시에나..)
|
||||
if($buff) {
|
||||
$eval_str = "?>".$buff;
|
||||
eval($eval_str);
|
||||
} else {
|
||||
@include($compiled_tpl_file);
|
||||
}
|
||||
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
?>
|
||||
132
classes/widget/WidgetHandler.class.php
Normal file
132
classes/widget/WidgetHandler.class.php
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* @class WidgetHandler
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief 위젯의 실행을 담당
|
||||
**/
|
||||
|
||||
class WidgetHandler {
|
||||
|
||||
var $widget_path = '';
|
||||
|
||||
/**
|
||||
* @brief 위젯 캐시 처리
|
||||
**/
|
||||
function getCache($sequence, $cache) {
|
||||
if(!$sequence || !$cache) return;
|
||||
|
||||
$cache_path = './files/cache/widget_cache/';
|
||||
if(!is_dir($cache_path)) {
|
||||
FileHandler::makeDir($cache_path);
|
||||
return;
|
||||
}
|
||||
|
||||
$cache_file = sprintf('%s%d.%s.cache', $cache_path, $sequence, Context::getLangType());
|
||||
if(!file_exists($cache_file)) return;
|
||||
|
||||
$filectime = filectime($cache_file);
|
||||
if($filectime + $cache*60 < time()) return;
|
||||
|
||||
$output = FileHandler::readFile($cache_file);
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 위젯을 찾아서 실행하고 결과를 출력
|
||||
* <div widget='위젯'...></div> 태그 사용 templateHandler에서 WidgetHandler::execute()를 실행하는 코드로 대체하게 된다
|
||||
**/
|
||||
function execute($widget, $args) {
|
||||
// 디버그를 위한 위젯 실행 시간 저장
|
||||
if(__DEBUG__==3) $start = getMicroTime();
|
||||
|
||||
// $widget의 객체를 받음
|
||||
$oWidget = WidgetHandler::getObject($widget);
|
||||
|
||||
// 위젯 실행
|
||||
if($oWidget) {
|
||||
$output = $oWidget->proc($args);
|
||||
}
|
||||
|
||||
if($args->widget_fix_width == 'Y') {
|
||||
$widget_width_type = strtolower($args->widget_width_type);
|
||||
if(!$widget_width_type||!in_array($widget_width_type,array("px","%"))) $widget_width_type = "px";
|
||||
|
||||
|
||||
if($widget_width_type == "px") {
|
||||
|
||||
$style = "overflow:hidden;";
|
||||
$style .= sprintf("%s:%s%s;", "width", $args->widget_width - $args->widget_margin_right - $args->widget_margin_left, $widget_width_type);
|
||||
$style .= sprintf("margin-top:%dpx;margin-bottom:%dpx;", $args->widget_margin_top, $args->widget_margin_bottom);
|
||||
$inner_style = sprintf("margin-left:%dpx;margin-right:%dpx;", $args->widget_margin_left, $args->widget_margin_right);
|
||||
|
||||
if($args->widget_position) {
|
||||
$style .= sprintf("%s:%s;", "float", $args->widget_position);
|
||||
$output = sprintf('<div style="%s"><div style="%s">%s</div></div>',$style, $inner_style, $output);
|
||||
} else {
|
||||
$style .= "float:left;";
|
||||
$output = sprintf('<div class="clear"></div><div style="%s"><div style="%s">%s</div></div>',$style, $inner_style, $output);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
$style = sprintf("padding:0;overflow:hidden;%s:%s%s;", "width", $args->widget_width, $widget_width_type);
|
||||
|
||||
$output = sprintf('<div style="margin:%dpx %dpx %dpx %dpx;">%s</div>', $args->widget_margin_top, $args->widget_margin_right,$args->widget_margin_bottom,$args->widget_margin_left, $output);
|
||||
|
||||
if($args->widget_position) {
|
||||
$style .= sprintf("%s:%s;", "float", $args->widget_position);
|
||||
$output = sprintf('<div style="%s">%s</div>',$style, $output);
|
||||
} else {
|
||||
$style .= "float:left;";
|
||||
$output = sprintf('<div class="clear"></div><div style="%s">%s</div>',$style, $output);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
$output = sprintf('<div style="margin:%dpx %dpx %dpx %dpx;padding:0;clear:both;">%s</div>', $args->widget_margin_top, $args->widget_margin_right,$args->widget_margin_bottom,$args->widget_margin_left, $output);
|
||||
}
|
||||
|
||||
if(__DEBUG__==3) $GLOBALS['__widget_excute_elapsed__'] += getMicroTime() - $start;
|
||||
|
||||
if($args->widget_sequence && $args->widget_cache) {
|
||||
$cache_path = './files/cache/widget_cache/';
|
||||
$cache_file = sprintf('%s%d.%s.cache', $cache_path, $args->widget_sequence, Context::getLangType());
|
||||
|
||||
FileHandler::writeFile($cache_file, $output);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 위젯 객체를 return
|
||||
**/
|
||||
function getObject($widget) {
|
||||
if(!$GLOBALS['_xe_loaded_widgets_'][$widget]) {
|
||||
// 일단 위젯의 위치를 찾음
|
||||
$oWidgetModel = &getModel('widget');
|
||||
$path = $oWidgetModel->getWidgetPath($widget);
|
||||
|
||||
// 위젯 클래스 파일을 찾고 없으면 에러 출력 (html output)
|
||||
$class_file = sprintf('%s%s.class.php', $path, $widget);
|
||||
if(!file_exists($class_file)) return sprintf(Context::getLang('msg_widget_is_not_exists'), $widget);
|
||||
|
||||
// 위젯 클래스를 include
|
||||
require_once($class_file);
|
||||
|
||||
// 객체 생성
|
||||
$eval_str = sprintf('$oWidget = new %s();', $widget);
|
||||
@eval($eval_str);
|
||||
if(!is_object($oWidget)) return sprintf(Context::getLang('msg_widget_object_is_null'), $widget);
|
||||
|
||||
if(!method_exists($oWidget, 'proc')) return sprintf(Context::getLang('msg_widget_proc_is_null'), $widget);
|
||||
|
||||
$oWidget->widget_path = $path;
|
||||
|
||||
$GLOBALS['_xe_loaded_widgets_'][$widget] = $oWidget;
|
||||
}
|
||||
return $GLOBALS['_xe_loaded_widgets_'][$widget];
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
268
classes/xml/XmlJsFilter.class.php
Normal file
268
classes/xml/XmlJsFilter.class.php
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
/**
|
||||
* @class XmlJsFilter
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief filter xml문서를 해석하여 js파일로 만듬
|
||||
* @version 0.1
|
||||
*
|
||||
* xml filter 파일은 js script로 컴파일 되어 캐싱됨
|
||||
*
|
||||
* <filter name="js function 이름" act="서버에 요청할 action 이름" confirm_msg_code="submit시에 prompt로 물어볼 메세지의 코드" >
|
||||
* <form> <-- 폼 항목의 체크
|
||||
* <node target="name" required="true" minlength="1" maxlength="5" filter="email,userid,alpha,number" equalto="target" />
|
||||
* </form>
|
||||
* <parameter> <-- 폼 항목을 조합하여 key=val 의 js array로 return, act는 필수
|
||||
* <param name="key" target="target" />
|
||||
* </parameter>
|
||||
* <response callback_func="callback 받게 될 js function 이름 지정" > <-- 서버에 ajax로 전송하여 받을 결과값
|
||||
* <tag name="error" /> <-- error이름의 결과값을 받겠다는 것
|
||||
* </response>
|
||||
* </filter>
|
||||
*
|
||||
* - form - node
|
||||
* target = 폼 element의 이름
|
||||
* required = true/ false 꼭 있어야 하는지에 대한 체크
|
||||
* minlength, maxlength = 최소/최대 길이
|
||||
* filter = javascript로 체크하기 위한 체크 필터
|
||||
* email : email의 형식 ( aaa.aaa@aaa.com)
|
||||
* userid : 영문+숫자+_, 첫 글자는 영문, 소문자
|
||||
* alpha : 영문값만 허용
|
||||
* number : 숫자만 허용
|
||||
* equalto = target , 현재 폼과 지정 target의 값이 동일해야 함
|
||||
*
|
||||
* - parameter - param
|
||||
* name = key : key를 이름으로 가지고 value의 값을 가지는 array 값 생성
|
||||
* target = target_name : target form element의 값을 가져옴
|
||||
*
|
||||
* - response
|
||||
* tag = key : return받을 결과값의 변수명
|
||||
**/
|
||||
|
||||
class XmlJsFilter extends XmlParser {
|
||||
var $compiled_path = './files/cache/js_filter_compiled/'; ///< 컴파일된 캐시 파일이 놓일 위치
|
||||
var $xml_file = NULL; ///< 대상 xml 파일
|
||||
var $js_file = NULL; ///< 컴파일된 js 파일
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
**/
|
||||
function XmlJsFilter($path, $xml_file) {
|
||||
$this->xml_file = sprintf("%s%s",$path, $xml_file);
|
||||
$this->js_file = $this->_getCompiledFileName($this->xml_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 원 xml파일과 compiled된js파일의 시간 비교 및 유무 비교등을 처리
|
||||
**/
|
||||
function compile() {
|
||||
if(!file_exists($this->xml_file)) return;
|
||||
if(!file_exists($this->js_file)) $this->_compile();
|
||||
else if(filectime($this->xml_file)>filectime($this->js_file)) $this->_compile();
|
||||
Context::addJsFile($this->js_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 실제 xml_file을 컴파일하여 js_file을 생성
|
||||
**/
|
||||
function _compile() {
|
||||
global $lang;
|
||||
|
||||
// xml 파일을 읽음
|
||||
$buff = FileHandler::readFile($this->xml_file);
|
||||
|
||||
// xml parsing
|
||||
$xml_obj = parent::parse($buff);
|
||||
|
||||
// XmlJsFilter는 filter_name, field, parameter 3개의 데이터를 핸들링
|
||||
$filter_name = $xml_obj->filter->attrs->name;
|
||||
$confirm_msg_code = $xml_obj->filter->attrs->confirm_msg_code;
|
||||
$module = $xml_obj->filter->attrs->module;
|
||||
$act = $xml_obj->filter->attrs->act;
|
||||
$extend_filter = $xml_obj->filter->attrs->extend_filter;
|
||||
|
||||
$field_node = $xml_obj->filter->form->node;
|
||||
if($field_node && !is_array($field_node)) $field_node = array($field_node);
|
||||
|
||||
$parameter_param = $xml_obj->filter->parameter->param;
|
||||
if($parameter_param && !is_array($parameter_param)) $parameter_param = array($parameter_param);
|
||||
|
||||
$response_tag = $xml_obj->filter->response->tag;
|
||||
if($response_tag && !is_array($response_tag)) $response_tag = array($response_tag);
|
||||
|
||||
// extend_filter가 있을 경우 해당 method를 호출하여 결과를 받음
|
||||
if($extend_filter) {
|
||||
|
||||
// extend_filter가 있을 경우 캐시 사용을 못하도록 js 캐시 파일명을 변경
|
||||
$this->js_file .= '.nocache.js';
|
||||
|
||||
// extend_filter는 module.method 로 지칭되어 이를 분리
|
||||
list($module_name, $method) = explode('.',$extend_filter);
|
||||
|
||||
// 모듈 이름과 method가 있을 경우 진행
|
||||
if($module_name&&$method) {
|
||||
// 해당 module의 model 객체를 받음
|
||||
$oExtendFilter = &getModel($module_name);
|
||||
|
||||
// method가 존재하면 실행
|
||||
if(method_exists($oExtendFilter, $method)) {
|
||||
// 결과를 받음
|
||||
//$extend_filter_list = call_user_method($method, $oExtendFilter, true);
|
||||
//$extend_filter_list = call_user_func(array($oExtendFilter, $method));
|
||||
$extend_filter_list = $oExtendFilter->{$method}(true);
|
||||
$extend_filter_count = count($extend_filter_list);
|
||||
|
||||
// 결과에서 lang값을 이용 문서 변수에 적용
|
||||
for($i=0;$i<$extend_filter_count;$i++) {
|
||||
$name = $extend_filter_list[$i]->name;
|
||||
$lang_value = $extend_filter_list[$i]->lang;
|
||||
if($lang_value) $lang->{$name} = $lang_value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$callback_func = $xml_obj->filter->response->attrs->callback_func;
|
||||
if(!$callback_func) $callback_func = "filterAlertMessage";
|
||||
|
||||
// 언어 입력을 위한 사용되는 필드 조사
|
||||
$target_list = array();
|
||||
$target_type_list = array();
|
||||
|
||||
// js function 을 만들기 시작
|
||||
$js_doc = sprintf("function %s(fo_obj) {\n", $filter_name);
|
||||
$js_doc .= sprintf("\tvar oFilter = new XmlJsFilter(fo_obj, \"%s\", \"%s\", %s);\n", $module, $act, $callback_func);
|
||||
|
||||
// field, 즉 체크항목의 script 생성
|
||||
$node_count = count($field_node);
|
||||
if($node_count) {
|
||||
foreach($field_node as $key =>$node) {
|
||||
$attrs = $node->attrs;
|
||||
$target = trim($attrs->target);
|
||||
if(!$target) continue;
|
||||
$required = $attrs->required=='true'?'true':'false';
|
||||
$minlength = $attrs->minlength>0?$attrs->minlength:'0';
|
||||
$maxlength = $attrs->maxlength>0?$attrs->maxlength:'0';
|
||||
$equalto = trim($attrs->equalto);
|
||||
$filter = $attrs->filter;
|
||||
|
||||
$js_doc .= sprintf(
|
||||
"\toFilter.addFieldItem(\"%s\",%s,%s,%s,\"%s\",\"%s\");\n",
|
||||
$target, $required, $minlength, $maxlength, $equalto, $filter
|
||||
);
|
||||
|
||||
if(!in_array($target, $target_list)) $target_list[] = $target;
|
||||
if(!$target_type_list[$target]) $target_type_list[$target] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
// extend_filter_item 체크
|
||||
for($i=0;$i<$extend_filter_count;$i++) {
|
||||
$filter_item = $extend_filter_list[$i];
|
||||
$target = trim($filter_item->name);
|
||||
if(!$target) continue;
|
||||
$type = $filter_item->type;
|
||||
$required = $filter_item->required?'true':'false';
|
||||
|
||||
// extend filter item의 type으로 filter를 구함
|
||||
switch($type) {
|
||||
case 'homepage' :
|
||||
$filter = 'homepage';
|
||||
break;
|
||||
case 'email_address' :
|
||||
$filter = 'email';
|
||||
break;
|
||||
default :
|
||||
$filter = '';
|
||||
break;
|
||||
}
|
||||
|
||||
$js_doc .= sprintf(
|
||||
"\toFilter.addFieldItem(\"%s\",%s,%s,%s,\"%s\",\"%s\");\n",
|
||||
$target, $required, 0, 0, '', $filter
|
||||
);
|
||||
|
||||
if(!in_array($target, $target_list)) $target_list[] = $target;
|
||||
if(!$target_type_list[$target]) $target_type_list[$target] = $type;
|
||||
|
||||
}
|
||||
|
||||
// 데이터를 만들기 위한 parameter script 생성
|
||||
$parameter_count = count($parameter_param);
|
||||
if($parameter_count) {
|
||||
// 기본 필터 내용의 parameter로 구성
|
||||
foreach($parameter_param as $key =>$param) {
|
||||
$attrs = $param->attrs;
|
||||
$name = trim($attrs->name);
|
||||
$target = trim($attrs->target);
|
||||
if(!$name || !$target) continue;
|
||||
$target = htmlentities($target,ENT_QUOTES);
|
||||
|
||||
$js_doc .= sprintf(
|
||||
"\toFilter.addParameterItem(\"%s\",\"%s\");\n",
|
||||
$name, $target
|
||||
);
|
||||
if(!in_array($name, $target_list)) $target_list[] = $name;
|
||||
}
|
||||
|
||||
// extend_filter_item 체크
|
||||
for($i=0;$i<$extend_filter_count;$i++) {
|
||||
$filter_item = $extend_filter_list[$i];
|
||||
$target = $name = trim($filter_item->name);
|
||||
if(!$name || !$target) continue;
|
||||
$target = htmlentities($target,ENT_QUOTES);
|
||||
|
||||
$js_doc .= sprintf(
|
||||
"\toFilter.addParameterItem(\"%s\",\"%s\");\n",
|
||||
$name, $target
|
||||
);
|
||||
if(!in_array($name, $target_list)) $target_list[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
// response script 생성
|
||||
$response_count = count($response_tag);
|
||||
for($i=0;$i<$response_count;$i++) {
|
||||
$attrs = $response_tag[$i]->attrs;
|
||||
$name = $attrs->name;
|
||||
$js_doc .= sprintf("\toFilter.addResponseItem(\"%s\");\n", $name);
|
||||
}
|
||||
|
||||
if($confirm_msg_code) $js_doc .= sprintf("\treturn oFilter.proc(\"%s\");\n",str_replace('"','\"',$lang->{$confirm_msg_code}));
|
||||
else $js_doc .= sprintf("\treturn oFilter.proc();\n");
|
||||
$js_doc .= "}\n";
|
||||
|
||||
// form 필드 lang 값을 기록
|
||||
$target_count = count($target_list);
|
||||
for($i=0;$i<$target_count;$i++) {
|
||||
$target = $target_list[$i];
|
||||
if(!$lang->{$target}) $lang->{$target} = $target;
|
||||
$js_doc .= sprintf("alertMsg[\"%s\"] = \"%s\";\n", $target, str_replace("\"","\\\"",$lang->{$target}));
|
||||
}
|
||||
|
||||
// target type을 기록
|
||||
$target_type_count = count($target_type_list);
|
||||
if($target_type_count) {
|
||||
foreach($target_type_list as $target => $type) {
|
||||
$js_doc .= sprintf("target_type_list[\"%s\"] = \"%s\";\n", $target, $type);
|
||||
}
|
||||
}
|
||||
|
||||
// 에러 메세지를 기록
|
||||
foreach($lang->filter as $key => $val) {
|
||||
if(!$val) $val = $key;
|
||||
$js_doc .= sprintf("alertMsg[\"%s\"] = \"%s\";\n", $key, str_replace("\"","\\\"",$val));
|
||||
}
|
||||
|
||||
// js파일 생성
|
||||
FileHandler::writeFile($this->js_file, $js_doc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief $xml_file로 compiled_xml_file이름을 return
|
||||
**/
|
||||
function _getCompiledFileName($xml_file) {
|
||||
return sprintf('%s%s.%s.compiled.js',$this->compiled_path, md5($xml_file),Context::getLangType());
|
||||
}
|
||||
}
|
||||
?>
|
||||
134
classes/xml/XmlParser.class.php
Normal file
134
classes/xml/XmlParser.class.php
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
<?php
|
||||
/**
|
||||
* @class XmlParser
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief xmlrpc를 해석하여 object로 return 하는 simple xml parser
|
||||
* @version 0.1
|
||||
*
|
||||
* xml 데이터의 attribute중에 xml:lang="ko,en,ch,jp,..." 이 있을 경우 지정된 lang 값에 해당하는 것만 남기는 트릭이 적용됨.
|
||||
* 무슨 문제를 일으킬지는 현재 모르나 잘 동작하고 있음
|
||||
**/
|
||||
|
||||
class XmlParser {
|
||||
|
||||
var $oParser = NULL; ///< xml parser
|
||||
|
||||
var $input = NULL; ///< input xml
|
||||
var $output = array(); ///< output object
|
||||
|
||||
var $lang = "en"; ///< 기본 언어타입
|
||||
|
||||
/**
|
||||
* @brief xml 파일을 로딩하여 parsing 처리 후 return
|
||||
**/
|
||||
function loadXmlFile($filename) {
|
||||
if(!file_exists($filename)) return;
|
||||
$buff = FileHandler::readFile($filename);
|
||||
|
||||
$oXmlParser = new XmlParser();
|
||||
return $oXmlParser->parse($buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief xml 파싱
|
||||
**/
|
||||
function parse($input = '') {
|
||||
// 디버그를 위한 컴파일 시작 시간 저장
|
||||
if(__DEBUG__==3) $start = getMicroTime();
|
||||
|
||||
$this->lang = Context::getLangType();
|
||||
|
||||
$this->input = $input?$input:$GLOBALS['HTTP_RAW_POST_DATA'];
|
||||
|
||||
// 지원언어 종류를 뽑음
|
||||
preg_match_all("/xml:lang=\"([^\"].+)\"/i", $this->input, $matches);
|
||||
|
||||
// xml:lang이 쓰였을 경우 지원하는 언어종류를 뽑음
|
||||
if(count($matches[1]) && $supported_lang = array_unique($matches[1])) {
|
||||
// supported_lang에 현재 접속자의 lang이 없으면 en이 있는지 확인하여 en이 있으면 en을 기본, 아니면 첫번째것을..
|
||||
if(!in_array($this->lang, $supported_lang)) {
|
||||
if(in_array('en', $supported_lang)) {
|
||||
$this->lang = 'en';
|
||||
} else {
|
||||
$this->lang = array_shift($supported_lang);
|
||||
}
|
||||
}
|
||||
// 특별한 언어가 지정되지 않았다면 언어체크를 하지 않음
|
||||
} else {
|
||||
unset($this->lang);
|
||||
}
|
||||
|
||||
$this->oParser = xml_parser_create();
|
||||
|
||||
xml_set_object($this->oParser, $this);
|
||||
xml_set_element_handler($this->oParser, "_tagOpen", "_tagClosed");
|
||||
xml_set_character_data_handler($this->oParser, "_tagBody");
|
||||
|
||||
xml_parse($this->oParser, $this->input);
|
||||
xml_parser_free($this->oParser);
|
||||
|
||||
if(!count($this->output)) return;
|
||||
|
||||
$output = array_shift($this->output);
|
||||
|
||||
// 디버그를 위한 컴파일 시작 시간 저장
|
||||
if(__DEBUG__==3) $GLOBALS['__xmlparse_elapsed__'] += getMicroTime() - $start;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 태그 오픈
|
||||
**/
|
||||
function _tagOpen($parser, $node_name, $attrs) {
|
||||
$obj->node_name = strtolower($node_name);
|
||||
$obj->attrs = $this->_arrToObj($attrs);
|
||||
|
||||
array_push($this->output, $obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief body 내용
|
||||
**/
|
||||
function _tagBody($parser, $body) {
|
||||
if(!trim($body)) return;
|
||||
$this->output[count($this->output)-1]->body .= $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 태그 닫음
|
||||
**/
|
||||
function _tagClosed($parser, $node_name) {
|
||||
$node_name = strtolower($node_name);
|
||||
$cur_obj = array_pop($this->output);
|
||||
$parent_obj = &$this->output[count($this->output)-1];
|
||||
if($this->lang&&$cur_obj->attrs->{'xml:lang'}&&$cur_obj->attrs->{'xml:lang'}!=$this->lang) return;
|
||||
if($this->lang&&$parent_obj->{$node_name}->attrs->{'xml:lang'}&&$parent_obj->{$node_name}->attrs->{'xml:lang'}!=$this->lang) return;
|
||||
|
||||
if($parent_obj->{$node_name}) {
|
||||
$tmp_obj = $parent_obj->{$node_name};
|
||||
if(is_array($tmp_obj)) {
|
||||
array_push($parent_obj->{$node_name}, $cur_obj);
|
||||
} else {
|
||||
$parent_obj->{$node_name} = array();
|
||||
array_push($parent_obj->{$node_name}, $tmp_obj);
|
||||
array_push($parent_obj->{$node_name}, $cur_obj);
|
||||
}
|
||||
} else {
|
||||
$parent_obj->{$node_name} = $cur_obj;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 파싱한 결과를 object vars에 담기 위한 method
|
||||
**/
|
||||
function _arrToObj($arr) {
|
||||
if(!count($arr)) return;
|
||||
foreach($arr as $key => $val) {
|
||||
$key = strtolower($key);
|
||||
$output->{$key} = $val;
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
?>
|
||||
337
classes/xml/XmlQueryParser.class.php
Normal file
337
classes/xml/XmlQueryParser.class.php
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
<?php
|
||||
/**
|
||||
* @class XmlQueryParser
|
||||
* @author zero (zero@nzeo.com)
|
||||
* @brief query xml을 파싱하여 캐싱을 한 후 결과를 return
|
||||
* @version 0.1
|
||||
*
|
||||
* @todo subquery나 union등의 확장 쿼리에 대한 지원이 필요
|
||||
**/
|
||||
|
||||
class XmlQueryParser extends XmlParser {
|
||||
|
||||
/**
|
||||
* @brief 쿼리 파일을 찾아서 파싱하고 캐싱한다
|
||||
**/
|
||||
function parse($query_id, $xml_file, $cache_file) {
|
||||
// query xml 파일을 찾아서 파싱, 결과가 없으면 return
|
||||
$buff = FileHandler::readFile($xml_file);
|
||||
$xml_obj = parent::parse($buff);
|
||||
if(!$xml_obj) return;
|
||||
unset($buff);
|
||||
|
||||
list($module, $id) = explode('.',$query_id);
|
||||
|
||||
// insert, update, delete, select등의 action
|
||||
$action = strtolower($xml_obj->query->attrs->action);
|
||||
if(!$action) return;
|
||||
|
||||
// 테이블 정리 (배열코드로 변환)
|
||||
$tables = $xml_obj->query->tables->table;
|
||||
if(!$tables) return;
|
||||
if(!is_array($tables)) $tables = array($tables);
|
||||
foreach($tables as $key => $val) {
|
||||
// 테이블과 alias의 이름을 구함
|
||||
$table_name = $val->attrs->name;
|
||||
$alias = $val->attrs->alias;
|
||||
if(!$alias) $alias = $table_name;
|
||||
|
||||
$output->tables[$table_name] = $alias;
|
||||
|
||||
// 테이블을 찾아서 컬럼의 속성을 구함
|
||||
$table_file = sprintf('./modules/%s/schemas/%s.xml', $module, $table_name);
|
||||
if(!file_exists($table_file)) {
|
||||
$searched_list = FileHandler::readDir('./modules');
|
||||
$searched_count = count($searched_list);
|
||||
for($i=0;$i<$searched_count;$i++) {
|
||||
$table_file = sprintf('./modules/%s/schemas/%s.xml', $searched_list[$i], $table_name);
|
||||
if(file_exists($table_file)) break;
|
||||
}
|
||||
}
|
||||
|
||||
if(file_exists($table_file)) {
|
||||
$table_xml = FileHandler::readFile($table_file);
|
||||
$table_obj = parent::parse($table_xml);
|
||||
if($table_obj->table) {
|
||||
foreach($table_obj->table->column as $k => $v) {
|
||||
$buff .= sprintf('$output->column_type["%s"] = "%s";%s', $v->attrs->name, $v->attrs->type, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 컬럼 정리
|
||||
$columns = $xml_obj->query->columns->column;
|
||||
if(!$columns) {
|
||||
$output->column[] = array("*" => "*");
|
||||
} else {
|
||||
if(!is_array($columns)) $columns = array($columns);
|
||||
foreach($columns as $key => $val) {
|
||||
$name = $val->attrs->name;
|
||||
/*
|
||||
if(strpos('.',$name)===false && count($output->tables)==1) {
|
||||
$tmp = array_values($output->tables);
|
||||
$name = sprintf('%s.%s', $tmp[0], $val->attrs->name);
|
||||
}
|
||||
*/
|
||||
|
||||
$output->columns[] = array(
|
||||
"name" => $name,
|
||||
"var" => $val->attrs->var,
|
||||
"default" => $val->attrs->default,
|
||||
"notnull" => $val->attrs->notnull,
|
||||
"filter" => $val->attrs->filter,
|
||||
"minlength" => $val->attrs->minlength,
|
||||
"maxlength" => $val->attrs->maxlength,
|
||||
"alias" => $val->attrs->alias,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 조건절 정리
|
||||
$conditions = $xml_obj->query->conditions;
|
||||
|
||||
$condition = $conditions->condition;
|
||||
if($condition) {
|
||||
$obj->condition = $condition;
|
||||
unset($condition);
|
||||
$condition = array($obj);
|
||||
}
|
||||
|
||||
$condition_group = $conditions->group;
|
||||
if($condition_group && !is_array($condition_group)) $condition_group = array($condition_group);
|
||||
|
||||
if($condition && $condition_group) $cond = array_merge($condition, $condition_group);
|
||||
elseif($condition_group) $cond = $condition_group;
|
||||
else $cond = $condition;
|
||||
|
||||
if($cond) {
|
||||
foreach($cond as $key => $val) {
|
||||
unset($cond_output);
|
||||
|
||||
if($val->attrs->pipe) $cond_output->pipe = $val->attrs->pipe;
|
||||
else $cond_output->pipe = null;
|
||||
|
||||
if(!$val->condition) continue;
|
||||
if(!is_array($val->condition)) $val->condition = array($val->condition);
|
||||
|
||||
foreach($val->condition as $k => $v) {
|
||||
$obj = $v->attrs;
|
||||
if(!$obj->alias) $obj->alias = $obj->column;
|
||||
$cond_output->condition[] = $obj;
|
||||
}
|
||||
|
||||
$output->conditions[] = $cond_output;
|
||||
}
|
||||
}
|
||||
|
||||
// group 정리
|
||||
$group_list = $xml_obj->query->groups->group;
|
||||
if($group_list) {
|
||||
if(!is_array($group_list)) $group_list = array($group_list);
|
||||
for($i=0;$i<count($group_list);$i++) {
|
||||
$group = $group_list[$i];
|
||||
$column = trim($group->attrs->column);
|
||||
if(!$column) continue;
|
||||
$group_column_list[] = $column;
|
||||
}
|
||||
if(count($group_column_list)) $output->groups = $group_column_list;
|
||||
}
|
||||
|
||||
// 네비게이션 정리
|
||||
$navigation = $xml_obj->query->navigation;
|
||||
if($navigation) {
|
||||
$order = $navigation->index;
|
||||
if($order) {
|
||||
if(!is_array($order)) $order = array($order);
|
||||
foreach($order as $order_info) {
|
||||
$output->order[] = $order_info->attrs;
|
||||
}
|
||||
}
|
||||
|
||||
$list_count = $navigation->list_count->attrs;
|
||||
$output->list_count = $list_count;
|
||||
|
||||
$page_count = $navigation->page_count->attrs;
|
||||
$output->page_count = $page_count;
|
||||
|
||||
$page = $navigation->page->attrs;
|
||||
$output->page = $page ;
|
||||
}
|
||||
|
||||
$column_count = count($output->columns);
|
||||
$condition_count = count($output->conditions);
|
||||
|
||||
// php script 생성
|
||||
|
||||
// table 정리
|
||||
$buff .= '$output->tables = array( ';
|
||||
foreach($output->tables as $key => $val) {
|
||||
$buff .= sprintf('"%s"=>"%s",', $key, $val);
|
||||
}
|
||||
$buff .= ' );'."\n";
|
||||
|
||||
// column 정리
|
||||
if($column_count) {
|
||||
$buff .= '$output->columns = array ( ';
|
||||
foreach($output->columns as $key => $val) {
|
||||
$val['default'] = $this->getDefault($val['name'], $val['default']);
|
||||
if($val['var'] && strpos($val['var'],'.')===false) {
|
||||
|
||||
if($val['default']) $buff .= sprintf('array("name"=>"%s", "alias"=>"%s", "value"=>$args->%s?$args->%s:%s),%s', $val['name'], $val['alias'], $val['var'], $val['var'], $val['default'] ,"\n");
|
||||
else $buff .= sprintf('array("name"=>"%s", "alias"=>"%s", "value"=>$args->%s),%s', $val['name'], $val['alias'], $val['var'], "\n");
|
||||
|
||||
if($val['default']) $default_list[$val['var']] = $val['default'];
|
||||
if($val['notnull']) $notnull_list[] = $val['var'];
|
||||
if($val['minlength']) $minlength_list[$val['var']] = $val['minlength'];
|
||||
if($val['maxlength']) $maxlength_list[$val['var']] = $val['maxlength'];
|
||||
} else {
|
||||
if($val['default']) $buff .= sprintf('array("name"=>"%s", "alias"=>"%s", "value"=>%s),%s', $val['name'], $val['alias'], $val['default'] ,"\n");
|
||||
else $buff .= sprintf('array("name"=>"%s", "alias"=>"%s",),%s', $val['name'], $val['alias'], "\n");
|
||||
}
|
||||
}
|
||||
$buff .= ' );'."\n";
|
||||
}
|
||||
|
||||
// conditions 정리
|
||||
if($condition_count) {
|
||||
$buff .= '$output->conditions = array ( ';
|
||||
foreach($output->conditions as $key => $val) {
|
||||
$buff .= sprintf('array("pipe"=>"%s",%s"condition"=>array(', $val->pipe,"\n");
|
||||
foreach($val->condition as $k => $v) {
|
||||
$v->default = $this->getDefault($v->column, $v->default);
|
||||
if($v->var) {
|
||||
if(strpos($v->var,".")===false) {
|
||||
if($v->default) $default_list[$v->var] = $v->default;
|
||||
if($v->filter) $filter_list[] = $v;
|
||||
if($v->default) $buff .= sprintf('array("column"=>"%s", "value"=>$args->%s?$args->%s:%s,"pipe"=>"%s","operation"=>"%s",),%s', $v->column, $v->var, $v->var, $v->default, $v->pipe, $v->operation, "\n");
|
||||
else $buff .= sprintf('array("column"=>"%s", "value"=>$args->%s,"pipe"=>"%s","operation"=>"%s",),%s', $v->column, $v->var, $v->pipe, $v->operation, "\n");
|
||||
} else {
|
||||
$buff .= sprintf('array("column"=>"%s", "value"=>"%s","pipe"=>"%s","operation"=>"%s",),%s', $v->column, $v->var, $v->pipe, $v->operation, "\n");
|
||||
}
|
||||
} else {
|
||||
if($v->default) $buff .= sprintf('array("column"=>"%s", "value"=>%s,"pipe"=>"%s","operation"=>"%s",),%s', $v->column, $v->default ,$v->pipe, $v->operation,"\n");
|
||||
else $buff .= sprintf('array("column"=>"%s", "pipe"=>"%s","operation"=>"%s",),%s', $v->column, $v->pipe, $v->operation,"\n");
|
||||
}
|
||||
}
|
||||
$buff .= ')),'."\n";
|
||||
}
|
||||
|
||||
$buff .= ' );'."\n";
|
||||
}
|
||||
|
||||
// order 정리
|
||||
if($output->order) {
|
||||
$buff .= '$output->order = array(';
|
||||
foreach($output->order as $key => $val) {
|
||||
$buff .= sprintf('array($args->%s?$args->%s:"%s",in_array($args->%s,array("asc","desc"))?$args->%s:("%s"?"%s":"asc")),', $val->var, $val->var, $val->default, $val->order, $val->order, $val->order, $val->order);
|
||||
}
|
||||
$buff .= ');'."\n";
|
||||
}
|
||||
|
||||
// list_count 정리
|
||||
if($output->list_count) {
|
||||
$buff .= sprintf('$output->list_count = array("var"=>"%s", "value"=>$args->%s?$args->%s:"%s");%s', $output->list_count->var, $output->list_count->var, $output->list_count->var, $output->list_count->default,"\n");
|
||||
}
|
||||
|
||||
// page_count 정리
|
||||
if($output->page_count) {
|
||||
$buff .= sprintf('$output->page_count = array("var"=>"%s", "value"=>$args->%s?$args->%s:"%s");%s', $output->page_count->var, $output->page_count->var, $output->page_count->var, $output->list_count->default,"\n");
|
||||
}
|
||||
|
||||
// page 정리
|
||||
if($output->page) {
|
||||
$buff .= sprintf('$output->page = array("var"=>"%s", "value"=>$args->%s?$args->%s:"%s");%s', $output->page->var, $output->page->var, $output->page->var, $output->list->default,"\n");
|
||||
}
|
||||
|
||||
// group by 정리
|
||||
if($output->groups) {
|
||||
$buff .= sprintf('$output->groups = array("%s");%s', implode('","',$output->groups),"\n");
|
||||
}
|
||||
|
||||
// default check
|
||||
if(count($default_list)) {
|
||||
foreach($default_list as $key => $val) {
|
||||
$pre_buff .= 'if(!isset($args->'.$key.')) $args->'.$key.' = '.$val.';'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
// not null check
|
||||
if(count($notnull_list)) {
|
||||
foreach($notnull_list as $key => $val) {
|
||||
$pre_buff .= 'if(!isset($args->'.$val.')) return new Object(-1, sprintf($lang->filter->isnull, $lang->'.$val.'?$lang->'.$val.':\''.$val.'\'));'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
// minlength check
|
||||
if(count($minlength_list)) {
|
||||
foreach($minlength_list as $key => $val) {
|
||||
$pre_buff .= 'if($args->'.$key.'&&strlen($args->'.$key.')<'.$val.') return new Object(-1, sprintf($lang->filter->outofrange, $lang->'.$key.'?$lang->'.$key.':\''.$key.'\'));'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
// maxlength check
|
||||
if(count($maxlength_list)) {
|
||||
foreach($maxlength_list as $key => $val) {
|
||||
$pre_buff .= 'if($args->'.$key.'&&strlen($args->'.$key.')>'.$val.') return new Object(-1, sprintf($lang->filter->outofrange, $lang->'.$key.'?$lang->'.$key.':\''.$key.'\'));'."\n";
|
||||
}
|
||||
}
|
||||
|
||||
// filter check
|
||||
if(count($filter_list)) {
|
||||
foreach($filter_list as $key => $val) {
|
||||
if(!$notnull_list[$key]) continue;
|
||||
$pre_buff .= sprintf('unset($_output); $_output = $this->checkFilter("%s",$args->%s,"%s"); if(!$_output->toBool()) return $_output;%s',$val->var,$val->var,$val->filter,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
$buff = "<?php if(!defined('__ZBXE__')) exit();\n"
|
||||
. sprintf('$output->query_id = "%s";%s', $query_id, "\n")
|
||||
. sprintf('$output->action = "%s";%s', $action, "\n")
|
||||
. $pre_buff
|
||||
. $buff
|
||||
. 'return $output; ?>';
|
||||
|
||||
// 저장
|
||||
FileHandler::writeFile($cache_file, $buff);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief column, condition등의 key에 default 값을 세팅
|
||||
**/
|
||||
function getDefault($name, $value) {
|
||||
if(!$value) return;
|
||||
$str_pos = strpos($value, '(');
|
||||
if($str_pos===false) return '"'.$value.'"';
|
||||
|
||||
$func_name = substr($value, 0, $str_pos);
|
||||
$args = substr($value, $str_pos+1, strlen($value)-1);
|
||||
|
||||
switch($func_name) {
|
||||
case 'ipaddress' :
|
||||
$val = '$_SERVER[\'REMOTE_ADDR\']';
|
||||
break;
|
||||
case 'unixtime' :
|
||||
$val = 'time()';
|
||||
break;
|
||||
case 'curdate' :
|
||||
$val = 'date("YmdHis")';
|
||||
break;
|
||||
case 'sequence' :
|
||||
$val = '$this->getNextSequence()';
|
||||
break;
|
||||
case 'plus' :
|
||||
$args = abs($args);
|
||||
$val = sprintf('"%s+%d"', $name, $args);
|
||||
break;
|
||||
case 'minus' :
|
||||
$args = abs($args);
|
||||
$val = sprintf('"%s-%d"', $name, $args);
|
||||
break;
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
Loading…
Add table
Add a link
Reference in a new issue