commit 5d96ff2eed6c6a0aec2ec4f99910428819c1cb35 Author: shenquanyi Date: Tue May 28 11:01:13 2024 +0800 初始化提交 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..5946bf1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.js linguist-language=PHP \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82931a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,51 @@ +############### +# folder # +############### +/runtime + +############### +# fixed file # +############### + + +################# +## Eclipse +################# + +*.pydevproject +.project +.metadata +bin/ +tmp/ +*.tmp +*.swp +*~.nib +local.properties +.classpath +.settings/ +.loadpath +.idea/ +.vscode/ + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + + +############ +## Windows +############ + +# Windows image file caches +Thumbs.db + +# Folder config file +Desktop.ini diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..16e7baa --- /dev/null +++ b/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "{}" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2018 Hunan AoYun Network Technology Co., Ltd. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ab522bf --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# PbootCMS + +### PbootCMS是全新内核且永久开源免费的PHP企业网站开发建设管理系统,是一套高效、简洁、 强悍的可免费商用的PHP CMS源码,能够满足各类企业网站开发建设的需要。系统采用简单到想哭的模板标签,只要懂HTML就可快速开发企业网站。官方提供了大量网站模板免费下载和使用,将致力于为广大开发者和企业提供最佳的网站开发建设解决方案。 +* 系统采用高效、简洁、强悍的模板标签,只要懂HTML就可快速开发企业网站; +* 系统采用PHP语言开发,使用自主研发的高速多层开发框架及缓存技术; +* 系统默认采用sqlite轻型数据库,放入PHP空间即可直接使用,可选mysql等数据库,满足各类存储需求; +* 系统采用响应式管理后台,满足各类设备随时管理的需要; +* 系统支持后台在线升级,满足系统及时升级更新的需要; +* 系统支持内容模型、多语言、自定义表单、筛选、多条件搜索、小程序、APP等功能; +* 系统支持多种URL模式及模型、栏目、内容自定义地址名称,满足各类网站推广优化的需要。 + +## 简单到想哭的模板标签: +``` +1、全局标签示意: +{pboot:sitetitle} 站点标题 +{pboot:sitelogo} 站点logo + +2、列表页标签示意: +{pboot:list num=10 order=date} +

[list:title]

