123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Description: 安装
  4. // +----------------------------------------------------------------------
  5. // | Author: Michael_xu | gengxiaoxu@5kcrm.com
  6. // +----------------------------------------------------------------------
  7. namespace app\admin\controller;
  8. use think\Controller;
  9. use think\Request;
  10. use think\Db;
  11. use Env;
  12. class Install extends Controller
  13. {
  14. // private $count = 100;
  15. // private $now = 0;
  16. public function _initialize()
  17. {
  18. /*防止跨域*/
  19. header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
  20. header('Access-Control-Allow-Credentials: true');
  21. header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
  22. header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, authKey, sessionId");
  23. $param = Request::instance()->param();
  24. $this->param = $param;
  25. // $request = request();
  26. // $m = strtolower($request->module());
  27. // $c = strtolower($request->controller());
  28. // $a = strtolower($request->action());
  29. //
  30. // if (!in_array($a, array('upgrade','upgradeprocess','checkversion')) && file_exists(CONF_PATH . "install.lock")) {
  31. // echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  32. // die();
  33. // }
  34. }
  35. private $upgrade_site = "http://message.72crm.com/";
  36. /**
  37. * [index 安装步骤]
  38. * @author Michael_xu
  39. * @param
  40. */
  41. public function index()
  42. {
  43. if (file_exists(CONF_PATH . "install.lock")) {
  44. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  45. die();
  46. }
  47. if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
  48. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('缺少必要的数据库文件!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  49. die();
  50. }
  51. return $this->fetch('index');
  52. }
  53. public function step1()
  54. {
  55. session('install_error',null);
  56. $data = [];
  57. $data['env'] = self::checkNnv();
  58. $data['dir'] = self::checkDir();
  59. $data['version'] = $this->version();
  60. $this->assign('data',$data);
  61. return $this->fetch('step1');
  62. }
  63. //版本
  64. public function version()
  65. {
  66. $res = include(CONF_PATH.'version.php');
  67. return $res ? : array('VERSION' => '11.0.0','RELEASE' => '20210219');
  68. }
  69. public function step2(){
  70. if (session('install_error')){
  71. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('环境检测未通过,不能进行下一步操作!');location.href='".$_SERVER["HTTP_REFERER"]."';</script>";
  72. die();
  73. }
  74. $data['os'] = PHP_OS;
  75. $data['php'] = phpversion();
  76. $data['version'] = $this->version();
  77. $this->assign('envir_data',$data);
  78. return $this->fetch();
  79. }
  80. public function step3(){
  81. return $this->fetch();
  82. }
  83. public function step4(){
  84. if (session('install_error')){
  85. return resultArray(['error' => '环境检测未通过,不能进行下一步操作!']);
  86. }
  87. if (file_exists(CONF_PATH . "install.lock")) {
  88. return resultArray(['error' => '请勿重复安装!']);
  89. }
  90. if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
  91. return resultArray(['error' => '缺少必要的数据库文件!']);
  92. }
  93. $temp = $this->param;
  94. $param = $temp['form'];
  95. $db_config['type'] = 'mysql';
  96. $db_config['hostname'] = $param['databaseUrl'];
  97. $db_config['hostport'] = $param['databasePort'];
  98. $db_config['database'] = $param['databaseName'];
  99. $db_config['username'] = $param['databaseUser'];
  100. $db_config['password'] = $param['databasePwd'];
  101. $db_config['prefix'] = $param['databaseTable'];
  102. $username = $param['root'];
  103. $password = $param['pwd'];
  104. $wkcode = $param['wkcode'];
  105. if (empty($db_config['hostname'])) {
  106. return resultArray(['error' => '请填写数据库主机!']);
  107. }
  108. if (empty($db_config['hostport'])) {
  109. return resultArray(['error' => '请填写数据库端口!']);
  110. }
  111. if (preg_match('/[^0-9]/', $db_config['hostport'])) {
  112. return resultArray(['error' => '数据库端口只能是数字!']);
  113. }
  114. if (empty($db_config['database'])) {
  115. return resultArray(['error' => '请填写数据库名!']);
  116. }
  117. if (empty($db_config['username'])) {
  118. return resultArray(['error' => '请填写数据库用户名!']);
  119. }
  120. if (empty($db_config['password'])) {
  121. return resultArray(['error' => '请填写数据库密码!']);
  122. }
  123. if (empty($db_config['prefix'])) {
  124. return resultArray(['error' => '请填写表前缀!']);
  125. }
  126. if (preg_match('/[^a-z0-9_]/i', $db_config['prefix'])) {
  127. return resultArray(['error' => '表前缀只能包含数字、字母和下划线!']);
  128. }
  129. if (empty($username)) {
  130. return resultArray(['error' => '请填写管理员用户名!']);
  131. }
  132. if (empty($wkcode)) {
  133. return resultArray(['error' => '请填写序列号!']);
  134. }
  135. $resCheckData = checkWkCode($wkcode);
  136. if (!$resCheckData) {
  137. return resultArray(['error' => '序列号错误!']);
  138. }
  139. $resData = object_to_array(json_decode($resCheckData));
  140. if ($resData['date'] != date('Y-m-d')) {
  141. return resultArray(['error' => '序列号已失效,请前往悟空官网个人中心获取最新数据!']);
  142. }
  143. if (empty($password)) {
  144. return resultArray(['error' => '请填写管理员密码!']);
  145. }
  146. session('install_count','');
  147. session('install_now','');
  148. $database = $db_config['database'];
  149. unset($db_config['database']);
  150. $connect = Db::connect($db_config);
  151. // 检测数据库连接
  152. try{
  153. $ret = $connect->execute('select version()');
  154. }catch(\Exception $e){
  155. return resultArray(['error' => '数据库连接失败,请检查数据库配置!']);
  156. }
  157. $check = $connect->execute("SELECT * FROM information_schema.schemata WHERE schema_name='".$database."'");
  158. if (!$check && !$connect->execute("CREATE DATABASE IF NOT EXISTS `".$database."` default collate utf8_general_ci ")) {
  159. return resultArray(['error' => '没有找到您填写的数据库名且无法创建!请检查连接账号是否有创建数据库的权限!']);
  160. }
  161. $db_config['database'] = $database;
  162. self::mkDatabase($db_config);
  163. self::mkLicense($wkcode);
  164. $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
  165. $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm.sql');
  166. $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
  167. if ($sqlList) {
  168. $sqlList = array_filter($sqlList);
  169. $install_count = count($sqlList);
  170. session('install_count',$install_count);
  171. foreach ($sqlList as $k=>$v) {
  172. $install_now = $k+1;
  173. session('install_now',$install_now);
  174. try {
  175. $temp_sql = $v.';';
  176. Db::connect($db_config)->query($temp_sql);
  177. } catch(\Exception $e) {
  178. // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
  179. return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
  180. }
  181. }
  182. }
  183. $salt = substr(md5(time()),0,4);
  184. $password = user_md5(trim($password), $salt, $username);
  185. //插入信息
  186. Db::connect($db_config)->query("insert into ".$db_config['prefix']."admin_user (username, password, salt, img, thumb_img, realname, create_time, num, email, mobile, sex, status, structure_id, post, parent_id, type, authkey, authkey_time ) values ( '".$username."', '".$password."', '".$salt."', '', '', '管理员', ".time().", '', '', '".$username."', '', 1, 1, 'CEO', 0, 1, '', 0 )");
  187. Db::connect($db_config)->query("insert into ".$db_config['prefix']."hrm_user_det (user_id, join_time, type, status, userstatus, create_time, update_time, mobile, sex, age, job_num, idtype, idnum, birth_time, nation, internship, done_time, parroll_id, email, political, location, leave_time ) values ( 1, ".time().", 1, 1, 2, ".time().", ".time().", '".$username."', '', 0, '', 0, '', '', 0, 0, 0, 0, '', '', '', 0 )");
  188. touch(CONF_PATH . "install.lock");
  189. return resultArray(['data'=>'安装成功']);
  190. }
  191. public function step5()
  192. {
  193. return $this->fetch();
  194. }
  195. //ajax 进度条
  196. public function progress()
  197. {
  198. $data['length'] = session('install_count');
  199. $data['now'] = session('install_now');
  200. return resultArray(['data'=>$data]);
  201. }
  202. //添加database.php文件
  203. private function mkDatabase(array $data)
  204. {
  205. $code = <<<INFO
  206. <?php
  207. return [
  208. // 数据库类型
  209. 'type' => 'mysql',
  210. // 服务器地址
  211. 'hostname' => '{$data['hostname']}',
  212. // 数据库名
  213. 'database' => '{$data['database']}',
  214. // 用户名
  215. 'username' => '{$data['username']}',
  216. // 密码
  217. 'password' => '{$data['password']}',
  218. // 端口
  219. 'hostport' => '{$data['hostport']}',
  220. // 连接dsn
  221. 'dsn' => '',
  222. // 数据库连接参数
  223. 'params' => [],
  224. // 数据库编码默认采用utf8
  225. 'charset' => 'utf8',
  226. // 数据库表前缀
  227. 'prefix' => '{$data['prefix']}',
  228. // 数据库调试模式
  229. 'debug' => true,
  230. // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
  231. 'deploy' => 0,
  232. // 数据库读写是否分离 主从式有效
  233. 'rw_separate' => false,
  234. // 读写分离后 主服务器数量
  235. 'master_num' => 1,
  236. // 指定从服务器序号
  237. 'slave_no' => '',
  238. // 自动读取主库数据
  239. 'read_master' => false,
  240. // 是否严格检查字段是否存在
  241. 'fields_strict' => true,
  242. // 数据集返回类型
  243. 'resultset_type' => 'array',
  244. ];
  245. INFO;
  246. file_put_contents( CONF_PATH.'database.php', $code);
  247. // 判断写入是否成功
  248. $config = include CONF_PATH.'database.php';
  249. if (empty($config['database']) || $config['database'] != $data['database']) {
  250. return resultArray(['error' => '[config/database.php]数据库配置写入失败!']);
  251. }
  252. return true;
  253. }
  254. //检查目录权限
  255. public function check_dir_iswritable($dir_path){
  256. $dir_path=str_replace( '\\','/',$dir_path);
  257. $is_writale=1;
  258. if (!is_dir($dir_path)) {
  259. $is_writale=0;
  260. return $is_writale;
  261. } else {
  262. $file_hd=@fopen($dir_path.'/test.txt','w');
  263. if (!$file_hd) {
  264. @fclose($file_hd);
  265. @unlink($dir_path.'/test.txt');
  266. $is_writale=0;
  267. return $is_writale;
  268. }
  269. $dir_hd = opendir($dir_path);
  270. while (false !== ($file=readdir($dir_hd))) {
  271. if ($file != "." && $file != "..") {
  272. if (is_file($dir_path.'/'.$file)) {
  273. //文件不可写,直接返回
  274. if (!is_writable($dir_path.'/'.$file)) {
  275. return 0;
  276. }
  277. } else {
  278. $file_hd2=@fopen($dir_path.'/'.$file.'/test.txt','w');
  279. if (!$file_hd2) {
  280. @fclose($file_hd2);
  281. @unlink($dir_path.'/'.$file.'/test.txt');
  282. $is_writale=0;
  283. return $is_writale;
  284. }
  285. //递归
  286. $is_writale=check_dir_iswritable($dir_path.'/'.$file);
  287. }
  288. }
  289. }
  290. }
  291. return $is_writale;
  292. }
  293. /**
  294. * [checkVersion 检查升级]
  295. * @author Michael_xu
  296. * @param
  297. */
  298. public function checkVersion(){
  299. $version = Config::load('version');
  300. $info = sendRequest($this->upgrade_site.'index.php?m=version&a=checkVersion', $version['VERSION']);
  301. if ($info){
  302. return resultArray(['data' => $info]);
  303. } else {
  304. return resultArray(['error' => '检查新版本出错!']);
  305. }
  306. }
  307. /**
  308. * 环境检测
  309. * @return array
  310. */
  311. private function checkNnv()
  312. {
  313. $items = [
  314. 'os' => ['操作系统', PHP_OS, '类Unix', 'ok'],
  315. 'php' => ['PHP版本', PHP_VERSION, '7.3 ( <em style="color: #888; font-size: 12px;">>= 5.6</em> )', 'ok','性能更佳'],
  316. 'gd' => ['gd', '开启', '开启', 'ok'],
  317. 'openssl' => ['openssl', '开启', '开启', 'ok'],
  318. 'pdo' => ['pdo', '开启', '开启', 'ok'],
  319. ];
  320. session('install_error','');
  321. if (substr($items['php'][1],0,3) < '5.6') {
  322. $items['php'][3] = 'error';
  323. session('install_error', true);
  324. }
  325. if (!extension_loaded('gd')) {
  326. $items['gd'][1] = '未开启';
  327. $items['gd'][3] = 'error';
  328. session('install_error', true);
  329. }
  330. if (!extension_loaded('openssl')) {
  331. $items['openssl'][1] = '未开启';
  332. $items['openssl'][3] = 'error';
  333. session('install_error', true);
  334. }
  335. if (!extension_loaded('pdo')) {
  336. $items['pdo'][1] = '未开启';
  337. $items['pdo'][3] = 'error';
  338. session('install_error', true);
  339. }
  340. // dump($items);die;
  341. return $items;
  342. }
  343. /**
  344. * 目录权限检查
  345. * @return array
  346. */
  347. private function checkDir()
  348. {
  349. $items = [
  350. ['dir', $this->root_path.'application', 'application', '读写', '读写', 'ok'],
  351. ['dir', $this->root_path.'extend', 'extend', '读写', '读写', 'ok'],
  352. ['dir', $this->root_path.'runtime', './temp', '读写', '读写', 'ok'],
  353. ['dir', $this->root_path.'public', './upload', '读写', '读写', 'ok'],
  354. ['file', $this->root_path.'config', 'config', '读写', '读写', 'ok'],
  355. ];
  356. foreach ($items as &$v) {
  357. if ($v[0] == 'dir') {// 文件夹
  358. if (!is_writable($v[1])) {
  359. if (is_dir($v[1])) {
  360. $v[4] = '不可写';
  361. $v[5] = 'no';
  362. } else {
  363. $v[4] = '不存在';
  364. $v[5] = 'no';
  365. }
  366. session('install_error', true);
  367. }
  368. } else {// 文件
  369. if (!is_writable($v[1])) {
  370. $v[4] = '不可写';
  371. $v[5] = 'no';
  372. session('install_error', true);
  373. }
  374. }
  375. }
  376. return $items;
  377. }
  378. /**
  379. * 验证序列号
  380. * @param
  381. * @return
  382. */
  383. public function checkCodeOld($username) {
  384. $encryption = md5($username);
  385. $substr = substr($username, strlen($username)-6);
  386. $subArr = str_split($substr, 1);
  387. $code = '';
  388. for ($i = 0; $i <= 5; $i++) {
  389. $code .= $encryption[$subArr[$i]];
  390. }
  391. return $code;
  392. }
  393. //写入license文件
  394. private function mkLicense($wkcode)
  395. {
  396. file_put_contents( CONF_PATH.'license.dat', $wkcode);
  397. // 判断写入是否成功
  398. // $config = include CONF_PATH.'license.dat';
  399. // if (empty($config)) {
  400. // return resultArray(['error' => 'license配置写入失败!']);
  401. // }
  402. return true;
  403. }
  404. }