diff --git a/upload/api/db/dbbak.php b/upload/api/db/dbbak.php index 3ac052aef8a5064a31b2582a6136a2e56915a409..6885d413ad560e77a2109fe097b7843adbae1c20 100644 --- a/upload/api/db/dbbak.php +++ b/upload/api/db/dbbak.php @@ -515,6 +515,10 @@ if($get['method'] == 'export') { $get['volume'] = 0; } + if(!preg_match('/^backup_(\d+)_\w+$/', $get['sqlpath']) || !preg_match('/^\d+_\w+\-(\d+).sql$/', $get['dumpfile'])) { + api_msg('bak_file_lose', $get['dumpfile']); + } + $get['volume']++; $next_dumpfile = preg_replace('/^(\d+)\_(\w+)\-(\d+)\.sql$/', '\\1_\\2-'.$get['volume'].'.sql', $get['dumpfile']); if(!is_file(BACKUP_DIR.$get['sqlpath'].'/'.$get['dumpfile'])) { @@ -558,7 +562,7 @@ if($get['method'] == 'export') { $directory = dir(BACKUP_DIR); while($entry = $directory->read()) { $filename = BACKUP_DIR.$entry; - if(is_dir($filename) && preg_match('/backup_(\d+)_\w+$/', $filename, $match)) { + if(is_dir($filename) && preg_match('/^backup_(\d+)_\w+$/', $filename, $match)) { $str .= "\t\n"; $str .= "\t\t$filename\n"; $str .= "\t\t$match[1]\n"; diff --git a/upload/config/config_global_default.php b/upload/config/config_global_default.php index 705c233ce454bb2ac5a61015ce310d85869fe884..d5a9bbf494f9bb9511db77b20d6456b4a9b4136a 100644 --- a/upload/config/config_global_default.php +++ b/upload/config/config_global_default.php @@ -176,6 +176,7 @@ $_config['admincp']['forcesecques'] = 0; // 管理人员必须设置安全提 $_config['admincp']['checkip'] = 1; // 后台管理操作是否验证管理员的 IP, 1=是[安全], 0=否。仅在管理员无法登陆后台时设置 0。 $_config['admincp']['runquery'] = 0; // 是否允许后台运行 SQL 语句 1=是 0=否[安全] $_config['admincp']['dbimport'] = 1; // 是否允许后台恢复论坛数据 1=是 0=否[安全] +$_config['admincp']['mustlogin'] = 1; // 是否必须前台登录后才允许后台登录 1=是[安全] 0=否 /** * 系统远程调用功能模块 diff --git a/upload/install/include/install_function.php b/upload/install/include/install_function.php index 6494b450a1d60d9fc8917ecf376a77c57ddbce5c..67c9ab9e4a6437004059b232d057f010270fa5d4 100644 --- a/upload/install/include/install_function.php +++ b/upload/install/include/install_function.php @@ -798,17 +798,6 @@ function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) { } -function generate_key() { - $random = random(32); - $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time()); - $return = array(); - for($i=0; $i<64; $i++) { - $p = intval($i/2); - $return[$i] = $i % 2 ? $random[$p] : $info[$p]; - } - return implode('', $return); -} - function show_install() { if(VIEW_OFF) return; ?> @@ -1336,14 +1325,14 @@ EOT; return $success; } -function _generate_key() { - $random = random(32); +function _generate_key($length = 32) { + $random = random($length); $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time()); - $return = array(); - for($i=0; $i<32; $i++) { - $return[$i] = $random[$i].$info[$i]; + $return = ''; + for($i=0; $i<$length; $i++) { + $return .= $random[$i].$info[$i]; } - return implode('', $return); + return $return; } function uc_write_config($config, $file, $password) { diff --git a/upload/source/admincp/admincp_checktools.php b/upload/source/admincp/admincp_checktools.php index 58f595dce72e1ff3ea5f8de9dab1828cc738b78b..8fbda7fb89b6c65dc650232449de8d9827fa0cde 100644 --- a/upload/source/admincp/admincp_checktools.php +++ b/upload/source/admincp/admincp_checktools.php @@ -286,6 +286,50 @@ if($operation == 'filecheck') { } } +} elseif($operation == 'replacekey') { + + $step = max(1, intval($_GET['step'])); + shownav('tools', 'nav_replacekey'); + showtips('replacekey_tips'); + showsubmenusteps('nav_replacekey', array( + array('nav_replacekey_confirm', $step == 1), + array('nav_replacekey_verify', $step == 2), + array('nav_replacekey_completed', $step == 3) + )); + if($step == 1) { + cpmsg(cplang('replacekey_tips_step1'), 'action=checktools&operation=replacekey&step=2', 'form', '', FALSE); + } elseif($step == 2) { + cpmsg(cplang('replacekey_tips_step2'), "action=checktools&operation=replacekey&step=3", 'loading', '', FALSE); + } elseif($step == 3) { + if(!is_writeable('./config/config_global.php')) { + cpmsg('replacekey_must_write_config', '', 'error'); + } + + $oldauthkey = $_G['config']['security']['authkey']; + $newauthkey = generate_key(64); + + $configfile = trim(file_get_contents(DISCUZ_ROOT.'./config/config_global.php')); + $configfile = substr($configfile, -2) == '?>' ? substr($configfile, 0, -2) : $configfile; + $configfile = str_replace($oldauthkey, $newauthkey, $configfile); + + if(file_put_contents(DISCUZ_ROOT.'./config/config_global.php', trim($configfile), LOCK_EX) === false) { + cpmsg('replacekey_must_write_config', '', 'error'); + } + + $ecdata = authcode($_G['setting']['ec_contract'], 'DECODE', $oldauthkey); + $ecdata = authcode($ecdata, 'ENCODE', $newauthkey); + C::t('common_setting')->update('ec_contract', $ecdata); + + $ftpdata = $_G['setting']['ftp']; + $ftppasswd = authcode($ftpdata['password'], 'DECODE', md5($oldauthkey)); + $ftpdata['password'] = authcode($ftppasswd, 'ENCODE', md5($newauthkey)); + C::t('common_setting')->update('ftp', $ftpdata); + + updatecache('setting'); + + cpmsg('replacekey_succeed', '', 'succeed', '', FALSE); + } + } elseif($operation == 'ftpcheck') { $alertmsg = ''; @@ -631,4 +675,13 @@ function findhook($hookid, $key) { } $hooks[] = ''; } -?> \ No newline at end of file + +function generate_key($length = 32) { + $random = random($length); + $info = md5($_SERVER['SERVER_SOFTWARE'].$_SERVER['SERVER_NAME'].$_SERVER['SERVER_ADDR'].$_SERVER['SERVER_PORT'].$_SERVER['HTTP_USER_AGENT'].time()); + $return = ''; + for($i=0; $i<$length; $i++) { + $return .= $random[$i].$info[$i]; + } + return $return; +} \ No newline at end of file diff --git a/upload/source/admincp/admincp_index.php b/upload/source/admincp/admincp_index.php index 8860d3a57622831b0a7bde4c1c9a2ee0e1a70bf5..8ba692ae8e956222a3fb82d08920ab40bad7031b 100644 --- a/upload/source/admincp/admincp_index.php +++ b/upload/source/admincp/admincp_index.php @@ -36,6 +36,25 @@ if(empty($siteuniqueid) || strlen($siteuniqueid) < 16) { updatecache('setting'); } +if(!empty($_GET['closesitereleasetips'])) { + C::t('common_setting')->update('sitereleasetips', 0); + $sitereleasetips = 0; + require_once libfile('function/cache'); + updatecache('setting'); +} else { + $sitereleasetips = C::t('common_setting')->fetch('sitereleasetips'); +} + +$siterelease = C::t('common_setting')->fetch('siterelease'); +$releasehash = substr(hash('sha512', $_G['config']['security']['authkey'].DISCUZ_VERSION.DISCUZ_RELEASE.$siteuniqueid), 0, 32); +if(empty($siterelease) || strcmp($siterelease, $releasehash) !== 0) { + C::t('common_setting')->update('siteversion', DISCUZ_VERSION); + C::t('common_setting')->update('siterelease', $releasehash); + C::t('common_setting')->update('sitereleasetips', 1); + $sitereleasetips = 1; + require_once libfile('function/cache'); + updatecache('setting'); +} if(submitcheck('notesubmit', 1)) { if(!empty($_GET['noteid']) && is_numeric($_GET['noteid'])) { @@ -259,6 +278,14 @@ if ($env_ok) { } showtablefooter(); +if($sitereleasetips) { + showtableheader('version_tips', 'fixpadding'); + showtablerow('', array('', 'class="td21" style="text-align:right;"'), + ''.lang("admincp", "version_tips_msg", array('ADMINSCRIPT' => ADMINSCRIPT, 'version' => constant("DISCUZ_VERSION").' R'.constant("DISCUZ_RELEASE"))).'' + ); + showtablefooter(); +} + showtableheader('home_onlines', 'nobottom fixpadding'); echo ''.$onlines.''; showtablefooter(); diff --git a/upload/source/admincp/admincp_login.php b/upload/source/admincp/admincp_login.php index 90090f5ba18fa5e345b0d24fc256f4fa27569691..fa22f9ac21ca853220ba2d7cab4fe6453e192a02 100644 --- a/upload/source/admincp/admincp_login.php +++ b/upload/source/admincp/admincp_login.php @@ -23,7 +23,10 @@ if($this->cpaccess == -3) { } -if($this->cpaccess == -3) { +if(!getglobal('uid') && getglobal('config/admincp/mustlogin')) { + echo '

'.lang('admincp_login', 'login_cp_guest').'

'; + +} elseif(!getstatus(getglobal('member/allowadmincp'), 1) || $this->cpaccess == -3) { echo '

'.lang('admincp_login', 'login_cp_noaccess').'

'; diff --git a/upload/source/admincp/admincp_menu.php b/upload/source/admincp/admincp_menu.php index 561931188938cc47ac59b50d98b1fa7524e84948..3324ceebf7451407a780987d1b0cf0aec84bee43 100644 --- a/upload/source/admincp/admincp_menu.php +++ b/upload/source/admincp/admincp_menu.php @@ -243,6 +243,7 @@ $menu['tools'] = array( $isfounder ? array('menu_tools_fileperms', 'tools_fileperms') : null, $isfounder ? array('menu_tools_filecheck', 'checktools_filecheck') : null, $isfounder ? array('menu_tools_hookcheck', 'checktools_hookcheck') : null, + $isfounder ? array('menu_tools_replacekey', 'checktools_replacekey') : null, ); if($isfounder) { diff --git a/upload/source/admincp/admincp_optimizer.php b/upload/source/admincp/admincp_optimizer.php index b275323a928d5cbdcf8fe68f78e885183573053c..d2d706bbde669418bf22a50853fc36736f2ecf9e 100644 --- a/upload/source/admincp/admincp_optimizer.php +++ b/upload/source/admincp/admincp_optimizer.php @@ -43,6 +43,9 @@ $security_option = array( 'optimizer_plugin', 'optimizer_loginpwcheck', 'optimizer_loginoutofdate', + 'optimizer_dbbackup_visit', + 'optimizer_filesafe', + 'optimizer_remote', ); $serversec_option = array( diff --git a/upload/source/class/optimizer/optimizer_dbbackup_visit.php b/upload/source/class/optimizer/optimizer_dbbackup_visit.php new file mode 100644 index 0000000000000000000000000000000000000000..6f1b7dc38b7f6ac2851fd056f0c66f3520e30951 --- /dev/null +++ b/upload/source/class/optimizer/optimizer_dbbackup_visit.php @@ -0,0 +1,102 @@ +check_exportfile($exportlog, $exportziplog, $exportsize, $filecount); + if(!$filecount) { + $return = array('status' => 0, 'type' => 'none', 'lang' => lang('optimizer', 'optimizer_dbbackup_visit_safe')); + } else { + $return = array('status' => 1, 'type' => 'notice', 'lang' => lang('optimizer', 'optimizer_dbbackup_visit_delete', array('filecount' => $filecount))); + } + return $return; + } + + function get_backup_dir() { + + $backupdirs = array(); + $dir = dir(DISCUZ_ROOT.'./data'); + while(($file = $dir->read()) !== FALSE) { + if(filetype(DISCUZ_ROOT.'./data/'.$file) == 'dir' && preg_match('/^backup_\w+/', $file)) { + $backupdirs[] = $file; + } + } + $dir->close(); + return $backupdirs; + } + + function check_exportfile(&$exportlog, &$exportziplog, &$exportsize, &$filecount) { + + $backupdirs = $this->get_backup_dir(); + if(empty($backupdirs)) { + return; + } + + $filecount = 0; + foreach($backupdirs as $backupdir) { + $dir = dir(DISCUZ_ROOT.'./data/'.$backupdir); + while($entry = $dir->read()) { + $entry = './data/'.$backupdir.'/'.$entry; + if(is_file($entry)) { + if(preg_match("/\.sql$/i", $entry)) { + $filesize = filesize($entry); + $fp = fopen($entry, 'rb'); + $identify = explode(',', base64_decode(preg_replace("/^# Identify:\s*(\w+).*/s", "\\1", fgets($fp, 256)))); + fclose($fp); + $key = preg_replace('/^(.+?)(\-\d+)\.sql$/i', '\\1', basename($entry)); + $exportlog[$key][$identify[4]] = array( + 'version' => $identify[1], + 'type' => $identify[2], + 'method' => $identify[3], + 'volume' => $identify[4], + 'tablepre' => $identify[5], + 'dbcharset' => $identify[6], + 'filename' => $entry, + 'dateline' => filemtime($entry), + 'size' => $filesize + ); + $testurl = str_replace('./data/', getglobal('siteurl').'data/', $entry); + $content = dfsockopen($testurl); + if(!empty($content)) { + $filecount++; + $exportsize[$key] += $filesize; + } + } elseif(preg_match("/\.zip$/i", $entry)) { + $key = preg_replace('/^(.+?)(\-\d+)\.zip$/i', '\\1', basename($entry)); + $filesize = filesize($entry); + $exportziplog[$key][] = array( + 'type' => 'zip', + 'filename' => $entry, + 'size' => filesize($entry), + 'dateline' => filemtime($entry) + ); + $testurl = str_replace('./data/', getglobal('siteurl').'data/', $entry); + $content = dfsockopen($testurl); + if(!empty($content)) { + $filecount++; + } + } + } + } + $dir->close(); + } + } +} \ No newline at end of file diff --git a/upload/source/class/optimizer/optimizer_filesafe.php b/upload/source/class/optimizer/optimizer_filesafe.php new file mode 100644 index 0000000000000000000000000000000000000000..7a76f8c9fbb667afcfa2f2eee83118f125a66ed6 --- /dev/null +++ b/upload/source/class/optimizer/optimizer_filesafe.php @@ -0,0 +1,46 @@ + 1, 'type' =>'header', 'lang' => lang('optimizer', 'optimizer_filesafe_need')); + } else { + $return = array('status' => 0, 'type' =>'none', 'lang' => lang('optimizer', 'optimizer_filesafe_no_need')); + } + return $return; + } + + public function optimizer() { + @unlink(DISCUZ_ROOT.'/install/index.php'); + @unlink(DISCUZ_ROOT.'/uc_server/install/index.php'); + @unlink(DISCUZ_ROOT.'/ucenter/install/index.php'); + @unlink(DISCUZ_ROOT.'/data/restore.php'); + if(strcmp(ADMINSCRIPT, 'admin.php') !== 0 && file_exists(DISCUZ_ROOT.'/admin.php')) { + @unlink(DISCUZ_ROOT.'/admin.php'); + } + cpmsg('optimizer_filesafe_optimizer', '', 'error'); + } +} \ No newline at end of file diff --git a/upload/source/class/optimizer/optimizer_remote.php b/upload/source/class/optimizer/optimizer_remote.php new file mode 100644 index 0000000000000000000000000000000000000000..a894636e396e71d2ecf11d26c82ae75709f3834b --- /dev/null +++ b/upload/source/class/optimizer/optimizer_remote.php @@ -0,0 +1,33 @@ + 1, 'type' =>'header', 'lang' => lang('optimizer', 'optimizer_remote_need')); + } else { + $return = array('status' => 0, 'type' =>'none', 'lang' => lang('optimizer', 'optimizer_remote_no_need')); + } + return $return; + } + + public function optimizer() { + cpmsg('optimizer_remote_optimizer', '', 'error'); + } +} \ No newline at end of file diff --git a/upload/source/language/lang_admincp.php b/upload/source/language/lang_admincp.php index 3541adc2b2e52debeaeff02393759628e229316a..14854f5710f9743502dc59a07740101b4c9174d9 100644 --- a/upload/source/language/lang_admincp.php +++ b/upload/source/language/lang_admincp.php @@ -505,6 +505,11 @@ $lang = array 'nav_hookcheck_verify' => '开始校验', 'nav_hookcheck_completed' => '校验结果', + 'nav_replacekey' => '密钥更新', + 'nav_replacekey_confirm' => '确认开始', + 'nav_replacekey_verify' => '开始更新', + 'nav_replacekey_completed' => '更新结果', + 'nav_updatecache' => '更新缓存', 'nav_updatecache_confirm' => '确认开始', 'nav_updatecache_verify' => '开始更新', @@ -5992,6 +5997,10 @@ $lang = array 'hookcheck_discuzhook' => '源文件嵌入点', 'hookcheck_delhook' => '丢失的嵌入点', + 'replacekey_tips' => '
  • 当站点沦陷时您应该考虑在此处密钥更新,以避免黑客通过已知的 AUTHKEY 获取站点控制权限。
  • 少数插件会使用站点密钥保存数据,当重置密钥时相关数据会丢失且无法恢复,敬请注意并在更新前做好数据库与站点文件的备份工作。
  • ', + 'replacekey_tips_step1' => '在操作之前建议您选择低峰期操作或临时关闭下挂网站,并做好数据、文件备份工作,点击下面按钮开始更换', + 'replacekey_tips_step2' => '正在进行密钥更新,请稍候......', + 'imagepreview_imagesize_source' => '原图片大小', 'imagepreview_imagesize_target' => '处理后图片大小', @@ -6069,7 +6078,7 @@ $lang = array 'db_volume' => '卷数', 'db_export_tips_nouc' => '
  • 您当前的数据备份不包含 UCenter,会影响到您的会员数据,请点击这里单独备份 UCenter 数据
  • 数据备份功能根据您的选择备份全部Discuz!数据,导出的数据文件可用“数据恢复”功能或 phpMyAdmin 导入。
  • ', 'db_export_tips_uc' => '
  • 数据备份功能根据您的选择备份全部Discuz! 和 UCenter数据,导出的数据文件可用“数据恢复”功能或 phpMyAdmin 导入。
  • ', - 'db_export_tips' => '
  • 全部备份均不包含模板文件和附件文件。模板、附件的备份只需通过 FTP 等下载 template/、data/attachment/ 目录即可,Discuz! 不提供单独备份。
  • MySQL Dump 的速度比 Discuz! 分卷备份快很多,但需要服务器支持相关的 Shell 权限,同时由于 MySQL 本身的兼容性问题,通常进行备份和恢复的服务器应当具有相同或相近的版本号才能顺利进行。因此 MySQL Dump 是有风险的:一旦进行备份或恢复操作的服务器其中之一禁止了 Shell,或由于版本兼容性问题导致导入失败,您将无法使用 MySQL Dump 备份或由备份数据恢复;Discuz! 分卷备份没有此限制。
  • 数据备份选项中的设置,仅供高级用户的特殊用途使用,当您尚未对数据库做全面细致的了解之前,请使用默认参数备份,否则将导致备份数据错误等严重问题。
  • 十六进制方式可以保证备份数据的完整性,但是备份文件会占用更多的空间。
  • 压缩备份文件可以让您的备份文件占用更小的空间。
  • ', + 'db_export_tips' => '
  • 出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。
  • 全部备份均不包含模板文件和附件文件。模板、附件的备份只需通过 FTP 等下载 template/、data/attachment/ 目录即可,Discuz! 不提供单独备份。
  • MySQL Dump 的速度比 Discuz! 分卷备份快很多,但需要服务器支持相关的 Shell 权限,同时由于 MySQL 本身的兼容性问题,通常进行备份和恢复的服务器应当具有相同或相近的版本号才能顺利进行。因此 MySQL Dump 是有风险的:一旦进行备份或恢复操作的服务器其中之一禁止了 Shell,或由于版本兼容性问题导致导入失败,您将无法使用 MySQL Dump 备份或由备份数据恢复;Discuz! 分卷备份没有此限制。
  • 数据备份选项中的设置,仅供高级用户的特殊用途使用,当您尚未对数据库做全面细致的了解之前,请使用默认参数备份,否则将导致备份数据错误等严重问题。
  • 十六进制方式可以保证备份数据的完整性,但是备份文件会占用更多的空间。
  • 压缩备份文件可以让您的备份文件占用更小的空间。
  • ', 'db_export_type' => '数据备份类型', 'db_export_discuz' => 'Discuz! 数据(不含UCenter)', 'db_export_discuz_uc' => 'Discuz! 和 UCenter 数据', @@ -6098,7 +6107,7 @@ $lang = array 'db_import_confirm' => '导入和当前 Discuz! 版本不一致的数据极有可能产生无法解决的故障,您确定继续吗?', 'db_import_confirm_sql' => '您确定导入该备份吗?', 'db_import_confirm_zip' => '您确定解压该备份吗?', - 'db_import_tips' => '
  • 本功能在恢复备份数据的同时,将全部覆盖原有数据,请确定恢复前已将论坛关闭,恢复全部完成后可以将论坛重新开放。
  • 恢复数据前请在 Discuz! 安装文件目录下 utility 文件夹内找到 restore.php 文件,然后将 restore.php 文件上传到程序文件夹data目录下。为了您站点的安全,成功恢复数据后请务必及时删除 restore.php 文件。
  • 您可以在数据备份记录处查看站点的备份文件的详细信息,删除过期的备份,并导入需要的备份。
  • ', + 'db_import_tips' => '
  • 本功能在恢复备份数据的同时,将全部覆盖原有数据,请确定恢复前已将论坛关闭,恢复全部完成后可以将论坛重新开放。
  • 出于安全考虑,我们强烈建议您下载数据库备份文件后在恢复页面删除数据库数据库备份文件或设置数据库备份文件不可通过 URL 访问,以保证网站安全。
  • 恢复数据前请在 Discuz! 安装文件目录下 utility 文件夹内找到 restore.php 文件,然后将 restore.php 文件上传到程序文件夹data目录下。为了您站点的安全,成功恢复数据后请务必及时删除 restore.php 文件。
  • 您可以在数据备份记录处查看站点的备份文件的详细信息,删除过期的备份,并导入需要的备份。
  • ', 'do_import_option' => '