+{/pboot:list} + +3、内容页标签示意: +{content:title} 标题 +{content:subtitle}副标题 +{content:author} 作者 +{content:source} 来源 + +更多简单到想哭的标签请参考开发手册... + +``` + +## 主要功能: +* 支持自定义模板 +* 支持站点信息后台配置 +* 支持无限极栏目 +* 支持自定义内容模型 +* 支持自定义内容字段 +* 支持专题单页内容 +* 支持列表内容管理 +* 支持内容复制移动 +* 支持自定义栏目地址 +* 支持自定义内容地址 +* 支持多语言区域建站 +* 支持手机独立模板 +* 支持手机版域名绑定 +* 支持首页分页 +* 支持页面SEO优化 +* 支持在线留言 +* 支持幻N组灯片轮播 +* 支持友情链接 +* 支持自定义表单 +* 支持多条件筛选 +* 支持多条件搜索 +* 支持验证码开关 +* 支持留言发送到多邮箱 +* 支持API对接 +* 支持小程序/APP开发 +* 支持Ajax远程获取数据 +* 支持自定义标签 +* 支持全站伪静态 +* 支持前端动态缓存 +* 支持系统角色管理 +* 支持完整角色权限管理 +* 支持多用户在线管理 +* 支持系统日志功能 +* 支持数据库在线管理 +* 支持后台在线升级 +* 支持自定义URL模式 + +## 系统安装: + +发布的源码默认采用sqlite数据库,放入PHP(7.0+)空间即可直接使用(不支持php8.0)。 + +如果需要启用Mysql版本,请导入目录下数据库文件/static/backup/sql/xxx.sql,同时请注意使用最新日期名字的脚本文件,并修改config/database数据库连接文件信息。 + +系统后台默认访问路径:http://ip/admin.php 账号:admin 密码:123456, + + +## 升级说明: + +* 使用后台在线升级(推荐): + +支持跨版本升级,会自动升级数据库及代码文件。 + +* 使用全包升级: + +支持跨版本升级,保留config、data、static、template目录,其余全部用新版替换, 同时如果涉及到的中间版本有升级数据库,需要使用群文件数据库脚本升级数据库。 + + +## 授权声明: +1、PbootCMS是免费可商用的建站系统,用户通过官网获取免费域名授权码即算授权成功,并且永久有效。对于已经授权的域名也不存在未来收费的说法,大家可以放心使用。 + +2、PbootCMS系统允许个人或公司进行任意二开及商用,但是不允许任何形式的破解或绕过系统授权的行为,包括但不限于通过PbootCMS系统建设网站、二次开发、发布衍生版本等情况,对于任何破解或绕过PbootCMS官网授权的行为,我们将保留依法追究法律责任的权力。 + +3、PbootCMS除了一个授权文件代码外,其它代码全部开源,并使用Apache2开源协议。对于任何基于PbootCMS进行二开的系统,应该遵守Apache2开源协议的有关要求。 + +4、PbootCMS官方不对使用本软件所构建网站中的文章、商品和其它任何信息承担责任,不管您通过任何渠道下载本软件,您一旦开始安装PbootCMS,即被视为完全理解并接受PbootCMS授权声明的各项条款。 + +## 联系我们: +官方网站:https://www.pbootcms.com/ + +Gitee:https://gitee.com/hnaoyun/PbootCMS diff --git a/api.php b/api.php new file mode 100644 index 0000000..17be95d --- /dev/null +++ b/api.php @@ -0,0 +1,26 @@ + 0, + 'data' => 'The version of your server PHP is too low, and the program requires PHP version not less than 5.3.' + )); + exit(); +} + +// 引用内核启动文件 +require dirname(__FILE__) . '/core/start.php'; diff --git a/apps/admin/controller/IndexController.php b/apps/admin/controller/IndexController.php new file mode 100644 index 0000000..0db2954 --- /dev/null +++ b/apps/admin/controller/IndexController.php @@ -0,0 +1,391 @@ +model = new IndexModel(); + } + + // 登录页面 + public function index() + { + if (session('sid')) { + location(url('admin/Index/home')); + } + $this->assign('admin_check_code', $this->config('admin_check_code')); + $this->display('index.html'); + } + + // 主页面 + public function home() + { + // 手动修改数据名称 + if (get('action') == 'moddb') { + if ($this->modDB()) { + alert_back('修改成功!'); + } else { + alert_back('修改失败!'); + } + } + + // 删除修改后老数据库(上一步无法直接修改删除) + if (issetSession('deldb')) { + @unlink(ROOT_PATH . session('deldb')); + unset($_SESSION['deldb']); + } + + $dbsecurity = true; + // 如果是sqlite数据库,并且路径为默认的,则标记为不安全 + if (get_db_type() == 'sqlite') { + // 数据库配置含有默认名字则进行修改 + if (strpos($this->config('database.dbname'), 'pbootcms') !== false) { + if (get_user_ip() != '127.0.0.1' && $this->modDB()) { // 非本地测试时尝试自动修改数据库名称 + $dbsecurity = true; + } else { + $dbsecurity = false; + } + } elseif (file_exists(ROOT_PATH . '/data/pbootcms.db')) { // 存在多余的默认数据库文件则改名 + rename(ROOT_PATH . '/data/pbootcms.db', ROOT_PATH . '/data/' . get_uniqid() . '.db'); + } + } elseif (file_exists(ROOT_PATH . '/data/pbootcms.db')) { + rename(ROOT_PATH . '/data/pbootcms.db', ROOT_PATH . '/data/' . get_uniqid() . '.db'); + } + + $this->assign('dbsecurity', $dbsecurity); + + if (!session('pwsecurity')) { + location(url('/admin/Index/ucenter')); + } + + $this->assign('server', get_server_info()); + $this->assign('branch', $this->config('upgrade_branch') == '3.X.dev' ? '3.X.dev' : '3.X'); + $this->assign('revise', $this->config('revise_version') ?: '0'); + $this->assign('snuser', $this->config('sn_user') ?: '0'); + $this->assign('site', get_http_url()); + + $this->assign('user_info', $this->model->getUserInfo(session('ucode'))); + + $this->assign('sum_msg', model('admin.content.Message')->getCount()); + + // 内容模型菜单 + $model = model('admin.content.Model'); + $models = $model->getModelMenu(); + foreach ($models as $key => $value) { + $models[$key]->count = $model->getModelCount($value->mcode)->count; + } + + $this->assign('model_msg', $models); + $this->display('system/home.html'); + } + + // 异步登录验证 + public function login() + { + if (!$_POST) { + return; + } + + // 在安装了gd库时才执行验证码验证 + if (extension_loaded("gd") && $this->config('admin_check_code') && strtolower(post('checkcode', 'var')) != session('checkcode')) { + json(0, '验证码错误!'); + } + + // 就收数据 + $username = post('username'); + $password = post('password'); + + if (!preg_match('/^[\x{4e00}-\x{9fa5}\w\-\.@]+$/u', $username)) { + json(0, '用户名含有不允许的特殊字符!'); + } + + if (!$username) { + json(0, '用户名不能为空!'); + } + + if (!$password) { + json(0, '密码不能为空!'); + } + + if (!!$time = $this->checkLoginBlack()) { + $this->log('登录锁定!'); + json(0, '您登录失败次数太多已被锁定,请' . $time . '秒后再试!'); + } + + // 执行用户登录 + $where = array( + 'username' => $username, + 'password' => encrypt_string($password) + ); + + // 判断数据库写入权限 + if ((get_db_type() == 'sqlite') && !is_writable(ROOT_PATH . $this->config('database.dbname'))) { + json(0, '数据库目录写入权限不足!'); + } + + if (!!$login = $this->model->login($where)) { + + session_regenerate_id(true); + session('sid', encrypt_string(session_id() . $login->id)); // 会话标识 + session('M', M); + + session('id', $login->id); // 用户id + session('ucode', $login->ucode); // 用户编码 + session('username', $login->username); // 用户名 + session('realname', $login->realname); // 真实名字 + + if ($where['password'] != '14e1b600b1fd579f47433b88e8d85291') { + session('pwsecurity', true); + } + + session('acodes', $login->acodes); // 用户管理区域 + if ($login->acodes) { // 当前显示区域 + session('acode', $login->acodes[0]); + } else { + session('acode', ''); + } + + session('rcodes', $login->rcodes); // 用户角色代码表 + session('levels', $login->levels); // 用户权限URL列表 + session('menu_tree', $login->menus); // 菜单树 + session('area_map', $login->area_map); // 区域代码名称映射表 + session('area_tree', $login->area_tree); // 用户区域树 + + $this->log('登录成功!'); + json(1, url('admin/Index/home')); + } else { + $this->setLoginBlack(); + $this->log('登录失败!'); + session('checkcode', mt_rand(10000, 99999)); // 登录失败,随机打乱原有验证码 + json(0, '用户名或密码错误!'); + } + } + + // 退出登录 + public function loginOut() + { + session_unset(); + location(url('/admin/Index/index')); + } + + // 用户中心,修改密码 + public function ucenter() + { + if ($_POST) { + $username = post('username'); // 用户名 + $realname = post('realname'); // 真实姓名 + $cpassword = post('cpassword'); // 现在密码 + $password = post('password'); // 新密码 + $rpassword = post('rpassword'); // 确认密码 + + if (!$username) { + alert_back('用户名不能为空!'); + } + if (!$cpassword) { + alert_back('当前密码不能为空!'); + } + + if (!preg_match('/^[\x{4e00}-\x{9fa5}\w\-\.@]+$/u', $username)) { + alert_back('用户名含有不允许的特殊字符!'); + } + + $data = array( + 'username' => $username, + 'realname' => $realname, + 'update_user' => $username + ); + + // 如果有修改密码,则添加数据 + if ($password) { + if ($password != $rpassword) { + alert_back('确认密码不正确!'); + } + $data['password'] = encrypt_string($password); + if ($data['password'] != '14e1b600b1fd579f47433b88e8d85291') { + session('pwsecurity', true); + } else { + session('pwsecurity', false); + } + } + + // 检查现有密码 + if ($this->model->checkUserPwd(encrypt_string($cpassword))) { + if ($this->model->modUserInfo($data)) { + session('username', post('username')); + session('realname', post('realname')); + $this->log('用户资料成功!'); + success('用户资料修改成功!', -1); + } + } else { + $this->log('用户资料修改时当前密码错误!'); + alert_location('当前密码错误!', -1); + } + } + $this->display('system/ucenter.html'); + } + + // 切换显示的数据区域 + public function area() + { + if ($_POST) { + $acode = post('acode'); + if (in_array($acode, session('acodes'))) { + session('acode', $acode); + cookie('lg', $acode); // 同步切换前台语言 + } + location(url('admin/Index/home')); + } + } + + // 清理缓存 + public function clearCache() + { + if (get('delall')) { + $rs = path_delete(RUN_PATH); + } else { + $rs = (path_delete(RUN_PATH . '/cache') && path_delete(RUN_PATH . '/complile') && path_delete(RUN_PATH . '/config') && path_delete(RUN_PATH . '/upgrade')); + } + cache_config(); // 清理缓存后立即生成新的配置 + if ($rs) { + if (extension_loaded('Zend OPcache')) { + opcache_reset(); // 在启用了OPcache加速器时同时清理 + } + $this->log('清理缓存成功!'); + alert_back('清理缓存成功!', 1); + } else { + $this->log('清理缓存失败!'); + alert_back('清理缓存失败!', 0); + } + } + + // 清理系统缓存 + public function clearOnlySysCache() + { + if (get('delall')) { + $rs = path_delete(RUN_PATH); + } else { + $rs = (path_delete(RUN_PATH . '/complile') && path_delete(RUN_PATH . '/config') && path_delete(RUN_PATH . '/upgrade')); + } + cache_config(); // 清理缓存后立即生成新的配置 + if ($rs) { + if (extension_loaded('Zend OPcache')) { + opcache_reset(); // 在启用了OPcache加速器时同时清理 + } + $this->log('清理缓存成功!'); + alert_back('清理缓存成功!', 1); + } else { + $this->log('清理缓存失败!'); + alert_back('清理缓存失败!', 0); + } + } + + // 清理会话 + public function clearSession() + { + ignore_user_abort(true); // 后台运行 + set_time_limit(7200); + ob_start(); + $output['code'] = 1; + $output['data'] = '执行成功,后台自动清理中!'; + $output['tourl'] = ''; + echo json_encode($output); + ob_end_flush(); + flush(); + $rs = path_delete(RUN_PATH . '/session', false, array( + 'sess_' . session_id() + )); + } + + // 文件上传方法 + public function upload() + { + $upload = upload('upload'); + if (is_array($upload)) { + json(1, $upload); + } else { + json(0, $upload); + } + } + + // 检查是否在黑名单 + private function checkLoginBlack() + { + // 读取黑名单 + $ip_black = RUN_PATH . '/data/' . md5('login_black') . '.php'; + if (file_exists($ip_black)) { + $data = require $ip_black; + $user_ip = get_user_ip(); + $lock_time = $this->config('lock_time') ?: 900; + $lock_count = $this->config('lock_count') ?: 5; + if (isset($data[$user_ip]) && $data[$user_ip]['count'] >= $lock_count && time() - $data[$user_ip]['time'] < $lock_time) { + return $lock_time - (time() - $data[$user_ip]['time']); // 返回剩余秒数 + } + } + return false; + } + + // 添加登录黑名单 + private function setLoginBlack() + { + // 读取黑名单 + $ip_black = RUN_PATH . '/data/' . md5('login_black') . '.php'; + if (file_exists($ip_black)) { + $data = require $ip_black; + } else { + $data = array(); + } + + // 添加IP + $user_ip = get_user_ip(); + $lock_time = $this->config('lock_time') ?: 900; + $lock_count = $this->config('lock_count') ?: 5; + if (isset($data[$user_ip]) && $data[$user_ip]['count'] < $lock_count && time() - $data[$user_ip]['time'] < $lock_time) { + $data[$user_ip] = array( + 'time' => time(), + 'count' => $data[get_user_ip()]['count'] + 1 + ); + } else { + $data[$user_ip] = array( + 'time' => time(), + 'count' => 1 + ); + } + + // 写入黑名单 + check_file($ip_black, true); + return file_put_contents($ip_black, "config('database.dbname'); + $dname = '/data/' . get_uniqid() . '.db'; + $sconfig = file_get_contents($file); + $dconfig = str_replace($sname, $dname, $sconfig); + if (file_put_contents($file, $dconfig)) { + if (!copy(ROOT_PATH . $sname, ROOT_PATH . $dname)) { + file_put_contents($file, $sconfig); // 回滚配置 + } else { + session('deldb', $sname); + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/apps/admin/controller/content/CompanyController.php b/apps/admin/controller/content/CompanyController.php new file mode 100644 index 0000000..857f83f --- /dev/null +++ b/apps/admin/controller/content/CompanyController.php @@ -0,0 +1,70 @@ +model = new CompanyModel(); + } + + // 显示公司设置 + public function index() + { + // 获取公司配置 + $this->assign('companys', $this->model->getList()); + $this->display('content/company.html'); + } + + // 修改公司设置 + public function mod() + { + if (! $_POST) { + return; + } + $data = array( + 'name' => post('name'), + 'address' => post('address'), + 'postcode' => post('postcode'), + 'contact' => post('contact'), + 'mobile' => post('mobile'), + 'phone' => post('phone'), + 'fax' => post('fax'), + 'email' => post('email'), + 'qq' => post('qq'), + 'weixin' => post('weixin'), + 'blicense' => post('blicense'), + 'other' => post('other') + ); + + if ($this->model->checkCompany()) { + if ($this->model->modCompany($data)) { + $this->log('修改公司信息成功!'); + success('修改成功!', - 1); + } else { + location(- 1); + } + } else { + $data['acode'] = session('acode'); + if ($this->model->addCompany($data)) { + $this->log('修改公司信息成功!'); + success('修改成功!', - 1); + } else { + location(- 1); + } + } + } +} \ No newline at end of file diff --git a/apps/admin/controller/content/ContentController.php b/apps/admin/controller/content/ContentController.php new file mode 100644 index 0000000..4ef13be --- /dev/null +++ b/apps/admin/controller/content/ContentController.php @@ -0,0 +1,607 @@ +model = new ContentModel(); + } + + // 文章列表 + public function index() + { + if ((! ! $id = get('id', 'int')) && $result = $this->model->getContent($id)) { + $this->assign('more', true); + $this->assign('content', $result); + } else { + $this->assign('list', true); + if (! $mcode = get('mcode', 'var')) { + error('传递的模型编码参数有误,请核对后重试!'); + } + + if (isset($_GET['keyword'])) { + if (! ! $scode = get('scode', 'var')) { + $result = $this->model->findContent($mcode, $scode, get('keyword', 'vars')); + } else { + $result = $this->model->findContentAll($mcode, get('keyword', 'vars')); + } + } elseif (! ! $scode = get('scode', 'int')) { + $result = $this->model->findContent($mcode, $scode, ''); + } else { + $result = $this->model->getList($mcode); + } + $this->assign('contents', $result); + + // 文章分类下拉列表 + $sort_model = model('admin.content.ContentSort'); + $sort_select = $sort_model->getListSelect($mcode); + $this->assign('search_select', $this->makeSortSelect($sort_select, get('scode'))); + $this->assign('sort_select', $this->makeSortSelect($sort_select, session('addscode'))); + $this->assign('subsort_select', $this->makeSortSelect($sort_select)); + + // 模型名称 + $this->assign('model_name', model('admin.content.Model')->getName($mcode)); + + // 扩展字段 + $this->assign('extfield', model('admin.content.ExtField')->getModelField($mcode)); + + $this->assign('baidu_zz_token', $this->config('baidu_zz_token')); + $this->assign('baidu_ks_token', $this->config('baidu_ks_token')); + + // 前端地址连接符判断 + $url_break_char = $this->config('url_break_char') ?: '_'; + $this->assign('url_break_char', $url_break_char); + + // 获取会员分组 + $this->assign('groups', model('admin.member.MemberGroup')->getSelect()); + } + + $this->display('content/content.html'); + } + + // 文章增加 + public function add() + { + if ($_POST) { + + // 获取数据 + $scode = post('scode'); + $subscode = post('subscode'); + $title = post('title'); + $titlecolor = post('titlecolor'); + $subtitle = post('subtitle'); + $filename = trim(post('filename'), '/'); + $author = post('author'); + $source = post('source'); + $outlink = post('outlink'); + $date = post('date'); + $ico = post('ico'); + $pics = post('pics'); + + // 获取多图标题 + $picstitle = post('picstitle'); + if ($picstitle) { + $picstitle = implode(',', $picstitle); + } + + $content = post('content'); + $tags = str_replace(',', ',', post('tags')); + $enclosure = post('enclosure'); + $keywords = post('keywords'); + $description = post('description'); + $status = post('status', 'int'); + $istop = post('istop', 'int', '', '', 0); + $isrecommend = post('isrecommend', 'int', '', '', 0); + $isheadline = post('isheadline', 'int', '', '', 0); + + $gid = post('gid', 'int') ?: 0; + $gtype = post('gtype', 'int') ?: 4; + $gnote = post('gnote'); + + if (! $scode) { + alert_back('内容分类不能为空!'); + } + + if (! $title) { + alert_back('文章标题不能为空!'); + } + + if ($filename && ! preg_match('/^[a-zA-Z0-9\-_\/]+$/', $filename)) { + alert_back('内容URL名称只允许字母、数字、横线、下划线组成!'); + } + + // 新闻tag为空则给默认值 + // $sort_model = model('admin.content.ContentSort'); + // $sort_select = $sort_model->getSortByScode($scode); + // if ($sort_select->p_name == '新闻') { + // $tags = !empty($tags) ? $tags : ContentModel::$newsTagDefault; + // } + $tags = !empty($tags) ? $tags : ContentModel::$TagDefault; + $keywords = !empty($keywords) ? $keywords : ContentModel::$KeywordsDefault; + + $content = self::fillContentImage($content, $title); + + // 自动提起前一百个字符为描述 + if (! $description && isset($_POST['content'])) { + $description = escape_string(clear_html_blank(substr_both(strip_tags($_POST['content']), 0, 150))); + } + + // 无缩略图时,自动提取文章第一张图为缩略图 + if (! $ico && preg_match('//i', decode_string($content), $srcs) && isset($srcs[1])) { + $ico = $srcs[1]; + } + + // 缩放缩略图 + if ($ico) { + resize_img(ROOT_PATH . $ico, '', $this->config('ico.max_width'), $this->config('ico.max_height')); + } + + // 检查自定义URL名称 + if ($filename) { + while ($this->model->checkFilename($filename)) { + $filename = $filename . '-' . mt_rand(1, 20); + } + } + + // 记住新增栏目 + session('addscode', $scode); + + // 构建数据 + $data = array( + 'acode' => session('acode'), + 'scode' => $scode, + 'subscode' => $subscode, + 'title' => $title, + 'titlecolor' => $titlecolor, + 'subtitle' => $subtitle, + 'filename' => $filename, + 'author' => $author, + 'source' => $source, + 'outlink' => $outlink, + 'date' => $date, + 'ico' => $ico, + 'pics' => $pics, + 'picstitle' => $picstitle, + 'content' => $content, + 'tags' => $tags, + 'enclosure' => $enclosure, + 'keywords' => $keywords, + 'description' => clear_html_blank($description), + 'sorting' => 255, + 'status' => $status, + 'istop' => $istop, + 'isrecommend' => $isrecommend, + 'isheadline' => $isheadline, + 'gid' => $gid, + 'gtype' => $gtype, + 'gnote' => $gnote, + 'visits' => 0, + 'likes' => 0, + 'oppose' => 0, + 'create_user' => session('username'), + 'update_user' => session('username') + ); + + // 执行添加 + if (! ! $id = $this->model->addContent($data)) { + // 扩展内容添加 + foreach ($_POST as $key => $value) { + if (preg_match('/^ext_[\w\-]+$/', $key)) { + if (! isset($data2['contentid'])) { + $data2['contentid'] = $id; + } + $temp = post($key); + if (is_array($temp)) { + $data2[$key] = implode(',', $temp); + } else { + $data2[$key] = str_replace("\r\n", '
', $temp); + } + } + } + if (isset($data2)) { + if (! $this->model->addContentExt($data2)) { + $this->model->delContent($id); + $this->log('新增文章失败!'); + error('新增失败!', - 1); + } + } + + $this->log('新增文章成功!'); + if (! ! $backurl = get('backurl')) { + success('新增成功!', base64_decode($backurl)); + } else { + success('新增成功!', url('/admin/Content/index/mcode/' . get('mcode'))); + } + } else { + $this->log('新增文章失败!'); + error('新增失败!', - 1); + } + } + } + + // 给文本域补充一张图片 + public static function fillContentImage($content, $title) + { + try { + $images_dir_root = ROOT_PATH . "/static/upload/default_image"; // 图片文件夹物理路径 + $images_dir_static = STATIC_DIR . "/upload/default_image"; // 图片文件夹路径 + $images = array_diff(scandir($images_dir_root), array('..', '.')); // 列出所有图片文件 + if (count($images) == 0) { + return $content; + } + + $random_image = $images[array_rand($images)]; // 随机选择一张图片 + // 构造标签 + $image_tag = "

\"$title\"

"; + // 获取文本域内容并插入图片 + $content = $content . escape_string($image_tag); + } catch (Exception $e) { + //throw $th; + } + + return $content; + } + + // 生成分类选择 + private function makeSortSelect($tree, $selectid = null) + { + $list_html = ''; + foreach ($tree as $value) { + // 默认选择项 + if ($selectid == $value->scode) { + $select = "selected='selected'"; + } else { + $select = ''; + } + $list_html .= "