diff --git a/.htaccess b/.htaccess index 89ecf951f..43536f5e9 100644 --- a/.htaccess +++ b/.htaccess @@ -15,37 +15,7 @@ RewriteRule ^(.+)/files/(member_extra_info|attach|cache|faceOff)/(.*) ./files/$2 RewriteCond %{SCRIPT_FILENAME} !-f RewriteRule ^(.+)/(files|modules|widgets|widgetstyles|layouts|m.layouts|addons)/(.*) ./$2/$3 [L] -# rss , blogAPI -RewriteRule ^(rss|atom)$ ./index.php?module=rss&act=$1 [L] -RewriteRule ^([a-zA-Z0-9_]+)/(rss|atom|api)$ ./index.php?mid=$1&act=$2 [L] -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/(rss|atom|api)$ ./index.php?vid=$1&mid=$2&act=$3 [L] - -# trackback -RewriteRule ^([0-9]+)/(.+)/trackback$ ./index.php?document_srl=$1&key=$2&act=trackback [L] -RewriteRule ^([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?mid=$1&document_srl=$2&key=$3&act=trackback [L] -RewriteRule ^([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?vid=$1&document_srl=$2&key=$3&act=trackback [L] -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback$ ./index.php?vid=$1&mid=$2&document_srl=$3&key=$4&act=trackback [L] - -# document permanent link -RewriteRule ^([0-9]+)$ ./index.php?document_srl=$1 [L,QSA] - -# mid link -RewriteCond %{SCRIPT_FILENAME} !-d -RewriteRule ^([a-zA-Z0-9_]+)/?$ ./index.php?mid=$1 [L,QSA] -# mid + document link -RewriteRule ^([a-zA-Z0-9_]+)/([0-9]+)$ ./index.php?mid=$1&document_srl=$2 [L,QSA] - -# vid + mid link -RewriteCond %{SCRIPT_FILENAME} !-d -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/?$ ./index.php?vid=$1&mid=$2 [L,QSA] -# vid + mid + document link -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([0-9]+)$ ./index.php?vid=$1&mid=$2&document_srl=$3 [L,QSA] - -# mid + entry title -RewriteRule ^([a-zA-Z0-9_]+)/entry/(.+)$ ./index.php?mid=$1&entry=$2 [L,QSA] -# vid + mid + entry title -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/entry/(.+)$ ./index.php?vid=$1&mid=$2&entry=$3 [L,QSA] - -#shop / vid / [category|product] / identifier +# router RewriteCond %{SCRIPT_FILENAME} !-f -RewriteRule ^([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([a-zA-Z0-9_\.-]+)$ ./index.php?act=route&vid=$1&type=$2&identifier=$3 [L,QSA] +RewriteCond %{SCRIPT_FILENAME} !-d +RewriteRule ^(.*)$ ./index.php [L] diff --git a/README.md b/README.md index 2d9cf86ba..977e48730 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ XpressEngine(XE)은 PHP로 작성한 설치형 CMS(Content Management System)입 @akasima @bnu @jhyeon1010 @khongchi @ngleader ## Authors -adrian.vasile.constantin, aerofleet, @akasima, @andreimarin, araste, @bnu, @bongkeun, bradly1, buffkj, c2joy, @canto, cbrghost, @ccata17, @ChanMyeong, chinaskyking, chschy, clench, @cometdev, @devdho, @devjin, @dionisrom, @dorami, @dragan-dan, ducduydaovn, duvent, @Eundong, @florinutz, @flourscent, @flyskyko, @ForPeople, FruitsHake, guny, @haneul, hankm2004, @hansim, haojilin, heemin, @hyeon0142, ikko, @izuzero, johnsonshu, juanlee0, k10206, kagami, @khongchi, @lansi951, @largeden, liahona, lickawtl, @mAKEkr, mayoojin, mglclub, @misol, mmx900, @mog422, mooo, mosmartin, @nagoon97, @ngleader, nicetwo, ovclas, @qw5414, @Rayyin, risapapa, rokmcssu, royallin, rubyeye, ryin005, @samswnlee, sanghunjun, @sejin7940, @smaker, @solidh, sspa3141, @stellar12, supershop, @taggon, @ucorina, unryong, venister, wdlee91, welcomeju, @YJSoft, ysnglee2000, zero + ## Contribution Guide `CONTRIBUTING.md`파일을 참고하세요. diff --git a/classes/context/Context.class.php b/classes/context/Context.class.php index 4cef22acb..ae3bc20eb 100644 --- a/classes/context/Context.class.php +++ b/classes/context/Context.class.php @@ -230,14 +230,30 @@ class Context define('_XE_SITELOCK_MESSAGE_', $message); header("HTTP/1.1 403 Forbidden"); - include _XE_PATH_ . 'common/tpl/sitelock.html'; + if(FileHandler::exists(_XE_PATH_ . 'common/tpl/sitelock.user.html')) + { + include _XE_PATH_ . 'common/tpl/sitelock.user.html'; + } + else + { + include _XE_PATH_ . 'common/tpl/sitelock.html'; + } exit; } } + // check if using rewrite module + $this->allow_rewrite = ($this->db_info->use_rewrite == 'Y' ? TRUE : FALSE); + // If XE is installed, get virtual site information if(self::isInstalled()) { + // If using rewrite module, initializes router + if($this->allow_rewrite) + { + Router::proc(); + } + $oModuleModel = getModel('module'); $site_module_info = $oModuleModel->getDefaultMid(); @@ -358,9 +374,6 @@ class Context $this->lang = &$GLOBALS['lang']; $this->loadLang(_XE_PATH_ . 'common/lang/'); - // check if using rewrite module - $this->allow_rewrite = ($this->db_info->use_rewrite == 'Y' ? TRUE : FALSE); - // set locations for javascript use if($_SERVER['REQUEST_METHOD'] == 'GET') { @@ -1059,6 +1072,7 @@ class Context */ function convertEncodingStr($str) { + if(!$str) return null; $obj = new stdClass(); $obj->str = $str; $obj = self::convertEncoding($obj); @@ -1554,7 +1568,9 @@ class Context 'act.document_srl.key.mid.vid' => ($act == 'trackback') ? "$vid/$mid/$srl/$key/$act" : '' ); - $query = $target_map[$target]; + Router::setMap($target_map); + + $query = Router::makePrettyUrl($target); } if(!$query) diff --git a/classes/display/DisplayHandler.class.php b/classes/display/DisplayHandler.class.php index a0559455e..9cdfd9c9b 100644 --- a/classes/display/DisplayHandler.class.php +++ b/classes/display/DisplayHandler.class.php @@ -292,7 +292,7 @@ class DisplayHandler extends Handler $buff = 'The IP address is not allowed. Change the value of __DEBUG_PROTECT_IP__ into your IP address in config/config.user.inc.php or config/config.inc.php'; } - return ""; + return ""; } // Output to a file diff --git a/classes/display/HTMLDisplayHandler.php b/classes/display/HTMLDisplayHandler.php index 809c74d13..39c9e7625 100644 --- a/classes/display/HTMLDisplayHandler.php +++ b/classes/display/HTMLDisplayHandler.php @@ -174,7 +174,7 @@ class HTMLDisplayHandler $output = preg_replace_callback('!!is', array($this, '_moveMetaToHeader'), $output); // change a meta fine(widget often put the tag like to the content because of caching) - $output = preg_replace_callback('//is', array($this, '_transMeta'), $output); + $output = preg_replace_callback('//is', array($this, '_transMeta'), $output); // handles a relative path generated by using the rewrite module if(Context::isAllowRewrite()) @@ -451,10 +451,23 @@ class HTMLDisplayHandler // add common JS/CSS files if(__DEBUG__ || !__XE_VERSION_STABLE__) { + $oContext->loadFile(array('./common/js/jquery-1.x.js', 'head', 'lt IE 9', -111000), true); + $oContext->loadFile(array('./common/js/jquery.js', 'head', 'gte IE 9', -110000), true); + $oContext->loadFile(array('./common/js/x.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/js/common.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/js/js_app.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/js/xml_handler.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/js/xml_js_filter.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/css/xe.css', '', '', -1000000), true); $oContext->loadFile(array('./common/css/mobile.css', '', '', -1000000), true); } else { + $oContext->loadFile(array('./common/js/jquery-1.x.min.js', 'head', 'lt IE 9', -111000), true); + $oContext->loadFile(array('./common/js/jquery.min.js', 'head', 'gte IE 9', -110000), true); + $oContext->loadFile(array('./common/js/x.min.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/js/xe.min.js', 'head', '', -100000), true); + $oContext->loadFile(array('./common/css/xe.min.css', '', '', -1000000), true); $oContext->loadFile(array('./common/css/mobile.min.css', '', '', -1000000), true); } } diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php index 29d94eb7f..968233923 100644 --- a/classes/file/FileHandler.class.php +++ b/classes/file/FileHandler.class.php @@ -515,7 +515,7 @@ class FileHandler * @param string $post_data Request arguments array for POST method * @return string If success, the content of the target file. Otherwise: none */ - function getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array()) + function getRemoteResource($url, $body = null, $timeout = 3, $method = 'GET', $content_type = null, $headers = array(), $cookies = array(), $post_data = array(), $request_config = array()) { try { @@ -533,6 +533,15 @@ class FileHandler else { $oRequest = new HTTP_Request($url); + + if(count($request_config) && method_exists($oRequest, 'setConfig')) + { + foreach($request_config as $key=>$val) + { + $oRequest->setConfig($key, $val); + } + } + if(count($headers) > 0) { foreach($headers as $key => $val) @@ -1008,6 +1017,33 @@ class FileHandler $path = self::getRealPath($path); return is_dir($path) ? $path : FALSE; } + + /** + * Check is writable dir + * + * @param string $path Target dir path + * @return bool + */ + function isWritableDir($path) + { + $path = self::getRealPath($path); + if(is_dir($path)==FALSE) + { + return FALSE; + } + + $checkFile = $path . '/_CheckWritableDir'; + + $fp = fopen($checkFile, 'w'); + if(!is_resource($fp)) + { + return FALSE; + } + fclose($fp); + + self::removeFile($checkFile); + return TRUE; + } } /* End of file FileHandler.class.php */ diff --git a/classes/frontendfile/FrontEndFileHandler.class.php b/classes/frontendfile/FrontEndFileHandler.class.php index c7d164dcd..a647b6dcd 100644 --- a/classes/frontendfile/FrontEndFileHandler.class.php +++ b/classes/frontendfile/FrontEndFileHandler.class.php @@ -8,7 +8,7 @@ class FrontEndFileHandler extends Handler { - static $isSSL = FALSE; + static $isSSL = null; /** * Map for css @@ -50,12 +50,13 @@ class FrontEndFileHandler extends Handler * Check SSL * * @return bool If using ssl returns true, otherwise returns false. + * @deprecated */ function isSsl() { - if(self::$isSSL) + if(!is_null(self::$isSSL)) { - return TRUE; + return self::$isSSL; } $url_info = parse_url(Context::getRequestUrl()); diff --git a/classes/module/ModuleHandler.class.php b/classes/module/ModuleHandler.class.php index 75cf81bc1..fde57e049 100644 --- a/classes/module/ModuleHandler.class.php +++ b/classes/module/ModuleHandler.class.php @@ -59,7 +59,10 @@ class ModuleHandler extends Handler $this->mid = $mid ? $mid : Context::get('mid'); $this->document_srl = $document_srl ? (int) $document_srl : (int) Context::get('document_srl'); $this->module_srl = $module_srl ? (int) $module_srl : (int) Context::get('module_srl'); - $this->entry = Context::convertEncodingStr(Context::get('entry')); + if($entry = Context::get('entry')) + { + $this->entry = Context::convertEncodingStr($entry); + } // Validate variables to prevent XSS $isInvalid = NULL; @@ -548,7 +551,6 @@ class ModuleHandler extends Handler } $xml_info = $oModuleModel->getModuleActionXml($forward->module); - $oMemberModel = getModel('member'); if($this->module == "admin" && $type == "view") { @@ -1145,12 +1147,25 @@ class ModuleHandler extends Handler { return new Object(); } + + //store before trigger call time + $before_trigger_time = NULL; + if(__LOG_SLOW_TRIGGER__> 0) + { + $before_trigger_time = microtime(true); + } foreach($triggers as $item) { $module = $item->module; $type = $item->type; $called_method = $item->called_method; + + $before_each_trigger_time = NULL; + if(__LOG_SLOW_TRIGGER__> 0) + { + $before_each_trigger_time = microtime(true); + } // todo why don't we call a normal class object ? $oModule = getModule($module, $type); @@ -1165,6 +1180,57 @@ class ModuleHandler extends Handler return $output; } unset($oModule); + + //store after trigger call time + $after_each_trigger_time = NULL; + //init value to 0 + $elapsed_time_trigger = 0; + + if(__LOG_SLOW_TRIGGER__> 0) + { + $after_each_trigger_time = microtime(true); + $elapsed_time_trigger = ($after_each_trigger_time - $before_each_trigger_time) * 1000; + } + + // if __LOG_SLOW_TRIGGER__ is defined, check elapsed time and leave trigger time log + if(__LOG_SLOW_TRIGGER__> 0 && $elapsed_time_trigger > __LOG_SLOW_TRIGGER__) + { + $buff = ''; + $log_file = _XE_PATH_ . 'files/_db_slow_trigger.php'; + if(!file_exists($log_file)) + { + $buff = '' . "\n"; + } + + $buff .= sprintf("%s\t%s.%s.%s.%s(%s)\n\t%0.6f msec\n\n", date("Y-m-d H:i"), $item->trigger_name,$item->module,$item->called_method,$item->called_position,$item->type, $elapsed_time_trigger); + + @file_put_contents($log_file, $buff, FILE_APPEND|LOCK_EX); + } + } + + //store after trigger call time + $after_trigger_time = NULL; + //init value to 0 + $elapsed_time = 0; + if(__LOG_SLOW_TRIGGER__> 0) + { + $after_trigger_time = microtime(true); + $elapsed_time = ($after_trigger_time - $before_trigger_time) * 1000; + } + + // if __LOG_SLOW_TRIGGER__ is defined, check elapsed time and leave trigger time log + if(__LOG_SLOW_TRIGGER__> 0 && $elapsed_time > __LOG_SLOW_TRIGGER__) + { + $buff = ''; + $log_file = _XE_PATH_ . 'files/_slow_trigger.php'; + if(!file_exists($log_file)) + { + $buff = '' . "\n"; + } + + $buff .= sprintf("%s\t%s.totaltime\n\t%0.6f msec\n\n", date("Y-m-d H:i"), $trigger_name,$elapsed_time); + + @file_put_contents($log_file, $buff, FILE_APPEND|LOCK_EX); } return new Object(); diff --git a/classes/object/Object.class.php b/classes/object/Object.class.php index aadf61e72..ed5a76bcf 100644 --- a/classes/object/Object.class.php +++ b/classes/object/Object.class.php @@ -165,7 +165,7 @@ class Object } /** - * Method to retrieve an object containing a key/value paris + * Method to retrieve an object containing a key/value pairs * * @return Object Returns an object containing key/value pairs */ diff --git a/classes/router/Router.class.php b/classes/router/Router.class.php new file mode 100644 index 000000000..8b95c2275 --- /dev/null +++ b/classes/router/Router.class.php @@ -0,0 +1,253 @@ + array('module' => 'rss', 'act' => '$1', '[L]' => TRUE), + '([a-zA-Z0-9_]+)/(rss|atom|api)' => array('mid' => '$1', 'act' => '$2', '[L]' => TRUE), + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/(rss|atom|api)' => array('vid' => '$1', 'mid' => '$2', 'act' => '$3', '[L]' => TRUE), + // trackback + '([0-9]+)/(.+)/trackback' => array('document_srl' => '$1', 'key' => '$2', 'act' => 'trackback', '[L]' => TRUE), + '([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback' => array('mid' => '$1', 'document_srl' => '$2', 'key' => '$3', 'act' => 'trackback', '[L]' => TRUE), + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([0-9]+)/(.+)/trackback' => array('vid' => '$1', 'mid' => '$2', 'document_srl' => '$3' , 'key' => '$4', 'act' => 'trackback', '[L]' => TRUE), + // document_srl + '([0-9]+)' => array('document_srl' => '$1', '[L]' => TRUE), + // mid + '([a-zA-Z0-9_]+)/?' => array('mid' => '$1', '[L]' => TRUE), + // mid + document_srl + '([a-zA-Z0-9_]+)/([0-9]+)' => array('mid' => '$1', 'document_srl' => '$2', '[L]' => TRUE), + // vid + mid + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/' => array('vid' => '$1', 'mid' => '$2', '[L]' => TRUE), + // vid + mid + document_srl + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([0-9]+)?' => array('vid' => '$1', 'mid' => '$2', 'document_srl' => '$3', '[L]' => TRUE), + // mid + entry title + '([a-zA-Z0-9_]+)/entry/(.+)' => array('mid' => '$1', 'entry' => '$2', '[L]' => TRUE), + // vid + mid + entry title + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/entry/(.+)' => array('vid' => '$1', 'mid' => '$2', 'entry' => '$3', '[L]' => TRUE), + // shop / vid / [category|product] / identifier + '([a-zA-Z0-9_]+)/([a-zA-Z0-9_]+)/([a-zA-Z0-9_\.-]+)' => array('act' => 'route', 'vid' => '$1', 'type' => '$2', 'identifier'=> '$3', '[L]' => TRUE) + ); + + /** + * Rewrite map + * @var array + */ + private static $rewrite_map = array(); + + /** + * @brief Applys routes. + * @see This function should be called only once + * @return void + */ + public static function proc() + { + $uri = $_SERVER['REQUEST_URI']; + + if (stripos($uri, $_SERVER['SCRIPT_NAME']) === 0) + { + $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME'])); + } + elseif (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) + { + $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME']))); + } + + if ($uri == '/' || empty($uri)) + { + return; + } + + // Get relative path from request uri + $path = parse_url($uri, PHP_URL_PATH); + + // Do some final cleaning of the URI and return it + $path = str_replace(array('//', '../'), '/', trim($path, '/')); + + if(strlen($path) > 0) + { + self::$segments = explode('/', $path); + } + + if(isset(self::$routes[$path])) + { + foreach(self::$routes[$path] as $key => $val) + { + if(strlen($val) > 0) + { + if(substr_compare($val, '$', 0, 1) == 0) + { + $segment_index = (int) substr($val, 1) - 1; + if($segment_index < 0) + { + continue; + } + + Context::set($key, self::$segments[$segment_index], TRUE); + } + else + { + Context::set($key, $val, TRUE); + } + } + else + { + Context::set($key, '', TRUE); + } + } + + return; + } + + $break = FALSE; + + // Apply routes + foreach(self::$routes as $regex => $query) + { + // Stop the routing proccess + if($break) + { + break; + } + if(preg_match('#^' . $regex . '$#', $path, $matches)) + { + foreach($query as $key => $val) + { + // If [L] keyword is defined + if($key == '[L]') + { + // Stop the routing process and don't apply any more rules + $break = TRUE; + continue; + } + + if(strlen($val) > 0) + { + if(substr($val, 0, 1) == '$') + { + $segment_index = (int) substr($val, 1) - 1; + if($segment_index < 0) + { + continue; + } + Context::set($key, self::$segments[$segment_index], TRUE); + } + else + { + Context::set($key, $val, TRUE); + } + } + else + { + Context::set($key, '', TRUE); + } + } + } + } + } + + /** + * @brief Add a rewrite map(s) + * @param array $map + * @return void + */ + public static function setMap($map) + { + self::$rewrite_map = array_merge(self::$rewrite_map, $map); + } + + /** + * @brief Add a route + * @param string $target + * @param array $query + * @return void + */ + public static function add($target, $query) + { + self::$routes[$target] = $query; + } + + /** + * @brief Add multiple routes + * @param array $routes + * @return void + */ + public function adds($routes) + { + self::$routes = array_merge(self::$routes, $routes); + } + + /** + * @brief Get segment from request uri + * @param int $index + * @return string + */ + public static function getSegment($index) + { + return self::$segments[$index - 1]; + } + + + /** + * @brief Get segment from request uri + * @param int $index + * @return string + */ + public static function getSegments() + { + return self::$segments; + } + + /** + * @brief Get route info + * @param string $regex + * @return array + */ + public static function getRoute($regex) + { + return self::$routes[$regex]; + } + + /** + * @brief Get routes list + * @return array + */ + public static function getRoutes() + { + return self::$routes; + } + + /** + * @brief Get routes list + * @param string $regex + * @return boolean + */ + public static function isExistsRoute($regex) + { + return isset(self::$routes[$regex]); + } + + /** + * @brief Makes shortten url + * @param string $regex + * @return string + */ + public static function makePrettyUrl($regex) + { + return self::$rewrite_map[$regex]; + } +} \ No newline at end of file diff --git a/classes/security/conf/embedWhiteUrl.xml b/classes/security/conf/embedWhiteUrl.xml index 00d1942c5..96f449663 100644 --- a/classes/security/conf/embedWhiteUrl.xml +++ b/classes/security/conf/embedWhiteUrl.xml @@ -87,6 +87,7 @@ http://player.vimeo.com/ + //player.vimeo.com/ diff --git a/classes/template/TemplateHandler.class.php b/classes/template/TemplateHandler.class.php index 3a9d72b66..7c0b53d71 100644 --- a/classes/template/TemplateHandler.class.php +++ b/classes/template/TemplateHandler.class.php @@ -365,12 +365,34 @@ class TemplateHandler ob_start(); if(substr($buff, 0, 7) == 'file://') { - include(substr($buff, 7)); + if(__DEBUG__) + { + //load cache file from disk + $eval_str = FileHandler::readFile(substr($buff, 7)); + $eval_str_buffed = "?>" . $eval_str; + @eval($eval_str_buffed); + $error_info = error_get_last(); + //parse error + if ($error_info['type'] == 4) + { + throw new Exception("Error Parsing Template - {$error_info['message']} in template file {$this->file}"); + } + } + else + { + include(substr($buff, 7)); + } } else { $eval_str = "?>" . $buff; - eval($eval_str); + @eval($eval_str); + $error_info = error_get_last(); + //parse error + if ($error_info['type'] == 4) + { + throw new Exception("Error Parsing Template - {$error_info['message']} in template file {$this->file}"); + } } return ob_get_clean(); diff --git a/classes/validator/Validator.class.php b/classes/validator/Validator.class.php index 8ad9d4f13..aa188bfe4 100644 --- a/classes/validator/Validator.class.php +++ b/classes/validator/Validator.class.php @@ -714,7 +714,7 @@ class Validator { $name = strtolower($name); - if(strpos('email,userid,url,alpha,alpha_number,number,', $name . ',') !== false) + if(in_array($name, array('email', 'userid', 'url', 'alpha', 'alpha_number', 'number'))) { continue; } diff --git a/classes/xml/xmlquery/argument/Argument.class.php b/classes/xml/xmlquery/argument/Argument.class.php index 33eebc324..ffc275495 100644 --- a/classes/xml/xmlquery/argument/Argument.class.php +++ b/classes/xml/xmlquery/argument/Argument.class.php @@ -1,398 +1,396 @@ - */ - -/** - * Argument class - * @author NAVER (developers@xpressengine.com) - * @package /classes/xml/xmlquery/argument - * @version 0.1 - */ -class Argument -{ - - /** - * argument value - * @var mixed - */ - var $value; - - /** - * argument name - * @var string - */ - var $name; - - /** - * argument type - * @var string - */ - var $type; - - /** - * result of argument type check - * @var bool - */ - var $isValid; - - /** - * error message - * @var Object - */ - var $errorMessage; - - /** - * column operation - */ - var $column_operation; - - /** - * Check if arg value is user submnitted or default - * @var mixed - */ - var $uses_default_value; - - /** - * Caches escaped and toString value so that the parsing won't happen multiple times - * @var mixed - */ - var $_value; // - - /** - * constructor - * @param string $name - * @param mixed $value - * @return void - */ - - function Argument($name, $value) - { - $this->value = $value; - $this->name = $name; - $this->isValid = TRUE; - } - - function getType() - { - if(isset($this->type)) - { - return $this->type; - } - if(is_string($this->value)) - { - return 'column_name'; - } - - return 'number'; - } - - function setColumnType($value) - { - $this->type = $value; - } - - function setColumnOperation($operation) - { - $this->column_operation = $operation; - } - - function getName() - { - return $this->name; - } - - function getValue() - { - if(!isset($this->_value)) - { - $value = $this->getEscapedValue(); - $this->_value = $this->toString($value); - } - return $this->_value; - } - - function getPureValue() - { - return $this->value; - } - - function getColumnOperation() - { - return $this->column_operation; - } - - function getEscapedValue() - { - return $this->escapeValue($this->value); - } - - function getUnescapedValue() - { - if($this->value === 'null') - { - return null; - } - return $this->value; - } - - /** - * mixed value to string - * @param mixed $value - * @return string - */ - function toString($value) - { - if(is_array($value)) - { - if(count($value) === 0) - { - return ''; - } - if(count($value) === 1 && $value[0] === '') - { - return ''; - } - return '(' . implode(',', $value) . ')'; - } - return $value; - } - - /** - * escape value - * @param mixed $value - * @return mixed - */ - function escapeValue($value) - { - $column_type = $this->getType(); - if($column_type == 'column_name') - { - $dbParser = DB::getParser(); - return $dbParser->parseExpression($value); - } - if(!isset($value)) - { - return null; - } - - $columnTypeList = array('date' => 1, 'varchar' => 1, 'char' => 1, 'text' => 1, 'bigtext' => 1); - if(isset($columnTypeList[$column_type])) - { - if(!is_array($value)) - { - $value = $this->_escapeStringValue($value); - } - else - { - $total = count($value); - for($i = 0; $i < $total; $i++) - { - $value[$i] = $this->_escapeStringValue($value[$i]); - } - //$value[$i] = '\''.$value[$i].'\''; - } - } - if($this->uses_default_value) - { - return $value; - } - if($column_type == 'number') - { - if(is_array($value)) - { - foreach($value AS $key => $val) - { - if(isset($val) && $val !== '') - { - $value[$key] = (int) $val; - } - } - } - else - { - $value = (int) $value; - } - } - - return $value; - } - - /** - * escape string value - * @param string $value - * @return string - */ - function _escapeStringValue($value) - { - // Remove non-utf8 chars. - $regex = '@((?:[\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}){1,100})|([\xF0-\xF7][\x80-\xBF]{3})|([\x80-\xBF])|([\xC0-\xFF])@x'; - - $value = preg_replace_callback($regex, array($this, 'utf8Replacer'), $value); - $db = DB::getInstance(); - $value = $db->addQuotes($value); - return '\'' . $value . '\''; - } - - function utf8Replacer($captures) - { - if(strlen($captures[1])) - { - // Valid byte sequence. Return unmodified. - return $captures[1]; - } - else if(strlen($captures[2])) - { - // Remove user defined area - if("\xF3\xB0\x80\x80" <= $captures[2]) - { - return; - } - - return $captures[2]; - } - else - { - return; - } - } - - function isValid() - { - return $this->isValid; - } - - function isColumnName() - { - $type = $this->getType(); - $value = $this->getUnescapedValue(); - if($type == 'column_name') - { - return TRUE; - } - if($type == 'number' && is_null($value)) - { - return FALSE; - } - if($type == 'number' && !is_numeric($value) && $this->uses_default_value) - { - return TRUE; - } - return FALSE; - } - - function getErrorMessage() - { - return $this->errorMessage; - } - - function ensureDefaultValue($default_value) - { - if($this->value === NULL || $this->value === '') - { - $this->value = $default_value; - $this->uses_default_value = TRUE; - } - } - - /** - * check filter by filter type - * @param string $filter_type - * @return void - */ - function checkFilter($filter_type) - { - if(isset($this->value) && $this->value != '') - { - global $lang; - $val = $this->value; - $key = $this->name; - switch($filter_type) - { - case 'email' : - case 'email_address' : - if(!preg_match('/^[\w-]+((?:\.|\+|\~)[\w-]+)*@[\w-]+(\.[\w-]+)+$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_email, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - case 'homepage' : - if(!preg_match('/^(http|https)+(:\/\/)+[0-9a-z_-]+\.[^ ]+$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_homepage, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - case 'userid' : - case 'user_id' : - if(!preg_match('/^[a-zA-Z]+([_0-9a-zA-Z]+)*$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_userid, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - case 'number' : - case 'numbers' : - if(is_array($val)) - { - $val = join(',', $val); - } - if(!preg_match('/^(-?)[0-9]+(,\-?[0-9]+)*$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_number, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - case 'alpha' : - if(!preg_match('/^[a-z]+$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_alpha, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - case 'alpha_number' : - if(!preg_match('/^[0-9a-z]+$/is', $val)) - { - $this->isValid = FALSE; - $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_alpha_number, $lang->{$key} ? $lang->{$key} : $key)); - } - break; - } - } - } - - function checkMaxLength($length) - { - if($this->value && (strlen($this->value) > $length)) - { - global $lang; - $this->isValid = FALSE; - $key = $this->name; - $this->errorMessage = new Object(-1, sprintf($lang->filter->outofrange, $lang->{$key} ? $lang->{$key} : $key)); - } - } - - function checkMinLength($length) - { - if($this->value && (strlen($this->value) < $length)) - { - global $lang; - $this->isValid = FALSE; - $key = $this->name; - $this->errorMessage = new Object(-1, sprintf($lang->filter->outofrange, $lang->{$key} ? $lang->{$key} : $key)); - } - } - - function checkNotNull() - { - if(!isset($this->value)) - { - global $lang; - $this->isValid = FALSE; - $key = $this->name; - $this->errorMessage = new Object(-1, sprintf($lang->filter->isnull, $lang->{$key} ? $lang->{$key} : $key)); - } - } - -} -/* End of file Argument.class.php */ -/* Location: ./classes/xml/xmlquery/argument/Argument.class.php */ + */ + +/** + * Argument class + * @author NAVER (developers@xpressengine.com) + * @package /classes/xml/xmlquery/argument + * @version 0.1 + */ +class Argument +{ + + /** + * argument value + * @var mixed + */ + var $value; + + /** + * argument name + * @var string + */ + var $name; + + /** + * argument type + * @var string + */ + var $type; + + /** + * result of argument type check + * @var bool + */ + var $isValid; + + /** + * error message + * @var Object + */ + var $errorMessage; + + /** + * column operation + */ + var $column_operation; + + /** + * Check if arg value is user submnitted or default + * @var mixed + */ + var $uses_default_value; + + /** + * Caches escaped and toString value so that the parsing won't happen multiple times + * @var mixed + */ + var $_value; // + + /** + * constructor + * @param string $name + * @param mixed $value + * @return void + */ + + function Argument($name, $value) + { + $this->value = $value; + $this->name = $name; + $this->isValid = TRUE; + } + + function getType() + { + if(isset($this->type)) + { + return $this->type; + } + if(is_string($this->value)) + { + return 'column_name'; + } + + return 'number'; + } + + function setColumnType($value) + { + $this->type = $value; + } + + function setColumnOperation($operation) + { + $this->column_operation = $operation; + } + + function getName() + { + return $this->name; + } + + function getValue() + { + if(!isset($this->_value)) + { + $value = $this->getEscapedValue(); + $this->_value = $this->toString($value); + } + return $this->_value; + } + + function getPureValue() + { + return $this->value; + } + + function getColumnOperation() + { + return $this->column_operation; + } + + function getEscapedValue() + { + return $this->escapeValue($this->value); + } + + function getUnescapedValue() + { + if($this->value === 'null') + { + return null; + } + return $this->value; + } + + /** + * mixed value to string + * @param mixed $value + * @return string + */ + function toString($value) + { + if(is_array($value)) + { + if(count($value) === 0) + { + return ''; + } + if(count($value) === 1 && $value[0] === '') + { + return ''; + } + return '(' . implode(',', $value) . ')'; + } + return $value; + } + + /** + * escape value + * @param mixed $value + * @return mixed + */ + function escapeValue($value) + { + $column_type = $this->getType(); + if($column_type == 'column_name') + { + $dbParser = DB::getParser(); + return $dbParser->parseExpression($value); + } + if(!isset($value)) + { + return null; + } + + $columnTypeList = array('date' => 1, 'varchar' => 1, 'char' => 1, 'text' => 1, 'bigtext' => 1); + if(isset($columnTypeList[$column_type])) + { + if(!is_array($value)) + { + $value = $this->_escapeStringValue($value); + } + else + { + foreach($value as $key=>$val) + { + $value[$key] = $this->_escapeStringValue($val); + } + } + } + if($this->uses_default_value) + { + return $value; + } + if($column_type == 'number') + { + if(is_array($value)) + { + foreach($value AS $key => $val) + { + if(isset($val) && $val !== '') + { + $value[$key] = (int) $val; + } + } + } + else + { + $value = (int) $value; + } + } + + return $value; + } + + /** + * escape string value + * @param string $value + * @return string + */ + function _escapeStringValue($value) + { + // Remove non-utf8 chars. + $regex = '@((?:[\x00-\x7F]|[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}){1,100})|([\xF0-\xF7][\x80-\xBF]{3})|([\x80-\xBF])|([\xC0-\xFF])@x'; + + $value = preg_replace_callback($regex, array($this, 'utf8Replacer'), $value); + $db = DB::getInstance(); + $value = $db->addQuotes($value); + return '\'' . $value . '\''; + } + + function utf8Replacer($captures) + { + if(strlen($captures[1])) + { + // Valid byte sequence. Return unmodified. + return $captures[1]; + } + else if(strlen($captures[2])) + { + // Remove user defined area + if("\xF3\xB0\x80\x80" <= $captures[2]) + { + return; + } + + return $captures[2]; + } + else + { + return; + } + } + + function isValid() + { + return $this->isValid; + } + + function isColumnName() + { + $type = $this->getType(); + $value = $this->getUnescapedValue(); + if($type == 'column_name') + { + return TRUE; + } + if($type == 'number' && is_null($value)) + { + return FALSE; + } + if($type == 'number' && !is_numeric($value) && $this->uses_default_value) + { + return TRUE; + } + return FALSE; + } + + function getErrorMessage() + { + return $this->errorMessage; + } + + function ensureDefaultValue($default_value) + { + if($this->value === NULL || $this->value === '') + { + $this->value = $default_value; + $this->uses_default_value = TRUE; + } + } + + /** + * check filter by filter type + * @param string $filter_type + * @return void + */ + function checkFilter($filter_type) + { + if(isset($this->value) && $this->value != '') + { + global $lang; + $val = $this->value; + $key = $this->name; + switch($filter_type) + { + case 'email' : + case 'email_address' : + if(!preg_match('/^[\w-]+((?:\.|\+|\~)[\w-]+)*@[\w-]+(\.[\w-]+)+$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_email, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + case 'homepage' : + if(!preg_match('/^(http|https)+(:\/\/)+[0-9a-z_-]+\.[^ ]+$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_homepage, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + case 'userid' : + case 'user_id' : + if(!preg_match('/^[a-zA-Z]+([_0-9a-zA-Z]+)*$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_userid, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + case 'number' : + case 'numbers' : + if(is_array($val)) + { + $val = join(',', $val); + } + if(!preg_match('/^(-?)[0-9]+(,\-?[0-9]+)*$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_number, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + case 'alpha' : + if(!preg_match('/^[a-z]+$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_alpha, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + case 'alpha_number' : + if(!preg_match('/^[0-9a-z]+$/is', $val)) + { + $this->isValid = FALSE; + $this->errorMessage = new Object(-1, sprintf($lang->filter->invalid_alpha_number, $lang->{$key} ? $lang->{$key} : $key)); + } + break; + } + } + } + + function checkMaxLength($length) + { + if($this->value && (strlen($this->value) > $length)) + { + global $lang; + $this->isValid = FALSE; + $key = $this->name; + $this->errorMessage = new Object(-1, sprintf($lang->filter->outofrange, $lang->{$key} ? $lang->{$key} : $key)); + } + } + + function checkMinLength($length) + { + if($this->value && (strlen($this->value) < $length)) + { + global $lang; + $this->isValid = FALSE; + $key = $this->name; + $this->errorMessage = new Object(-1, sprintf($lang->filter->outofrange, $lang->{$key} ? $lang->{$key} : $key)); + } + } + + function checkNotNull() + { + if(!isset($this->value)) + { + global $lang; + $this->isValid = FALSE; + $key = $this->name; + $this->errorMessage = new Object(-1, sprintf($lang->filter->isnull, $lang->{$key} ? $lang->{$key} : $key)); + } + } + +} +/* End of file Argument.class.php */ +/* Location: ./classes/xml/xmlquery/argument/Argument.class.php */ diff --git a/common/css/xe.css b/common/css/xe.css index cdddb3605..44177eacc 100644 --- a/common/css/xe.css +++ b/common/css/xe.css @@ -300,7 +300,7 @@ button.btn { -moz-border-radius-topleft: 4px; border-top-left-radius: 4px; } -.btn-group>.btn: last-child { +.btn-group>.btn:last-child { -webkit-border-top-right-radius: 4px; -moz-border-radius-topright: 4px; border-top-right-radius: 4px; diff --git a/common/js/common.js b/common/js/common.js index 00fbe2bd2..498392750 100644 --- a/common/js/common.js +++ b/common/js/common.js @@ -596,14 +596,25 @@ function doDocumentLoad(obj) { } /* 저장된 게시글의 선택 */ -function doDocumentSelect(document_srl) { +function doDocumentSelect(document_srl, module) { if(!opener || !opener.objForSavedDoc) { window.close(); return; } + if(module===undefined) { + module = 'document'; + } + // 게시글을 가져와서 등록하기 - opener.location.href = opener.current_url.setQuery('document_srl', document_srl).setQuery('act', 'dispBoardWrite'); + switch(module) { + case 'page' : + opener.location.href = opener.current_url.setQuery('document_srl', document_srl).setQuery('act', 'dispPageAdminContentModify'); + break; + default : + opener.location.href = opener.current_url.setQuery('document_srl', document_srl).setQuery('act', 'dispBoardWrite'); + break; + } window.close(); } @@ -900,7 +911,7 @@ function get_by_id(id) { jQuery(function($){ // display popup menu that contains member actions and document actions - $(document).click(function(evt) { + $(document).on('click touchstart', function(evt) { var $area = $('#popup_menu_area'); if(!$area.length) $area = $('