Install.php 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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'] = '5kcrm_';
  102. // $db_config['prefix'] = $param['databaseTable'];
  103. $username = $param['root'];
  104. $password = $param['pwd'];
  105. $wkcode = $param['wkcode'];
  106. if (empty($db_config['hostname'])) {
  107. return resultArray(['error' => '请填写数据库主机!']);
  108. }
  109. if (empty($db_config['hostport'])) {
  110. return resultArray(['error' => '请填写数据库端口!']);
  111. }
  112. if (preg_match('/[^0-9]/', $db_config['hostport'])) {
  113. return resultArray(['error' => '数据库端口只能是数字!']);
  114. }
  115. if (empty($db_config['database'])) {
  116. return resultArray(['error' => '请填写数据库名!']);
  117. }
  118. if (empty($db_config['username'])) {
  119. return resultArray(['error' => '请填写数据库用户名!']);
  120. }
  121. if (empty($db_config['password'])) {
  122. return resultArray(['error' => '请填写数据库密码!']);
  123. }
  124. if (empty($db_config['prefix'])) {
  125. return resultArray(['error' => '请填写表前缀!']);
  126. }
  127. if (preg_match('/[^a-z0-9_]/i', $db_config['prefix'])) {
  128. return resultArray(['error' => '表前缀只能包含数字、字母和下划线!']);
  129. }
  130. if (empty($username)) {
  131. return resultArray(['error' => '请填写管理员用户名!']);
  132. }
  133. if (empty($wkcode)) {
  134. return resultArray(['error' => '请填写序列号!']);
  135. }
  136. $resCheckData = checkWkCode($wkcode);
  137. if (!$resCheckData) {
  138. return resultArray(['error' => '序列号错误!']);
  139. }
  140. $resData = object_to_array(json_decode($resCheckData));
  141. if ($resData['date'] != date('Y-m-d')) {
  142. return resultArray(['error' => '序列号已失效,请前往悟空官网个人中心获取最新数据!']);
  143. }
  144. if (empty($password)) {
  145. return resultArray(['error' => '请填写管理员密码!']);
  146. }
  147. session('install_count','');
  148. session('install_now','');
  149. $database = $db_config['database'];
  150. unset($db_config['database']);
  151. $connect = Db::connect($db_config);
  152. // 检测数据库连接
  153. try{
  154. $ret = $connect->execute('select version()');
  155. }catch(\Exception $e){
  156. return resultArray(['error' => '数据库连接失败,请检查数据库配置!']);
  157. }
  158. $check = $connect->execute("SELECT * FROM information_schema.schemata WHERE schema_name='".$database."'");
  159. if (!$check && !$connect->execute("CREATE DATABASE IF NOT EXISTS `".$database."` default collate utf8_general_ci ")) {
  160. return resultArray(['error' => '没有找到您填写的数据库名且无法创建!请检查连接账号是否有创建数据库的权限!']);
  161. }
  162. $db_config['database'] = $database;
  163. self::mkDatabase($db_config);
  164. self::mkLicense($wkcode);
  165. $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
  166. $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm.sql');
  167. $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
  168. if ($sqlList) {
  169. $sqlList = array_filter($sqlList);
  170. $install_count = count($sqlList);
  171. session('install_count',$install_count);
  172. foreach ($sqlList as $k=>$v) {
  173. $install_now = $k+1;
  174. session('install_now',$install_now);
  175. try {
  176. $temp_sql = $v.';';
  177. Db::connect($db_config)->query($temp_sql);
  178. } catch(\Exception $e) {
  179. // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
  180. return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
  181. }
  182. }
  183. }
  184. $salt = substr(md5(time()),0,4);
  185. $password = user_md5(trim($password), $salt, $username);
  186. //插入信息
  187. 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 )");
  188. 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 )");
  189. touch(CONF_PATH . "install.lock");
  190. return resultArray(['data'=>'安装成功']);
  191. }
  192. /**
  193. * 安装成功界面
  194. *
  195. * @author fnqi
  196. * @date 2021-03-11
  197. * @return mixed
  198. */
  199. public function step5()
  200. {
  201. return $this->fetch();
  202. }
  203. /**
  204. * 安装超时界面
  205. *
  206. * @author fanqi
  207. * @date 2021-03-11
  208. * @return mixed
  209. */
  210. public function step6()
  211. {
  212. return $this->fetch();
  213. }
  214. //ajax 进度条
  215. public function progress()
  216. {
  217. $data['length'] = session('install_count');
  218. $data['now'] = session('install_now');
  219. return resultArray(['data'=>$data]);
  220. }
  221. //添加database.php文件
  222. private function mkDatabase(array $data)
  223. {
  224. $code = <<<INFO
  225. <?php
  226. return [
  227. // 数据库类型
  228. 'type' => 'mysql',
  229. // 服务器地址
  230. 'hostname' => '{$data['hostname']}',
  231. // 数据库名
  232. 'database' => '{$data['database']}',
  233. // 用户名
  234. 'username' => '{$data['username']}',
  235. // 密码
  236. 'password' => '{$data['password']}',
  237. // 端口
  238. 'hostport' => '{$data['hostport']}',
  239. // 连接dsn
  240. 'dsn' => '',
  241. // 数据库连接参数
  242. 'params' => [],
  243. // 数据库编码默认采用utf8
  244. 'charset' => 'utf8',
  245. // 数据库表前缀
  246. 'prefix' => '{$data['prefix']}',
  247. // 数据库调试模式
  248. 'debug' => true,
  249. // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
  250. 'deploy' => 0,
  251. // 数据库读写是否分离 主从式有效
  252. 'rw_separate' => false,
  253. // 读写分离后 主服务器数量
  254. 'master_num' => 1,
  255. // 指定从服务器序号
  256. 'slave_no' => '',
  257. // 自动读取主库数据
  258. 'read_master' => false,
  259. // 是否严格检查字段是否存在
  260. 'fields_strict' => true,
  261. // 数据集返回类型
  262. 'resultset_type' => 'array',
  263. ];
  264. INFO;
  265. file_put_contents( CONF_PATH.'database.php', $code);
  266. // 判断写入是否成功
  267. $config = include CONF_PATH.'database.php';
  268. if (empty($config['database']) || $config['database'] != $data['database']) {
  269. return resultArray(['error' => '[config/database.php]数据库配置写入失败!']);
  270. }
  271. return true;
  272. }
  273. //检查目录权限
  274. public function check_dir_iswritable($dir_path){
  275. $dir_path=str_replace( '\\','/',$dir_path);
  276. $is_writale=1;
  277. if (!is_dir($dir_path)) {
  278. $is_writale=0;
  279. return $is_writale;
  280. } else {
  281. $file_hd=@fopen($dir_path.'/test.txt','w');
  282. if (!$file_hd) {
  283. @fclose($file_hd);
  284. @unlink($dir_path.'/test.txt');
  285. $is_writale=0;
  286. return $is_writale;
  287. }
  288. $dir_hd = opendir($dir_path);
  289. while (false !== ($file=readdir($dir_hd))) {
  290. if ($file != "." && $file != "..") {
  291. if (is_file($dir_path.'/'.$file)) {
  292. //文件不可写,直接返回
  293. if (!is_writable($dir_path.'/'.$file)) {
  294. return 0;
  295. }
  296. } else {
  297. $file_hd2=@fopen($dir_path.'/'.$file.'/test.txt','w');
  298. if (!$file_hd2) {
  299. @fclose($file_hd2);
  300. @unlink($dir_path.'/'.$file.'/test.txt');
  301. $is_writale=0;
  302. return $is_writale;
  303. }
  304. //递归
  305. $is_writale=check_dir_iswritable($dir_path.'/'.$file);
  306. }
  307. }
  308. }
  309. }
  310. return $is_writale;
  311. }
  312. /**
  313. * [checkVersion 检查升级]
  314. * @author Michael_xu
  315. * @param
  316. */
  317. public function checkVersion(){
  318. $version = Config::load('version');
  319. $info = sendRequest($this->upgrade_site.'index.php?m=version&a=checkVersion', $version['VERSION']);
  320. if ($info){
  321. return resultArray(['data' => $info]);
  322. } else {
  323. return resultArray(['error' => '检查新版本出错!']);
  324. }
  325. }
  326. /**
  327. * 环境检测
  328. * @return array
  329. */
  330. private function checkNnv()
  331. {
  332. $items = [
  333. 'os' => ['操作系统', PHP_OS, '类Unix', 'ok'],
  334. 'php' => ['PHP版本', PHP_VERSION, '7.3 ( <em style="color: #888; font-size: 12px;">>= 5.6</em> )', 'ok','性能更佳'],
  335. 'gd' => ['gd', '开启', '开启', 'ok'],
  336. 'openssl' => ['openssl', '开启', '开启', 'ok'],
  337. 'pdo' => ['pdo', '开启', '开启', 'ok'],
  338. ];
  339. session('install_error','');
  340. if (substr($items['php'][1],0,3) < '5.6') {
  341. $items['php'][3] = 'error';
  342. session('install_error', true);
  343. }
  344. if (!extension_loaded('gd')) {
  345. $items['gd'][1] = '未开启';
  346. $items['gd'][3] = 'error';
  347. session('install_error', true);
  348. }
  349. if (!extension_loaded('openssl')) {
  350. $items['openssl'][1] = '未开启';
  351. $items['openssl'][3] = 'error';
  352. session('install_error', true);
  353. }
  354. if (!extension_loaded('pdo')) {
  355. $items['pdo'][1] = '未开启';
  356. $items['pdo'][3] = 'error';
  357. session('install_error', true);
  358. }
  359. // dump($items);die;
  360. return $items;
  361. }
  362. /**
  363. * 目录权限检查
  364. * @return array
  365. */
  366. private function checkDir()
  367. {
  368. $items = [
  369. ['dir', $this->root_path.'application', 'application', '读写', '读写', 'ok'],
  370. ['dir', $this->root_path.'extend', 'extend', '读写', '读写', 'ok'],
  371. ['dir', $this->root_path.'runtime', './temp', '读写', '读写', 'ok'],
  372. ['dir', $this->root_path.'public', './upload', '读写', '读写', 'ok'],
  373. ['file', $this->root_path.'config', 'config', '读写', '读写', 'ok'],
  374. ];
  375. foreach ($items as &$v) {
  376. if ($v[0] == 'dir') {// 文件夹
  377. if (!is_writable($v[1])) {
  378. if (is_dir($v[1])) {
  379. $v[4] = '不可写';
  380. $v[5] = 'no';
  381. } else {
  382. $v[4] = '不存在';
  383. $v[5] = 'no';
  384. }
  385. session('install_error', true);
  386. }
  387. } else {// 文件
  388. if (!is_writable($v[1])) {
  389. $v[4] = '不可写';
  390. $v[5] = 'no';
  391. session('install_error', true);
  392. }
  393. }
  394. }
  395. return $items;
  396. }
  397. /**
  398. * 验证序列号
  399. * @param
  400. * @return
  401. */
  402. public function checkCodeOld($username) {
  403. $encryption = md5($username);
  404. $substr = substr($username, strlen($username)-6);
  405. $subArr = str_split($substr, 1);
  406. $code = '';
  407. for ($i = 0; $i <= 5; $i++) {
  408. $code .= $encryption[$subArr[$i]];
  409. }
  410. return $code;
  411. }
  412. //写入license文件
  413. private function mkLicense($wkcode)
  414. {
  415. file_put_contents( CONF_PATH.'license.dat', $wkcode);
  416. // 判断写入是否成功
  417. // $config = include CONF_PATH.'license.dat';
  418. // if (empty($config)) {
  419. // return resultArray(['error' => 'license配置写入失败!']);
  420. // }
  421. return true;
  422. }
  423. }