From 929bf6976a4f63514e83ef725f002072eb8b7e48 Mon Sep 17 00:00:00 2001 From: yama Date: Sat, 2 Mar 2013 13:39:45 +0900 Subject: [PATCH 01/21] [#9563] onManagerMainFrameHeaderHTMLBlock event issue http://tracker.modx.com/issues/9563 --- manager/includes/header.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manager/includes/header.inc.php b/manager/includes/header.inc.php index b400f07b3a..a9eb81b9e9 100755 --- a/manager/includes/header.inc.php +++ b/manager/includes/header.inc.php @@ -4,7 +4,7 @@ // invoke OnManagerRegClientStartupHTMLBlock event $evtOut = $modx->invokeEvent('OnManagerMainFrameHeaderHTMLBlock'); -$onManagerMainFrameHeaderHTMLBlock = is_array($evtOut) ? '
' . implode('', $evtOut) . '
' : ''; +$onManagerMainFrameHeaderHTMLBlock = is_array($evtOut) ? implode("\n", $evtOut) : ''; ?> From f6e12f498a017379b9907aa7e4cb8082dc45145d Mon Sep 17 00:00:00 2001 From: yama Date: Sat, 2 Mar 2013 15:55:46 +0900 Subject: [PATCH 02/21] OnWUsrFormRender event adjustment http://tracker.modx.com/issues/9564 (Coded by breezer) --- manager/actions/mutate_web_user.dynamic.php | 35 +++++++++++---------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/manager/actions/mutate_web_user.dynamic.php b/manager/actions/mutate_web_user.dynamic.php index a14f5f0997..ba0b886b09 100644 --- a/manager/actions/mutate_web_user.dynamic.php +++ b/manager/actions/mutate_web_user.dynamic.php @@ -99,7 +99,8 @@ function ConvertDate($date) { global $modx; if ($date == "") {return "0";} - else {} {return $modx->toTimeStamp($date);} + //else {} {return $modx->toTimeStamp($date);} + else {return $modx->toTimeStamp($date);} } // include the country list language file @@ -515,9 +516,6 @@ function SetUrl(url, width, height, alt){ - - - $v) $groupsarray[] = $v; } -?> - -
-" . $_lang['access_permissions_user_message'] . "

"; + echo '
+

'.$_lang['web_access_permissions'].'

+ + '; + echo '

'. $_lang['access_permissions_user_message'] . '

'; $sql = "SELECT name, id FROM $dbase.`".$table_prefix."webgroup_names` ORDER BY name"; $rs = mysql_query($sql); $limit = mysql_num_rows($rs); for($i=0; $i<$limit; $i++) { $row=mysql_fetch_assoc($rs); - echo "".$row['name']."
"; + echo ''.$row['name'].'
'; } -?> -
-'; + } -?> - -'; + // invoke OnWUsrFormRender event $evtOut = $modx->invokeEvent("OnWUsrFormRender",array("id" => $user)); if(is_array($evtOut)) echo implode("",$evtOut); ?> - \ No newline at end of file + +
+ + From a7ef345d2abd4216b7fc26ed9b25f950725d4611 Mon Sep 17 00:00:00 2001 From: yama Date: Sat, 2 Mar 2013 19:10:05 +0900 Subject: [PATCH 03/21] Refactor #9567 Add "limit" option to $modx->db->delete() http://tracker.modx.com/issues/9567 --- manager/includes/extenders/dbapi.mysql.class.inc.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/manager/includes/extenders/dbapi.mysql.class.inc.php b/manager/includes/extenders/dbapi.mysql.class.inc.php index d345240601..573a0bc5d0 100644 --- a/manager/includes/extenders/dbapi.mysql.class.inc.php +++ b/manager/includes/extenders/dbapi.mysql.class.inc.php @@ -154,13 +154,14 @@ function query($sql) { * @name: delete * */ - function delete($from,$where='',$fields='') { + function delete($from, $where='', $orderby='', $limit = '') { if (!$from) return false; else { - $table = $from; - $where = ($where != "") ? "WHERE $where" : ""; - return $this->query("DELETE $fields FROM $table $where"); + if($where != '') $where = "WHERE {$where}"; + if($orderby !== '') $orderby = "ORDER BY {$orderby}"; + if($limit != '') $limit = "LIMIT {$limit}"; + return $this->query("DELETE FROM {$from} {$where} {$orderby} {$limit}"); } } From 6feb7c54cb900b2c2542d14daef32c30d2fc8d5a Mon Sep 17 00:00:00 2001 From: yama Date: Tue, 5 Mar 2013 08:08:15 +0900 Subject: [PATCH 04/21] Improvement to full table name call (New feature, $modx->db->replaceFullTableName() ) --- .../extenders/dbapi.mysql.class.inc.php | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/manager/includes/extenders/dbapi.mysql.class.inc.php b/manager/includes/extenders/dbapi.mysql.class.inc.php index 573a0bc5d0..4e2c0ea013 100644 --- a/manager/includes/extenders/dbapi.mysql.class.inc.php +++ b/manager/includes/extenders/dbapi.mysql.class.inc.php @@ -501,5 +501,30 @@ function makeArray($rs=''){ function getVersion() { return mysql_get_server_info(); } + + /** + * @name replaceFullTableName + * @desc Get full table name. Append table name and table prefix. + * + * @param string $str + * @return string + */ + function replaceFullTableName($str,$force=null) { + + $str = trim($str); + $dbase = trim($this->config['dbase'],'`'); + $prefix = $this->config['table_prefix']; + if(!empty($force)) + { + $result = "`{$dbase}`.`{$prefix}{$str}`"; + } + elseif(strpos($str,'[+prefix+]')!==false) + { + $result = preg_replace('@\[\+prefix\+\]([0-9a-zA-Z_]+)@', "`{$dbase}`.`{$prefix}$1`", $str); + } + else $result = $str; + + return $result; + } } ?> \ No newline at end of file From 4c3c64df2a42d47c1414221dd97391467198dd1d Mon Sep 17 00:00:00 2001 From: yama Date: Tue, 5 Mar 2013 14:45:05 +0900 Subject: [PATCH 05/21] Refactor #9570 Detailed log message http://tracker.modx.com/issues/9570 --- .../includes/document.parser.class.inc.php | 390 ++++++++++++------ 1 file changed, 258 insertions(+), 132 deletions(-) diff --git a/manager/includes/document.parser.class.inc.php b/manager/includes/document.parser.class.inc.php index f811d85a24..25c11dfc56 100755 --- a/manager/includes/document.parser.class.inc.php +++ b/manager/includes/document.parser.class.inc.php @@ -790,13 +790,18 @@ function evalPlugin($pluginCode, $params) { eval ($pluginCode); $msg= ob_get_contents(); ob_end_clean(); - if ($msg && isset ($php_errormsg)) { - if (!strpos($php_errormsg, 'Deprecated')) { // ignore php5 strict errors - // log error - $this->logEvent(1, 3, "$php_errormsg

$msg", $this->Event->activePlugin . " - Plugin"); - if ($this->isBackend()) - $this->Event->alert("An error occurred while loading. Please see the event log for more information.

$msg"); - } + if ($msg && isset ($php_errormsg)) { + $error_info = error_get_last(); + if($error_info['type']===2048 || $error_info['type']===8192) $error_type = 2; + else $error_type = 3; + if(2<$error_type) { + extract($error_info); + if($msg===false) $msg = 'ob_get_contents() error'; + $result = $this->messageQuit('PHP Parse Error', '', true, $type, $file, 'Plugin', $text, $line, $msg); + if ($this->isBackend()) { + $this->event->alert("An error occurred while loading. Please see the event log for more information.

{$msg}

"); + } + } } else { echo $msg; } @@ -814,14 +819,22 @@ function evalSnippet($snippet, $params) { $snip= eval ($snippet); $msg= ob_get_contents(); ob_end_clean(); - if ($msg && isset ($php_errormsg)) { - if (!strpos($php_errormsg, 'Deprecated')) { // ignore php5 strict errors - // log error - $this->logEvent(1, 3, "$php_errormsg

$msg", $this->currentSnippet . " - Snippet"); - if ($this->isBackend()) - $this->Event->alert("An error occurred while loading. Please see the event log for more information

$msg"); - } - } + if (isset($php_errormsg)) + { + $error_info = error_get_last(); + if($error_info['type']===2048 || $error_info['type']===8192) $error_type = 2; + else $error_type = 3; + if(2<$error_type) + { + extract($error_info); + if($msg===false) $msg = 'ob_get_contents() error'; + $result = $this->messageQuit('PHP Parse Error', '', true, $type, $file, 'Snippet', $text, $line, $msg); + if ($this->isBackend()) + { + $this->event->alert("An error occurred while loading. Please see the event log for more information

{$msg}{$snip}

"); + } + } + } unset ($modx->event->params); return $msg . $snip; } @@ -2684,124 +2697,237 @@ function phpError($nr, $text, $file, $line) { $this->messageQuit("PHP Parse Error", '', true, $nr, $file, $source, $text, $line); } - function messageQuit($msg= 'unspecified error', $query= '', $is_error= true, $nr= '', $file= '', $source= '', $text= '', $line= '') { - - $version= isset ($GLOBALS['version']) ? $GLOBALS['version'] : ''; + function messageQuit($msg= 'unspecified error', $query= '', $is_error= true, $nr= '', $file= '', $source= '', $text= '', $line= '', $output='') { + + $version= isset ($GLOBALS['modx_version']) ? $GLOBALS['modx_version'] : ''; $release_date= isset ($GLOBALS['release_date']) ? $GLOBALS['release_date'] : ''; - $parsedMessageString= " - MODx Content Manager $version » $release_date - - - - "; - if ($is_error) { - $parsedMessageString .= "

« MODx Parse Error »

- - - "; - } else { - $parsedMessageString .= "

« MODx Debug/ stop message »

-
MODx encountered the following error while attempting to parse the requested resource:
« $msg »
- - "; - } - - if (!empty ($query)) { - $parsedMessageString .= ""; - } - - if ($text != '') { - - $errortype= array ( - E_ERROR => "Error", - E_WARNING => "Warning", - E_PARSE => "Parsing Error", - E_NOTICE => "Notice", - E_CORE_ERROR => "Core Error", - E_CORE_WARNING => "Core Warning", - E_COMPILE_ERROR => "Compile Error", - E_COMPILE_WARNING => "Compile Warning", - E_USER_ERROR => "User Error", - E_USER_WARNING => "User Warning", - E_USER_NOTICE => "User Notice", - - ); - - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - if ($source != '') { - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - } - } - - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= ""; - $parsedMessageString .= ""; - $parsedMessageString .= ""; - - $parsedMessageString .= "
The MODx parser recieved the following debug/ stop message:
« $msg »
      SQL: $query -
      [Copy SQL to ClipBoard]
 
PHP error debug
  Error: $text 
  Error type/ Nr.: " . $errortype[$nr] . " - $nr 
  File: $file 
  Line: $line 
  Line $line source: $source 
 
Parser timing
  MySQL: [^qt^]([^q^] Requests)
  PHP: [^p^] 
  Total: [^t^] 
"; - $parsedMessageString .= ""; - - $totalTime= ($this->getMicroTime() - $this->tstart); - $queryTime= $this->queryTime; - $phpTime= $totalTime - $queryTime; - $queries= isset ($this->executedQueries) ? $this->executedQueries : 0; - $queryTime= sprintf("%2.4f s", $queryTime); - $totalTime= sprintf("%2.4f s", $totalTime); - $phpTime= sprintf("%2.4f s", $phpTime); - - $parsedMessageString= str_replace("[^q^]", $queries, $parsedMessageString); - $parsedMessageString= str_replace("[^qt^]", $queryTime, $parsedMessageString); - $parsedMessageString= str_replace("[^p^]", $phpTime, $parsedMessageString); - $parsedMessageString= str_replace("[^t^]", $totalTime, $parsedMessageString); - - // Set 500 response header - header('HTTP/1.1 500 Internal Server Error'); - - // Display error - echo $parsedMessageString; - ob_end_flush(); - - // Log error - $this->logEvent(0, 3, $parsedMessageString, $source= 'Parser'); - - // Make sure and die! - exit(); - } + $request_uri = $_SERVER['REQUEST_URI']; + $request_uri = htmlspecialchars($request_uri, ENT_QUOTES, $this->config['modx_charset']); + $ua = htmlspecialchars($_SERVER['HTTP_USER_AGENT'], ENT_QUOTES, $this->config['modx_charset']); + $referer = htmlspecialchars($_SERVER['HTTP_REFERER'], ENT_QUOTES, $this->config['modx_charset']); + if ($is_error) { + $str = '

« MODX Parse Error »

+ + + '; + } else { + $str = '

« MODX Debug/ stop message »

+
MODX encountered the following error while attempting to parse the requested resource:
« ' . $msg . ' »
+ + '; + } + + if (!empty ($query)) { + $str .= ''; + } + + $errortype= array ( + E_ERROR => "ERROR", + E_WARNING => "WARNING", + E_PARSE => "PARSING ERROR", + E_NOTICE => "NOTICE", + E_CORE_ERROR => "CORE ERROR", + E_CORE_WARNING => "CORE WARNING", + E_COMPILE_ERROR => "COMPILE ERROR", + E_COMPILE_WARNING => "COMPILE WARNING", + E_USER_ERROR => "USER ERROR", + E_USER_WARNING => "USER WARNING", + E_USER_NOTICE => "USER NOTICE", + E_STRICT => "STRICT NOTICE", + E_RECOVERABLE_ERROR => "RECOVERABLE ERROR", + E_DEPRECATED => "DEPRECATED", + E_USER_DEPRECATED => "USER DEPRECATED" + ); + + if(!empty($nr) || !empty($file)) + { + $str .= ''; + if ($text != '') + { + $str .= '"; + } + $str .= ''; + $str .= '"; + $str .= ''; + $str .= ""; + $str .= ""; + } + + if ($source != '') + { + $str .= ""; + } + + $str .= ''; + + $str .= ''; + $str .= ""; + $str .= ''; + + if(isset($_GET['a'])) $action = $_GET['a']; + elseif(isset($_POST['a'])) $action = $_POST['a']; + if(isset($action) && !empty($action)) + { + include_once($this->config['core_path'] . 'actionlist.inc.php'); + global $action_list; + if(isset($action_list[$action])) $actionName = " - {$action_list[$action]}"; + else $actionName = ''; + $str .= ''; + $str .= ""; + $str .= ''; + } + + if(preg_match('@^[0-9]+@',$this->documentIdentifier)) + { + $resource = $this->getDocumentObject('id',$this->documentIdentifier); + $url = $this->makeUrl($this->documentIdentifier,'','','full'); + $link = '' . $resource['pagetitle'] . ''; + $str .= ''; + $str .= ''; + } + + if(!empty($this->currentSnippet)) + { + $str .= ""; + $str .= ''; + } + + if(!empty($this->event->activePlugin)) + { + $str .= ""; + $str .= ''; + } + + $str .= ""; + $str .= ""; + + $str .= ""; + $str .= ''; + $str .= ''; + + $str .= ''; + + $str .= ""; + $str .= ''; + $str .= ''; + + $str .= ""; + $str .= ''; + $str .= ''; + + $str .= ""; + $str .= ''; + $str .= ''; + + $str .= "
The MODX parser recieved the following debug/ stop message:
« ' . $msg . ' »
SQL > ' . $query . '
+
PHP error debug
' . "Error : {$text}
ErrorType[num] : ' . $errortype [$nr] . "[{$nr}]
File : {$file}
Line : {$line}
Source : {$source}
Basic info
REQUEST_URI : {$request_uri}
Manager action : {$action}{$actionName}
Resource : [' . $this->documentIdentifier . ']' . $link . '
Current Snippet : ' . $this->currentSnippet . '
Current Plugin : ' . $this->event->activePlugin . '(' . $this->event->name . ')' . '
Referer : {$referer}
User Agent : {$ua}
IP : ' . $_SERVER['REMOTE_ADDR'] . '
Parser timing
MySQL : [^qt^] ([^q^] Requests)
PHP : [^p^]
Total : [^t^]
\n"; + + $totalTime= ($this->getMicroTime() - $this->tstart); + + $mem = memory_get_peak_usage(true); + $total_mem = $mem - $this->mstart; + $total_mem = ($total_mem / 1024 / 1024) . ' mb'; + + $queryTime= $this->queryTime; + $phpTime= $totalTime - $queryTime; + $queries= isset ($this->executedQueries) ? $this->executedQueries : 0; + $queryTime= sprintf("%2.4f s", $queryTime); + $totalTime= sprintf("%2.4f s", $totalTime); + $phpTime= sprintf("%2.4f s", $phpTime); + + $str= str_replace('[^q^]', $queries, $str); + $str= str_replace('[^qt^]',$queryTime, $str); + $str= str_replace('[^p^]', $phpTime, $str); + $str= str_replace('[^t^]', $totalTime, $str); + $str= str_replace('[^m^]', $total_mem, $str); + + if(isset($php_errormsg) && !empty($php_errormsg)) $str = "{$php_errormsg}
\n{$str}"; + $str .= '
' . $this->get_backtrace(debug_backtrace()) . "\n"; + + if(!empty($output)) + { + $str .= '

Output:

' . $output . '
'; + } + + // Log error + if(!empty($this->currentSnippet)) $source = 'Snippet - ' . $this->currentSnippet; + elseif(!empty($this->event->activePlugin)) $source = 'Plugin - ' . $this->event->activePlugin; + elseif($source!=='') $source = 'Parser - ' . $source; + elseif($query!=='') $source = 'SQL Query'; + else $source = 'Parser'; + if(isset($actionName) && !empty($actionName)) $source .= $actionName; + switch($nr) + { + case E_DEPRECATED : + case E_USER_DEPRECATED : + case E_STRICT : + case E_NOTICE : + case E_USER_NOTICE : + $error_level = 2; + break; + default: + $error_level = 3; + } + $this->logEvent(0, $error_level, $str,$source); + if($error_level === 2) return true; + + // Set 500 response header + header('HTTP/1.1 500 Internal Server Error'); + + // Display error + if (isset($_SESSION['mgrValidated'])) + { + echo 'MODX Content Manager ' . $version . ' » ' . $release_date . ' + + + + + ' . $str . ''; + + } + else echo 'Error'; + ob_end_flush(); + exit; + } + + function get_backtrace($backtrace) { + + $str = "

