Index.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. <?php
  2. namespace app\install\controller;
  3. use app\model\shop\Shop;
  4. use app\model\system\Addon;
  5. use app\model\system\Api;
  6. use app\model\system\Group;
  7. use app\model\system\H5;
  8. use app\model\system\Menu;
  9. use app\model\system\Site;
  10. use app\model\system\User;
  11. use think\facade\Cache;
  12. use think\facade\Event;
  13. class Index extends BaseInstall
  14. {
  15. public function __construct()
  16. {
  17. //执行父类构造函数
  18. parent::__construct();
  19. }
  20. /**
  21. *安装
  22. */
  23. public function index()
  24. {
  25. if (file_exists($this->lock_file)) {
  26. $this->redirect(__ROOT__);
  27. }
  28. $step = input("step", 1);
  29. if ($step == 1) {
  30. return $this->fetch('index/step-1', [], $this->replace);
  31. } elseif ($step == 2) {
  32. //系统变量
  33. $system_variables = [];
  34. $phpv = phpversion();
  35. $os = PHP_OS;
  36. $server = $_SERVER[ 'SERVER_SOFTWARE' ];
  37. $host = ( empty($_SERVER[ 'REMOTE_ADDR' ]) ? $_SERVER[ 'REMOTE_HOST' ] : $_SERVER[ 'REMOTE_ADDR' ] );
  38. $name = $_SERVER[ 'SERVER_NAME' ];
  39. $verison = version_compare(PHP_VERSION, '7.1.0') == -1 ? false : true;
  40. //pdo
  41. $pdo = extension_loaded('pdo') && extension_loaded('pdo_mysql');
  42. $system_variables[] = [ "name" => "pdo", "need" => "开启", "status" => $pdo ];
  43. //curl
  44. $curl = extension_loaded('curl') && function_exists('curl_init');
  45. $system_variables[] = [ "name" => "curl", "need" => "开启", "status" => $curl ];
  46. //openssl
  47. $openssl = extension_loaded('openssl');
  48. $system_variables[] = [ "name" => "openssl", "need" => "开启", "status" => $openssl ];
  49. //gd
  50. $gd = extension_loaded('gd');
  51. $system_variables[] = [ "name" => "GD库", "need" => "开启", "status" => $gd ];
  52. //fileinfo
  53. $fileinfo = extension_loaded('fileinfo');
  54. $system_variables[] = [ "name" => "fileinfo", "need" => "开启", "status" => $fileinfo ];
  55. $root_path = str_replace("\\", DIRECTORY_SEPARATOR, dirname(dirname(dirname(dirname(__FILE__)))));
  56. $root_path = str_replace("/", DIRECTORY_SEPARATOR, $root_path);
  57. $dirs_list = [
  58. [ "path" => $root_path, "path_name" => "/", "name" => "整目录" ],
  59. [ "path" => $root_path . DIRECTORY_SEPARATOR . "public", "path_name" => "public", "name" => "public" ],
  60. [ "path" => $root_path . DIRECTORY_SEPARATOR . "config", "path_name" => "config", "name" => "config" ],
  61. [ "path" => $root_path . DIRECTORY_SEPARATOR . 'runtime', "path_name" => "runtime", "name" => "runtime" ],
  62. [ "path" => $root_path . DIRECTORY_SEPARATOR . 'app/install', "path_name" => "app/install", "name" => "安装目录" ]
  63. ];
  64. //目录 可读 可写检测
  65. $is_dir = true;
  66. foreach ($dirs_list as $k => $v) {
  67. $is_readable = is_readable($v[ "path" ]);
  68. $is_write = is_write($v[ "path" ]);
  69. $dirs_list[ $k ][ "is_readable" ] = $is_readable;
  70. $dirs_list[ $k ][ "is_write" ] = $is_write;
  71. if ($is_readable == false || $is_write == false) {
  72. $is_dir = false;
  73. }
  74. }
  75. $this->assign("root_path", $root_path);
  76. $this->assign("system_variables", $system_variables);
  77. $this->assign("phpv", $phpv);
  78. $this->assign("server", $server);
  79. $this->assign("host", $host);
  80. $this->assign("os", $os);
  81. $this->assign("name", $name);
  82. $this->assign("verison", $verison);
  83. $this->assign("dirs_list", $dirs_list);
  84. if ($verison && $pdo && $curl && $openssl && $gd && $fileinfo && $is_dir) {
  85. $continue = true;
  86. } else {
  87. $continue = false;
  88. }
  89. $this->assign("continue", $continue);
  90. return $this->fetch('index/step-2', [], $this->replace);
  91. } elseif ($step == 3) {
  92. return $this->fetch('index/step-3', [], $this->replace);
  93. } elseif ($step == 4) {
  94. set_time_limit(300);
  95. $source_file = "./app/install/source/database.php";//源配置文件
  96. $target_dir = "./config";
  97. $target_file = "database.php";
  98. $file_name = "./app/install/source/database.sql";//数据文件
  99. //数据库
  100. $dbport = input("dbport", "3306");
  101. $dbhost = input("dbhost", "localhost");
  102. $dbuser = input("dbuser", "root");
  103. $dbpwd = input("dbpwd", "root");
  104. $dbname = input("dbname", "niushop_b2c_v5");//数据库名称
  105. $dbprefix = input("dbprefix", "");//前缀
  106. //平台
  107. $site_name = input('site_name', "");
  108. $username = input('username', "");
  109. $password = input('password', "");
  110. $password2 = input('password2', "");
  111. $yanshi = input('yanshi', "");// 演示数据开关
  112. if ($dbhost == '' || $dbuser == '') {
  113. return $this->returnError([], '数据库链接配置信息丢失!');
  114. }
  115. // if ($dbprefix == '') {
  116. // return $this->returnError('数据表前缀为空!');
  117. // }
  118. //可写测试
  119. $write_result = is_write($target_dir);
  120. if (!$write_result) {
  121. //判断是否有可写的权限,linux操作系统要注意这一点,windows不必注意。
  122. return $this->returnError([], '配置文件不可写,权限不够!');
  123. }
  124. //数据库连接测试
  125. $conn = @mysqli_connect($dbhost, $dbuser, $dbpwd, "", $dbport);
  126. if (!$conn) {
  127. return $this->returnError([], '连接数据库失败!请检查连接参数!');
  128. }
  129. //平台
  130. if ($site_name == '' || $username == '' || $password == '') {
  131. return $this->returnError([], '平台信息不能为空!');
  132. }
  133. if ($password != $password2) {
  134. return $this->returnError([], '两次密码输入不一样,请重新输入');
  135. }
  136. //数据库可写和是否存在测试
  137. $empty_db = mysqli_select_db($conn, $dbname);
  138. if ($empty_db) {
  139. $sql = "DROP DATABASE `$dbname`";
  140. $retval = mysqli_query($conn, $sql);
  141. if (!$retval) {
  142. return $this->returnError([], '删除数据库失败: ' . mysqli_error($conn));
  143. }
  144. }
  145. //如果数据库不存在,我们就进行创建。
  146. $dbsql = "CREATE DATABASE `$dbname`";
  147. $db_create = mysqli_query($conn, $dbsql);
  148. if (!$db_create) {
  149. return $this->returnError([], '创建数据库失败,请确认是否有足够的权限!');
  150. }
  151. //链接数据库
  152. @mysqli_select_db($conn, $dbname);
  153. //修改配置文件
  154. $fp = fopen($source_file, "r");
  155. $configStr = fread($fp, filesize($source_file));
  156. fclose($fp);
  157. $configStr = str_replace('model_hostname', $dbhost, $configStr);
  158. $configStr = str_replace('model_database', $dbname, $configStr);
  159. $configStr = str_replace("model_username", $dbuser, $configStr);
  160. $configStr = str_replace("model_password", $dbpwd, $configStr);
  161. $configStr = str_replace("model_port", $dbport, $configStr);
  162. $configStr = str_replace("model_prefix", $dbprefix, $configStr);
  163. $fp = fopen($target_dir . DIRECTORY_SEPARATOR . $target_file, "w");
  164. if ($fp == false) {
  165. return $this->returnError([], '写入配置失败,请检查' . $target_dir . '/' . $target_file . '是否可写入!');
  166. }
  167. fwrite($fp, $configStr);
  168. fclose($fp);
  169. //导入SQL并执行。
  170. $get_sql_data = file_get_contents($file_name);
  171. $sql_query = $this->getSqlQuery($get_sql_data);
  172. @mysqli_query($conn, "SET NAMES utf8");
  173. $query_count = count($sql_query);
  174. for ($i = 0; $i < $query_count; $i++) {
  175. $sql = trim($sql_query[$i]);
  176. if (strstr($sql, 'CREATE TABLE')) {
  177. $match_item = preg_match('/CREATE TABLE [`]?(\\w+)[`]?/is', $sql, $match_data);
  178. } elseif(strstr($sql, 'ALTER TABLE')) {
  179. $match_item = preg_match('/ALTER TABLE [`]?(\\w+)[`]?/is', $sql, $match_data);
  180. }elseif(strstr($sql, 'INSERT INTO')){
  181. $match_item = preg_match('/INSERT INTO [`]?(\\w+)[`]?/is', $sql, $match_data);
  182. }else{
  183. $match_item = 0;
  184. }
  185. if ($match_item > 0) {
  186. try{
  187. $table_name = $match_data[ "1" ];
  188. $new_table_name = $dbprefix . $table_name;
  189. $sql_item = $this->str_replace_first($table_name, $new_table_name, $sql);
  190. @mysqli_query($conn, $sql_item);
  191. }catch(\Exception $e){
  192. return $this->returnError([], '数据库解析失败'.$e->getMessage());
  193. }
  194. }
  195. }
  196. @mysqli_close($conn);
  197. $database_config = include $target_dir . DIRECTORY_SEPARATOR . $target_file;
  198. \think\facade\Config::set($database_config, "database");
  199. //安装菜单
  200. $menu = new Menu();
  201. $shop_menu_res = $menu->refreshMenu('shop', '');
  202. if ($shop_menu_res[ "code" ] < 0) {
  203. return $this->returnError([], '店铺菜单失败!');
  204. }
  205. //安装插件
  206. $addon_model = new Addon();
  207. $addon_result = $addon_model->installAllAddon();
  208. if ($addon_result[ "code" ] < 0) {
  209. return $this->returnError([], $addon_result[ "message" ]);
  210. }
  211. $this->init_data = include "./app/install/source/init.php";//源配置文件
  212. $initdata_result = $this->initData(input());
  213. if ($initdata_result[ "code" ] < 0) {
  214. return $this->returnError([], '默认数据添加失败!');
  215. }
  216. // H5端刷新
  217. $h5 = new H5();
  218. $h5_res = $h5->refresh();
  219. if ($h5_res[ 'code' ] < 0) {
  220. return $this->returnError([], 'h5部署失败!');
  221. }
  222. //添加店铺
  223. $site_data = [
  224. 'site_type' => 'shop',
  225. 'create_time' => time(),
  226. 'site_name' => $site_name,
  227. 'username' => $username
  228. ];
  229. $site_model = new Site();
  230. $site_result = $site_model->addSite($site_data);
  231. if ($site_result[ 'code' ] < 0) {
  232. return $this->returnError([], '默认站点添加失败!');
  233. }
  234. $site_id = $site_result[ 'data' ];
  235. $shop_data = [
  236. 'site_id' => $site_id,
  237. 'shop_status' => 1
  238. ];
  239. $shop_model = new Shop();
  240. $shop_result = $shop_model->addShop($shop_data);
  241. if ($shop_result[ 'code' ] < 0) {
  242. return $this->returnError([], '默认店铺添加失败!');
  243. }
  244. // 添加默认数据
  245. $default_result = $this->defaultData($site_id);
  246. if ($default_result[ 'code' ] < 0) {
  247. return $default_result;
  248. }
  249. //添加系统用户组
  250. $group_model = new Group();
  251. $group_data = array (
  252. "site_id" => $site_id,
  253. "app_module" => "shop",
  254. "group_name" => "系统管理员",
  255. "group_status" => 1,
  256. "is_system" => 1,
  257. "menu_array" => "",
  258. "desc" => "",
  259. );
  260. $group_result = $group_model->addGroup($group_data);
  261. if ($group_result[ "code" ] < 0) {
  262. return $this->returnError([], '后台管理员权限组添加失败!');
  263. }
  264. $group_id = $group_result[ "data" ];
  265. $user_model = new User();
  266. $user_data = array (
  267. "app_module" => "shop",
  268. "app_group" => 0,
  269. "is_admin" => 1,
  270. "site_id" => $site_id,
  271. "group_id" => $group_id,
  272. "username" => $username,
  273. "password" => $password
  274. );
  275. $user_result = $user_model->addUser($user_data);
  276. if ($user_result[ "code" ] < 0) {
  277. return $this->returnError([], '后台管理员添加失败!');
  278. }
  279. if ($yanshi) {
  280. // 演示数据
  281. $yanshi_data_result = $this->yanShiData($site_id);
  282. if ($yanshi_data_result[ "code" ] < 0) {
  283. return $this->returnError([], '演示数据添加失败!');
  284. }
  285. }
  286. $fp = fopen($this->lock_file, "w");
  287. if ($fp == false) {
  288. return $this->returnError([], "写入失败,请检查目录" . dirname(dirname(__FILE__)) . "是否可写入!'");
  289. }
  290. fwrite($fp, '已安装');
  291. fclose($fp);
  292. return $this->returnSuccess([], "安装成功");
  293. }
  294. }
  295. public function installSuccess()
  296. {
  297. return $this->fetch('index/step-4', [], $this->replace);
  298. }
  299. /**
  300. * 测试数据库
  301. */
  302. public function testDb($dbhost = '', $dbport = '', $dbuser = '', $dbpwd = '', $dbname = '')
  303. {
  304. $dbport = input("dbport", "");
  305. $dbhost = input("dbhost", "");
  306. $dbuser = input("dbuser", "");
  307. $dbpwd = input("dbpwd", "");
  308. $dbname = input("dbname", "");
  309. try {
  310. if ($dbport != "" && $dbhost != "") {
  311. $dbhost = $dbport != '3306' ? $dbhost . ':' . $dbport : $dbhost;
  312. }
  313. if ($dbhost == '' || $dbuser == '') {
  314. return $this->returnError([
  315. "status" => -1,
  316. "message" => "数据库账号或密码不能为空"
  317. ]);
  318. }
  319. if (!function_exists("mysqli_connect")) {
  320. return $this->returnError([
  321. "status" => -1,
  322. "message" => "mysqli扩展类必须开启"
  323. ]);
  324. }
  325. $conn = @mysqli_connect($dbhost, $dbuser, $dbpwd);
  326. if ($conn) {
  327. if (empty($dbname)) {
  328. $result = [
  329. "status" => 1,
  330. "message" => "数据库连接成功"
  331. ];
  332. } else {
  333. if (@mysqli_select_db($conn, $dbname)) {
  334. $result = [
  335. "status" => 2,
  336. "message" => "数据库存在,系统将覆盖数据库"
  337. ];
  338. } else {
  339. $result = [
  340. "status" => 1,
  341. "message" => "数据库不存在,系统将自动创建"
  342. ];
  343. }
  344. }
  345. } else {
  346. $result = [
  347. "status" => -1,
  348. "message" => "数据库连接失败!"
  349. ];
  350. }
  351. @mysqli_close($conn);
  352. return $this->returnSuccess($result);
  353. } catch (\Exception $e) {
  354. $result = [
  355. "status" => -1,
  356. "message" => $e->getMessage()
  357. ];
  358. return $this->returnSuccess($result);
  359. }
  360. }
  361. /**
  362. * @param $sql_data sql文件
  363. * @return array
  364. */
  365. public function getSqlQuery($sql_data)
  366. {
  367. $sql_data = preg_replace("/TYPE=(InnoDB|MyISAM|MEMORY)( DEFAULT CHARSET=[^; ]+)?/", "ENGINE=\\1 DEFAULT CHARSET=utf8", $sql_data);
  368. $sql_data = str_replace("\r", "\n", $sql_data);
  369. $sql_query = [];
  370. $num = 0;
  371. $sql_arr = explode(";\n", trim($sql_data));
  372. unset($sql);
  373. foreach ($sql_arr as $sql) {
  374. $sql_query[$num] = '';
  375. $sqls = explode("\n", trim($sql));
  376. $sqls = array_filter($sqls);
  377. foreach ($sqls as $query) {
  378. $str1 = substr($query, 0, 1);
  379. if ($str1 != '#' && $str1 != '-')
  380. $sql_query[$num] .= $query;
  381. }
  382. $num++;
  383. }
  384. return $sql_query;
  385. }
  386. /**
  387. * 初始化平台数据
  388. */
  389. private function initData($param)
  390. {
  391. $init_event_result = $this->initEvent();
  392. if ($init_event_result[ 'code' ] < 0) {
  393. return $init_event_result;
  394. }
  395. // 初始化自定义组件、链接
  396. $diyview_result = $this->initDiyView();
  397. if ($diyview_result[ 'code' ] < 0) {
  398. return $this->returnError([], '自定义组件初始化失败!');
  399. }
  400. $api_model = new Api();
  401. $data = array (
  402. "public_key" => $this->init_data[ 'api' ][ 'public_key' ],
  403. "private_key" => $this->init_data[ 'api' ][ 'private_key' ],
  404. );
  405. $api_result = $api_model->setApiConfig($data, 1);
  406. if ($api_result[ 'code' ] < 0) {
  407. return $this->returnError([], 'api秘钥配置失败!');
  408. }
  409. return $this->returnSuccess();
  410. }
  411. /**
  412. * 添加店铺默认数据
  413. */
  414. private function defaultData($site_id)
  415. {
  416. // 添加店铺相册默认分组
  417. model("album")->add([ 'site_id' => $site_id, 'type' => 'video', 'album_name' => "默认分组", 'update_time' => time(), 'is_default' => 1, 'level' => 1 ]);
  418. $result = model("album")->add([ 'site_id' => $site_id, 'type' => 'img', 'album_name' => "默认分组", 'update_time' => time(), 'is_default' => 1, 'level' => 1 ]);
  419. if ($result === false) {
  420. return $this->returnError([], '默认相册创建失败!');
  421. }
  422. //执行事件
  423. $add_site_result = event("AddSite", [ 'site_id' => $site_id ]);
  424. if (!empty($add_site_result)) {
  425. foreach ($add_site_result as $site_item) {
  426. if (!empty($site_item) && $site_item[ 'code' ] < 0) {
  427. return $this->returnError([], $site_item[ 'message' ]);
  428. }
  429. }
  430. }
  431. return $this->returnSuccess();
  432. }
  433. /**
  434. * 演示数据
  435. * @param $sys_uid
  436. * @return array
  437. */
  438. private function yanShiData($site_id)
  439. {
  440. $result_array = event("AddYanshiData", [ 'site_id' => $site_id ]);
  441. if (!empty($result_array)) {
  442. foreach ($result_array as $item) {
  443. if (!empty($item) && $item[ 'code' ] < 0) {
  444. return $this->returnError([], $item[ 'message' ]);
  445. }
  446. }
  447. }
  448. return $this->returnSuccess();
  449. }
  450. /**
  451. * 初始化自定义组件、链接
  452. * @return array
  453. */
  454. private function initDiyView()
  455. {
  456. $addon = new Addon();
  457. $res = $addon->refreshDiyView('');
  458. return $res;
  459. }
  460. /**
  461. * 初始化插件
  462. */
  463. private function initEvent()
  464. {
  465. try {
  466. $cache = Cache::get("addon_event_list");
  467. if (empty($cache)) {
  468. $addon_model = new Addon();
  469. $addon_data = $addon_model->getAddonList([], 'name');
  470. $listen_array = [];
  471. foreach ($addon_data[ 'data' ] as $k => $v) {
  472. $addon_event = require_once 'addon/' . $v[ 'name' ] . '/config/event.php';
  473. $listen = isset($addon_event[ 'listen' ]) ? $addon_event[ 'listen' ] : [];
  474. if (!empty($listen)) {
  475. $listen_array[] = $listen;
  476. }
  477. }
  478. Cache::tag("addon")->set("addon_event_list", $listen_array);
  479. } else {
  480. $listen_array = $cache;
  481. }
  482. if (!empty($listen_array)) {
  483. foreach ($listen_array as $k => $listen) {
  484. if (!empty($listen)) {
  485. Event::listenEvents($listen);
  486. }
  487. }
  488. }
  489. return $this->returnSuccess();
  490. } catch (\Exception $e) {
  491. return $this->returnError('', $e->getMessage());
  492. }
  493. }
  494. function str_replace_first($search, $replace, $subject)
  495. {
  496. return implode($replace, explode($search, $subject, 2));
  497. }
  498. }