Browse Source

first commit

master
unknown 2 years ago
commit
fbc2634b88
  1. 13
      .gitignore
  2. 20
      HuoCMS_close_source/.example.env
  3. 42
      HuoCMS_close_source/.travis.yml
  4. 201
      HuoCMS_close_source/LICENSE
  5. 32
      HuoCMS_close_source/LICENSE.txt
  6. 124
      HuoCMS_close_source/README.md
  7. 22
      HuoCMS_close_source/app/AppService.php
  8. 118
      HuoCMS_close_source/app/BaseController.php
  9. 82
      HuoCMS_close_source/app/ExceptionHandle.php
  10. 309
      HuoCMS_close_source/app/Plugin.php
  11. 8
      HuoCMS_close_source/app/Request.php
  12. 101
      HuoCMS_close_source/app/command/BaiduTongji.php
  13. 61
      HuoCMS_close_source/app/command/CreateController.php
  14. 53
      HuoCMS_close_source/app/command/CreateLink.php
  15. 28
      HuoCMS_close_source/app/command/CreateModel.php
  16. 59
      HuoCMS_close_source/app/command/WebDiagnosis.php
  17. 55
      HuoCMS_close_source/app/command/WebDiagnosis2.php
  18. 55
      HuoCMS_close_source/app/command/WebDiagnosis3.php
  19. 30
      HuoCMS_close_source/app/command/service/Server.php
  20. 149
      HuoCMS_close_source/app/command/service/TaskServer.php
  21. 171
      HuoCMS_close_source/app/command/service/TongJiServer.php
  22. 55
      HuoCMS_close_source/app/command/service/step/CheckIncluded.php
  23. 124
      HuoCMS_close_source/app/command/service/step/CheckKeywords.php
  24. 78
      HuoCMS_close_source/app/command/service/step/CheckLinks.php
  25. 156
      HuoCMS_close_source/app/command/service/step/CheckSSL301.php
  26. 136
      HuoCMS_close_source/app/command/service/step/CheckTplCode.php
  27. 138
      HuoCMS_close_source/app/command/stubs/controller.stub
  28. 113
      HuoCMS_close_source/app/command/stubs/model.stub
  29. 1300
      HuoCMS_close_source/app/common.php
  30. 1
      HuoCMS_close_source/app/controller/api/.gitignore
  31. 204
      HuoCMS_close_source/app/controller/backend/AccountController.php
  32. 322
      HuoCMS_close_source/app/controller/backend/AdminController.php
  33. 40
      HuoCMS_close_source/app/controller/backend/AdminLoginLogController.php
  34. 182
      HuoCMS_close_source/app/controller/backend/AdminMenuController.php
  35. 41
      HuoCMS_close_source/app/controller/backend/AdminOptLogController.php
  36. 140
      HuoCMS_close_source/app/controller/backend/AdvertisementController.php
  37. 158
      HuoCMS_close_source/app/controller/backend/AttachmentCateController.php
  38. 508
      HuoCMS_close_source/app/controller/backend/AttachmentController.php
  39. 90
      HuoCMS_close_source/app/controller/backend/BaseController.php
  40. 537
      HuoCMS_close_source/app/controller/backend/CategoryController.php
  41. 1110
      HuoCMS_close_source/app/controller/backend/ContentController.php
  42. 146
      HuoCMS_close_source/app/controller/backend/ContentTagController.php
  43. 68
      HuoCMS_close_source/app/controller/backend/DashboardController.php
  44. 146
      HuoCMS_close_source/app/controller/backend/DatabaseController.php
  45. 686
      HuoCMS_close_source/app/controller/backend/DesignController.php
  46. 27
      HuoCMS_close_source/app/controller/backend/ExcelController.php
  47. 585
      HuoCMS_close_source/app/controller/backend/FormController.php
  48. 14
      HuoCMS_close_source/app/controller/backend/GoogleStatisticsController.php
  49. 154
      HuoCMS_close_source/app/controller/backend/InnerChartController.php
  50. 130
      HuoCMS_close_source/app/controller/backend/InquiryCategoryController.php
  51. 231
      HuoCMS_close_source/app/controller/backend/InquiryController.php
  52. 152
      HuoCMS_close_source/app/controller/backend/InquiryEmailController.php
  53. 153
      HuoCMS_close_source/app/controller/backend/JobCateController.php
  54. 154
      HuoCMS_close_source/app/controller/backend/JobCityController.php
  55. 164
      HuoCMS_close_source/app/controller/backend/JobController.php
  56. 356
      HuoCMS_close_source/app/controller/backend/KeywordController.php
  57. 91
      HuoCMS_close_source/app/controller/backend/KeywordQueryController.php
  58. 129
      HuoCMS_close_source/app/controller/backend/KeywordWebsiteController.php
  59. 255
      HuoCMS_close_source/app/controller/backend/LinkController.php
  60. 105
      HuoCMS_close_source/app/controller/backend/MaterialController.php
  61. 163
      HuoCMS_close_source/app/controller/backend/ModuleController.php
  62. 159
      HuoCMS_close_source/app/controller/backend/ModuleFieldController.php
  63. 166
      HuoCMS_close_source/app/controller/backend/NavCateController.php
  64. 316
      HuoCMS_close_source/app/controller/backend/NavController.php
  65. 52
      HuoCMS_close_source/app/controller/backend/PluginController.php
  66. 185
      HuoCMS_close_source/app/controller/backend/PosterController.php
  67. 121
      HuoCMS_close_source/app/controller/backend/RecycleBinController.php
  68. 108
      HuoCMS_close_source/app/controller/backend/ResumeController.php
  69. 186
      HuoCMS_close_source/app/controller/backend/RoleController.php
  70. 80
      HuoCMS_close_source/app/controller/backend/SeoAccountController.php
  71. 242
      HuoCMS_close_source/app/controller/backend/SeoCheckController.php
  72. 54
      HuoCMS_close_source/app/controller/backend/SeoController.php
  73. 139
      HuoCMS_close_source/app/controller/backend/SeoSettingController.php
  74. 46
      HuoCMS_close_source/app/controller/backend/SiteMapController.php
  75. 125
      HuoCMS_close_source/app/controller/backend/SlideCateController.php
  76. 134
      HuoCMS_close_source/app/controller/backend/SlideController.php
  77. 139
      HuoCMS_close_source/app/controller/backend/SocialMarketingController.php
  78. 45
      HuoCMS_close_source/app/controller/backend/StaticFileController.php
  79. 617
      HuoCMS_close_source/app/controller/backend/StatisticsController.php
  80. 180
      HuoCMS_close_source/app/controller/backend/SysSettingController.php
  81. 539
      HuoCMS_close_source/app/controller/backend/SystemInstallController.php
  82. 169
      HuoCMS_close_source/app/controller/backend/TagController.php
  83. 277
      HuoCMS_close_source/app/controller/backend/ThemeController.php
  84. 206
      HuoCMS_close_source/app/controller/backend/ThemeFileController.php
  85. 84
      HuoCMS_close_source/app/controller/backend/UploadController.php
  86. 287
      HuoCMS_close_source/app/controller/backend/WebsiteController.php
  87. 86
      HuoCMS_close_source/app/controller/backend/WebsiteLangController.php
  88. 90
      HuoCMS_close_source/app/controller/backend/WebsiteServerController.php
  89. 125
      HuoCMS_close_source/app/controller/backend/WebsiteSettingController.php
  90. 333
      HuoCMS_close_source/app/controller/frontend/BaseController.php
  91. 132
      HuoCMS_close_source/app/controller/frontend/DesignBaseController.php
  92. 140
      HuoCMS_close_source/app/controller/frontend/DesignController.php
  93. 128
      HuoCMS_close_source/app/controller/frontend/DetailController.php
  94. 274
      HuoCMS_close_source/app/controller/frontend/FormController.php
  95. 105
      HuoCMS_close_source/app/controller/frontend/InquiryController.php
  96. 55
      HuoCMS_close_source/app/controller/frontend/ListController.php
  97. 67
      HuoCMS_close_source/app/controller/frontend/ResumeController.php
  98. 89
      HuoCMS_close_source/app/controller/frontend/SearchController.php
  99. 55
      HuoCMS_close_source/app/controller/frontend/SeoController.php
  100. 59
      HuoCMS_close_source/app/controller/frontend/TagController.php

13
.gitignore

@ -0,0 +1,13 @@
/HuoCMS_close_source/.env
/.idea
/.vscode
/.Ds.store
*.log
*.DS_Store
/HuoCMS_close_source/runtime
.VSCodeCounter/
/HuoCMS_close_source/composer.lock
/HuoCMS_close_source/public/nginx.htaccess
/HuoCMS_close_source/public/.htaccess
/HuoCMS_close_source/public/excel/*
/docker-compose/mysql/data/

20
HuoCMS_close_source/.example.env

@ -0,0 +1,20 @@
APP_DEBUG = true
APP_HOST = http://localhost
[APP]
DEFAULT_TIMEZONE = Asia/Shanghai
LAZY_LOAD_SIZE =
[DATABASE]
TYPE = mysql
HOSTNAME = 127.0.0.1
DATABASE = huo_cms
USERNAME = root
PASSWORD =
HOSTPORT = 3306
CHARSET = utf8mb4
DEBUG = true
PREFIX = hc_
[LANG]
default_lang = zh

42
HuoCMS_close_source/.travis.yml

@ -0,0 +1,42 @@
sudo: false
language: php
branches:
only:
- stable
cache:
directories:
- $HOME/.composer/cache
before_install:
- composer self-update
install:
- composer install --no-dev --no-interaction --ignore-platform-reqs
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Core.zip .
- composer require --update-no-dev --no-interaction "topthink/think-image:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-migration:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-captcha:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-mongo:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-worker:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-helper:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-queue:^1.0"
- composer require --update-no-dev --no-interaction "topthink/think-angular:^1.0"
- composer require --dev --update-no-dev --no-interaction "topthink/think-testing:^1.0"
- zip -r --exclude='*.git*' --exclude='*.zip' --exclude='*.travis.yml' ThinkPHP_Full.zip .
script:
- php think unit
deploy:
provider: releases
api_key:
secure: TSF6bnl2JYN72UQOORAJYL+CqIryP2gHVKt6grfveQ7d9rleAEoxlq6PWxbvTI4jZ5nrPpUcBUpWIJHNgVcs+bzLFtyh5THaLqm39uCgBbrW7M8rI26L8sBh/6nsdtGgdeQrO/cLu31QoTzbwuz1WfAVoCdCkOSZeXyT/CclH99qV6RYyQYqaD2wpRjrhA5O4fSsEkiPVuk0GaOogFlrQHx+C+lHnf6pa1KxEoN1A0UxxVfGX6K4y5g4WQDO5zT4bLeubkWOXK0G51XSvACDOZVIyLdjApaOFTwamPcD3S1tfvuxRWWvsCD5ljFvb2kSmx5BIBNwN80MzuBmrGIC27XLGOxyMerwKxB6DskNUO9PflKHDPI61DRq0FTy1fv70SFMSiAtUv9aJRT41NQh9iJJ0vC8dl+xcxrWIjU1GG6+l/ZcRqVx9V1VuGQsLKndGhja7SQ+X1slHl76fRq223sMOql7MFCd0vvvxVQ2V39CcFKao/LB1aPH3VhODDEyxwx6aXoTznvC/QPepgWsHOWQzKj9ftsgDbsNiyFlXL4cu8DWUty6rQy8zT2b4O8b1xjcwSUCsy+auEjBamzQkMJFNlZAIUrukL/NbUhQU37TAbwsFyz7X0E/u/VMle/nBCNAzgkMwAUjiHM6FqrKKBRWFbPrSIixjfjkCnrMEPw=
file:
- ThinkPHP_Core.zip
- ThinkPHP_Full.zip
skip_cleanup: true
on:
tags: true

201
HuoCMS_close_source/LICENSE

@ -0,0 +1,201 @@
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:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) 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
(d) 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 [yyyy] [name of copyright owner]
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.

32
HuoCMS_close_source/LICENSE.txt

@ -0,0 +1,32 @@
ThinkPHP遵循Apache2开源协议发布,并提供免费使用。
版权所有Copyright © 2006-2016 by ThinkPHP (http://thinkphp.cn)
All rights reserved。
ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。
Apache Licence是著名的非盈利开源组织Apache采用的协议。
该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,
允许代码修改,再作为开源或商业软件发布。需要满足
的条件:
1. 需要给代码的用户一份Apache Licence ;
2. 如果你修改了代码,需要在被修改的文件中说明;
3. 在延伸的代码中(修改和有源代码衍生的代码中)需要
带有原来代码中的协议,商标,专利声明和其他原来作者规
定需要包含的说明;
4. 如果再发布的产品中包含一个Notice文件,则在Notice文
件中需要带有本协议内容。你可以在Notice中增加自己的
许可,但不可以表现为对Apache Licence构成更改。
具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

124
HuoCMS_close_source/README.md

@ -0,0 +1,124 @@
# HuoCMS
## 声明
HuoCMS是一款免费的开源可商用网站建设系统,但是商用需要在官网: http://www.huocms.com 获取免费授权,授权的域名需要获得备案。
获取专属定制版以及更多版本信息,可访问HuoCMS官网,了解更多。
## 系统简介
基于ThinkPhp6.0+Vue 开发的一套HuoCMS建站系统。
HuoCMS是一套内容管理系统同时也是一套企业官网建设系统,能够帮过用户快速搭建自己的网站。可以满足企业站,外贸站,个人博客等一系列的建站需求。HuoCMS的优势: 可以使用统一后台管理多个网站的内容,统一维护,不同内容可以在不同的网站上面共享,方便快捷。
HuoCMS亮点
```
多语言,多站点自由切换
后台界面美观
附件统一管理,一次上传重复使用
网站内容集中管理,一次添加,多个站点共同享用
SEO功能强大
前台模版自由定义和切换
具有丰富的前台模版标签,方便用户自由调用内容
。。。。。。。
```
## 系统演示
HuoCMS后台演示站点(请使用电脑PC打开)
地址:http://demo.huocms.com/admin.php
账号:admin@admin.com
密码:123123
HuoCMS开发群(QQ):714064832
前台仓库访问地址: https://gitee.com/njsq/huocms_vue
前台仓库克隆地址: `https://gitee.com/njsq/huocms_vue.git`
## 页面展示
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/cover.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/01.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/02.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/03.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/04.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/05.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/06.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/07.jpg)
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/intro/08.jpg)
## 安装教程
### 软件下载
- 在`git`仓库 `https://gitee.com/digital-flag/huocms.git` ,克隆下载
- 在`HuoCMS`官网上`http://www.huocms.com`下载全量安装包
### 环境推荐
```
* 最好选择类Unix系统(推荐Linux)
* Nignx/Apache/IIS
* PHP >7.2
* MySQL 5.7
环境搭建推荐选择使用bt宝塔面板,简单易用。
```
### 安装HuoCMS
1. 勾选许可协议,继续安装
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/install/1.png)
2. 环境监测:检查环境是否都正确,确认无误后,点击下一步。如有X号等错误提示,请根据提示修改服务器环境配置。
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/install/2.png)
3. 配置系统:填写数据库用户名、数据库名、数据库密码、后台管理员账号密码
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/install/3.png)
4. 创建数据库
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/install/4.png)
5. 完成安装,访问后台
![image](https://gitee.com/njsq/huocms_readme_static/raw/master/readme/install/5.png)
### 登录
前台地址: http://你的域名
后台地址:http://你的域名/admin.php;
账号密码:
| 账号 | 密码 |
| ---- | ---- |
| admin@admin.com | huocms.com |
或者是你在配置系统安装步骤配置的密码。
## 问题反馈
官方网站:
http://www.huocms.com
官方QQ群:
714064832
## 版权授权
- HuoCMS是一款免费的开源可商用系统,但是商用需要在HuoCMS官网http://www.huocms.com/grant.html 上获取授权码,主域名获取授权,授权域名需要取得备案。
- 免费的授权需要保留前台的HuoCMS版权,以及后台的版权和Logo,去版权请到HuoCMS官网授权页面http://www.huocms.com/grant.html 获取去版权和Logo的授权。
- 禁止将本项目的代码和资源进行任何形式的出售(包括二开后的衍生产品),产生的一切任何后果责任由侵权者自负。
- HuoCMS系统允许个人或公司进行任意二开及商用,但是不允许任何形式的破解或绕过系统授权的行为,包括但不限于通过HuoCMS系统建设网站、二次开发、发布衍生版本等情况,对于任何破解或绕过HuoCMS官网授权的行为,我们将保留依法追究法律责任的权力。
- HuoCMS官方不对使用本软件所构建网站中的文章、产品和其它任何信息承担责任,不管您通过任何渠道下载本软件,您一旦开始安装HuoCMS,即被视为完全理解并接受HuoCMS授权声明的各项条款。
## 特别鸣谢
- ThinkPHP: https://www.thinkphp.cn/
- ThinkCmf: https://www.thinkcmf.com/
- Vue: https://cn.vuejs.org/
- ElementUI: https://element.eleme.cn/#/zh-CN
- ElementAdmin: https://panjiachen.github.io/vue-element-admin-site/zh/
---
版权信息 HuoCMS
版权所有Copyright © 2021 by HuoCMS (http://www.huocms.com)
All rights reserved。

22
HuoCMS_close_source/app/AppService.php

@ -0,0 +1,22 @@
<?php
declare (strict_types = 1);
namespace app;
use think\Service;
/**
* 应用服务类
*/
class AppService extends Service
{
public function register()
{
// 服务注册
}
public function boot()
{
// 服务启动
}
}

118
HuoCMS_close_source/app/BaseController.php

@ -0,0 +1,118 @@
<?php
declare (strict_types = 1);
namespace app;
use think\App;
use think\Container;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\Response;
use think\Validate;
/**
* 控制器基础类
*/
abstract class BaseController
{
/**
* Request实例
* @var \think\Request
*/
protected $request;
/**
* 应用实例
* @var \think\App
*/
protected $app;
/**
* 是否批量验证
* @var bool
*/
protected $batchValidate = false;
/**
* 构造方法
* @access public
* @param App $app 应用对象
*/
public function __construct(App $app)
{
$this->app = $app;
$this->request = $this->app->request;
// 控制器初始化
$this->initialize();
}
// 初始化
protected function initialize()
{
// 允许跨域
$this->cors();
}
public function cors()
{
header("access-control-allow-headers: Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified-Since,Keep-Alive,Origin,Login-Agent,X-Mx-ReqToken,X-Requested-With");
header("access-control-allow-methods: GET, POST, PUT, DELETE, HEAD, OPTIONS,PATCH");
header("access-control-allow-credentials: true");
header("access-control-allow-origin: *");
}
/**
* 验证数据
* @access protected
* @param array $data 数据
* @param string|array $validate 验证器名或者验证规则数组
* @param array $message 提示信息
* @param bool $batch 是否批量验证
* @return array|string|true
* @throws ValidateException
*/
protected function validate(array $data, $validate, array $message = [], bool $batch = false)
{
if (is_array($validate)) {
$v = new Validate();
$v->rule($validate);
} else {
if (strpos($validate, '.')) {
// 支持场景
[$validate, $scene] = explode('.', $validate);
}
$class = false !== strpos($validate, '\\') ? $validate : $this->app->parseClass('validate', $validate);
$v = new $class();
if (!empty($scene)) {
$v->scene($scene);
}
}
$v->message($message);
// 是否批量验证
if ($batch || $this->batchValidate) {
$v->batch(true);
}
return $v->failException(true)->check($data);
}
/**
* 获取当前的response 输出类型
* @access protected
* @return string
*/
protected function getResponseType(): string
{
if (!$this->app) {
$this->app = Container::get('app');
}
$isAjax = $this->request->isAjax();
return $isAjax || $this->request->isJson()
? 'json'
: 'html';
}
}

82
HuoCMS_close_source/app/ExceptionHandle.php

@ -0,0 +1,82 @@
<?php
namespace app;
use app\exception\AuthException;
use app\exception\BadSysSettingException;
use app\exception\BaseException;
use app\exception\ModelException;
use app\exception\ModelNotUniqueException;
use app\exception\TokenException;
use think\db\exception\DataNotFoundException;
use think\db\exception\ModelNotFoundException;
use think\exception\Handle;
use think\exception\HttpException;
use think\exception\HttpResponseException;
use think\exception\ValidateException;
use think\facade\Log;
use think\Response;
use Throwable;
/**
* 应用异常处理类
*/
class ExceptionHandle extends Handle
{
/**
* 不需要记录信息(日志)的异常类列表
* @var array
*/
protected $ignoreReport = [
HttpException::class,
HttpResponseException::class,
ModelNotFoundException::class,
DataNotFoundException::class,
ValidateException::class,
];
/**
* 记录异常信息(包括日志或者其它方式记录)
*
* @access public
* @param Throwable $exception
* @return void
*/
public function report(Throwable $exception): void
{
// 使用内置的方式记录异常日志
parent::report($exception);
}
/**
* Render an exception into an HTTP response.
*
* @access public
* @param \think\Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 详细错误日志写入文件
Log::error($e->getMessage());
$str = $this->formatterTraceStr($e);
Log::error($str);
if(request()->isAjax() || request()->isJson() || env('APP_DEBUG') == 1){
// 添加自定义异常处理机制
return jsonReturn($e->getCode() ?: -1, $e->getMessage());
}
// 其他错误交给系统处理
return parent::render($request, $e);
}
public function formatterTraceStr(Throwable $e): string
{
$str = "=========手动记录日志=============\n" ;
$str .= '请求的API是【' . request()->url() . "\n";
$str .= '请求携带的参数是【' . json_encode(request() -> param()) . "\n";
$str .= $e->getTraceAsString();
$str .= "\n".date('Y-m-d H:i:s') . "】=========日志记录结束=============";
return $str;
}
}

309
HuoCMS_close_source/app/Plugin.php

@ -0,0 +1,309 @@
<?php
namespace app;
use app\model\AdminMenu;
use think\facade\Cache;
use think\facade\Db;
use think\View;
/**
* 插件类
*/
abstract class Plugin
{
/**
* 视图实例对象
* @var view
* @access protected
*/
private $view = null;
public static $vendorLoaded = [];
/**
* $info = array(
* 'name'=>'HelloWorld',
* 'title'=>'HelloWorld',
* 'description'=>'HelloWorld',
* 'status'=>1,
* 'author'=>'ThinkCMF',
* 'version'=>'1.0'
* )
*/
public $info = [];
private $pluginPath = '';
private $name = '';
private $configFilePath = '';
private $themeRoot = "";
/**
* Plugin constructor.
*/
public function __construct()
{
$this->name = $this->getName();
$nameCStyle = parse_name($this->name);
$this->pluginPath = CMS_ROOT . 'plugins/' . $nameCStyle . '/';
$this->configFilePath = $this->pluginPath . 'config.php';
if (empty(self::$vendorLoaded[$this->name])) {
$pluginVendorAutoLoadFile = $this->pluginPath . 'vendor/autoload.php';
if (file_exists($pluginVendorAutoLoadFile)) {
require_once $pluginVendorAutoLoadFile;
}
self::$vendorLoaded[$this->name] = true;
}
$config = $this->getConfig();
$theme = isset($config['theme']) ? $config['theme'] : '';
//$depr = "/";
$root = hcGetRoot();
$themeDir = empty($theme) ? "" : '/' . $theme;
$themePath = 'view' . $themeDir;
$this->themeRoot = $this->pluginPath . $themePath . '/';
$pluginRoot = "plugins/{$nameCStyle}";
$cmfAdminThemePath = config('template.cmf_admin_theme_path');
$cmfAdminDefaultTheme = config('template.cmf_admin_default_theme');
$adminThemePath = "{$cmfAdminThemePath}{$cmfAdminDefaultTheme}";
$replaceConfig = [
'__ROOT__' => $root,
'__PLUGIN_TMPL__' => $root . '/' . $pluginRoot . '/' . $themePath,
'__PLUGIN_ROOT__' => $root . '/' . $pluginRoot,
'__ADMIN_TMPL__' => "{$root}/{$adminThemePath}",
'__STATIC__' => "{$root}/static",
'__WEB_ROOT__' => $root
];
$app = app();
$view = new View($app);
$this->view = $view;
$this->view->engine()->config([
'view_base' => $this->themeRoot,
'tpl_replace_string' => $replaceConfig
]);
//加载多语言
$langSet = $app->lang->getLangSet();
$lang_file = $this->pluginPath . "lang/" . $langSet . ".php";
$app->lang->load($lang_file);
}
/**
* 加载模板输出
* @access protected
* @param string $template 模板文件名
* @return string
* @throws \Exception
*/
final protected function fetch($template)
{
if (!is_file($template)) {
$engineConfig = config('view');
$template = $this->themeRoot . $template . '.' . $engineConfig['view_suffix'];
}
// 模板不存在 抛出异常
if (!is_file($template)) {
throw new TemplateNotFoundException('template not exists:' . $template, $template);
}
return $this->view->fetch($template);
}
/**
* 渲染内容输出
* @access protected
* @param string $content 模板内容
* @return mixed
*/
final protected function display($content = '')
{
return $this->view->display($content);
}
/**
* 模板变量赋值
* @access protected
* @param mixed $name 要显示的模板变量
* @param mixed $value 变量的值
* @return void
*/
final protected function assign($name, $value = '')
{
$this->view->assign($name, $value);
}
/**
* 获取插件名
* @return string
*/
final public function getName()
{
if (empty($this->name)) {
$class = get_class($this);
$this->name = substr($class, strrpos($class, '\\') + 1, -6);
}
return $this->name;
}
/**
* 检查插件信息完整性
* @return bool
*/
final public function checkInfo()
{
$infoCheckKeys = ['name', 'title', 'description', 'status', 'author', 'version'];
foreach ($infoCheckKeys as $value) {
if (!array_key_exists($value, $this->info))
return false;
}
return true;
}
/**
* 获取插件根目录绝对路径
* @return string
*/
final public function getPluginPath()
{
return $this->pluginPath;
}
/**
* 获取插件配置文件绝对路径
* @return string
*/
final public function getConfigFilePath()
{
return $this->configFilePath;
}
/**
*
* @return string
*/
final public function getThemeRoot()
{
return $this->themeRoot;
}
/**
* @return View
*/
public function getView()
{
return $this->view;
}
/**
* 获取插件的配置数组
* @return array
*/
final public function getConfig()
{
$name = $this->getName();
if (PHP_SAPI != 'cli') {
static $_config = [];
if (isset($_config[$name])) {
return $_config[$name];
}
}
$pluginCofingKey = 'cmf_'.$name.'_plugin_config';
if (Cache::has($pluginCofingKey)){
return Cache::get($pluginCofingKey);
}
$ttl = mt_rand(600,6000);
$config = Db::name('plugin')->cache('cmf_'.$name.'_plugin_config_db',$ttl)->where('name', $name)->value('config');
if (!empty($config) && $config != "null") {
$config = json_decode($config, true);
} else {
$config = $this->getDefaultConfig();
}
Cache::set($pluginCofingKey,$config,$ttl);
$_config[$name] = $config;
return $config;
}
/**
* 获取插件的配置数组
* @return array
*/
final public function getDefaultConfig()
{
$config = [];
if (file_exists($this->configFilePath)) {
$tempArr = include $this->configFilePath;
if (!empty($tempArr) && is_array($tempArr)) {
foreach ($tempArr as $key => $value) {
if ($value['type'] == 'group') {
foreach ($value['options'] as $gkey => $gvalue) {
foreach ($gvalue['options'] as $ikey => $ivalue) {
$config[$ikey] = $ivalue['value'];
}
}
} else {
$config[$key] = $tempArr[$key]['value'];
}
}
}
}
return $config;
}
protected function installSql()
{
//执行安装sql
$dbConfig = env();
$sqlArr = hcSplitSql($this->pluginPath . '/install.sql', $dbConfig['DATABASE_PREFIX'], $dbConfig['DATABASE_CHARSET']);
$db = Db::connect();
foreach ($sqlArr as $sql) {
$sqlToExec = $sql . ';';
$result = sp_execute_sql($db, $sqlToExec);
if (!empty($result['error'])) {
return false;
}
}
return true;
}
public function editMenu($type = 1, $remark = '') {
$adminMenuModel = new AdminMenu();
if ($type == 1) { //安装
$adminMenuModel->where('remark', $remark)->update(['status' => 1]);
} else {//卸载
$adminMenuModel->where('remark', $remark)->update(['status' => 2]);
}
}
//必须实现安装
abstract public function install();
//必须卸载插件方法
abstract public function uninstall();
}

8
HuoCMS_close_source/app/Request.php

@ -0,0 +1,8 @@
<?php
namespace app;
// 应用请求对象类
class Request extends \think\Request
{
}

101
HuoCMS_close_source/app/command/BaiduTongji.php

@ -0,0 +1,101 @@
<?php
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\facade\Db;
class BaiduTongji extends Command
{
protected function configure()
{
$this->setName('baiduTongji')
->setDescription('百度统计');
}
protected function execute(Input $input, Output $output)
{
set_time_limit(0);
ini_set('memory_limit', '512M');
/*************************************** 百度统计开始 ************************************************/
$url = 'http://api.baidu.com/json/tongji/v1/ReportService/getData';
$listUrl = 'https://api.baidu.com/json/tongji/v1/ReportService/getSiteList';
$accountList = Db::name('seo_account')->field('account,password,token')->where("type=1")->selectOrFail();
$insertData = [
'pv_count' => 0,
'uv_count' => 0,
'ip_count' => 0,
'avg_visit_time' => 0
];
$totalNum = 0;
foreach ($accountList as $vo) {
$header = [
'account_type' => '1',
'username' => $vo['account'],
'password' => $vo['password'],
'token' => $vo['token'],
];
$lists = curlPost($listUrl, json_encode(['header' => $header]));
$website = json_decode($lists['data'], true);
if (empty($website['header']['failures'])) {
$website = $website['body']['data']['0']['list'];
}
if (!empty($website)) {
foreach ($website as $k => $v) {
$totalNum++;
$info = curlPost($url, json_encode([
'body' => [
"site_id"=> $v['site_id'],
"method" => "overview/getOutline"
],
'header' => $header
]))['data'];
$info = json_decode($info, true);
if (empty($info['body']['data'])) {
continue;
}
$info = $info['body']['data']['0']['result'];
if (isset($info['items']['1'])) {
if (is_numeric($info['items']['1']['1'])) {
$insertData['pv_count'] += $info['items']['1']['1'];
}
if (is_numeric($info['items']['1']['2'])) {
$insertData['uv_count'] += $info['items']['1']['2'];
}
if (is_numeric($info['items']['1']['3'])) {
$insertData['ip_count'] += $info['items']['1']['3'];
}
if (is_numeric($info['items']['1']['5'])) {
$insertData['avg_visit_time'] += $info['items']['1']['5'];
}
}
}
}
}
if ($totalNum != 0) {
$insertData['avg_visit_time'] = round($insertData['avg_visit_time'] / $totalNum);
}
$insertData['count_date'] = date('Y-m-d', strtotime('-1 day'));
Db::name('baidu_tj_gather')->insert($insertData);
/*************************************** 百度统计结束 ************************************************/
}
}

61
HuoCMS_close_source/app/command/CreateController.php

@ -0,0 +1,61 @@
<?php
declare (strict_types = 1);
namespace app\command;
use think\console\command\Make;
use think\console\input\Option;
use think\console\input\Argument;
class CreateController extends Make
{
protected $type = "Controller";
protected function configure()
{
// 指令配置
$this->setName('make:hc-controller')
->addArgument('name', Argument::OPTIONAL, "controller path")
->setDescription('create a HuoCms controller command');
}
protected function getStub(): string
{
$stubPath = __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR;
return $stubPath . 'controller.stub';
}
protected function getClassName(string $name): string
{
return parent::getClassName($name) . ($this->app->config->get('route.controller_suffix') ? 'Controller' : '');
}
protected function getNamespace(string $app): string
{
return parent::getNamespace($app) . '\\controller';
}
protected function buildClass(string $name)
{
$stub = file_get_contents($this->getStub());
$namespace = trim(implode('\\', array_slice(explode('\\', $name), 0, -1)), '\\');
$class = str_replace($namespace . '\\', '', $name);
$modelName = str_replace(($this->app->config->get('route.controller_suffix') ? 'Controller' : ''),'',$class);
$funcParam = lcfirst($modelName);
return str_replace(['{%className%}', '{%actionSuffix%}', '{%namespace%}', '{%app_namespace%}','{%modelInstance%}','{%modelName%}'], [
$class,
$this->app->config->get('route.action_suffix'),
$namespace,
$this->app->getNamespace(),
$funcParam,
$modelName,
], $stub);
}
}

53
HuoCMS_close_source/app/command/CreateLink.php

@ -0,0 +1,53 @@
<?php
declare (strict_types = 1);
namespace app\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class CreateLink extends Command
{
protected function configure()
{
// 指令配置
$this->setName('admin-view:link')
->setDescription('the app\command\createLink command');
}
protected function execute(Input $input, Output $output)
{
foreach ($this->links() as $link => $target) {
if (file_exists($link)) {
$output->writeln('<error>' . $link . ' already exists!</error>');
} else {
$this->createLink($target, $link);
$output->writeln('<info>' . $link . ' created successfully.</info>');
}
}
$output->writeln('The links have been created.');
}
protected function links(): array
{
return ['public/view' => app()->getRootPath() .'view/'];
}
public function createLink($target,$link): bool
{
if (! windows_os()) {
return symlink($target, $link);
}
$mode = is_directory($target) ? 'J' : 'H';
exec("mklink /{$mode} ".escapeshellarg($link).' '.escapeshellarg($target));
}
}

28
HuoCMS_close_source/app/command/CreateModel.php

@ -0,0 +1,28 @@
<?php
declare (strict_types = 1);
namespace app\command;
use think\console\command\Make;
use think\console\input\Argument;
class CreateModel extends Make
{
protected function configure()
{
// 指令配置
$this->setName('make:hc-model')
->addArgument('name', Argument::OPTIONAL, "model path")
->setDescription('create a new model class with five base function');
}
protected function getStub(): string
{
return __DIR__ . DIRECTORY_SEPARATOR . 'stubs' . DIRECTORY_SEPARATOR . 'model.stub';
}
protected function getNamespace(string $app): string
{
return parent::getNamespace($app) . '\\model';
}
}

59
HuoCMS_close_source/app/command/WebDiagnosis.php

@ -0,0 +1,59 @@
<?php
namespace app\command;
use app\command\service\Server;
use app\command\service\TaskServer;
use app\command\service\TongJiServer;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class WebDiagnosis extends Command
{
protected function configure()
{
$this->setName('seo:check')
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of workerman service.', null)
->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of workerman service.', null)
->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the workerman service in daemon mode.')
->setDescription('网站诊断服务器');
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
if (DIRECTORY_SEPARATOR !== '\\') {
if (!in_array($action, ['start', 'stop', 'reload', 'restart', 'status', 'connections'])) {
$output->writeln("<error>Invalid argument action:{$action}, Expected start|stop|restart|reload|status|connections .</error>");
return false;
}
global $argv;
array_shift($argv);
array_shift($argv);
array_shift($argv);
array_unshift($argv, 'think', $action);
}
$logo = <<<EOL
_____ ______ ____ _____ _ _ ______ _____ _ __
/ ____ | ____ / __ \ / ____ | | | | | ____ / ____ | |/ /
| (___ | |__ | | | | | | | |__| | | |__ | | | ' /
\___ \ | __| | | | | | | | __ | | __| | | | <
____) | |___ | |__| | | |____ | | | | | |___ | |____ | . \
|_____/ |______ \____/ \_____ |_| |_| |______ \_____ |_|\_\
EOL;
$output->writeln($logo . PHP_EOL);
if (!(strtoupper(substr(PHP_OS,0,3))==='WIN')) {
TongJiServer::start();
TaskServer::start();
}
Server::start();
}
}

55
HuoCMS_close_source/app/command/WebDiagnosis2.php

@ -0,0 +1,55 @@
<?php
namespace app\command;
use app\command\service\Server;
use app\command\service\TaskServer;
use app\command\service\TongJiServer;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class WebDiagnosis2 extends Command
{
protected function configure()
{
$this->setName('seo:check2')
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of workerman service.', null)
->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of workerman service.', null)
->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the workerman service in daemon mode.')
->setDescription('网站诊断服务器');
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
if (DIRECTORY_SEPARATOR !== '\\') {
if (!in_array($action, ['start', 'stop', 'reload', 'restart', 'status', 'connections'])) {
$output->writeln("<error>Invalid argument action:{$action}, Expected start|stop|restart|reload|status|connections .</error>");
return false;
}
global $argv;
array_shift($argv);
array_shift($argv);
array_shift($argv);
array_unshift($argv, 'think', $action);
}
$logo = <<<EOL
_____ ______ ____ _____ _ _ ______ _____ _ __
/ ____ | ____ / __ \ / ____ | | | | | ____ / ____ | |/ /
| (___ | |__ | | | | | | | |__| | | |__ | | | ' /
\___ \ | __| | | | | | | | __ | | __| | | | <
____) | |___ | |__| | | |____ | | | | | |___ | |____ | . \
|_____/ |______ \____/ \_____ |_| |_| |______ \_____ |_|\_\
EOL;
$output->writeln($logo . PHP_EOL);
TongJiServer::start();
}
}

55
HuoCMS_close_source/app/command/WebDiagnosis3.php

@ -0,0 +1,55 @@
<?php
namespace app\command;
use app\command\service\Server;
use app\command\service\TaskServer;
use app\command\service\TongJiServer;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;
class WebDiagnosis3 extends Command
{
protected function configure()
{
$this->setName('seo:check3')
->addArgument('action', Argument::OPTIONAL, "start|stop|restart|reload|status|connections", 'start')
->addOption('host', 'H', Option::VALUE_OPTIONAL, 'the host of workerman service.', null)
->addOption('port', 'p', Option::VALUE_OPTIONAL, 'the port of workerman service.', null)
->addOption('daemon', 'd', Option::VALUE_NONE, 'Run the workerman service in daemon mode.')
->setDescription('网站诊断服务器');
}
protected function execute(Input $input, Output $output)
{
$action = $input->getArgument('action');
if (DIRECTORY_SEPARATOR !== '\\') {
if (!in_array($action, ['start', 'stop', 'reload', 'restart', 'status', 'connections'])) {
$output->writeln("<error>Invalid argument action:{$action}, Expected start|stop|restart|reload|status|connections .</error>");
return false;
}
global $argv;
array_shift($argv);
array_shift($argv);
array_shift($argv);
array_unshift($argv, 'think', $action);
}
$logo = <<<EOL
_____ ______ ____ _____ _ _ ______ _____ _ __
/ ____ | ____ / __ \ / ____ | | | | | ____ / ____ | |/ /
| (___ | |__ | | | | | | | |__| | | |__ | | | ' /
\___ \ | __| | | | | | | | __ | | __| | | | <
____) | |___ | |__| | | |____ | | | | | |___ | |____ | . \
|_____/ |______ \____/ \_____ |_| |_| |______ \_____ |_|\_\
EOL;
$output->writeln($logo . PHP_EOL);
TaskServer::start();
}
}

30
HuoCMS_close_source/app/command/service/Server.php

@ -0,0 +1,30 @@
<?php
namespace app\command\service;
use Workerman\Protocols\Http\Request;
use \Workerman\Connection\AsyncTcpConnection;
use Workerman\Connection\TcpConnection;
use Workerman\Worker;
class Server
{
public static function start()
{
$http_worker = new Worker("http://0.0.0.0:19910");
$http_worker->count = 1;
$http_worker->name = 'task accept';
$http_worker->onMessage = function(TcpConnection $connection, Request $request)
{
$task_connection = new AsyncTcpConnection('Text://127.0.0.1:19890');
$task_connection->send(json_encode($request->post()));
$task_connection->connect();
$connection->send(json_encode(['code' => 0, 'data' => '', 'msg' => '任务投递成功']));
};
if(!defined('GLOBAL_START')) {
Worker::runAll();
}
}
}

149
HuoCMS_close_source/app/command/service/TaskServer.php

@ -0,0 +1,149 @@
<?php
namespace app\command\service;
use app\command\service\step\CheckIncluded;
use app\command\service\step\CheckKeywords;
use app\command\service\step\CheckLinks;
use app\command\service\step\CheckSSL301;
use app\command\service\step\CheckTplCode;
use Workerman\Worker;
use Workerman\Connection\TcpConnection;
class TaskServer
{
public static $db;
public static function start()
{
$taskWorker = new Worker('Text://0.0.0.0:19890');
$taskWorker->count = 8;
$taskWorker->name = 'TaskWorker';
$taskWorker->onWorkerStart = function (Worker $worker)
{
self::$db = new \Workerman\MySQL\Connection(env('database.hostname'),
env('database.hostport', 3306), env('database.username'), env('database.password', ''), env('database.database', ''));
};
$taskWorker->onMessage = function(TcpConnection $connection, $taskData)
{
$taskData = json_decode($taskData, true);
try {
switch ($taskData['cmd']) {
case 'code':
$res = self::codeAnalysis($taskData);
break;
case 'web':
$res = self::webpageAnalysis($taskData);
break;
case 'keywords':
$res = self::keywordsAnalysis($taskData, self::$db);
break;
case 'links':
$res = self::linksAnalysis($taskData, self::$db);
break;
case 'article':
$res = self::articleAnalysis($taskData);
break;
}
self::$db->update(env('database.prefix') . 'seo_check_task_detail')
->cols([
'remark' => json_encode($res),
'status' => 2,
'update_time' => date('Y-m-d H:i:s')
])
->where('task_id=' . $taskData['task_id'] . ' AND code="' . $taskData['cmd'] . '"')->query();
$has = self::$db->select('id')->from(env('database.prefix') . 'seo_check_task_detail')
->where('task_id=' . $taskData['task_id'] . ' AND status=1')->row();
if (empty($has)) {
self::$db->update(env('database.prefix') . 'seo_check_task')->cols(array('status'=>'2'))->where("id={$taskData['task_id']}")->query();
}
} catch (\Exception $e) {
if (strpos($e->getMessage(), '404 Not Found') !== false || strpos($e->getMessage(), '503 Service Temporarily Unavailable') !== false) {
$connection->send(json_encode(['code' => -1, 'data' => [], 'msg' => '该网站暂时无法访问']));
} else {
$connection->send(json_encode(['code' => -1, 'data' => [], 'msg' => $e->getMessage()]));
}
return;
}
$connection->send(json_encode($res));
};
if (strtoupper(substr(PHP_OS,0,3))==='WIN') {
Worker::runAll();
}
}
/**
* 代码分析
* @param $taskData
* @return array
*/
private static function codeAnalysis($taskData)
{
$analysis = [];
// 检测301
$analysis301 = CheckSSL301::run($taskData);
// 检测模板代码
$analysisTplCode = CheckTplCode::run($taskData);
$analysis = $analysis + $analysis301 + $analysisTplCode;
return dataReturn(101, '代码分析完成', $analysis);
}
/**
* 网站收录分析
* @param $taskData
* @return array
*/
private static function webpageAnalysis($taskData)
{
$analysis = CheckIncluded::run($taskData);
return dataReturn(102, '收录分析完成', $analysis);
}
/**
* 关键词分析
* @param $taskData
* @param $db
* @return array
*/
private static function keywordsAnalysis($taskData, $db)
{
$analysis = CheckKeywords::run($taskData, $db);
return dataReturn(103, '关键词分析完成', $analysis);
}
/**
* 导入链接分析
* @param $taskData
* @param $db
* @return array
*/
private static function linksAnalysis($taskData, $db)
{
$analysis = CheckLinks::run($taskData, $db);
return dataReturn(104, '导入链接分析完成', $analysis);
}
/**
* 文章分析
* @param $taskData
* @return array
*/
private static function articleAnalysis($taskData)
{
return dataReturn(105, '文章分析完成');
}
}

171
HuoCMS_close_source/app/command/service/TongJiServer.php

@ -0,0 +1,171 @@
<?php
namespace app\command\service;
use think\facade\Log;
use Workerman\Timer;
use Workerman\Worker;
class TongJiServer
{
public static function start()
{
$task = new Worker();
$task->count = 1;
$task->name = 'pv collect';
$task->onWorkerStart = function($task)
{
$db = new \Workerman\MySQL\Connection(env('database.hostname'),
env('database.hostport', 3306), env('database.username'), env('database.password', ''), env('database.database', ''));
/*************************************** 站长之家排名开始 ************************************************/
$baiduPcUrl = 'https://apidatav2.chinaz.com/single/baidupc/keywordranking';
$baiduMobileUrl = 'https://apidatav2.chinaz.com/single/baidumobile/keywordranking';
$pc360Url = 'https://apidatav2.chinaz.com/single/sopc/keywordranking';
$sogouMobileUrl = 'https://apidatav2.chinaz.com/single/sogoumobile/keywordranking';
file_put_contents('./last_rum_time.log', time()); // 上次执行时间
$info = $db->select('value')->from(env('database.prefix') . 'sys_setting')
->where('title="chinaz_token" and seller_id=1')->row();
if (!empty($info)) {
$token = $info['value'];
Timer::add(3600, function () use ($db, $token, $baiduPcUrl, $baiduMobileUrl, $pc360Url, $sogouMobileUrl) {
if (date('H:i') >= '11:52' || date('H:i') < '11:53') {
$frequency = $db->select('value')->from(env('database.prefix') . 'sys_setting')
->where('title="keywords_search_time" and seller_id=1')->row();
$lastRunTime = file_get_contents('./last_rum_time.log');
$canRun = false;
if ($frequency == 'week') {
if ((time() - $lastRunTime) / 86400 >= 7) {
$canRun = true;
file_put_contents('./last_rum_time.log', time());
}
} elseif($frequency == 'day' && (time() - $lastRunTime) >= 86400) {
$canRun = true;
file_put_contents('./last_rum_time.log', time());
} else {
$canRun = true;
file_put_contents('./last_rum_time.log', time());
}
Log::info('可执行状态:' . $canRun);
try {
if ($canRun) {
Log::info('执行统计开始' . $canRun);
$keywords = $db->select('id,name,url,website_id,seller_id')->from(env('database.prefix') . 'keyword')
->where('status=1 and is_del=1')->query();
foreach ($keywords as $key => $vo) {
$updateData = [
'baidu_pc' => 0,
'baidu_mob' => 0,
'three_pc' => 0,
'sougou_mob' => 0
];
// 百度PC
$res = curlPost($baiduPcUrl, [
'key' => $token,
'domain' => $vo['url'],
'keyword' => $vo['name'],
'top100' => true
])['data'];
Log::info($vo['name'] . ' 百度PC res>>>>>>>:' . $res);
$res = json_decode($res, true);
if (!empty($res['Result']['Ranks'])) {
$rank = explode('-', $res['Result']['Ranks']['0']['RankStr']);
$updateData['baidu_pc'] = ($rank[0] - 1) * 10 + $rank['1'];
self::writeKeywordsQuery($db, $vo, $res, $rank, 'baidu_pc');
}
// 百度移动
$res = curlPost($baiduMobileUrl, [
'key' => $token,
'domain' => $vo['url'],
'keyword' => $vo['name']
])['data'];
Log::info($vo['name'] . ' 百度移动 res>>>>>>>:' . $res);
$res = json_decode($res, true);
if (!empty($res['Result']['Ranks'])) {
$rank = explode('-', $res['Result']['Ranks']['0']['RankStr']);
$updateData['baidu_mob'] = ($rank[0] - 1) * 10 + $rank['1'];
self::writeKeywordsQuery($db, $vo, $res, $rank, 'baidu_mob');
}
// 360pc
$res = curlPost($pc360Url, [
'key' => $token,
'domain' => $vo['url'],
'keyword' => $vo['name']
])['data'];
Log::info($vo['name'] . ' 360pc res>>>>>>>:' . $res);
$res = json_decode($res, true);
if (!empty($res['Result']['Ranks'])) {
$rank = explode('-', $res['Result']['Ranks']['0']['RankStr']);
$updateData['three_pc'] = ($rank[0] - 1) * 10 + $rank['1'];
self::writeKeywordsQuery($db, $vo, $res, $rank, 'three_pc');
}
// 搜狗移动
$res = curlPost($sogouMobileUrl, [
'key' => $token,
'domain' => $vo['url'],
'keyword' => $vo['name']
])['data'];
Log::info($vo['name'] . ' 搜狗移动 res>>>>>>>:' . $res);
$res = json_decode($res, true);
if (!empty($res['Result']['Ranks'])) {
$rank = explode('-', $res['Result']['Ranks']['0']['RankStr']);
$updateData['sougou_mob'] = ($rank[0] - 1) * 10 + $rank['1'];
self::writeKeywordsQuery($db, $vo, $res, $rank, 'sougou_mob');
}
$db->update(env('database.prefix') . 'keyword')->cols($updateData)->where('id=' . $vo['id'])->query();
}
}
} catch (\Exception $e) {
Log::error($e->getMessage() . '>>>>>>
' . $e->getTraceAsString());
}
Log::info('执行结束');
}
});
}
/*************************************** 站长之家排名结束 ************************************************/
};
if (strtoupper(substr(PHP_OS,0,3))==='WIN') {
Worker::runAll();
}
}
protected static function writeKeywordsQuery($db, $vo, $res, $rank, $engine)
{
$db->insert(env('database.prefix') . 'keyword_query')->cols([
'keyword_id' => $vo['id'],
'seller_id' => $vo['seller_id'],
'website_id' => $vo['website_id'],
'keyword' => $vo['name'],
'search_engine' => $engine,
'collect_count' => isset($res['Result']['SiteCount']) ? $res['Result']['SiteCount'] : 0,
'top_rank' => ($rank[0] - 1) * 10 + $rank['1'],
'create_time' => time(),
'page_title' => $res['Result']['Ranks']['0']['Title'] ?? '',
'page_url' => $res['Result']['Ranks']['0']['Url'] ?? '',
])->query();
}
}

55
HuoCMS_close_source/app/command/service/step/CheckIncluded.php

@ -0,0 +1,55 @@
<?php
namespace app\command\service\step;
use GuzzleHttp\Client;
class CheckIncluded
{
public static function run($taskData)
{
$included = [
'status' => 1,
'count' => 0
];
try {
$client = new Client();
$url = 'https://www.baidu.com/s?wd=site%3A' . $taskData['websiteUrl'];
$jar = new \GuzzleHttp\Cookie\CookieJar();
$userAgentMap = config('userAgent');
$userAgentKey = array_rand($userAgentMap);
$res = $client->request('GET', $url, [
'cookies' => $jar,
'headers' => [
'user-agent' => $userAgentMap[$userAgentKey]
],
]);
if ($res->getStatusCode() == 200) {
$html = \phpQuery::newDocumentHTML($res->getBody());
$hasNoInclude = $html['.content_none .nors']->html();
if (!empty($hasNoInclude)) {
$included = [
'status' => 2,
'count' => 0
];
} else {
$included = [
'status' => 1,
'count' => $html['#content_left .c-span-last p:eq(0) b']->text()
];
}
} else {
return $included;
}
} catch (\Exception $e) {
return $included;
}
return $included;
}
}

124
HuoCMS_close_source/app/command/service/step/CheckKeywords.php

@ -0,0 +1,124 @@
<?php
namespace app\command\service\step;
use think\facade\Db;
class CheckKeywords
{
public static function run($taskData, $db)
{
$analysis = [
'deadLink' => []
];
$keywords = $taskData['keywords'];
if (empty($keywords)) {
return [];
}
// 处理栏目页
$columnPages = $taskData['cate'];
$cateIds = [];
$cateId2Alias = [];
$opts = [
'http'=> [
'method' => "GET",
'timeout' => 10,
]
];
$context = stream_context_create($opts);
foreach ($columnPages as $vo) {
$cateIds[] = $vo['id'];
$cateId2Alias[$vo['id']] = $vo['alias'];
try {
$nowPageHtml = file_get_contents('http://' . $taskData['websiteUrl'] . $vo['alias'], false, $context);
echo "查询获取到页面数据" . PHP_EOL;
$totalWords = self::getCleanContent($nowPageHtml);
foreach ($keywords as $v) {
$analysis[$vo['alias']][$v['name']] = round((substr_count($totalWords, $v['name'])
* mb_strlen($v['name'])) / mb_strlen($totalWords), 4);
}
} catch (\Exception $e) {
echo "获取到死链" . 'http://' . $taskData['websiteUrl'] . $vo['alias'] . PHP_EOL;
$analysis['deadLink'][] = 'http://' . $taskData['websiteUrl'] . $vo['alias'];
}
}
// 处理文章页
if (!empty($cateIds)) {
$pageSize = 20;
$total = $db->select('count(*) as `c_total`')->from(env('database.prefix') . 'category_sub_content')
->where("category_id in(" . implode(',', $cateIds) . ")")->row()['c_total'];
$totalPage = ceil($total / $pageSize);
for ($nowPage = 1; $nowPage <= $totalPage; $nowPage++) {
$offset = ($nowPage - 1) * $pageSize;
$articles = $db->select('category_id,sub_content_id')->from(env('database.prefix') . 'category_sub_content')
->where("category_id in(" . implode(',', $cateIds) . ")")->limit($pageSize)->offset($offset)->query();
foreach ($articles as $vo) {
if (isset($cateId2Alias[$vo['category_id']])) {
$url = $cateId2Alias[$vo['category_id']] . '/' . $vo['sub_content_id'];
try {
$nowPageHtml = file_get_contents('http://' . $taskData['websiteUrl'] . $url, false, $context);
$totalWords = self::getCleanContent($nowPageHtml);
foreach ($keywords as $v) {
$analysis[$url][$v['name']] = round((substr_count($totalWords, $v['name']) * mb_strlen($v['name'])) / mb_strlen($totalWords), 4);
}
} catch (\Exception $e) {
$analysis['deadLink'][] = 'http://' . $taskData['websiteUrl'] . $url;
}
}
}
}
}
// 最后统计总数据
$analysisFinal = [];
foreach ($analysis as $key => $vo) {
if ($key != 'deadLink') {
$analysisFinal['keywords'][] = '路径 ' . $key . ' 的关键词密度是:' . round(array_sum($vo), 2);
} else {
$analysisFinal[$key] = $vo;
}
}
return $analysisFinal;
}
private static function getCleanContent($nowPage)
{
// 获取所有的img的alt
$html = \phpQuery::newDocument($nowPage);
$images = $html['img'];
$a = $html['a'];
// 去除js标签内的内容
$html['script']->html('');
$html['noscript']->html('');
$html['style']->html('');
$imagesAltMap = [];
foreach ($images as $img) {
if (!empty(trim(pq($img)->attr('alt')))) {
$imagesAltMap[] = trim(pq($img)->attr('alt'));
}
}
$aTitleMap = [];
foreach ($a as $item) {
if (!empty(trim(pq($item)->attr('title')))) {
$aTitleMap[] = trim(pq($item)->attr('title'));
}
}
$cleanWords = trim(str_replace(' ', '', str_replace(PHP_EOL, '', strip_tags($html))));
return $cleanWords . implode('', $imagesAltMap) . implode('', $aTitleMap);
}
}

78
HuoCMS_close_source/app/command/service/step/CheckLinks.php

@ -0,0 +1,78 @@
<?php
namespace app\command\service\step;
use think\facade\Db;
class CheckLinks
{
public static function run($taskData, $db)
{
$links = $db->select('url,type,position')->from(env('database.prefix') . 'link')
->where("is_del=1 AND website_id = " . $taskData['websiteId'])->query();
$inLinks = [];
$outLinks = [];
foreach ($links as $vo) {
if ($vo['type'] == 1) {
try {
$html = file_get_contents($vo['position']);
if (strstr($html, $vo['url']) == false) {
$inLinks['linksHave'][] = [
'status' => 2,
'msg' => $vo['position'] . '的友链已经被删除'
];
} else {
$inLinks['linksHave'][] = [
'status' => 1,
'msg' => $vo['position'] . '的友链正常显示'
];
// 检测nofollow
$html = \phpQuery::newDocument($html);
if ($html['a[href="' . $vo['url'] . '"]']->attr('rel') === 'nofollow') {
$inLinks['nofollow'][] = [
'status' => 2,
'msg' => $vo['position'] . '的友链添加了nofollow'
];
} else {
$inLinks['nofollow'][] = [
'status' => 1,
'msg' => $vo['position'] . '的友链属性正常'
];
}
}
} catch (\Exception $e) {
$inLinks['linksHave'][] = [
'status' => 2,
'msg' => $vo['position'] . '无法访问'
];
}
} else if ($vo['type'] == 2) {
try {
file_get_contents($vo['url']);
$outLinks['linksHave'][] = [
'status' => 1,
'msg' => $vo['url'] . '可以正常访问'
];
} catch (\Exception $e) {
$outLinks['linksHave'][] = [
'status' => 2,
'msg' => $vo['url'] . '无法访问'
];
}
}
}
$analysis = [
'inlinks' => $inLinks,
'outlinks' => $outLinks
];
return $analysis;
}
}

156
HuoCMS_close_source/app/command/service/step/CheckSSL301.php

@ -0,0 +1,156 @@
<?php
namespace app\command\service\step;
use GuzzleHttp\Client;
class CheckSSL301
{
/**
* 检测 301 ssl
* @param $taskData
* @return array
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public static function run($taskData)
{
$analysis = [];
$urlMap = explode('.', $taskData['websiteUrl']);
$client = new Client();
// 二级域名的情况
if (count($urlMap) == 3 && $urlMap[0] != 'www') {
$analysis['c301'] = [
'status' => 2,
'msg' => '该网站使用的非一级域名,建议使用一级域名'
];
$analysis['ssl'] = self::requestWithHttps($client, $taskData);
return $analysis;
}
// 非二级域名的情况
if (count($urlMap) == 3 && $urlMap[0] == 'www') {
$url = 'http://' . $urlMap['1'] . '.' . $urlMap['2'];
$domain = $urlMap['1'] . '.' . $urlMap['2'];
} else {
$url = 'http://' . $taskData['websiteUrl'];
$domain = $taskData['websiteUrl'];
}
$userAgentMap = config('userAgent');
$userAgentKey = array_rand($userAgentMap);
$res = $client->request('GET', $url, [
'allow_redirects' => false,
'headers' => [
'user-agent' => $userAgentMap[$userAgentKey]
],
]);
// 做了 301 跳转的
if ($res->getStatusCode() == 301) {
// 进一步确认
$resHeaders = $res->getHeaders();
$location = $resHeaders['Location'][0];
if (strpos($location, 'https://') !== false) {
$analysis['ssl'] = [
'status' => 1,
'msg' => '该网站采用了安全的https协议'
];
} else {
$analysis['ssl'] = [
'status' => 2,
'msg' => '该网站没有采用了安全的https协议'
];
}
$ckDomain = strstr($location, 'www');
if ($ckDomain !== false) {
$analysis['c301'] = [
'status' => 1,
'msg' => '该网站采用正确的301跳转方式'
];
return $analysis;
}
// 进一步确认
if ($analysis['ssl']['status'] != 1) {
$analysis['c301'] = [
'status' => 2,
'msg' => '该网站没有采用正确的301跳转方式'
];
return $analysis;
}
// 去请求带https的www域名
$res2 = $client->request('GET', 'https://www.' . $domain, [
'allow_redirects' => false
]);
if ($res2->getStatusCode() == 200) {
$analysis['c301'] = [
'status' => 1,
'msg' => '该网站采用正确的301跳转方式'
];
} else {
$analysis['c301'] = [
'status' => 2,
'msg' => '该网站没有采用正确的301跳转方式'
];
}
return $analysis;
}
// 未做 301 跳转的
$analysis['c301'] = [
'status' => 2,
'msg' => '该网站没有采用正确的301跳转方式'
];
$analysis['ssl'] = self::requestWithHttps($client, $taskData);
return $analysis;
}
private static function requestWithHttps($client, $taskData)
{
$ssl = [];
$userAgentMap = config('userAgent');
$userAgentKey = array_rand($userAgentMap);
try {
$res2 = $client->request('GET', 'https://' . $taskData['websiteUrl'], [
'allow_redirects' => false,
'headers' => [
'user-agent' => $userAgentMap[$userAgentKey]
],
]);
if ($res2->getStatusCode() == 200) {
$ssl = [
'status' => 1,
'msg' => '该网站采用了安全的https协议'
];
} else {
$ssl = [
'status' => 2,
'msg' => '该网站没有采用了安全的https协议'
];
}
} catch (\Exception $e) {
$ssl = [
'status' => 2,
'msg' => '该网站没有采用了安全的https协议'
];
}
return $ssl;
}
}

136
HuoCMS_close_source/app/command/service/step/CheckTplCode.php

@ -0,0 +1,136 @@
<?php
namespace app\command\service\step;
use think\facade\App;
class CheckTplCode
{
public static function run($taskData)
{
$analysis = [
'hn' => [
'status' => 1,
'msg' => []
],
'tags' => [
'status' => 1,
'msg' => []
],
'robots' => [
'status' => 1,
'msg' => 'robots.txt文件正确'
],
'sitemap' => [
'status' => 1,
'msg' => 'sitemap文件放置正确'
],
'urlLevel' => [
'status' => 1,
'msg' => []
],
'c404' => [
'status' => 1,
'msg' => '404文件放置正确'
]
];
// 目录层级
foreach ($taskData['cate'] as $vo) {
if ($vo['alias'] != '/' && !empty($vo['alias'])) {
$level = count(array_filter(explode('/', $vo['alias'])));
if ($level >= 3) {
$analysis['urlLevel']['status'] = 2;
$analysis['urlLevel']['msg'][] = $vo['title'] . '页面,url层级太深,达到了' . $level . '层';
}
}
}
// 404文件
$rootPath = App::getRootPath() . 'public';
if (!is_file($rootPath . '/system_file/hc_error/404.html')) {
$analysis['c404']['status'] = 2;
$analysis['c404']['msg'] = '未正确放置404文件';
}
$path = $rootPath . '/themes/website/' . $taskData['websiteId'] . '/' . $taskData['lang'] . '/' . $taskData['theme'];
if (!is_dir($path)) {
return $analysis;
}
$files = scandir($path);
foreach ($files as $value){
if($value != '.' && $value != '..' && is_file($path . '/' . $value)){
$html = file_get_contents($path . '/' . $value);
// 存在ajax
if (strstr($html, '$.ajax') !== false || strstr($html, '$.getJSON') !== false
|| strstr($html, '$.post') !== false) {
$analysis['tags']['status'] = 2;
$analysis['tags']['msg']['ajax'][] = $value . '页面,有ajax异步请求,建议更换。';
}
$html = \phpQuery::newDocumentHTML($html);
// 页面为vue.js编写
$html['script']->html('');
$html['noscript']->html('');
$vueJs = str_replace(PHP_EOL, '', trim(strip_tags($html)));
if (empty($vueJs)) {
$analysis['tags']['status'] = 2;
$analysis['tags']['msg']['vuejs'][] = $value . '页面,是Vue.js编写无法收录';
}
// 检测h1数量
$h1 = $html["h1"];
if (count($h1) >= 2) {
$analysis['hn']['status'] = 2;
$analysis['hn']['msg']['h1'][] = $value . '有' . count($h1) . '个<h1>标签,数量过多。';
}
// 检测iframe框架
$iframe = $html["iframe"];
if (count($iframe) > 0) {
$analysis['tags']['status'] = 2;
$analysis['tags']['msg']['iframe'][] = $value . '页面,存在iframe标签,建议更换。';
}
// 检测flash技术
$flash = $html["object"];
if (count($flash) > 0) {
$analysis['tags']['status'] = 2;
$analysis['tags']['msg']['flash'][] = $value . '页面,存在flash标签,建议更换。';
}
// alt标签
$imgs = $html["img"];
foreach($imgs as $imgObj) {
if (empty(pq($imgObj)->attr('alt'))) {
$analysis['tags']['status'] = 2;
$analysis['tags']['msg']['alt'][] = $value . '页面,img标签alt属性缺少或为空';
break;
}
}
// robots 文件
if (!is_file($rootPath . '/robots.txt')) {
$analysis['robots'] = [
'status' => 2,
'msg' => '未在正确放置robots.txt文件'
];
}
// sitemap
if (!is_file($rootPath . '/xml/' . $taskData['websiteId'] . '_sitemap.xml')) {
$analysis['sitemap'] = [
'status' => 2,
'msg' => '未正确放置sitemap.xml文件'
];
}
}
}
return $analysis;
}
}

138
HuoCMS_close_source/app/command/stubs/controller.stub

@ -0,0 +1,138 @@
<?php
declare (strict_types = 1);
namespace {%namespace%};
use app\model\{%modelName%};
use app\validate\{%modelName%}Validate;
use think\exception\ValidateException;
class {%className%} extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index{%actionSuffix%}({%modelName%} ${%modelInstance%}): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
${%modelInstance%}List = ${%modelInstance%}->get{%modelName%}List($where,$limit);
return json(pageReturn(${%modelInstance%}List));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save{%actionSuffix%}({%modelName%} ${%modelInstance%}): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate({%modelName%}Validate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = ${%modelInstance%} -> add{%modelName%}($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read{%actionSuffix%}({%modelName%} ${%modelInstance%}): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = ${%modelInstance%}->get{%modelName%}($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update{%actionSuffix%}({%modelName%} ${%modelInstance%}): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate({%modelName%}Validate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = ${%modelInstance%} -> update{%modelName%}($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete{%actionSuffix%}({%modelName%} ${%modelInstance%}): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
// TO DO
// 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = ${%modelInstance%}->del{%modelName%}($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

113
HuoCMS_close_source/app/command/stubs/model.stub

@ -0,0 +1,113 @@
<?php
declare (strict_types = 1);
namespace {%namespace%};
use app\exception\ModelException;
use app\exception\ModelEmptyException;
/**
* @mixin \think\Model
*/
class {%className%} extends Model
{
/**
* @param array $where
* @param int $limit
* @return array
* @throws ModelException
*/
public function get{%className%}List(array $where = [],int $limit = 10): array
{
try{
$res = $this->where($where)->paginate($limit);
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->getMsg,$res);
}
/**
* @param array $where
* @return array
* @throws ModelEmptyException
* @throws ModelException
*/
public function get{%className%}(array $where = []): array
{
try{
$res = $this->where($where)->find();
if(empty($res)){
throw new ModelEmptyException();
}
}catch(ModelEmptyException $me){
throw new ModelEmptyException();
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->getMsg,$res);
}
/**
* @param $param
* @return array
* @throws ModelException
*/
public function add{%className%}($param): array
{
try{
$res = self::create($param);
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->addMsg,$res->id);
}
/**
* @param array $where
* @param array $param
* @return array
* @throws ModelException
*/
public function update{%className%}(array $where = [],array $param = []): array
{
try{
$res = self::where($where)->update($param);
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->updateMsg,$res);
}
/**
* @param $where
* @return array
* @throws ModelException
*/
public function softDel{%className%}($where): array
{
try{
$res = $this->where($where)->update($this->delData);
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->delMsg,$res);
}
/**
* @param $where
* @return array
* @throws ModelException
*/
public function del{%className%}($where): array
{
try{
$res = $this->where($where)->delete();
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return dataReturn($this->sucCode,$this->delMsg,$res);
}
}

1300
HuoCMS_close_source/app/common.php
File diff suppressed because it is too large
View File

1
HuoCMS_close_source/app/controller/api/.gitignore

@ -0,0 +1 @@
./*

204
HuoCMS_close_source/app/controller/backend/AccountController.php

@ -0,0 +1,204 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\PhoneCode;
use app\model\SysSetting;
use app\service\PhoneCodeService;
use app\service\RoleService;
use app\service\sms\ALiSms;
use app\validate\LoginValidate;
use app\model\Admin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Env;
use think\facade\Lang;
class AccountController extends \app\BaseController
{
/**
* @param Admin $adminModel
* @return \think\response\Json
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
* @throws \app\exception\TokenException
*/
public function login(Admin $adminModel): \think\response\Json
{
if (request()->isPost()) {
$param = request()->only(['account','password']);
$pattern = "/^[\w\.-]+@\w+\.\w+(\.\w+)?$/";
if(!env('APP_DEBUG') == true || !(preg_match($pattern,$param['account']) && env('APP_DEBUG') == true)){
$param['account'] = $this->RSA_openssl($param['account'], 'decode');
$param['password'] = $this->RSA_openssl($param['password'], 'decode');
}
// 检验完整性
try {
validate(LoginValidate::class)->scene('login')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = ['account' => $param['account']];
$admin = $adminModel->getAdmin($where,['role'])['data'];
if (!checkPassword($param['password'], $admin['password'])) {
return jsonReturn(-2, Lang::get('用户名密码不正确'));
}
if ($admin['status'] == 2) {
return jsonReturn(-3, Lang::get('该账号已经被禁用'));
}
if ($admin['code_auth'] == 1 && !empty($admin['phone'])) {
$data = [
'phone' => $admin['phone'],
'code' => random_code_type(6, 'number'),
'seller_id' => $admin['seller_id'],
'expired_time' => date('Y-m-d H:i:s', time() + 5 * 60), // 登录验证码5分钟有效
];
//保存发送code记录
$codeModel = new PhoneCode();
$codeModel->insertGetId([
'phone' => $data['phone'],
'code' => $data['code'],
'expired_time' => $data['expired_time']
]);
Cache::set($admin['phone'] . '_login', time(), 5 * 60);
if (Env::get('APP_DEBUG')) {
return jsonReturn(0, 'code_auth', $data);
}
$res = ALiSms::sendOneAuthMsg($data);
if ($res['code'] != 0) {
return json($res);
}
return jsonReturn(0, 'code_auth', ['phone' => $admin['phone']]);
}
return $this->getMenuAndToken($admin);
}
return jsonReturn(-1, Lang::get('请求方式错误'));
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function authCode(Admin $adminModel): \think\response\Json
{
$param = request()->only(['phone','code']);
$param['phone'] = $this->RSA_openssl($param['phone'], 'decode');
$param['code'] = $this->RSA_openssl($param['code'], 'decode');
$authCodeRes = PhoneCodeService::authCode($param);
if ($authCodeRes['code'] != 0) {
return json($authCodeRes);
}
$where = ['phone' => $param['phone']];
$admin = $adminModel->getAdmin($where,['role'])['data'];
return $this->getMenuAndToken($admin);
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
* @throws \app\exception\TokenException
*/
protected function getMenuAndToken($admin): \think\response\Json
{
// 缓存权限数据
$roleRes = RoleService::getMenuAndUpdateAuth($admin['id']);
$loginTime = time();
// 登录日志
$data = [
'seller_id' => $admin['seller_id'],
'admin_id' => $admin['id'],
'admin_name' => $admin['name'],
'title' => $admin['name'].Lang('登录后台系统'),
'ip' => request()->ip(),
'agent' => request()->header()['user-agent'],
'login_time' => $loginTime
];
event('AdminLoginLog',$data);
// 更新最后登录时间
$admin->last_login_time = $loginTime;
$admin->save();
// 获取密码配置
$setting = new SysSetting();
$passConf = $setting -> getCustomData(['id'=>120])['data'];
if(!empty($passConf['value']) && $passConf['status'] == 1){
$passConf = json_decode($passConf['value'],true);
if($passConf['change_duration'] > 0){
$admin -> pass_tips = time() - $admin -> pass_last_change > 86400 * 30 * $passConf['change_duration'] ? 1 : 0;
}
}
$menu = $roleRes['data'];
if(empty($menu)){
return jsonReturn(-1, Lang::get('请联系管理员分配权限后再登录'));
}
return jsonReturn(0, Lang::get('登录成功'), [
'token' => createUserToken([
'uid' => $admin['id'],
'name' => $admin['name'],
'seller_id' => $admin['seller_id']
],'admin'),
'user' => $admin,
'menu' => $menu,
]);
}
/**
* @description RSA公钥加密 私钥解密
* @param string $data 待加解密数据
* @param string $operate 操作类型 encode:加密 decode:解密
* @return string 返回加密内容/解密内容
* @throws \Exception
*/
protected function RSA_openssl(string $data, string $operate = 'encode'): string
{
//RSA 公钥
$rsa_public = config('system.rsa_public_key');
//RSA 私钥
$rsa_private = config('system.rsa_private_key');
//RSA 公钥加密
if ('encode' == $operate) {
$public_key = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($rsa_public, 64, "\n", true) . "\n-----END PUBLIC KEY-----";
$key = openssl_pkey_get_public($public_key);
if (!$key) {
throw new \Exception('公钥不可用,请联系系统维护人员');
}
$return_en = openssl_public_encrypt($data, $crypted, $key);
if (!$return_en) {
throw new \Exception('公钥加密失败,请联系系统维护人员');
}
return base64_encode($crypted);
}
//RSA 私钥解密
if ('decode' == $operate) {
$private_key = "-----BEGIN PRIVATE KEY-----\n" . wordwrap($rsa_private, 64, "\n", true) . "\n-----END PRIVATE KEY-----";
$key = openssl_pkey_get_private($private_key);
if (!$key) {
throw new \Exception('私钥不可用,请联系系统维护人员');
}
$return_de = openssl_private_decrypt(base64_decode($data), $decrypted, $key);
if (!$return_de) {
throw new \Exception('私钥解密失败,请联系系统维护人员');
}
return $decrypted;
}
return '';
}
}

322
HuoCMS_close_source/app/controller/backend/AdminController.php

@ -0,0 +1,322 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\hctrait\AdminPassTrait;
use app\model\Admin;
use app\model\AdminMenu;
use app\model\SysSetting;
use app\validate\AdminValidate;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Lang;
use think\facade\Log;
class AdminController extends BaseController
{
use AdminPassTrait;
/**
* @param Admin $admin
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Admin $admin): \think\response\Json
{
$where = [
['seller_id','=',$this->admin['seller_id']],
['is_del','=',1]
];
$name = input('name') ?? '';
if(!empty($name)){
$where[] = ['name','like','%'.$name.'%'];
}
$limit = $this->setLimit();
$adminList = $admin->getAdminList($where,$limit);
return json(pageReturn($adminList));
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function read(Admin $Admin): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('管理员ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $Admin->getAdmin($where,['role']);
return json($res);
}
/**
* 新建管理员
*
* @param Admin $admin
* @return \think\Response
* @throws \app\exception\ModelException
*/
public function save(Admin $admin): \think\Response
{
$param = input('post.');
try{
validate(AdminValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// 密码规则验证
$err = $this->checkPass($param['password'],$this->admin['seller_id']);
if(!empty($err['message'])){
return jsonReturn(-3,$err['message']);
}
$param['password'] = makePassword($param['password']);
if(isset($param['group'])){
unset($param);
}
Db::startTrans();
try{
$res = $admin -> addAdmin($param);
$res['data']->role()->attach($param['role'],['seller_id'=>$this->admin['seller_id']]);
event("AdminOptLog",[
'admin_id' => $this->admin['uid'],
'admin_name' => $this->admin['name'],
'title'=>Lang::get('管理员管理'),
"content"=>Lang::get('新增管理员').$res['data']['id'],
]);
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(-3,$e->getMessage());
}
return json($res);
}
/**
* 编辑管理员
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(Admin $admin): \think\response\Json
{
if(request()->isPost()){
$param = request()->except(['password'], 'post');
$password = request()->post('password');
try {
validate(AdminValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
Db::startTrans();
try{
if(isset($param['group']) && $param['group'] == 1){
return jsonReturn(-1,Lang::get('系统管理员不能修改'));
}
$manager = $admin -> getAdmin($where)['data'];
$manager->role()->detach();
$manager->role()->attach($param['role'],['seller_id'=>$this->admin['seller_id']]);
if(!empty($password)){
// 密码规则验证
$err = $this->checkPass($password,$this->admin['seller_id']);
if(!empty($err['message'])){
return jsonReturn(-3,$err['message']);
}
$param['password'] = makePassword($password);
$param['pass_last_change'] = time();
}
unset($param['role']);
$res = $admin->updateAdmin($where,$param);
event("AdminOptLog",[
'admin_id' => $this->admin['uid'],
'admin_name' => $this->admin['name'],
'title'=>Lang::get('管理员管理'),
"content"=>Lang::get('更新管理员信息').$param['id'],
]);
Db::commit();
}catch (\Exception $e){
Db::rollback();
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
return jsonReturn(-3,$e->getMessage());
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除管理员
*
* @throws \app\exception\ModelException
*/
public function delete(Admin $admin): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('管理员ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
event("AdminOptLog",[
'admin_id' => $this->admin['uid'],
'admin_name' => $this->admin['name'],
'title'=>Lang::get('管理员管理'),
"content"=>Lang::get('删除管理员').$id,
]);
$res = $admin->delAdmin($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 修改个人资料
*
* @throws \app\exception\ModelException
*/
public function selfUpdate(Admin $admin): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(AdminValidate::class)->scene('selfUpdate')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if ($param['code_auth'] == 1 && empty($param['phone'])) {
return jsonReturn(-2, Lang::get('开启短信验证登录需填写手机号'));
}
$where = [
'id' => $this->admin['uid'],
'seller_id' => $this->admin['seller_id'],
];
if (empty($param['password'])) {
unset($param['password']);
} else {
// 密码规则验证
$err = $this->checkPass($param['password'],$this->admin['seller_id']);
if(!empty($err['message'])){
return jsonReturn(-5,$err['message']);
}
$param['password'] = makePassword($param['password']);
// 记录密码修改时间
$param['pass_last_change'] = time();
}
$res = $admin -> updateAdmin($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function self(Admin $Admin,AdminMenu $AdminMenu): \think\response\Json
{
$admin = $Admin->getAdmin(['id' => $this->admin['uid'],'seller_id' => $this->admin['seller_id']],['role'])['data'];
// 获取权限
$role = $admin['role']->toArray();
if(empty($role)){
$auth = [];
}else{
$roleIds = array_column($role,'id');
if(in_array(1,$roleIds)){
$auth = $AdminMenu->getAllAdminMenu(['is_menu'=> 1,'seller_id'=>1])['data']->toArray();
}else{
$menuIds = array_column($role,'auth');
$tmpMenuIds = [];
foreach ($menuIds as $menuId){
$tmp = explode(',',$menuId);
$tmpMenuIds = array_merge($tmpMenuIds,$tmp);
}
$whereIn = array_unique($tmpMenuIds);
$auth = $AdminMenu -> getAllAdminMenu([['id','in',$whereIn],['is_menu','=',1]])['data']->toArray();
}
}
$menu = makeTree($auth);
return jsonReturn(0,'success',[
'user' => $admin,
'menu' => $menu,
]);
}
/**
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function current(): \think\response\Json
{
$adminModel = new Admin();
$adminMenuModel = new AdminMenu();
$admin = $adminModel->getAdmin(['id' => $this->admin['uid']], ['role'])['data'];
// 缓存权限数据
$role = $admin['role']->toArray();
if (empty($role)) {
$auth = [];
} else {
$roleIds = array_column($role, 'id');
if (in_array(1, $roleIds)) {
$auth = $adminMenuModel->getAllCustomDataModel(['seller_id' => $admin['seller_id'], 'status' => 1],'id asc','id,controller,action,path,frontend_path')['data']->toArray();
} else {
$menuIds = array_column($role, 'auth');
$tmpMenuIds = [];
foreach ($menuIds as $menuId) {
if($menuId){
$tmp = explode(',', $menuId);
$tmpMenuIds = array_merge($tmpMenuIds, $tmp);
}
}
$whereIn = array_unique($tmpMenuIds);
$auth = $adminMenuModel->getAllCustomDataModel([
['id', 'in', $whereIn],
['seller_id', '=', $admin['seller_id']],
['status', '=', 1]
],'id asc','id,controller,action,path,frontend_path')['data']->toArray();
}
}
$allowPath = array_filter(array_column($auth, 'frontend_path'));
$dynamic_content_auth = [];
// 动态菜单
foreach($auth as $val){
// 内容 content/index
$tempPath = strtolower($val['path']);
// 如果路径是 /content/index/1 格式
if(preg_match('/^\/content\/index\/\d+$/',$tempPath)){
$dynamic_content_auth[] = str_replace('/content/index','/addCustomContent',$tempPath);
$dynamic_content_auth[] = str_replace('/content/index','/updateCustomContent',$tempPath);
}
// 审核
// 如果路径是 /content/checklist/1 格式
if(preg_match('/^\/content\/checklist\/\d+$/',$tempPath)){
$dynamic_content_auth[] = str_replace('/content/checklist','/auditingContent',$tempPath);
}
}
$allowPath = array_merge($allowPath, $dynamic_content_auth);
$allowPath = array_merge($allowPath, array_keys(config('rbac.skip_auth')));
return jsonReturn(0,'success',$allowPath);
}
}

40
HuoCMS_close_source/app/controller/backend/AdminLoginLogController.php

@ -0,0 +1,40 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\AdminLoginLog;
use think\facade\Lang;
use think\facade\Request;
class AdminLoginLogController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\Response
* @throws \app\exception\ModelException
*/
public function index(AdminLoginLog $adminLoginLog): \think\Response
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = $this->setLimit();
$name = input('admin_name');
if($name){
$where['admin_name'] = $name;
}
$id = input('admin_id');
if($id){
$where['id'] = $id;
}
$adminLogList = $adminLoginLog->getAdminLoginLogList($where,$limit);
return json(pageReturn($adminLogList));
}
public function delete(): \think\response\Json
{
return parent::customDelete(Lang::get('登录日志'),Lang::get('登录日志删除'));
}
}

182
HuoCMS_close_source/app/controller/backend/AdminMenuController.php

@ -0,0 +1,182 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\AdminMenu;
use app\service\RoleService;
use app\validate\AdminMenuValidate;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Lang;
class AdminMenuController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(AdminMenu $adminMenu): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$adminMenuList = $adminMenu->getAllAdminMenu($where)['data']->toArray();
// foreach($adminMenuList as $key => $val){
// if($val['is_menu'] == 2){
// unset($adminMenuList[$key]);
// }
// }
$adminMenuList = generate($adminMenuList);
return jsonReturn(0,'success',$adminMenuList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(AdminMenu $adminMenu): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(AdminMenuValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['path'] = '/' .$param['controller'].'/'.$param['action'];
$res = $adminMenu -> addAdminMenu($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(AdminMenu $adminMenu): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $adminMenu->getAdminMenu($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(AdminMenu $adminMenu): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(AdminMenuValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['path'] = '/' .$param['controller'].'/'.$param['action'];
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = $adminMenu -> updateAdminMenu($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(AdminMenu $adminMenu): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-3,Lang::get('请求方法错误'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $adminMenu->softDelAdminMenu($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 单个控制菜单是否显示
* @author:🍁
* @Time:2023/5/22 11:12 上午
*/
public function updateMenuStatus(AdminMenu $adminMenu)
{
$id = $this->request->post('id/d',0);
$info = $adminMenu->where(['id'=>$id,'is_del'=>1])->field('id,status')->find();
if(empty($info)){
return jsonReturn(-1,lang('菜单不存在'));
}
$updateData = [
'status'=>$info['status']==1?2:1,
'update_time'=>date("Y-m-d H:i:s")
];
$res = $adminMenu->where(['id'=>$id])->update($updateData);
if($res){
return jsonReturn(0,lang('修改成功'),$updateData);
}
return jsonReturn(-2,lang('修改失败'));
}
/**
* 得到当前登录用户的权限节点
* @author:🍁
* @Time:2023/5/22 11:24 上午
*/
public function getUserMenuList(AdminMenu $adminMenu)
{
return json(RoleService::getMenuAndUpdateAuth($this->admin['uid']));
}
/**
* 获取动态菜单
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function getDynamicMenu(): \think\response\Json
{
return json(RoleService::getDynamicMenu($this->admin['uid']));
}
}

41
HuoCMS_close_source/app/controller/backend/AdminOptLogController.php

@ -0,0 +1,41 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\AdminOptLog;
use think\facade\Lang;
class AdminOptLogController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(AdminOptLog $adminOptLog): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = $this->setLimit();
$name = input('admin_name');
if($name){
$where['admin_name'] = $name;
}
$id = input('admin_id');
if($id){
$where['id'] = $id;
}
$adminLogList = $adminOptLog->getAdminOptLogList($where,$limit);
return json(pageReturn($adminLogList));
}
public function delete(): \think\response\Json
{
return parent::customDelete(Lang::get('操作日志'),Lang::get('操作日志删除'));
}
}

140
HuoCMS_close_source/app/controller/backend/AdvertisementController.php

@ -0,0 +1,140 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Advertisement;
use app\model\Attachment;
use app\validate\AdvertisementValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class AdvertisementController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Advertisement $advertisement): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$title = input('title');
if ($title) {
$where = [ 'title' => $title];
}
$limit = $this->setLimit();
$with = [
'attachment' => function($query){
$query->field('id,name,type,url');
}
];
$advertisementList = $advertisement->getAdvertisementList($where,$limit,'*',$with);
return json(pageReturn($advertisementList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(Advertisement $advertisement): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(AdvertisementValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['expiration_date'] = date('Y-m-d',strtotime($param['expiration_date']));
$param['status'] = 2; // 默认状态禁用
$res = $advertisement -> addAdvertisement($param);
optEventLog($res['data']['id'],Lang::get('广告'),Lang::get('新增'));
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Advertisement $advertisement): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('广告ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $advertisement->getAdvertisement($where,'',['attachment'=>function($q){
$q->field('id,name,type,url');
}]);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(Advertisement $advertisement): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(AdvertisementValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$param['expiration_date'] = date('Y-m-d',strtotime($param['expiration_date']));
$res = $advertisement -> updateAdvertisement($where,$param);
optEventLog($param['id'],Lang::get('广告'),Lang::get('更新'));
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(Advertisement $advertisement): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
optEventLog($id,Lang::get('广告'),Lang::get('删除'));
$res = $advertisement->softDelAdvertisement($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

158
HuoCMS_close_source/app/controller/backend/AttachmentCateController.php

@ -0,0 +1,158 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\AttachmentCate;
use app\service\CacheService;
use app\validate\AttachmentCateValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class AttachmentCateController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(AttachmentCate $attachmentCate): \think\response\Json
{
$where = [
['seller_id' ,'=', $this->admin['seller_id']],
];
$title = input('title');
if(!empty($title)){
$where[] = ['title', 'like', '%' . $title . '%'];
}
$attachmentCateList = $attachmentCate->getAllCustomArrayData($where)['data'];
$attachmentCateList = makeTree($attachmentCateList);
array_unshift($attachmentCateList,[
'id' => 0,
'parent_id' => 0,
'path' => 0,
'title'=> Lang::get('全部分类'),
'children' => [],
]);
return jsonReturn(0,Lang::get('成功'),$attachmentCateList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
* @throws \ReflectionException
*/
public function save(AttachmentCate $attachmentCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(AttachmentCateValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$attachmentCate->saveUnique(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'parent_id'=>$param['parent_id']],'栏目已经存在');
// 完善栏目数据
if ($param['parent_id']) {
$parentCate = $attachmentCate->getCustomData(['id' => $param['parent_id'], 'seller_id' => $param['seller_id']])['data'];
$param['path'] = $parentCate['path'] . '-' . $param['parent_id'];
} else {
$param['path'] = 0;
}
$res = $attachmentCate -> addAttachmentCate($param);
CacheService::deleteRelationCacheByObject($attachmentCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(AttachmentCate $attachmentCate): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('分类ID不能为空'));
}
$where = [
'id' => $id,
];
// 其他逻辑
$res = $attachmentCate->getAttachmentCate($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function update(AttachmentCate $attachmentCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(AttachmentCateValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $attachmentCate -> updateAttachmentCate($where,$param);
CacheService::deleteRelationCacheByObject($attachmentCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function delete(AttachmentCate $attachmentCate): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('分类ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$subCate = $attachmentCate -> getAllCustomArrayData(['seller_id'=>$this->admin['seller_id'],'parent_id'=>$id])['data'];
if(!empty($subCate)){
return jsonReturn(-1,Lang::get('分类下面有子分类,不能直接删除'));
}
$cate = $attachmentCate -> getCustomData($where,['attachment'=>function($q){
$q->where('is_del',1);
}])['data']->toArray();
if(!empty($cate['attachment'])){
return jsonReturn(-2,Lang::get('分类下有附件不能直接删除'));
}
$res = $attachmentCate->delAttachmentCate($where);
CacheService::deleteRelationCacheByObject($attachmentCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

508
HuoCMS_close_source/app/controller/backend/AttachmentController.php

@ -0,0 +1,508 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelException;
use app\model\Attachment;
use app\model\AttachmentCate;
use app\model\Model;
use app\model\RecycleBin;
use app\model\SysSetting;
use app\service\CacheService;
use app\service\ThemeService;
use app\service\upload\Upload;
use app\validate\AttachmentValidate;
use think\exception\ValidateException;
use think\facade\App;
use think\facade\Db;
use think\facade\Lang;
use think\file\UploadedFile;
use think\Image;
class AttachmentController extends BaseController
{
protected $type = [
'file' => 4,
'image' => 2,
'video' => 3,
'mp3' => 5,
'zip' => 1,
];
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Attachment $attachment): \think\response\Json
{
$type = (int)input('type');
$where = [
['seller_id' ,'=', $this->admin['seller_id']],
['is_del' ,'=', 1],
];
$cate_id = (int)input('cate_id');
if($cate_id){
$Cate = new AttachmentCate();
$cate = $Cate -> getCustomData(['id'=>$cate_id,'seller_id'=>$this->admin['seller_id']])['data'];
$path = $cate['path'] . '-' . $cate['id'];
$cates = $Cate -> getAllCustomArrayData([['path','like',$path.'%'],['seller_id','=',$this->admin['seller_id']]])['data'];
$ids = array_column($cates,'id');
array_unshift($ids,$cate['id']);
if(count($ids) == 1){
$where[] = ['attachment_cate_id', '=', $ids[0]];
}else{
$where[] = ['attachment_cate_id', 'in', $ids];
}
}
if($type){
$where[] = ['type', '=', $type];
}
$name = input('name');
if(!empty($name)){
$where[] = ['name', 'like', '%' . $name . '%'];
}
$limit = $this->setLimit();
$attachmentList = $attachment->getAttachmentList($where,$limit);
$res = pageReturn($attachmentList);
foreach ($res['data'] as &$value) {
$value['prefix_url'] = '';
$value['suffix_url'] = '';
if (strpos($value['url'], 'http') === false) {
if (strpos($value['url'], 'storage/') === false) {
$value['prefix_url'] = 'http://' . $this->request->host() . 'storage/';
$value['suffix_url'] = $value['url'];
$value['url'] = 'http://' . $this->request->host() . $value['url'];
continue;
}
$value['url'] = 'http://' . $this->request->host() . $value['url'];
//前缀,后缀
$urlStr = explode('storage/', $value['url']);
$value['prefix_url'] = $urlStr[0] . 'storage/';
$value['suffix_url'] = $urlStr[1];
}
}
return json($res);
}
// 修改附件路径
public function editFileUrl()
{
$param = $this->request->param();
if (empty($param['id']) || empty($param['name']) || empty($param['suffix_url'])) {
return json(dataReturn(-1, Lang::get('必填项不能为空!')));
}
$attachmentModel = new Attachment();
$info = $attachmentModel->where('id', $param['id'])->find();
if (!isset($info['id'])) {
return json(dataReturn(-1, Lang::get('文件不存在!')));
}
$param['suffix_url'] = str_replace('..', '', $param['suffix_url']);
$param['suffix_url'] = str_replace('//', '/', $param['suffix_url']);
$oldUrl = $info['url'];
$oldPathUrl = CMS_ROOT . 'public' . $oldUrl;
$newUrl = 'storage/' . $param['suffix_url'];
$newPathUrl = CMS_ROOT . 'public/' . $newUrl;
$updateData = [
'name' => $param['name'],
'description' => $param['description'],
'url' => $newUrl,
];
$fileInfo = pathinfo($newPathUrl);
mkdirs($fileInfo['dirname']);
$copyRes = true;
if ($oldPathUrl != $newPathUrl) {
$copyRes = copy($oldPathUrl, $newPathUrl);
}
if ($copyRes) {
// 复制成功
$res = $attachmentModel->where('id', $param['id'])->update($updateData);
} else {
$res = false;
}
if ($res === false) {
return json(dataReturn(-1, lang('修改失败')));
} else {
return json(dataReturn(0, lang('修改成功')));
}
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \ReflectionException
*/
public function save(Attachment $attachment): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
foreach($param as &$val){
try{
validate(AttachmentValidate::class)->scene('save')->check($val);
$val['seller_id'] = $this->admin['seller_id'];
}catch (ValidateException $e){
return jsonReturn(-1, $e->getError());
}
if ($val['storage'] == 5 && strpos($val['url'], 'http') !== 0) {
return jsonReturn(-1, lang('网络附件链接地址请以http开头'));
}
if ($val['storage'] == 5) {
// 网络附件根据url的后缀识别是什么类型
$file_type = fileFormat($val['url']);
$val['type'] = $this->type[$file_type];
}
}
$res = $attachment->addAllCustomData($param);
CacheService::deleteRelationCacheByObject($attachment);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function read(Attachment $attachment): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('附件ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = $attachment->getAttachment($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function update(Attachment $attachment): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$seller_id = $this->admin['seller_id'];
try {
validate(AttachmentValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if (isset($param['storage']) && $param['storage'] == 5 && strpos($param['url'], 'http') !== 0) {
return jsonReturn(-1, lang('网络附件链接地址请以http开头'));
}
if (isset($param['storage']) && $param['storage'] == 5) {
// 网络附件根据url的后缀识别是什么类型
$file_type = fileFormat($param['url']);
$param['type'] = $this->type[$file_type];
}
$where = [
'id' => $param['id'],
'seller_id' => $seller_id,
];
$res = $attachment -> updateAttachment($where,$param);
CacheService::deleteRelationCacheByObject($attachment);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(Attachment $Attachment): \think\response\Json
{
$idArr = $this->request->param('id');
if(is_string($idArr)){
$ids = explode(',',$idArr);
}else{
$ids = $idArr;
}
$where = [
['id','in',$ids],
['seller_id','=',$this->admin['seller_id']]
];
$attachment = $Attachment -> getAllCustomArrayData($where)['data'];
Db::startTrans();
try{
$binData=[];
foreach ($attachment as $val){
// 复制删除内容到回收站表
$binData[] = [
'seller_id' => $this->admin['seller_id'],
'object_id' => $val['id'],
'sub_id' => 0,
'module_id' => 0,
'table_name' => '附件-attachment',
'title' => !empty($val['name']) ? $val['name'] : '附件' . $val['id'],
'admin_id' => $this->admin['uid'],
'name' => $this->admin['name'],
];
}
$recycleBin = new RecycleBin();
$recycleBin -> addAllCustomData($binData);
$Attachment -> updateAttachment($where,['is_del'=>2,'delete_time'=>time()]);
CacheService::deleteRelationCacheByObject($Attachment);
optEventLog($idArr,Lang::get('附件'),Lang::get('删除'));
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(-1,Lang::get('删除失败'));
}
return jsonReturn(0,Lang::get('删除成功'));
}
/**
* @throws \app\exception\ModelException
*/
public function uploadAndSave(Attachment $attachment): \think\response\Json
{
if(request()->isPost()){
set_time_limit(0);
$file = request()->file('file');
$reduceImg = request()->file('reduce_img');
if(empty($file)){
return jsonReturn(-8,lang('文件上传失败,请重新尝试'));
}
$seller_id = $this->admin['seller_id'];
$attachmentModel = new Attachment();
$has = $attachmentModel->checkFileExist($this->admin['seller_id'], $file->hash());
if ($has['code'] == 0) {
$reduceImgData = !empty($reduceImg)?$this->singleUpload($reduceImg,$seller_id)['data']:[];
$updateData = [
'update_time' => time(),
'reduce_img'=> !empty($reduceImgData)?$reduceImgData['getUploadFileInfo']['url']:"",
'attachment_cate_id' => $this->request->param('attachment_cate_id/d',0),
];
// 更新時間
$attachmentModel->where('id', $has['data']['id'])->update($updateData);
return json($has);
}
$fileData = $this->singleUpload($file,$seller_id)['data'];
$reduceImgData = !empty($reduceImg)?$this->singleUpload($reduceImg,$seller_id)['data']:[];
$fileData['getUploadFileInfo']['seller_id'] = $seller_id;
$fileData['getUploadFileInfo']['type'] = $fileData['fileType'];
$fileData['getUploadFileInfo']['size'] = round($fileData['fileSize'] / 1024,2);
$fileData['getUploadFileInfo']['attachment_cate_id'] =$this->request->param('attachment_cate_id/d',0);
$fileData['getUploadFileInfo']['reduce_img'] = !empty($reduceImgData)?$reduceImgData['getUploadFileInfo']['url']:"";
$attachment = new Attachment();
$res = $attachment->addAttachment($fileData['getUploadFileInfo']);
optEventLog($res['data']['id'],Lang::get('附件'),Lang::get('添加'));
return json($res);
}
return jsonReturn(-3,lang('请求方法错误'));
}
/**
* @throws ModelException
*/
private function singleUpload($file,$seller_id)
{
// 查看文件类型
$fileName = $file->getOriginalName();
$fileExt = $file->getOriginalExtension();
$file_type = fileFormat($fileName);
$fileType = $this->type[$file_type];
$Settings = new SysSetting();
$uploadSetting = $Settings->getAllCustomArrayData(['parent_id'=>1,'group'=>'upload','status'=>1],'id desc','id,group,title,value')['data'];
$uploadSetting = getColumnForKeyArray($uploadSetting,'title');
$limitSize = $uploadSetting[$file_type.'_size']['value'] * 1024; // byte
$fileSize = $file->getSize(); // 单位byte
if($fileSize > $limitSize){
throw new ModelException(lang('文件过大,请修改上传限制或者替换小的文件'),-1);
}
$extArr = explode(',',$uploadSetting[$file_type.'_ext']['value']);
if(!in_array($fileExt,$extArr)){
throw new ModelException(lang('文件格式错误,请重新上传'),-2);
}
$type = $this->getUploadType();
$upload = new Upload();
$info = $upload->create($file,$seller_id, $type,$file_type);
if(!$info){
throw new ModelException(lang('上传失败请重新尝试'),-3);
}
$getUploadFileInfo = $upload->getUploadFileInfo()['data'];
$waterConfig = SysSetting::where(['group'=>'upload'])->column("value",'title');
//上传的是图片格式,
if($type=="local" && $file_type=="image" && isset($waterConfig['water_status'])&& $waterConfig['water_status']==1){
$fullPath ='./'.$getUploadFileInfo['url'];
$waterFontPath = $this->getWaterFontPath($waterConfig['water_font_path']??"");
$originalImage = Image::open($fullPath);
$originalImage->text($waterConfig['water_text']??'HuoCMS',App::getRootPath()."public/system_file/alifont/ali-Regular.woff",
$waterConfig['water_font_size']??20,$waterConfig['water_font_color']??"#18171b",$waterFontPath)->save($fullPath);
}
return dataReturn(0,'上传成功',
[
'fileType'=>$fileType,
'fileSize'=>$fileSize,
'getUploadFileInfo'=>$getUploadFileInfo
]);
}
public function sliceUploadAndSave(Upload $uploader): \think\response\Json
{
$params = $this->request->param();
$params['resource_chunk'] = $this->request->file('resource_chunk');
$file_type = fileFormat('abc.'.$params['resource_type']);
$Settings = new SysSetting();
$uploadSetting = $Settings->getAllCustomArrayData(['parent_id'=>1,'group'=>'upload','status'=>1],'id desc','id,group,title,value')['data'];
$uploadSetting = getColumnForKeyArray($uploadSetting,'title');
$extArr = explode(',',$uploadSetting[$file_type.'_ext']['value']);
if(!in_array($params['resource_type'],$extArr)){
return jsonReturn(-2,lang('文件格式错误,请重新上传'));
}
$res = $uploader->tmpMove($params['resource_chunk'],$file_type,$params['resource_temp_path'],$params['chunk_index']);
if($res){
$tmPath = runtime_path() . 'slice/'.$file_type.'/'.$params['resource_temp_path'];
$num = getFileNumber($tmPath);
if($num == $params['chunk_total']){
try {
$filepath = $uploader->mergeBlob($tmPath,$params['resource_temp_path'],$params['chunk_total'],$params['resource_type']);
$type = $this->getUploadType();
$file = new UploadedFile($filepath,$params['resource_temp_path'].'.'.$params['resource_type']);
if($type == 'local'){
if(!file_exists(public_path() . 'storage/' . $file_type.'/'. date('Ymd'))){
@mkdir(public_path() . 'storage/' . $file_type.'/'. date('Ymd'),0755,true);
}
copy($filepath,public_path() . 'storage/' . $file_type.'/'. date('Ymd') .'/'.$params['resource_temp_path'] .'.'.$params['resource_type']);
$cateId = (int)input('attachment_cate_id');
$uploadInfo['name'] = $params['resource_name'];
$uploadInfo['url'] = 'storage/' . $file_type.'/'. date('Ymd') .'/'.$params['resource_temp_path'] .'.'.$params['resource_type'];
$uploadInfo['mime_type'] = $params['resource_type'];
$uploadInfo['storage'] = 1;
$uploadInfo['type'] = $this->type[$file_type];
$uploadInfo['size'] = round($file->getSize() / 1024,2);
$uploadInfo['attachment_cate_id'] = $cateId;
$attachment = new Attachment();
$res = $attachment->addAttachment($uploadInfo);
optEventLog($res['data']['id'],Lang::get('附件'),Lang::get('添加'));
(new ThemeService()) -> deleteFile($tmPath);
return json($res);
}else{
$upload = new Upload();
$res = $upload->create($file,$this->admin['seller_id'], $type);
if($res){
$fileSize = $file->getSize();
$fileType = $this->type[$file_type];
$res = $this->getResponse($fileType,$fileSize,$upload);
(new ThemeService()) -> deleteFile($tmPath);
return json($res);
}else{
return jsonReturn(-1,Lang::get('上传失败'));
}
}
} catch (\Exception $e) {
return jsonReturn(-1,$e->getMessage(),[]);
}
}else{
return jsonReturn(1,Lang::get('上传成功'),$res);
}
}else{
return jsonReturn(-1,Lang::get('上传失败'),$res);
}
}
/**
* @throws \app\exception\ModelException
*/
public function getResponse($fileType, $fileSize, $upload)
{
$uploadInfo = $upload->getUploadFileInfo();
$cateId = (int)input('attachment_cate_id');
if ($uploadInfo['code'] == 0) {
$uploadInfo['data']['type'] = $fileType;
$uploadInfo['data']['size'] = round($fileSize / 1024,2);
$uploadInfo['data']['attachment_cate_id'] = $cateId;
$attachment = new Attachment();
$res = $attachment->addAttachment($uploadInfo['data']);
optEventLog($res['data']['id'],Lang::get('附件'),Lang::get('添加'));
return $res;
} else {
return $uploadInfo;
}
}
public function getFileType()
{
}
/**
* @throws \app\exception\ModelException
*/
public function getUploadType()
{
// 文件信息提取
$where = [
'seller_id' => $this->admin['seller_id'],
'group' => 'upload',
'title' => 'storage'
];
$place = new SysSetting();
return $place->getSysSetting($where)['data']->toArray()['value'];
}
/**
* 得到文字水印的位置
*/
private function getWaterFontPath($fontPath)
{
$arr = [
'右下'=>Image::WATER_SOUTHEAST,
'左上'=>Image::WATER_NORTHWEST,
'上居中'=>Image::WATER_NORTH,
'右上'=>Image::WATER_NORTHEAST,
'左居中'=>Image::WATER_WEST,
'居中'=>Image::WATER_CENTER,
'右居中'=>Image::WATER_EAST,
'左下'=>Image::WATER_SOUTHWEST,
'下居中'=>Image::WATER_SOUTH,
];
return !isset($arr[$fontPath])?Image::WATER_SOUTHEAST:$arr[$fontPath];
}
}

90
HuoCMS_close_source/app/controller/backend/BaseController.php

@ -0,0 +1,90 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\BaseController as AppBaseController;
use app\model\Model;
use think\facade\Lang;
use think\facade\Request;
class BaseController extends AppBaseController
{
public $admin;
public $lang;
/**
* 控制器中间件
* @var array
*/
protected $middleware = [
'login',
'auth',
];
public function initialize()
{
parent::initialize();
self::createInstallFile();
$this->admin = $this->request->admin;
session('adminId', $this->admin['uid']);
$this->lang = config('lang.allow_lang_list');
}
public function setLimit(): int
{
$limit = 10;
$limitPage = (int)input('param.limit');
if($limitPage){
$limit = $limitPage;
}
return $limit;
}
private static function createInstallFile()
{
if(!hcInstalled() && is_dir(app()->getRootPath().'data/install/')){
$url = env('app_host') . '/install';
redirect($url);
}
// 更新版本标识
updateVersion();
}
public function customDelete($opt,$title='批量删除'): \think\response\Json
{
$ids = $this->request->param('id');
if(is_string($ids)){
$ids = explode(',',$ids);
}
$className = str_replace('backend.','',Request::controller());
$modelName = '\\app\\model\\' . $className;
$model = new $modelName();
try{
$model->whereIn('id',$ids)->delete();
optEventLog(json_encode($ids),$title,$opt);
}catch (\Exception $e){
return jsonReturn(-1,Lang::get('删除失败'));
}
return jsonReturn(0,Lang::get('删除成功'));
}
public function customSoftDelete($opt,$title='批量删除'): \think\response\Json
{
$ids = $this->request->param('id');
if(is_string($ids)){
$ids = explode(',',$ids);
}
$className = str_replace('backend.','',Request::controller());
$modelName = '\\app\\model\\' . $className;
$model = new $modelName();
try{
$model->whereIn('id',$ids)->update(['is_del'=>2,'delete_time'=>time()]);
optEventLog(json_encode($ids),$title,$opt);
}catch (\Exception $e){
return jsonReturn(-1,Lang::get('删除失败'));
}
return jsonReturn(0,Lang::get('删除成功'));
}
}

537
HuoCMS_close_source/app/controller/backend/CategoryController.php

@ -0,0 +1,537 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelException;
use app\model\AdminMenu;
use app\model\Attachment;
use app\model\Category;
use app\model\CategoryCheck;
use app\model\Route;
use app\model\ThemeFile;
use app\model\Website;
use app\service\ApiService;
use app\service\CacheService;
use app\service\CategoryService;
use app\service\StaticFileService;
use app\validate\CategoryValidate;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Lang;
class CategoryController extends BaseController
{
protected $cacheKeyArr = 'hc_module_cate_arr';
/**
* 栏目列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function index(Category $category): \think\response\Json
{
$websiteId = (int)input('param.website_id');
if(!$websiteId){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$where = [
['seller_id','=', $this->admin['seller_id']],
['website_id','=',$websiteId],
];
$lang = input('lang');
if(empty($lang)){
$lang = config('lang.default_lang');
}
$Website = new Website();
$website = $Website -> getCustomArrayData(['id'=>$websiteId,'seller_id'=>$this->admin['seller_id']])['data'];
$domain = $website['domain'];
if($lang != config('lang.default_lang')){
$domain = $domain .'/'.$lang;
}
$title = $this->request->param('title','');
$checkStatus = $this->request->param('need_check',0);
if($checkStatus == 1){
$where[] = ['need_check','=',$checkStatus];
}
if(!empty($title)) {
$where[] = ['title', 'like', '%' . $title . '%'];
}
$where[] = ['lang','=',$lang];
$with = [
'thumbnail' => function($query){
$query->field('id,name,url');
}
];
//栏目管理搜索栏目名称
$categoryTitle = $this->request->param("category_title/s",'','trim,strip_tags');
if(!empty($categoryTitle)){
$categoryIdPath = $category->where([
['seller_id','=', $this->admin['seller_id']],
['website_id','=',$websiteId],
['lang','=',$lang],
['title','like',"%{$categoryTitle}%"],
])->column('path','id');
if(empty($categoryIdPath)){
return jsonReturn(0,'内容不存在');
}
$selectIds = [];
foreach ($categoryIdPath as $pathId => $paths){
$paths = explode('-',$paths);
for ($i=1;$i<count($paths)-1;$i++){
$selectIds[$paths[$i]] = $paths[$i];
}
$selectIds[$pathId] = $pathId;
}
$where[] = ['id','in',$selectIds];
}
$themeFileModel = new ThemeFile();
$designFileList = $themeFileModel->getAllCustomArrayData([['is_design', '=', 1]])['data'];
$newDesignFileList = [];
foreach ($designFileList as $value) {
$value['file_name'] = str_replace('.html', '', $value['file']);
$newDesignFileList[$value['file']] = $value;
$newDesignFileList[$value['file_name']] = $value;
}
$categoryList = $category->getAllCustomArrayData($where,'id asc','id,seller_id,website_id,module_id,parent_id,title,lang,alias,type,path,thumbnail,sort,status,list_tpl',$with)['data'];
foreach($categoryList as &$item){
if($item['type'] == 1 || $item['type'] == 4){
if(!empty($item['alias'])){
if($item['alias'] == '/'){
$item['fullUrl'] = 'http://' . $domain;
}else{
$item['fullUrl'] = 'http://' . $domain . $item['alias'].'.'.config('route.url_html_suffix');
}
}else{
$item['fullUrl'] = 'http://' . $domain . '/list/index/'.$item['id'].'.'.config('route.url_html_suffix');
}
}else if($item['type'] == 3){
$item['fullUrl'] = $item['alias'];
}else{
$item['fullUrl'] = 'javascript:;';
}
$item['is_design'] = 0;
$item['design_path'] = '';
if (isset($newDesignFileList[$item['list_tpl']])) {
$item['is_design'] = 1;
$item['design_path'] = $newDesignFileList[$item['list_tpl']]['design_path'];
}
}
if($checkStatus != 1){
$categoryList = makeTree($categoryList);
}
return jsonReturn(0,'success',$categoryList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function save(CategoryService $categoryService,Category $Category): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['alias'] = $param['alias'] ?? '';
$param['module_id'] = $param['module_id'] ?? 1;
$param['is_menu'] = $param['is_menu'] ?? 2;
// 数据验证
try{
if(!empty($param['parent_map'])){
$param = $this->getMapCateData($param);
}
validate(CategoryValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
if (in_array($param['alias'], StaticFileService::$forbidNames)) {
return jsonReturn(-2,lang('别名已被系统占用,请修改别名'));
}
$param['seller_id'] = $this->admin['seller_id'];
$category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
if(!empty($category)){
return jsonReturn(-2,'栏目已经存在');
}
if(in_array($param['type'],[1,4]) && empty($param['alias'])){
if($param['list_tpl'] == 'index'){
$param['alias'] = '/';
}else{
$param['alias'] = $this->getAlias($param['title'],$param['website_id'],$param['lang'],$param['seller_id']);
}
}
if(!empty($param['alias']) && $param['alias'] != 'javascript:;'){
$category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']])['data'];
}
if(!empty($category)){
return jsonReturn(-3,lang('栏目别名已经存在'));
}
if ($param['need_check'] == 1 && (empty($param['check_list']) || !is_array($param['check_list']))) {
return jsonReturn(-3,'请设置审核人员!');
}
if (!empty($param['field_list'])) {
$keyArr = [];
foreach ($param['field_list'] as $value) {
if (isset($keyArr[$value['key']])) {
return jsonReturn(-5,lang('自定义字段名称重复:') . $value['key']);
}
$keyArr[$value['key']] = $value;
}
$param['field_list'] = json_encode($param['field_list'], JSON_UNESCAPED_UNICODE);
}
return $categoryService -> createCategory($param);
}
return jsonReturn(-3,Lang::get(lang('请求方法错误')));
}
/**
* 栏目详情
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Category $category,Attachment $attachment): \think\response\Json
{
$param = input('param.');
try {
validate(CategoryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id']= $this->admin['seller_id'];
$with = [
'thumbnail' => function($query){
$query->field('id,name,url');
},'banner' => function($query){
$query->field('id,name,url');
}
];
$res = $category->getCategory($param,$with);
if (!empty($res['data']['content'])) {
$res['data']['content'] = htmlspecialchars_decode($res['data']['content']);
}
$res['data']['check_list'] = [];
if ($res['data']['need_check'] == 1) {
$checkModel = new CategoryCheck();
$checkList = $checkModel->where([
['category_id', '=', $res['data']['id']],
['status', '=', 1],
['type','=',1]
])->select()->toArray();
$res['data']['check_list'] = $checkList;
}
if (!empty($res['data']['field_list'])) {
$res['data']['field_list'] = json_decode($res['data']['field_list'], true);
}
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function update(CategoryService $categoryService,Category $Category): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['is_menu'] = $param['is_menu'] ?? 2;
try {
if(!empty($param['parent_map'])){
$param = $this->getMapCateData($param);
}
validate(CategoryValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if (in_array($param['alias'], StaticFileService::$forbidNames)) {
return jsonReturn(-2,lang('别名已被系统占用,请修改别名'));
}
$param['seller_id'] = $this->admin['seller_id'];
if(in_array($param['type'],[1,4]) && empty($param['alias'])){
if($param['list_tpl'] == 'index'){
$param['alias'] = '/';
}else{
$param['alias'] = $this->getAlias($param['title'],$param['website_id'],$param['lang'],$param['seller_id']);
}
}
$category = $Category->existCategory(['title'=>$param['title'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'parent_id'=>$param['parent_id']])['data'];
if(!empty($category) && $category['id'] != $param['id']){
return jsonReturn(-2,lang('栏目已经存在'));
}
$category = $Category->existCategory(['title'=>$param['alias'],'seller_id'=>$param['seller_id'],'website_id'=>$param['website_id']])['data'];
if(!empty($category) && $category['id'] != $param['id']){
return jsonReturn(-3,lang('栏目别名已经存在'));
}
if (isset($param['need_check']) && $param['need_check'] == 1 && (empty($param['check_list']) || !is_array($param['check_list']))) {
return jsonReturn(-3,lang('请设置审核人员'));
}
if (!empty($param['field_list'])) {
$keyArr = [];
foreach ($param['field_list'] as $value) {
if (isset($keyArr[$value['key']])) {
return jsonReturn(-5,lang('自定义字段名称重复:') . $value['key']);
}
$keyArr[$value['key']] = $value;
}
$param['field_list'] = json_encode($param['field_list'], JSON_UNESCAPED_UNICODE);
}
$this->deleteCateCacheKey($param['website_id'],$param['lang']);
return $categoryService -> updateCategory($param);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除栏目
* @param Category $category
* @param Route $route
* @return \think\response\Json
*/
public function delete(Category $category,Route $route): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(CategoryValidate::class)->scene('delete')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang']
];
Db::startTrans();
try {
$subCate = $category -> getAllCustomArrayData(['seller_id'=>$this->admin['seller_id'],'parent_id'=>$param['id']])['data'];
$this->deleteCateCacheKey($param['website_id'],$param['lang']);
if(!empty($subCate)){
return jsonReturn(-1,lang('栏目下面有子栏目,不能直接删除'));
}
$res = $category->delCategory($where);
$route->delRoute(['seller_id' => $this->admin['seller_id'],'category_id'=>$param['id']]);
$route->getRoutes($param['website_id'], $this->admin['seller_id'], $param['lang']);
// 把动态菜单删除
$menu = new AdminMenu();
// 审核 /content/checkList/41
$menu -> delCustomData(['path'=>'/content/checkList/'.$param['id']]);
// 内容 /content/index/5
$menu -> delCustomData(['path'=>'/content/index/'.$param['id']]);
CacheService::deleteRelationCacheByObject($route);
CacheService::deleteRelationCacheByObject($category);
$optAdmin = request()->admin;
event("AdminOptLog",[
'admin_id' => $optAdmin['uid'],
'admin_name' => $optAdmin['name'],
'title'=>lang("栏目管理"),
"content"=>lang("删除栏目,栏目ID为").$param['id'],
]);
Db::commit();
CacheService::clear();
}catch (ModelException $me){
Db::rollback();
return jsonReturn(50023,$me->getMessage());
}catch (\Exception $e){
Db::rollback();
return jsonReturn(50024,$e->getMessage());
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 分组获取栏目列表
* @param Category $Category
* @return \think\response\Json
*/
public function getModuleCate(Category $Category): \think\response\Json
{
$param = input('get.');
try {
validate(CategoryValidate::class)->scene('getModuleCate')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$Website = new Website();
$website = $Website->getAllCustomArrayData([['id','in',$param['site_id']],['seller_id','=',$this->admin['seller_id']]]
,'id asc','id,seller_id,title,domain')['data'];
$website = getColumnForKeyArray($website,'id');
$category = $Category -> getAllCustomArrayData([['website_id','in',$param['site_id']],['seller_id','=',$this->admin['seller_id']],['lang','=',$param['lang']]],'id asc')['data'];
$category = getArrayGroupBy($category,'website_id');
$response = [];
foreach($category as $key => $cate){
$tmpCategory = $this->makeTree($cate);
$tmpCategory = $this->imp($tmpCategory);
$tmpCate = $website[$key];
$tmpCate['category'] = $tmpCategory;
$response[] = $tmpCate;
}
return jsonReturn(0,lang('成功'),$response);
}
public function makeTree($data, int $pid=0, int $level=0): array
{
$tree = array();
$tmpTree = [];
foreach ($data as $key => &$value) {
$str = str_repeat('--',$level);
$value['title'] = $str . $value['title'];
if ($value['parent_id'] == $pid) {
$value['level'] = $level;
unset($data[$key]);
$tmpTree[] = $value;
$value['children'] = $this->makeTree($data, $value['id'],$level+1);
$tree[] = $value;
}else{
$tmpTree[] = $value;
}
}
return $tree;
}
public function imp($tree, $children='children'): array
{
$impArr = array();
foreach($tree as $w) {
if(isset($w[$children])) {
$t = $w[$children];
unset($w[$children]);
$impArr[] = $w;
if(is_array($t)) $impArr = array_merge($impArr, $this->imp($t, $children));
} else {
$impArr[] = $w;
}
}
return $impArr;
}
/**
* 栏目复制
* @throws ModelException
* @throws \Exception
*/
public function copy(CategoryService $categoryService): \think\response\Json
{
set_time_limit(300);
$param = input('post.');
try {
validate(CategoryValidate::class)->scene('copy')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
foreach ($param['target_site'] as $val){
if(empty($val) || !is_numeric($val)){
return jsonReturn(-1,lang('目标站点数据异常,请检查'));
}
}
$res = $categoryService -> copyCate($param['original_site'],$param['target_site'],$param['lang'],$this->admin['seller_id']);
return json($res);
}
/**
* @throws \app\exception\ModelEmptyException
* @throws ModelException
*/
public function getMapCateData(&$param)
{
$Category = new Category();
$param['parent_path'] = json_encode($param['parent_map']);
$param['parent_map'] = array_pop($param['parent_map']);
$mapCate = $Category->getCategory(['id'=>$param['parent_map'],'seller_id'=>$this->admin['seller_id']])['data']->toArray();
foreach($mapCate as $k => $v){
if($k == 'parent_id'){
continue;
}
if(empty($param[$k]) && !in_array($k,['id','create_time','update_time'])){
$param[$k] = $v;
}
}
return $param;
}
public function deleteCateCacheKey($siteId,$lang)
{
$cateCacheKey = 'hc_cate_' . $this->admin['seller_id'] . '_' . $siteId .'_' . $lang;
Cache::delete($cateCacheKey);
$moduleCateArr = Cache::get($this->cacheKeyArr);
if(!empty($moduleCateArr)){
foreach ($moduleCateArr as $cate){
$tmpCate = explode('_',str_replace('hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_','',$cate));
if(in_array($siteId,$tmpCate)){
$moduleCateCacheKey = 'hc_module_cate_' . $this->admin['seller_id'] . '_' . $lang .'_' . $siteId;
Cache::delete($moduleCateCacheKey);
unset($moduleCateArr[$cate]);
}
}
Cache::set($this->cacheKeyArr,$moduleCateArr);
}
}
/**
* @throws ModelException
* @throws \app\exception\ModelEmptyException
*/
public function getAlias($title, $siteId, $lang, $sellerId): string
{
$pinyin = new Pinyin();
$cacheKey = $sellerId .'_'.$siteId .'_'. $lang . '_website_cache_key';
$settingData = Cache::get($cacheKey);
if(empty($settingData)){
$settingData = ApiService::setWebsiteSetting($sellerId,$siteId,$lang);
}
if(!empty($settingData['alias_rule']) && $settingData['alias_rule'] == 1){
$alias = strtolower('/' . $pinyin -> abbr($title));
}else{
$alias = strtolower('/' . $pinyin -> permalink($title,''));
}
return $alias;
}
public function copyToOtherLang(CategoryService $categoryService): \think\response\Json
{
$param = $this->request->only(['from','to','site_id']);
try {
validate(CategoryValidate::class)->scene('copyCategoryToAnotherLang')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
return json($categoryService -> copyCategoryToOtherLang($param['from'],$param['to'],$param['site_id'],$this->admin['seller_id']));
}
public function updateStatus(CategoryService $categoryService): \think\response\Json
{
$param = $this->request->only(['id','status']);
try {
validate(CategoryValidate::class)->scene('updateStatus')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
return json($categoryService -> updateStatus($param['id'],$param['status'],$this->admin['seller_id']));
}
}

1110
HuoCMS_close_source/app/controller/backend/ContentController.php
File diff suppressed because it is too large
View File

146
HuoCMS_close_source/app/controller/backend/ContentTagController.php

@ -0,0 +1,146 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\ContentTag;
use app\taglib\HcTaglib;
use app\validate\ContentTagValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class ContentTagController extends BaseController
{
public function initialize()
{
define('ADMIN_SITE_ID',(int)input('site_id'));
define('ADMIN_SELLER_ID',$this->admin['seller_id']);
parent::initialize();
}
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(ContentTag $contentTag): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
$contentTagList = $contentTag->getContentTagList($where,$limit);
return json(pageReturn($contentTagList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(ContentTag $contentTag): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(ContentTagValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $contentTag -> addContentTag($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(HcTaglib $hcTaglib): \think\response\Json
{
$param = input('post.');
try {
validate(ContentTagValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$func = 'tag' . ucfirst($param['title']);
// $hcTaglib = new HcTaglib(new Template());
$hcTaglib->$func();
dd($param);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(ContentTag $contentTag): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(ContentTagValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = $contentTag -> updateContentTag($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(ContentTag $contentTag): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
// TO DO
// 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $contentTag->delContentTag($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

68
HuoCMS_close_source/app/controller/backend/DashboardController.php

@ -0,0 +1,68 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use think\facade\Db;
class DashboardController extends BaseController
{
/**
* 后台首页看板
*
*/
public function index(): \think\Response
{
if(!hcInstalled()){
createInstallFile();
}
$install_date = filectime(app()->getRootPath().'public/system_file/install.lock');
// 运行天数
$total_day = (int)ceil((time() - $install_date) / (24*3600)) ?: 1;
// 总站点数
$site_count = Db::name('website')->where('seller_id',$this->admin['seller_id'])->count('id');
// 总访客数
$visit_count = count(Db::name('visit_log')->distinct(true)->field('ip,visited_time')->select()->toArray());
// 总文章数 (模型为系统文章模型)
$article_count = Db::name('sub_content')->where('is_del',1)->count('id');
// 总询盘数
$inquiry_count = Db::name('inquiry')->where('is_del',1)->count('id');
// 总关键词数
$keyword_count = Db::name('keyword')->where('is_del',1)->count('id');
// 总导入链接数
$in_link_count = Db::name('link')->where(['type'=>1,'is_del'=>1])->count('id');
// 总导出链接数
$out_link_count = Db::name('link')->where(['type'=>2,'is_del'=>1])->count('id');
// 授权信息 // https://www.huocms.com/auth
$domain = request()->param('domain');
if(empty($domain)){
$auth_info = null;
}else{
$authRes = curlPost(config('system.auth_query_url'),['domain'=> request()->param('domain')])['data'];
$auth_info = json_decode($authRes,true);
if(empty($auth_info['data'])){
$auth_info = null;
}else{
$auth_info = $auth_info['data'];
}
$websiteTitle = Db::name('website')->where('domain',$domain)->where('seller_id',$this->admin['seller_id'])->value('title');
}
return jsonReturn(0,'success',[
'total_day' => $total_day,
'site_count' => $site_count,
'visit_count' => $visit_count,
'article_count' => $article_count,
'inquiry_count' => $inquiry_count,
'keyword_count' => $keyword_count,
'in_link_count' => $in_link_count,
'out_link_count' => $out_link_count,
'auth_info' => $auth_info,
'version' => file_get_contents(app()->getRootPath().'version'),
'website_title' => $websiteTitle ?? '',
]);
}
}

146
HuoCMS_close_source/app/controller/backend/DatabaseController.php

@ -0,0 +1,146 @@
<?php
namespace app\controller\backend;
use app\model\Database;
use app\service\MysqlBackupService;
use think\App;
use think\facade\Db;
use think\facade\Env;
class DatabaseController extends BaseController
{
protected $service;
/**
* @throws \Exception
*/
public function __construct(App $app)
{
parent::__construct($app);
$config = array(
'level' => 5,//数据库备份卷大小
'compress' => 0,//数据库备份文件是否启用压缩 0不压缩 1 压缩
);
$this->service = new MysqlBackupService($config);
}
/**
* 数据表列表
* @return \think\response\Json
*/
public function tableList(): \think\response\Json
{
return json($this->service->dataList());
}
/**
* 备份文件列表
* @return mixed
* @throws \app\exception\ModelException
*/
public function index()
{
$path = app()->getRootPath() .'backup/';
$glob = hcScanDir($path.'*');
if(empty($glob)){
return jsonReturn(0,'success');
}
arsort($glob);
$data = [];
foreach ($glob as $key => $val){
$tmp = [
'id' => $key+1,
'title' => $val,
'size' => sprintf("%.2f",filesize($path.$val) / 1000) .'kb' ,
];
array_push($data,$tmp);
}
return jsonReturn(0,lang('成功'),$data);
}
/**
* @param $name
* @return mixed
*/
public function detail($name)
{
return jsonReturn($this->service->detail($name));
}
/**
* 数据库备份
* @throws \app\exception\ModelException
* @throws \think\db\exception\BindParamException
*/
public function backup(): \think\response\Json
{
return $this->service->backupDatabase($this->admin['seller_id']);
}
/**
* 文件恢复
* @return \think\response\Json
*/
public function restore(): \think\response\Json
{
if(!request()->isPost()){
return jsonReturn(-1,lang('方法请求错误'));
}
$filename = input('post.filename');
$res = $this->service->import($filename,0);
return json($res);
}
/**
* 数据表优化
* @param $name
* @throws \Exception
*/
public function optimize($name): \think\response\Json
{
$this->service->optimize($name);
return jsonReturn(0,lang('优化成功'));
}
/**
* 数据表修复
* @param $name
* @throws \Exception
*/
public function repair($name): \think\response\Json
{
$this->service->repair($name);
return jsonReturn(0,lang('修复成功'));
}
/**
* @return \think\response\File
*/
public function downloadFile(): \think\response\File
{
try {
$time = intval($this->request->param('filename'));
$file =$this->service->getFile('time', $time);
$fileName = $file[0];
return download($fileName,$time);
}catch (UploadFailException $e){
return app('json')->fail(lang('下载失败'));
}
}
/**
* @throws \Exception
*/
public function delete(): \think\response\Json
{
$filename = $this->request->param('filename');
if(empty($filename)){
return jsonReturn(-2,lang('文件名不能为空'));
}
return $this->service->delFile($filename);
}
}

686
HuoCMS_close_source/app/controller/backend/DesignController.php

@ -0,0 +1,686 @@
<?php
namespace app\controller\backend;
use app\model\BigField;
use app\model\Category;
use app\model\CategorySubContent;
use app\model\SubContent;
use app\model\Theme;
use app\model\ThemeFile;
use app\model\Website;
use app\model\WebsiteSetting;
use app\service\ApiService;
use app\service\ThemeFileService;
use app\service\ThemeService;
use app\validate\WebsiteSettingValidate;
use think\exception\ValidateException;
use think\response\Json;
class DesignController extends BaseController
{
protected $designBase = 'public/design/designPage';
protected function sanitizeFileName($file)
{
//sanitize, remove double dot .. and remove get parameters if any
$file = CMS_ROOT . 'public/design/designPage/' . preg_replace('@\?.*$@', '', preg_replace('@\.{2,}@', '', preg_replace('@[^\/\\a-zA-Z0-9\-\._]@', '', $file)));
return $file;
}
public function save()
{
return $this->publish(1);
// $param = $this->request->param();
// // 数据验证
// try {
// validate(WebsiteSettingValidate::class)->scene('read')->check($param);
// } catch (ValidateException $e) {
// return jsonReturn(-1, $e->getError());
// }
//
// define('MAX_FILE_LIMIT', 1024 * 1024 * 2);//2 Megabytes max html file size
//
// $html = "";
// if (isset($_POST['startTemplateUrl']) && !empty($_POST['startTemplateUrl'])) {
// $startTemplateUrl = $this->sanitizeFileName($_POST['startTemplateUrl']);
// $html = file_get_contents($startTemplateUrl);
// } else if (isset($_POST['html'])) {
// $html = substr($_POST['html'], 0, MAX_FILE_LIMIT);
// }
//
// $where = [
// 'seller_id' => $this->admin['seller_id'],
// 'website_id' => $param['website_id'],
// 'lang' => $param['lang'],
// 'is_active' => 1
// ];
// $Theme = new Theme();
// $theme = $Theme->getActiveTheme($where)['data']->toArray();
// $themeName = $theme['theme'];
//
// $pathInfo = pathinfo($param['file']);
// $filename = $pathInfo['filename'];
//// $file = $this->sanitizeFileName($_POST['file']);
// $file = CMS_ROOT . "view/website/{$param['website_id']}/{$param['lang']}/{$themeName}/single_{$filename}.html";
//
// if (file_put_contents($file, $html)) {
// echo "保存成功 $file";
// } else {
// header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal Server Error', true, 500);
// echo "保存失败! $file\n可能的原因是缺少写权限或文件路径不正确!";
// }
// exit();
}
/**
* @param $saveType 1保存2发布
* @return Json|void
*/
public function publish($saveType = 2)
{
$param = $this->request->param();
// 数据验证
try {
validate(WebsiteSettingValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
define('MAX_FILE_LIMIT', 1024 * 1024 * 2);//2 Megabytes max html file size
$html = "";
if (isset($param['startTemplateUrl']) && !empty($param['startTemplateUrl'])) {
$startTemplateUrl = $this->sanitizeFileName($param['startTemplateUrl']);
$html = file_get_contents($startTemplateUrl);
} else if (isset($_POST['html'])) {
$html = substr($_POST['html'], 0, MAX_FILE_LIMIT);
}
preg_match_all( '~<img.*?src=["\']+(.*?)["\']+.*>~' , $html, $match );
$imgTagArr = $match[0];
$imgSrcArr = $match[1];
$maxImgSize = config('system.lazy_load_size'); // 读取文件大小,大于 配置文件 做懒加载
$oldImgTagArr = [];
$newImgTagArr = [];
foreach ($imgSrcArr as $key => $value) {
// 没有需要懒加载的标签,跳过
if (strpos($imgTagArr[$key], 'lazy-img') === false) {
continue;
}
if (empty($value)) {
continue;
}
if (strpos($value, 'data:') === 0) {
continue;
}
if (strpos($value, 'http:') === 0) {
$fileUrl = $value;
$res = @get_headers($fileUrl,true);
if (!isset($res['Content-Length'])) {
continue;
}
$filesize = round($res['Content-Length']/1024,2);
}
else {
$publicPath = CMS_ROOT . 'public';
if (strpos($value, '/') !== 0) {
$publicPath .= '/';
}
$fileUrl = $publicPath . $value;
if (!file_exists($fileUrl)) {
continue;
}
$filesize = filesize($fileUrl);
$filesize /= pow(1024, 1);
}
if ($filesize > $maxImgSize) {
$imgTagArr[$key] = str_replace("data-src='{$value}'", '', $imgTagArr[$key]);
$imgTagReplace = str_replace($value, '/system_file/loading.png', $imgTagArr[$key]);
$replaceStr = " data-src='{$value}' ";
$imgTagReplace = substr_replace($imgTagReplace, $replaceStr, 4, 0);
$oldImgTagArr[] = $imgTagArr[$key];
$newImgTagArr[] = $imgTagReplace;
}
}
if (!empty($oldImgTagArr)) {
$html = str_replace($oldImgTagArr, $newImgTagArr, $html);
}
$jsStr = '
<script id="loadingJs" src="/system_file/js/huocms-loading.js"></script>
</head>';
if (strpos($html, '/system_file/js/huocms-loading.js') === false) {
$html = str_replace('</head>', $jsStr, $html);
}
// 去除图片展示的当前的域名
$imgStr = 'src="' . request()->header()['origin'];
$html = str_replace($imgStr, 'src="', $html);
// 去除动态添加所显示出的类名
$html = str_replace('<script id="baseJs" src="/system_file/js/base.min.js"></script>', '', $html);
// 去除swiper生成的类名、属性等
$html = str_replace('swiper-initialized swiper-horizontal swiper-backface-hidden', '', $html);
$html = str_replace('swiper-slide-prev', '', $html);
$html = str_replace('swiper-slide-active', '', $html);
$html = str_replace('swiper-slide-next', '', $html);
$html = str_replace('<span class="swiper-notification" aria-live="assertive" aria-atomic="true"></span>', '', $html);
$pattern = '/role=(\"|\')(.*?)>/i';
$replacement = '>';
$html = preg_replace($pattern, $replacement, $html);
$pattern = '/id=(\"|\')swiper-wrapper-(.*?)>/i';
$html = preg_replace($pattern, $replacement, $html);
$html = \phpQuery::newDocument($html);
// 根据section的顺序确定各个部分插入的顺序
$html['head #viewHelp']->remove();//移除可视化时用于方便界面编辑的css
$blockHtmlArr = [];
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang'],
'is_active' => 1
];
$Theme = new Theme();
$themeFileModel = new ThemeFile();
$theme = $Theme->getActiveTheme($where)['data']->toArray();
$themeName = $theme['theme'];
$BigField = new BigField();
$version = $BigField->where([
['seller_id', '=', $this->admin['seller_id']],
['theme_id', '=', $theme['id']],
])->max('version');
$version = $version ?: 0;
$version++;
$version = intval($version);
\phpQuery::each($html['body .huocms-block'], function ($key, $item) use ($html, &$blockHtmlArr, $param, $themeName, $saveType, $theme, $version) {
$domObj = $html['.huocms-block:eq('.$key.')'];
$includePath = $domObj->attr('data-inclue-path'); // 自己有包含路径或某个子元素有包含路径,需要将代码替换掉
$components = $domObj->find('.huocms-components');
foreach ($components as $obj) {
$subIncludePath = pq($obj)->attr('data-inclue-path');
if (!empty($subIncludePath)) {
if (pq($obj)->hasClass('huocms-static-edit')) {
$content = pq($obj)->htmlOuter();
$themeFileName = "{$subIncludePath}.html";
$filename = $subIncludePath;
ThemeService::saveThemeFileHistory($param['website_id'], $param['lang'], $theme, $this->admin['seller_id'], $themeFileName, $filename, $content, '', '', $version);
}
$includeHtml = '
{include file="'.$subIncludePath.'"}
';
$next = pq($obj)->next();
$parent = pq($obj)->parent();
if (empty($next->html())) {
pq($obj)->remove();
$parent->append($includeHtml);
} else {
pq($obj)->remove();
$next->before($includeHtml);
}
}
}
$blockHtml = '';
if (!empty($includePath)) {
if ($domObj->hasClass('huocms-static-edit')) {
$content = $domObj->htmlOuter();
$themeFileName = "{$includePath}.html";
$filename = $includePath;
ThemeService::saveThemeFileHistory($param['website_id'], $param['lang'], $theme, $this->admin['seller_id'], $themeFileName, $filename, $content, '', '', $version);
}
$domObj = '
{include file="'.$includePath.'"}
';
$blockHtml = $domObj;
$blockHtmlArr[] = $blockHtml;
return $item;
}
$tmpTemplate = $domObj->attr('data-huocms-block');
$blockId = $domObj->attr('data-huocms-blockid');
$blockType = $this->getBlockType($domObj);
// echo $blockType . '<br/>';
if (!empty($tmpTemplate) && !empty($blockId)) {
$blockTemplatePath = CMS_ROOT . $this->designBase . DIRECTORY_SEPARATOR . $tmpTemplate;
$blockHtml = file_get_contents($blockTemplatePath);
$blockHtml = $this->replaceHtml($blockType, $blockId, $blockHtml, $domObj);
} else {
$blockHtml = $domObj;
}
$blockHtmlArr[] = $blockHtml;
return $item;
});
$html['body .huocms-block']->remove();
$html['body #think_page_trace']->remove();
$html['body #think_page_trace_open']->remove();
$blockHtmlArr = array_reverse($blockHtmlArr);
foreach ($blockHtmlArr as $value) {
$html['body']->prepend($value);
}
// exit();
//保存生成的html
$pathInfo = pathinfo($param['file']);
$filename = $pathInfo['filename'];
$filePath = CMS_ROOT . "public/themes/website/{$param['website_id']}/{$param['lang']}/{$themeName}/{$filename}.html";
$viewFilePath = CMS_ROOT . "public/themes/hc_original/{$themeName}/{$filename}.html";
// 替换SEO
$html['head meta[name="description"]']->remove();
$html['head meta[name="keywords"]']->remove();
$html['head title']->remove();
$html['head']->prepend($this->getSeoHtml());
$themeFileName = "{$filename}.html";
// 保存至版本数据库中
$content = $html->html();
// 多个换行仅保留一个换行
$content = preg_replace("/(\r?\n[ \t]*){2,}/", "\n", $content);
ThemeService::saveThemeFileHistory($param['website_id'], $param['lang'], $theme, $this->admin['seller_id'], $themeFileName, $filename, $content, '', '', $version);
if ($saveType == 1) {
echo "保存成功 !";
return;
}
//更新theme_file
$themeService = new ThemeService();
$suffix = config('view.view_suffix');
$res = $themeService->publishThemeFile($theme['id'],$param['website_id'],$this->admin['seller_id'],$suffix, $version);
$res = $res->getData();
if ($res['code'] != 0) {
echo $res['msg'];
return;
}
$themeFileModel->updateThemeFile([
['file', '=', $themeFileName],
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
], ['is_design' => 1, 'design_path' => $themeFileName]);
echo "发布成功 !";
return;
}
protected function getBlockType($node) {
$classes = explode( ' ', $node->attr('class'));
$blockType = '';
foreach ($classes as $class) {
if ($class != 'huocms-components' && $class != 'huocms-block') {
$blockType = $class;
break;
}
}
return $blockType;
}
public function replaceHtml($blockType, $id, $html, $node)
{
if (strpos($blockType, 'block') !== false) {
// 替换模板里的navID
$blockHtml = str_replace('hcTaglib:category id="1"', 'hcTaglib:category id="' . $id . '"', $html);
} elseif ($blockType == 'huocms-nav') {
// 替换模板里的navID
$blockHtml = str_replace('hcTaglib:nav cid="2"', 'hcTaglib:nav cid="' . $id . '"', $html);
} elseif ($blockType == 'huocms-banner') {
// 替换模板里的navID
$blockHtml = str_replace('hcTaglib:slide cid="1"', 'hcTaglib:slide cid="' . $id . '"', $html);
} else {
$blockHtml = $node;
}
return $blockHtml;
}
public function getSeoHtml()
{
return '
<title>{$current_cate.seo_title|default=$current_cate.title}</title>
<meta name="description" content="{$current_cate.seo_description|default=$current_cate.title}">
<meta name="keywords" content="{$current_cate.seo_keywords|default=$current_cate.title}">';
}
// setting接口
public function getSetting()
{
}
/**
* 单个链接列表接口
* 基础链接:客服链接,icp备案链接,公安备案链接
* 栏目链接
* 内容链接
* @return Json
*/
public function getLinkList()
{
$param = $this->request->param();
// 数据验证
try {
validate(WebsiteSettingValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang'],
];
$websiteSetting = new WebsiteSetting();
$res = $websiteSetting->getWebsiteSetting($where);
$res['data'] = $res['data']->toArray();
$res['data']['setting'] = json_decode($res['data']['setting'], true);
$link = [
'name' => '基本链接',
'value' => '',
'child' => [
[
'name' => '客服链接',
'value' => $res['data']['setting']['customer_code'] ?? '',
],
[
'name' => 'icp备案链接',
'value' => $res['data']['setting']['icp_link'] ?? '',
],
[
'name' => '公网安备链接',
'value' => $res['data']['setting']['gwa_link'] ?? '',
],
]
];
$categoryList = $this->categoryList();
$cate = [
'name' => '栏目链接',
'value' => '',
'child' => $categoryList,
];
$data = [
'link' => $link,
'cate' => $cate,
'content' => [],
];
return jsonReturn(0, '成功', $data);
}
// 导航接口
public function getNavList()
{
}
// 友情链接接口
public function getFriendLink()
{
}
public function getCategoryList()
{
return jsonReturn(0, '成功', $this->categoryList());
}
public function categoryListSetWhere(&$where, $type)
{
switch ($type) {
case 'suq_block1':
case 'suq_block2_contact':
case 'suq_block3':
case 'suq_block4':
case 'suq_block5':
case 'suq_block6':
case 'suq_footer':
$where[] = ['type', 'in', [2,3]];
$where[] = ['id', '>', 1];
break;
case 'suq_block2':
$where[] = ['id', '>', 1];
break;
default:
break;
}
}
// 栏目列表接口
protected function categoryList()
{
$param = $this->request->param();
$where = [
['seller_id', '=', $this->admin['seller_id']],
['website_id', '=', $param['website_id']],
];
$lang = $param['lang'] ?? '';
if (empty($lang)) {
$lang = 'zh';
}
$Website = new Website();
$website = $Website->getWebsite(['id' => $param['website_id'], 'seller_id' => $this->admin['seller_id']])['data'];
$domain = $website['domain'];
if ($lang != 'zh') {
$domain = $domain . '/' . $lang;
}
$where[] = ['lang', '=', $lang];
if(isset($param['type'])) {
$this->categoryListSetWhere($where, $param['type']);
}
$cateModel = new Category();
$categoryList = $cateModel->where($where)->field('id,type,title,alias')->select()->each(function (&$item) use ($domain) {
if ($item['type'] == 1 || $item['type'] == 4) {
if (!empty($item['alias'])) {
if ($item['alias'] == '/') {
$item['fullUrl'] = 'http://' . $domain;
} else {
$item['fullUrl'] = 'http://' . $domain . $item['alias'] . '.' . config('route.url_html_suffix');
}
} else {
$item['fullUrl'] = 'http://' . $domain . '/list/index/' . $item['id'] . '.' . config('route.url_html_suffix');
}
} else if ($item['type'] == 3) {
$item['fullUrl'] = $item['alias'];
} else {
$item['fullUrl'] = 'javascript:;';
}
});
return $categoryList->toArray();
}
// 栏目内容接口
public function getCategoryData()
{
$param = $this->request->param();
$categoryModel = new Category();
$contentModel = new SubContent();
$category = [];
$subCategory = [];
//获取此栏目数据和下面所有子栏目数据,并且拿到所有栏目下的内容数据
if ($param['type'] == 'suq_block1') {
//获取选择栏目的的标题和副标题,再获取子栏目的名称和缩略图
//最后获取子栏目的内容列表
$category = $categoryModel->getCategory([
['id', '=', $param['category_id']],
['type', 'in', [2,3]],
], [], 'id, type, title, sub_title, alias')['data'];
$subCategory = $categoryModel->where([
['parent_id', '=', $param['category_id']],
['type', 'in', [2,3]],
])->with(['thumbnail'])->field('id, type, title, sub_title, desc, thumbnail, alias')->select();
foreach ($subCategory as &$subCate) {
$subCate['content'] = $contentModel->alias('a')
->join('category_sub_content b', 'b.sub_content_id = a.id', 'left')
->with(['thumbnail'])
->where([
['b.category_id', '=', $subCate['id']]
])
->field('a.id, title, thumbnail')
->select();
}
} else if ($param['type'] == 'suq_block2' ||
$param['type'] == 'suq_block3' ||
$param['type'] == 'suq_block4' ||
$param['type'] == 'suq_footer') {
$category = $categoryModel->getCategory([
['id', '=', $param['category_id']],
['type', 'in', [2,3]],
], ['thumbnail'], 'id, type, title, sub_title, desc, alias, thumbnail, description')['data'];
$contentList = $contentModel->alias('a')
->join('category_sub_content b', 'b.sub_content_id = a.id', 'left')
->with(['thumbnail'])
->where([
['b.category_id', '=', $param['category_id']]
])
->field('a.id, title, sub_title, description, thumbnail')
->select()->toArray();
foreach ($contentList as &$value) {
if (isset($value['thumbnail']['url'])) {
$value['thumbnail_url'] = $value['thumbnail']['url'];
}
if (in_array($category['type'], [1,2,4])) {
$value['href'] = hcUrl('detail/index', ['cid' => $param['category_id'], 'id' => $value['id']]);
} else {
$value['href'] = $category['alias'];
}
}
$category['content'] = $contentList;
} else if ($param['type'] == 'suq_block5' ||
$param['type'] == 'suq_block6' ||
$param['type'] == 'suq_block2_contact') {
$category = $categoryModel->getCategory([
['id', '=', $param['category_id']],
['type', 'in', [2,3]],
], ['thumbnail'], 'id, type, title, sub_title, desc, alias, thumbnail, description, seo_description')['data'];
}
$returnData = [
'category' => $category,
'subCategory' => $subCategory,
];
return jsonReturn(0, '成功', $returnData);
}
// 内容列表接口
public function getContentList()
{
}
// 内容详情接口
// 幻灯片接口
// 广告接口
// 获取模板文件历史版本
public function getHistoryList()
{
$param = $this->request->param();
$initPage = $param['init_page'] ?? 'index';
$initPageName = $initPage . '.html';
$param['limit'] = $param['limit'] ?? 100;
$themeModel = new Theme();
$themeId = $themeModel->where([
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
['is_active', '=', 1],
])->value('id');
if (empty($themeId)) {
return jsonReturn(-1, '当前站点没有激活的模板,请先去安装模板');
}
// 获取当前模板文件id
$themeFileModel = new ThemeFile();
$themeFileId = $themeFileModel->where([
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
['theme_id', '=', $themeId],
['file', '=', $initPageName],
])->value('id');
if (empty($themeFileId)) {
return jsonReturn(-2, '模板文件不存在');
}
$bigFieldModel = new BigField();
$list = $bigFieldModel->alias('a')
->join('admin b', 'b.id = a.admin_id', 'left')
->join('theme_file c', 'a.theme_file_id = c.id')
->where([
['a.theme_id', '=', $themeId],
['a.theme_file_id', '=', $themeFileId],
])->field('a.*, b.name as admin_name, c.file')->order('id desc')->paginate($param['limit']);
return json(pageReturn(dataReturn(0, '', $list)));
}
public function setPreviewPage()
{
$param = $this->request->param();
$initPage = $param['init_page'] ?? 'index';
$initPageName = $initPage . '.html';
$version = $param['version'] ?? 1; // 将此版本的所有文件都塞入view下
$themeModel = new Theme();
$theme = $themeModel->where([
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
['is_active', '=', 1],
])->field('id, theme')->find();
if (empty($theme['id'])) {
return jsonReturn(-1, '当前站点没有激活的模板,请先去安装模板');
}
ThemeService::updatePreviewFile($param, $version, $theme);
session('history-view', time());
return jsonReturn(0, '预览初始化成功');
}
}

27
HuoCMS_close_source/app/controller/backend/ExcelController.php

@ -0,0 +1,27 @@
<?php
namespace app\controller\backend;
use think\facade\Cache;
use think\response\Json;
class ExcelController
{
/**
* 下载
* @return array|Json
*/
public function downInquiryExcel()
{
$token = input('param.token');
$data = Cache::get( $token );
// Cache::delete($token);
if(!empty($data)){
return createDownloadExcel( $data['file_name'], $data['sheet_name'], $data['head'], $data['data'], $data['matched']);
}
return jsonReturn(-1,'已过期');
}
}

585
HuoCMS_close_source/app/controller/backend/FormController.php

@ -0,0 +1,585 @@
<?php
namespace app\controller\backend;
use app\model\DiyForm;
use Overtrue\Pinyin\Pinyin;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\facade\Cache;
use think\facade\Db;
class FormController extends BaseController
{
public function index(DiyForm $diyFormModel)
{
$limit = input('param.limit');
$name = input('param.name');
$where[] = ['is_del', '=', 1];
$where[] = ['seller_id', '=', $this->admin['seller_id']];
if (!empty($name)) {
$where[] = ['name', 'like', '%' . $name . '%'];
}
try {
$list = $diyFormModel->where($where)->order('id desc')->paginate($limit);
} catch (\Exception $e) {
return jsonReturn(-1, $e->getMessage());
}
return json(pageReturn(dataReturn(0, lang('成功'), $list)));
}
public function info(DiyForm $diyFormModel)
{
$id = $this->request->param('id');
$info = $diyFormModel->where('id', $id)->find();
if (empty($info)) {
return jsonReturn(-3, lang('该表单不存在'));
}
return jsonReturn(0, lang('获取成功'), $info);
}
public function add(DiyForm $diyFormModel)
{
$param = input('post.');
if (empty($param['name'])) {
return jsonReturn(-1, lang('请输入表单名称'));
}
try {
$has = $diyFormModel->where('name', $param['name'])->find();
if (!empty($has)) {
return jsonReturn(-3, lang('该表单已经存在'));
}
$pinyinModel = new Pinyin();
$tableName = $pinyinModel->abbr($param['name']);
$has = $diyFormModel->where('table', $tableName)->find();
if (!empty($has)) {
$tableName = $tableName . '_' . uniqid();
}
$param['seller_id'] = $this->admin['seller_id'];
$param['table'] = $tableName;
$param['code'] = uniqid(); // 表单唯一标识
$param['create_time'] = date('Y-m-d H:i:s');
$diyFormModel->insert($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
return jsonReturn(0, lang('添加成功'));
}
public function edit(DiyForm $diyFormModel)
{
$param = input('post.');
if (empty($param['name'])) {
return jsonReturn(-1, lang('请输入表单名称'));
}
try {
$has = $diyFormModel->where('name', $param['name'])->where('id', '<>', $param['id'])->find();
if (!empty($has)) {
return jsonReturn(-3, lang('该表单已经存在'));
}
$pinyinModel = new Pinyin();
$tableName = $pinyinModel->abbr($param['name']);
$has = $diyFormModel->where('table', $tableName)->where('id', '<>', $param['id'])->find();
if (!empty($has)) {
$tableName = $tableName . '_' . uniqid();
}
$param['table'] = $tableName;
$param['update_time'] = date('Y-m-d H:i:s');
$diyFormModel->where('id', $param['id'])->update($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
return jsonReturn(0, lang('编辑成功'));
}
public function del(DiyForm $diyFormModel)
{
$id = input('param.id');
try {
$info = $diyFormModel->where('id', $id)->find();
if ($info['status'] == 2) {
return jsonReturn(-1, lang('该表单已经发布,请先卸载'));
}
$diyFormModel->where('id', $id)->delete();
} catch (\Exception $e) {
return jsonReturn(-2, $e->getMessage());
}
return jsonReturn(0, lang('删除成功'));
}
public function detail(DiyForm $diyFormModel)
{
$param = input('param.');
try {
$info = $diyFormModel->where('id', $param['id'])->find();
$formJson = json_decode($info['design_content'], true);
$field2Dict = [];
$header = [];
foreach ($formJson as $vo) {
if (!isset($vo['field'])) {
continue;
}
$header[] = [
'label' => $vo['title'],
'property' => $vo['field'],
'type' => $vo['type'],
'options' => $vo['options'] ?? ''
];
// 为了方便字典翻译,优化前端显示
if (isset($vo['options'])) {
$dictDataMap = [];
foreach ($vo['options'] as $k => $v) {
$dictDataMap[$v['value']] = $v['label'];
}
$field2Dict[$vo['field']] = $dictDataMap;
}
if ($vo['type'] == 'switch') {
$dictDataMap = [];
$dictDataMap[$vo['props']['activeValue']] = $vo['props']['activeText'];
$dictDataMap[$vo['props']['inactiveValue']] = $vo['props']['inactiveText'];
$field2Dict[$vo['field']] = $dictDataMap;
}
}
$param['queryParams'] = json_decode($param['queryParams'], true);
if (!empty($param['queryParams']) &&
!empty($param['queryParams']['condition']) &&
!empty($param['queryParams']['childTips'])) {
$where = $this->buildWhere($param['queryParams']['childTips']);
if ($param['queryParams']['condition'] == 'and') {
$data = Db::table(makeFormTable($info['table']))->where($where)
->order('id', 'desc')->paginate($param['limit']);
} else if ($param['queryParams']['condition'] == 'or') {
$data = Db::table(makeFormTable($info['table']))->whereOr($where)
->order('id', 'desc')->paginate($param['limit']);
}
} else {
$data = Db::table(makeFormTable($info['table']))
->order('id', 'desc')->paginate($param['limit']);
}
$data = $data->each(function ($item) use ($field2Dict) {
foreach ($item as $key => $vo) {
if (isset($field2Dict[$key])) {
$showValueMap = [];
$valueMap = explode(',', $vo);
foreach ($valueMap as $valueKey) {
$showValueMap[] = isset($field2Dict[$key][$valueKey]) ? $field2Dict[$key][$valueKey] : $valueKey;
}
$item[$key] = implode(',', $showValueMap);
}
}
return $item;
});
} catch (\Exception $e) {
return jsonReturn(-3, $e->getMessage() . $e->getLine());
}
return jsonReturn(0, 'success', [
'header' => $header,
'data' => $data->getCollection(),
'total' => $data->total()
]);
}
public function deploy(DiyForm $diyFormModel)
{
$id = input('param.id');
$info = $diyFormModel->where('id', $id)->find();
if ($info['status'] == 2) {
return jsonReturn(-1, lang('该表单已经发布,无需再次发布'));
}
if (empty($info['design_content'])) {
return jsonReturn(-2, lang('请先完成表单设计'));
}
$tableName = makeFormTable($info['table']);
$title = $info['name'];
$column = '';
$columnMap = json_decode($info['design_content'], true);
foreach ($columnMap as $key => $vo) {
if (empty($vo['field'])) {
continue;
}
// 强迫症为了dd打印的时候格式对其,其实没啥意义
$tab = '';
if ($key > 0) {
$tab = ' ';
}
$column .= $tab . '`' . $vo['field'] . '` varchar(255) NULL DEFAULT NULL COMMENT "' . $vo['title'] . '",' . PHP_EOL;
}
try {
$sql = <<<EOL
CREATE TABLE `{$tableName}` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT "id",
{$column} `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT "创建时间",
`update_time` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT "更新时间",
`visitor_id` varchar(255) DEFAULT '' COMMENT '前端标识',
`sub_id` int(11) DEFAULT 0 COMMENT '关联内容id',
`ip` varchar(20) DEFAULT '',
`user_agent` varchar(255) DEFAULT '' COMMENT '浏览器标识',
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 COMMENT='{$title}';
EOL;
Db::execute($sql);
$diyFormModel->where('id', $id)->update([
'status' => 2,
'update_time' => date('Y-m-d H:i:s')
]);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
return jsonReturn(0, lang('部署成功'));
}
public function undeploy(DiyForm $diyFormModel)
{
$id = input('param.id');
$info = $diyFormModel->where('id', $id)->find();
if ($info['status'] != 2) {
return jsonReturn(-1, lang('该表单尚未发布,无法卸载'));
}
try {
Db::query('DROP TABLE IF EXISTS `' . makeFormTable($info['table']) . '`');
$diyFormModel->where('id', $id)->update([
'status' => 1,
'update_time' => date('Y-m-d H:i:s')
]);
} catch (\Exception $e) {
return jsonReturn(-1, $e->getMessage());
}
return jsonReturn(0, lang('卸载成功'));
}
// 获取问题和答案详情
public function quesDetail(DiyForm $diyFormModel)
{
$param = input('param.');
try {
$info = $diyFormModel->where('id', $param['id'])->find();
$formJson = json_decode($info['design_content'], true);
$field2Dict = [];
$header = [];
foreach ($formJson as $vo) {
if (!isset($vo['field'])) {
continue;
}
$header[$vo['field']] = [
'label' => $vo['title'],
'property' => $vo['field'],
'type' => $vo['type'],
'options' => []
];
if ($vo['type'] == 'switch') {
$header[$vo['field']]['options'][$vo['props']['activeValue']] = ['label' => $vo['props']['activeText']];
$header[$vo['field']]['options'][$vo['props']['inactiveValue']] = ['label' => $vo['props']['inactiveText']];
}
if (!empty($vo['options'])) {
foreach ($vo['options'] as $v) {
$header[$vo['field']]['options'][$v['value']] = $v;
}
}
}
$param['queryParams'] = json_decode($param['queryParams'], true);
if (!empty($param['queryParams']) &&
!empty($param['queryParams']['condition']) &&
!empty($param['queryParams']['childTips'])) {
$where = $this->buildWhere($param['queryParams']['childTips']);
if ($param['queryParams']['condition'] == 'and') {
$data = Db::table(makeFormTable($info['table']))->where($where)->select();
} else if ($param['queryParams']['condition'] == 'or') {
$data = Db::table(makeFormTable($info['table']))->whereOr($where)->select();
} else {
$data = [];
}
} else {
$data = Db::table(makeFormTable($info['table']))->select();
}
$newData = [];
$quesNum = 1;
foreach ($header as $key => $value) {
foreach ($data as $item) {
if (!isset($item[$key])) {
continue;
}
$newData[$key]['quesNum'] = $quesNum;
$newData[$key]['type'] = $value['type'];
$newData[$key]['ques'] = $value['label'];
if (!isset($newData[$key]['total'])) {
$newData[$key]['total'] = 0;
}
if ($value['type'] == 'input' || $value['type'] == 'timePicker' || $value['type'] == 'datePicker') {
$newData[$key]['type_name'] = '填空';
$newData[$key]['type'] = 'list';
// 填空题 ,填的才是答案,使用列表展示
$newData[$key]['total']++;
$newData[$key]['detail'][] = [
'id' => $item['id'],
'answer' => $item[$key],
];
} else if ($value['type'] == 'radio' || $value['type'] == 'select' || $value['type'] == 'switch') {
$newData[$key]['type_name'] = '单选';
$newData[$key]['type'] = 'radio';
// 单选题 使用饼图展示,需要计算百分比
$newData[$key]['total']++;
if (isset($newData[$key]['detail'][$item[$key]]['count'])) {
$newData[$key]['detail'][$item[$key]]['count']++;
} else {
$newData[$key]['detail'][$item[$key]]['answer'] = $value['options'][$item[$key]]['label'];
$newData[$key]['detail'][$item[$key]]['count'] = 1;
}
} else if ($value['type'] == 'slider' || $value['type'] == 'rate') {
$newData[$key]['type_name'] = '滑块/打分';
$newData[$key]['type'] = 'rate';
$newData[$key]['total']++;
if (isset($newData[$key]['detail'][$item[$key]]['count'])) {
$newData[$key]['detail'][$item[$key]]['count']++;
} else {
$newData[$key]['detail'][$item[$key]]['answer'] = $item[$key];
$newData[$key]['detail'][$item[$key]]['count'] = 1;
}
} else if ($value['type'] == 'checkbox') {
$newData[$key]['type_name'] = '多选';
// 多选题 默认使用柱状图,需要计算百分比
$answer = explode(',', $item[$key]);
foreach ($answer as $v) {
$newData[$key]['total']++;
if (isset($newData[$key]['detail'][$v]['count'])) {
$newData[$key]['detail'][$v]['count']++;
} else {
$newData[$key]['detail'][$v]['answer'] = $value['options'][$v]['label'];
$newData[$key]['detail'][$v]['count'] = 1;
}
}
}
}
$quesNum++;
}
// 整理成前端echart需要的数据
foreach ($newData as &$value) {
if ($value['type'] == 'list') {
continue;
}
$newDetail = [];
foreach ($value['detail'] as $v) {
$newDetail['data'][] = [
'name' => $v['answer'],
'value' => $v['count'],
];
$newDetail['nameArr'][] = $v['answer'];
$newDetail['valueArr'][] = $v['count'];
}
$value['detail'] = $newDetail;
}
// dd($newData);
} catch (\Exception $e) {
return jsonReturn(-3, $e->getMessage() . $e->getLine());
}
return jsonReturn(0, lang('成功'), [
'header' => array_values($header),
'data' => $newData,
'total' => count($newData),
]);
}
private function buildWhere($childTips)
{
$where = [];
foreach ($childTips as $vo) {
switch ($vo['rule']) {
case 'eq':
$where[] = [$vo['field'], '=', $vo['val']];
break;
case 'like':
$where[] = [$vo['field'], 'like', '%' . $vo['val'] . '%'];
break;
case 'left_like':
$where[] = [$vo['field'], 'like', '%' . $vo['val']];
break;
case 'right_like':
$where[] = [$vo['field'], 'like', $vo['val'] . '%'];
break;
case 'neq':
$where[] = [$vo['field'], '<>', $vo['val']];
break;
case 'gt':
$where[] = [$vo['field'], '>', $vo['val']];
break;
case 'gte':
$where[] = [$vo['field'], '>=', $vo['val']];
break;
break;
case 'lt':
$where[] = [$vo['field'], '<', $vo['val']];
break;
case 'lte':
$where[] = [$vo['field'], '<=', $vo['val']];
break;
}
}
return $where;
}
/**
* 表单下载
*/
public function exportForm()
{
$id = $this->request->param('id/d', 0);
$queryParams = $this->request->param('queryParams', '');
$queryParams = !empty($queryParams) ? json_decode($queryParams, true) : [];
//通过id找到表单的表名
$diyFormModel = new DiyForm();
$tableInfo = $diyFormModel->where([
'id' => $id,
'is_del' => 1,
'seller_id' => $this->admin['seller_id']
])->field('table,id')->find();
if (empty($tableInfo)) {
return jsonReturn(-1, '表单不存在');
}
$tableName = $tableInfo['table'];
$tableName = makeFormTable($tableName);
$tableStruct = Db::query("SHOW FULL COLUMNS FROM {$tableName}");
$columnList = $keys = $title = [];
foreach ($tableStruct as $struct) {
if (in_array($struct['Field'], ['id', 'sub_id'])) {
continue;
}
$title[] = $struct['Comment'];
$keys[] =$struct['Field'];
}
$list = [];
if (!empty($queryParams) &&
!empty($queryParams['condition']) &&
!empty($queryParams['childTips'])) {
$where = $this->buildWhere($queryParams['childTips']);
if ($queryParams['condition'] == 'and') {
$list = Db::table($tableName)->where($where)
->order('id', 'desc')->select();
} else if ($queryParams['condition'] == 'or') {
$list = Db::table($tableName)->whereOr($where)
->order('id', 'desc')->select();
}
} else {
$list = Db::table($tableName)
->order('id', 'desc')->select();
}
$spreadsheet = new Spreadsheet();
$activeWorksheet = $spreadsheet->getActiveSheet();
$total = count($keys);
for ($i = 0; $i < $total; $i++) {
$column = getSheetColLabel($i + 1);
$cell = $column . '1';
$columnList[] = $column;
$activeWorksheet->setCellValue($cell, $title[$i]);
}
foreach ($list as $k => $v) {
for ($x = 0; $x < $total; $x++) {
$activeWorksheet->setCellValue($columnList[$x] . ($k + 2), $v[$keys[$x]]);
}
}
if(!file_exists('excel')){
mkdir("excel",0777,true);
}
$writer = new Xlsx($spreadsheet);
$filename = 'form'.date("YmdHis").'.xlsx';
$writer->save("./excel/".$filename);
return jsonReturn(0, '成功', ['url' => '/excel/'.$filename]);
}
}

14
HuoCMS_close_source/app/controller/backend/GoogleStatisticsController.php

@ -0,0 +1,14 @@
<?php
namespace app\controller\backend;
use app\service\GoogleRequest;
class GoogleStatisticsController extends \app\BaseController
{
public function read() {
$googleStatistics = new GoogleRequest();
$googleStatistics->start();
}
}

154
HuoCMS_close_source/app/controller/backend/InnerChartController.php

@ -0,0 +1,154 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelException;
use app\model\InnerChart;
use app\validate\InnerChartValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class InnerChartController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(InnerChart $innerChart): \think\response\Json
{
$limit = $this->setLimit();
$type = input('type');
$siteId = (int)input('website_id');
if(empty($type)){
$type = 1;
}
$where = [
['seller_id' ,'=', $this->admin['seller_id']],
['type' ,'=', $type],
];
if ($type != 2) {
$where[] = ['website_id','=',$siteId];
}
$keyword = input('keyword');
if($keyword){
$where[] = ['keyword','like','%'.$keyword.'%'];
}
try{
$innerList = $innerChart->where($where)->order('id','desc')->paginate($limit)->each(function(&$item){
$count = (int)$item->content()->sum('total');
$item -> count = $count;
$item -> save();
});
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return json(['code'=>0,'total'=>$innerList->total(),'msg'=>'success','data'=>$innerList->all()]);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(InnerChart $innerChart): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
if(empty($param['website_id'])){
$param['website_id'] = 0;
}
// 数据验证
try{
validate(InnerChartValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$res = $innerChart -> addInnerChart($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(InnerChart $innerChart): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('内链ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $innerChart->getInnerChart($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(InnerChart $innerChart): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(InnerChartValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if(empty($param['website_id'])){
$param['website_id'] = 0;
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $innerChart -> updateInnerChart($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(InnerChart $innerChart): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('内链ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $innerChart->delInnerChart($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

130
HuoCMS_close_source/app/controller/backend/InquiryCategoryController.php

@ -0,0 +1,130 @@
<?php
namespace app\controller\backend;
use \app\validate\InquiryCategoryValidate;
use app\model\InquiryCategory;
use think\exception\ValidateException;
use \think\response\Json;
class InquiryCategoryController extends BaseController
{
/**
* 获取线索列表,可按条件查询
* @return Json
*/
public function index(): Json
{
if (request()->isGet()) {
$param['seller_id'] = $this->admin['seller_id'];
$inquiryCategory = new InquiryCategory();
$res = $inquiryCategory->getInquiryCategoryList($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 询单类别查询
* @return Json
*/
public function read(): Json
{
if (request()->isGet()) {
$param = input('get.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryCategoryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$inquiryCategory = new InquiryCategory();
$res = $inquiryCategory->getInquiryCategory($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 新增询单类别
* @return Json
*/
public function save(): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryCategoryValidate::class)->scene('save')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$inquiryCategory = new InquiryCategory();
$res = $inquiryCategory->addInquiryCategory($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 更新询单类别
* @return Json
*/
public function update(): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryCategoryValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$inquiryCategory = new InquiryCategory();
$res = $inquiryCategory->updateInquiryCategory($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 删除询单类别
* @return Json
*/
public function delete(): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryCategoryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$inquiryCategory = new InquiryCategory();
$res = $inquiryCategory->deleteInquiryCategory($param);
return jsonReturn($res['code'], $res['msg']);
}
return jsonReturn(-2, lang('请求方法错误'));
}
}

231
HuoCMS_close_source/app/controller/backend/InquiryController.php

@ -0,0 +1,231 @@
<?php
namespace app\controller\backend;
use app\model\Inquiry;
use app\model\RecycleBin;
use app\validate\InquiryValidate;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Lang;
use think\response\Json;
class InquiryController extends BaseController {
/**
* 查询询单列表
* @return Json
*/
public function index(): Json
{
if (request()->isGet()) {
$siteId = (int)input('website_id');
if(empty($siteId)){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
'is_del' => 1,
];
$limit = $this->setLimit();
$inquiry = new Inquiry();
$res = $inquiry->getInquiryList($where,'*', $limit);
return json(pageReturn($res));
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 新增询单信息
* @return Json
* @method Post
*/
public function backendSave(): Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
if (empty($param['phone']) && empty($param['wechat']) && empty($param['email']) && empty($param['qq']) && empty($param['telphone'])) {
return jsonReturn(-4, lang('联系方式必须填写一个'));
}
try {
validate(InquiryValidate::class)->scene('save')->check($param);
} catch (ValidateException $e){
return jsonReturn(-4, $e->getMessage());
}
$inquiry = new Inquiry();
$res = $inquiry -> addInquiry($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 询单信息查询
* @return Json
* @method Post
*/
public function read(): Json
{
if (request()->isGet()) {
$param = input('get.');
try {
validate(InquiryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e){
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
$inquiry = new Inquiry();
$res = $inquiry->getInquiry($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 更新询单信息
* @return Json
* @method Post
*/
public function update(): Json
{
if(request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
if (empty($param['mobile']) && empty($param['wechat']) && empty($param['email']) && empty($param['qq'])) {
return jsonReturn(-4, lang('联系方式必须填写一个'));
}
try {
validate(InquiryValidate::class)->scene('update')->check($param);
} catch (ValidateException $e){
return jsonReturn(-4, $e->getMessage());
}
$inquiry = new Inquiry();
$res = $inquiry->updateInquiry($param);
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* 删除询单信息
* @return Json
* @throws \app\exception\ModelException
*/
public function delete(): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryValidate::class)->scene('read')->check($param);
} catch (ValidateException $e){
return jsonReturn(-4, $e->getMessage());
}
$Inquiry = new Inquiry();
$inquiry = $Inquiry->getInquiry($param)['data'];
if(empty($inquiry)){
jsonReturn(-3, lang('询盘不存在'));
}
// 复制删除内容到回收站表
$recycleBin = new RecycleBin();
$binData = [
'seller_id' => $param['seller_id'],
'object_id' => $inquiry['id'],
'sub_id' => 0,
'module_id' => 0,
'table_name' => lang('询盘'),
'title' => !empty($inquiry['title']) ? $inquiry['title'] : lang('询盘内容') . $inquiry['id'],
'admin_id' => $this->admin['uid'],
'name' => $this->admin['name'],
];
$recycleBin -> addRecycleBin($binData);
$inquiry->is_del = 2;
$inquiry->delete_time = time();
$inquiry->save();
return jsonReturn(0, lang('删除成功'));
}
return jsonReturn(-2, lang('请求方法错误'));
}
public function batch_delete(): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(InquiryValidate::class)->scene('batch')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$where = [
['seller_id' ,'=', $this->admin['seller_id']],
['ids','in', $param['ids']],
];
$linkWebsite = new Inquiry();
$res = $linkWebsite->batchDeleteInquiry($where);
return jsonReturn($res['code'], $res['msg']);
}
return jsonReturn(-1, lang('请求方法错误'));
}
/**
* 导出询盘的内容
* @return
*/
public function exportInquiry()
{
if(!file_exists('excel')){
mkdir("excel",0777,true);
}
$Inquiry = new Inquiry();
$siteId = $this->request->param("website_id/d",0);
$list = $Inquiry->where(['is_del'=>1,'website_id'=>$siteId])->alias('i')->join("inquiry_category ic",'ic.id = i.inquiry_type','left')
->column('i.*,ic.name cate_name');
$title = [
'公司名称', '联系人姓名', '询盘内容', '固定电话', "号码", '邮箱', 'qq', '询盘类型', '公司地址', '企业网址', '询盘来源', '来源网址', 'ip', '预算金额', '需求说明',
];
$keys = ['company_name', 'contacts_name' , 'content', 'telphone', 'phone', 'email', 'qq', 'cate_name',
'company_address', 'company_site', 'referer', 'referer_web', 'ip', 'expect_amount', 'explain'];
$columnList = [];
$spreadsheet = new Spreadsheet();
$activeWorksheet = $spreadsheet->getActiveSheet();
$total = count($title);
for ($i=0;$i<$total;$i++){
$column = getSheetColLabel($i + 1);
$cell = $column . '1';
$columnList[] = $column;
$activeWorksheet->setCellValue($cell, $title[$i]);
}
foreach ($list as $k=>$v){
for ($x=0;$x<$total;$x++){
$activeWorksheet->setCellValue($columnList[$x] . ($k + 2),$v[$keys[$x]]);
}
}
$writer = new Xlsx($spreadsheet);
$filename = '询盘导出'.date("YmdHis").'.xlsx';
$writer->save("./excel/".$filename);
return jsonReturn(0, '成功', ['url' => '/excel/'.$filename]);
}
}

152
HuoCMS_close_source/app/controller/backend/InquiryEmailController.php

@ -0,0 +1,152 @@
<?php
namespace app\controller\backend;
use app\model\InquiryEmail;
use app\model\WebsiteInquiryEmail;
use app\validate\InquiryEmailValidate;
use think\facade\Db;
use think\facade\Lang;
use \think\response\Json;
class InquiryEmailController extends BaseController
{
/**
* @param InquiryEmail $InquiryEmail
* @return Json
* @throws \think\db\exception\DbException
*/
public function index (InquiryEmail $InquiryEmail): Json
{
if (request()->isGet()) {
$siteId = (int)input('website_id');
if(!$siteId){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$limit = $this->setLimit();
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
];
$WebsiteInquiryEmail = new WebsiteInquiryEmail();
$ids = $WebsiteInquiryEmail->where($where)->column('inquiry_email_id');
if(empty($ids)){
return json(['code' => 0, 'msg' => 'ok', 'count' => 0, 'data' => []]);
}
$emailWhere = [
['seller_id','=',$this->admin['seller_id']],
['id','in',$ids]
];
$inquiryEmail = $InquiryEmail -> where($emailWhere)->paginate($limit)->each(function(&$item)use($WebsiteInquiryEmail){
$ids = $WebsiteInquiryEmail->where($where = [
'seller_id' => $this->admin['seller_id'],
'inquiry_email_id' => $item['id'],
])->column('website_id');
$item['website_id'] = $ids;
});
return json(['code' => 0, 'msg' => 'ok', 'count' => $inquiryEmail->total(), 'data' => $inquiryEmail->all()]);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* @return Json
*/
public function save(InquiryEmail $InquiryEmail): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(InquiryEmailValidate::class)->scene('save')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
$siteIds = $param['website_id'];
unset($param['website_id']);
Db::startTrans();
try{
$res = $InquiryEmail -> addInquiryEmail($param);
$inquiryEmail = $res['data'];
$inquiryEmail->website()->attach($siteIds,['seller_id'=>$param['seller_id']]);
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(0,lang('系统错误请重试'));
}
return json($res);
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* @return Json
*/
public function update(InquiryEmail $InquiryEmail): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(InquiryEmailValidate::class)->scene('update')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
Db::startTrans();
try{
$param['seller_id'] = $this->admin['seller_id'];
$inquiryEmail = $InquiryEmail->getInquiryEmail(['id'=>$param['id'],'seller_id'=>$param['seller_id']])['data'];
$inquiryEmail->website()->detach();
$inquiryEmail->website()->attach($param['website_id'],['seller_id'=>$param['seller_id']]);
$inquiryEmail->email = $param['email'];
if(isset($param['email'])){
$inquiryEmail->status = $param['status'];
}
$inquiryEmail->save();
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(-1,lang('系统错误请重试'));
}
return jsonReturn(0,lang('保存成功'));
}
return jsonReturn(-2, lang('请求方法错误'));
}
/**
* @return Json
*/
public function delete(InquiryEmail $InquiryEmail): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(InquiryEmailValidate::class)->scene('read')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
Db::startTrans();
try{
$inquiryEmail = $InquiryEmail->getInquiryEmail(['id'=>$param['id'],'seller_id'=>$param['seller_id']])['data'];
$inquiryEmail->website()->detach();
$inquiryEmail->delete();
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(0,lang('系统错误请重试'));
}
return jsonReturn(0, lang('删除成功'));
}
return jsonReturn(-2, lang('请求方法错误'));
}
}

153
HuoCMS_close_source/app/controller/backend/JobCateController.php

@ -0,0 +1,153 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Job;
use app\model\JobCate;
use app\validate\JobCateValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class JobCateController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(JobCate $jobCate): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
$jobCateList = $jobCate->getJobCateList($where,$limit);
return json(pageReturn($jobCateList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(JobCate $jobCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(JobCateValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $jobCate -> addJobCate($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(JobCate $jobCate): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $jobCate->getJobCate($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(JobCate $jobCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(JobCateValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = $jobCate -> updateJobCate($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(JobCate $jobCate, Job $job): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
$seller_id = $this->admin['seller_id'];
if(!$id){
// TODO 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
// TODO 分类使用判断
$job_where = [
'job_cate_id' => $id,
'seller_id' => $seller_id,
];
$has = $job->getJob($job_where);
if ($has['code'] == 0) {
return jsonReturn(-3, lang('工作类别在使用中'));
} else {
$where = [
'id' => $id,
'seller_id' => $seller_id,
];
$res = $jobCate->softDelJobCate($where);
return json($res);
}
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

154
HuoCMS_close_source/app/controller/backend/JobCityController.php

@ -0,0 +1,154 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Job;
use app\model\JobCity;
use app\validate\JobCityValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class JobCityController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(JobCity $jobCity): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
$jobCityList = $jobCity->getJobCityList($where,$limit);
return json(pageReturn($jobCityList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(JobCity $jobCity): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(JobCityValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $jobCity -> addJobCity($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(JobCity $jobCity): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $jobCity->getJobCity($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(JobCity $jobCity): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(JobCityValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$res = $jobCity -> updateJobCity($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(JobCity $jobCity, Job $job): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
$seller_id = $this->admin['seller_id'];
if(!$id){
// TO DO
// 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
// TODO 分类使用判断
$job_where = [
'job_city_id' => $id,
'seller_id' => $seller_id,
];
$has = $job->getJob($job_where);
if ($has['code'] == 0) {
return jsonReturn(-3, lang('工作类别在使用中'));
} else {
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $jobCity->softDelJobCity($where);
return json($res);
}
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

164
HuoCMS_close_source/app/controller/backend/JobController.php

@ -0,0 +1,164 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelEmptyException;
use app\exception\ModelException;
use app\model\Job;
use app\model\JobCate;
use app\model\JobCity;
use app\model\Website;
use app\validate\JobValidate;
use think\exception\ValidateException;
use think\facade\Lang;
use think\response\Json;
class JobController extends BaseController
{
/**
* 显示资源列表
*
* @return Json
* @throws ModelException
*/
public function index(Job $job): Json
{
$seller_id = $this->admin['seller_id'];
$job_city_id = input('job_city_id');
$job_cate_id = input('job_cate_id');
$title = input('title');
$where = [
'seller_id' => $seller_id,
'is_del' => 1,
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
if (!empty($job_city_id)) {
$where['job_city_id'] = $job_city_id;
}
if (!empty($job_cate_id)) {
$where['job_cate_id'] = $job_cate_id;
}
if (!empty($title)) {
// 模糊查询
$jobList = $job->searchJob($where,$title, $limit);
} else {
$jobList = $job->getJobList($where,$limit);
}
return json(pageReturn($jobList));
}
/**
* 保存新建的资源
*
* @return Json
* @throws ModelException
*/
public function save(Job $job): Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(JobValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$res = $job -> addJob($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return Json
* @throws ModelException
* @throws ModelEmptyException
*/
public function read(Job $job): Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('不能为空'));
}
$siteId = (int)input('website_id');
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
];
$jobRes = $job->getJob($where,['jobCity','jobCity'])['data']->toArray();
return jsonReturn(0, lang('查询成功'), $jobRes);
}
/**
* 保存更新的资源
* @return Json
* @throws ModelException
*/
public function update(Job $job): Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(JobValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
'website_id' => $param['website_id']
];
$res = $job -> updateJob($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws ModelException
*/
public function delete(Job $job): Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('职位ID不能为空'));
}
$siteId = (int)input('website_id');
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
];
$res = $job->delJob($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

356
HuoCMS_close_source/app/controller/backend/KeywordController.php

@ -0,0 +1,356 @@
<?php
namespace app\controller\backend;
use app\model\Keyword;
use app\model\KeywordQuery;
use app\model\Website;
use app\service\ExcelService;
use app\service\KeywordService;
use app\service\MonitorService;
use app\validate\KeywordValidate;
use think\exception\ValidateException;
use think\facade\Lang;
use think\response\Json;
class KeywordController extends BaseController
{
public $header = ['关键词名称','关键词链接','关键词位置','关键词状态'];
public $map = ['name','url','position','status'];
/**
* 读取数据列表
* @return Json
* @method Post
* @error_number 0: 成功, -1: 数据库查询失败, -2: 请求方法错误, -3: 数据重复, -4:数据缺少或校验不通过,
*/
public function index(Keyword $Keyword): Json
{
if (request()->isGet()) {
$websiteId = (int)input('website_id', '', 'trim');
if(!$websiteId){
return jsonReturn(-1,Lang::get('站点不能为空'));
}
$where = [
'website_id' => $websiteId,
'seller_id' => $this->admin['seller_id'],
];
$limit = $this->setLimit();
$res = $Keyword->getKeywordList($where, $limit,'id,website_id,name,url,position,sort,baidu_pc,baidu_mob,three_pc,sougou_mob,status',['website']);
return json(pageReturn($res));
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 读取数据
* @return Json
*/
public function read(Keyword $Keyword)
{
if (request()->isGet()) {
$param = input('get.');
try {
validate(KeywordValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
$res = $Keyword->getKeyword($param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 保存
* @param Keyword $Keyword
* @return Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(Keyword $Keyword): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(KeywordValidate::class)->scene('save')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
$uniqueWhere = [
'website_id' => $param['website_id'],
'name' => $param['name'],
'url' => $param['url']
];
$Keyword->saveUnique($uniqueWhere,Lang::get('关键词已经存在'));
$res = $Keyword->addKeyword($param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 编辑
* @param Keyword $Keyword
* @return Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function update(Keyword $Keyword): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(KeywordValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$uniqueWhere = [
'website_id' => $param['website_id'],
'name' => $param['name'],
'url' => $param['url']
];
$Keyword->updateUnique($uniqueWhere,$param['id'],Lang::get('关键词已经存在'));
$updateWhere = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
$res = $Keyword->updateKeyword($updateWhere,$param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 删除数据
* @return Json
*/
public function delete(Keyword $Keyword): Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(KeywordValidate::class)->scene('delete')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
if(empty($param['keyword_id'])){
jsonReturn(0, lang('删除成功'));
}else{
if(count($param['keyword_id'])){
$where = [
'id' => $param['keyword_id'][0],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id']
];
}else{
$where = [
['id' , 'in',$param['keyword_id']],
['seller_id' ,'=', $param['seller_id']],
['website_id', '=', $param['website_id']]
];
}
$res = $Keyword->deleteKeyword($where);
return json($res);
}
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 导入关键词
* @param ExcelService $excelService
* @param Keyword $Keyword
* @return Json
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
*/
public function import(ExcelService $excelService,Keyword $Keyword): Json
{
$param = input('post.');
$param['file'] = request()->file('file');
try {
validate(KeywordValidate::class)->scene('import')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$data = $excelService->readData($param['file']);
if(empty($data)){
return jsonReturn(-1,Lang::get('数据读取失败或者文件加为空,请检查'));
}
$data = $this->checkData($data);
if(isset($data['code'])){
return json($data);
}
$data = $this->dealWithData($data,$param['website_id']);
$res = $Keyword->addAllCustomData($data);
return json($res);
}
/**
* @param $data
* @return array
*/
public function checkData($data): array
{
$header = array_shift($data);
if(count($header) != 4){
return dataReturn(-2,Lang::get('数据格式错误,请参考样例'));
}
$i = 0;
foreach($header as $value){
if($value != $this->header[$i]){
return dataReturn(-3,Lang::get('数据格式错误,请参考样例'));
}
$i++;
}
return $data;
}
/**
* @param $data
* @param $siteId
* @return array
*/
public function dealWithData($data,$siteId): array
{
$tmpData = [];
foreach($data as $val){
if(!empty($val)){
$tmp = ['website_id' => $siteId];
$tmp['seller_id'] = $this->admin['seller_id'];
$i = 0;
foreach($val as $vv){
if($i == 0 && empty($vv)){
break;
}
if($i == 3){
if($vv == '正常'){
$vv = 1;
}else{
$vv = 2;
}
}
$tmp[$this->map[$i]] = $vv;
if($i == 3){
array_push($tmpData,$tmp);
}
$i++;
}
}
}
return $tmpData;
}
/**
* 关键词模版
* @return Json
*/
public function template(): Json
{
return jsonReturn(0,'success',config('system.keyword_template_path'));
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function monitor(MonitorService $monitorService): Json
{
$param = input('get.');
try {
validate(KeywordValidate::class)->scene('monitor')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
return $monitorService->getMonitorData($param);
}
public function echarts()
{
$param = $this->request->param();
try {
validate(KeywordValidate::class)->scene('echarts')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$keywordQueryModel = new KeywordQuery();
$startTime = time() - ($param['days'] * 86400);
$list = $keywordQueryModel->where('create_time', '>=', $startTime)
->where('search_engine', $param['search_engine'])
->where('keyword_id', $param['id'])->select();
$list = $list ? $list->toArray() : [];
$days = [];
$values = [];
foreach ($list as $value) {
$days[] = $value['create_time'];
$values[] = $value['top_rank'];
}
$data = [
'days' => array_values($days),
'values' => $values,
];
return jsonReturn(0, 'success', $data);
}
// 单个更新排名
public function updateRank()
{
$param = $this->request->param();
try {
validate(KeywordValidate::class)->scene('updateRank')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$token = KeywordService::getChinaZToken($this->admin['seller_id']);
$keywordModel = new Keyword();
$keywordData = $keywordModel->where([
['id', '=', $param['id']]
])->findOrEmpty();
if (!isset($keywordData['name'])) {
return jsonReturn(-2, Lang::get('关键词不存在!'));
}
switch ($param['search_engine']) {
case 'baidu_pc' :
KeywordService::baiduPcRank($token, $keywordData);
break;
case 'baidu_mob':
KeywordService::baiduMobileRank($token, $keywordData);
break;
case 'three_pc':
KeywordService::pc360Rank($token, $keywordData);
break;
case 'sougou_mob':
KeywordService::sougouMobileRank($token, $keywordData);
break;
default:
return jsonReturn(-3, Lang::get('搜索引擎不存在'));
break;
}
return jsonReturn(0, Lang::get('执行成功!'));
}
}

91
HuoCMS_close_source/app/controller/backend/KeywordQueryController.php

@ -0,0 +1,91 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\KeywordQuery;
use app\service\MonitorService;
use app\validate\KeywordQueryValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class KeywordQueryController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(MonitorService $monitorService): \think\response\Json
{
$param = input('get.');
try {
validate(KeywordQueryValidate::class)->scene('monitor')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
return $monitorService->keywordMonitor($param);
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(KeywordQuery $keywordQuery): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('关键词ID'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $keywordQuery->getKeywordQuery($where);
return json($res);
}
public function save(KeywordQuery $keywordQuery)
{
$param = input('keywordmonitor');
foreach ( $param as &$val) {
$val['ranks'] = json_encode($val['ranks']);
}
unset($val);
$res = $keywordQuery->saveAll($param);
dd($res);
}
//获取关键词查询列表
public function list()
{
$param = $this->request->param();
$param['limit'] = $param['limit'] ?? 10;
if (empty($param['keyword_id']) || empty($param['engine'])) {
return jsonReturn(-1, Lang::get('参数错误'));
}
$keywordQueryModel = new KeywordQuery();
$list = $keywordQueryModel->getKeywordQueryList([
['keyword_id', '=', $param['keyword_id']],
['search_engine', '=', $param['engine']]
], intval($param['limit']));
return json(pageReturn($list));
}
}

129
HuoCMS_close_source/app/controller/backend/KeywordWebsiteController.php

@ -0,0 +1,129 @@
<?php
namespace app\controller\backend;
use app\model\KeywordWebsite;
use app\validate\KeywordWebsiteValidate;
use think\exception\ValidateException;
use think\facade\Lang;
use think\response\Json;
class KeywordWebsiteController extends BaseController
{
/**
* 读取数据列表
* @return Json
* @method Post
* @error_number 0: 成功, -1: 数据库查询失败, -2: 请求方法错误, -3: 数据重复, -4:数据缺少或校验不通过,
*/
public function index(): Json
{
if (\request()->isGet()) {
$param = input('get.');
$param['seller_id'] = $this->admin['seller_id'];
$keyword = new KeywordWebsite();
$res = $keyword->getKeywordWebsiteList($param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 读取数据
* @return Json
*/
public function read()
{
if (request()->isGet()) {
$param = input('get.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(KeywordWebsiteValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$KeywordWebsite = new KeywordWebsite();
$res = $KeywordWebsite->getKeywordWebsite($param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 存入数据
* @return Json
*/
public function save()
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(KeywordWebsiteValidate::class)->scene('save')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$KeywordWebsite = new KeywordWebsite();
$res = $KeywordWebsite->addKeywordWebsite($param);
return jsonReturn($res['code'], $res['msg'], $res['data']);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 更新数据
* @return Json
*/
public function update(): Json
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(KeywordWebsiteValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$KeywordWebsite = new KeywordWebsite();
$res = $KeywordWebsite->updateKeywordWebsite($param);
return jsonReturn($res['code'], $res['msg']);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 删除数据
* @return Json
*/
public function delete()
{
if (request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(KeywordWebsiteValidate::class)->scene('read')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-4, $e->getMessage());
}
$KeywordWebsite = new KeywordWebsite();
$res = $KeywordWebsite->deleteKeywordWebsite($param);
return jsonReturn($res['code'], $res['msg']);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
}

255
HuoCMS_close_source/app/controller/backend/LinkController.php

@ -0,0 +1,255 @@
<?php
namespace app\controller\backend;
use app\exception\ModelEmptyException;
use app\exception\ModelException;
use app\model\Link;
use app\model\LinkWebsite;
use app\model\Model;
use app\model\RecycleBin;
use app\service\CacheService;
use app\validate\LinkValidate;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Lang;
use think\response\Json;
class LinkController extends BaseController
{
/**
* 友情链接列表
* @key id, seller_id
* @return Json
* @throws \app\exception\ModelException
*/
public function index(Link $link): Json
{
if(request()->isGet()) {
$param = input('get.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(LinkValidate::class)->scene('index')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$where = [
'website_id' => $param['website_id'],
'seller_id' => $param['seller_id'],
'type' => $param['type'],
'is_del' => 1
];
$limit = $this->setLimit();
// 翻页数据
$res = $link->getLinkList($where,$limit);
$data = pageReturn($res);
// 统计数据
$total = $data['count'];
$changeNum = 0;
if($total){
$now = mktime(0,0,0,date('m'),1,date('Y'));
// 上月总数
$lastMonthNum = $link->where($where)->whereTime('create_time','<',$now)->count();
$changeNum = $total - $lastMonthNum;
}
$data['change'] = $changeNum;
return json($data);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 读取单条友情链接信息
* @return Json
*/
public function read(Link $link): Json
{
if (request()->isGet()) {
$param = input('get.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(LinkValidate::class)->scene('read')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['is_del'] = 1;
$res = $link->getLink($param);
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 新增友情链接
* @return Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(Link $link): Json
{
if(request()->isPost()) {
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
try {
validate(LinkValidate::class)->scene('save')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
if(isset($param['add_time']) && empty($param['add_time'])){
unset($param['add_time']);
}
if(isset($param['end_time']) && empty($param['end_time'])){
unset($param['end_time']);
}
$link->saveUnique(['seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'type'=>$param['type'],'name'=>$param['name'],'is_del'=>1],'友情链接已经存在');
$res = $link->addLink($param);
CacheService::deleteCacheList('Link_cache_list');
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 更新友情链接信息
* @return Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function update(Link $link): Json
{
if (request()->isPost())
{
$param = input('post.');
try {
validate(LinkValidate::class)->scene('update')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
if(isset($param['add_time']) && empty($param['add_time'])){
unset($param['add_time']);
}
if(isset($param['end_time']) && empty($param['end_time'])){
unset($param['end_time']);
}
$link->updateUnique([
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'type' => $param['type'],
'name' => $param['name'],
],$param['id'],lang('友情链接名称已存在'));
$link->updateUnique([
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'type' => $param['type'],
'url' => $param['url'],
],$param['id'],lang('友情链接地址已存在'));
$res = $link->updateLink($where,$param);
CacheService::deleteCacheList('Link_cache_list');
return json($res);
}
return jsonReturn(-2, Lang::get('请求方法错误'));
}
/**
* 删除友情链接信息
* @return Json
* @throws ModelException
*/
public function delete(Link $link,RecycleBin $recycleBin): Json
{
if (!request()->isPost()) {
return jsonReturn(-2, Lang::get('请求方法错误'));
}
$param = input('post.');
try {
validate(LinkValidate::class)->scene('read')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
$param['seller_id'] = $this->admin['seller_id'];
$where = [
'id' => $param['id'],
'seller_id' => $param['seller_id'],
'website_id' => $param['website_id'],
'is_del' => 1,
];
Db::startTrans();
try{
$res = $link->softDelLink($where);
CacheService::deleteCacheList('Link_cache_list');
if($res['data'] == 1){
$binData = [
'object_id' => $param['id'],
'table_name' => 'link',
'title' => "友情链接{$param['id']}",
'admin_id' => $this->admin['uid'],
'name' => $this->admin['name'],
];
$recycleBin->addRecycleBin($binData);
}
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(-3,$e->getMessage());
}
return json($res);
}
/**
* @throws ModelException
*/
public function copy(Link $link): Json
{
if(!request()->isPost()){
return jsonReturn(-1, Lang::get('请求方法错误'));
}
$param = input('post.');
try {
validate(LinkValidate::class)->scene('copy')->check($param);
} catch (\Exception $e) {
return jsonReturn(-4, $e->getMessage());
}
if($param['website_id'] == $param['copy_site_id']){
return jsonReturn(-5, lang('目标网站ID和复制网站ID不能相等'));
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['copy_site_id'],
'is_del' => 1,
];
$selfWhere = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'is_del' => 1,
];
$field = ['name','url','sort','target','is_del'];
$linkList = $link->getAllLink($where,$field)['data']->toArray();
$selfList = $link->getAllLink($selfWhere,$field)['data']->toArray();
$flag = array_column($selfList,'name');
if(!empty($linkList)){
foreach($linkList as $key => &$val){
$val['website_id'] = $param['website_id'];
if(in_array($val['name'],$flag)){
unset($linkList[$key]);
}
}
unset($val);
$res = json($link->addAllLink($linkList));
}else{
$res = jsonReturn(0,0,Lang::get('成功'));
}
return $res;
}
}

105
HuoCMS_close_source/app/controller/backend/MaterialController.php

@ -0,0 +1,105 @@
<?php
namespace app\controller\backend;
use app\model\PosterMaterial;
use app\model\SysSetting;
use app\service\upload\Upload;
use think\facade\Lang;
class MaterialController extends BaseController
{
public function index()
{
$posterModel = new PosterMaterial();
$list = $posterModel->getMaterialList([]);
foreach ($list['data'] as $v) {
$v['source'] = str_replace("\\", '/', $v['source']);
}
return json($list);
}
public function upload()
{
if (request()->isPost()) {
set_time_limit(0);
$file = request()->file('file');
if (empty($file)) {
return jsonReturn(-8, Lang::get('文件上传失败,请重新尝试'));
}
$imageSize = getimagesize($file);
$seller_id = $this->admin['seller_id'];
// 查看文件类型
$fileName = $file->getOriginalName();
$fileExt = $file->getOriginalExtension();
$file_type = fileFormat($fileName);
// 附件大小和类型验证
// 获取上传配置
$Settings = new SysSetting();
$uploadSetting = $Settings->getAllCustomArrayData(['parent_id' => 1, 'group' => 'upload', 'status' => 1], 'id desc', 'id,group,title,value')['data'];
$uploadSetting = getColumnForKeyArray($uploadSetting, 'title');
$limitSize = $uploadSetting[$file_type . '_size']['value'] * 1024; // byte
$fileSize = $file->getSize(); // 单位byte
if ($fileSize > $limitSize) {
return jsonReturn(-1, Lang::get('文件过大,请修改上传限制或者替换小的文件'));
}
$extArr = explode(',', $uploadSetting[$file_type . '_ext']['value']);
if (!in_array($fileExt, $extArr)) {
return jsonReturn(-2, Lang::get('文件格式错误,请重新上传'));
}
$type = $this->getUploadType();
$upload = new Upload();
$upload->create($file, $seller_id, $type, $file_type);
$res = $upload->getUploadFileInfo()['data'];
$res['width'] = $imageSize[0];
$res['height'] = $imageSize[1];
$res['type'] = $fileExt;
if (strpos($res['url'], 'http') === false) {
$res['url'] = request()->domain() . '/' . $res['url'];
}
return jsonReturn(0, Lang::get('上传成功'), $res);
}
return jsonReturn(-3, Lang::get('请求方法错误'));
}
public function add()
{
if (request()->isPost()) {
$param = input('post.');
$posterModel = new PosterMaterial();
return json($posterModel->addMaterial($param));
}
}
public function del()
{
$id = input('param.id');
$posterModel = new PosterMaterial();
return json($posterModel->delMaterial($id));
}
/**
* @throws \app\exception\ModelException
*/
public function getUploadType()
{
// 文件信息提取
$where = [
'seller_id' => $this->admin['seller_id'],
'group' => 'upload',
'title' => 'storage'
];
$place = new SysSetting();
return $place->getSysSetting($where)['data']->toArray()['value'];
}
}

163
HuoCMS_close_source/app/controller/backend/ModuleController.php

@ -0,0 +1,163 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Module;
use app\service\CacheService;
use app\service\ModuleFieldService;
use app\service\ModuleService;
use app\validate\ModuleValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class ModuleController extends BaseController
{
/**
* 资源列表
* @param Module $module
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Module $module): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = $this->setLimit();
$moduleList = $module->getModuleList($where,$limit);
return json(pageReturn($moduleList));
}
/**
* 保存新建的资源
*
* @return \think\Response\Json
* @throws \Exception
*/
public function save(ModuleService $moduleService): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(ModuleValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// 数据库前缀
$prefix = config('database.connections')[config('database.default')]['prefix'];
$param['database_table'] = $prefix . $param['table'];
$param['status'] = 1;
$param['seller_id'] = $this->admin['seller_id'];
$res = $moduleService -> save($param);
// 系统模型添加
// $model = new Module();
// $res = $model->addModule($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\Response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Module $module): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('模型ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $module->getModule($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function update(Module $module): \think\response\Json
{
if(request()->isPost()){
$param = request()->only(['id','title','description','status']);
try {
validate(ModuleValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $module -> updateModule($where,$param);
CacheService::deleteRelationCacheByObject($module);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(ModuleService $moduleService): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,'ErrorMsg');
}
$param = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $moduleService->destroy($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 模型表
* @param ModuleService $moduleService
* @return \think\response\Json
*/
public function all(ModuleService $moduleService): \think\response\Json
{
return $moduleService -> getAllModuleTable($this->admin['seller_id']);
}
/**
* 模型表字段
* @param ModuleFieldService $moduleFieldService
* @return \think\response\Json
*/
public function field(ModuleFieldService $moduleFieldService): \think\response\Json
{
$table = $this->request->param('table');
if(empty($table)){
return jsonReturn(-1,Lang::get('表名不能为空'));
}
$res = $moduleFieldService -> getModuleTableField($table);
return json($res);
}
}

159
HuoCMS_close_source/app/controller/backend/ModuleFieldController.php

@ -0,0 +1,159 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\ModuleField;
use app\service\ContentService;
use app\service\ModuleFieldService;
use app\validate\ModuleFieldValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class ModuleFieldController extends BaseController
{
protected $paramKeys = ['id','module_id','form_title','table_field','validate_rule',
'type','length','default','status','placeholder','is_null','form_validate',
'order','settings','attach_data'
];
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(ModuleField $moduleField): \think\response\Json
{
$moduleId = (int)input('module_id');
if(!$moduleId){
return jsonReturn(-1,Lang::get('模型ID不能为空'));
}
$where = [
'seller_id' => $this->admin['seller_id'],
'module_id' => $moduleId,
];
$moduleFieldList = $moduleField->where($where)->select()->each(function(&$item){
if($item['form_type'] == 'reference'){
$service = new ContentService();
$item['attach_data'] = $service->getModuleContent($item['settings']['table'],$item['seller_id'])['data'];
}
})->toArray();
$list = getColumnForKeyArray($moduleFieldList,'order');
$len = count($list);
$tmp = [];
$res = $this->sortField($list,$len,'id',$tmp);
return jsonReturn(0,Lang::get('成功'),$res);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function save(ModuleFieldService $moduleFieldService,ModuleField $field): \think\response\Json
{
if(request()->isPost()){
$param = request()->only($this->paramKeys);
// 数据验证
try{
validate(ModuleFieldValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$res = $moduleFieldService->save($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(ModuleField $moduleField): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,'字段ID不能为空');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// 其他逻辑
$res = $moduleField->getModuleField($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function update(ModuleFieldService $moduleFieldService): \think\response\Json
{
if(request()->isPost()){
$param = request()->only($this->paramKeys);
try {
validate(ModuleFieldValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$res = $moduleFieldService -> update($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function delete(ModuleFieldService $moduleField): \think\response\Json
{
if(request()->isPost()){
$param = request()->only(['id','module_id']);
try {
validate(ModuleFieldValidate::class)->scene('delete')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'module_id' => $param['module_id'],
'seller_id' => $this->admin['seller_id']
];
$res = $moduleField->destroy($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
public function sortField($data,$len,$key,&$tmp)
{
if(isset($data[$key])){
array_push($tmp,$data[$key]);
if($len > 0){
$this->sortField($data,$len,$data[$key]['table_field'],$tmp);
}
}
return $tmp;
}
}

166
HuoCMS_close_source/app/controller/backend/NavCateController.php

@ -0,0 +1,166 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Nav;
use app\model\NavCate;
use app\service\CacheService;
use app\validate\NavCateValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class NavCateController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(NavCate $navCate): \think\response\Json
{
$siteId = (int)input('website_id');
if(!$siteId){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$lang = input('lang');
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
'lang' => $lang
];
$navCateList = $navCate->getAllCustomArrayData($where,'id asc');
return json($navCateList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
* @throws \ReflectionException
*/
public function save(NavCate $navCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(NavCateValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// 唯一验证
$navCate -> saveUnique(
[
'seller_id'=>$this->admin['seller_id'],
'website_id' => $param['website_id'],
'title'=>$param['title'],
'lang' => $param['lang'],
],'导航分类已存在');
$res = $navCate -> addNavCate($param);
CacheService::deleteRelationCacheByObject($navCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(NavCate $navCate): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,lang('导航分类ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $navCate->getNavCate($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelNotUniqueException
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function update(NavCate $navCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(NavCateValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
// 唯一验证
$navCate -> updateUnique(
[
'seller_id'=>$this->admin['seller_id'],
'website_id' => $param['website_id'],
'title'=>$param['title'],
'lang' => $param['lang'],
],$param['id'],lang('导航分类已存在'));
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $navCate -> updateNavCate($where,$param);
CacheService::deleteRelationCacheByObject($navCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function delete(NavCate $navCate,Nav $Nav): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(NavCateValidate::class)->scene('delete')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$whereNav = [
'nav_cate_id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
$nav = $Nav->getNavList($whereNav)['data']->toArray();
if(!empty($nav)){
return jsonReturn(-2,lang('分类下有菜单不能直接删除'));
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
$res = $navCate->delNavCate($where);
CacheService::deleteRelationCacheByObject($navCate);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

316
HuoCMS_close_source/app/controller/backend/NavController.php

@ -0,0 +1,316 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Category;
use app\model\Model;
use app\model\Nav;
use app\model\NavCate;
use app\model\Route;
use app\service\CacheService;
use app\validate\NavValidate;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Lang;
class NavController extends BaseController
{
/**
* 导航列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function index(Nav $nav): \think\response\Json
{
$param = input('param.');
try{
validate(NavValidate::class)->scene('index')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
$where = [
'seller_id' => $this->admin['seller_id'],
'nav_cate_id' => $param['cate_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang'],
];
$navList = $nav->getAllCustomArrayData($where)['data'];
$navList = makeTree($navList);
return jsonReturn(0,'success',$navList);
}
/**
* 新增导航
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelNotUniqueException
* @throws \ReflectionException
*/
public function save(Nav $nav,NavCate $NavCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(NavValidate::class)->scene('save')->check($param);
}catch(ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
if(empty($param['sort'])){
// 设置排序
$maxOrder = $nav->getMaxOrderNav(['parent_id' => $param['parent_id'],'seller_id' => $this->admin['seller_id']], 'sort')['data'];
if (!empty($maxOrder)) {
$param['sort'] = (int)$maxOrder + 10;
}
}
// 设置网站ID
$navCate = $NavCate -> getNavCate(['id'=>$param['nav_cate_id'],'seller_id'=>$this->admin['seller_id']])['data'];
$param['website_id'] = $navCate['website_id'];
// 唯一性验证
$nav->saveUnique(['title'=>$param['title'],'lang'=>$param['lang'],'nav_cate_id'=>$param['nav_cate_id'],'website_id'=>$param['website_id'],'seller_id'=>$param['seller_id'],'parent_id'=>$param['parent_id']],'导航已存在');
// 设置URL
if($param['type'] == 2){
$this->setNavUrl($param);
}
$res = $nav -> addNav($param);
CacheService::deleteRelationCacheByObject($nav);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 导航详情
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Nav $nav): \think\response\Json
{
$param = input('param.');
try {
validate(NavValidate::class)->scene('read')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
$res = $nav->getNav($where);
return json($res);
}
/**
* 更新导航
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelNotUniqueException
* @throws \ReflectionException
*/
public function update(Nav $nav, NavCate $NavCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(NavValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
// 设置网站ID
$navCate = $NavCate -> getNavCate(['id'=>$param['nav_cate_id'],'seller_id'=>$this->admin['seller_id']])['data'];
$param['website_id'] = $navCate['website_id'];
// 唯一性验证
$nav->updateUnique(['title'=>$param['title'],'website_id'=>$param['website_id'],'nav_cate_id'=>$param['nav_cate_id'],'seller_id'=>$this->admin['seller_id']],$param['id'],'导航已存在');
// 设置url
if($param['type'] == 2){
$this->setNavUrl($param);
}
if(empty($param['sort'])){
// 设置排序
$maxOrder = $nav->getMaxOrderNav(['parent_id' => $param['parent_id'],'seller_id' => $this->admin['seller_id']], 'sort')['data'];
if (!empty($maxOrder)) {
$param['sort'] = (int)$maxOrder + 10;
}
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $nav -> updateNav($where,$param);
CacheService::deleteRelationCacheByObject($nav);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除导航
*
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \ReflectionException
*/
public function delete(Nav $nav): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(NavValidate::class)->scene('delete')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1,$e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
$children = $nav->getNavList([
'parent_id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
])['data']->toArray();
if(count($children)){
$res = ['code'=>-4,'msg'=>lang('有子菜单不能删除')];
}else{
$res = $nav->delNav($where);
CacheService::deleteRelationCacheByObject($nav);
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 设置导航路由
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function setNavUrl(&$param)
{
$param['href'] = $this->getHrefByCategoryId($param['category_id'],$this->admin['seller_id']);
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function getHrefByCategoryId($categoryId, $sellerId)
{
$Category = new Category();
$category = $Category -> getCustomArrayData(['id'=>$categoryId,'seller_id' => $sellerId])['data'];
if($category['type'] == 2){
$href = 'javascript:;';
}else if($category['type'] == 3){
$href = $category['alias'];
} else{
$Route = new Route();
$route = $Route -> getCustomArrayData(['full_url'=> 'List/index?id='.$categoryId,'seller_id'=> $sellerId])['data'];
$href = $route['url'];
}
return $href;
}
/**
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \ReflectionException
*/
public function batchCreate(): \think\response\Json
{
$param = $this->request->only(['category_ids','nav_cate_id','target','lang','website_id']);
try {
validate(NavValidate::class)->scene('batchCreate')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
// 获取所有栏目
$category = new Category();
$whereCate = [
['seller_id','=',$this->admin['seller_id']],
['website_id','=',$param['website_id']],
['lang','=',$param['lang']]
];
if($param['category_ids'] != 0 || !empty($param['category_ids'])){
$whereCate[] = ['id','in',$param['category_ids']];
}
$categories = $category -> getAllCustomArrayData($whereCate,'id asc')['data'];
// 查询目前导航表中的最大ID
$prefix = env('database.prefix');
$navTable = $prefix . 'nav';
$res = Db::query("SHOW TABLE STATUS WHERE NAME = '$navTable'");
$maxId = $res[0]['Auto_increment'];
$targetIds = range($maxId, $maxId + count($categories) - 1);
// 栏目ID
$cateIds = array_column($categories,'id');
$mapIds = array_combine($cateIds,$targetIds);
// 生成导航插入数据
$nav = [];
foreach($categories as $cate){
$tmp = [];
$href = $this->getHrefByCategoryId($cate['id'],$this->admin['seller_id']);
$tmp['href'] = $href;
$tmp['nav_cate_id'] = $param['nav_cate_id'];
$tmp['lang'] = $param['lang'];
$tmp['target'] = $param['target'];
$tmp['sort'] = $cate['sort'];
$tmp['title'] = $cate['title'];
$tmp['category_id'] = $cate['id'];
$tmp['status'] = 1;
$tmp['no_follow'] = 2;
$tmp['website_id'] = $param['website_id'];
$tmp['seller_id'] = $this->admin['seller_id'];
if($cate['parent_id']){
$tmp['parent_id'] = $mapIds[$cate['parent_id']];
}else{
$tmp['parent_id'] = 0;
}
$tmp['id'] = $mapIds[$cate['id']];
$nav[] = $tmp;
}
// 插入导航数据
$Nav = new Nav();
Db::name('nav')->insertAll($nav);
CacheService::deleteRelationCacheByObject($Nav);
return jsonReturn(0);
}
/**
* 更新导航状态
* @throws \ReflectionException
* @throws \app\exception\ModelException
*/
public function updateStatus(): \think\response\Json
{
$param = $this->request->only(['id','status']);
try {
validate(NavValidate::class)->scene('updateStatus')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$Nav = new Nav();
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $Nav -> updateNav($where,['status'=>$param['status']]);
CacheService::deleteRelationCacheByObject($Nav);
return json($res);
}
}

52
HuoCMS_close_source/app/controller/backend/PluginController.php

@ -0,0 +1,52 @@
<?php
namespace app\controller\backend;
use app\model\Plugin as PluginModel;
use app\service\PluginService;
use think\facade\Lang;
class PluginController extends BaseController
{
public function index()
{
$pluginModel = new PluginModel();
$plugins = $pluginModel->getList();
return jsonReturn(0, Lang::get('成功'), $plugins);
}
public function install()
{
$param = $this->request->only(['name' => '']);
$res = PluginService::install($param['name']);
if ($res === true) {
return jsonReturn(0, lang('安装成功'));
}
return jsonReturn(-1, lang('安装失败') . $res);
}
public function uninstall()
{
$param = $this->request->only(['name' => '']);
$res = PluginService::uninstall($param['name']);
if ($res === true) {
return jsonReturn(0, lang('卸载成功'));
}
return jsonReturn(-1, lang('插件卸载失败') . $res);
}
public function editStatus()
{
$param = $this->request->only(['name' => '', 'status' => 1]);
$res = PluginService::editStatus($param['name'], $param['status']);
return json($res);
}
}

185
HuoCMS_close_source/app/controller/backend/PosterController.php

@ -0,0 +1,185 @@
<?php
namespace app\controller\backend;
use app\model\Poster;
use Kkokk\Poster\PosterManager;
class PosterController extends BaseController
{
public function index()
{
$posterModel = new Poster();
return json($posterModel->getPosterList([]));
}
public function add()
{
if (request()->isPost()) {
$param = input('post.');
$param['id'] = $param['id'] ?? 0;
if (empty($param['name'])) {
return jsonReturn(-1, lang('请填写海报名称'));
}
$posterModel = new Poster();
if ($posterModel->where([
['id', '<>', $param['id']],
['name', '=', $param['name']]
])->value('id')) {
return jsonReturn(-1, lang('海报名称已存在'));
}
try {
$preview = $this->makePreview($param, 'cover');
} catch (\Exception $e) {
return jsonReturn(-3, 'error', $e->getTrace());
}
$addParam = [
'name' => $param['name'],
'preview' => request()->domain() . '/' . ltrim($preview['url'], './'),
'status' => 1,
'design_content' => json_encode($param)
];
if (!empty($param['id'])) {
return json($posterModel->editPoster([['id', '=', $param['id']]],$addParam));
}
return json($posterModel->addPoster($addParam));
}
}
public function copy() {
if (!request()->isPost()) {
return jsonReturn(-1, lang('请求错误'));
}
$param = input('post.');
if (empty($param['id'])) {
return jsonReturn(-2, lang('参数错误'));
}
$posterModel = new Poster();
$data = $posterModel->where('id', '=', $param['id'])->findOrEmpty();
if (empty($data)) {
return jsonReturn(-3, lang('找不到要复制的海报'));
}
$designContent = json_decode($data['design_content'], true);
$designContent['name'] = $designContent['name'] . lang('-副本');
unset($designContent['id']);
$addParam = [
'name' => $designContent['name'],
'preview' => $data['preview'],
'status' => 1,
'design_content' => json_encode($designContent)
];
$res = $posterModel->addPoster($addParam);
if ($res['code'] == 0) {
$res['msg'] = lang('复制成功');
}
return json($res);
}
public function edit()
{
$id = input('param.id');
$posterModel = new Poster();
return json($posterModel->getDesignInfoById($id));
}
public function del()
{
$id = input('param.id');
$posterModel = new Poster();
return json($posterModel->del($id));
}
public function preview()
{
try {
$posterData = input('post.');
$result = $this->makePreview($posterData);
return jsonReturn(0, 'success', request()->domain() . '/' . ltrim($result['url'], './'));
} catch (\Exception $e) {
file_put_contents('./error.log', $e->getFile() . ' --- ' . $e->getLine() . ' --- ' . $e->getMessage() . PHP_EOL, FILE_APPEND);
return jsonReturn(-1, $e->getMessage());
}
}
/**
* @param $posterData
* @param $type
* @return mixed
*/
protected function makePreview($posterData, $type = 'temp')
{
$name = uniqid();
if ($type == 'temp') {
$PosterManager = new PosterManager('./poster_preview/temp/' . $name . '.' . $posterData['type']);
} else {
$PosterManager = new PosterManager('./poster_preview/cover/' . $name . '.' . $posterData['type']);
}
$temp = $PosterManager;
if ($posterData['activeName'] == 'img' && !empty($posterData['img_src'])) {
$temp = $temp->buildImDst($posterData['img_src'], $posterData['width'], $posterData['height']);
} else {
$temp = $temp->buildIm($posterData['width'], $posterData['height'], $this->hex2rgba($posterData['color']));
}
if (isset($posterData['item']) && !empty($posterData['item'])) {
foreach ($posterData['item'] as $vo) {
if ($vo['t'] == 'text') {
$font = '/system_file/alifont/' . $vo['fn'] . '.woff';
$temp = $temp->buildText($vo['v'], $vo['x'], $vo['y'], $vo['s'], $this->hex2rgba($vo['c']), $vo['w'], $font, $vo['a'], $vo['w'], 1, 0, $vo['rotate']);
} else if ($vo['t'] == 'image') {
$temp = $temp->buildImage($vo['v'], $vo['x'], $vo['y'], 0, 0, $vo['w'], $vo['h'], $this->hex2rgba($vo['c']), 'normal', $vo['rotate']);
} else if ($vo['t'] == 'qrcode') {
$temp = $temp->buildQr($vo['v'], $vo['x'], $vo['y'], 0, 0, $vo['w'], $vo['h'], 4, 1, $vo['rotate']);
}
}
}
return $temp->getPoster();
}
protected function hex2rgba($color)
{
$hexColor = str_replace('#', '', $color);
$lens = strlen($hexColor);
if ($lens != 3 && $lens != 6) {
return false;
}
$newColor = '';
if ($lens == 3) {
for ($i = 0; $i < $lens; $i++) {
$newColor .= $hexColor[$i] . $hexColor[$i];
}
} else {
$newColor = $hexColor;
}
$hex = str_split($newColor, 2);
$rgba = [];
foreach ($hex as $vls) {
$rgba[] = hexdec($vls);
}
$rgba[] = 1;
return $rgba;
}
}

121
HuoCMS_close_source/app/controller/backend/RecycleBinController.php

@ -0,0 +1,121 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\RecycleBin;
use app\service\ModuleFieldService;
use think\facade\Db;
use think\facade\Lang;
class RecycleBinController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(RecycleBin $recycleBin): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$table = input('param.table_name') ?: '';
if($table){
$where['table_name'] = $table;
}
$limit = $this->setLimit();
$recycleBinList = $recycleBin->getRecycleBinList($where,$limit);
return json(pageReturn($recycleBinList));
}
/**
* 回收站清空
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function clean(RecycleBin $recycleBin): \think\response\Json
{
if(request()->isPost()){
$res = $recycleBin -> delRecycleBin(['seller_id'=>$this->admin['seller_id']]);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 单条数据恢复
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \think\db\exception\DbException
*/
public function restore(ModuleFieldService $fieldService): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('数据ID不能为空'));
}
return $fieldService->resotreData($id,$this->admin['seller_id']);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(RecycleBin $recycleBin): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('数据ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $recycleBin->delRecycleBin($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 恢复多条数据
* @throws \think\db\exception\DbException
*/
public function allRestore(RecycleBin $recycleBin): \think\response\Json
{
if(!request()->isPost()){
return jsonReturn(-4,Lang::get('请求方法错误'));
}
$ids = input('param.ids');
if(!is_array($ids)){
return jsonReturn(-1,Lang::get('恢复数据参数错误'));
}
if(empty($ids)){
return jsonReturn(-2,Lang::get('恢复数据参数不能为空'));
}
$tableName = $recycleBin->whereIn('id',$ids)->column('table_name');
if(empty($tableName)){
return jsonReturn(-5,Lang::get('恢复数据不存在'));
}
$table = array_unique($tableName);
if(count($table) > 1){
return jsonReturn(-3,Lang::get('请选择相同类型的内容恢复'));
}
$recycleBin->whereIn('id',$ids)->where('seller_id',$this->admin['seller_id'])->delete();
$res = Db::name($table[0])->whereIn('id',$ids)->update(['is_del'=>1,'delete_time'=>0,'update_time'=>time()]);
return jsonReturn(0,Lang::get('恢复成功'),$res);
}
}

108
HuoCMS_close_source/app/controller/backend/ResumeController.php

@ -0,0 +1,108 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Attachment;
use app\model\Resume;
use think\facade\Lang;
class ResumeController extends BaseController
{
/**
* 简历列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Resume $resume): \think\response\Json
{
$where = [
['seller_id' ,'=', $this->admin['seller_id']],
['is_del' ,'=', 1],
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// 添加其他逻辑
$param = $this->request->only(['username'=>'','phone'=>'','start_time'=>'','end_time'=>'','email'=>'']);
if(!empty($param['username'])){
$where[] = ['username','like','%'.$param['username'.'%']];
}
if(!empty($param['phone'])){
$where[] = ['phone','like','%'.$param['phone'.'%']];
}
if(!empty($param['email'])){
$where[] = ['email','like','%'.$param['email'.'%']];
}
if(!empty($param['start_time']) && !empty($param['end_time']) ){
$where[] = ['create_time','between',[$param['start_time'],$param['end_time']]];
}
$attachment = new Attachment();
$resumeList = $resume->where($where)->paginate($limit)->each(function($item)use($attachment){
$file = $attachment->field('id,name,url')->where('id',$item->attachment_id)->findOrEmpty();
if(empty($file)){
$item->attachment = null;
}else{
$item->attachment = $file;
}
});
return json(['code' => 0, 'msg' => 'ok', 'count' => $resumeList->total(), 'data' => $resumeList->all()]);
}
/**
* 删除简历
*
* @throws \app\exception\ModelException
*/
public function delete(Resume $resume): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $resume->softDelResume($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
public function save(Resume $resume): \think\response\Json
{
if(request()->isPost()){
$param = $this->request->only(['nav_content','html_content','md_content','username']);
$res = $resume->addCustomData($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
public function read(Resume $resume): \think\response\Json
{
if(request()->isGet()){
$id = (int)$this->request->param('id');
$res = $resume->getCustomData(['id'=>$id]);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
public function update(Resume $resume): \think\response\Json
{
if(request()->isPost()){
$param = $this->request->only(['nav_content','html_content','md_content','username','id']);
$id = (int) $param['id'];
unset($param['id']);
$res = $resume->updateCustomData([['id','=',$id]],$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

186
HuoCMS_close_source/app/controller/backend/RoleController.php

@ -0,0 +1,186 @@
<?php
declare (strict_types=1);
namespace app\controller\backend;
use app\model\Admin;
use app\model\AdminMenu;
use app\model\Role;
use app\service\RoleService;
use app\validate\RoleValidate;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Lang;
class RoleController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Role $role): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$roleList = $role->getRoleList($where);
return json($roleList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(Role $role): \think\response\Json
{
if (request()->isPost()) {
$param = request()->only(['title', 'status']);
// 数据验证
try {
validate(RoleValidate::class)->scene('save')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$role->saveUnique(['seller_id' => $param['seller_id'], 'title' => $param['title']], lang('角色已经存在'));
$res = $role->addRole($param);
return json($res);
}
return jsonReturn(-3, Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Role $role): \think\response\Json
{
$id = (int)input('id');
if (!$id) {
return jsonReturn(-1, Lang::get('角色ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $role->getRole($where, ['website']);
if (!empty($res['data']['kid_auth'])) {
$res['data']['auth'] = explode(',', $res['data']['kid_auth']);
} else {
$res['data']['auth'] = [];
}
$res['data']['website_id'] = array_column($res['data']['website']->toArray(), 'id');
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
* @throws \app\exception\ModelEmptyException
*/
public function update(Role $role): \think\response\Json
{
if (request()->isPost()) {
$param = input('post.');
try {
validate(RoleValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
if ($param['group'] == 1) {
jsonReturn(-2, Lang::get('系统默认角色,不能编辑'));
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$roleInfo = $role->getRole($where)['data'];
if (empty($roleInfo)) {
return jsonReturn(-3, Lang::get('角色不存在'));
}
$role->updateUnique(['seller_id' => $this->admin['seller_id'], 'title' => $param['title']], $param['id'], lang('角色已经存在'));
if (!empty($param['auth'])) {
$len = count($param['auth']);
foreach ($param['auth'] as $key => $val) {
if ($val == 2) {
break;
}
if ($len == $key + 1) {
$param['auth'][] = 2;
}
}
$param['auth'] = implode(',', $param['auth']);
}
$roleInfo->website()->detach();
$roleInfo->website()->attach($param['website_id']);
unset($param['website_id']);
if(!empty($param['kid_auth'])){
$param['kid_auth'] = implode(',', $param['kid_auth']);
}else{
$param['kid_auth'] = '';
}
$res = $role->updateRole($where, $param);
return json($res);
}
return jsonReturn(-3, Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(Role $role): \think\response\Json
{
if (request()->isPost()) {
$id = (int)input('id');
if (!$id) {
return jsonReturn(-1, Lang::get('Id不能为空'));
}
if ($id == 1) {
return jsonReturn(-2, Lang::get('系统默认角色,不能删除'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $role->delRole($where);
return json($res);
}
return jsonReturn(-3, Lang::get('请求方法错误'));
}
/**
* @throws \app\exception\ModelException
*/
public function getAuth(AdminMenu $AdminMenu): \think\response\Json
{
$auth = $AdminMenu->getAllAdminMenu(['seller_id' => $this->admin['seller_id'], 'status' => 1])['data']->toArray();
$auth = generate($auth);
return jsonReturn(0, Lang::get('成功'), $auth);
}
public function getMenuAndUpdateAuth()
{
$adminId = $this->admin['uid'];
$res = RoleService::getMenuAndUpdateAuth($adminId);
return json($res);
}
}

80
HuoCMS_close_source/app/controller/backend/SeoAccountController.php

@ -0,0 +1,80 @@
<?php
namespace app\controller\backend;
use app\model\SeoAccount;
use app\validate\SeoAccountValidate;
use think\exception\ValidateException;
use think\response\Json;
/**
* SEO账号灌管理
*/
class SeoAccountController extends BaseController
{
public function lists(SeoAccount $seoModel): Json
{
$limit = input('param.limit');
$where = [];
$list = $seoModel->getAccountList($where, $limit);
return json(pageReturn($list));
}
public function add(SeoAccount $seoModel): Json
{
$param = input('post.');
$has = $seoModel->field('id')->where('account', $param['account'])->find();
if (!empty($has)) {
return jsonReturn(-2, lang('该账号已经存在'));
}
try {
validate(SeoAccountValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['create_time'] = date('Y-m-d H:i:s');
$seoModel->insert($param);
return jsonReturn(0, lang('添加账号成功'));
}
public function info(SeoAccount $seoModel): Json
{
$info = $seoModel->where('id', input('param.id'))->find();
return jsonReturn(0, lang('查询成功'), $info);
}
public function edit(SeoAccount $seoModel): Json
{
$param = input('post.');
$has = $seoModel->field('id')->where('account', $param['account'])->where('id', '<>', $param['id'])->find();
if (!empty($has)) {
return jsonReturn(-2, lang('该账号已经存在'));
}
try {
validate(SeoAccountValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$param['update_time'] = date('Y-m-d H:i:s');
$seoModel->where('id', $param['id'])->update($param);
return jsonReturn(0, lang('编辑账号成功'));
}
public function del(SeoAccount $seoModel)
{
$seoModel->where('id', input('param.id'))->delete();
return jsonReturn(0, lang('删除成功'));
}
}

242
HuoCMS_close_source/app/controller/backend/SeoCheckController.php

@ -0,0 +1,242 @@
<?php
declare (strict_types=1);
namespace app\controller\backend;
use think\facade\Db;
class SeoCheckController extends BaseController
{
public function index()
{
$limit = input('param.limit');
$where = [];
$list = Db::name('seo_check_task')->where($where)->order('create_time desc')->paginate($limit);
return json(pageReturn(['code' => 0, 'data' => $list, 'msg' => lang('成功')]));
}
public function check()
{
$param = $this->request->param();
if ($param['flag'] == 'progress') {
$taskDetail = Db::name('seo_check_task_detail')->where('task_id', $param['task_id'])->select();
$isEnd = true;
$checkData = [];
$success = 0;
$error = 0;
foreach ($taskDetail as $vo) {
if ($vo['status'] == 1) {
$isEnd = false;
}
if (!empty($vo['remark'])) {
$data = json_decode($vo['remark'], true);
$checkData[] = $data;
if ($data['code'] == 101) {
foreach ($data['data'] as $key => $v) {
if ($v['status'] == 1) {
$success++;
continue;
}
if ($key == 'tags') {
$error += isset($v['msg']['ajax']) ? count($v['msg']['ajax']) : 0;
$error += isset($v['msg']['alt']) ? count($v['msg']['alt']) : 0;
continue;
}
if (is_array($v['msg'])) {
$error += count($v['msg']);
} else {
$error ++;
}
}
}
if ($data['code'] == 102) {
if ($data['data']['status'] == 1) {
$success++;
} else {
$error++;
}
}
if ($data['code'] == 103) {
$error += isset($data['data']['deadLink']) ? count($data['data']['deadLink']) : 0;
$error += isset($data['data']['keywords']) ? count($data['data']['keywords']) : 0;
}
if ($data['code'] == 104) {
if (isset($data['data']['inlinks']['linksHave'])) {
foreach ($data['data']['inlinks']['linksHave'] as $v) {
if ($v['status'] == 1) {
$success++;
} else {
$error++;
}
}
}
if (isset($data['data']['inlinks']['nofollow'])) {
foreach ($data['data']['inlinks']['nofollow'] as $v) {
if ($v['status'] == 1) {
$success++;
} else {
$error++;
}
}
}
if (isset($data['data']['outlinks']['linksHave'])) {
foreach ($data['data']['outlinks']['linksHave'] as $v) {
if ($v['status'] == 1) {
$success++;
} else {
$error++;
}
}
}
}
}
}
if ($isEnd) {
Db::name('seo_check_task')->where('id', $param['task_id'])->update([
'status' => 2,
'update_time' => date('Y-m-d H:i:s')
]);
}
return json(['code' => 0, 'data' => [
'success' => $success,
'error' => $error,
'check_data' => $checkData,
'is_end' => $isEnd,
'task' => Db::name('seo_check_task')->where('id', $param['task_id'])->find()
], 'msg' => 'success']);
}
$websiteId = input('param.website_id');
$list = Db::name('theme')->field('lang,theme')->where('is_active', 1)->where('website_id', $websiteId)->select();
return jsonReturn(0, 'success', $list);
}
public function start()
{
if (request()->isPost()) {
$param = input('post.');
$hasRun = Db::name('seo_check_task')->field('id')->where('website_id', $param['website_id'])->where('status', 1)->find();
if (!empty($hasRun)) {
return jsonReturn(-1, lang('该站点正在检测中'));
}
Db::startTrans();
try {
$taskId = Db::name('seo_check_task')->insertGetId([
'website_id' => $param['website_id'],
'website_url' => $param['website_url'],
'lang' => $param['lang'],
'theme' => $param['theme'],
'status' => 1,
'create_time' => date('Y-m-d H:i:s')
]);
$params = [
[
'task_id' => $taskId,
'status' => 1,
'code' => 'code',
'create_time' => date('Y-m-d H:i:s')
],
[
'task_id' => $taskId,
'status' => 1,
'code' => 'web',
'create_time' => date('Y-m-d H:i:s')
],
[
'task_id' => $taskId,
'status' => 1,
'code' => 'keywords',
'create_time' => date('Y-m-d H:i:s')
],
[
'task_id' => $taskId,
'status' => 1,
'code' => 'links',
'create_time' => date('Y-m-d H:i:s')
],
[
'task_id' => $taskId,
'status' => 1,
'code' => 'article',
'create_time' => date('Y-m-d H:i:s')
],
];
Db::name('seo_check_task_detail')->insertAll($params);
Db::commit();
} catch (\Exception $e) {
Db::rollback();
return jsonReturn(-2, $e->getMessage());
}
$taskData = [
'task_id' => $taskId,
'websiteId' => $param['website_id'],
'start_time' => date('Y-m-d H:i:s'),
'lang' => $param['lang'],
'theme' => $param['theme'],
'websiteUrl' => $param['website_url'],
'cate' => Db::name('category')->field('id,title,alias')->where('status', 1)
->where('lang', $param['lang'])
->where('type', '<>', 3)->where('website_id', $param['website_id'])->select(),
'keywords' => Db::name('keyword')->field('name')->where('is_del', 1)->where('website_id', $param['website_id'])->select()
];
// 以text协议发送$task_data数据
$taskData['cmd'] = 'code';
$this->sendData($taskData);
$taskData['cmd'] = 'web';
$this->sendData($taskData);
$taskData['cmd'] = 'keywords';
$this->sendData($taskData);
$taskData['cmd'] = 'links';
$this->sendData($taskData);
$taskData['cmd'] = 'article';
$this->sendData($taskData);
return jsonReturn(0, lang('启动成功'), $taskData);
}
}
public function del()
{
if (!request()->isPost()) {
return jsonReturn(-1, lang('请求错误'));
}
$param = $this->request->only(['id']);
Db::name('seo_check_task')->where('id', '=', $param['id'])->delete();
Db::name('seo_check_task_detail')->where('task_id', '=', $param['id'])->delete();
return jsonReturn(0, lang('删除成功'));
}
protected function sendData($data)
{
// 与服务端建立连接
$client = stream_socket_client('tcp://127.0.0.1:19890');
fwrite($client, json_encode($data) . "\n");
//关闭句柄
fclose($client);
}
}

54
HuoCMS_close_source/app/controller/backend/SeoController.php

@ -0,0 +1,54 @@
<?php
namespace app\controller\backend;
use app\model\BaiduTjGather;
use app\model\SeoAccount;
class SeoController extends BaseController
{
public function baidu(SeoAccount $seoAccount, BaiduTjGather $baiduTjGather): \think\response\Json
{
$account = $seoAccount->field('id,account')->where('type', 1)->where('status', 1)->select();
$pvData = $baiduTjGather->getYesterdayData()['data'];
if (empty($pvData)) {
$pvData = [
'pv_count' => 0,
'uv_count' => 0,
'ip_count' => 0,
'avg_visit_time' => '00:00:00'
];
} else {
$pvData['avg_visit_time'] = $this->changeTimeType($pvData['avg_visit_time']);
}
$data = [
'account' => $account,
'pvData' => $pvData
];
return jsonReturn(0, lang('查询成功'), $data);
}
/**
* 计算时长
* @param $seconds
* @return string
*/
protected function changeTimeType($seconds): string
{
if ($seconds > 3600) {
$hours = intval($seconds / 3600);
$minutes = $seconds % 3600;
$time = $hours . ":" . gmstrftime('%M:%S', $minutes);
} else {
$time = gmstrftime('%H:%M:%S', $seconds);
}
return $time;
}
}

139
HuoCMS_close_source/app/controller/backend/SeoSettingController.php

@ -0,0 +1,139 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\SeoSetting;
use app\validate\SeoSettingValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class SeoSettingController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(SeoSetting $seoSetting): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
$seoSettingList = $seoSetting->getSeoSettingList($where,$limit);
return json(pageReturn($seoSettingList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(SeoSetting $seoSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(SeoSettingValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $seoSetting -> addSeoSetting($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(SeoSetting $seoSetting): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $seoSetting->getSeoSetting($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(SeoSetting $seoSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(SeoSettingValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $seoSetting -> updateSeoSetting($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(SeoSetting $seoSetting): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
// TO DO
// 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $seoSetting->delSeoSetting($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

46
HuoCMS_close_source/app/controller/backend/SiteMapController.php

@ -0,0 +1,46 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Website;
use app\service\Sitemap;
use think\facade\Lang;
class SiteMapController extends BaseController
{
/**
* @throws \app\exception\ModelException
*/
public function gen() {
$website_id = input('website_id');
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $website_id,
];
$sitemap = new Sitemap($where['seller_id'], $where['website_id']);
$sitemap->scan();
$silian = $sitemap->siliamGen();
// 生成xml文件
$path = $sitemap->sitemapGen();
$websiteWhere = [
'id' => $website_id
];
$param = [
'sitemap_url' => $path,
'silian_url' => $silian,
];
$website = new Website();
$res = $website->updateWebsite($websiteWhere, $param);
return jsonReturn($res['code'], Lang('生成成功'), $res['data']);
}
}

125
HuoCMS_close_source/app/controller/backend/SlideCateController.php

@ -0,0 +1,125 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\SlideCate;
use app\validate\SlideCateValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class SlideCateController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(SlideCate $slideCate): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = $this->setLimit();
$slideCateList = $slideCate->getSlideCateList($where,$limit);
return json(pageReturn($slideCateList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(SlideCate $slideCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(SlideCateValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$res = $slideCate -> addSlideCate($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(SlideCate $slideCate): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('分类ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $slideCate->getSlideCate($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(SlideCate $slideCate): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(SlideCateValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $slideCate -> updateSlideCate($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(SlideCate $slideCate): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('分类ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $slideCate->delSlideCate($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

134
HuoCMS_close_source/app/controller/backend/SlideController.php

@ -0,0 +1,134 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Slide;
use app\service\CacheService;
use app\validate\SlideValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class SlideController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Slide $slide): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'slide_cate_id' => (int)input('slide_cate_id'),
];
$slideList = $slide->getAllCustomArrayData($where,'sort desc','*',['attachment'=>function($q){
$q->field('id,name,url,type');
}]);
return json($slideList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function save(Slide $slide): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(SlideValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$res = $slide -> addSlide($param);
CacheService::deleteRelationCacheByObject($slide);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Slide $slide): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('幻灯片ID'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// 其他逻辑
$res = $slide->getSlide($where,['attachment'=>function($q){
$q->field('id,name,url,type');
}]);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*@throws \ReflectionException
*/
public function update(Slide $slide): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(SlideValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $slide -> updateSlide($where,$param);
CacheService::deleteRelationCacheByObject($slide);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function delete(Slide $slide): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('幻灯片ID'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $slide->delSlide($where);
CacheService::deleteRelationCacheByObject($slide);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

139
HuoCMS_close_source/app/controller/backend/SocialMarketingController.php

@ -0,0 +1,139 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\SocialMarketing;
use app\validate\SocialMarketingValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class SocialMarketingController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(SocialMarketing $socialMarketing): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
];
$limit = 10;
$limitParam = (int)input('limit');
if($limitParam){
$limit = $limitParam;
}
// TODO
// 添加其他逻辑
$socialMarketingList = $socialMarketing->getSocialMarketingList($where,$limit);
return json(pageReturn($socialMarketingList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(SocialMarketing $socialMarketing): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
$param['seller_id'] = $this->admin['seller_id'];
// 数据验证
try{
validate(SocialMarketingValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $socialMarketing -> addSocialMarketing($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(SocialMarketing $socialMarketing): \think\response\Json
{
$id = (int)input('id');
if(!$id){
// TODO
// 修改错误消息
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
// TODO
// 其他逻辑
$res = $socialMarketing->getSocialMarketing($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(SocialMarketing $socialMarketing): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(SocialMarketingValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$res = $socialMarketing -> updateSocialMarketing($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
*/
public function delete(SocialMarketing $socialMarketing): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
// TO DO
// 替换错误提示
return jsonReturn(-1,'ErrorMsg');
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $socialMarketing->delSocialMarketing($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

45
HuoCMS_close_source/app/controller/backend/StaticFileController.php

@ -0,0 +1,45 @@
<?php
namespace app\controller\backend;
use app\service\StaticFileService;
class StaticFileController extends BaseController
{
public function updateCategoryCache()
{
$param = $this->request->only(['site_id', 'lang']);
$param['admin'] = $this->admin;
$staticService = new StaticFileService();
$res = $staticService->updateCategoryCache($param);
return json($res);
}
public function createCategory()
{
$param = $this->request->only(['site_id', 'lang', 'category_id' => 0, 'has_child']);
$param['admin'] = $this->admin;
$param['category_id'] = $param['category_id'] ?? 0;
$staticService = new StaticFileService();
$res = $staticService->createCategory($param['category_id'], $param, $param['has_child']);
return json($res);
}
public function createContent()
{
$param = $this->request->only(['site_id', 'lang', 'category_id' => 0]);
$param['admin'] = $this->admin;
$param['category_id'] = $param['category_id'] ?? 0;
$staticService = new StaticFileService();
$res = $staticService->createContent($param['category_id'], $param);
return json($res);
}
}

617
HuoCMS_close_source/app/controller/backend/StatisticsController.php

@ -0,0 +1,617 @@
<?php
namespace app\controller\backend;
use app\exception\BadSysSettingException;
use app\model\BaiduTjGather;
use app\model\SeoAccount;
use app\model\SysSetting;
use app\model\Visit;
use app\model\VisitLog;
use app\model\Website;
use think\facade\Lang;
class StatisticsController extends BaseController
{
public $header = '';
public $url = 'http://api.baidu.com/json/tongji/v1/ReportService/getData';
protected $baiduInfo;
private $site_id = 0;
/**
* @throws \app\exception\ModelException
*/
public function setConfig()
{
$id = input('param.id') ?? 0;
if (!empty($id)) {
$info = (new SeoAccount())->where('id', $id)->find();
$this->baiduInfo = [
'account_type' => '1',
'username' => $info['account'],
'password' => $info['password'],
'token' => $info['token'],
];
} else {
$this->baiduInfo = null;
}
}
/**
* @throws \app\exception\ModelException
* @throws BadSysSettingException
*/
public function initialize()
{
parent::initialize();
}
/**
* @throws BadSysSettingException
*/
public function baiduErrorReturn($response)
{
if(!empty($response['header']['failures'])){
throw new BadSysSettingException($response['header']['failures'][0]['message']);
}
}
/**
* @throws BadSysSettingException
*/
public function getResponse($data)
{
$data = json_encode(['body'=>$data, "header"=>$this->header]);
$response = $this->https_request($this->url, $data);
$response = json_decode($response,true);
$this->baiduErrorReturn($response);
return $response;
}
/**
* @throws BadSysSettingException
*/
public function lists(): \think\response\Json
{
$url = 'https://api.baidu.com/json/tongji/v1/ReportService/getSiteList';
$data = json_encode(["header"=>$this->header]);
$response = $this->https_request($url, $data);
$response = json_decode($response, true);
$this->baiduErrorReturn($response);
return jsonReturn(0, Lang::get('查询成功'), $response['body']['data']['0']['list']);
}
public function indexLists()
{
$websiteModel = new Website();
$list = $websiteModel->field('*, id as site_id, domain')->select();
return jsonReturn(0, Lang::get('查询成功'), $list);
}
// 首页趋势图
public function indexQST()
{
ini_set('memory_limit', '512M');
$websiteId = $this->request->request('website_id')?$this->request->request('website_id'):1;
$type = $this->request->request('type')?$this->request->request('type'):1;
$nowDay = date('Y-m-d');
// 今天
$startTime = strtotime($nowDay);
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
if ($type==2) { // 昨天
$startTime = strtotime(date('Y-m-d', strtotime('-1 day')));
$endTime = strtotime($nowDay) - 1;
} elseif ($type==3) { // 最近7天
$startTime = strtotime(date('Y-m-d', strtotime('-6 day')));
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
} elseif ($type==4) { // 最近30天
$startTime = strtotime(date('Y-m-d', strtotime('-29 day')));
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
}
$visitModel = new VisitLog();
$list = $visitModel->where([
['create_time', '>=', $startTime],
['create_time', '<=', $endTime],
['website_id', '=', $websiteId],
])->select()->toArray();
$newList = [];
if ($type == 1 || $type == 2) {
$maxH = 23;
if ($type == 1) {
$maxH = date('H');
}
for ($i = 0; $i <= $maxH; $i++) {
if ($i < 10) {
$i = '0' . $i;
}
$i = (string)$i;
$newList[$i] = 0;
}
} else {
for ($i = $startTime; $i <= $endTime;) {
$dateStr = date('Y-m-d', $i);
$newList[$dateStr] = 0;
$i += 86400;
}
}
$type1List = $type2List = $type3List = $newList;
$type2Unique = []; // 校验唯一
$type3Unique = []; // 校验唯一
// type 为1和2,时间间隔为小时。否则为天
foreach ($list as $value) {
if ($type == 1 || $type == 2) {
$key = date('H', strtotime($value['create_time']));
} else {
$key = date('Y-m-d', strtotime($value['create_time']));
}
$type1List[$key] ++;
if (!isset($type2Unique[$key][$value['agent']])) {
$type2Unique[$key][$value['agent']] = 1;
$type2List[$key] ++;
}
if (!isset($type3Unique[$key][$value['ip']])) {
$type3Unique[$key][$value['ip']] = 1;
$type3List[$key] ++;
}
}
$returnData['pv_list'] = array_values($type1List);
$returnData['uv_list'] = array_values($type2List);
$returnData['ip_list'] = array_values($type3List);
$returnData['time'] = array_keys($type1List);
foreach ($returnData['time'] as &$value) {
$value = (string)$value;
}
return jsonReturn(0, Lang::get('查询成功'), $returnData);
}
// 首页地区分布图
public function indexArea()
{
$websiteId = $this->request->request('website_id')?$this->request->request('website_id'):1;
$type = $this->request->request('type')?$this->request->request('type'):1;
$nowDay = date('Y-m-d');
// 今天
$startTime = strtotime($nowDay);
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
if ($type==2) { // 昨天
$startTime = strtotime(date('Y-m-d', strtotime('-1 day')));
$endTime = strtotime($nowDay) - 1;
} elseif ($type==3) { // 最近7天
$startTime = strtotime(date('Y-m-d', strtotime('-6 day')));
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
} elseif ($type==4) { // 最近30天
$startTime = strtotime(date('Y-m-d', strtotime('-29 day')));
$endTime = strtotime(date('Y-m-d', strtotime('+1 day')));
}
$visitModel = new VisitLog();
$list = $visitModel->where([
['create_time', '>=', $startTime],
['create_time', '<=', $endTime],
['website_id', '=', $websiteId],
['visited_area', '<>', '内网ip'],
])->select()->toArray();
$total = count($list);
$newData = [];
foreach ($list as $value) {
$areaArr = explode('-', $value['visited_area']);
$province = $areaArr[0];
if (!isset($newData[$province])) {
$newData[$province] = [
'name' => $province,
'value' => 1,
'pv_ratio' => bcmul(1 / $total, 100, 2),
];
} else {
$newData[$province]['value']++;
$newData[$province]['pv_ratio'] = bcmul($newData[$province]['value']/$total, 100, 2);
}
}
return jsonReturn(0, Lang::get('查询成功'), array_values($newData));
}
/**
* 访客年龄分布
* @return false|string|\think\response\Json
* @throws BadSysSettingException
*/
public function age()
{
$data = [
"site_id"=> $this->request->param('site_id') ? $this->request->param('site_id') : $this->site_id,
"method" => "overview/getAge"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
return jsonReturn(0, '查询成功', $response);
}
/**
* 今日昨日浏览量分析
* @throws BadSysSettingException
*/
public function outline(): \think\response\Json
{
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"method" => "overview/getOutline"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
foreach ($response['items'] as $key => $value) {
if(is_numeric($value[5]) && $value[5] != '--'){
$response['items'][$key][5] = $this->secToTime($value[5]);
}elseif(is_array($value[5]) && $value[5]['val'] != '--'){
$response['items'][$key][5]['val'] = $this->secToTime($value[5]['val']);
}
}
return jsonReturn(0, Lang::get('查询成功'),$response);
}
/**
* 趋势图
* pv_count (浏览量PV)
* visitor_count (访客数UV)
* ip_count (IP )
* bounce_ratio (跳出率,%)
* avg_visit_time (平均访问时长,秒)
* trans_count (转化次数)
* @throws BadSysSettingException
*/
public function qxt()
{
$type = $this->request->request('type')?$this->request->request('type'):1;
$contrast = $this->request->request('contrast')?$this->request->request('contrast'):1;
$metrics = $this->request->request('metrics')?$this->request->request('metrics'):'pv_count';
switch ($metrics) {
case 'visitor_count':
$name = Lang::get('访客数(UV)');
break;
case 'ip_count':
$name = Lang::get('IP数');
break;
case 'bounce_ratio':
$name = Lang::get('跳出率');
break;
case 'avg_visit_time':
$name = Lang::get('平均访问时长');
break;
case 'trans_count':
$name = Lang::get('转化次数');
break;
default:
$name = Lang::get('浏览量(PV)');
break;
}
$et = date('Ymd', time());
if($type==1){
$st = date('Ymd', time());
if($contrast==1){
$start_date2 = date('Ymd', time()-(3600*24));
$end_date2 = date('Ymd', time()-(3600*24));
}elseif($contrast==2){
$start_date2 = date('Ymd', time()-(3600*24*7));
$end_date2 = date('Ymd', time()-(3600*24*7));
}
}elseif ($type==2) {
$st = date('Ymd', strtotime('-1 day'));
$et = date('Ymd', strtotime('-1 day'));
if($contrast==1){
$start_date2 = date('Ymd', strtotime('-1 day')-(3600*24));
$end_date2 = date('Ymd', strtotime('-1 day')-(3600*24));
}elseif($contrast==2){
$start_date2 = date('Ymd', time()-(3600*24*7));
$end_date2 = date('Ymd', time()-(3600*24*7));
}
}elseif ($type==3) {
$st = date('Ymd', strtotime('-6 day'));
}elseif ($type==4) {
$st = date('Ymd', strtotime('-29 day'));
}
if($contrast && ($type == 1 or $type == 2)){
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $st,
"end_date" => $et,
"start_date2" => $start_date2,
"end_date2" => $end_date2,
"metrics" => $metrics,
"method" => "overview/getTimeTrendRpt"
];
}else{
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $st,
"end_date" => $et,
"metrics" => $metrics,
"method" => "overview/getTimeTrendRpt"
];
}
$response = $this->getResponse($data);
$result = $response['body']['data']['0']['result']['items'];
$new = [];
$new[0] = $result[1];
$new[1] = $result[2];
if($metrics != 'avg_visit_time'){
foreach ($new as $key => $value) {
foreach ($value as $k => $v) {
$count = count($value);
if($type == 3 || $type == 4){
$new[$key][$k][0] = date('Y/m/d', strtotime('-'.($count-$k-1).' day'));
$new[$key][$k][1] = $v[0];
}
if($k<=10){
array_push($new[$key][$k], $k.':00-'.$k.':59');
}else{
array_push($new[$key][$k], $k.':00-'.$k.':59');
}
}
}
}else{
if($type == 3 || $type ==4){
$anew = [];
$anew[0] = $result[1];
foreach ($anew as $key => $value) {
foreach ($value as $k => $v) {
$count = count($value);
$anew[$key][$k][0] = date('Y/m/d', strtotime('-'.($count-$k-1).' day'));
$anew[$key][$k][1] = $v[0];
if($k<=10){
array_push($anew[$key][$k], $k.':00-'.$k.':59');
}else{
array_push($anew[$key][$k], $k.':00-'.$k.':59');
}
array_push($anew[$key][$k],$this->secToTime($v[0]));
}
}
return json_encode(['code'=>0, 'msg'=> Lang::get('查询成功'),'name'=>$name,'data'=>$anew]);
}else{
foreach ($new as $key => $value) {
foreach ($value as $k => $v) {
if($k<=10){
array_push($new[$key][$k], $k.':00-'.$k.':59');
}else{
array_push($new[$key][$k], $k.':00-'.$k.':59');
}
array_push($new[$key][$k],$this->secToTime($v[1]));
}
}
}
}
return jsonReturn(0, Lang::get('查询成功'),['name'=>$name,'data'=>$new]);
}
// /**
// * 关键词消费排名
// * @throws BadSysSettingException
// */
// public function search_word()
// {
// $type = $this->request->request('type')?$this->request->request('type'):1;
// $se = $this->getSTAndET($type);
// $data = [
// "site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
// "start_date" => $se['st'],
// "end_date" => $se['st'],
// "metrics" => "pv_count,visit_count,visitor_count",
// "method" => "overview/getWord"
// ];
// $response = $this->getResponse($data);
// $response = $response['body']['data']['0']['result'];
// return jsonReturn(0, '查询成功',$response);
// }
/**
* Top10搜索词
* @throws BadSysSettingException
*/
public function search_word()
{
$type = $this->request->request('type')?$this->request->request('type'):1;
$se = $this->getSTAndET($type);
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $se['st'],
"end_date" => $se['st'],
"metrics" => "pv_count,pv_ratio",
"method" => "source/searchword/a"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
$list = $response['items'][0] ?? [];
if (count($list) > 10) {
$list = array_slice($list, 0, 10);
$response['items'][0] = $list;
}
return jsonReturn(0, Lang::get('查询成功'),$response);
}
public function https_request($url,$data)
{
// 初始化
$curl = curl_init();
// 设置
curl_setopt($curl,CURLOPT_URL,$url);
// 检查ssl证书
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
// 从检查本地证书检查是否ssl加密
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,$url);
// 判断$data 判断是否post
if ( !empty($data) ) {
curl_setopt($curl,CURLOPT_POST,1);// 开启post
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);// 发送post $data
}
// 返回结果 是文件流的方式返回
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if($err){
return false;
}else{
return $response;
}
}
/**
* 网站概况(来源网站、搜索词、入口页面、受访页面、新老访客)
* @throws BadSysSettingException
*/
public function get_common_track_rpt(): \think\response\Json
{
$type = $this->request->request('type') ? $this->request->request('type') : 1;
$se = $this->getSTAndET($type);
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $se['st'],
"end_date" => $se['et'],
"method" => "overview/getCommonTrackRpt"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
foreach ($response['visitType'] as $key => $value) {
$response['visitType'][$key]['avg_visit_time'] = $this->secToTime($value['avg_visit_time']);
}
return jsonReturn(0, Lang::get('查询成功'), $response);
}
/**
* 网站概况(地域分布)
* @throws BadSysSettingException
*/
public function area()
{
$type = $this->request->request('type')?$this->request->request('type'):2;
$se = $this->getSTAndET($type);
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $se['st'],
"end_date" => $se['et'],
"metrics"=> "pv_count,pv_ratio",
"method" => "visit/district/a"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
$new = [];
foreach ($response['items'][0] as $key => $value) {
$new[$key]['name'] = $value[0]['name'];
$new[$key]['area'] = $value[0]['area'];
}
foreach ($response['items'][1] as $key => $value) {
$new[$key]['pv_count'] = $value[0];
$new[$key]['pv_ratio'] = $value[1];
}
return jsonReturn(0, Lang::get('查询成功'),$new);
}
/**
*
* 网站概况(地域分布Top10)
*
* @throws BadSysSettingException
*/
public function area_top(): \think\response\Json
{
$type = $this->request->request('type')?$this->request->request('type'):2;
$se = $this->getSTAndET($type);
$data = [
"site_id"=> $this->request->param('site_id')?$this->request->param('site_id'):$this->site_id,
"start_date" => $se['st'],
"end_date" => $se['et'],
"metrics"=> "pv_count,pv_ratio",
"method" => "visit/district/a"
];
$response = $this->getResponse($data);
$response = $response['body']['data']['0']['result'];
$new = [];
foreach ($response['items'][0] as $key => $value) {
$new[$key]['name'] = $value[0]['name'];
$new[$key]['area'] = $value[0]['area'];
}
foreach ($response['items'][1] as $key => $value) {
$new[$key]['pv_count'] = $value[0];
$new[$key]['pv_ratio'] = $value[1];
}
$new = array_slice($new, 0, 10);
return jsonReturn(0, Lang::get('查询成功'), $new);
}
public function http_request($url,$data)
{
// 初始化
$curl = curl_init();
// 设置
curl_setopt($curl,CURLOPT_URL,$url);
// 检查ssl证书
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER,FALSE);
// 从检查本地证书检查是否ssl加密
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST,$url);
// 判断$data 判断是否post
if ( !empty($data) ) {
curl_setopt($curl,CURLOPT_POST,1);// 开启post
curl_setopt($curl,CURLOPT_POSTFIELDS,$data);// 发送post $data
}
// 返回结果 是文件流的方式返回
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
return $response;
}
// 获取开始日期和结束日期
public function getSTAndET($type): array
{
$et = date('Ymd', time());
if($type==1){
$st = date('Ymd', time());
}elseif ($type==2) {
$st = date('Ymd', strtotime('-1 day'));
$et = date('Ymd', strtotime('-1 day'));
}elseif ($type==3) {
$st = date('Ymd', strtotime('-6 day'));
}else {
$st = date('Ymd', strtotime('-29 day'));
}
return ['st' => $st,'et'=>$et];
}
public function secToTime($sec)
{
if (is_numeric($sec)) {
$strSecond = gmstrftime('%H:%M:%S', $sec);
} else {
$strSecond = $sec;
}
return $strSecond;
}
}

180
HuoCMS_close_source/app/controller/backend/SysSettingController.php

@ -0,0 +1,180 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\SysSetting;
use app\service\CacheService;
use app\validate\SysSettingValidate;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Lang;
class SysSettingController extends BaseController
{
protected $group = ['email','upload','sem','analysis','others','company'];
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(SysSetting $sysSetting): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'status' => 1,
];
$order = 'sort asc,id asc';
$sysSettingList = $sysSetting->getAllCustomArrayData($where,$order)['data'];
$sysSettingList = makeTree($sysSettingList);
return jsonReturn(0,Lang::get('成功'),$sysSettingList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(SysSetting $sysSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(SysSettingValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$res = $sysSetting -> addCustomData($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function read(SysSetting $sysSetting): \think\response\Json
{
$param = input('param.');
// 数据验证
try{
validate(SysSettingValidate::class)->scene('read')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$where = [
['group','=',$param['group']],
['seller_id','=',$this->admin['seller_id']],
];
$order = 'sort asc';
$res = $sysSetting->getAllCustomArrayData($where,$order)['data'];
$res = generate($res);
return jsonReturn(0,Lang::get('成功'),$res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException*@throws \ReflectionException
* @throws \ReflectionException
*/
public function update(SysSetting $sysSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
if(empty($param['group'])){
return jsonReturn(-1,Lang::get('配置分组不能为空'));
}
if(!in_array($param['group'],$this->group)){
return jsonReturn(-2,Lang::get('配置分组类型错误'));
}
if($param['group'] == 'setting'){
Cache::delete('hc_company_'. $this->admin['seller_id']);
}
try {
validate(SysSettingValidate::class)->check($param);
} catch (\Exception $e) {
return jsonReturn(-1, $e->getMessage());
}
$where = [
'seller_id' => $this->admin['seller_id'],
];
foreach($param as $key => $val){
$whereVal = array_merge($where,['title'=>$key]);
$sysSetting -> updateSysSetting($whereVal,['value'=>$val]);
}
CacheService::deleteRelationCacheByObject($sysSetting);
return jsonReturn(0,Lang::get("保存成功"));
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function emailClear(SysSetting $sysSetting): \think\response\Json
{
$sysSetting -> updateSysSetting(['seller_id' => $this->admin['seller_id'],'group'=>'email'],['value'=>'']);
CacheService::deleteRelationCacheByObject($sysSetting);
return jsonReturn(0,Lang::get("成功"));
}
public function clearCache(): \think\response\Json
{
CacheService::clear();
return jsonReturn(0, Lang::get("成功"));
}
/**
*
* @throws \app\exception\ModelException
*/
public function password(): \think\response\Json
{
$param = $this->request->only([
'status','length','string_type','special_char','change_duration'
]);
try {
validate(SysSettingValidate::class)->scene('pass')->check($param);
} catch (\Exception $e) {
return jsonReturn(-1, $e->getMessage());
}
$sysSetting = new SysSetting();
$status = $param['status'] ?? 2;
unset($param['status']);
$value = json_encode($param);
$where = [
'id' => '120',
'seller_id' => $this->admin['seller_id'],
];
$res = $sysSetting -> updateSysSetting($where,['value'=>$value,'status'=>$status]);
return json($res);
}
/**
* @throws \app\exception\ModelException
*/
public function passInfo(): \think\response\Json
{
$sysSetting = new SysSetting();
$where = [
'id' => '120',
'seller_id' => $this->admin['seller_id'],
];
$res = $sysSetting -> getSysSetting($where);
if(!empty($res['data']['value'])){
$res['data']['value'] = json_decode($res['data']['value'],true);
}
return json($res);
}
}

539
HuoCMS_close_source/app/controller/backend/SystemInstallController.php

@ -0,0 +1,539 @@
<?php
declare (strict_types=1);
namespace app\controller\backend;
use app\BaseController;
use app\exception\InstallException;
use app\model\Admin;
use app\model\Model;
use app\model\Route;
use app\model\Website;
use app\model\WebsiteLang;
use app\model\WebsiteServer;
use app\model\WebsiteSetting;
use app\service\ThemeService;
use app\validate\SystemInstallValidate;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Log;
use think\facade\View;
use think\Validate;
class SystemInstallController extends BaseController
{
/**
* 显示资源列表
*
*/
public function index()
{
if (hcInstalled()) {
return redirect('/admin.php');
}
// 向huocms官网请求是否认证
$domain = request()->host();
if (!empty($domain)) {
$authRes = curlPost(config('system.auth_query_url'), ['domain' => $domain])['data'];
Log::info('auth_query_url:' . $authRes);
}
$year = date('Y', time());
$month = date('m', time());
$day = date('d', time());
View::assign(['year' => $year, 'month' => $month, 'day' => $day]);
return View::fetch(CMS_ROOT . 'data/install/install.html');
}
public function monitor(): string
{
// if (file_exists_case('data/conf/config.php')) {
// @unlink('data/conf/config.php');
// }
$data = [];
$data['phpversion'] = @phpversion();
$data['os'] = PHP_OS;
$tmp = function_exists('gd_info') ? gd_info() : [];
// $server = $_SERVER["SERVER_SOFTWARE"];
// $host = $this->request->host();
// $name = $_SERVER["SERVER_NAME"];
// $max_execution_time = ini_get('max_execution_time');
// $allow_reference = (ini_get('allow_call_time_pass_reference') ? '<font color=green>[√]On</font>' : '<font color=red>[×]Off</font>');
// $allow_url_fopen = (ini_get('allow_url_fopen') ? '<font color=green>[√]On</font>' : '<font color=red>[×]Off</font>');
// $safe_mode = (ini_get('safe_mode') ? '<font color=red>[×]On</font>' : '<font color=green>[√]Off</font>');
$err = 0;
if (empty($tmp['GD Version'])) {
$gd = '/system_file/install/image/success_icon.jpg';
$err++;
} else {
$gd = '/system_file/install/image/error_icon.png ' . $tmp['GD Version'];
}
if (class_exists('pdo')) {
$data['pdo'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['pdo'] = '/system_file/install/image/error_icon.png';
$err++;
}
if (extension_loaded('pdo_mysql')) {
$data['pdo_mysql'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['pdo_mysql'] = '/system_file/install/image/error_icon.png';
$err++;
}
if (extension_loaded('curl')) {
$data['curl'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['curl'] = '/system_file/install/image/error_icon.png';
$err++;
}
if (extension_loaded('gd')) {
$data['gd'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['gd'] = '/system_file/install/image/error_icon.png';
if (function_exists('imagettftext')) {
$data['gd'] .= '/system_file/install/image/error_icon.png';
}
$err++;
}
if (extension_loaded('mbstring')) {
$data['mbstring'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['mbstring'] = '/system_file/install/image/error_icon.png';
if (function_exists('imagettftext')) {
$data['mbstring'] .= '/system_file/install/image/error_icon.png';
}
$err++;
}
if (extension_loaded('fileinfo')) {
$data['fileinfo'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['fileinfo'] = '/system_file/install/image/error_icon.png';
$err++;
}
if (ini_get('file_uploads')) {
$data['upload_size'] = ini_get('upload_max_filesize');
} else {
$data['upload_size'] = '未开启';
$err++;
}
if (function_exists('session_start')) {
$data['session'] = '/system_file/install/image/success_icon.jpg';
} else {
$data['session'] = '/system_file/install/image/error_icon.png';
$err++;
}
if (version_compare(phpversion(), '7.2.0', '>=') && version_compare(phpversion(), '7.0.0', '<') && ini_get('always_populate_raw_post_data') != -1) {
$data['always_populate_raw_post_data'] = '未关闭';
$data['show_always_populate_raw_post_data_tip'] = true;
$err++;
} else {
$data['always_populate_raw_post_data'] = '已关闭';
}
$folders = [
realpath(CMS_ROOT . 'data') . DIRECTORY_SEPARATOR,
realpath(CMS_ROOT . 'runtime') . DIRECTORY_SEPARATOR,
realpath(CMS_ROOT . 'public/themes') . DIRECTORY_SEPARATOR,
realpath(CMS_ROOT . 'public/storage') . DIRECTORY_SEPARATOR,
realpath(CMS_ROOT . 'public/poster_preview') . DIRECTORY_SEPARATOR,
];
$newFolders = [];
foreach ($folders as $dir) {
$testDir = $dir;
sp_dir_create($testDir);
if (sp_testwrite($testDir)) {
$newFolders[$dir]['w'] = true;
} else {
$newFolders[$dir]['w'] = false;
$err++;
}
if (is_readable($testDir)) {
$newFolders[$dir]['r'] = true;
} else {
$newFolders[$dir]['r'] = false;
$err++;
}
if ($newFolders[$dir]['w'] && $newFolders[$dir]['r']) {
$newFolders[$dir]['icon'] = '/system_file/install/image/success_icon.jpg';
} else {
$newFolders[$dir]['icon'] = '/system_file/install/image/error_icon.png';
}
}
$data['err'] = $err;
$data['folders'] = $newFolders;
View::assign($data);
return View::fetch(CMS_ROOT . 'data/install/monitor.html');
}
public function configure(): string
{
return View::fetch(CMS_ROOT . 'data/install/configure.html');
}
public function create(): string
{
$param = request()->param();
if (empty($param['username'])) {
$param['username'] = 'admin@huocms.com';
}
if (empty($param['password'])) {
$param['password'] = 'huocms.com';
}
$dbConfig = [
'type' => 'mysql',
// 连接名
'hostname' => $param['hostname'],
// 用户名
'username' => $param['username'],
// 密码
'password' => $param['password'],
// 端口
'hostport' => $param['hostport'],
// 数据库编码默认采用utf8mb4
'charset' => $param['charset'],
// 数据库表前缀
'prefix' => $param['prefix'],
];
$this->updateDbConfig($dbConfig);
$sql = "CREATE DATABASE IF NOT EXISTS `{$param['database']}` DEFAULT CHARACTER SET " . $param['charset'];
$db = Db::connect('install_db');
$db->execute($sql);
$dbConfig['database'] = $param['database'];
$this->exchangeEnv($dbConfig);
session('install.db_config', $dbConfig);
$sql = hcSplitSql(CMS_ROOT . '/data/install/install.sql', $dbConfig['prefix'], $dbConfig['charset']);
session('install.sql', $sql);
View::assign('sql_count', count($sql));
session('install.error', 0);
session('install.admin_info', [
'name' => $param['admin'],
'account' => $param['email'],
'password' => makePassword($param['admin_pass'])
]);
return View::fetch(CMS_ROOT . 'data/install/create.html');
}
public function install()
{
$dbConfig = session('install.db_config');
$sql = session('install.sql');
if (empty($dbConfig) || empty($sql)) {
return json([
'code' => -1,
'data' => '',
'msg' => '非法安装!'
]);
}
$sqlIndex = $this->request->param('sql_index', 0, 'intval');
$this->updateDbConfig($dbConfig);
$db = Db::connect('install_db');
if ($sqlIndex >= count($sql)) {
return json([
'code' => 200,
'data' => '',
'msg' => '安装完成!'
]);
}
$sqlToExec = $sql[$sqlIndex] . ';';
$result = sp_execute_sql($db, $sqlToExec);
if (!empty($result['error'])) {
return json([
'code' => -1,
'data' => [
'sql' => $sqlToExec,
'exception' => $result['exception']
],
'msg' => '安装失败!'
]);
} else {
return json([
'code' => 0,
'data' => $result,
'msg' => '安装成功!'
]);
}
}
public function exchangeEnv($dbConfig)
{
$envFile = CMS_ROOT . '.env';
$example = CMS_ROOT . '.example.env';
if (file_exists($example)) {
copy($example, $envFile);
} else {
touch($envFile);
$initArray = [
"APP_DEBUG = true",
"APP_HOST = http://localhost",
"",
"[APP]",
"DEFAULT_TIMEZONE = Asia/Shanghai",
"",
"[DATABASE]",
"TYPE = mysql",
"HOSTNAME = 127.0.0.1",
"DATABASE = huo_cms",
"USERNAME = root",
"PASSWORD = ",
"HOSTPORT = 3306",
"CHARSET = utf8mb4",
"DEBUG = true",
"PREFIX = hc_",
"",
"[LANG]",
"default_lang = zh",
];
file_put_contents($envFile, implode(PHP_EOL, $initArray));
}
$merge = [
'app_debug' => true,
'app_host' => request()->domain(),
];
$data = [];
foreach (array_merge($merge, $dbConfig) as $key => $val) {
$key = strtoupper($key);
$data[$key] = $val;
}
$this->updateEnv($envFile, $data);
}
public function updateEnv($envFile, $data = array())
{
$oldEnv = file($envFile);
if (!count($data)) {
return;
}
if (array_keys($data) === range(0, count($data) - 1)) {
return;
}
$pattern = '/([^\=]*)\=[^\n]*/';
$newEnv = [];
foreach ($oldEnv as $line) {
preg_match($pattern, $line, $matches);
if (!count($matches)) {
$newEnv[] = $line;
continue;
}
if (!key_exists(trim($matches[1]), $data)) {
$newEnv[] = $line;
continue;
}
$line = trim($matches[1]) . "={$data[trim($matches[1])]}\n";
$newEnv[] = $line;
}
$newContent = implode('', $newEnv);
file_put_contents($envFile, $newContent);
}
public function userCheck(): \think\response\Json
{
$param = request()->param();
try {
validate(SystemInstallValidate::class)->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
return jsonReturn(0, 'success');
}
public function testPass(): \think\response\Json
{
$param = request()->param();
$dbConfig = [
'type' => 'mysql',
// 连接名
'hostname' => $param['hostname'],
// 数据库名
'username' => $param['username'],
// 密码
'password' => $param['password'],
// 端口
'hostport' => $param['hostport'],
];
$this->updateDbConfig($dbConfig);
$supportInnoDb = false;
try {
$db = Db::connect('install_db');
$engines = $db->query("SHOW ENGINES;");
foreach ($engines as $engine) {
if ($engine['Engine'] == 'InnoDB' && $engine['Support'] != 'NO') {
$supportInnoDb = true;
break;
}
}
} catch (\Exception $e) {
return jsonReturn(-1, '数据库账号或密码不正确!' . $e->getMessage());
}
if (!$supportInnoDb) {
return jsonReturn(-2, '数据库账号密码验证通过,但不支持InnoDb!');
} else {
return jsonReturn(0, 'success');
}
}
public function installCompleteCheck(): \think\response\Json
{
$admin = session("install.admin_info");
if (empty($admin)) {
return jsonReturn(-1, '用户创建失败,请重试');
}
Db::startTrans();
try {
// 创建管理员
$Admin = new Admin();
$admin['seller_id'] = 1;
$admin['status'] = 1;
$admin['group'] = 1;
$res = $Admin->addAdmin($admin)['data'];
$res->role()->attach(1, ['seller_id' => 1]);
session('adminId', $res['id']);
$website = new Website();
$siteParam = [
'title' => '演示站点',
'domain' => request()->host()
];
// 创建站点
// 1. 保存站点到数据库
$res = $website->addWebsite($siteParam);
if ($res['data'] != 1) {
throw new InstallException();
}
// 2. 生成一份默认的站点配置,配置的值为空
$tmpData = config('system.website_setting');
$sysData = [
"setting" => json_encode($tmpData),
"website_id" => $res['data'],
"lang" => "zh"
];
$siteSetting = new WebsiteSetting();
$siteSetting->addWebsiteSetting($sysData);
// 3. 选择站点语言简体中文,服务器为本地服务器
$langData[] = [
'seller_id' => 1,
'website_id' => $res['data'],
'lang_name' => '简体中文',
'lang' => 'zh',
];
$WebsiteLang = new WebsiteLang();
$WebsiteLang->addWebsiteLang($langData);
$serverData = [
'seller_id' => 1,
'website_id' => $res['data'],
'type' => 1,
];
$WebsiteServer = new WebsiteServer();
$WebsiteServer->addWebsiteServer($serverData);
// 4.生成路由
$Route = new Route();
$Route->updateRoute(['seller_id' => 1], ['website_id' => $res['data']]);
$Route->getRoutes($res['data'], 1, 'zh');
// 5.安装模版
$ThemeService = new ThemeService();
$ThemeService->installTheme('demo', $res['data'], 1);
createInstallFile();
session("install.step", 4);
Db::commit();
} catch (InstallException $e) {
@unlink(CMS_ROOT . 'public/system_file/install.lock');
Db::rollback();
dump($e->getLine());
dd($e->getTrace());
return jsonReturn(-3, '安装失败,请清空数据库后重试');
} catch (\Exception $e) {
@unlink(CMS_ROOT . 'public/system_file/install.lock');
Db::rollback();
return jsonReturn(-1, '用户创建失败,请重试' . $e->getMessage());
}
return jsonReturn(0, 'success');
}
public function completeCheck(): \think\response\Json
{
if (session("install.step") == 4) {
return jsonReturn(0, '安装成功');
} else {
return jsonReturn(-1, '安装失败');
}
}
public function complete(): string
{
return View::fetch(CMS_ROOT . 'data/install/complete.html');
}
private function updateDbConfig($dbConfig)
{
$oldDbConfig = config('database');
$oldDbConfig['connections']['install_db'] = $dbConfig;
config($oldDbConfig, 'database');
}
public function write_ini_file($assoc_arr, $path, $has_sections = FALSE): bool
{
$content = "";
if ($has_sections) {
foreach ($assoc_arr as $key => $elem) {
$content .= "[" . $key . "]n";
foreach ($elem as $key2 => $elem2) {
if (is_array($elem2)) {
for ($i = 0; $i < count($elem2); $i++) {
$content .= $key2 . "[] = " . $elem2[$i] . "\r\n";
}
} else if ($elem2 == "") {
$content .= $key2 . " = n";
} else {
$content .= $key2 . " = " . $elem2 . "\r\n";
}
}
}
} else {
foreach ($assoc_arr as $key => $elem) {
if (is_array($elem)) {
for ($i = 0; $i < count($elem); $i++) {
$content .= $key . "[] = " . $elem[$i] . "\r\n";
}
} else if ($elem == "") {
$content .= $key . " = n";
} else {
$content .= $key . " = " . $elem . "\r\n";
}
}
}
if (!$handle = fopen($path, 'w')) {
return false;
}
if (!fwrite($handle, $content)) {
return false;
}
fclose($handle);
return true;
}
}

169
HuoCMS_close_source/app/controller/backend/TagController.php

@ -0,0 +1,169 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelException;
use app\model\RecycleBin;
use app\model\Tag;
use app\validate\TagValidate;
use Overtrue\Pinyin\Pinyin;
use think\exception\ValidateException;
use think\facade\Lang;
class TagController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(Tag $tag): \think\response\Json
{
$websiteId = (int)input('param.website_id');
if(!$websiteId){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$lang = input('lang');
if(empty($lang)){
$lang = 'zh';
}
$limit = $this->setLimit();
$title = input('title') ?: '';
$where = [
['seller_id', '=' ,$this->admin['seller_id']],
['website_id' ,'=', $websiteId],
['lang','=',$lang],
['is_del','=',1],
];
if($title){
array_push($where,['title','like','%'.$title.'%']);
}
try{
$tagList = $tag->where($where)->paginate($limit)->each(function(&$item){
$contentNum = $item->subContent()->where('is_del',1)->count();
$item -> article_count = $contentNum;
$item -> save();
});
}catch(\Exception $e){
throw new ModelException($e->getMessage());
}
return json(['code'=>0,'total'=>$tagList->total(),'msg'=>Lang::get('成功'),'data'=>$tagList->all()]);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(Tag $tag): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(TagValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$param['unique_tag'] = $param['seller_id'] . '-' . $param['website_id'] . '-' . $param['lang'] .'-' . $param['title'];
$tag->saveUnique(['unique_tag'=> $param['unique_tag'],'is_del'=>1],Lang::get('标签名称已经存在'));
$pinyin = new Pinyin();
$param['first_letter'] = strtoupper(substr($pinyin->abbr($param['title']),0,1));
$param = $this->setSEO($param);
$res = $tag -> addTag($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException*@throws \app\exception\ModelNotUniqueException
* @throws \app\exception\ModelNotUniqueException
*/
public function update(Tag $tag): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(TagValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$param = $this->setSEO($param);
$param['unique_tag'] = $this->admin['seller_id'] . '-' . $param['website_id'] . '-' . $param['lang'] .'-'. $param['title'];
$tag->updateUnique(['unique_tag' => $param['unique_tag']],$param['id'],Lang::get('标签名称已经存在'));
$pinyin = new Pinyin();
$param['first_letter'] = strtoupper(substr($pinyin->abbr($param['title']),0,1));
$res = $tag -> updateTag($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function delete(Tag $Tag,RecycleBin $recycleBin): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('标签ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id'],
];
$tag = $Tag->getTag($where)['data'];
// 复制删除内容到回收站表
$binData = [
'seller_id' => $this->admin['seller_id'],
'object_id' => $id,
'sub_id' => '',
'module_id' => '',
'table_name' => 'tag',
'title' => $tag['title'],
'admin_id' => $this->admin['seller_id'],
'name' => $this->admin['name'],
];
$recycleBin -> addRecycleBin($binData);
$res = $Tag -> softDelTag($where);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 配置SEO
* @param $param
* @return mixed
*/
public function setSEO($param)
{
if(empty($param['seo_title'])){
$param['seo_title'] = $param['title'];
}
if(empty($param['seo_keywords'])){
$param['seo_keywords'] = $param['title'];
}
if(empty($param['seo_description'])){
$param['seo_description'] = $param['title'];
}
return $param;
}
}

277
HuoCMS_close_source/app/controller/backend/ThemeController.php

@ -0,0 +1,277 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelEmptyException;
use app\exception\ModelException;
use app\model\Theme;
use app\model\ThemeFile;
use app\service\ThemeService;
use app\validate\ThemeValidate;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Lang;
use think\response\Json;
class ThemeController extends BaseController
{
/**
* 已安装模板
*
* @return Json
* @throws ModelException
*/
public function index(Theme $theme): Json
{
$website_id = (int)input('param.website_id');
if(!$website_id){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$lang = input('param.lang') ?: config('lang.default_lang');
$where = [
['seller_id','=',$this->admin['seller_id']],
['website_id','=',$website_id],
['lang','=',$lang]
];
$limit = $this->setLimit();
$themeList = $theme->getThemeList($where,$limit);
return json(pageReturn($themeList));
}
/**
* 模板完整更新
*
* @return Json
* @throws ModelException*@throws \app\exception\ModelEmptyException
* @throws ModelEmptyException
*/
public function update(ThemeService $themeService): Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(ThemeValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$suffix = config('view.view_suffix');
return $themeService->updateTheme($param['theme_id'],$param['website_id'],$this->admin['seller_id'],$suffix);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 系统模版
*
* @param Theme $themeModel
* @return Json
*/
public function install(Theme $themeModel): Json
{
$themesDirs = hcScanDir("themes/hc_original/*", GLOB_ONLYDIR);
$themes = [];
foreach ($themesDirs as $dir) {
$manifest = "themes/hc_original/$dir/manifest.json";
if (hcFileExist($manifest)) {
$manifest = file_get_contents($manifest);
$theme = json_decode($manifest, true);
}
$theme['theme'] = $dir;
$themes[] = $theme;
}
return jsonReturn(0,Lang::get('成功'),$themes);
}
/**
* 模版安装
*
* @throws ModelException
*/
public function installTheme(ThemeService $service): Json
{
if ($this->request->isPost()) {
set_time_limit(300);
$param = input('post.');
try {
validate(ThemeValidate::class)->scene('installTheme')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
$suffix = config('view.view_suffix');
return $service->installTheme($param['theme'],$param['website_id'],$this->admin['seller_id'],$suffix,$param['lang']);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 卸载模板
* @throws ModelEmptyException
* @throws ModelException
*/
public function uninstall(ThemeService $service): Json
{
if ($this->request->isPost()) {
$param = input('post.');
try {
validate(ThemeValidate::class)->scene('uninstall')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
return $service->uninstallTheme($param['theme_id'],$param['website_id'],$this->admin['seller_id']);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 模板文件
*
* @throws ModelException
*/
public function tmpFile(ThemeFile $ThemeFile): Json
{
$param = input('param.');
try {
validate(ThemeValidate::class)->scene('tmpFile')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$limit = $this->setLimit();
$where = [
'seller_id' => $this->admin['seller_id'],
'theme_id' => $param['theme_id'],
'website_id' => $param['website_id'],
];
$res = $ThemeFile -> getThemeFileList($where,'id,name,file,real_path',$limit);
return json(pageReturn($res));
}
/**
*
* @param ThemeFile $ThemeFile
* @return Json
* @throws ModelException
*/
public function templateFile(ThemeFile $ThemeFile): Json
{
$param = input('param.');
try {
validate(ThemeValidate::class)->scene('templateFile')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$theme = new Theme();
$activeTheme = $theme->getActiveTheme(['seller_id'=>$this->admin['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang'],'is_active'=>1])['data'];
if(empty($activeTheme)){
return jsonReturn(-1,Lang::get('未安装或启用模版'));
}
$where = [
'seller_id' => $this->admin['seller_id'],
'theme_id' => $activeTheme['id'],
'website_id' => $param['website_id'],
];
$template = $ThemeFile -> getAllCustomArrayData($where)['data'];
return jsonReturn(0,Lang::get('成功'),$template);
}
/**
* 启用模版
*
* @throws ModelException
*/
public function active(Theme $Theme): Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(ThemeValidate::class)->scene('active')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
Db::startTrans();
try{
// 将所有模版暂停启用
$Theme->updateTheme(['seller_id'=>$this->admin['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']],['is_active'=>2]);
// 启用当前模版
$res = $Theme->updateTheme(['id'=>$param['theme_id'],'seller_id'=>$this->admin['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']],['is_active'=>1]);
Db::commit();
}catch (\Exception $e){
Db::rollback();
return jsonReturn(-3,Lang::get('模版安装启用错误'));
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 所有目录
* @throws ModelEmptyException
* @throws ModelException
*/
public function allFilePath(ThemeService $service): Json
{
$param = input('param.');
try {
validate(ThemeValidate::class)->scene('allFilePath')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
return $service->filesPath($param['website_id'],$param['lang']);
}
public function allFiles(ThemeService $service): Json
{
$param = input('param.');
try {
validate(ThemeValidate::class)->scene('allFiles')->check($param);
}catch (ValidateException $e){
return jsonReturn(-1,$e->getError());
}
return $service->files($param['path'],(int)$param['website_id'],$param['lang']);
}
public function dealWithImg(): Json
{
$sourcePath = input('post.source');
$terminalPath = input('post.terminal');
$sourceFiles = glob($sourcePath.'/*');
$tmpFiles = [];
foreach ($sourceFiles as $sourceFile) {
$key = pathinfo($sourceFile,PATHINFO_FILENAME);
$ext = pathinfo($sourceFile,PATHINFO_EXTENSION);
$tmpFiles[$key] = $ext;
}
$terminalFiles = glob($terminalPath.'/*');
$termFiles = [];
foreach ($terminalFiles as $val) {
$key = pathinfo($val,PATHINFO_FILENAME);
$ext = pathinfo($val,PATHINFO_EXTENSION);
$termFiles[$key] = $ext;
}
foreach ($termFiles as $key => $term){
if($term != $tmpFiles[$key]){
$formName = $terminalPath .'/' . $key . '.' . $term;
$toName = $terminalPath.'/' . $key . '.' . $tmpFiles[$key];
rename($formName,$toName);
}
}
return jsonReturn(0,'success');
}
public function delete(ThemeService $service): Json
{
$theme = input('param.theme');
if(empty($theme)){
return jsonReturn(-1,Lang::get('模版名称不能为空'));
}
$res = $service -> delOriginalTheme($theme);
return json($res);
}
}

206
HuoCMS_close_source/app/controller/backend/ThemeFileController.php

@ -0,0 +1,206 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\exception\ModelEmptyException;
use app\model\Theme;
use app\model\ThemeFile;
use app\service\CacheService;
use app\service\ComponentDataService;
use app\service\ThemeFileService;
use app\validate\ThemeFileValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class ThemeFileController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(ThemeFile $themeFile): \think\response\Json
{
$where = [
'seller_id' => $this->admin['seller_id'],
'is_del' => 1,
];
$limit = $this->setLimit();
$themeFileList = $themeFile->getThemeFileList($where,$limit);
return json(pageReturn($themeFileList));
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function save(ThemeFile $themeFile): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(ThemeFileValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// TODO
// 其他逻辑
$res = $themeFile -> addThemeFile($param);
CacheService::deleteRelationCacheByObject($themeFile);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
*/
public function read(ThemeFileService $themeFileService): \think\response\Json
{
$path = input('param.path');
if (strpos($path, '..') !== false) {
return jsonReturn(-1,Lang::get('文件路径有误'));
}
if(empty($path)){
return jsonReturn(-1,Lang::get('文件路径不能为空'));
}
// 不是可编辑文件
$ext = pathinfo($path, PATHINFO_EXTENSION);
if (!in_array($ext, ['js', 'json', 'html', 'css', 'less', 'htm', 'sass'])) {
return jsonReturn(-1,Lang::get('不支持的编辑文件'));
}
return $themeFileService->readSource($path);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \ReflectionException
*/
public function update(ThemeFileService $themeFileService): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(ThemeFileValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
return $themeFileService -> updateResource($param['path'],$param['content']);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 更新单个文件
* @param ThemeFileService $themeFileService
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function singleUpdate(ThemeFileService $themeFileService): \think\response\Json
{
if(request()->isPost()){
$path = input('param.path');
$path = str_replace('\\', '/', $path);
$path = trim($path,'/');
if(empty($path)){
return jsonReturn(-1,Lang::get('文件路径不能为空'));
}
$res = $themeFileService -> updateThemeFile($path);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 模板设计
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function design(ThemeFileService $themeFileService)
{
$param = input('param.');
try {
validate(ThemeFileValidate::class)->scene('design')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$url = '/';
if(!empty($param['url'])){
$url = $param['url'];
}
define('ADMIN_SITE_ID',$param['website_id']);
define('ADMIN_SELLER_ID',$this->admin['seller_id']);
return $themeFileService -> design($param['theme_id'],$param['website_id'],$this->admin['seller_id'],$url);
}
/**
* @throws ModelEmptyException
* @throws \app\exception\ModelException
*/
public function compData(ThemeFileService $themeFileService)
{
$param = input('param.');
try {
validate(ThemeFileValidate::class)->scene('design')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
define('ADMIN_SITE_ID',$param['website_id']);
define('ADMIN_SELLER_ID',$this->admin['seller_id']);
define('ADMIN_LANG',$param['lang']);
return $themeFileService -> compData($this->admin['seller_id'],$param['theme_id'],$param['website_id'],$param['url'],$param['block']);
}
/**
* @throws \app\exception\ModelException
*/
public function active(Theme $Theme,ThemeFile $ThemeFile): \think\response\Json
{
$siteId = (int)input('website_id');
$lang = input('lang');
if(empty($siteId)){
return jsonReturn(-1,Lang::get('站点ID不能为空'));
}
$themeWhere = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
'lang' => $lang,
'is_active' => 1
];
try{
$theme = $Theme->getTheme($themeWhere)['data'];
}catch (ModelEmptyException $e){
return jsonReturn(-1,Lang::get('该站点没有启用的模板'));
}
$fileWhere = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
'theme_id' => $theme['id'],
];
$list = $ThemeFile->getThemeAllFile($fileWhere);
return json($list);
}
public function singleUpdateFile()
{
}
}

84
HuoCMS_close_source/app/controller/backend/UploadController.php

@ -0,0 +1,84 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\SysSetting;
use app\service\upload\Upload;
use think\facade\Lang;
use think\Request;
class UploadController extends BaseController
{
protected $type = [
'file' => 4,
'image' => 2,
'video' => 3,
'mp3' => 5,
'zip' => 1,
];
/**
* 保存新建的资源
*
* @param \think\Request $request
* @return \think\Response
* @throws \app\exception\ModelException
*/
public function save(Request $request): \think\Response
{
if(request()->isPost()){
$file = request()->file('file');
if(empty($file)){
return jsonReturn(-2,Lang::get('文件不能为空'));
}
$seller_id = $this->admin['seller_id'];
// 查看文件类型
$fileName = $file->getOriginalName();
$fileExt = $file->getOriginalExtension();
$file_type = fileFormat($fileName);
$fileType = $this->type[$file_type];
// 附件大小和类型验证
// 获取上传配置
$Settings = new SysSetting();
$uploadSetting = $Settings->getAllCustomArrayData(['parent_id'=>1,'group'=>'upload','status'=>1],'id desc','id,group,title,value')['data'];
$uploadSetting = getColumnForKeyArray($uploadSetting,'title');
$limitSize = $uploadSetting[$file_type.'_size']['value'] * 1024; // byte
$fileSize = $file->getSize(); // 单位byte
if($fileSize > $limitSize){
return jsonReturn(-1,Lang::get('文件过大,请修改上传限制或者替换小的文件'));
}
$extArr = explode(',',$uploadSetting[$file_type.'_ext']['value']);
if(!in_array($fileExt,$extArr)){
return jsonReturn(-2,Lang::get('文件格式错误,请重新上传'));
}
// 文件信息提取
$where = [
'seller_id' => $seller_id,
'group' => 'upload',
'title' => 'storage'
];
$place = new SysSetting();
$type = $place->getSysSetting($where)['data']->toArray()['value'];
$upload = new Upload();
$info = $upload->create($file,$seller_id, $type,$file_type);
if ($info) {
$uploadInfo = $upload->getUploadFileInfo();
if ($uploadInfo['code'] == 0) {
$uploadInfo['data']['type'] = $fileType;
$uploadInfo['data']['size'] = round($fileSize / 1024,2);
$uploadInfo['data']['mime_type'] = $fileExt;
}
return json($uploadInfo);
}else{
return jsonReturn(-1, Lang::get('上传失败请重新尝试'));
}
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

287
HuoCMS_close_source/app/controller/backend/WebsiteController.php

@ -0,0 +1,287 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Admin;
use app\model\Route;
use app\model\Website;
use app\model\WebsiteLang;
use app\model\WebsiteSetting;
use app\service\CacheService;
use app\service\SitemapService;
use app\service\WebsiteLangService;
use app\validate\WebsiteValidate;
use app\service\WebsiteService;
use think\facade\Db;
use think\exception\ValidateException;
use think\facade\Lang;
class WebsiteController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\Response
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function index(Website $website): \think\response\Json
{
$where = [
['seller_id','=', $this->admin['seller_id']],
];
$uid = $this -> admin['uid'];
$authSiteId = [];
if($uid != 1){
$admin = new Admin();
$adminInfo = $admin -> getAdmin(['seller_id' => $this->admin['seller_id'],'id' => $uid],['role.website'])['data'] -> toArray();
$authSite = array_column($adminInfo['role'],'website');
foreach($authSite as $val){
$authSiteId = array_merge($authSiteId,array_column($val,'id'));
}
$authSiteId = array_unique($authSiteId);
$where[] = ['id','in',$authSiteId];
}
$websiteList = $website->getAllCustomArrayData($where)['data'];
$websiteList = makeTree($websiteList);
return jsonReturn(0,Lang::get('成功'),$websiteList);
}
/**
* 保存新建的资源
*
* @return \think\Response
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(Website $website): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(WebsiteValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$website->saveUnique(['seller_id'=>$this->admin['seller_id'],'title'=>$param['title']],'网站名称已存在');
$param['seller_id'] = $this->admin['seller_id'];
$param['status'] = 1;
Db::startTrans();
try{
// 1. 保存站点到数据库
$res = $website -> addWebsite($param);
if($param['parent_id'] == 0){
$this->selfData($res['data'],$param['domain'],$param['parent_id']);
}else{
$this->sonData($res['data'],$param['domain'],$param['parent_id']);
}
CacheService::deleteRelationCacheByObject($website);
Db::commit();
}catch(\Exception $e){
Db::rollback();
return jsonReturn(-5,$e->getMessage());
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* @throws \app\exception\ModelException
*/
public function selfData($siteId, $domain, $parentId)
{
// 2. 生成一份默认的站点配置,配置的值为空
$tmpData = config('system.website_setting');
$sysData = [
"setting"=> json_encode($tmpData),
"website_id"=>$siteId,
"lang"=>config('lang.default_lang')
];
$siteSetting = new WebsiteSetting();
$siteSetting -> addWebsiteSetting($sysData);
// 3. 选择站点语言简体中文,服务器为本地服务器
$langData[]= [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
'lang_name' => '简体中文',
'lang' => config('lang.default_lang'),
];
$WebsiteLang = new WebsiteLang();
$WebsiteLang->addWebsiteLang($langData);
}
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function sonData($siteId, $domain, $parentId)
{
$website = new Website();
// 1. 写入父站点的路由
$parent = $website -> getWebsite(['id'=>$parentId,'seller_id'=>$this->admin['seller_id']])['data'];
$parentDomain = $parent['domain'];
$start = $parentId . '_' ;
$path = CMS_ROOT . 'route';
$files = glob("$path/$start*.php");
foreach ($files as $file){
$tmpStr = str_replace($parentDomain,$domain,file_get_contents($file));
$basename = str_replace($start,$siteId.'_',basename($file));
file_put_contents($path . DIRECTORY_SEPARATOR . $basename,$tmpStr);
}
// 父站点路由copy一份到子站点保存到数据库
$route = new Route();
$routes = $route -> getAllCustomArrayData(['seller_id'=>$this->admin['seller_id'],'website_id'=>$parentId])['data'];
foreach ($routes as &$val){
$val['website_id'] = $siteId;
$val['seller_id'] = $this->admin['seller_id'];
unset($val['id']);
unset($val['create_time']);
unset($val['update_time']);
}
unset($val);
$route->addAllCustomData($routes);
// 2. 写入语言+配置
$WebsiteLang = new WebsiteLang();
$parentLang = $WebsiteLang->getAllCustomArrayData(['id'=>$parentId,'seller_id'=>$this->admin['seller_id']])['data'];
$lang = array_column($parentLang,'lang');
$websiteLangService = new WebsiteLangService();
$websiteLangService->setSiteLang(['seller_id'=>$this->admin['seller_id'],'site_id'=>$siteId,'lang'=>$lang]);
}
/**
* 显示指定的资源
*
* @return \think\Response
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(Website $website): \think\response\Json
{
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$where = [
'id' => $id,
'seller_id' => $this->admin['seller_id']
];
$res = $website->getWebsite($where);
return json($res);
}
/**
* 设置网站状态
* @param Website $website
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function setStatus(Website $website)
{
if(!request()->isPost()){
return jsonReturn(-3,Lang::get('请求方法错误'));
}
$param = $this->request->only(['id' => 0, 'status' => 1]);
try {
validate(WebsiteValidate::class)->scene('setStatus')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
if ($param['status'] == 2) {
$childWhere = [
'parent_id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$website->updateWebsite($childWhere, ['status' => $param['status']]);
}
$res = $website->updateWebsite($where, ['status' => $param['status']]);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
* @throws \ReflectionException
*/
public function update(Website $website): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(WebsiteValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'id' => $param['id'],
'seller_id' => $this->admin['seller_id'],
];
$site = $website->getWebsite($where)['data'];
if($param['domain'] != $site['domain']){
// 修改路由域名配置
$routePath = app()->getRootPath() . 'route'. DIRECTORY_SEPARATOR;
$fileArr = hcScanDir($routePath.'*');
foreach($fileArr as $val){
$siteId = $param['id'];
$pattern = '/^'.$siteId.'_/';
if(is_file($routePath . $val) && preg_match($pattern,$val)){
$conArr = str_replace($site['domain'],$param['domain'],file_get_contents($routePath.$val));
file_put_contents($routePath.$val,$conArr);
}
}
}
$res = $website -> updateWebsite($where,$param);
CacheService::deleteRelationCacheByObject($website);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 删除指定资源
*
*/
public function delete(WebsiteService $websiteService): \think\response\Json
{
if(request()->isPost()){
$id = (int)input('id');
if(!$id){
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$res = $websiteService->deleteSite($id,$this->admin['seller_id']);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* xml文件
* @param SitemapService $sitemapService
* @return \think\response\Json
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function sitemap(SitemapService $sitemapService): \think\response\Json
{
$siteId = (int)$this->request->param('website_id');
$sellerId = $this->admin['seller_id'];
$res = $sitemapService -> makeSitemap($siteId,$sellerId);
return json($res);
}
}

86
HuoCMS_close_source/app/controller/backend/WebsiteLangController.php

@ -0,0 +1,86 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Model;
use app\model\Website;
use app\model\WebsiteLang;
use app\model\WebsiteSetting;
use app\service\CacheService;
use app\service\WebsiteLangService;
use app\validate\WebsiteLangValidate;
use think\Cookie;
use think\exception\ValidateException;
use think\facade\Lang;
class WebsiteLangController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function index(WebsiteLang $websiteLang): \think\response\Json
{
$siteId = (int)input('site_id');
if(!$siteId){
return jsonReturn(-1, Lang::get('站点ID不能为空'));
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $siteId,
];
$websiteLangList = $websiteLang->getAllCustomArrayData($where,'id asc');
return json($websiteLangList);
}
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \ReflectionException
*/
public function save(WebsiteLangService $websiteLangService): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(WebsiteLangValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$res = $websiteLangService -> setSiteLang($param);
CacheService::deleteRelationCacheByObject(WebsiteLang::class);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 系统语言
* @return \think\response\Json
*/
public function system(): \think\response\Json
{
if(request()->isGet()){
$lang = config('system.lang');
return json(['code'=>0,'msg'=>'success','data'=>$lang]);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 切换语言
*/
public function changeLang(\think\Lang $lang,Cookie $cookie){
$val = $this->request->param('lang/s','');
$cookie->set($lang->getConfig()['cookie_var'], $val);
return jsonReturn(0,Lang::get('操作成功'));
}
}

90
HuoCMS_close_source/app/controller/backend/WebsiteServerController.php

@ -0,0 +1,90 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\WebsiteServer;
use app\validate\WebsiteServerValidate;
use think\exception\ValidateException;
use think\facade\Lang;
class WebsiteServerController extends BaseController
{
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function save(WebsiteServer $websiteServer): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(WebsiteServerValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$res = $websiteServer -> addWebsiteServer($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(WebsiteServer $websiteServer): \think\response\Json
{
$siteId = (int)input('site_id');
if(!$siteId){
// 修改错误消息
return jsonReturn(-1,Lang::get('网站ID不能为空'));
}
$where = [
'website_id' => $siteId,
'seller_id' => $this->admin['seller_id']
];
$res = $websiteServer->getWebsiteServer($where);
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(WebsiteServer $websiteServer): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(WebsiteServerValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
];
unset($param['website_id']);
$res = $websiteServer -> updateWebsiteServer($where,$param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

125
HuoCMS_close_source/app/controller/backend/WebsiteSettingController.php

@ -0,0 +1,125 @@
<?php
declare (strict_types = 1);
namespace app\controller\backend;
use app\model\Attachment;
use app\model\Model;
use app\model\WebsiteSetting;
use app\validate\WebsiteSettingValidate;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Cookie;
use think\facade\Lang;
class WebsiteSettingController extends BaseController
{
/**
* 保存新建的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelNotUniqueException
*/
public function save(WebsiteSetting $websiteSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
// 数据验证
try{
validate(WebsiteSettingValidate::class)->scene('save')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$param['seller_id'] = $this->admin['seller_id'];
$param['setting'] = json_encode($param['setting']);
$websiteSetting->saveUnique(['seller_id'=>$param['seller_id'],'website_id'=>$param['website_id'],'lang'=>$param['lang']],'相同配置已经存在,请编辑');
$res = $websiteSetting -> addWebsiteSetting($param);
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
/**
* 显示指定的资源
*
* @return \think\response\Json
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function read(WebsiteSetting $websiteSetting,Attachment $attachment): \think\response\Json
{
$param = input('param.');
// 数据验证
try{
validate(WebsiteSettingValidate::class)->scene('read')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang'],
];
$cacheKey = $this->admin['seller_id'] .'_'.$param['website_id'] .'_'. $param['lang'] . '_website_cache_key';
Cache::delete($cacheKey);
$res = $websiteSetting->getWebsiteSetting($where);
$res['data'] = $res['data']->toArray();
$res['data']['setting'] = json_decode($res['data']['setting'],true);
if(!empty($res['data']['setting']['logo'])){
$attach = $attachment->getAttachment(['id'=>$res['data']['setting']['logo'],'seller_id'=>$this->admin['seller_id']])['data'];
if(!empty($attach)){
$res['data']['setting']['logo'] = $attach;
}
}
if(!empty($res['data']['setting']['wechat_code'])){
$attach = $attachment->getAttachment(['id'=>$res['data']['setting']['wechat_code'],'seller_id'=>$this->admin['seller_id']])['data'];
if(!empty($attach)){
$res['data']['setting']['wechat_code'] = $attach;
}
}
if(!empty($res['data']['setting']['dark_logo'])){
$attach = $attachment->getAttachment(['id'=>$res['data']['setting']['dark_logo'],'seller_id'=>$this->admin['seller_id']])['data'];
if(!empty($attach)){
$res['data']['setting']['dark_logo'] = $attach;
}
}
return json($res);
}
/**
* 保存更新的资源
* @return \think\response\Json
* @throws \app\exception\ModelException
*/
public function update(WebsiteSetting $websiteSetting): \think\response\Json
{
if(request()->isPost()){
$param = input('post.');
try {
validate(WebsiteSettingValidate::class)->scene('update')->check($param);
} catch (ValidateException $e) {
return jsonReturn(-1, $e->getError());
}
$where = [
'seller_id' => $this->admin['seller_id'],
'website_id' => $param['website_id'],
'lang' => $param['lang'],
];
$setting = json_encode($param['setting']);
$res = $websiteSetting -> updateWebsiteSetting($where,['setting'=>$setting]);
$siteCacheKey = $this->admin['seller_id'] .'_'.$param['website_id'] .'_'. $param['lang'] . '_website_cache_key';
Cache::delete($siteCacheKey);
if(config('lang')['use_cookie']){
Cookie::set(config('lang')['cookie_var'],$param['lang']);
}
return json($res);
}
return jsonReturn(-3,Lang::get('请求方法错误'));
}
}

333
HuoCMS_close_source/app/controller/frontend/BaseController.php

@ -0,0 +1,333 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\BaseController as AppBaseController;
use app\model\Theme;
use app\model\VisitLog;
use app\model\Website;
use app\service\ApiService;
use think\facade\Cache;
use think\facade\View;
use Overtrue\PHPOpenCC\OpenCC;
class BaseController extends AppBaseController
{
protected $rootDomain;
protected $domain;
protected $siteId;
protected $sellerId;
protected $theme;
protected $lang;
protected $realLang;
protected $viewBase;
protected $settingData;
protected $parentSiteId;
protected $realSiteId;
protected $viewSiteId;
protected $preview;
/**
* @throws \app\exception\ModelException
* @throws \Exception
*/
public function initialize()
{
$this->setCommonParam();
$this->getRootDomain();
$this->setRealSiteId();
$this->getActiveTheme();
$this->setVisitedData();
parent::initialize();
}
/**
* @throws \app\exception\ModelException
*/
public function setCommonParam()
{
// 更新版本标识
updateVersion();
$domain = $this->request->host();
$Website = new Website();
$website = $Website->getWebsiteByDomain($domain,'id,domain,seller_id,parent_id,status')['data'];
if ($website['status'] == 2) {
$this->to404();
}
// 是否为预览状态
$historyViewTime = session('history-view');
$preview = $this->request->param('preview', '');
if (!empty($preview)) {
if ((time() - $historyViewTime) < 30 * 60) {
// 30分钟内可预览
$this->preview = 1;
} else {
header('Location: /');
return;
}
}
$this->domain = $domain;
$this->siteId = $website['id'];
$this->parentSiteId = $website['parent_id'];
$this->sellerId = $website['seller_id'];
$this->realLang = $this->setLang();
$this->lang = $this->setRealLang();
$this->viewBase = config('view.view_dir_name');
define('INDEX_SITE_ID',$this->siteId);
define('INDEX_SELLER_ID',$this->sellerId);
define('INDEX_LANG',$this->lang);
}
public function getRootDomain()
{
$rootDomain = $this->request->rootDomain();
if( $rootDomain === 'com.cn'){
$domainArr = explode('.',$this->domain);
array_shift($domainArr);
$this->rootDomain = implode('.',$domainArr);
}else{
$this->rootDomain = $rootDomain;
}
}
/**
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function getActiveTheme()
{
$Theme = new Theme();
$theme = $Theme->getActiveTheme(['seller_id'=>$this->sellerId,'website_id'=>$this->viewSiteId,'lang'=>$this->lang,'is_active'=>1])['data']->toArray();
$cacheKey = $this->sellerId .'_'.$this->siteId .'_'. $this->lang . '_website_cache_key';
$settingData = Cache::get($cacheKey);
if(empty($settingData)){
$settingData = ApiService::setWebsiteSetting($this->sellerId,$this->siteId,$this->lang);
}
$this->settingData = $settingData;
if(isMobile() && !empty($settingData['common_template']) && $settingData['common_template'] == 2){
$this->theme = 'm_' . $theme['theme'];
}else{
$this->theme = $theme['theme'];
}
}
/**
* @throws \app\exception\ModelException
*/
public function setRealSiteId()
{
$siteId = $this->siteId;
$Theme = new Theme();
$theme = $Theme->getActiveTheme(['seller_id'=>$this->sellerId,'website_id'=>$siteId,'lang'=>$this->lang,'is_active'=>1])['data'];
$this->viewSiteId = $siteId;
// 本站点没有安装启用模板,页面加载用父级的模板
if ($this->parentSiteId && empty($theme)){
$this->viewSiteId = $this->parentSiteId;
}
if($this->parentSiteId){
$siteId = $this->parentSiteId;
}
define('INDEX_REAL_SITE_ID',$siteId);
return $this->realSiteId = $siteId;
}
public function setRealLang(): string
{
return $this->realLang == config('lang.traditional_chinese') ? 'zh' : $this->realLang;
}
public function setLang(): string
{
return getLang();
}
protected function assign($name,$value = ''): \think\View
{
return View::assign($name, $value);
}
/**
* 加载模板输出
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @return mixed
*/
protected function fetch(string $template = '', array $vars = [])
{
$template = $this->parseTemplate($template);
$this->_initializeView($this->viewSiteId,$this->lang,$this->theme);
$html = View::fetch($template, $vars);
$replace = <<<EOL
<script id="baseJs" src="/system_file/js/base.min.js"></script>
</head>
EOL;
$html = str_replace('</head>', $replace, $html);
if($this->realLang == config('lang.traditional_chinese')){
$html = OpenCC::s2tw($html);
}
return $html;
}
/**
* 加载模板输出(system_file)
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @return mixed
*/
protected function fetchSystem(string $template = '', array $vars = [])
{
$template = $this->parseTemplateSystem($template);
$this->_initializeViewSystem($this->viewSiteId,$this->lang,$this->theme);
$html = View::fetch($template, $vars);
$replace = <<<EOL
<script id="baseJs" src="/system_file/js/base.min.js"></script>
</head>
EOL;
$html = str_replace('</head>', $replace, $html);
if($this->realLang == config('lang.traditional_chinese')){
$html = OpenCC::s2tw($html);
}
return $html;
}
/**
* 定位模板
* @param $template
* @return string
*/
private function parseTemplate($template): string
{
$path = CMS_ROOT . $this->viewBase . DIRECTORY_SEPARATOR . $this->viewSiteId.DIRECTORY_SEPARATOR .$this->lang.DIRECTORY_SEPARATOR.$this->theme;
if (!empty($this->preview)) {
$path = CMS_ROOT . 'public/themes/preview/'.$this->theme;
}
$ext = getFileExt($template);
$path .= DIRECTORY_SEPARATOR . ltrim($template,'/');
if( $ext != config('view.view_suffix')){
$path .= '.'.config('view.view_suffix');
}
return $path ;
}
/**
* 定位模板
* @param $template
* @return string
*/
private function parseTemplateSystem($template): string
{
$path = CMS_ROOT . 'public/system_file' . DIRECTORY_SEPARATOR;
$ext = getFileExt($template);
$path .= DIRECTORY_SEPARATOR . ltrim($template,'/');
if( $ext != config('view.view_suffix')){
$path .= '.'.config('view.view_suffix');
}
return $path ;
}
/**
* 常量替换
* @param $siteId
* @param $lang
* @param $themeName
*/
protected function _initializeView($siteId,$lang,$themeName)
{
if (!empty($this->preview)) {
$viewReplaceStr = [
'__TMPL__' => "/themes/preview/{$themeName}",
'__STATIC__' => empty($this->settingData['static_file']) ? "/themes/preview/{$themeName}/static" : $this->settingData['static_file'] ,
];
View::engine()->config([
'view_path' => CMS_ROOT . '/public/themes/preview/' .$this->theme . '/',
'tpl_replace_string' => $viewReplaceStr,
'display_cache' => false,
'tpl_cache' => false,
]);
} else {
$viewReplaceStr = [
'__TMPL__' => "/themes/website/{$siteId}/{$lang}/{$themeName}",
'__STATIC__' => empty($this->settingData['static_file']) ? "/themes/website/{$siteId}/{$lang}/{$themeName}/static" : $this->settingData['static_file'] ,
];
View::engine()->config([
'view_path' => CMS_ROOT . $this->viewBase . DIRECTORY_SEPARATOR . $siteId. DIRECTORY_SEPARATOR .$this->lang.DIRECTORY_SEPARATOR.$this->theme .DIRECTORY_SEPARATOR,
'tpl_replace_string' => $viewReplaceStr,
'display_cache' => false,
'tpl_cache' => false,
]);
}
}
/**
* 常量替换
* @param $siteId
* @param $lang
* @param $themeName
*/
protected function _initializeViewSystem($siteId,$lang,$themeName)
{
$viewReplaceStr = [
'__TMPL__' => "/themes/website/{$siteId}/{$lang}/{$themeName}",
'__STATIC__' => empty($this->settingData['static_file']) ? "/themes/website/{$siteId}/{$lang}/{$themeName}/static" : $this->settingData['static_file'] ,
];
View::engine()->config([
'view_path' => CMS_ROOT . 'public/system_file' . DIRECTORY_SEPARATOR,
'tpl_replace_string' => $viewReplaceStr,
'display_cache' => false,
'tpl_cache' => false,
]);
}
/**
* @throws \Exception
*/
private function setVisitedData()
{
$VisitLog = new VisitLog();
$ip = request()->ip();
$agent = !empty(request()->header()['user-agent']) ? request()->header()['user-agent'] : '未知设备';
$address = getLocationByIp($ip,2);
if(empty($address['province'])){
$area = "内网ip";
}else{
$area = $address['province']."-".$address['city'];
}
$url = $this->request->domain().$this->request->url();
$device = getDeviceInfo($agent);
$param = [
'seller_id' => $this->sellerId,
'website_id' => $this->siteId,
'domain' => $this->domain,
'referrer' => empty($_SERVER['HTTP_REFERER']) ? '未知' : $_SERVER['HTTP_REFERER'],
'url' => $url,
'ip' => $ip,
'agent' => $agent,
'visited_area' => $area,
'visited_device' => $device['deviceOs'] .'/'.$device['deviceVersion'],
'visited_time' => date('Y-m-d',time())
];
$VisitLog -> addCustomData($param);
}
public function to404()
{
header('Location: /system_file/hc_error/404.html');
exit();
}
}

132
HuoCMS_close_source/app/controller/frontend/DesignBaseController.php

@ -0,0 +1,132 @@
<?php
namespace app\controller\frontend;
use think\facade\View;
class DesignBaseController extends BaseController
{
protected $designBase = 'public/design/designPage';
protected $designPath = '';
public function initialize()
{
parent::initialize();
$this->setPath();
}
public function setPath()
{
$this->designPath = CMS_ROOT . 'public/design/';
}
/**
* 加载模板输出(system_file)
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @return mixed
*/
protected function fetchDesign(string $template = '', array $vars = [])
{
$template = $this->parseTemplateDesign($template);
$this->_initializeViewDesign($this->realSiteId,$this->lang);
$html = View::fetch($template, $vars);
$replace = <<<EOL
<script id="baseJs" src="/system_file/js/base.min.js"></script>
</head>
EOL;
$html = str_replace('</head>', $replace, $html);
return $html;
}
/**
*
* 定位模板
* @param $template
* @return string
*/
private function parseTemplateDesign($template): string
{
$path = CMS_ROOT . "public/design/designPage" . DIRECTORY_SEPARATOR;
$ext = getFileExt($template);
$path .= DIRECTORY_SEPARATOR . ltrim($template,'/');
if( $ext != config('view.view_suffix')){
$path .= '.'.config('view.view_suffix');
}
return $path ;
}
/**
* 常量替换
* @param $siteId
* @param $lang
*/
protected function _initializeViewDesign($siteId,$lang)
{
$viewReplaceStr = [
'__TMPL__' => "/design/designPage",
'__STATIC__' => empty($this->settingData['static_file']) ? "/design/designPage/static" : $this->settingData['static_file'] ,
];
View::engine()->config([
'view_path' => CMS_ROOT . $this->designBase . DIRECTORY_SEPARATOR,
'tpl_replace_string' => $viewReplaceStr,
'display_cache' => false,
'tpl_cache' => false,
]);
}
/**
* 加载模板输出(system_file)
* @access protected
* @param string $template 模板文件名
* @param array $vars 模板输出变量
* @return mixed
*/
protected function fetchDesignPage(string $template = '', array $vars = [])
{
$template = $this->parseTemplateDesignPage($template);
$this->_initializeViewDesignPage($this->realSiteId,$this->lang);
return View::fetch($template, $vars);
}
/**
*
* 定位模板
* @param $template
* @return string
*/
private function parseTemplateDesignPage($template): string
{
$path = CMS_ROOT . "design/designPage/{$this->realSiteId}/{$this->lang}" . DIRECTORY_SEPARATOR;
$ext = getFileExt($template);
$path .= DIRECTORY_SEPARATOR . ltrim($template,'/');
if( $ext != config('view.view_suffix')){
$path .= '.'.config('view.view_suffix');
}
return $path ;
}
/**
* 常量替换
* @param $siteId
* @param $lang
*/
protected function _initializeViewDesignPage($siteId,$lang)
{
$viewReplaceStr = [
'__TMPL__' => "/design/designPage/{$siteId}/{$lang}",
'__STATIC__' => empty($this->settingData['static_file']) ? "/design/designPage/{$siteId}/{$lang}/static" : $this->settingData['static_file'] ,
];
View::engine()->config([
'view_path' => CMS_ROOT . $this->designBase . DIRECTORY_SEPARATOR . $siteId. DIRECTORY_SEPARATOR .$this->lang.DIRECTORY_SEPARATOR,
'tpl_replace_string' => $viewReplaceStr,
'display_cache' => false,
'tpl_cache' => false,
]);
}
}

140
HuoCMS_close_source/app/controller/frontend/DesignController.php

@ -0,0 +1,140 @@
<?php
namespace app\controller\frontend;
use app\model\BigField;
use app\model\Category;
use app\model\Theme;
use app\model\ThemeFile;
use app\model\WebsiteSetting;
use app\validate\DesignValidate;
use think\exception\ValidateException;
class DesignController extends DesignBaseController
{
public function index()
{
$param = $this->request->param();
$param['html'] = $param['html'] ?? '';
// 数据验证
try{
validate(DesignValidate::class)->scene('index')->check($param);
}catch(ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// 获取当前站的模板目录
$themeModel = new Theme();
$theme = $themeModel->where([
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
['is_active', '=', 1],
])->value('theme');
if (empty($theme)) {
return jsonReturn(-1, lang('当前站点没有激活的模板,请去安装模板'));
}
//search for html files in demo and my-pages folders
// $htmlFiles = glob("{design/designPage/*\/*.html,design/designPage/*.html,design/demo/*\/*.html,design/demo/*.html}", GLOB_BRACE);
// $htmlFiles = glob("{design/designPage/*\/*.html,design/designPage/*.html}", GLOB_BRACE);
// $htmlFiles = glob("{themes/hc_original/{$theme}/*.html,themes/hc_original/{$theme}/*\/*.html}", GLOB_BRACE);
//
//
// $files = [];
// foreach ($htmlFiles as $file) {
// $file = mb_substr($file, 7);
// $pathInfo = pathinfo($file);
// if (in_array($pathInfo['basename'], array('new-page-blank-template.html', 'editor.html'))) continue;//skip template files
//
// $filename = $pathInfo['filename'];
//// var_dump($filename);
//
// $folder = preg_replace('@/.+?$@', '', $pathInfo['dirname']);
// $subfolder = preg_replace('@^.+?/@', '', $pathInfo['dirname']);
//
// if ($filename == 'index' && $subfolder) {
//// $filename = $subfolder;
// }
// $url = $pathInfo['dirname'] . '/' . $pathInfo['basename'];
// $name = ucfirst($filename);
//
//// dump($pathInfo['basename']);
//
// $files[] = [
// 'name' => $name,
// 'file' => $filename,
// 'title' => $name,
//// 'url' => '../themes/' . $url,
// 'url' => '/' . $pathInfo['basename'],
// 'folder' => '../themes/' . $folder,
// ];
//
//// $files .= "{name:'$name', file:'$filename', title:'$name', url: '$url', folder:'$folder'},";
// }
// 获取当前网站所有有模板的栏目的路由
$category = new Category();
$list = $category->where([
['website_id', '=', $param['website_id']],
['lang', '=', $param['lang']],
['type', 'in', [4]],
['status', '=', 1],
['list_tpl', '<>', ''],
])->field('id, title, list_tpl, alias')->group('list_tpl')->select()->toArray();
if (empty($list)) {
return jsonReturn(-1, lang('当前站点已安装模板,但没有栏目使用单页模板,如当前站是子站,需要编辑父站点的数据,请回后台切换至父站点'));
}
$files = [];
$initPage = '';
foreach ($list as $value) {
$pathInfo = pathinfo($value['list_tpl']);
if ($param['html'] == $value['list_tpl']) {
$initPage = $pathInfo['filename'];
}
$file = [
'name' => $pathInfo['filename'],
'file' => $value['list_tpl'],
'title' => $value['list_tpl'],
// 'url' => '../themes/' . $url,
'url' => $value['alias'],
'folder' => $value['title'],
];
$files[] = $file;
}
// dd($files);
$where = [
'website_id' => $param['website_id'],
'lang' => $param['lang'],
];
// 获取系统配置
$websiteSetting = new WebsiteSetting();
$res = $websiteSetting->getWebsiteSetting($where);
$res['data'] = $res['data']->toArray();
$setting = $res['data']['setting'];
$initPage = $initPage ?: $files[0]['name'];
$data = [
'website_id' => $param['website_id'],
'lang' => $param['lang'],
'setting' => $setting,
'pages' => json_encode($files),
'init_page' => $initPage,
];
$this->assign($data);
return $this->fetchDesign('editor');
}
public function getDesignHtml()
{
$param = $this->request->param();
return $this->fetchDesign($param['html_path']);
}
}

128
HuoCMS_close_source/app/controller/frontend/DetailController.php

@ -0,0 +1,128 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\exception\ModelEmptyException;
use app\exception\ModelException;
use app\model\Category;
use app\model\SysSetting;
use app\service\ContentService;
use app\validate\ContentValidate;
use think\exception\HttpException;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Log;
use think\facade\View;
class DetailController extends BaseController
{
/**
* 内容详情
* @param Category $Category
* @return mixed
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function index(Category $Category)
{
$id = (int)input('id');
$cid = (int)input('cid');
$cateCacheKey = 'hc_detail_cate_' .$this->sellerId.'_'.$this->siteId.'_'.$this->lang.'_'. $cid ;
$category = cache($cateCacheKey);
if(empty($category)){
try {
$category = $Category->getCategory(['id' => $cid, 'seller_id' => $this->sellerId, 'website_id' => $this->siteId,'lang' => $this->lang],['module.moduleField'])['data']->toArray();
Cache::set($cateCacheKey,$category);
}catch (ModelEmptyException $me){
$category = $Category->getCategory(['id' => $cid, 'seller_id' => $this->sellerId, 'website_id' => $this->realSiteId,'lang' => $this->lang],['module.moduleField'])['data']->toArray();
Cache::set($cateCacheKey,$category);
}
}
if (!empty($category['content'])) {
$category['content'] = htmlspecialchars_decode($category['content']);
}
$contentService = new ContentService();
$param = [
'cate' => $category,
'id' => $id,
'seller_id' => $this->sellerId,
'website_id' => $this->siteId,
'lang' => $this->lang,
'field' => '*',
'main_content' => 1
];
$content = $contentService->getContentDetail($param);
$content->hits = $content->hits + 1;
$content->save();
if (!empty($content['content'])) {
$content['content'] = htmlspecialchars_decode($content['content']);
}
$where = [
'group' => 'company',
'title' => 'huocms_powerby',
];
$huocmsPowerby = SysSetting::where($where)->value('value');
if ($huocmsPowerby) {
$category['seo_title'] = $content['seo_title'] ?: $content['title'];
$category['seo_keyword'] = $content['seo_keyword'] ?: $content['title'];
$category['seo_description'] = $content['seo_description'] ?: $content['title'];
$category['seo_title'] .= "-$huocmsPowerby";
$category['seo_keyword'] .= ",$huocmsPowerby";
$category['seo_description'] .= ",$huocmsPowerby";
}
$this->assign('hc_content',$content->toArray());
$this->assign('current_cate',$category);
$this->assign('root_domain',$this->rootDomain);
$template = !empty($content['detail_tpl']) ? $content['detail_tpl'] : $category['detail_tpl'];
return $this->fetch($template);
}
/**
* 文件预览
* @throws ModelException
* @throws ModelEmptyException
*/
public function preview()
{
$param = $this->request->only(['id','cid','lang'=>$this->lang,'website_id'=>$this->realSiteId]);
$Category = new Category();
$category = $Category->getCustomArrayData(['id' => $param['cid'], 'website_id' => $param['website_id'],'lang' => $param['lang']],['module.moduleField'])['data'];
if(empty($category)){
Log::error("栏目不存在");
throw new HttpException(404,'资源不存在');
}
$param['cate'] = $category;
$param['seller_id'] = $this->sellerId;
$param['field'] = '*';
$param['main_content'] = 1;
if (!empty($category['content'])) {
$category['content'] = htmlspecialchars_decode($category['content']);
}
$contentService = new ContentService();
$content = $contentService->getPreviewContent($param);
if(empty($content)){
Log::error("内容不存在");
throw new HttpException(404,'资源不存在');
}
if (!empty($content['content'])) {
$content['content'] = htmlspecialchars_decode($content['content']);
}
if($category['id'] == 41 && empty($content['content'])){
if(empty($content['main_content']['file']['url'])){
return redirect('/404.html');
}else{
$url = $content['main_content']['file']['url'];
return redirect($url);
}
}
View::assign('hc_content',$content->toArray());
View::assign('current_cate',$category);
$template = !empty($content['detail_tpl']) ? $content['detail_tpl'] : $category['detail_tpl'];
return $this->fetch($template);
}
}

274
HuoCMS_close_source/app/controller/frontend/FormController.php

@ -0,0 +1,274 @@
<?php
namespace app\controller\frontend;
use app\model\Attachment;
use app\model\customModel\Down;
use app\model\DiyForm;
use app\model\SubContent;
use app\model\SysSetting;
use app\service\upload\Upload;
use think\facade\Db;
class FormController extends BaseController
{
protected $type = [
'file' => 4,
'image' => 2,
'video' => 3,
'mp3' => 5,
'zip' => 1,
];
public function index()
{
$code = $this->request->param('code');
$formModel = new DiyForm();
$formData = $formModel->where('code', $code)->findOrEmpty();
if (empty($formData)) {
$this->to404();
}
$this->assign('formData', $formData);
$html = $this->formHtml();
$html = str_replace(['{formData_name}', '{formData_designContent}', '{formData_designOption}', '{formData_code}'],
[$formData['name'],$formData['design_content'],$formData['design_option'],$formData['code']], $html);
return $html;
}
public function save()
{
$param = $this->request->param();
$code = $param['code'];
unset($param['code']);
$formModel = new DiyForm();
$formData = $formModel->where('code', $code)->findOrEmpty();
if (empty($formData)) {
return jsonReturn(-1, lang('提交失败'));
}
$tableName = 'diyform_' . $formData['table'];
foreach ($param as &$value) {
if (is_array($value)) {
$value = implode(',', $value);
}
}
$param['ip'] = $this->request->ip();
$param['user_agent'] = $this->request->header('user-agent');
Db::name($tableName)->insert($param);
return jsonReturn(0, lang('提交成功'));
}
// 上传文件
public function uploadFormFile()
{
if(!request()->isPost()){
return jsonReturn(-1, lang('请求错误'));
}
$file = request()->file('file');
if(empty($file)){
return jsonReturn(-2,lang('文件不能为空'));
}
$seller_id = $this->sellerId;
// 查看文件类型
$fileName = $file->getOriginalName();
$fileExt = $file->getOriginalExtension();
$file_type = fileFormat($fileName);
$fileType = $this->type[$file_type];
// 附件大小和类型验证
// 获取上传配置
$Settings = new SysSetting();
$uploadSetting = $Settings->getAllCustomArrayData(['parent_id'=>1,'group'=>'upload','status'=>1],'id desc','id,group,title,value')['data'];
$uploadSetting = getColumnForKeyArray($uploadSetting,'title');
$limitSize = $uploadSetting[$file_type.'_size']['value'] * 1024; // byte
$fileSize = $file->getSize(); // 单位byte
if($fileSize > $limitSize){
return jsonReturn(-1,lang('文件过大,请修改上传限制或者替换小的文件'));
}
$extArr = explode(',',$uploadSetting[$file_type.'_ext']['value']);
if(!in_array($fileExt,$extArr)){
return jsonReturn(-2,lang('文件格式错误,请重新上传'));
}
// 文件信息提取
$where = [
'seller_id' => $seller_id,
'group' => 'upload',
'title' => 'storage'
];
$place = new SysSetting();
$type = $place->getSysSetting($where)['data']->toArray()['value'];
$upload = new Upload();
$info = $upload->create($file,$seller_id, $type,$file_type);
if ($info) {
$uploadInfo = $upload->getUploadFileInfo();
if ($uploadInfo['code'] == 0) {
$uploadInfo['data']['type'] = $fileType;
$uploadInfo['data']['size'] = round($fileSize / 1024,2);
$uploadInfo['data']['mime_type'] = $fileExt;
}
return json($uploadInfo);
}else{
return jsonReturn(-1, lang('上传失败请重新尝试'));
}
}
/**
* 下载文件
* @return void
*/
public function downFile()
{
$param = $this->request->param();
if (empty($param)) {
$this->to404();
}
$id = intval($param['id']);
$downFlag = false; // 可下载标识
$downModel = new Down();
$downData = $downModel->where('sub_id', '=', $id)->findOrEmpty();
if (empty($downData)) {
$this->to404();
}
$subContentModel = new SubContent();
$downData['title'] = $subContentModel->where('id', '=', $downData['sub_id'])->value('title');
$formData = [];
if ($downData['is_form'] == '是') {
$formModel = new DiyForm();
$formData = $formModel->where('id', '=', $downData['form_id'])->where('status', '=', 2)->findOrEmpty();
if (empty($formData)) {
$this->to404();
}
$tableName = 'diyform_' . $formData['table'];
$where = [
['sub_id', '=', $id],
['ip', '=', $this->request->ip()],
['user_agent', '=', $this->request->header('user-agent')],
['visitor_id', '=', $this->request->param('visitor_id')]
];
$id = Db::name($tableName)->where($where)->value('id');
if (!empty($id)) {
$downFlag = true;
}
} else {
$downFlag = true;
}
if ($downFlag) {
$fileModel = new Attachment();
$downData['fileArr'] = $fileModel->where('id', 'in', json_decode($downData['file'], true))->select()->toArray();
}
$this->assign('downData', $downData);
$this->assign('formData', $formData);
$this->assign('downFlag', $downFlag);
$this->assign('visitor_id', $this->request->param('visitor_id'));
return $this->fetchSystem('down/index');
}
/**
* 问卷html
* @return string
*/
protected function formHtml()
{
$html = <<<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{formData_name}</title>
</head>
<body>
<div class="container" style="display: block;max-width:1200px;margin: 0 auto; ">
<div id="app-3" class="formBox" style="padding-top: 50px">
<template>
<form-create
v-model="fapi"
:rule="rule"
:option="option"
@submit="onSubmit"
></form-create>
</template>
</div>
</div>
</body>
<!-- import Vue.js -->
<!-- <script src="//vuejs.org/js/vue.min.js"></script>-->
<!-- 生产环境版本,优化了尺寸和速度 -->
<script src="/system_file/form/vue@2"></script>
<!-- import stylesheet -->
<link rel="stylesheet" href="/system_file/form/index.css">
<!-- import element -->
<script src="/system_file/form/index.js"></script>
<!-- import form-create/element -->
<script src="/system_file/form/form-create.min.js"></script>
<!-- import form-create/designer -->
<script src="/system_file/form/index.min.js"></script>
<script src="/system_file/form/jquery-3.4.1.min.js"></script>
<script>
//FcDesigner 生成的`JSON`
// const FcDesignerRule = '[{"type":"input","field":"cuk5qqdw3umc","title":"输入框","info":"","_fc_drag_tag":"input","hidden":false,"display":true}]';
const FcDesignerRule = '{formData_designContent}';
//FcDesigner 生成的`options`
// const FcDesignerOptions = '{"form":{"labelPosition":"right","size":"mini","labelWidth":"125px","hideRequiredAsterisk":false,"showMessage":true,"inlineMessage":false}}';
const FcDesignerOptions = '{formData_designOption}';
const code = '{formData_code}';
console.log(FcDesignerOptions, 'asdasdasdasdsada')
var app3 = new Vue({
el: '#app-3',
data: {
fapi: null,
rule: formCreate.parseJson(FcDesignerRule),
option: formCreate.parseJson(FcDesignerOptions)
},
methods: {
onSubmit (formData) {
formData.code = code
//todo 提交表单
console.log(formData, '提交表单提交表单提交表单')
$.post('/addFormData.html', formData, function(res) {
console.log(res, '接口返回');
if (res.code == 0) {
alert('提交成功')
} else {
alert('提交失败')
}
});
}
}
})
</script>
</html>
EOF;
return $html;
}
}

105
HuoCMS_close_source/app/controller/frontend/InquiryController.php

@ -0,0 +1,105 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\model\Inquiry;
use app\model\SysSetting;
use app\model\Website;
use app\service\EmailService;
use app\validate\frontend\InquiryValidate;
use GuzzleHttp\Client;
use think\exception\ValidateException;
use think\facade\Cache;
use think\facade\Log;
class InquiryController extends BaseController
{
/**
* 保存新建的资源
*
* @return \think\Response
* @throws \app\exception\ModelException
* @throws \app\exception\ModelEmptyException
*/
public function save(): \think\Response
{
// 获取用户的 IP 地址或其他标识
$identifier = request()->ip();
// 设置限制时间窗口(例如:1分钟)
$window = 60;
// 设置允许的最大请求数
$maxRequests = 5;
// 生成存储请求计数的缓存键
$cacheKey = 'request_rate_limit:' . $identifier;
// 获取当前时间内已发送的请求次数
$requestCount = (int)Cache::get($cacheKey,0);
// 如果请求次数超过限制,则返回错误响应
if ($requestCount >= $maxRequests) {
return json(['status' => 'error', 'message' => '请求频率过高,请稍后再试']);
}
$param = request()->param();
if(empty($param)){
return jsonReturn(-1,lang('请填写询盘信息'));
}
try{
validate(InquiryValidate::class)->check($param);
}catch (ValidateException $e){
return jsonReturn(-1, $e->getError());
}
// 获取询盘收件箱
$webSite = new Website();
$site = $webSite->getWebsite(['domain' => $this->domain],['inquiryEmail'])['data']->toArray();
$email = [];
if(!empty($site['inquiryEmail'])){
$email = array_column($site['inquiryEmail'],'email');
}
$inquiry = new Inquiry();
$param['seller_id'] = $this->sellerId;
$param['website_id'] = $this->siteId;
$param['ip'] = request()->ip();
$param['inquiry_type'] = 1;
$res = $inquiry -> addInquiry($param);
try{
// 获取suwork配置
$sysSetting = new SysSetting();
$setting = $sysSetting->getAllSysSetting([['title','like','suwork_%']])['data']->toArray();
$key = array_column($setting,'title');
$setting = array_combine($key,$setting);
if(!empty($setting['suwork_appid']['value']) && !empty($setting['suwork_secret']['value']) && !empty($setting['suwork_api']['value'])){
$suworkAccept = config('system.suwork_accept');
$data = array_intersect_key($param,$suworkAccept);
$data['referer_type'] = 1;
$data['referer_web'] = empty($_SERVER['HTTP_REFERER']) ? '未知' : $_SERVER['HTTP_REFERER'];
$data['appid'] = $setting['suwork_appid']['value'];
$data['secret'] = $setting['suwork_secret']['value'];
$data['inquiry_time'] = date('Y-m-d H:i:s',time());
$option = [
'form_params' => $data,
];
$client = new Client();
$response = $client->post($setting['suwork_api']['value'],$option);
$result = json_decode($response->getBody()->getContents(),true);
if($result['code'] != 0){
Log::record($result['msg'],'info');
}
}
// 发送邮件
$EmailService = new EmailService();
$EmailService->sendEmail($this->domain.lang('网站收到询盘'),$email);
}catch (\Exception $e){
Log::error($e->getMessage());
return jsonReturn(0,lang('提交成功'),1);
}
// 增加请求计数
Cache::set($cacheKey,$requestCount + 1, $window);
return json($res);
}
}

55
HuoCMS_close_source/app/controller/frontend/ListController.php

@ -0,0 +1,55 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\exception\ModelEmptyException;
use app\model\Category;
use app\model\SysSetting;
class ListController extends BaseController
{
/**
* @param Category $Category
* @return mixed
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
*/
public function index(Category $Category)
{
$id = (int)input('id');
$with=['thumbnail'=>function($q){
$q->field('id,name,url,type');
},'banner'=>function($q){
$q->field('id,name,url,type');
}
];
try {
$category = $Category->getCategory(['id' => $id, 'seller_id' => $this->sellerId, 'website_id' => $this->siteId,'lang' => $this->lang],$with)['data']->toArray();
}catch (ModelEmptyException $me){
$category = $Category->getCategory(['id' => $id, 'seller_id' => $this->sellerId, 'website_id' => $this->realSiteId,'lang' => $this->lang],$with)['data']->toArray();
}
if (!empty($category['content'])) {
$category['content'] = htmlspecialchars_decode($category['content']);
}
$where = [
'group' => 'company',
'title' => 'huocms_powerby',
];
$huocmsPowerby = SysSetting::where($where)->value('value');
if ($huocmsPowerby) {
$category['seo_title'] .= " - $huocmsPowerby";
$category['seo_keywords'] .= ",$huocmsPowerby";
$category['seo_description'] .= ",$huocmsPowerby";
}
$this->assign('current_cate',$category);
$this->assign('root_domain',$this->rootDomain);
$template = $category['list_tpl'];
return $this->fetch($template);
}
}

67
HuoCMS_close_source/app/controller/frontend/ResumeController.php

@ -0,0 +1,67 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\model\Attachment;
use app\model\Resume;
use app\service\upload\Upload;
use app\validate\frontend\ResumeValidate;
use think\exception\ValidateException;
use think\Request;
class ResumeController extends BaseController
{
private $allowExtension = [
'pdf','doc','docx'
];
/**
* 保存新建的资源
*
* @param \think\Request $request
* @return \think\Response
* @throws \app\exception\ModelException
*/
public function save(Request $request,Upload $upload)
{
//
$param = $request->only(['username','phone','email','remark']);
try{
validate(ResumeValidate::class)->check($param);
}catch (ValidateException $e){
return jsonReturn(-1, $e->getError());
}
$file = $request->file('resume_file');
if(empty($file)){
return jsonReturn(-1,'简历不能为空');
}
$extension = strtolower($file->getOriginalExtension());
if(!in_array($extension,$this->allowExtension)){
// return jsonReturn(-1,'简历文件格式不对,请上传pdf或者word文件');
}
// 查看文件类型
$fileName = $file->getOriginalName();
$file_type = fileFormat($fileName);
$upload = new Upload();
$info = $upload->create($file,$this->sellerId, 'local',$file_type);
if(!$info){
jsonReturn(-1,'简历上传失败,请重新尝试');
}
$info = $upload->getUploadFileInfo()['data'];
$attachment = new Attachment();
$info['size'] = round($file->getSize() / 1024,2);
$info['seller_id'] = $this->sellerId;
$info['attachment_cate_id'] = 0;
$info['type'] = 4;
$res = $attachment->addCustomData($info)['data'];
if(empty($res)){
jsonReturn(-2,'简历上传失败,请重新尝试');
}
$resume = new Resume();
$param['website_id'] = $this->siteId;
$param['attachment_id'] = $res['id'];
$res = $resume -> addCustomData($param);
return json($res);
}
}

89
HuoCMS_close_source/app/controller/frontend/SearchController.php

@ -0,0 +1,89 @@
<?php
namespace app\controller\frontend;
use app\model\Category;
use app\model\CategorySubContent;
use app\model\SubContent;
use app\model\SysSetting;
class SearchController extends BaseController
{
/**
* @throws \app\exception\ModelEmptyException
* @throws \app\exception\ModelException
* @throws \think\db\exception\DbException
*/
public function index(Category $Category)
{
//拿到搜索页数据,主要为了拿seo数据
$with=['thumbnail'=>function($q){
$q->field('id,name,url,type');
},'banner'=>function($q){
$q->field('id,name,url,type');
}
];
$where = [
['seller_id', '=', $this->sellerId],
['website_id', '=', $this->realSiteId],
['is_search', '=', 1],
];
$category = $Category->getCategory($where,$with)['data']->toArray();
$settingWhere = [
'group' => 'company',
'title' => 'huocms_powerby',
];
$huocmsPowerby = SysSetting::where($settingWhere)->value('value');
if ($huocmsPowerby) {
$category['seo_title'] .= " - $huocmsPowerby";
$category['seo_keywords'] .= ",$huocmsPowerby";
$category['seo_description'] .= ",$huocmsPowerby";
}
$this->assign('current_cate',$category);
//搜索
$param = $this->request->param();
$keywords = $param['q'];
$this->assign('keywords',$keywords);
// 获取可以查询的栏目
$category = new Category();
$categories = $category -> getAllCustomArrayData($where,'id desc','id')['data'];
$cateIds = array_column($categories,'id');
$cateSub = new CategorySubContent();
$cateSubWhere = [
['category_id','in',$cateIds]
];
$cateSubCon = $cateSub->getAllCategorySubContent($cateSubWhere)['data'];
$subIds = array_column($cateSubCon,'sub_content_id');
$SubContent = new SubContent();
$content = $SubContent->with(['thumbnail'=>function($q){
$q->field('id,name,url,type');
},'category'])->where(['seller_id'=>$this->sellerId,'is_del'=>1]);
if(!empty($param['q'])){
$content = $content -> whereLike('title|description|sub_title','%' . $keywords . '%');
}
$param['siteId'] = $this->realSiteId;
$param['sellerId'] = $this->sellerId;
$data = $content->whereIn('id',$subIds)
->order('id','desc')
->paginate([
'page' => $param['page'] ?? 1,
'list_rows' => $param['limit'] ?? 10,
])->each(function (&$item)use($param){
if(!empty($item['category'])) {
$item['category'] = $item->toArray()['category'];
$item['category_id'] = $item['category'][0]['id'];
}
$item['thumbnail'] = $item->toArray()['thumbnail'];
});
$data->appends(['q' => $keywords]);
$this->assign('list', $data->items());
$this->assign('list_page', $data->render());
return $this->fetch(config('view.view_search_page_name'));
}
}

55
HuoCMS_close_source/app/controller/frontend/SeoController.php

@ -0,0 +1,55 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
class SeoController extends BaseController
{
/**
* robots文件读取
*
*/
public function getRobots()
{
$filename = $this->siteId . '_robots.txt';
$path = app() -> getRootPath() . 'public/robots/' . $filename ;
if(!hcFileExist($path)){
$sysRobots = app() -> getRootPath() . 'public/robots/robots.txt' ;
touch($path);
copy($sysRobots,$path);
}
header("Content-type:text/html;");
$content = file_get_contents($path);
$content = '<pre>' . str_replace("\n",'<pre>',$content);
echo $content;
exit;
}
/**
* sitemap xml文件读取
*
*/
public function getSitemapXml()
{
$filename = $this->siteId . '_sitemap.xml';
$path = app() -> getRootPath() . 'public/xml/' . $filename;
$content = @file_get_contents($path);
header("Content-type:text/xml;");
echo $content;
exit;
}
/**
* sitemap html文件读取
*
*/
public function getSitemapHtml()
{
$filename = $this->siteId . '_sitemap.html';
$path = app() -> getRootPath() . 'public/sitemap_html/' . $filename;
echo @file_get_contents($path);
exit;
}
}

59
HuoCMS_close_source/app/controller/frontend/TagController.php

@ -0,0 +1,59 @@
<?php
declare (strict_types = 1);
namespace app\controller\frontend;
use app\model\Tag;
use think\Request;
class TagController extends BaseController
{
/**
* 显示资源列表
*
* @return \think\Response
*/
public function index()
{
$tagModel = new Tag();
//标签整合展示
$param = $this->request->param();
$allTag = $tagModel->where([
'website_id' => $this->siteId,
'seller_id' => $this->sellerId,
'lang' => $this->lang,
])->group('first_letter')->column('first_letter');
$charArr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', "H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
foreach ($charArr as $key => $value) {
if (!in_array($value, $allTag)) {
unset($charArr[$key]);
}
}
$charArr = array_values($charArr);
$this->assign('allTag', $charArr);
$param['name'] = $param['name'] ?? $charArr[0];
$param['page'] = $param['page'] ?? 1;
$param['limit'] = $param['limit'] ?? 80;
//默认获取A首字母开头的标签
$tagList = $tagModel->where([
'website_id' => $this->siteId,
'seller_id' => $this->sellerId,
'lang' => $this->lang,
])->where('first_letter', '=', $param['name'])->paginate(
[
'page' => $param['page'],
'list_rows' => $param['limit'],
]
);
$this->assign('tagList', $tagList);
$this->assign('name', $param['name']);
return $this->fetch(config('view.view_tag_page_name'));
}
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save