Backtrace

\n"; + $str .= ''; + $backtrace = array_reverse($backtrace); + foreach ($backtrace as $key => $val) + { + $key++; + if(substr($val['function'],0,11)==='messageQuit') break; + elseif(substr($val['function'],0,8)==='phpError') break; + $path = str_replace('\\','/',$val['file']); + if(strpos($path,MODX_BASE_PATH)===0) $path = substr($path,strlen(MODX_BASE_PATH)); + if(!empty($val['args']) && 0 < count($val['args'])) + { + foreach($val['args'] as $v) + { + if(is_array($v)) $v = 'array()'; + elseif(is_object($v)) + { + $v = get_class($v); + } + else + { + $v = str_replace('"', '', $v); + $v = htmlspecialchars($v,ENT_QUOTES,$this->config['modx_charset']); + if(32 < strlen($v)) $v = mb_substr($v,0,32,$this->config['modx_charset']) . '...'; + $a[] = '"' . $v . '"'; + } + } + $args = join(', ', $a); + } + else $args = ''; + $str .= ""; + $str .= ""; + } + $str .= '
{$key}{$val['function']}({$args})
{$path} on line {$val['line']}
'; + return $str; + } function getRegisteredClientScripts() { return implode("\n", $this->jscripts); From 32961d845dca724f528774f0cc4eb98c306a332e Mon Sep 17 00:00:00 2001 From: yama Date: Tue, 5 Mar 2013 14:49:11 +0900 Subject: [PATCH 06/21] Refactor #9583 Refactoring System configuration in manager screen http://tracker.modx.com/issues/9583 --- manager/actions/mutate_settings.dynamic.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/manager/actions/mutate_settings.dynamic.php b/manager/actions/mutate_settings.dynamic.php index cba152973c..586eaddc12 100644 --- a/manager/actions/mutate_settings.dynamic.php +++ b/manager/actions/mutate_settings.dynamic.php @@ -1424,4 +1424,14 @@ function get_lang_options($key=null, $selected_lang=null) { return $lang_options; } } -?> \ No newline at end of file + +function form_radio($name,$value,$checked=false,$add='',$disabled=false) { + if($checked) $checked = ' checked="checked"'; + if($disabled) $disabled = ' disabled'; + if($add) $add = ' ' . $add; + return ''; +} + +function wrap_label($str='',$object) { + return ""; +} From 28c9605cafe36b70a82219a31b93ca7fd077ae12 Mon Sep 17 00:00:00 2001 From: yama Date: Tue, 5 Mar 2013 14:53:09 +0900 Subject: [PATCH 07/21] Feature #9582 Add new config "Detection level of the PHP error" http://tracker.modx.com/issues/9582 --- manager/actions/mutate_settings.dynamic.php | 13 +++++++++++++ manager/includes/document.parser.class.inc.php | 6 +++--- manager/includes/lang/english.inc.php | 9 ++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/manager/actions/mutate_settings.dynamic.php b/manager/actions/mutate_settings.dynamic.php index 586eaddc12..632c4ad359 100644 --- a/manager/actions/mutate_settings.dynamic.php +++ b/manager/actions/mutate_settings.dynamic.php @@ -750,6 +750,19 @@ function confirmLangChange(el, lkey, elupd){
+ + + + + +
+
+
+
+ + + +
config['error_reporting'] || 2<$error_type) { extract($error_info); if($msg===false) $msg = 'ob_get_contents() error'; $result = $this->messageQuit('PHP Parse Error', '', true, $type, $file, 'Plugin', $text, $line, $msg); @@ -819,12 +819,12 @@ function evalSnippet($snippet, $params) { $snip= eval ($snippet); $msg= ob_get_contents(); ob_end_clean(); - if (isset($php_errormsg)) + if ((0<$this->config['error_reporting']) && isset($php_errormsg)) { $error_info = error_get_last(); if($error_info['type']===2048 || $error_info['type']===8192) $error_type = 2; else $error_type = 3; - if(2<$error_type) + if(1<$this->config['error_reporting'] || 2<$error_type) { extract($error_info); if($msg===false) $msg = 'ob_get_contents() error'; diff --git a/manager/includes/lang/english.inc.php b/manager/includes/lang/english.inc.php index 62a1a51c0e..1d5642e922 100755 --- a/manager/includes/lang/english.inc.php +++ b/manager/includes/lang/english.inc.php @@ -1081,4 +1081,11 @@ $_lang["yourinfo_title"] = 'Your info'; $_lang["yourinfo_total_logins"] = 'Total number of logins:'; $_lang["yourinfo_username"] = 'You are logged in as:'; -?> \ No newline at end of file + +$_lang['a17_error_reporting_title'] = 'Detection level of the PHP error'; +$_lang['a17_error_reporting_msg'] = 'Set the detection level of the PHP error.'; +$_lang['a17_error_reporting_opt0'] = 'Ignore all'; +$_lang['a17_error_reporting_opt1'] = 'Ignore the warning of a slight notice level(E_ALL & ~E_NOTICE & ~E_DEPRECATED & ~E_STRICT)'; +$_lang['a17_error_reporting_opt2'] = 'Detect all errors except E_NOTICE'; +$_lang['a17_error_reporting_opt99'] = 'Detect all'; + From 37920216788abf912b7ab387b3eb2ae59d07be33 Mon Sep 17 00:00:00 2001 From: yama Date: Sun, 10 Mar 2013 16:15:26 +0900 Subject: [PATCH 08/21] Use DBAPI --- manager/processors/login.processor.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/manager/processors/login.processor.php b/manager/processors/login.processor.php index ba7deee4ee..c96e4acfe5 100755 --- a/manager/processors/login.processor.php +++ b/manager/processors/login.processor.php @@ -74,7 +74,7 @@ return; } -$row = mysql_fetch_assoc($rs); +$row = $modx->db->getRow($rs); $internalKey = $row['internalKey']; $dbasePassword = $row['password']; @@ -92,7 +92,7 @@ // get the user settings from the database $sql = "SELECT setting_name, setting_value FROM $dbase.`".$table_prefix."user_settings` WHERE user='".$internalKey."' AND setting_value!=''"; $rs = mysql_query($sql); -while ($row = mysql_fetch_assoc($rs)) { +while ($row = $modx->db->getRow($rs)) { ${$row['setting_name']} = $row['setting_value']; } // blocked due to number of login errors. @@ -106,7 +106,7 @@ // blocked due to number of login errors, but get to try again if($failedlogins>=$failed_allowed && $blockeduntildatedb->query($sql); } // this user has been blocked by an admin, so no way he's loggin in! @@ -195,7 +195,7 @@ if($failedlogins>=$failed_allowed) { //block user for too many fail attempts $sql = "update $dbase.`".$table_prefix."user_attributes` SET blockeduntil='".(time()+($blocked_minutes*60))."' where internalKey=$internalKey"; - $rs = mysql_query($sql); + $rs = $modx->db->query($sql); } else { //sleep to help prevent brute force attacks $sleep = (int)$failedlogins/2; @@ -298,4 +298,3 @@ function jsAlert($msg){ echo ""; } } -?> \ No newline at end of file From 05abf6cf8679bf6eb871132de60ea61123ad2fc8 Mon Sep 17 00:00:00 2001 From: yama Date: Sun, 10 Mar 2013 16:17:28 +0900 Subject: [PATCH 09/21] New feature - Add salt string to password --- .../extenders/manager.api.class.inc.php | 93 ++++++++++++++++++- 1 file changed, 90 insertions(+), 3 deletions(-) diff --git a/manager/includes/extenders/manager.api.class.inc.php b/manager/includes/extenders/manager.api.class.inc.php index e86aa9339a..981cbe2a2c 100644 --- a/manager/includes/extenders/manager.api.class.inc.php +++ b/manager/includes/extenders/manager.api.class.inc.php @@ -63,7 +63,94 @@ function clearSavedFormValues(){ unset($_SESSION["mgrFormValueId"]); } + function genHash($password, $seed='1') + { // $seed is user_id basically + global $modx; + + if(isset($modx->config['pwd_hash_algo']) && !empty($modx->config['pwd_hash_algo'])) + $algorithm = $modx->config['pwd_hash_algo']; + else $algorithm = 'UNCRYPT'; + + $salt = md5($password . $seed); + + switch($algorithm) + { + case 'BLOWFISH_Y': + $salt = '$2y$07$' . substr($salt,0,22); + break; + case 'BLOWFISH_A': + $salt = '$2a$07$' . substr($salt,0,22); + break; + case 'SHA512': + $salt = '$6$' . substr($salt,0,16); + break; + case 'SHA256': + $salt = '$5$' . substr($salt,0,16); + break; + case 'MD5': + $salt = '$1$' . substr($salt,0,8); + break; + } + + if($algorithm!=='UNCRYPT') + { + $password = sha1($password) . crypt($password,$salt); + } + else $password = sha1($salt.$password); + + $result = strtolower($algorithm) . '>' . md5($salt.$password) . substr(md5($salt),0,8); + + return $result; + } + + function getUserHashAlgorithm($uid) + { + global $modx; + $tbl_manager_users = $modx->getFullTableName('manager_users'); + $rs = $modx->db->select('*',$tbl_manager_users,"id='{$uid}'"); + $row = $modx->db->getRow($rs); + $password = $row['password']; + + if(strpos($password,'>')===false) $algo = 'NOSALT'; + else + { + $algo = substr($password,0,strpos($password,'>')); + } + return strtoupper($algo); + } + + function checkHashAlgorithm($algorithm='') + { + if(empty($algorithm)) return; + + switch($algorithm) + { + case 'BLOWFISH_Y': + if(defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1) + { + if(version_compare('5.3.7', PHP_VERSION) <= 0) $result = true; + } + break; + case 'BLOWFISH_A': + if(defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH == 1) $result = true; + break; + case 'SHA512': + if(defined('CRYPT_SHA512') && CRYPT_SHA512 == 1) $result = true; + break; + case 'SHA256': + if(defined('CRYPT_SHA256') && CRYPT_SHA256 == 1) $result = true; + break; + case 'MD5': + if(defined('CRYPT_MD5') && CRYPT_MD5 == 1 && PHP_VERSION != '5.3.7') + $result = true; + break; + case 'UNCRYPT': + $result = true; + break; + } + + if(!isset($result)) $result = false; + + return $result; + } } - - -?> \ No newline at end of file From 3107e064fba9673241547482ee5c45417ff0058c Mon Sep 17 00:00:00 2001 From: yama Date: Sun, 10 Mar 2013 18:39:20 +0900 Subject: [PATCH 10/21] Add salt to password --- manager/processors/login.processor.php | 49 ++++++++++++++++--- .../processors/save_password.processor.php | 8 +-- manager/processors/save_user.processor.php | 11 +++-- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/manager/processors/login.processor.php b/manager/processors/login.processor.php index c96e4acfe5..3dfc36689b 100755 --- a/manager/processors/login.processor.php +++ b/manager/processors/login.processor.php @@ -168,12 +168,49 @@ )); // check if plugin authenticated the user -if (!$rt||(is_array($rt) && !in_array(TRUE,$rt))) { - // check user password - local authentication - if($dbasePassword != md5($givenPassword)) { - jsAlert($e->errors[901]); - $newloginerror = 1; - } + +if (!isset($rt)||!$rt||(is_array($rt) && !in_array(TRUE,$rt))) +{ + // check user password - local authentication + $tbl_manager_users = $modx->getFullTableName('manager_users'); + if(strpos($dbasePassword,'>')!==false) + { + if(!isset($modx->config['pwd_hash_algo']) || empty($modx->config['pwd_hash_algo'])) $modx->config['pwd_hash_algo'] = 'UNCRYPT'; + $user_algo = $modx->manager->getUserHashAlgorithm($internalKey); + + if($user_algo !== $modx->config['pwd_hash_algo']) + { + $bk_pwd_hash_algo = $modx->config['pwd_hash_algo']; + $modx->config['pwd_hash_algo'] = $user_algo; + } + + if($dbasePassword != $modx->manager->genHash($givenPassword, $internalKey)) + { + jsAlert($e->errors[901]); + $newloginerror = 1; + } + elseif(isset($bk_pwd_hash_algo)) + { + $modx->config['pwd_hash_algo'] = $bk_pwd_hash_algo; + $field = array(); + $field['password'] = $modx->manager->genHash($givenPassword, $internalKey); + $modx->db->update($field, "{$tbl_manager_users}manager_users", "username='{$username}'"); + } + } + else + { + if($dbasePassword != md5($givenPassword)) + { + jsAlert($e->errors[901]); + $newloginerror = 1; + } + else + { + $field = array(); + $field['password'] = $modx->manager->genHash($givenPassword, $internalKey); + $modx->db->update($field, "{$tbl_manager_users}manager_users", "username='{$username}'"); + } + } } if($use_captcha==1) { diff --git a/manager/processors/save_password.processor.php b/manager/processors/save_password.processor.php index 959d76c57d..fdc4dbb4f3 100755 --- a/manager/processors/save_password.processor.php +++ b/manager/processors/save_password.processor.php @@ -21,9 +21,11 @@ exit; } -$sql = "UPDATE $dbase.`".$table_prefix."manager_users` SET password=md5('".$pass1."') where id=".$modx->getLoginUserID().";"; -$rs = mysql_query($sql); -if(!$rs){ + $tbl_manager_users = $modx->getFullTableName('manager_users'); + $uid = $modx->getLoginUserID(); + $f['password'] = $modx->manager->genHash($pass1, $uid); + $rs = $modx->db->update($f,$tbl_manager_users,"id='{$uid}'"); + if(!$rs){ echo "An error occured while attempting to save the new password."; exit; } diff --git a/manager/processors/save_user.processor.php b/manager/processors/save_user.processor.php index 69eca91d9f..80fbb2480e 100755 --- a/manager/processors/save_user.processor.php +++ b/manager/processors/save_user.processor.php @@ -161,9 +161,12 @@ function generate_password($length = 10) { //get the key by sql } - $sql = "INSERT INTO $dbase.`" . $table_prefix . "user_attributes` (internalKey, fullname, role, email, phone, mobilephone, fax, zip, state, country, gender, dob, photo, comment, blocked, blockeduntil, blockedafter) - VALUES($key, '$fullname', '$roleid', '$email', '$phone', '$mobilephone', '$fax', '$zip', '$state', '$country', '$gender', '$dob', '$photo', '$comment', '$blocked', '$blockeduntil', '$blockedafter');"; - $rs = $modx->db->query($sql); + $field['password'] = $modx->manager->genHash($newpassword, $key); + $modx->db->update($field,'[+prefix+]manager_users',"id='{$key}'"); + + $field = array(); + $field = compact('internalKey','fullname','role','email','phone','mobilephone','fax','zip','state','country','gender','dob','photo','comment','blocked','blockeduntil','blockedafter'); + $rs = $modx->db->insert($field,'[+prefix+]user_attributes'); if (!$rs) { webAlert("An error occurred while attempting to save the user's attributes."); exit; @@ -269,7 +272,7 @@ function generate_password($length = 10) { webAlert("No password generation method specified!"); exit; } - $updatepasswordsql = ", password=MD5('$newpassword') "; + $updatepasswordsql = ", password='" . $modx->manager->genHash($newpassword, $id) . "' "; } if ($passwordnotifymethod == 'e') { sendMailMessage($email, $newusername, $newpassword, $fullname); From 79b3cb5ef3b5780828bed669b5d65af327258f1f Mon Sep 17 00:00:00 2001 From: yama Date: Sun, 10 Mar 2013 19:03:59 +0900 Subject: [PATCH 11/21] Add new system setting "Password hash algorithm" --- manager/actions/mutate_settings.dynamic.php | 34 ++++++++++++++++++++- manager/includes/lang/english.inc.php | 2 ++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/manager/actions/mutate_settings.dynamic.php b/manager/actions/mutate_settings.dynamic.php index 632c4ad359..50aa055459 100644 --- a/manager/actions/mutate_settings.dynamic.php +++ b/manager/actions/mutate_settings.dynamic.php @@ -54,7 +54,9 @@ $settings['rb_base_url'] = $rb_base_url = trim($settings['rb_base_url']) == '' ? 'assets/' : $settings['rb_base_url']; ?> - + - - '; - - // Page output: TV form - if ($save == 0) { - $output .= ' - - '; - - // Document is locked message - if ($locked) { - $output .= ' -

'.$_lang['locked'].'

-
'.$_lang['lock_msg'].'
- '; - } - - // Normal form - else { - // Image preview - if ($tv['type'] == 'image') { - $imagePreview = ' -
- - '; - } - - $output .= ' -
- - - - - -

'.$tv['caption'].'

- -
'.$tv['description'].'
- -
- '.$tvHtml.' -
- - '.$imagePreview.' - -
- '.$editorHtml.' - '; - } - } - - // Page output: close modal box and refresh parent frame - else $output .= ''; - - // Page output: footer - $output .= ' - - - '; - } - - else { - $output = 'Error: Access denied.'; - } - } - - // QM+ with toolbar - else { - - if(isset($_SESSION['mgrValidated']) && $_REQUEST['z'] != 'manprev') { - - // If logout break here - if(isset($_REQUEST['logout'])) { - $this->Logout(); - break; - } - - $userID = $_SESSION['mgrInternalKey']; - //$docID = $this->modx->documentIdentifier; - $doc = $this->modx->getDocument($docID); - - // Edit button - - $editButton = ' -
  • - '.$_lang['edit_resource'].' -
  • - '; - - // Check if user has manager access to current document - $access = $this->checkAccess(); - - // Does user have permissions to edit document - if($access) $controls .= $editButton; - - if ($this->addbutton == 'true' && $access) { - // Add button - $addButton = ' -
  • - '.$_lang['create_resource_here'].' -
  • - '; - - // Does user have permissions to add document - if($this->modx->hasPermission('new_document')) $controls .= $addButton; - } - - // Custom add buttons if not empty and enough permissions - if ($this->custombutton != '') { - - // Replace [*id*] with current doc id - $this->custombutton = str_replace("[*id*]", $docID, $this->custombutton); - - // Handle [~id~] links - $this->custombutton = $this->modx->rewriteUrls($this->custombutton); - - $buttons = explode("||", $this->custombutton); // Buttons are divided by "||" - - // Custom buttons class index - $i = 0; - - // Parse buttons - foreach($buttons as $key => $field) { - $i++; - - $field = substr($field, 1, -1); // Trim "'" from beginning and from end - $buttonParams = explode("','", $field); // Button params are divided by "','" - - $buttonTitle = $buttonParams[0]; - $buttonAction = $buttonParams[1]; // Contains URL if this is not add button - $buttonParentId = $buttonParams[2]; // Is empty is this is not add button - $buttonTplId = $buttonParams[3]; - - // Button visible for all - if ($buttonParams[4] == '') { - $showButton = TRUE; - } - // Button is visible for specific user roles - else { - $showButton = FALSE; - - // Get user roles the button is visible for - $buttonRoles = explode(",", $buttonParams[4]); // Roles are divided by ',' - - // Check if user role is found - foreach($buttonRoles as $key => $field) { - if ($field == $_SESSION['mgrRole']) { - $showButton = TRUE; - } - } - } - - // Show custom button - if ($showButton) { - switch ($buttonAction) - { - case 'new': - $customButton = ' -
  • - '.$buttonTitle.' -
  • - '; - break; - - case 'link': - $customButton = ' -
  • - '.$buttonTitle.' -
  • - '; - break; - - case 'modal': - $customButton = ' -
  • - '.$buttonTitle.' -
  • - '; - break; - } - $controls .= $customButton; - } - } - } - - // Go to Manager button - if ($this->managerbutton == 'true') { - $managerButton = ' -
  • - '.$_lang['manager'].' -
  • - '; - $controls .= $managerButton; - } - - // Logout button - $logout = $this->modx->config['site_url'].'manager/index.php?a=8&quickmanager=logout&logoutid='.$docID; - $logoutButton = ' -
  • - '.$_lang['logout'].' -
  • - '; - $controls .= $logoutButton; - - // Add action buttons - $editor = ' -
    - -
    - -
      -
    • X
    • -
    • - '.$controls.' -
    -
    '; - - $css = ' - - - - '; - - // Autohide toolbar? Default: true - if ($this->autohide == 'false') { - $css .= ' - - '; - } - - // Insert jQuery and ColorBox in head if needed - if ($this->loadfrontendjq == 'true') $head .= ''; - if ($this->loadtb == 'true') { - $head .= ' - - - - - - '; - } - - // Insert ColorBox jQuery definitions for QuickManager+ - $head .= ' - - '; - - // Insert QM+ css in head - $head .= $css; - - // Place QM+ head information in head, just before tag - $output = preg_replace('~()~i', $head . '\1', $output); - - // Insert editor toolbar right after tag - $output = preg_replace('~(]*>)~i', '\1' . $editor, $output); - - // Search and create edit buttons in to the content - if ($this->editbuttons == 'true' && $access) { - $output = preg_replace('//', '$2', $output); - } - - // Search and create new document buttons in to the content - if ($this->newbuttons == 'true' && $access) { - $output = preg_replace('//', '$3', $output); - } - - // Search and create new document buttons in to the content - if ($this->tvbuttons == 'true' && $access) { - // Set and get user doc groups for TV permissions - $this->docGroup = ''; - $mrgDocGroups = $_SESSION['mgrDocgroups']; - if (!empty($mrgDocGroups)) $this->docGroup = implode(",", $mrgDocGroups); - - // Create TV buttons and check TV permissions - $output = preg_replace_callback('//', array(&$this, 'createTvButtons'), $output); - } - } - } - - break; - - // Edit document in ThickBox frame (MODx manager frame) - case 'OnDocFormPrerender': - - // If there is Qm call, add control buttons and modify to edit document page - if (intval($_REQUEST['quickmanager']) == 1) { - - global $content; - - // Set template for new document, action = 4 - if(intval($_GET['a']) == 4) { - - // Custom add button - if (isset($_GET['customaddtplid'])) { - // Set template - $content['template'] = intval($_GET['customaddtplid']); - } - - // Normal add button - else { - switch ($this->tpltype) { - // Template type is parent - case 'parent': - // Get parent document id - $pid = $content['parent'] ? $content['parent'] : intval($_REQUEST['pid']); - - // Get parent document - $parent = $this->modx->getDocument($pid); - - // Set parent template - $content['template'] = $parent['template']; - - break; - - // Template is specific id - case 'id': - $content['template'] = $this->tplid; - - break; - - // Template is inherited by Inherit Selected Template plugin - case 'selected': - // Get parent document id - $pid = $content['parent'] ? $content['parent'] : intval($_REQUEST['pid']); - - // Get inheritTpl TV - $tv = $this->modx->getTemplateVar("inheritTpl", "", $pid); - - // Set template to inherit - if ($tv['value'] != '') $content['template'] = $tv['value']; - else $content['template'] = $this->modx->config['default_template']; - - break; - } - } - } - - // Manager control class - $mc = new Mcc(); - - // Hide default manager action buttons - $mc->addLine('$("#actions").hide();'); - - // Get MODx theme - $qm_theme = $this->modx->config['manager_theme']; - - // Get doc id - $doc_id = intval($_REQUEST['id']); - - // Get jQuery conflict mode - if ($this->noconflictjq == 'true') $jq_mode = '$j'; - else $jq_mode = '$'; - - // Add action buttons - $mc->addLine('var controls = "";'); - - // Modify head - $mc->head = ''; - if ($this->loadmanagerjq == 'true') $mc->head .= ''; - - // Add control button - $mc->addLine('$("body").prepend(controls);'); - - // Hide fields to from front-end editors - if ($this->hidefields != '') { - $hideFields = explode(",", $this->hidefields); - - foreach($hideFields as $key => $field) { - $mc->hideField($field); - } - } - - // Hide tabs to from front-end editors - if ($this->hidetabs != '') { - $hideTabs = explode(",", $this->hidetabs); - - foreach($hideTabs as $key => $field) { - $mc->hideTab($field); - } - } - - // Hide sections from front-end editors - if ($this->hidesections != '') { - $hideSections = explode(",", $this->hidesections); - - foreach($hideSections as $key => $field) { - $mc->hideSection($field); - } - } - - // Hidden field to verify that QM+ call exists - $hiddenFields = ''; - - // Different doc to be refreshed? - if (isset($_REQUEST['qmrefresh'])) { - $hiddenFields .= ''; - } - - // Output - $e->output($mc->Output().$hiddenFields); - } - - break; - - // Where to logout - case 'OnManagerLogout': - // Only if cancel editing the document and QuickManager is in use - if ($_REQUEST['quickmanager'] == 'logout') { - // Redirect to document id - if ($this->logout != 'manager') { - $this->modx->sendRedirect($this->modx->makeUrl($_REQUEST['logoutid']), 0, 'REDIRECT_HEADER', 'HTTP/1.1 301 Moved Permanently'); - } - } - - break; - } - } - - // Check if user has manager access permissions to current document - //_______________________________________________________ - function checkAccess() { - $access = FALSE; - - // If user is admin (role = 1) - if ($_SESSION['mgrRole'] == 1) $access = TRUE; - - else { - $docID = $this->modx->documentIdentifier; - - // Database table - $table= $this->modx->getFullTableName("document_groups"); - - // Check if current document is assigned to one or more doc groups - $sql= "SELECT id FROM {$table} WHERE document={$docID}"; - $result= $this->modx->db->query($sql); - $rowCount= $this->modx->recordCount($result); - - // If document is assigned to one or more doc groups, check access - if ($rowCount >= 1) { - - // Get document groups for current user - $mrgDocGroups = $_SESSION['mgrDocgroups']; - if (!empty($mrgDocGroups)) { - $docGroup = implode(",", $mrgDocGroups); - - // Check if user has access to current document - $sql= "SELECT id FROM {$table} WHERE document = {$docID} AND document_group IN ({$docGroup})"; - $result= $this->modx->db->query($sql); - $rowCount = $this->modx->recordCount($result); - - if ($rowCount >= 1) $access = TRUE; - } - - else $access = FALSE; - } - - else $access = TRUE; - } - - return $access; - } - - // Function from: manager/processors/cache_sync.class.processor.php - //_____________________________________________________ - function getParents($id, $path = '') { // modx:returns child's parent - global $modx; - if(empty($this->aliases)) { - $sql = "SELECT id, IF(alias='', id, alias) AS alias, parent FROM ".$modx->getFullTableName('site_content'); - $qh = $modx->db->query($sql); - if ($qh && $modx->db->getRecordCount($qh) > 0) { - while ($row = $modx->db->getRow($qh)) { - $this->aliases[$row['id']] = $row['alias']; - $this->parents[$row['id']] = $row['parent']; - } - } - } - if (isset($this->aliases[$id])) { - $path = $this->aliases[$id] . ($path != '' ? '/' : '') . $path; - return $this->getParents($this->parents[$id], $path); - } - return $path; - } - - // Create TV buttons if user has permissions to TV - //_____________________________________________________ - function createTvButtons($matches) { - - $access = FALSE; - $table = $this->modx->getFullTableName('site_tmplvar_access'); - $docID = $this->modx->documentIdentifier; - - // Get TV caption for button title - $tv = $this->modx->getTemplateVar($matches[1]); - $caption = $tv['caption']; - - // If caption is empty this must be a "build-in-tv-field" like pagetitle etc. - if ($caption == '') { - - // Allowed for all - $access = TRUE; - - // Resolve caption - $caption = $this->getDefaultTvCaption($matches[1]); - } - - // Check TV access - else { - $access = $this->checkTvAccess($tv['id']); - } - - // Return TV button link if access - if ($access && $caption != '') { - return ''.$caption.''; - } - } - - // Check user access to TV - //_____________________________________________________ - function checkTvAccess($tvId) { - $access = FALSE; - $table = $this->modx->getFullTableName('site_tmplvar_access'); - - // If user is admin (role = 1) - if ($_SESSION['mgrRole'] == 1 && !$access) { $access = TRUE; } - - // Check permission to TV, is TV in document group? - if (!$access) { - $sql = "SELECT id FROM {$table} WHERE tmplvarid = {$tvId}"; - $result = $this->modx->db->query($sql); - $rowCount = $this->modx->recordCount($result); - // TV is not in any document group - if ($rowCount == 0) { $access = TRUE; } - } - - // Check permission to TV, TV is in document group - if (!$access && $this->docGroup != '') { - $sql = "SELECT id FROM {$table} WHERE tmplvarid = {$tvId} AND documentgroup IN ({$this->docGroup})"; - $result = $this->modx->db->query($sql); - $rowCount = $this->modx->recordCount($result); - if ($rowCount >= 1) { $access = TRUE; } - } - - return $access; - } - - // Get default TV ("build-in" TVs) captions - //_____________________________________________________ - function getDefaultTvCaption($name) { - - global $_lang; - $caption = ''; - - switch ($name) { - case 'pagetitle' : $caption = $_lang['resource_title']; break; - case 'longtitle' : $caption = $_lang['long_title']; break; - case 'description' : $caption = $_lang['resource_description']; break; - case 'content' : $caption = $_lang['resource_content']; break; - case 'menutitle' : $caption = $_lang['resource_opt_menu_title']; break; - case 'introtext' : $caption = $_lang['resource_summary']; break; - } - - return $caption; - } - - // Check that a document isn't locked for editing - //_____________________________________________________ - function checkLocked() { - - $activeUsersTable = $this->modx->getFullTableName('active_users'); - $pageId = $this->modx->documentIdentifier; - $locked = TRUE; - $userId = $_SESSION['mgrInternalKey']; - - $sql = "SELECT `internalKey` - FROM {$activeUsersTable} - WHERE (`action` = 27) - AND `internalKey` != '{$userId}' - AND `id` = '{$pageId}';"; - $result = $this->modx->db->query($sql); - - if ($this->modx->db->getRecordCount($result) === 0) { - $locked = FALSE; - } - - return $locked; - } - - // Set document locked on/off - //_____________________________________________________ - function setLocked($locked) { - - $activeUsersTable = $this->modx->getFullTableName('active_users'); - $pageId = $this->modx->documentIdentifier; - $userId = $_SESSION['mgrInternalKey']; - - // Set document locked - if ($locked == 1) { - $fields = array ( - 'id' => $pageId, - 'action' => 27 - ); - } - - // Set document unlocked - else { - $fields = array ( - 'id' => 'NULL', - 'action' => 2 - ); - } - - $where = 'internalKey = "' . $userId . '"'; - - $result = $this->modx->db->update($fields, $activeUsersTable, $where); - } - - // Save TV - //_____________________________________________________ - function saveTv($tvName) { - - $tmplvarContentValuesTable = $this->modx->getFullTableName('site_tmplvar_contentvalues'); - $siteContentTable = $this->modx->getFullTableName('site_content'); - $pageId = $this->modx->documentIdentifier; - $result = null; - $time = time(); - $user = $_SESSION['mgrInternalKey']; - $tvId = isset($_POST['tvid']) ? intval($_POST['tvid']) : ''; - $tvContent = isset($_POST['tv'.$tvName]) ? $_POST['tv'.$tvName] : ''; - $tvContentTemp = ''; - - // Escape TV content - $tvContent = $this->modx->db->escape($tvContent); - - // Invoke OnBeforeDocFormSave event - $this->modx->invokeEvent('OnBeforeDocFormSave', array('mode'=>'upd', 'id'=>$pageId)); - - // Handle checkboxes and other arrays, TV to be saved must be e.g. value1||value2||value3 - if (is_array($tvContent)) { - foreach($tvContent as $key => $value) { - $tvContentTemp .= $value . '||'; - } - $tvContentTemp = substr($tvContentTemp, 0, -2); // Remove last || - $tvContent = $tvContentTemp; - } - - // Save TV - if ($tvId != '') { - $sql = "SELECT id - FROM {$tmplvarContentValuesTable} - WHERE `tmplvarid` = '{$tvId}' - AND `contentid` = '{$pageId}';"; - $result = $this->modx->db->query($sql); - - // TV exists, update TV - if($this->modx->db->getRecordCount($result)) { - - $sql = "UPDATE {$tmplvarContentValuesTable} - SET `value` = '{$tvContent}' - WHERE `tmplvarid` = '{$tvId}' - AND `contentid` = '{$pageId}';"; - } - - // TV does not exist, create new TV - else { - $sql = "INSERT INTO {$tmplvarContentValuesTable} (tmplvarid, contentid, value) - VALUES('{$tvId}', '{$pageId}', '{$tvContent}');"; - } - - // Page edited by - $this->modx->db->update(array('editedon'=>$time, 'editedby'=>$user), $siteContentTable, 'id = "' . $pageId . '"'); - } - - // Save default field, e.g. pagetitle - else { - $sql = "UPDATE {$siteContentTable} - SET - `{$tvName}` = '{$tvContent}', - `editedon` = '{$time}', - `editedby` = '{$user}' - WHERE `id` = '{$pageId}';"; - - } - - // Update TV - if($sql) { $result = $this->modx->db->query($sql); } - - // Log possible errors - if(!$result) { - $this->modx->logEvent(0, 0, "

    Save failed!

    SQL:
    {$sql}
    ", 'QuickManager+'); - } - - // No errors - else { - // Invoke OnDocFormSave event - $this->modx->invokeEvent('OnDocFormSave', array('mode'=>'upd', 'id'=>$pageId)); - - // Clear cache - $this->clearCache(); - } - } - - // Clear cache - //_____________________________________________________ - function clearCache() { - // Clear cache - include_once $this->modx->config['base_path']."manager/processors/cache_sync.class.processor.php"; - $sync = new synccache(); - $sync->setCachepath($this->modx->config['base_path']."assets/cache/"); - $sync->setReport(false); - $sync->emptyCache(); - } - -} -} +modx = $modx; + + // Get plugin parameters + $this->jqpath = $jqpath; + $this->loadmanagerjq = $loadmanagerjq; + $this->loadfrontendjq = $loadfrontendjq; + $this->noconflictjq = $noconflictjq; + $this->loadtb = $loadtb; + $this->tbwidth = $tbwidth; + $this->tbheight = $tbheight; + $this->usemm = $usemm; + $this->hidefields = $hidefields; + $this->hidetabs = $hidetabs; + $this->hidesections = $hidesections; + $this->addbutton = $addbutton; + $this->tpltype = $tpltype; + $this->tplid = $tplid; + $this->custombutton = $custombutton; + $this->managerbutton = $managerbutton; + $this->logout = $logout; + $this->autohide = $autohide; + $this->editbuttons = $editbuttons; + $this->editbclass = $editbclass; + $this->newbuttons = $newbuttons; + $this->newbclass = $newbclass; + $this->tvbuttons = $tvbuttons; + $this->tvbclass = $tvbclass; + + // Includes + include_once($this->modx->config['base_path'].'assets/plugins/qm/mcc.class.php'); + + // Run plugin + $this->Run(); + } + + //_______________________________________________________ + function Run() { + + // Include MODx manager language file + global $_lang; + + // Get manager language + $manager_language = $this->modx->config['manager_language']; + + // Individual user language setting (if set) + $query = 'SELECT setting_name, setting_value FROM '.$this->modx->getFullTableName('user_settings').' WHERE setting_name=\'manager_language\' AND user='.$_SESSION['mgrInternalKey']; + $records = $this->modx->db->query($query); + if ($this->modx->db->getRecordCount($records) > 0) { + $record = $this->modx->db->getRow($records); + $manager_language = $record['setting_value']; + } + + // Include_once the language file + if(!isset($manager_language) || !file_exists(MODX_MANAGER_PATH."includes/lang/".$manager_language.".inc.php")) { + $manager_language = "english"; // if not set, get the english language file. + } + // Include default language + include_once MODX_MANAGER_PATH."includes/lang/english.inc.php"; + + // Include user language + if($manager_language!="english" && file_exists(MODX_MANAGER_PATH."includes/lang/".$manager_language.".inc.php")) { + include_once MODX_MANAGER_PATH."includes/lang/".$manager_language.".inc.php"; + } + + // Get event + $e = &$this->modx->Event; + + // Run plugin based on event + switch ($e->name) { + + // Save document + case 'OnDocFormSave': + + // Saving process for Qm only + if(intval($_REQUEST['quickmanager']) == 1) { + + $id = $e->params['id']; + $key = $id; + + // Normal saving document procedure stops to redirect => Before redirecting secure documents and clear cache + + // Secure web documents - flag as private (code from: manager/processors/save_content.processor.php) + include $this->modx->config['base_path']."manager/includes/secure_web_documents.inc.php"; + secureWebDocument($key); + + // Secure manager documents - flag as private (code from: manager/processors/save_content.processor.php) + include $this->modx->config['base_path']."manager/includes/secure_mgr_documents.inc.php"; + secureMgrDocument($key); + + // Clear cache + $this->clearCache(); + + // Different doc to be refreshed than the one we are editing? + if (isset($_POST['qmrefresh'])) { + $id = intval($_POST['qmrefresh']); + } + + // Redirect to clearer page which refreshes parent window and closes modal box frame + $this->modx->sendRedirect($this->modx->config['base_url'].'index.php?id='.$id.'&quickmanagerclose=1', 0, 'REDIRECT_HEADER', 'HTTP/1.1 301 Moved Permanently'); + } + + break; + + // Display page in front-end + case 'OnWebPagePrerender': + + // Get document id + $docID = $this->modx->documentIdentifier; + + // Get page output + $output = &$this->modx->documentOutput; + + // Close modal box after saving (previously close.php) + if (isset($_GET['quickmanagerclose'])) { + + // Set url to refresh + $url = $this->modx->makeUrl($docID, '', '', 'full'); + + $output = ' + + + + + + + + + + '; + + break; + } + + // QM+ TV edit + if(intval($_GET['quickmanagertv'] == 1) && $_GET['tvname'] != '' && $this->tvbuttons == 'true') { + + $tvName = ''; + $locked = FALSE; + $access = FALSE; + $save = 0; + $imagePreview = ''; + + // Includes + $manager_path = 'manager/'; + include_once($manager_path.'includes/tmplvars.inc.php'); + include_once($manager_path.'includes/tmplvars.commands.inc.php'); + include_once($manager_path.'includes/tmplvars.format.inc.php'); + + // Get save status + if (isset($_POST['save'])) $save = intval($_POST['save']); + + // Get TV name + if (preg_match('/^([^\\"\'\(\)<>!?]+)/i', $_GET['tvname'])) $tvName = $_GET['tvname']; + + // Get TV array + $tv = $this->modx->getTemplateVar($tvName, '*', $docID); + + // Handle default TVs + switch ($tvName) { + case 'pagetitle' : $tv['type'] = 'text'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + case 'longtitle' : $tv['type'] = 'text'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + case 'description' : $tv['type'] = 'text'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + case 'content' : $tv['type'] = 'richtext'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + case 'menutitle' : $tv['type'] = 'text'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + case 'introtext' : $tv['type'] = 'textarea'; $tv['caption'] = $this->getDefaultTvCaption($tvName); $access = TRUE; break; + } + + // Check TV access + if (!$access) { $access = $this->checkTvAccess($tv['id']); } + + // User can access TV + if ($access) { + + // Show TV form + if ($save == 0) { + + // Check is document locked? Someone else is editing the document... //$_lang['lock_msg'] + if ($this->checkLocked()) $locked = TRUE; + + // Set document locked + else $this->setLocked(1); + + // Handle RTE + if($tv['type'] == 'richtext') { + // Invoke OnRichTextEditorInit event + $eventOutput = $this->modx->invokeEvent("OnRichTextEditorInit", array('editor'=>$this->modx->config['which_editor'], 'elements'=>array('tv'.$tvName))); + + if(is_array($eventOutput)) { + $editorHtml = implode("",$eventOutput); + } + } + + // Render TV html + $tvHtml = renderFormElement($tv['type'], $tv['name'], $tv['default_text'], $tv['elements'], $tv['value']); + + // Get jQuery conflict mode + if ($this->noconflictjq == 'true') $jq_mode = '$j'; + else $jq_mode = '$'; + } + + // Save TV + else { + // Remove document locked + $this->setLocked(0); + + // Save TV + $this->saveTv($tvName); + } + + // Page output: header + $output = ' + + + + + + + + + + + '; + + // Page output: TV form + if ($save == 0) { + $output .= ' + + '; + + // Document is locked message + if ($locked) { + $output .= ' +

    '.$_lang['locked'].'

    +
    '.$_lang['lock_msg'].'
    + '; + } + + // Normal form + else { + // Image preview + if ($tv['type'] == 'image') { + $imagePreview = ' +
    + + '; + } + + $output .= ' +
    + + + + + +

    '.$tv['caption'].'

    + +
    '.$tv['description'].'
    + +
    + '.$tvHtml.' +
    + + '.$imagePreview.' + +
    + '.$editorHtml.' + '; + } + } + + // Page output: close modal box and refresh parent frame + else $output .= ''; + + // Page output: footer + $output .= ' + + + '; + } + + else { + $output = 'Error: Access denied.'; + } + } + + // QM+ with toolbar + else { + + if(isset($_SESSION['mgrValidated']) && $_REQUEST['z'] != 'manprev') { + + // If logout break here + if(isset($_REQUEST['logout'])) { + $this->Logout(); + break; + } + + $userID = $_SESSION['mgrInternalKey']; + //$docID = $this->modx->documentIdentifier; + $doc = $this->modx->getDocument($docID); + + // Edit button + + $editButton = ' +
  • + '.$_lang['edit_resource'].' +
  • + '; + + // Check if user has manager access to current document + $access = $this->checkAccess(); + + // Does user have permissions to edit document + if($access) $controls .= $editButton; + + if ($this->addbutton == 'true' && $access) { + // Add button + $addButton = ' +
  • + '.$_lang['create_resource_here'].' +
  • + '; + + // Does user have permissions to add document + if($this->modx->hasPermission('new_document')) $controls .= $addButton; + } + + // Custom add buttons if not empty and enough permissions + if ($this->custombutton != '') { + + // Replace [*id*] with current doc id + $this->custombutton = str_replace("[*id*]", $docID, $this->custombutton); + + // Handle [~id~] links + $this->custombutton = $this->modx->rewriteUrls($this->custombutton); + + $buttons = explode("||", $this->custombutton); // Buttons are divided by "||" + + // Custom buttons class index + $i = 0; + + // Parse buttons + foreach($buttons as $key => $field) { + $i++; + + $field = substr($field, 1, -1); // Trim "'" from beginning and from end + $buttonParams = explode("','", $field); // Button params are divided by "','" + + $buttonTitle = $buttonParams[0]; + $buttonAction = $buttonParams[1]; // Contains URL if this is not add button + $buttonParentId = $buttonParams[2]; // Is empty is this is not add button + $buttonTplId = $buttonParams[3]; + + // Button visible for all + if ($buttonParams[4] == '') { + $showButton = TRUE; + } + // Button is visible for specific user roles + else { + $showButton = FALSE; + + // Get user roles the button is visible for + $buttonRoles = explode(",", $buttonParams[4]); // Roles are divided by ',' + + // Check if user role is found + foreach($buttonRoles as $key => $field) { + if ($field == $_SESSION['mgrRole']) { + $showButton = TRUE; + } + } + } + + // Show custom button + if ($showButton) { + switch ($buttonAction) + { + case 'new': + $customButton = ' +
  • + '.$buttonTitle.' +
  • + '; + break; + + case 'link': + $customButton = ' +
  • + '.$buttonTitle.' +
  • + '; + break; + + case 'modal': + $customButton = ' +
  • + '.$buttonTitle.' +
  • + '; + break; + } + $controls .= $customButton; + } + } + } + + // Go to Manager button + if ($this->managerbutton == 'true') { + $managerButton = ' +
  • + '.$_lang['manager'].' +
  • + '; + $controls .= $managerButton; + } + + // Logout button + $logout = $this->modx->config['site_url'].'manager/index.php?a=8&quickmanager=logout&logoutid='.$docID; + $logoutButton = ' +
  • + '.$_lang['logout'].' +
  • + '; + $controls .= $logoutButton; + + // Add action buttons + $editor = ' +
    + +
    + +
      +
    • X
    • +
    • + '.$controls.' +
    +
    '; + + $css = ' + + + + '; + + // Autohide toolbar? Default: true + if ($this->autohide == 'false') { + $css .= ' + + '; + } + + // Insert jQuery and ColorBox in head if needed + if ($this->loadfrontendjq == 'true') $head .= ''; + if ($this->loadtb == 'true') { + $head .= ' + + + + + + '; + } + + // Insert ColorBox jQuery definitions for QuickManager+ + $head .= ' + + '; + + // Insert QM+ css in head + $head .= $css; + + // Place QM+ head information in head, just before tag + $output = preg_replace('~()~i', $head . '\1', $output); + + // Insert editor toolbar right after tag + $output = preg_replace('~(]*>)~i', '\1' . $editor, $output); + + // Search and create edit buttons in to the content + if ($this->editbuttons == 'true' && $access) { + $output = preg_replace('//', '$2', $output); + } + + // Search and create new document buttons in to the content + if ($this->newbuttons == 'true' && $access) { + $output = preg_replace('//', '$3', $output); + } + + // Search and create new document buttons in to the content + if ($this->tvbuttons == 'true' && $access) { + // Set and get user doc groups for TV permissions + $this->docGroup = ''; + $mrgDocGroups = $_SESSION['mgrDocgroups']; + if (!empty($mrgDocGroups)) $this->docGroup = implode(",", $mrgDocGroups); + + // Create TV buttons and check TV permissions + $output = preg_replace_callback('//', array(&$this, 'createTvButtons'), $output); + } + } + } + + break; + + // Edit document in ThickBox frame (MODx manager frame) + case 'OnDocFormPrerender': + + // If there is Qm call, add control buttons and modify to edit document page + if (intval($_REQUEST['quickmanager']) == 1) { + + global $content; + + // Set template for new document, action = 4 + if(intval($_GET['a']) == 4) { + + // Custom add button + if (isset($_GET['customaddtplid'])) { + // Set template + $content['template'] = intval($_GET['customaddtplid']); + } + + // Normal add button + else { + switch ($this->tpltype) { + // Template type is parent + case 'parent': + // Get parent document id + $pid = $content['parent'] ? $content['parent'] : intval($_REQUEST['pid']); + + // Get parent document + $parent = $this->modx->getDocument($pid); + + // Set parent template + $content['template'] = $parent['template']; + + break; + + // Template is specific id + case 'id': + $content['template'] = $this->tplid; + + break; + + // Template is inherited by Inherit Selected Template plugin + case 'selected': // Template is inherited by Inherit Selected Template plugin + case 'sibling': + // Get parent document id + $pid = $content['parent'] ? $content['parent'] : intval($_REQUEST['pid']); + + if ($this->modx->config['auto_template_logic'] === 'sibling') { + // Eoler: template_autologic in Evolution 1.0.5+ + // http://tracker.modx.com/issues/9586 + $tv = array(); + $sibl = $this->modx->getDocumentChildren($pid, 1, 0, 'template', '', 'menuindex', 'ASC', 1); + if(empty($sibl)) { + $sibl = $this->modx->getDocumentChildren($pid, 0, 0, 'template', '', 'menuindex', 'ASC', 1); + } + if(!empty($sibl)) { + $tv['value'] = $sibl[0]['template']; + } + else $tv['value'] = ''; // Added by yama + } else { + // Get "inheritTpl" TV + $tv = $this->modx->getTemplateVar('inheritTpl', '', $pid); + } + + // Set template to inherit + if ($tv['value'] != '') $content['template'] = $tv['value']; + else $content['template'] = $this->modx->config['default_template']; + break; + } + } + } + + // Manager control class + $mc = new Mcc(); + + // Hide default manager action buttons + $mc->addLine('$("#actions").hide();'); + + // Get MODx theme + $qm_theme = $this->modx->config['manager_theme']; + + // Get doc id + $doc_id = intval($_REQUEST['id']); + + // Get jQuery conflict mode + if ($this->noconflictjq == 'true') $jq_mode = '$j'; + else $jq_mode = '$'; + + // Add action buttons + $mc->addLine('var controls = "";'); + + // Modify head + $mc->head = ''; + if ($this->loadmanagerjq == 'true') $mc->head .= ''; + + // Add control button + $mc->addLine('$("body").prepend(controls);'); + + // Hide fields to from front-end editors + if ($this->hidefields != '') { + $hideFields = explode(",", $this->hidefields); + + foreach($hideFields as $key => $field) { + $mc->hideField($field); + } + } + + // Hide tabs to from front-end editors + if ($this->hidetabs != '') { + $hideTabs = explode(",", $this->hidetabs); + + foreach($hideTabs as $key => $field) { + $mc->hideTab($field); + } + } + + // Hide sections from front-end editors + if ($this->hidesections != '') { + $hideSections = explode(",", $this->hidesections); + + foreach($hideSections as $key => $field) { + $mc->hideSection($field); + } + } + + // Hidden field to verify that QM+ call exists + $hiddenFields = ''; + + // Different doc to be refreshed? + if (isset($_REQUEST['qmrefresh'])) { + $hiddenFields .= ''; + } + + // Output + $e->output($mc->Output().$hiddenFields); + } + + break; + + // Where to logout + case 'OnManagerLogout': + // Only if cancel editing the document and QuickManager is in use + if ($_REQUEST['quickmanager'] == 'logout') { + // Redirect to document id + if ($this->logout != 'manager') { + $this->modx->sendRedirect($this->modx->makeUrl($_REQUEST['logoutid']), 0, 'REDIRECT_HEADER', 'HTTP/1.1 301 Moved Permanently'); + } + } + + break; + } + } + + // Check if user has manager access permissions to current document + //_______________________________________________________ + function checkAccess() { + $access = FALSE; + + // If user is admin (role = 1) + if ($_SESSION['mgrRole'] == 1) $access = TRUE; + + else { + $docID = $this->modx->documentIdentifier; + + // Database table + $table= $this->modx->getFullTableName("document_groups"); + + // Check if current document is assigned to one or more doc groups + $sql= "SELECT id FROM {$table} WHERE document={$docID}"; + $result= $this->modx->db->query($sql); + $rowCount= $this->modx->recordCount($result); + + // If document is assigned to one or more doc groups, check access + if ($rowCount >= 1) { + + // Get document groups for current user + $mrgDocGroups = $_SESSION['mgrDocgroups']; + if (!empty($mrgDocGroups)) { + $docGroup = implode(",", $mrgDocGroups); + + // Check if user has access to current document + $sql= "SELECT id FROM {$table} WHERE document = {$docID} AND document_group IN ({$docGroup})"; + $result= $this->modx->db->query($sql); + $rowCount = $this->modx->recordCount($result); + + if ($rowCount >= 1) $access = TRUE; + } + + else $access = FALSE; + } + + else $access = TRUE; + } + + return $access; + } + + // Function from: manager/processors/cache_sync.class.processor.php + //_____________________________________________________ + function getParents($id, $path = '') { // modx:returns child's parent + global $modx; + if(empty($this->aliases)) { + $sql = "SELECT id, IF(alias='', id, alias) AS alias, parent FROM ".$modx->getFullTableName('site_content'); + $qh = $modx->db->query($sql); + if ($qh && $modx->db->getRecordCount($qh) > 0) { + while ($row = $modx->db->getRow($qh)) { + $this->aliases[$row['id']] = $row['alias']; + $this->parents[$row['id']] = $row['parent']; + } + } + } + if (isset($this->aliases[$id])) { + $path = $this->aliases[$id] . ($path != '' ? '/' : '') . $path; + return $this->getParents($this->parents[$id], $path); + } + return $path; + } + + // Create TV buttons if user has permissions to TV + //_____________________________________________________ + function createTvButtons($matches) { + + $access = FALSE; + $table = $this->modx->getFullTableName('site_tmplvar_access'); + $docID = $this->modx->documentIdentifier; + + // Get TV caption for button title + $tv = $this->modx->getTemplateVar($matches[1]); + $caption = $tv['caption']; + + // If caption is empty this must be a "build-in-tv-field" like pagetitle etc. + if ($caption == '') { + + // Allowed for all + $access = TRUE; + + // Resolve caption + $caption = $this->getDefaultTvCaption($matches[1]); + } + + // Check TV access + else { + $access = $this->checkTvAccess($tv['id']); + } + + // Return TV button link if access + if ($access && $caption != '') { + return ''.$caption.''; + } + } + + // Check user access to TV + //_____________________________________________________ + function checkTvAccess($tvId) { + $access = FALSE; + $table = $this->modx->getFullTableName('site_tmplvar_access'); + + // If user is admin (role = 1) + if ($_SESSION['mgrRole'] == 1 && !$access) { $access = TRUE; } + + // Check permission to TV, is TV in document group? + if (!$access) { + $sql = "SELECT id FROM {$table} WHERE tmplvarid = {$tvId}"; + $result = $this->modx->db->query($sql); + $rowCount = $this->modx->recordCount($result); + // TV is not in any document group + if ($rowCount == 0) { $access = TRUE; } + } + + // Check permission to TV, TV is in document group + if (!$access && $this->docGroup != '') { + $sql = "SELECT id FROM {$table} WHERE tmplvarid = {$tvId} AND documentgroup IN ({$this->docGroup})"; + $result = $this->modx->db->query($sql); + $rowCount = $this->modx->recordCount($result); + if ($rowCount >= 1) { $access = TRUE; } + } + + return $access; + } + + // Get default TV ("build-in" TVs) captions + //_____________________________________________________ + function getDefaultTvCaption($name) { + + global $_lang; + $caption = ''; + + switch ($name) { + case 'pagetitle' : $caption = $_lang['resource_title']; break; + case 'longtitle' : $caption = $_lang['long_title']; break; + case 'description' : $caption = $_lang['resource_description']; break; + case 'content' : $caption = $_lang['resource_content']; break; + case 'menutitle' : $caption = $_lang['resource_opt_menu_title']; break; + case 'introtext' : $caption = $_lang['resource_summary']; break; + } + + return $caption; + } + + // Check that a document isn't locked for editing + //_____________________________________________________ + function checkLocked() { + + $activeUsersTable = $this->modx->getFullTableName('active_users'); + $pageId = $this->modx->documentIdentifier; + $locked = TRUE; + $userId = $_SESSION['mgrInternalKey']; + + $sql = "SELECT `internalKey` + FROM {$activeUsersTable} + WHERE (`action` = 27) + AND `internalKey` != '{$userId}' + AND `id` = '{$pageId}';"; + $result = $this->modx->db->query($sql); + + if ($this->modx->db->getRecordCount($result) === 0) { + $locked = FALSE; + } + + return $locked; + } + + // Set document locked on/off + //_____________________________________________________ + function setLocked($locked) { + + $activeUsersTable = $this->modx->getFullTableName('active_users'); + $pageId = $this->modx->documentIdentifier; + $userId = $_SESSION['mgrInternalKey']; + + // Set document locked + if ($locked == 1) { + $fields = array ( + 'id' => $pageId, + 'action' => 27 + ); + } + + // Set document unlocked + else { + $fields = array ( + 'id' => 'NULL', + 'action' => 2 + ); + } + + $where = 'internalKey = "' . $userId . '"'; + + $result = $this->modx->db->update($fields, $activeUsersTable, $where); + } + + // Save TV + //_____________________________________________________ + function saveTv($tvName) { + + $tmplvarContentValuesTable = $this->modx->getFullTableName('site_tmplvar_contentvalues'); + $siteContentTable = $this->modx->getFullTableName('site_content'); + $pageId = $this->modx->documentIdentifier; + $result = null; + $time = time(); + $user = $_SESSION['mgrInternalKey']; + $tvId = isset($_POST['tvid']) ? intval($_POST['tvid']) : ''; + $tvContent = isset($_POST['tv'.$tvName]) ? $_POST['tv'.$tvName] : ''; + $tvContentTemp = ''; + + // Escape TV content + $tvContent = $this->modx->db->escape($tvContent); + + // Invoke OnBeforeDocFormSave event + $this->modx->invokeEvent('OnBeforeDocFormSave', array('mode'=>'upd', 'id'=>$pageId)); + + // Handle checkboxes and other arrays, TV to be saved must be e.g. value1||value2||value3 + if (is_array($tvContent)) { + foreach($tvContent as $key => $value) { + $tvContentTemp .= $value . '||'; + } + $tvContentTemp = substr($tvContentTemp, 0, -2); // Remove last || + $tvContent = $tvContentTemp; + } + + // Save TV + if ($tvId != '') { + $sql = "SELECT id + FROM {$tmplvarContentValuesTable} + WHERE `tmplvarid` = '{$tvId}' + AND `contentid` = '{$pageId}';"; + $result = $this->modx->db->query($sql); + + // TV exists, update TV + if($this->modx->db->getRecordCount($result)) { + + $sql = "UPDATE {$tmplvarContentValuesTable} + SET `value` = '{$tvContent}' + WHERE `tmplvarid` = '{$tvId}' + AND `contentid` = '{$pageId}';"; + } + + // TV does not exist, create new TV + else { + $sql = "INSERT INTO {$tmplvarContentValuesTable} (tmplvarid, contentid, value) + VALUES('{$tvId}', '{$pageId}', '{$tvContent}');"; + } + + // Page edited by + $this->modx->db->update(array('editedon'=>$time, 'editedby'=>$user), $siteContentTable, 'id = "' . $pageId . '"'); + } + + // Save default field, e.g. pagetitle + else { + $sql = "UPDATE {$siteContentTable} + SET + `{$tvName}` = '{$tvContent}', + `editedon` = '{$time}', + `editedby` = '{$user}' + WHERE `id` = '{$pageId}';"; + + } + + // Update TV + if($sql) { $result = $this->modx->db->query($sql); } + + // Log possible errors + if(!$result) { + $this->modx->logEvent(0, 0, "

    Save failed!

    SQL:
    {$sql}
    ", 'QuickManager+'); + } + + // No errors + else { + // Invoke OnDocFormSave event + $this->modx->invokeEvent('OnDocFormSave', array('mode'=>'upd', 'id'=>$pageId)); + + // Clear cache + $this->clearCache(); + } + } + + // Clear cache + //_____________________________________________________ + function clearCache() { + // Clear cache + include_once $this->modx->config['base_path']."manager/processors/cache_sync.class.processor.php"; + $sync = new synccache(); + $sync->setCachepath($this->modx->config['base_path']."assets/cache/"); + $sync->setReport(false); + $sync->emptyCache(); + } + +} +} ?> \ No newline at end of file From 3dd3be78f4a567589072594c4d51f37b5833b00b Mon Sep 17 00:00:00 2001 From: yama Date: Sun, 10 Mar 2013 21:07:42 +0900 Subject: [PATCH 13/21] Refactor #9568 @Bindings enable/disable option in System configuration http://tracker.modx.com/issues/9568 --- install/setup.sql | 3 ++- manager/actions/mutate_settings.dynamic.php | 11 +++++++++++ manager/includes/lang/english.inc.php | 3 +++ manager/includes/tmplvars.commands.inc.php | 7 +++++-- manager/includes/tmplvars.inc.php | 10 +++++----- 5 files changed, 26 insertions(+), 8 deletions(-) diff --git a/install/setup.sql b/install/setup.sql index a87a757bba..79794fa7b0 100755 --- a/install/setup.sql +++ b/install/setup.sql @@ -965,7 +965,8 @@ INSERT IGNORE INTO `{PREFIX}system_settings` ('automatic_alias','1'), ('datetime_format','dd-mm-YYYY'), ('warning_visibility', '1'), -('remember_last_tab', '0'); +('remember_last_tab', '0'), +('enable_bindings', '1'); REPLACE INTO `{PREFIX}user_roles` diff --git a/manager/actions/mutate_settings.dynamic.php b/manager/actions/mutate_settings.dynamic.php index 50aa055459..e86dfb1275 100644 --- a/manager/actions/mutate_settings.dynamic.php +++ b/manager/actions/mutate_settings.dynamic.php @@ -795,6 +795,17 @@ function confirmLangChange(el, lkey, elupd){
    + + + + +
    +
    + + + + +
    @Bindings commands. Describe any command in the entry field (template variable) on the contribution screen and carry out this function. When manage a site in plural members because the practice of the PHP sentence is possible, attention is necessary for the use of this function.'; diff --git a/manager/includes/tmplvars.commands.inc.php b/manager/includes/tmplvars.commands.inc.php index 0a5487362c..74e5fe1e3a 100755 --- a/manager/includes/tmplvars.commands.inc.php +++ b/manager/includes/tmplvars.commands.inc.php @@ -14,13 +14,16 @@ 'DIRECTORY' ); -function ProcessTVCommand($value, $name = '', $docid = '') { +function ProcessTVCommand($value, $name = '', $docid = '', $src='docform') { global $modx; $etomite = & $modx; $docid = intval($docid) ? intval($docid) : $modx->documentIdentifier; $nvalue = trim($value); if (substr($nvalue, 0, 1) != '@') return $value; + elseif(isset($modx->config['enable_bindings']) && $modx->config['enable_bindings']!=1 && $src==='docform') { + return '@Bindings is disabled.'; + } else { list ($cmd, $param) = ParseCommand($nvalue); $cmd = trim($cmd); @@ -115,7 +118,7 @@ function ProcessTVCommand($value, $name = '', $docid = '') { } // support for nested bindings - return is_string($output) && ($output != $value) ? ProcessTVCommand($output, $name, $docid) : $output; + return is_string($output) && ($output != $value) ? ProcessTVCommand($output, $name, $docid, $src) : $output; } } diff --git a/manager/includes/tmplvars.inc.php b/manager/includes/tmplvars.inc.php index 792c0dd26e..b35ab1e082 100755 --- a/manager/includes/tmplvars.inc.php +++ b/manager/includes/tmplvars.inc.php @@ -43,7 +43,7 @@ function renderFormElement($field_type, $field_id, $default_text, $field_element break; case "dropdown": // handler for select boxes $field_html .= ''; - $index_list = ParseIntputOptions(ProcessTVCommand($field_elements, $field_id)); + $index_list = ParseIntputOptions(ProcessTVCommand($field_elements, $field_id,'','tvform')); while (list($item, $itemvalue) = each ($index_list)) { list($item,$itemvalue) = (is_array($itemvalue)) ? $itemvalue : explode("==",$itemvalue); @@ -66,7 +66,7 @@ function renderFormElement($field_type, $field_id, $default_text, $field_element case "listbox-multiple": // handler for select boxes where you can choose multiple items $field_value = explode("||",$field_value); $field_html .= ' read()) { if (strpos($file, ".inc.php") > 0) { From 6016767bfe2344683220efa07c5dc82bff4b2577 Mon Sep 17 00:00:00 2001 From: yama Date: Mon, 11 Mar 2013 01:02:13 +0900 Subject: [PATCH 15/21] Refactor #9617 Refactoring backup manage --- manager/actions/bkmanager.static.php | 585 ++++++++++++++++++++------ manager/includes/lang/english.inc.php | 16 + 2 files changed, 470 insertions(+), 131 deletions(-) diff --git a/manager/actions/bkmanager.static.php b/manager/actions/bkmanager.static.php index a76fcb0eb2..135464ad92 100644 --- a/manager/actions/bkmanager.static.php +++ b/manager/actions/bkmanager.static.php @@ -1,51 +1,53 @@ INCLUDE_ORDERING_ERROR

    Please use the MODx Content Manager instead of accessing this file directly."); +if(!defined('IN_MANAGER_MODE') || IN_MANAGER_MODE != 'true') exit(); if(!$modx->hasPermission('bk_manager')) { $e->setError(3); $e->dumpError(); } -if ($manager_theme) - $manager_theme .= '/'; -else $manager_theme = ''; +$dbase = trim($dbase,'`'); -// Get table names (alphabetical) -$tbl_event_log = $modx->getFullTableName('event_log'); +if(!isset($modx->config['snapshot_path'])) +{ + if(is_dir(MODX_BASE_PATH . 'temp/backup/')) $modx->config['snapshot_path'] = MODX_BASE_PATH . 'temp/backup/'; + else $modx->config['snapshot_path'] = MODX_BASE_PATH . 'assets/backup/'; +} // Backup Manager by Raymond: $mode = isset($_POST['mode']) ? $_POST['mode'] : ''; -function callBack(&$dumpstring) { - $today = date("d_M_y"); - $today = strtolower($today); - if(!headers_sent()) { - header('Expires: 0'); - header('Cache-Control: private'); - header('Pragma: cache'); - header('Content-type: application/download'); - header('Content-Disposition: attachment; filename='.$today.'_database_backup.sql'); +if ($mode=='restore1') +{ + if(isset($_POST['textarea']) && !empty($_POST['textarea'])) + { + $source = trim($_POST['textarea']); + $_SESSION['textarea'] = $source . "\n"; } - echo $dumpstring; - return true; + else + { + $source = file_get_contents($_FILES['sqlfile']['tmp_name']); + } + import_sql($source); + header('Location: index.php?r=9&a=93'); + exit; } - -function nicesize($size) { - $a = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); - - $pos = 0; - while ($size >= 1024) { - $size /= 1024; - $pos++; +elseif ($mode=='restore2') +{ + $path = $modx->config['snapshot_path'] . $_POST['filename']; + if(file_exists($path)) + { + $source = file_get_contents($path); + import_sql($source); + header('Location: index.php?r=9&a=93'); } - if ($size==0) - return '-'; - else return round($size,2).' '.$a[$pos]; + exit; } - -if ($mode=='backup') { +elseif ($mode=='backup') +{ $tables = isset($_POST['chk']) ? $_POST['chk'] : ''; - if (!is_array($tables)) { + if (!is_array($tables)) + { echo ''. ''. ''; @@ -58,25 +60,109 @@ function nicesize($size) { * Perform MySQLdumper data dump */ @set_time_limit(120); // set timeout limit to 2 minutes - $dbname = str_replace('`', '', $dbase); - $dumper = new Mysqldumper($database_server, $database_user, $database_password, $dbname); + $dumper = new Mysqldumper($database_server, $database_user, $database_password, $dbase); $dumper->setDBtables($tables); $dumper->setDroptables((isset($_POST['droptables']) ? true : false)); $dumpfinished = $dumper->createDump('callBack'); - if($dumpfinished) { + if($dumpfinished) + { exit; - } else { + } + else + { $e->setError(1, 'Unable to Backup Database'); $e->dumpError(); exit; } // MySQLdumper class can be found below -} else { +} +elseif ($mode=='snapshot') +{ + if(!is_dir(rtrim($modx->config['snapshot_path'],'/'))) + { + mkdir(rtrim($modx->config['snapshot_path'],'/')); + @chmod(rtrim($modx->config['snapshot_path'],'/'), 0777); + } + if(!file_exists("{$modx->config['snapshot_path']}.htaccess")) + { + $htaccess = "order deny,allow\ndeny from all\n"; + file_put_contents("{$modx->config['snapshot_path']}.htaccess",$htaccess); + } + if(!is_writable(rtrim($modx->config['snapshot_path'],'/'))) + { + echo parsePlaceholder($_lang["bkmgr_alert_mkdir"],$modx->config['snapshot_path']); + exit; + } + $escaped_table_prefix = str_replace('_', '\\_', $table_prefix); + $sql = "SHOW TABLE STATUS FROM `{$dbase}` LIKE '{$escaped_table_prefix}%'"; + $rs = $modx->db->query($sql); + $tables = array(); + if(0<$modx->db->getRecordCount($rs)) + { + while($db_status = $modx->db->getRow($rs)) + { + $tables[] = $db_status['Name']; + } + } + $today = $modx->toDateFormat(time()); + $today = str_replace(array('/',' '), '-', $today); + $today = str_replace(':', '', $today); + $today = strtolower($today); + global $path; + $path = "{$modx->config['snapshot_path']}{$today}.sql"; + + @set_time_limit(120); // set timeout limit to 2 minutes + $dumper = new Mysqldumper($database_server, $database_user, $database_password, $dbase); + $dumper->setDBtables($tables); + $dumper->setDroptables(true); + $dumpfinished = $dumper->createDump('snapshot'); + + $pattern = "{$modx->config['snapshot_path']}*.sql"; + $files = glob($pattern,GLOB_NOCHECK); + $total = ($files[0] !== $pattern) ? count($files) : 0; + arsort($files); + while(10 < $total && $limit < 50) + { + $del_file = array_pop($files); + unlink($del_file); + $total = count($files); + $limit++; + } + + if($dumpfinished) + { + $_SESSION['result_msg'] = 'snapshot_ok'; + header("Location: index.php?a=93"); + exit; + } else { + $e->setError(1, 'Unable to Backup Database'); + $e->dumpError(); + exit; + } +} +else +{ include_once "header.inc.php"; // start normal header } +if(isset($_SESSION['result_msg']) && $_SESSION['result_msg'] != '') +{ + switch($_SESSION['result_msg']) + { + case 'import_ok': + $ph['result_msg'] = '
    ' . $_lang["bkmgr_import_ok"] . '
    '; + break; + case 'snapshot_ok': + $ph['result_msg'] = '
    ' . $_lang["bkmgr_snapshot_ok"] . '
    '; + break; + } + $_SESSION['result_msg'] = ''; +} +else $ph['result_msg'] = ''; + ?> +

    -
    +
    + +
    +
    +
    + +
    +

    +

    -

    -

    +

    +

    - - - - - - - + + + + + + + + db->query($sql); +$limit = $modx->db->getRecordCount($rs); for ($i = 0; $i < $limit; $i++) { - $db_status = mysql_fetch_assoc($rs); + $db_status = $modx->db->getRow($rs); $bgcolor = ($i % 2) ? '#EEEEEE' : '#FFFFFF'; if (isset($tables)) @@ -128,50 +228,47 @@ function submitForm(){ else $table_string = ''; echo ''."\n". - "\t\t\t\t".''."\n". - "\t\t\t\t".''."\n"; + ''."\n". + ''."\n"; + echo ''."\n"; // Enable record deletion for certain tables (TRUNCATE TABLE) if they're not already empty $truncateable = array( $table_prefix.'event_log', - $table_prefix.'log_access', // should these three - $table_prefix.'log_hosts', // be deleted? - sirlancelot (2008-02-26) - $table_prefix.'log_visitors', // $table_prefix.'manager_log', ); if($modx->hasPermission('settings') && in_array($db_status['Name'], $truncateable) && $db_status['Rows'] > 0) { - echo "\t\t\t\t".''."\n"; } else { - echo "\t\t\t\t".''."\n"; + echo ''."\n"; } if($modx->hasPermission('settings')) { - echo "\t\t\t\t".''."\n"; } else { - echo ''."\n"; + echo ''."\n"; } - echo "\t\t\t\t".''."\n". - "\t\t\t\t".''."\n". - "\t\t\t\t".''."\n". - "\t\t\t"; + echo ''."\n". + ''."\n". + ''."\n". + ""; $total = $total+$db_status['Index_length']+$db_status['Data_length']; $totaloverhead = $totaloverhead+$db_status['Data_free']; } ?> - + + - - - +
    '.$db_status['Name'].''.$db_status['Rows'].''.$db_status['Rows'].''.$db_status['Collation'].''. - ''.nicesize($db_status['Data_length']+$db_status['Data_free']).''. + echo ''. + ''.$modx->nicesize($db_status['Data_length']+$db_status['Data_free']).''. ''.nicesize($db_status['Data_length']+$db_status['Data_free']).''.$modx->nicesize($db_status['Data_length']+$db_status['Data_free']).''.($db_status['Data_free'] > 0 ? - ''.nicesize($db_status['Data_free']).'' : + echo ''.($db_status['Data_free'] > 0 ? + ''.$modx->nicesize($db_status['Data_free']).'' : '-'). ''.($db_status['Data_free'] > 0 ? nicesize($db_status['Data_free']) : '-').''.($db_status['Data_free'] > 0 ? $modx->nicesize($db_status['Data_free']) : '-').''.nicesize($db_status['Data_length']-$db_status['Data_free']).''.nicesize($db_status['Index_length']).''.nicesize($db_status['Index_length']+$db_status['Data_length']+$db_status['Data_free']).'
    '.$modx->nicesize($db_status['Data_length']-$db_status['Data_free']).''.$modx->nicesize($db_status['Index_length']).''.$modx->nicesize($db_status['Index_length']+$db_status['Data_length']+$db_status['Data_free']).'
     0 ? ''.$modx->nicesize($totaloverhead).'
    ('.number_format($totaloverhead).' B)' : '-'?>
     0 ? ''.nicesize($totaloverhead).'
    ('.number_format($totaloverhead).' B)' : '-'?>
     ".nicesize($total)."
    (".number_format($total)." B)"?>
    ".$modx->nicesize($total)."
    (".number_format($total)." B)"?>
    @@ -184,8 +281,160 @@ function submitForm(){
    +
    +

    + + + + + + + +$v) + { + $title[] = $k; + } + $result = '' . join('',$title) . ''; + foreach($last_result as $row) + { + $result_value = array(); + if($row) + { + foreach($row as $k=>$v) + { + $result_value[] = $v; + } + $result .= '' . join('',$result_value) . ''; + } + } + $style = ''; + $result = $style . '' . $result . '
    '; + } +} + +function checked($cond) +{ + if($cond) return ' checked'; +} +?> +

    + + +

    +
    +
    + +
    +
    + icons_save" /> +
    + + +

    ' . $result . '
    '; +?> +
    + +
    +

    + + + "snapshot_path={$modx->config['snapshot_path']}"));?> +
    + + +
    + icons_save" /> + + +
    + +
    +
    +
    + + + +config['snapshot_path']}*.sql"; +$files = glob($pattern,GLOB_NOCHECK); +$total = ($files[0] !== $pattern) ? count($files) : 0; +if(is_array($files) && 0 < $total) +{ + echo '
      '; + arsort($files); + $tpl = '
    • [+filename+] ([+filesize+]) (' . $_lang["bkmgr_restore_submit"] . ')
    • ' . "\n"; + while ($file = array_shift($files)) + { + $filename = substr($file,strrpos($file,'/')+1); + $filesize = $modx->nicesize(filesize($file)); + echo str_replace(array('[+filename+]','[+filesize+]'),array($filename,$filesize),$tpl); + } + echo '
    '; +} +else +{ + echo $_lang["bkmgr_snapshot_nothing"]; +} +?> + +
    +
    +
    + +
    - + + + setHost($host); - $this->setDBuser($dbuser); - $this->setDBpassword($dbpassword); - $this->setDBname($dbname); - $this->setDBcharset($connection_charset); - $this->setDBconnectionMethod($connection_method); + var $database_server; + var $dbname; + + function Mysqldumper($database_server, $database_user, $database_password, $dbname) { // Don't drop tables by default. + $this->dbname = $dbname; $this->setDroptables(false); } - function getDBconnectionMethod() { return $this->_dbconnectionmethod; } - function getDBcharset() { return $this->_dbcharset; } - function getDBname() { return $this->_dbname; } - function getDBpassword() { return $this->_dbpassword; } - function getDBuser() { return $this->_dbuser; } - function getHost() { return $this->_host; } - - function setDBconnectionMethod($connection_method) { $this->_dbconnectionmethod = (isset($GLOBALS['database_connection_method']) ? $GLOBALS['database_connection_method'] : $connection_method); } - function setDBcharset($dbcharset) { $this->_dbcharset = $dbcharset; } - function setDBname($dbname) { $this->_dbname = $dbname; } - function setDBpassword($dbpassword) { $this->_dbpassword = $dbpassword; } - function setDBuser($dbuser) { $this->_dbuser = $dbuser; } - function setHost($host) { $this->_host = $host; } - function setDBtables($dbtables) { $this->_dbtables = $dbtables; } // If set to true, it will generate 'DROP TABLE IF EXISTS'-statements for each table. @@ -242,67 +468,61 @@ function setDroptables($state) { $this->_isDroptables = $state; } function isDroptables() { return $this->_isDroptables; } function createDump($callBack) { - global $site_name,$full_appname; + global $modx; // Set line feed $lf = "\n"; - $resource = mysql_connect($this->getHost(), $this->getDBuser(), $this->getDBpassword()); - mysql_select_db($this->getDBname(), $resource); - $database_connection_method = $this->getDBconnectionMethod(); - $database_connection_charset = $this->getDBcharset(); - @mysql_query("{$database_connection_method} {$database_connection_charset}"); - $result = mysql_query("SHOW TABLES",$resource); + $result = $modx->db->query('SHOW TABLES'); $tables = $this->result2Array(0, $result); foreach ($tables as $tblval) { - $result = mysql_query("SHOW CREATE TABLE `$tblval`"); + $result = $modx->db->query("SHOW CREATE TABLE `{$tblval}`"); $createtable[$tblval] = $this->result2Array(1, $result); } // Set header - $output = "#". $lf; - $output .= "# ".addslashes($site_name)." Database Dump" . $lf; - $output .= "# ".$full_appname.$lf; - $output .= "# ". $lf; - $output .= "# Host: " . $this->getHost() . $lf; - $output .= "# Generation Time: " . date("M j, Y at H:i") . $lf; - $output .= "# Server version: ". mysql_get_server_info() . $lf; + $output = "#{$lf}"; + $output .= "# ".addslashes($modx->config['site_name'])." Database Dump{$lf}"; + $output .= "# MODX Version:{$modx->config['settings_version']}{$lf}"; + $output .= "# {$lf}"; + $output .= "# Host: {$this->database_server}{$lf}"; + $output .= "# Generation Time: " . $modx->toDateFormat(time()) . $lf; + $output .= "# Server version: ". $modx->db->getVersion() . $lf; $output .= "# PHP Version: " . phpversion() . $lf; - $output .= "# Database : `" . $this->getDBname() . "`" . $lf; + $output .= "# Database : `{$this->dbname}`{$lf}"; $output .= "#"; // Generate dumptext for the tables. if (isset($this->_dbtables) && count($this->_dbtables)) { - $this->_dbtables = implode(",",$this->_dbtables); + $this->_dbtables = implode(',',$this->_dbtables); } else { unset($this->_dbtables); } foreach ($tables as $tblval) { // check for selected table if(isset($this->_dbtables)) { - if (strstr(",".$this->_dbtables.",",",$tblval,")===false) { + if (strstr(",{$this->_dbtables},",",{$tblval},")===false) { continue; } } - $output .= $lf . $lf . "# --------------------------------------------------------" . $lf . $lf; - $output .= "#". $lf . "# Table structure for table `$tblval`" . $lf; - $output .= "#" . $lf . $lf; + $output .= "{$lf}{$lf}# --------------------------------------------------------{$lf}{$lf}"; + $output .= "#{$lf}# Table structure for table `{$tblval}`{$lf}"; + $output .= "#{$lf}{$lf}"; // Generate DROP TABLE statement when client wants it to. if($this->isDroptables()) { - $output .= "DROP TABLE IF EXISTS `$tblval`;" . $lf; + $output .= "DROP TABLE IF EXISTS `{$tblval}`;{$lf}"; } - $output .= $createtable[$tblval][0].";" . $lf; + $output .= "{$createtable[$tblval][0]};{$lf}"; $output .= $lf; - $output .= "#". $lf . "# Dumping data for table `$tblval`". $lf . "#" . $lf; - $result = mysql_query("SELECT * FROM `$tblval`"); - $rows = $this->loadObjectList("", $result); + $output .= "#{$lf}# Dumping data for table `{$tblval}`{$lf}#{$lf}"; + $result = $modx->db->select('*',$tblval); + $rows = $this->loadObjectList('', $result); foreach($rows as $row) { $insertdump = $lf; - $insertdump .= "INSERT INTO `$tblval` VALUES ("; + $insertdump .= "INSERT INTO `{$tblval}` VALUES ("; $arr = $this->object2Array($row); foreach($arr as $key => $value) { $value = addslashes($value); - $value = str_replace("\n", '\\r\\n', $value); - $value = str_replace("\r", '', $value); + $value = str_replace(array("\r\n","\r","\n"), '\\n', $value); $insertdump .= "'$value',"; } $output .= rtrim($insertdump,',') . ");"; @@ -310,10 +530,9 @@ function createDump($callBack) { // invoke callback -- raymond if ($callBack) { if (!$callBack($output)) break; - $output = ""; + $output = ''; } } - mysql_close($resource); return ($callBack) ? true: $output; } @@ -354,4 +573,108 @@ function result2Array($numinarray = 0, $resource) { } } -?> \ No newline at end of file +function import_sql($source,$result_code='import_ok') +{ + global $modx,$e; + + $tbl_active_users = $modx->getFullTableName('active_users'); + $rs = $modx->db->select('*',$tbl_active_users,"action='27'"); + if(0 < $modx->db->getRecordCount($rs)) + { + echo ''. + ''. + ''; + exit; + } + + $settings = getSettings(); + + $source = str_replace(array("\r\n","\n","\r"),"\n",$source); + $sql_array = preg_split('@;[ \t]*\n@', $source); + foreach($sql_array as $sql_entry) + { + $sql_entry = trim($sql_entry, "\r\n; "); + if(empty($sql_entry)) continue; + $rs = $modx->db->query($sql_entry); + } + restoreSettings($settings); + + $modx->clearCache(); + if(0 < $modx->db->getRecordCount($rs)) + { + while($row = $modx->db->getRow($rs)) + { + $_SESSION['last_result'][] = $row; + } + } + + $_SESSION['result_msg'] = $result_code; +} + +function callBack(&$dumpstring) { + global $modx; + $today = $modx->toDateFormat(time(),'dateOnly'); + $today = str_replace('/', '-', $today); + $today = strtolower($today); + if(!headers_sent()) { + header('Expires: 0'); + header('Cache-Control: private'); + header('Pragma: cache'); + header('Content-type: application/download'); + header("Content-Disposition: attachment; filename={$today}_database_backup.sql"); + } + echo $dumpstring; + return true; +} + +function snapshot(&$dumpstring) { + global $path; + file_put_contents($path,$dumpstring,FILE_APPEND); + return true; +} + +function getSettings() +{ + global $modx; + + $tbl_system_settings = $modx->getFullTableName('system_settings'); + $rs = $modx->db->select('setting_name, setting_value',$tbl_system_settings); + + $settings = array(); + while ($row = $modx->db->getRow($rs)) + { + switch($row['setting_name']) + { + case 'rb_base_dir': + case 'filemanager_path': + case 'site_url': + case 'base_url': + $settings[$row['setting_name']] = $row['setting_value']; + break; + } + } + return $settings; +} + +function restoreSettings($settings) +{ + global $modx; + + $tbl_system_settings = $modx->getFullTableName('system_settings'); + foreach($settings as $k=>$v) + { + $modx->db->update(array('setting_value'=>$v),$tbl_system_settings,"setting_name='{$k}'"); + } +} + +function parsePlaceholder($tpl='', $ph=array()) +{ + if(empty($ph) || empty($tpl)) return $tpl; + + foreach($ph as $k=>$v) + { + $k = "[+{$k}+]"; + $tpl = str_replace($k, $v, $tpl); + } + return $tpl; +} diff --git a/manager/includes/lang/english.inc.php b/manager/includes/lang/english.inc.php index 83a4d0664c..73d94026ba 100755 --- a/manager/includes/lang/english.inc.php +++ b/manager/includes/lang/english.inc.php @@ -1094,3 +1094,19 @@ $_lang["enable_bindings_title"] = 'Enable @Bindings commands'; $_lang['enable_bindings_message'] = 'Enable @Bindings commands. Describe any command in the entry field (template variable) on the contribution screen and carry out this function. When manage a site in plural members because the practice of the PHP sentence is possible, attention is necessary for the use of this function.'; + +$_lang["bkmgr_alert_mkdir"] = 'A file cannot be created in a directory. Please check the permission of [+snapshot_path+]'; +$_lang["bkmgr_restore_msg"] = '

    A site can be restore using an SQL file.

    '; +$_lang["bkmgr_restore_title"] = 'Restore'; +$_lang["bkmgr_import_ok"] = 'SQL recovery was performed normally.'; +$_lang["bkmgr_snapshot_ok"] = 'The snapshot was saved normally.'; +$_lang["bkmgr_run_sql_file_label"] = 'Execute by sql file'; +$_lang["bkmgr_run_sql_direct_label"] = 'Direct execute SQL command strings'; +$_lang["bkmgr_run_sql_submit"] = 'Execute restore'; +$_lang["bkmgr_run_sql_result"] = 'Result'; +$_lang["bkmgr_snapshot_title"] = 'Snapshot save and recovery'; +$_lang["bkmgr_snapshot_msg"] = '

    The contents of the database are saved and restored to a server.
    Preservation place : [+snapshot_path+] ($modx->config[\'snapshot_path\'])

    '; +$_lang["bkmgr_snapshot_submit"] = 'Add snapshot'; +$_lang["bkmgr_snapshot_list_title"] = 'List of snapshot'; +$_lang["bkmgr_restore_submit"] = 'Revert this data'; +$_lang["bkmgr_snapshot_nothing"] = 'No snapshot'; From ef7366ccbe5a587d83d10269a40f15fff785431b Mon Sep 17 00:00:00 2001 From: yama Date: Mon, 11 Mar 2013 01:05:16 +0900 Subject: [PATCH 16/21] Feature #9615 Add new function for documentParser "$modx->nicesize()" --- manager/includes/document.parser.class.inc.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/manager/includes/document.parser.class.inc.php b/manager/includes/document.parser.class.inc.php index 6e1db36aca..af8962e5d1 100755 --- a/manager/includes/document.parser.class.inc.php +++ b/manager/includes/document.parser.class.inc.php @@ -2960,6 +2960,15 @@ function stripAlias($alias) { } } + function nicesize($size) { + $a = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); + $pos = 0; + while ($size >= 1024) { + $size /= 1024; + $pos++; + } + return round($size,2).' '.$a[$pos]; + } // End of class. From 6c73d87d955c995c6f9e5284dec508e3d905d6b2 Mon Sep 17 00:00:00 2001 From: yama Date: Mon, 11 Mar 2013 01:26:07 +0900 Subject: [PATCH 17/21] Feature #9566 Improvement to full table name call http://tracker.modx.com/issues/9566 --- .../extenders/dbapi.mysql.class.inc.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/manager/includes/extenders/dbapi.mysql.class.inc.php b/manager/includes/extenders/dbapi.mysql.class.inc.php index 4e2c0ea013..b93a9bf203 100644 --- a/manager/includes/extenders/dbapi.mysql.class.inc.php +++ b/manager/includes/extenders/dbapi.mysql.class.inc.php @@ -117,12 +117,10 @@ function disconnect() { } function escape($s) { - if (function_exists('mysql_real_escape_string') && $this->conn) { - $s = mysql_real_escape_string($s, $this->conn); - } else { - $s = mysql_escape_string($s); - } - return $s; + if (empty ($this->conn) || !is_resource($this->conn)) { + $this->connect(); + } + return mysql_real_escape_string($s, $this->conn); } /** @@ -158,6 +156,7 @@ function delete($from, $where='', $orderby='', $limit = '') { if (!$from) return false; else { + $from = $this->replaceFullTableName($from); if($where != '') $where = "WHERE {$where}"; if($orderby !== '') $orderby = "ORDER BY {$orderby}"; if($limit != '') $limit = "LIMIT {$limit}"; @@ -173,11 +172,11 @@ function select($fields = "*", $from = "", $where = "", $orderby = "", $limit = if (!$from) return false; else { - $table = $from; + $from = $this->replaceFullTableName($from); $where = ($where != "") ? "WHERE $where" : ""; $orderby = ($orderby != "") ? "ORDER BY $orderby " : ""; $limit = ($limit != "") ? "LIMIT $limit" : ""; - return $this->query("SELECT $fields FROM $table $where $orderby $limit"); + return $this->query("SELECT $fields FROM $from $where $orderby $limit"); } } @@ -189,6 +188,7 @@ function update($fields, $table, $where = "") { if (!$table) return false; else { + $table = $this->replaceFullTableName($table); if (!is_array($fields)) $flds = $fields; else { @@ -221,11 +221,13 @@ function insert($fields, $intotable, $fromfields = "*", $fromtable = "", $where $flds = "(" . implode(",", $keys) . ") " . (!$fromtable && $values ? "VALUES('" . implode("','", $values) . "')" : ""); if ($fromtable) { + $fromtable = $this->replaceFullTableName($fromtable); $where = ($where != "") ? "WHERE $where" : ""; $limit = ($limit != "") ? "LIMIT $limit" : ""; $sql = "SELECT $fromfields FROM $fromtable $where $limit"; } } + $intotable = $this->replaceFullTableName($intotable); $rt = $this->query("INSERT INTO $intotable $flds $sql"); $lid = $this->getInsertId(); return $lid ? $lid : $rt; From f61e09b4c45153ae3b1423c8c61622306d636ded Mon Sep 17 00:00:00 2001 From: yama Date: Mon, 11 Mar 2013 01:34:22 +0900 Subject: [PATCH 18/21] Use DBAPI See @3792021 --- manager/processors/login.processor.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/manager/processors/login.processor.php b/manager/processors/login.processor.php index 3dfc36689b..15499b0278 100755 --- a/manager/processors/login.processor.php +++ b/manager/processors/login.processor.php @@ -90,8 +90,7 @@ $email = $row['email']; // get the user settings from the database -$sql = "SELECT setting_name, setting_value FROM $dbase.`".$table_prefix."user_settings` WHERE user='".$internalKey."' AND setting_value!=''"; -$rs = mysql_query($sql); +$rs = $modx->db->select('setting_name, setting_value', '[+prefix+]user_settings', "user='{$internalKey}' AND setting_value!=''"); while ($row = $modx->db->getRow($rs)) { ${$row['setting_name']} = $row['setting_value']; } From 259c8f86e38f2aa95d21a88a91d8782c53e28b84 Mon Sep 17 00:00:00 2001 From: yama Date: Thu, 14 Mar 2013 20:10:32 +0900 Subject: [PATCH 19/21] Refactor #9622 Refactor "Manage Files" http://tracker.modx.com/issues/9622 --- manager/actions/files.dynamic.php | 1151 +++++++++++++++++------------ 1 file changed, 688 insertions(+), 463 deletions(-) diff --git a/manager/actions/files.dynamic.php b/manager/actions/files.dynamic.php index 00feff51bb..4ef6595b7f 100644 --- a/manager/actions/files.dynamic.php +++ b/manager/actions/files.dynamic.php @@ -1,24 +1,55 @@ INCLUDE_ORDERING_ERROR

    Please use the MODx Content Manager instead of accessing this file directly."); +if(!defined('IN_MANAGER_MODE') || IN_MANAGER_MODE != 'true') exit(); if(!$modx->hasPermission('file_manager')) { - $e->setError(3); - $e->dumpError(); + $e->setError(3); + $e->dumpError(); } - -if ($manager_theme) - $manager_theme .= '/'; -else $manager_theme = ''; +$token_check = checkToken(); +$newToken = makeToken(); // settings -$excludes = array('.', '..', 'cgi-bin', 'manager', '.svn'); -$editablefiles = array('.txt', '.php', '.shtml', '.html', '.htm', '.xml', '.js', '.css', '.pageCache', $friendly_url_suffix); -$inlineviewablefiles = array('.txt', '.php', '.html', '.htm', '.xml', '.js', '.css', '.pageCache', $friendly_url_suffix); -$viewablefiles = array('.jpg', '.gif', '.png', '.ico'); +$theme_image_path = $modx->config['site_url'] . 'manager/media/style/' . $modx->config['manager_theme'] . '/images/'; +$excludes = array('.', '..', '.svn'); +$alias_suffix = (!empty($friendly_url_suffix)) ? ','.ltrim($friendly_url_suffix,'.') : ''; +$editablefiles = explode(',', 'txt,php,shtml,html,htm,xml,js,css,pageCache,htaccess'.$alias_suffix); +$inlineviewablefiles = explode(',', 'txt,php,html,htm,xml,js,css,pageCache,htaccess'.$alias_suffix); +$viewablefiles = explode(',', 'jpg,gif,png,ico'); + +$editablefiles = add_dot($editablefiles); +$inlineviewablefiles = add_dot($inlineviewablefiles); +$viewablefiles = add_dot($viewablefiles); + +$proteted_path = array(); +/* jp only +if($_SESSION['mgrRole']!=1) +{ +*/ + $proteted_path[] = $modx->config['base_path'] . 'manager'; + $proteted_path[] = $modx->config['base_path'] . 'temp/backup'; + $proteted_path[] = $modx->config['base_path'] . 'assets/backup'; + + if(!$modx->hasPermission('save_plugin')) $proteted_path[] = $modx->config['base_path'] . 'assets/plugins'; + if(!$modx->hasPermission('save_snippet')) $proteted_path[] = $modx->config['base_path'] . 'assets/snippets'; + if(!$modx->hasPermission('save_template')) $proteted_path[] = $modx->config['base_path'] . 'assets/templates'; + if(!$modx->hasPermission('save_module')) $proteted_path[] = $modx->config['base_path'] . 'assets/modules'; + if(!$modx->hasPermission('empty_cache')) $proteted_path[] = $modx->config['base_path'] . 'assets/cache'; + if(!$modx->hasPermission('import_static')) { + $proteted_path[] = $modx->config['base_path'] . 'temp/import'; + $proteted_path[] = $modx->config['base_path'] . 'assets/import'; + } + if(!$modx->hasPermission('export_static')) { + $proteted_path[] = $modx->config['base_path'] . 'temp/export'; + $proteted_path[] = $modx->config['base_path'] . 'assets/export'; + } +/* +} +*/ + // Mod added by Raymond $enablefileunzip = true; $enablefiledownload = true; -$new_file_permissions = octdec($new_file_permissions); $newfolderaccessmode = $new_folder_permissions ? octdec($new_folder_permissions) : 0777; +$new_file_permissions = $new_file_permissions ? octdec($new_file_permissions) : 0666; // End Mod - by Raymond // make arrays from the file upload settings $upload_files = explode(',',$upload_files); @@ -27,111 +58,35 @@ $upload_flash = explode(',',$upload_flash); // now merge them $uploadablefiles = array_merge($upload_files,$upload_images,$upload_media,$upload_flash); -$count = count($uploadablefiles); -for($i=0; $i<$count; $i++) { - $uploadablefiles[$i] = ".".$uploadablefiles[$i]; // add a dot :) +$uploadablefiles = add_dot($uploadablefiles); +function add_dot($array) +{ + $count = count($array); + for($i=0; $i<$count; $i++) { + $array[$i] = '.'.strtolower(trim($array[$i])); // add a dot :) + } + return $array; } // end settings -function ufilesize($size) { - $a = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); - $pos = 0; - while ($size >= 1024) { - $size /= 1024; - $pos++; - } - return round($size,2)." ".$a[$pos]; -} - -function removeLastPath($string) { - $pos = false; - $search = "/"; - if (is_int(strpos($string, $search))) { - $endPos = strlen($string); - while ($endPos > 0) { - $endPos = $endPos - 1; - $pos = strpos($string, $search, $endPos); - if (is_int($pos)) { - break; - } - } - } - if (is_int($pos)) { - $len = strlen($search); - return substr($string, 0, $pos); - } - return $string; -} - -function getExtension($string) { - $pos = false; - $search = "."; - if (is_int(strpos($string, $search))) { - $endPos = strlen($string); - while ($endPos > 0) { - $endPos = $endPos - 1; - $pos = strpos($string, $search, $endPos); - if (is_int($pos)) { - break; - } - } - } - if (is_int($pos)) { - $len = strlen($search); - return substr($string, $pos); - } - return $string; -} - -function fsize($file) { - $a = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); - $pos = 0; - $size = filesize($file); - while ($size >= 1024) { - $size /= 1024; - $pos++; - } - return round($size,2)." ".$a[$pos]; -} - -function mkdirs($strPath, $mode){ // recursive mkdir function - if (is_dir($strPath)) return true; - $pStrPath = dirname($strPath); - if (!mkdirs($pStrPath, $mode)) return false; - return @mkdir($strPath); +// get the current work directory +if(isset($_REQUEST['path']) && !empty($_REQUEST['path'])) +{ + $_REQUEST['path'] = str_replace('..','',$_REQUEST['path']); + $startpath = is_dir($_REQUEST['path']) ? $_REQUEST['path'] : removeLastPath($_REQUEST['path']) ; } - -function logFileChange($type, $filename) { - //global $_lang; - - include_once('log.class.inc.php'); - $log = new logHandler(); - - switch ($type) { - case 'upload': $string = 'Uploaded File'; break; - case 'delete': $string = 'Deleted File'; break; - case 'modify': $string = 'Modified File'; break; - default: $string = 'Viewing File'; break; - } - - $string = sprintf($string, $filename); - $log->initAndWriteLog($string, '', '', '', $type, $filename); - - // HACK: change the global action to prevent double logging - // @see manager/index.php @ 915 - global $action; $action = 1; +else +{ + $startpath = $filemanager_path; } +$startpath = rtrim($startpath,'/'); -// get the current work directory -if(isset($_REQUEST['path']) && !empty($_REQUEST['path'])) { - $_REQUEST['path'] = str_replace('..','',$_REQUEST['path']); - $startpath = is_dir($_REQUEST['path']) ? $_REQUEST['path'] : removeLastPath($_REQUEST['path']) ; -} else { - $startpath = $filemanager_path; +if(!is_readable($startpath)) +{ + echo $_lang["not_readable_dir"]; + exit; } -$len = strlen($filemanager_path); - // Raymond: get web start path for showing pictures $rf = realpath($filemanager_path); $rw = realpath('../'); @@ -140,283 +95,251 @@ function logFileChange($type, $filename) { else $webstart_path = '../'.$webstart_path; ?> + +

    -

    +
    +
      + [+subject+]'; + $ph['image'] = 'folder.gif'; + $ph['subject'] = $_lang['add_folder']; + $ph['href'] = 'index.php?a=31&mode=newfolder&path='.urlencode($startpath).'&name='; + $_ = parsePlaceholder($tpl,$ph); + + $tpl = '
    • ' . $_lang['files.dynamic.php1'] . '
    • '; + $ph['image'] = 'page-html.gif'; + $ph['href'] = 'index.php?a=31&mode=newfile&path='.urlencode($startpath).'&name='; + $_ .= parsePlaceholder($tpl,$ph); + echo $_; +} +?> +
    • icons_cancel" />
    • +
    +
    +
    - config['clean_uploaded_filename']) { - $nameparts = explode('.', $name); - $nameparts = array_map(array($modx, 'stripAlias'), $nameparts); - $name = implode('.', $nameparts); - } - $userfiles[$i]['name'] = $name; - $userfiles[$i]['type'] = $_FILES['userfile']['type'][$i]; - } - } - - foreach((array)$userfiles as $userfile) { - - // this seems to be an upload action. - printf("

    ".$_lang['files_uploading']."

    ", $userfile['name'], substr($startpath, $len, strlen($startpath))); - echo $userfile['error']==0 ? "

    ".$_lang['files_file_type'].$userfile['type'].", ".fsize($userfile['tmp_name']).'

    ' : ''; - - $userfilename = $userfile['tmp_name']; - - if (is_uploaded_file($userfilename)) { - // file is uploaded file, process it! - if(!in_array(getExtension($userfile['name']), $uploadablefiles)) { - echo '

    '.$_lang['files_filetype_notok'].'

    '; - } else { - if(@move_uploaded_file($userfile['tmp_name'], $_POST['path'].'/'.$userfile['name'])) { - // Ryan: Repair broken permissions issue with file manager - if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') - @chmod($_POST['path']."/".$userfile['name'], $new_file_permissions); - // Ryan: End - echo '

    '.$_lang['files_upload_ok'].'

    '; - - // invoke OnFileManagerUpload event - $modx->invokeEvent('OnFileManagerUpload', - array( - 'filepath' => $_POST['path'], - 'filename' => $userfile['name'] - )); - // Log the change - logFileChange('upload', $_POST['path'].'/'.$userfile['name']); - } else { - echo '

    '.$_lang['files_upload_copyfailed'].' '.$_lang["files_upload_permissions_error"].'

    '; - } - } - } else { - echo '
    '.$_lang['files_upload_error'].':'; - switch($userfile['error']){ - case 0: //no error; possible file attack! - echo $_lang['files_upload_error0']; - break; - case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini - echo $_lang['files_upload_error1']; - break; - case 2: //uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form - echo $_lang['files_upload_error2']; - break; - case 3: //uploaded file was only partially uploaded - echo $_lang['files_upload_error3']; - break; - case 4: //no file was uploaded - echo $_lang['files_upload_error4']; - break; - default: //a default error, just in case! :) - echo $_lang['files_upload_error5']; - break; - } - echo '
    '; - } - echo '
    '; - } +if(!empty($_FILES['userfile'])) $information = fileupload(); +elseif($_POST['mode']=='save') echo textsave(); +elseif($_REQUEST['mode']=='delete') echo delete_file(); + +if(in_array($startpath,$proteted_path)) +{ + echo $_lang['files.dynamic.php2']; + exit; } -if($_POST['mode']=='save') { - echo $_lang['editing_file']; - $filename = $_POST['path']; - $content = $_POST['content']; - if (!$handle = fopen($filename, 'w')) { - echo 'Cannot open file (',$filename,')'; - exit; - } - - // Write $content to our opened file. - if (fwrite($handle, $content) === FALSE) { - echo ''.$_lang['file_not_saved'].'

    '; - } else { - echo ''.$_lang['file_saved'].'

    '; - $_REQUEST['mode'] = 'edit'; - } - fclose($handle); - - // Log the change - logFileChange('modify', $filename); +$tpl = '[+subject+] '; +$ph = array(); +$ph['style_path'] = $theme_image_path; +// To Top Level with folder icon to the left +if($startpath==$filemanager_path || $startpath.'/' == $filemanager_path) +{ + $ph['image'] = 'deletedfolder.gif'; + $ph['subject'] = 'Top'; } - - -if($_REQUEST['mode']=='delete') { - printf($_lang['deleting_file'], str_replace('\\', '/', $_REQUEST['path'])); - $file = $_REQUEST['path']; - if (!@unlink($file)) { - echo ''.$_lang['file_not_deleted'].'

    '; - } else { - echo ''.$_lang['file_deleted'].'

    '; - } - - // Log the change - logFileChange('delete', $file); +else +{ + $ph['image'] = 'folder.gif'; + $ph['subject'] = 'Top / '; } +echo parsePlaceholder($tpl,$ph); +$len = strlen($filemanager_path); +if(substr($startpath, $len, strlen($startpath))=='') + $topic_path = '/'; +else +{ + $topic_path = substr($startpath, $len, strlen($startpath)); + $pieces = explode('/',rtrim($topic_path,'/')); + $path = ''; + $count = count($pieces); + foreach($pieces as $i=>$v) + { + if(empty($v)) continue; + $path .= rtrim($v,'/') . '/'; + if(1<$count) + { + $href = 'index.php?a=31&mode=drill&path=' . urlencode($filemanager_path.$path); + $pieces[$i] = '' . trim($v,'/') . ''; + } + else $pieces[$i] = trim($v,'/'); + $count--; + } + $topic_path = join(' / ', $pieces); +} -echo $_lang['files_dir_listing']?>

    +?> + echo $_lang['files_access_denied']?>
    0) { - // str_replace must be used under windows to convert "/" into "\" - $complete_path = $path.str_replace('/','\\',dirname(zip_entry_name($zip_entry))); - $complete_name = $path.str_replace ('/','\\',zip_entry_name($zip_entry)); - if(!file_exists($complete_path)) { - $tmp = ''; - foreach(explode('\\',$complete_path) AS $k) { - $tmp .= $k.'\\'; - if(!file_exists($tmp)) { - @mkdir($tmp, $newfolderaccessmode); - } - } - } - if (zip_entry_open($zip, $zip_entry, 'r')) { - $fd = fopen($complete_name, 'w'); - fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry))); - fclose($fd); - zip_entry_close($zip_entry); - } - } - } - umask($old_umask); - zip_close($zip); - return true; - } - zip_close($zip); - } - if(!$err=@unzip(realpath("$startpath/".$_REQUEST['file']),realpath($startpath))) { - echo ''.$_lang['file_unzip_fail'].($err===0? 'Missing zip library (php_zip.dll / zip.so)':'').'

    '; - } else { - echo ''.$_lang['file_unzip'].'

    '; - } +if ($enablefileunzip && $_REQUEST['mode']=='unzip' && is_writable($startpath)) +{ + if(!$err=@unzip(realpath("{$startpath}/".$_REQUEST['file']),realpath($startpath))) + { + echo ''.$_lang['file_unzip_fail'].($err===0? 'Missing zip library (php_zip.dll / zip.so)':'').'

    '; + } + else + { + echo ''.$_lang['file_unzip'].'

    '; + } } // End Unzip - Raymond // New Folder & Delete Folder option - Raymond -if (is_writable($startpath)){ - // Delete Folder - if($_REQUEST['mode']=='deletefolder') { - $folder = $_REQUEST['folderpath']; - if(!@rmdir($folder)) { - echo ''.$_lang['file_folder_not_deleted'].'

    '; - } else { - echo ''.$_lang['file_folder_deleted'].'

    '; - } - } - - -// Create folder here -if($_REQUEST['mode']=='newfolder') { - $old_umask = umask(0); - $foldername = str_replace('..\\','',str_replace('../','',$_REQUEST['name'])); - if(!mkdirs($startpath."/$foldername",$newfolderaccessmode)) { - echo '',$_lang['file_folder_not_created'],'

    '; - } else { - if (!@chmod($startpath.'/'.$foldername,$newfolderaccessmode)) { - echo ''.$_lang['file_folder_chmod_error'].'

    '; - } else { - echo ''.$_lang['file_folder_created'].'

    '; - } - } - umask($old_umask); -} - echo ' '.$_lang['add_folder'].'
    '; +if (is_writable($startpath)) +{ + // Delete Folder + if($_REQUEST['mode']=='deletefolder') + { + $folder = $_REQUEST['folderpath']; + if(!$token_check) + { + echo ''.$_lang['file_folder_not_deleted'].'

    '; + } + elseif(!@rrmdir($folder)) + { + echo ''.$_lang['file_folder_not_deleted'].'

    '; + } + else + { + echo ''.$_lang['file_folder_deleted'].'

    '; + } + } + + // Create folder here + if($_REQUEST['mode']=='newfolder') + { + $old_umask = umask(0); + $foldername = str_replace('..\\','',str_replace('../','',$_REQUEST['name'])); + if(!mkdirs("{$startpath}/{$foldername}",0777)) + { + echo '',$_lang['file_folder_not_created'],'

    '; + } + else + { + if (!@chmod($startpath.'/'.$foldername,$newfolderaccessmode)) + { + echo ''.$_lang['file_folder_chmod_error'].'

    '; + } + else + { + echo ''.$_lang['file_folder_created'].'

    '; + } + } + umask($old_umask); + } + // Create file here + if($_REQUEST['mode']=='newfile') + { + $old_umask = umask(0); + $filename = str_replace('..\\','',str_replace('../','',$_REQUEST['name'])); + $filename = $modx->db->escape($filename); + + if(!in_array(getExtension($filename), $uploadablefiles)) + { + echo ''.$_lang['files_filetype_notok'].'

    '; + } + elseif(preg_match('@(\\\\|\/|\:|\;|\,|\*|\?|\"|\<|\>|\||\?)@',$filename)!==0) + { + echo $_lang['files.dynamic.php3']; + } + else + { + $rs = file_put_contents("{$startpath}/{$filename}",''); + if($rs===false) + { + echo '',$_lang['file_folder_not_created'],'

    '; + } + else + { + echo $_lang['files.dynamic.php4']; + } + umask($old_umask); + } + } } // End New Folder - Raymond -$uponelevel = removeLastPath($startpath); - -// To Top Level with folder icon to the left -if($startpath==$filemanager_path || $startpath.'/' == $filemanager_path) { - echo ' ',$_lang['files_top_level'],'
    '; -} else { - echo ' ',$_lang['files_top_level'],'
    '; -} -// Up One level with folder icon to the left -if($startpath == $filemanager_path || $startpath.'/' == $filemanager_path) { - echo ' '.$_lang['files_up_level'].'
    '; -} else { - echo ' ',$_lang['files_up_level'],'
    '; -} -echo '
    '; - - $filesize = 0; $files = 0; $folders = 0; @@ -424,88 +347,7 @@ function unzip($file, $path) { $files_array = array(); if(strlen(MODX_BASE_PATH) < strlen($filemanager_path)) $len--; -function ls($curpath) { - global $_lang; - global $excludes, $editablefiles, $inlineviewablefiles, $viewablefiles, $enablefileunzip, $enablefiledownload, $uploadablefiles, $folders, $files, $filesizes, $len, $dirs_array, $files_array, $webstart_path, $manager_theme, $modx; - $dircounter = 0; - $filecounter = 0; - $curpath = str_replace('//','/',$curpath.'/'); - - if (!is_dir($curpath)) { - echo 'Invalid path "',$curpath,'"
    '; - return; - } - $dir = dir($curpath); - - // first, get info - while ($file = $dir->read()) { - if(!in_array($file, $excludes)) { - $newpath = $curpath.$file; - if(is_dir($newpath)) { - $dirs_array[$dircounter]['dir'] = $newpath; - $dirs_array[$dircounter]['stats'] = lstat($newpath); - $dirs_array[$dircounter]['text'] = ' '.$file.''; - $dirs_array[$dircounter]['delete'] = is_writable($curpath) ? ''.$_lang['file_delete_folder'].'' : ''; - - // increment the counter - $dircounter++; - } else { - $type=getExtension($newpath); - $files_array[$filecounter]['file'] = $newpath; - $files_array[$filecounter]['stats'] = lstat($newpath); - $files_array[$filecounter]['text'] = ''.$file; - $files_array[$filecounter]['view'] = (in_array($type, $viewablefiles)) ? - ''.$_lang['files_viewfile'].'' : (($enablefiledownload && in_array($type, $uploadablefiles))? ''.$_lang['file_download_file'].'':''.$_lang['files_viewfile'].''); - $files_array[$filecounter]['view'] = (in_array($type, $inlineviewablefiles)) ? ''.$_lang['files_viewfile'].'' : $files_array[$filecounter]['view'] ; - $files_array[$filecounter]['unzip'] = ($enablefileunzip && $type=='.zip') ? ''.$_lang['file_download_unzip'].'' : '' ; - $files_array[$filecounter]['edit'] = (in_array($type, $editablefiles) && is_writable($curpath) && is_writable($newpath)) ? ''.$_lang['files_editfile'].'' : ''.$_lang['files_editfile'].''; - $files_array[$filecounter]['delete'] = is_writable($curpath) && is_writable($newpath) ? ''.$_lang['file_delete_file'].'' : ''.$_lang['file_delete_file'].''; - - - // increment the counter - $filecounter++; - } - } - } - $dir->close(); - - // dump array entries for directories - $folders = count($dirs_array); - sort($dirs_array); // sorting the array alphabetically (Thanks pxl8r!) - for($i=0; $i<$folders; $i++) { - $filesizes += $dirs_array[$i]['stats']['7']; - echo ''; - echo '',$dirs_array[$i]['text'],''; - echo '',$modx->toDateFormat($dirs_array[$i]['stats']['9']),''; - echo '',ufilesize($dirs_array[$i]['stats']['7']),''; - echo ''; - echo $dirs_array[$i]['delete']; - echo ''; - echo ''; - } - - // dump array entries for files - $files = count($files_array); - sort($files_array); // sorting the array alphabetically (Thanks pxl8r!) - for($i=0; $i<$files; $i++) { - $filesizes += $files_array[$i]['stats']['7']; - echo ''; - echo '',$files_array[$i]['text'],''; - echo '',$modx->toDateFormat($files_array[$i]['stats']['9']),''; - echo '',ufilesize($files_array[$i]['stats']['7']),''; - echo ''; - echo $files_array[$i]['unzip']; - echo $files_array[$i]['view']; - echo $files_array[$i]['edit']; - echo $files_array[$i]['delete']; - echo ''; - echo ''; - } - - - return; -} -echo '

    '; +echo '
    '; ?> @@ -516,97 +358,480 @@ function ls($curpath) { '; + echo ''; } -?>
    This directory is empty.
    This directory is empty.
    +
    +',$folders,'
    '; -echo $_lang['files_files'],': ',$files,'
    '; -echo $_lang['files_data'],': ',ufilesize($filesizes),'
    '; +echo $_lang['files_directories'],': ',$folders,' '; +echo $_lang['files_files'],': ',$files,' '; +echo $_lang['files_data'],': ',$modx->nicesize($filesizes),' '; echo $_lang['files_dirwritable'],' ',is_writable($startpath)==1 ? $_lang['yes'].'.' : $_lang['no'].'.' -?>
    -
    +?> +
    -

    + -
    - - - - - -
    - + + + + - + +
    - - ".$_lang['files_upload_inhibited_msg']."

    "; + echo "

    ".$_lang['files_upload_inhibited_msg']."

    "; } + ?>
    - +
    -
    + + +
    - +
    - -
    - -
    \ No newline at end of file + +function ls($curpath) +{ + global $_lang,$theme_image_path,$_style; + global $excludes, $proteted_path, $editablefiles, $inlineviewablefiles, $viewablefiles, $enablefileunzip, $enablefiledownload, $uploadablefiles, $folders, $files, $filesizes, $len, $dirs_array, $files_array, $webstart_path, $modx; + $dircounter = 0; + $filecounter = 0; + $curpath = str_replace('//','/',$curpath.'/'); + + if (!is_dir($curpath)) + { + echo 'Invalid path "',$curpath,'"
    '; + return; + } + $dir = scandir($curpath); + + // first, get info + foreach ($dir as $file) + { + $newpath = $curpath.$file; + if($file==='..'||$file==='.') continue; + if(is_dir($newpath)) + { + $dirs_array[$dircounter]['dir'] = $newpath; + $dirs_array[$dircounter]['stats'] = lstat($newpath); + if($file==='..'||$file==='.') continue; + elseif(!in_array($file, $excludes) && !in_array($newpath,$proteted_path)) + { + $dirs_array[$dircounter]['text'] = ' '.$file.''; + + $dfiles = scandir($newpath); + foreach($dfiles as $i=>$infile) + { + switch($infile) + { + case '..': + case '.': + unset($dfiles[$i]); + break; + } + } + $file_exists = (0'.$_lang['file_delete_folder'].'' : ''; + } + else + { + $dirs_array[$dircounter]['text'] = ' '.$file . ''; + $dirs_array[$dircounter]['delete'] = is_writable($curpath) ? ''.$_lang['file_delete_folder'].'' : ''; + } + + // increment the counter + $dircounter++; + } + else + { + $type=getExtension($newpath); + $files_array[$filecounter]['file'] = $newpath; + $files_array[$filecounter]['stats'] = lstat($newpath); + $files_array[$filecounter]['text'] = ''.$file; + $files_array[$filecounter]['view'] = (in_array($type, $viewablefiles)) ? + ''.$_lang['files_viewfile'].' ' : (($enablefiledownload && in_array($type, $uploadablefiles))? ''.$_lang['file_download_file'].' ':''.$_lang['files_viewfile'].' '); + $files_array[$filecounter]['view'] = (in_array($type, $inlineviewablefiles)) ? ''.$_lang['files_viewfile'].' ' : $files_array[$filecounter]['view'] ; + $files_array[$filecounter]['unzip'] = ($enablefileunzip && $type=='.zip') ? ''.$_lang['file_download_unzip'].' ' : '' ; + $files_array[$filecounter]['edit'] = (in_array($type, $editablefiles) && is_writable($curpath) && is_writable($newpath)) ? ''.$_lang['files_editfile'].' ' : ''.$_lang['files_editfile'].' '; + $files_array[$filecounter]['delete'] = is_writable($curpath) && is_writable($newpath) ? ''.$_lang['file_delete_file'].' ' : ''.$_lang['file_delete_file'].' '; + + // increment the counter + $filecounter++; + } + } + + // dump array entries for directories + $folders = count($dirs_array); + sort($dirs_array); // sorting the array alphabetically (Thanks pxl8r!) + for($i=0; $i<$folders; $i++) + { + $filesizes += $dirs_array[$i]['stats']['7']; + echo ''; + echo '',$dirs_array[$i]['text'],''; + echo '',$modx->toDateFormat($dirs_array[$i]['stats']['9']),''; + echo '',$modx->nicesize($dirs_array[$i]['stats']['7']),''; + echo ''; + echo $dirs_array[$i]['delete']; + echo ''; + echo ''; + } + + // dump array entries for files + $files = count($files_array); + sort($files_array); // sorting the array alphabetically (Thanks pxl8r!) + for($i=0; $i<$files; $i++) + { + $filesizes += $files_array[$i]['stats']['7']; + echo ''; + echo '',$files_array[$i]['text'],''; + echo '',$modx->toDateFormat($files_array[$i]['stats']['9']),''; + echo '',$modx->nicesize($files_array[$i]['stats']['7']),''; + echo ''; + echo $files_array[$i]['unzip']; + echo $files_array[$i]['view']; + echo $files_array[$i]['edit']; + echo $files_array[$i]['delete']; + echo ''; + echo ''; + } + return; +} + +function removeLastPath($string) { + $pos = strrpos($string, '/'); + if($pos!==false) + { + $path = substr($string,0,$pos); + } + else $path = false; + return $path; +} + +function getExtension($string) { + $pos = strrpos($string, '.'); + if($pos!==false) + { + $ext = substr($string,$pos); + $ext = strtolower($ext); + } + else $ext = false; + return $ext; +} + +function mkdirs($strPath, $mode){ // recursive mkdir function + if (is_dir($strPath)) return true; + $pStrPath = dirname($strPath); + if (!mkdirs($pStrPath, $mode)) return false; + return @mkdir($strPath); +} + +function logFileChange($type, $filename) +{ + //global $_lang; + + include_once('log.class.inc.php'); + $log = new logHandler(); + + switch ($type) + { + case 'upload': $string = 'Uploaded File'; break; + case 'delete': $string = 'Deleted File'; break; + case 'modify': $string = 'Modified File'; break; + default: $string = 'Viewing File'; break; + } + + $string = sprintf($string, $filename); + $log->initAndWriteLog($string, '', '', '', $type, $filename); + + // HACK: change the global action to prevent double logging + // @see manager/index.php @ 915 + global $action; $action = 1; +} + +// by patrick_allaert - php user notes +function unzip($file, $path) +{ + global $newfolderaccessmode; + // added by Raymond + $r = substr($path,strlen($path)-1,1); + if ($r!='\\'||$r!='/') $path .='/'; + if (!extension_loaded('zip')) + { + return 0; + } + // end mod + $zip = zip_open($file); + if ($zip) + { + $old_umask = umask(0); + while ($zip_entry = zip_read($zip)) + { + if (zip_entry_filesize($zip_entry) > 0) + { + // str_replace must be used under windows to convert "/" into "\" + $complete_path = $path.str_replace('/','\\',dirname(zip_entry_name($zip_entry))); + $complete_name = $path.str_replace ('/','\\',zip_entry_name($zip_entry)); + if(!file_exists($complete_path)) + { + $tmp = ''; + foreach(explode('\\',$complete_path) AS $k) + { + $tmp .= $k.'\\'; + if(!file_exists($tmp)) + { + @mkdir($tmp, 0777); + } + } + } + if (zip_entry_open($zip, $zip_entry, 'r')) + { + $fd = fopen($complete_name, 'w'); + fwrite($fd, zip_entry_read($zip_entry, zip_entry_filesize($zip_entry))); + fclose($fd); + zip_entry_close($zip_entry); + } + } + } + umask($old_umask); + zip_close($zip); + return true; + } + zip_close($zip); +} + +function rrmdir($dir) +{ + foreach(glob($dir . '/*') as $file) + { + if(is_dir($file)) rrmdir($file); + else unlink($file); + } + return rmdir($dir); +} + +function fileupload() +{ + global $modx,$_lang,$startpath, $filemanager_path, $uploadablefiles, $new_file_permissions; + $msg = ''; + + if(!empty($_FILES['userfile']['tmp_name'])) + { + $userfile['tmp_name'] = $_FILES['userfile']['tmp_name']; + $userfile['error'] = $_FILES['userfile']['error']; + $name = $_FILES['userfile']['name']; + if($modx->config['clean_uploaded_filename']==1) + { + $nameparts = explode('.', $name); + $nameparts = array_map(array($modx, 'stripAlias'), $nameparts, array('file_manager')); + $name = implode('.', $nameparts); + } + $userfile['name'] = $name; + $userfile['type'] = $_FILES['userfile']['type']; + } + + // this seems to be an upload action. + $path = $modx->config['site_url'] . substr($startpath, strlen($filemanager_path), strlen($startpath)); + $path = rtrim($path,'/') . '/' . $userfile['name']; + $msg .= $path; + if($userfile['error']==0) + { + $img = (strpos($userfile['type'],'image')!==false) ? '
    ' : ''; + $msg .= "

    ".$_lang['files_file_type'].$userfile['type'].", ".$modx->nicesize(filesize($userfile['tmp_name'])).$img.'

    '; + } + + $userfilename = $userfile['tmp_name']; + + if (is_uploaded_file($userfilename)) + { + // file is uploaded file, process it! + if(!in_array(getExtension($userfile['name']), $uploadablefiles)) + { + $msg .= '

    '.$_lang['files_filetype_notok'].'

    '; + } + else + { + if(@move_uploaded_file($userfile['tmp_name'], $_POST['path'].'/'.$userfile['name'])) + { + // Ryan: Repair broken permissions issue with file manager + if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN') + @chmod($_POST['path']."/".$userfile['name'], $new_file_permissions); + // Ryan: End + $msg .= '

    '.$_lang['files_upload_ok'].'

    '; + + // invoke OnFileManagerUpload event + $modx->invokeEvent('OnFileManagerUpload', + array( + 'filepath' => $_POST['path'], + 'filename' => $userfile['name'] + )); + // Log the change + logFileChange('upload', $_POST['path'].'/'.$userfile['name']); + } + else + { + $msg .= '

    '.$_lang['files_upload_copyfailed'].' '.$_lang["files_upload_permissions_error"].'

    '; + } + } + } + else + { + $msg .= '
    '.$_lang['files_upload_error'].':'; + switch($userfile['error']) + { + case 0: //no error; possible file attack! + $msg .= $_lang['files_upload_error0']; + break; + case 1: //uploaded file exceeds the upload_max_filesize directive in php.ini + $msg .= $_lang['files_upload_error1']; + break; + case 2: //uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the html form + $msg .= $_lang['files_upload_error2']; + break; + case 3: //uploaded file was only partially uploaded + $msg .= $_lang['files_upload_error3']; + break; + case 4: //no file was uploaded + $msg .= $_lang['files_upload_error4']; + break; + default: //a default error, just in case! :) + $msg .= $_lang['files_upload_error5']; + break; + } + $msg .= '
    '; + } + return $msg; +} + +function textsave() +{ + global $_lang; + + $msg = $_lang['editing_file']; + $filename = $_POST['path']; + $content = $_POST['content']; + + // Write $content to our opened file. + if (file_put_contents($filename, $content) === FALSE) + { + $msg .= ''.$_lang['file_not_saved'].'

    '; + } + else + { + $msg .= ''.$_lang['file_saved'].'

    '; + $_REQUEST['mode'] = 'edit'; + } + // Log the change + logFileChange('modify', $filename); + return $msg; +} + +function delete_file() +{ + global $_lang, $token_check; + + $msg = sprintf($_lang['deleting_file'], str_replace('\\', '/', $_REQUEST['path'])); + + $file = $_REQUEST['path']; + if(!$token_check) + { + $msg .= ''.$_lang['file_not_deleted'].'

    '; + } + elseif(!@unlink($file)) + { + $msg .= ''.$_lang['file_not_deleted'].'

    '; + } + else + { + $msg .= ''.$_lang['file_deleted'].'

    '; + } + + // Log the change + logFileChange('delete', $file); + + return $msg; +} + +function parsePlaceholder($tpl,$ph) { + foreach($ph as $k=>$v) { + $k = "[+{$k}+]"; + $tpl = str_replace($k,$v,$tpl); + } + return $tpl; +} + +function checkToken() +{ + if(isset($_POST['token']) && !empty($_POST['token'])) $token = $_POST['token']; + elseif(isset($_GET['token']) && !empty($_GET['token'])) $token = $_GET['token']; + else $token = false; + + if(isset($_SESSION['token']) && !empty($_SESSION['token']) && $_SESSION['token']===$token) + { + $rs =true; + } + else $rs = false; + $_SESSION['token'] = ''; + return $rs; +} + +function makeToken() +{ + $newToken = uniqid(''); + $_SESSION['token'] = $newToken; + return $newToken; +} From bd5a3b3becb8f0a5cc2bc56161af2380a70ea5b4 Mon Sep 17 00:00:00 2001 From: yama Date: Thu, 14 Mar 2013 20:19:12 +0900 Subject: [PATCH 20/21] Feature #9624 Add .htaccess into assets/cache/ http://tracker.modx.com/issues/9624 --- manager/processors/cache_sync.class.processor.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/manager/processors/cache_sync.class.processor.php b/manager/processors/cache_sync.class.processor.php index 245fa66f0f..2d5c135637 100755 --- a/manager/processors/cache_sync.class.processor.php +++ b/manager/processors/cache_sync.class.processor.php @@ -296,6 +296,10 @@ function buildCache($modx) { exit; } + if(!is_file($this->cachePath . '/.htaccess')) { + file_put_contents($this->cachePath . '/.htaccess', "order deny,allow\ndeny from all\n"); + } + // Write $somecontent to our opened file. if (fwrite($handle, $somecontent) === FALSE) { echo 'Cannot write main MODx cache file! Make sure the assets/cache directory is writable!'; From 368d0dbf74484ecb28975889ac0ca96ffa0d2913 Mon Sep 17 00:00:00 2001 From: yama Date: Thu, 14 Mar 2013 22:51:58 +0900 Subject: [PATCH 21/21] Fix - Run snippet in manager issue --- manager/includes/document.parser.class.inc.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manager/includes/document.parser.class.inc.php b/manager/includes/document.parser.class.inc.php index af8962e5d1..ce58178797 100755 --- a/manager/includes/document.parser.class.inc.php +++ b/manager/includes/document.parser.class.inc.php @@ -819,7 +819,7 @@ function evalSnippet($snippet, $params) { $snip= eval ($snippet); $msg= ob_get_contents(); ob_end_clean(); - if ((0<$this->config['error_reporting']) && isset($php_errormsg)) + if ((0<$this->config['error_reporting']) && $msg && isset($php_errormsg)) { $error_info = error_get_last(); if($error_info['type']===2048 || $error_info['type']===8192) $error_type = 2; @@ -827,15 +827,15 @@ function evalSnippet($snippet, $params) { if(1<$this->config['error_reporting'] || 2<$error_type) { extract($error_info); - if($msg===false) $msg = 'ob_get_contents() error'; $result = $this->messageQuit('PHP Parse Error', '', true, $type, $file, 'Snippet', $text, $line, $msg); if ($this->isBackend()) { - $this->event->alert("An error occurred while loading. Please see the event log for more information

    {$msg}{$snip}

    "); + $this->event->alert("An error occurred while loading. Please see the event log for more information

    {$msg}

    "); } } } unset ($modx->event->params); + $this->currentSnippet = ''; return $msg . $snip; }