123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  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. if (!in_array($a, array('upgrade','upgradeprocess','checkversion')) && file_exists(CONF_PATH . "install.lock")) {
  30. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  31. die();
  32. }
  33. }
  34. private $upgrade_site = "http://message.72crm.com/";
  35. /**
  36. * [index 安装步骤]
  37. * @author Michael_xu
  38. * @param
  39. */
  40. public function index()
  41. {
  42. if (file_exists(CONF_PATH . "install.lock")) {
  43. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('请勿重复安装!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  44. die();
  45. }
  46. if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
  47. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('缺少必要的数据库文件!');location.href='".$_SERVER["HTTP_HOST"]."';</script>";
  48. die();
  49. }
  50. return $this->fetch('index');
  51. }
  52. public function step1()
  53. {
  54. session('install_error',null);
  55. $data = [];
  56. $data['env'] = self::checkNnv();
  57. $data['dir'] = self::checkDir();
  58. $data['version'] = $this->version();
  59. $this->assign('data',$data);
  60. return $this->fetch('step1');
  61. }
  62. //版本
  63. public function version()
  64. {
  65. $res = include(CONF_PATH.'version.php');
  66. return $res ? : array('VERSION' => '9.0.0','RELEASE' => '20190330');
  67. }
  68. public function step2(){
  69. if (session('install_error')){
  70. echo "<meta http-equiv='content-type' content='text/html; charset=UTF-8'> <script>alert('环境检测未通过,不能进行下一步操作!');location.href='".$_SERVER["HTTP_REFERER"]."';</script>";
  71. die();
  72. }
  73. $data['os'] = PHP_OS;
  74. $data['php'] = phpversion();
  75. $data['version'] = $this->version();
  76. $this->assign('envir_data',$data);
  77. return $this->fetch();
  78. }
  79. public function step3(){
  80. return $this->fetch();
  81. }
  82. public function step4(){
  83. if (session('install_error')){
  84. return resultArray(['error' => '环境检测未通过,不能进行下一步操作!']);
  85. }
  86. if (file_exists(CONF_PATH . "install.lock")) {
  87. return resultArray(['error' => '请勿重复安装!']);
  88. }
  89. if (!file_exists(getcwd() . "/public/sql/5kcrm.sql")) {
  90. return resultArray(['error' => '缺少必要的数据库文件!']);
  91. }
  92. $temp = $this->param;
  93. $param = $temp['form'];
  94. $db_config['type'] = 'mysql';
  95. $db_config['hostname'] = $param['databaseUrl'];
  96. $db_config['hostport'] = $param['databasePort'];
  97. $db_config['database'] = $param['databaseName'];
  98. $db_config['username'] = $param['databaseUser'];
  99. $db_config['password'] = $param['databasePwd'];
  100. $db_config['prefix'] = $param['databaseTable'];
  101. $username = $param['root'];
  102. $password = $param['pwd'];
  103. if (empty($db_config['hostname'])) {
  104. return resultArray(['error' => '请填写数据库主机!']);
  105. }
  106. if (empty($db_config['hostport'])) {
  107. return resultArray(['error' => '请填写数据库端口!']);
  108. }
  109. if (preg_match('/[^0-9]/', $db_config['hostport'])) {
  110. return resultArray(['error' => '数据库端口只能是数字!']);
  111. }
  112. if (empty($db_config['database'])) {
  113. return resultArray(['error' => '请填写数据库名!']);
  114. }
  115. if (empty($db_config['username'])) {
  116. return resultArray(['error' => '请填写数据库用户名!']);
  117. }
  118. if (empty($db_config['password'])) {
  119. return resultArray(['error' => '请填写数据库密码!']);
  120. }
  121. if (empty($db_config['prefix'])) {
  122. return resultArray(['error' => '请填写表前缀!']);
  123. }
  124. if (preg_match('/[^a-z0-9_]/i', $db_config['prefix'])) {
  125. return resultArray(['error' => '表前缀只能包含数字、字母和下划线!']);
  126. }
  127. if (empty($username)) {
  128. return resultArray(['error' => '请填写管理员用户名!']);
  129. }
  130. if (empty($password)) {
  131. return resultArray(['error' => '请填写管理员密码!']);
  132. }
  133. session('install_count','');
  134. session('install_now','');
  135. $database = $db_config['database'];
  136. unset($db_config['database']);
  137. $connect = Db::connect($db_config);
  138. // 检测数据库连接
  139. try{
  140. $ret = $connect->execute('select version()');
  141. }catch(\Exception $e){
  142. return resultArray(['error' => '数据库连接失败,请检查数据库配置!']);
  143. }
  144. $check = $connect->execute("SELECT * FROM information_schema.schemata WHERE schema_name='".$database."'");
  145. if (!$check && !$connect->execute("CREATE DATABASE IF NOT EXISTS `".$database."` default collate utf8_general_ci ")) {
  146. return resultArray(['error' => '没有找到您填写的数据库名且无法创建!请检查连接账号是否有创建数据库的权限!']);
  147. }
  148. $db_config['database'] = $database;
  149. self::mkDatabase($db_config);
  150. $C_Patch = substr($_SERVER['SCRIPT_FILENAME'],0,-10);
  151. $sql = file_get_contents( $C_Patch.'/public/sql/5kcrm.sql');
  152. $sqlList = parse_sql($sql, 0, ['5kcrm_' => $db_config['prefix']]);
  153. if ($sqlList) {
  154. $sqlList = array_filter($sqlList);
  155. $install_count = count($sqlList);
  156. session('install_count',$install_count);
  157. foreach ($sqlList as $k=>$v) {
  158. $install_now = $k+1;
  159. session('install_now',$install_now);
  160. try {
  161. $temp_sql = $v.';';
  162. Db::connect($db_config)->query($temp_sql);
  163. } catch(\Exception $e) {
  164. // return resultArray(['error' => '请启用InnoDB数据引擎,并检查数据库是否有DROP和CREATE权限']);
  165. return resultArray(['error' => '数据库sql安装出错,请操作数据库手动导入sql文件']);
  166. }
  167. }
  168. }
  169. $salt = substr(md5(time()),0,4);
  170. $password = user_md5(trim($password), $salt, $username);
  171. //插入信息
  172. 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 )");
  173. 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 )");
  174. touch(CONF_PATH . "install.lock");
  175. return resultArray(['data'=>'安装成功']);
  176. }
  177. //ajax 进度条
  178. public function progress()
  179. {
  180. $data['length'] = session('install_count');
  181. $data['now'] = session('install_now');
  182. return resultArray(['data'=>$data]);
  183. }
  184. //添加database.php文件
  185. private function mkDatabase(array $data)
  186. {
  187. $code = <<<INFO
  188. <?php
  189. return [
  190. // 数据库类型
  191. 'type' => 'mysql',
  192. // 服务器地址
  193. 'hostname' => '{$data['hostname']}',
  194. // 数据库名
  195. 'database' => '{$data['database']}',
  196. // 用户名
  197. 'username' => '{$data['username']}',
  198. // 密码
  199. 'password' => '{$data['password']}',
  200. // 端口
  201. 'hostport' => '{$data['hostport']}',
  202. // 连接dsn
  203. 'dsn' => '',
  204. // 数据库连接参数
  205. 'params' => [],
  206. // 数据库编码默认采用utf8
  207. 'charset' => 'utf8',
  208. // 数据库表前缀
  209. 'prefix' => '{$data['prefix']}',
  210. // 数据库调试模式
  211. 'debug' => true,
  212. // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
  213. 'deploy' => 0,
  214. // 数据库读写是否分离 主从式有效
  215. 'rw_separate' => false,
  216. // 读写分离后 主服务器数量
  217. 'master_num' => 1,
  218. // 指定从服务器序号
  219. 'slave_no' => '',
  220. // 自动读取主库数据
  221. 'read_master' => false,
  222. // 是否严格检查字段是否存在
  223. 'fields_strict' => true,
  224. // 数据集返回类型
  225. 'resultset_type' => 'array',
  226. ];
  227. INFO;
  228. file_put_contents( CONF_PATH.'database.php', $code);
  229. // 判断写入是否成功
  230. $config = include CONF_PATH.'database.php';
  231. if (empty($config['database']) || $config['database'] != $data['database']) {
  232. return resultArray(['error' => '[config/database.php]数据库配置写入失败!']);
  233. }
  234. return true;
  235. }
  236. //检查目录权限
  237. public function check_dir_iswritable($dir_path){
  238. $dir_path=str_replace( '\\','/',$dir_path);
  239. $is_writale=1;
  240. if (!is_dir($dir_path)) {
  241. $is_writale=0;
  242. return $is_writale;
  243. } else {
  244. $file_hd=@fopen($dir_path.'/test.txt','w');
  245. if (!$file_hd) {
  246. @fclose($file_hd);
  247. @unlink($dir_path.'/test.txt');
  248. $is_writale=0;
  249. return $is_writale;
  250. }
  251. $dir_hd = opendir($dir_path);
  252. while (false !== ($file=readdir($dir_hd))) {
  253. if ($file != "." && $file != "..") {
  254. if (is_file($dir_path.'/'.$file)) {
  255. //文件不可写,直接返回
  256. if (!is_writable($dir_path.'/'.$file)) {
  257. return 0;
  258. }
  259. } else {
  260. $file_hd2=@fopen($dir_path.'/'.$file.'/test.txt','w');
  261. if (!$file_hd2) {
  262. @fclose($file_hd2);
  263. @unlink($dir_path.'/'.$file.'/test.txt');
  264. $is_writale=0;
  265. return $is_writale;
  266. }
  267. //递归
  268. $is_writale=check_dir_iswritable($dir_path.'/'.$file);
  269. }
  270. }
  271. }
  272. }
  273. return $is_writale;
  274. }
  275. /**
  276. * [checkVersion 检查升级]
  277. * @author Michael_xu
  278. * @param
  279. */
  280. public function checkVersion(){
  281. $version = Config::load('version');
  282. $info = sendRequest($this->upgrade_site.'index.php?m=version&a=checkVersion', $version['VERSION']);
  283. if ($info){
  284. return resultArray(['data' => $info]);
  285. } else {
  286. return resultArray(['error' => '检查新版本出错!']);
  287. }
  288. }
  289. /**
  290. * 环境检测
  291. * @return array
  292. */
  293. private function checkNnv()
  294. {
  295. $items = [
  296. 'os' => ['操作系统', PHP_OS, '类Unix', 'ok'],
  297. 'php' => ['PHP版本', PHP_VERSION, '7.2 ( <em style="color: #888; font-size: 12px;">>= 5.6</em> )', 'ok','性能更佳'],
  298. 'gd' => ['gd', '开启', '开启', 'ok'],
  299. 'openssl' => ['openssl', '开启', '开启', 'ok'],
  300. 'pdo' => ['pdo', '开启', '开启', 'ok'],
  301. ];
  302. session('install_error','');
  303. if (substr($items['php'][1],0,3) < '5.6') {
  304. $items['php'][3] = 'error';
  305. session('install_error', true);
  306. }
  307. if (!extension_loaded('gd')) {
  308. $items['gd'][1] = '未开启';
  309. $items['gd'][3] = 'error';
  310. session('install_error', true);
  311. }
  312. if (!extension_loaded('openssl')) {
  313. $items['openssl'][1] = '未开启';
  314. $items['openssl'][3] = 'error';
  315. session('install_error', true);
  316. }
  317. if (!extension_loaded('pdo')) {
  318. $items['pdo'][1] = '未开启';
  319. $items['pdo'][3] = 'error';
  320. session('install_error', true);
  321. }
  322. // dump($items);die;
  323. return $items;
  324. }
  325. /**
  326. * 目录权限检查
  327. * @return array
  328. */
  329. private function checkDir()
  330. {
  331. $items = [
  332. ['dir', $this->root_path.'application', 'application', '读写', '读写', 'ok'],
  333. ['dir', $this->root_path.'extend', 'extend', '读写', '读写', 'ok'],
  334. ['dir', $this->root_path.'runtime', './temp', '读写', '读写', 'ok'],
  335. ['dir', $this->root_path.'public', './upload', '读写', '读写', 'ok'],
  336. ['file', $this->root_path.'config', 'config', '读写', '读写', 'ok'],
  337. ];
  338. foreach ($items as &$v) {
  339. if ($v[0] == 'dir') {// 文件夹
  340. if (!is_writable($v[1])) {
  341. if (is_dir($v[1])) {
  342. $v[4] = '不可写';
  343. $v[5] = 'no';
  344. } else {
  345. $v[4] = '不存在';
  346. $v[5] = 'no';
  347. }
  348. session('install_error', true);
  349. }
  350. } else {// 文件
  351. if (!is_writable($v[1])) {
  352. $v[4] = '不可写';
  353. $v[5] = 'no';
  354. session('install_error', true);
  355. }
  356. }
  357. }
  358. return $items;
  359. }
  360. }