From 40326eec5f44653bb506962dcf22a76207c39d96 Mon Sep 17 00:00:00 2001 From: ngleader Date: Mon, 3 Nov 2008 09:32:57 +0000 Subject: [PATCH] =?UTF-8?q?Json=20=EC=A7=80=EC=9B=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://xe-core.googlecode.com/svn/sandbox@4744 201d5d3c-b55e-5fd7-737f-ddc643e51545 --- classes/context/Context.class.php | 33 ++++- classes/display/DisplayHandler.class.php | 30 +++- classes/module/ModuleHandler.class.php | 2 +- classes/module/ModuleObject.class.php | 2 +- common/js/common.js | 17 ++- common/js/xml_handler.js | 175 ++++++++++++++++++++++- config/func.inc.php | 66 ++++++--- 7 files changed, 292 insertions(+), 33 deletions(-) diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index e558b4c92..e4ab631fd 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -108,6 +108,7 @@ // Request Argument 설정 $this->_setXmlRpcArgument(); + $this->_setJSONRequestArgument(); $this->_setRequestArgument(); $this->_setUploadedArgument(); @@ -492,7 +493,7 @@ /** * @brief response method를 강제로 지정 (기본으로는 request method를 이용함) * - * method의 종류에는 HTML/ TEXT/ XMLRPC가 있음 + * method의 종류에는 HTML/ TEXT/ XMLRPC/ JSON가 있음 **/ function setResponseMethod($method = "HTML") { $oContext = &Context::getInstance(); @@ -517,12 +518,14 @@ function _getResponseMethod() { if($this->response_method) return $this->response_method; - if($this->_getRequestMethod()=="XMLRPC") return "XMLRPC"; + $RequestMethod = $this->_getRequestMethod(); + if($RequestMethod=="XMLRPC") return "XMLRPC"; + else if($RequestMethod=="JSON") return "JSON"; return "HTML"; } /** - * @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC) + * @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC/JSON) **/ function setRequestMethod($type) { $oContext = &Context::getInstance(); @@ -531,11 +534,12 @@ /** - * @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC) + * @brief request method가 어떤것인지 판단하여 저장 (GET/POST/XMLRPC/JSON) **/ function _setRequestMethod($type = '') { if($type) return $this->request_method = $type; + if(strpos($_SERVER['CONTENT_TYPE'],'json')) return $this->request_method = 'JSON'; if($GLOBALS['HTTP_RAW_POST_DATA']) return $this->request_method = "XMLRPC"; $this->request_method = $_SERVER['REQUEST_METHOD']; @@ -558,6 +562,22 @@ } } + /** + * @brief JSON 방식일 경우 처리 + **/ + function _setJSONRequestArgument() { + if($this->_getRequestMethod() != 'JSON') return; +// if(!$GLOBALS['HTTP_RAW_POST_DATA']) return; + + $params = array(); + parse_str($GLOBALS['HTTP_RAW_POST_DATA'],$params); + + foreach($params as $key => $val) { + $val = $this->_filterRequestVar($key, $val); + $this->_set($key, $val, true); + } + } + /** * @brief XML RPC일때 **/ @@ -571,7 +591,6 @@ unset($params->attrs); if(!count($params)) return; - foreach($params as $key => $obj) { $val = $this->_filterRequestVar($key, $obj->body); $this->_set($key, $val, true); @@ -629,7 +648,7 @@ } /** - * @brief Request Method값을 return (GET/POST/XMLRPC); + * @brief Request Method값을 return (GET/POST/XMLRPC/JSON); **/ function getRequestMethod() { $oContext = &Context::getInstance(); @@ -637,7 +656,7 @@ } /** - * @brief Request Method값을 return (GET/POST/XMLRPC); + * @brief Request Method값을 return (GET/POST/XMLRPC/JSON); **/ function _getRequestMethod() { return $this->request_method; diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php index d66947cbe..4135bcb0e 100644 --- a/classes/display/DisplayHandler.class.php +++ b/classes/display/DisplayHandler.class.php @@ -26,13 +26,13 @@ // header 출력 $this->_printHeader(); - // request method에 따른 처리 if(Context::getRequestMethod() == 'XMLRPC') $content = $this->_toXmlDoc($oModule); + else if(Context::getRequestMethod() == 'JSON') $content = $this->_toJSON($oModule); else $content = $this->_toHTMLDoc($oModule); // 요청방식에 따라 출력을 별도로 - if(Context::getResponseMethod()!="XMLRPC") { + if(Context::getResponseMethod()=="HTML") { Context::set('content', $content); @@ -93,6 +93,17 @@ else print $content; } + /** + * @brief RequestMethod가 JSON이면 JSON 데이터로 컨텐츠 생성 + **/ + function _toJSON(&$oModule) { + $variables = $oModule->getVariables(); + //if(function_exists('json_encode')) return json_encode($variables); + //else return json_encode2($variables); + return json_encode2($variables); + } + + /** * @brief RequestMethod가 XML이면 XML 데이터로 컨텐츠 생성 **/ @@ -209,7 +220,8 @@ ***/ function _printHeader() { if($this->gz_enabled) header("Content-Encoding: gzip"); - if(Context::getResponseMethod() != 'HTML') return $this->_printXMLHeader(); + if(Context::getResponseMethod() == 'JSON') return $this->_printJSONHeader(); + else if(Context::getResponseMethod() != 'HTML') return $this->_printXMLHeader(); else return $this->_printHTMLHeader(); } @@ -236,5 +248,17 @@ header("Cache-Control: post-check=0, pre-check=0", false); header("Pragma: no-cache"); } + + /** + * @brief JSON header 출력 (utf8 고정) + **/ + function _printJSONHeader() { + 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"); + } } ?> diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 588b0d5a0..f7a2bbc8b 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -188,7 +188,7 @@ } // XMLRPC call 이 아니면 message view 객체 이용하도록 - if(Context::getRequestMethod() != 'XMLRPC') { + if(Context::getRequestMethod() != 'XMLRPC' && Context::getRequestMethod() != 'JSON') { // 에러가 발생하였을시 처리 if($this->error) { // message 모듈 객체를 생성해서 컨텐츠 생성 diff --git a/classes/module/ModuleObject.class.php b/classes/module/ModuleObject.class.php index 876df4aa7..0e4a0593b 100644 --- a/classes/module/ModuleObject.class.php +++ b/classes/module/ModuleObject.class.php @@ -350,7 +350,7 @@ } // view action이고 결과 출력이 XMLRPC일 경우 해당 모듈의 api method를 실행 - if(Context::getResponseMethod() == 'XMLRPC' && $this->module_info->module_type == 'view') { + if((Context::getResponseMethod() == 'XMLRPC' || Context::getResponseMethod() == 'JSON') && $this->module_info->module_type == 'view') { $oAPI = getAPI($this->module_info->module, 'api'); if(method_exists($oAPI, $this->act)) { $oAPI->{$this->act}($this); diff --git a/common/js/common.js b/common/js/common.js index 045dee201..0f820bee7 100644 --- a/common/js/common.js +++ b/common/js/common.js @@ -398,6 +398,7 @@ function chkPopupMenu(evt) { // 이벤트 대상이 없으면 무시 var e = new xEvent(evt); + if(!e) return; // 대상의 객체 구함 @@ -437,14 +438,15 @@ function chkPopupMenu(evt) { // action이름을 규칙에 맞게 작성 var action_name = "get" + module_name.substr(0,1).toUpperCase() + module_name.substr(1,module_name.length-1) + "Menu"; + // 서버에 메뉴를 요청 var params = new Array(); params["target_srl"] = target_srl; params["cur_mid"] = current_mid; params["cur_act"] = current_url.getQuery('act'); params["menu_id"] = menu_id; - params["page_x"] = e.pageX; - params["page_y"] = e.pageY; + params["page_x"] = e.pageX >0 ? e.pageX : GetObjLeft(obj); + params["page_y"] = e.pageY >0 ? e.pageY : GetObjTop(obj)+ xHeight(obj); var response_tags = new Array("error","message","menus"); @@ -458,6 +460,15 @@ function chkPopupMenu(evt) { } +function GetObjTop(obj) { + if(obj.offsetParent == document.body) return xOffsetTop(obj); + else return xOffsetTop(obj) + GetObjTop(obj.offsetParent); +} +function GetObjLeft(obj) { + if(obj.offsetParent == document.body) return xOffsetLeft(obj); + else return xOffsetLeft(obj) + GetObjLeft(obj.offsetParent); +} + function displayPopupMenu(ret_obj, response_tags, params) { var target_srl = params["target_srl"]; @@ -558,7 +569,7 @@ function displayPopupMenu(ret_obj, response_tags, params) { // 레이어 출력 if(html) { var area = xGetElementById("popup_menu_area"); - xInnerHtml(area, ""); + xInnerHtml(area, ''); xLeft(area, params["page_x"]); xTop(area, params["page_y"]); if(xWidth(area)+xLeft(area)>xClientWidth()+xScrollLeft()) xLeft(area, xClientWidth()-xWidth(area)+xScrollLeft()); diff --git a/common/js/xml_handler.js b/common/js/xml_handler.js index d57fa92f3..5f9adf6bf 100644 --- a/common/js/xml_handler.js +++ b/common/js/xml_handler.js @@ -78,7 +78,7 @@ function zGetXmlHttp() { } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); } - } + } return null; } @@ -160,12 +160,20 @@ function xml_handlerGetResponseXML() { return null; } + function xml_parseXmlDoc(dom) { + if(!dom) return; + var jsonStr = xml2json(dom,false,false); + var jsonObj = eval("("+ jsonStr +");"); + return jsonObj.response; +/* + var ret_obj = new Array(); var obj = dom.firstChild; + var preObj; if(!obj) return; while(obj) { @@ -175,11 +183,11 @@ function xml_parseXmlDoc(dom) { var value = null; if(obj.childNodes.length==1 && obj.firstChild.nodeType != 1) { + value = obj.firstChild.nodeValue; } else { value = this.parseXMLDoc(obj); } - if(typeof(ret_obj[name])=='undefined') { ret_obj[name] = value; } else { @@ -195,8 +203,10 @@ function xml_parseXmlDoc(dom) { } obj = obj.nextSibling; + } return ret_obj; +*/ } function xml_handlerToZMsgObject(xmlDoc, tags) { @@ -215,3 +225,164 @@ function xml_handlerToZMsgObject(xmlDoc, tags) { } return obj_ret; } + + + +/* This work is licensed under Creative Commons GNU LGPL License. + + License: http://creativecommons.org/licenses/LGPL/2.1/ + Version: 0.9 + Author: Stefan Goessner/2006 + Web: http://goessner.net/ +*/ +function xml2json(xml, tab, ignoreAttrib) { + var X = { + toObj: function(xml) { + var o = {}; + if (xml.nodeType==1) { // element node .. + if (ignoreAttrib && xml.attributes.length) // element with attributes .. + for (var i=0; i 1) + o = X.escape(X.innerXml(xml)); + else + for (var n=xml.firstChild; n; n=n.nextSibling){ + //o["#cdata"] = X.escape(n.nodeValue); + o = X.escape(n.nodeValue); + } + } + } + if (!xml.attributes.length && !xml.firstChild) o = null; + } + else if (xml.nodeType==9) { // document.node + o = X.toObj(xml.documentElement); + } + else + alert("unhandled node type: " + xml.nodeType); + return o; + }, + toJson: function(o, name, ind) { + var json = name ? ("\""+name+"\"") : ""; + if (o instanceof Array) { + for (var i=0,n=o.length; i 1 ? ("\n"+ind+"\t"+o.join(",\n"+ind+"\t")+"\n"+ind) : o.join("")) + "]"; + } + else if (o == null) + json += (name&&":") + "null"; + else if (typeof(o) == "object") { + var arr = []; + for (var m in o) + arr[arr.length] = X.toJson(o[m], m, ind+"\t"); + json += (name?":{":"{") + (arr.length > 1 ? ("\n"+ind+"\t"+arr.join(",\n"+ind+"\t")+"\n"+ind) : arr.join("")) + "}"; + } + else if (typeof(o) == "string") + json += (name&&":") + "\"" + o.toString() + "\""; + else + json += (name&&":") + o.toString(); + return json; + }, + innerXml: function(node) { + var s = "" + if ("innerHTML" in node) + s = node.innerHTML; + else { + var asXml = function(n) { + var s = ""; + if (n.nodeType == 1) { + s += "<" + n.nodeName; + for (var i=0; i"; + } + else + s += "/>"; + } + else if (n.nodeType == 3) + s += n.nodeValue; + else if (n.nodeType == 4) + s += ""; + return s; + }; + for (var c=node.firstChild; c; c=c.nextSibling) + s += asXml(c); + } + return s; + }, + escape: function(txt) { + return txt.replace(/[\\]/g, "\\\\") + .replace(/[\"]/g, '\\"') + .replace(/[\n]/g, '\\n') + .replace(/[\r]/g, '\\r'); + }, + removeWhite: function(e) { + e.normalize(); + for (var n = e.firstChild; n; ) { + if (n.nodeType == 3) { // text node + if (!n.nodeValue.match(/[^ \f\n\r\t\v]/)) { // pure whitespace text node + var nxt = n.nextSibling; + e.removeChild(n); + n = nxt; + } + else + n = n.nextSibling; + } + else if (n.nodeType == 1) { // element node + X.removeWhite(n); + n = n.nextSibling; + } + else // any other node + n = n.nextSibling; + } + return e; + } + }; + if (xml.nodeType == 9) // document node + xml = xml.documentElement; + var json = X.toJson(X.toObj(X.removeWhite(xml)), xml.nodeName, ""); + return "{" + (tab ? json.replace(/\t/g, tab) : json.replace(/\t|\n/g, "")) + "}"; +} diff --git a/config/func.inc.php b/config/func.inc.php index e4001a3a2..52c50c690 100644 --- a/config/func.inc.php +++ b/config/func.inc.php @@ -29,7 +29,7 @@ '); } - + // time zone $time_zone = array( '-1200' => '[GMT -12:00] Baker Island Time', @@ -90,7 +90,7 @@ * @return module controller instance **/ function &getController($module_name) { - return getModule($module_name, 'controller'); + return getModule($module_name, 'controller'); } /** @@ -99,7 +99,7 @@ * @return module admin controller instance **/ function &getAdminController($module_name) { - return getModule($module_name, 'controller','admin'); + return getModule($module_name, 'controller','admin'); } /** @@ -108,7 +108,7 @@ * @return module view instance **/ function &getView($module_name) { - return getModule($module_name, 'view'); + return getModule($module_name, 'view'); } /** @@ -117,7 +117,7 @@ * @return module admin view instance **/ function &getAdminView($module_name) { - return getModule($module_name, 'view','admin'); + return getModule($module_name, 'view','admin'); } /** @@ -126,7 +126,7 @@ * @return module model instance **/ function &getModel($module_name) { - return getModule($module_name, 'model'); + return getModule($module_name, 'model'); } /** @@ -135,7 +135,7 @@ * @return module admin model instance **/ function &getAdminModel($module_name) { - return getModule($module_name, 'model','admin'); + return getModule($module_name, 'model','admin'); } /** @@ -144,7 +144,7 @@ * @return module api class instance **/ function &getAPI($module_name) { - return getModule($module_name, 'api'); + return getModule($module_name, 'api'); } /** @@ -153,7 +153,7 @@ * @return module class instance **/ function &getClass($module_name) { - return getModule($module_name, 'class'); + return getModule($module_name, 'class'); } /** @@ -217,7 +217,7 @@ * @param tail 잘라졌을 경우 문자열의 제일 뒤에 붙을 꼬리 * @return string **/ - function cut_str($string,$cut_size=0,$tail = '...') { + function cut_str($string,$cut_size=0,$tail = '...') { if($cut_size<1 || !$string) return $string; $chars = Array(12, 4, 3, 5, 7, 7, 11, 8, 4, 5, 5, 6, 6, 4, 6, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 4, 4, 8, 6, 8, 6, 10, 8, 8, 9, 8, 8, 7, 9, 8, 3, 6, 7, 7, 11, 8, 9, 8, 9, 8, 8, 7, 8, 8, 10, 8, 8, 8, 6, 11, 6, 6, 6, 4, 7, 7, 7, 7, 7, 3, 7, 7, 3, 3, 6, 3, 9, 7, 7, 7, 7, 4, 7, 3, 7, 6, 10, 6, 6, 7, 6, 6, 6, 9); @@ -389,7 +389,7 @@ return (float)$time1 + (float)$time2; } - /** + /** * @brief 첫번째 인자로 오는 object var에서 2번째 object의 var들을 제거 * @param target_obj 원 object * @param del_obj 원 object의 vars에서 del_obj의 vars를 제거한다 @@ -417,9 +417,9 @@ return $return_obj; } - /** + /** * @brief php5 이상에서 error_handing을 debugPrint로 변경 - * @param errno + * @param errno * @param errstr * @return file * @return line @@ -537,7 +537,7 @@ 'green' => 0xFF & ($int >> 0x8), 'blue' => 0xFF & $int); } - + } /** @@ -577,9 +577,9 @@ return $url; } - /** + /** * javascript의 escape의 php unescape 함수 - * Function converts an Javascript escaped string back into a string with specified charset (default is UTF-8). + * Function converts an Javascript escaped string back into a string with specified charset (default is UTF-8). * Modified function from http://pure-essence.net/stuff/code/utf8RawUrlDecode.phps **/ function utf8RawUrlDecode ($source) { @@ -620,4 +620,38 @@ if($num<2097152)return chr(($num>>18)+240).chr((($num>>12)&63)+128).chr((($num>>6)&63)+128) .chr(($num&63)+128); return ''; } + + + function json_encode2($data) { + switch (gettype($data)) { + case 'boolean': + return $data?'true':'false'; + case 'integer': + case 'double': + return $data; + case 'string': + return '"'.strtr($data, array('\\'=>'\\\\','"'=>'\\"')).'"'; + case 'object': + $data = get_object_vars($data); + case 'array': + $rel = false; // relative array? + $key = array_keys($data); + foreach ($key as $v) { + if (!is_int($v)) { + $rel = true; + break; + } + } + + $arr = array(); + foreach ($data as $k=>$v) { + $arr[] = ($rel?'"'.strtr($k, array('\\'=>'\\\\','"'=>'\\"')).'":':'').json_encode2($v); + } + + return $rel?'{'.join(',', $arr).'}':'['.join(',', $arr).']'; + default: + return '""'; + } + } + ?>