InstallController.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: liuyifan
  5. * Date: 2019/4/2
  6. * Time: 13:36
  7. */
  8. namespace app\platform\controllers;
  9. use Illuminate\Redis\Database;
  10. use Predis\Connection\ConnectionException;
  11. use \Illuminate\Support\Facades\DB;
  12. use app\platform\modules\system\models\SystemSetting;
  13. use app\platform\modules\user\models\AdminUser;
  14. use app\common\services\Utils;
  15. use app\platform\modules\user\models\YzUserProfile;
  16. use app\common\traits\JsonTrait;
  17. use Illuminate\Support\Facades\Redis;
  18. use League\Flysystem\Filesystem;
  19. class InstallController
  20. {
  21. use JsonTrait;
  22. public $user_txt;
  23. public function __construct()
  24. {
  25. if (file_exists(base_path().'/bootstrap/install.lock')) {
  26. return $this->errorJson('操作失败,商城已部署', ['status' => -1]);
  27. }
  28. $this->user_txt = base_path().'/app/platform/controllers/user.txt';
  29. }
  30. public function agreement()
  31. {
  32. /* // 取出 xml 单独标签列
  33. $file = base_path().'/manifest.xml';
  34. $con = file_get_contents($file);
  35. $xmlTag = 'version';
  36. preg_match_all("/<".$xmlTag.">.*<\/".$xmlTag.">/", $con, $temp);
  37. // 返回 ] 第一次出现的位置
  38. $first = strpos($temp[0][0],"]");
  39. // 返回 [ 最后一次出现的位置
  40. $end = strripos($temp[0][0],"[")+1;
  41. $version = substr($temp[0][0], $end, $first-$end);*/
  42. /* $app = config('database.redis.default');
  43. $app['host'] = '123';
  44. $a = new Database($app);
  45. $b = $a->connection();
  46. return $this->successJson('成功', [
  47. 'version' => $a,
  48. 'version' => $a,
  49. 'version1' => $app,
  50. ]);*/
  51. /* $redis['host']= '127.0.0.1';
  52. $pwd= null;
  53. $redis['port']= '6379';
  54. $redis['cache_database']= '1';
  55. $redis['database']= '0';
  56. $str = '<?php
  57. $redis = array();
  58. $redis[\'host\'] = \'' . $redis['host']. '\';
  59. $redis[\'password\'] = \'' . $pwd . '\';
  60. //$redis[\'port\'] = \'' . $redis['port'] . '\';
  61. //$redis[\'database\'] = \'' . $redis['database']. '\';
  62. //$redis[\'cache_database\'] = \'' . $redis['cache_database']. '\';
  63. //';
  64. file_put_contents(base_path('database/redis.php'), $str); //写入配置文件
  65. //\Artisan::call('config:cache');
  66. config(['database.redis.default.password' => $pwd]);
  67. config(['database.redis.cache.password' => $pwd]);
  68. app()->singleton('redis', function ($app) {
  69. return new Database($app['config']['database.redis']);
  70. });
  71. $a = \Illuminate\Support\Facades\Redis::ping();
  72. dd($a);*/
  73. $version = require base_path('config/version.php').'';
  74. return $this->successJson('成功', [
  75. 'version' => $version
  76. ]);
  77. }
  78. /**
  79. * 运行环境检测
  80. */
  81. public function check()
  82. {
  83. // 服务器操作系统
  84. $ret['server_os'] = php_uname();
  85. // 服务器域名
  86. $ret['server_name'] = $_SERVER['SERVER_NAME'];
  87. // PHP版本
  88. $ret['php_version'] = PHP_VERSION;
  89. // 程序安装目录
  90. $ret['servier_dir'] = base_path();
  91. // 磁盘剩余空间
  92. if(function_exists('disk_free_space')) {
  93. $ret['server_disk'] = floor(disk_free_space(base_path()) / (1024*1024)).'M';
  94. } else {
  95. $ret['server_disk'] = 'unknow';
  96. }
  97. // 上传限制
  98. $ret['upload_size'] = @ini_get('file_uploads') ? ini_get('upload_max_filesize') : 'unknow';
  99. // 检测PHP版本必须为5.6
  100. $ret['php_version_remark'] = true;
  101. if(version_compare(PHP_VERSION, '5.6.0') == -1 && version_compare(PHP_VERSION, '5.7') == 1 ) {
  102. $ret['php_version_remark'] = false;
  103. }
  104. // 检测 cURL
  105. $ret['php_curl'] = extension_loaded('curl') && function_exists('curl_init');
  106. // cURL 版本
  107. $ret['php_curl_version'] = curl_version()['version'];
  108. // 检测 PDO
  109. $ret['php_pdo'] = extension_loaded('pdo') && extension_loaded('pdo_mysql');
  110. // 检测 openSSL
  111. $ret['php_openssl'] = extension_loaded('openssl');
  112. // 检测 GD
  113. $ret['php_gd'] = extension_loaded('gd');
  114. // GD 库版本
  115. $ret['php_gd_version'] = gd_info()['GD Version'];
  116. // 检测 session.auto_start开启
  117. // $ret['php_session_auto_start'] = strtolower(ini_get('session.auto_start')) == '0' || 'off' ? true : false;
  118. // 检测 json
  119. // $ret['json'] = extension_loaded('json') && function_exists('json_decode') && function_exists('json_encode');
  120. // 检测 file_get_content
  121. $ret['file_get_content'] = function_exists('file_get_contents');
  122. //检测redis
  123. // $ret['redis'] = $this->getRedisStatus();
  124. $result = $this->returnData($ret);
  125. return $this->successJson('成功', [
  126. 'server_info'=> $result['server_info'],
  127. 'sysytem_environment' => $result['sysytem_environment'],
  128. 'check_function' => $result['check_function']
  129. ]);
  130. }
  131. /**
  132. * 运行环境检测 返回数据
  133. *
  134. * @param $ret
  135. * @return mixed
  136. */
  137. public function returnData($ret)
  138. {
  139. $result['server_info'] = [
  140. [
  141. 'name' => '服务器操作系统',
  142. 'value' => $ret['server_os'],
  143. ],
  144. [
  145. 'name' => '服务器域名',
  146. 'value' => $ret['server_name'],
  147. ],
  148. [
  149. 'name' => 'PHP版本',
  150. 'value' => $ret['php_version'],
  151. ],
  152. [
  153. 'name' => '程序安装目录',
  154. 'value' => $ret['servier_dir'],
  155. ],
  156. [
  157. 'name' => '磁盘剩余空间',
  158. 'value' => $ret['server_disk'],
  159. ],
  160. [
  161. 'name' => '上传限制大小',
  162. 'value' => $ret['upload_size'],
  163. ],
  164. ];
  165. $result['sysytem_environment'] = [
  166. [
  167. 'name' => 'PHP版本',
  168. 'need' => '7.4',
  169. 'optimum' => '7.4',
  170. 'check' => $ret['php_version_remark'],
  171. 'value' => $ret['php_version'],
  172. ],
  173. [
  174. 'name' => 'cURL',
  175. 'need' => '支持',
  176. 'optimum' => '无限制',
  177. 'check' => $ret['php_curl'],
  178. 'value' => $ret['php_curl_version'],
  179. ],
  180. [
  181. 'name' => 'PDO',
  182. 'need' => '支持',
  183. 'optimum' => '无限制',
  184. 'check' => $ret['php_pdo'],
  185. 'value' => $ret['php_pdo'] ? '支持' : '不支持',
  186. ],
  187. [
  188. 'name' => 'openSSL',
  189. 'need' => '支持',
  190. 'optimum' => '无限制',
  191. 'check' => $ret['php_openssl'],
  192. 'value' => $ret['php_openssl'] ? '支持' : '不支持',
  193. ],
  194. [
  195. 'name' => 'GD',
  196. 'need' => '支持',
  197. 'optimum' => 'GD2',
  198. 'check' => $ret['php_gd'],
  199. 'value' => $ret['php_gd_version'],
  200. ]
  201. /* [
  202. 'name' => 'Redis',
  203. 'need' => '支持',
  204. 'optimum' => '无限制',
  205. 'check' => $ret['redis'],
  206. 'value' => $ret['redis'] ? '支持' : '不支持',
  207. ],*/
  208. ];
  209. $result['check_function'] = [
  210. [
  211. 'name' => 'file_get_content',
  212. 'need' => '支持',
  213. 'value' => $ret['file_get_content'] ? '支持' : '不支持',
  214. ],
  215. ];
  216. return $result;
  217. }
  218. /**
  219. * 文件权限设置
  220. */
  221. public function filePower()
  222. {
  223. $check_filename = [
  224. '/bootstrap',
  225. '/storage/framework',
  226. '/storage/logs'
  227. ];
  228. $check = [
  229. base_path() . '/bootstrap/cache',
  230. base_path() . '/storage/framework/view',
  231. base_path() . '/storage/logs',
  232. ];
  233. $ret = [];
  234. for($i=0; $i<count($check); $i++) {
  235. $ret[$i]['name'] = $check_filename[$i];
  236. $ret[$i]['need'] = '可写';
  237. $ret[$i]['value'] = (bool)$this->check_writeable($check[$i]);
  238. }
  239. //判断是否存在static文件夹,没有的话就下载免费版,并覆盖掉原来的文件
  240. $static_dir = base_path()."/static";
  241. if (is_dir($static_dir)) {
  242. $dh = @opendir($static_dir);
  243. $i = 0;
  244. while (($file = readdir($dh)) !== false){
  245. if($file != "." && $file != ".."){
  246. $i += 1;
  247. }
  248. }
  249. closedir($dh);
  250. if ($i <= 0) {
  251. //下载免费版并覆盖原来的数据
  252. $this->downloadFree();
  253. }
  254. } else {
  255. //下载免费版并覆盖原来的数据
  256. $this->downloadFree();
  257. }
  258. return $this->successJson('成功', $ret);
  259. }
  260. /**
  261. * 检查目录是否有可读可写的权限
  262. * @param $dir
  263. * @return int
  264. */
  265. private function check_writeable($dir)
  266. {
  267. $writeable = 0;
  268. if(!is_dir($dir)) {
  269. @mkdir($dir, 0777);
  270. }
  271. if(is_dir($dir)) {
  272. if($fp = fopen("$dir/test.txt", 'w+')) {
  273. fclose($fp);
  274. unlink("$dir/test.txt");
  275. $writeable = 1;
  276. } else {
  277. $writeable = 0;
  278. }
  279. }
  280. return $writeable;
  281. }
  282. /**
  283. * 账号设置
  284. */
  285. public function setInformation()
  286. {
  287. $set = request()->set;
  288. $user = request()->user;
  289. $redis = request()->redis;
  290. $set['AUTH_PASSWORD'] = randNum(8);
  291. $filename = base_path().'/.env';
  292. $env = file_get_contents($filename);
  293. // 验证超级管理员信息
  294. if (!$user['username'] || !$user['password']) {
  295. return $this->errorJson('用户名或密码不能为空');
  296. } elseif ($user['password'] !== $user['repassword']) {
  297. return $this->errorJson('两次密码不一致');
  298. }
  299. foreach ($set as $item=>$value) {
  300. // 获取键第一次出现位置
  301. $check_env_key = strpos($env, $item);
  302. // 获取键后面 \n 换行符第一次出现位置
  303. $check_env_value = strpos($env, "\n", $check_env_key);
  304. // 得出两个位置之间的内容进行替换
  305. $num = $check_env_value - $check_env_key;
  306. if ((bool)$check_env_key) {
  307. $env = substr_replace($env, "{$item}='{$value}'", $check_env_key, $num);
  308. } else {
  309. $env .= "\n{$item}='$value'\n";
  310. }
  311. }
  312. try{
  313. $link = new \PDO("mysql:host=".$set['DB_HOST'].";port=".$set['DB_PORT'], $set['DB_USERNAME'], $set['DB_PASSWORD']);
  314. $link->exec("CREATE DATABASE IF NOT EXISTS `{$set['DB_DATABASE']}` DEFAULT CHARACTER SET utf8");
  315. new \PDO("mysql:host=".$set['DB_HOST'].";dbname=".$set['DB_DATABASE'].";port=".$set['DB_PORT'], $set['DB_USERNAME'], $set['DB_PASSWORD']);
  316. } catch (\Exception $e){
  317. return $this->errorJson($e->getMessage());
  318. }
  319. $result = file_put_contents($filename, $env);
  320. if (!$result) {
  321. return $this->errorJson('保存mysql配置数据有误');
  322. }
  323. fopen($this->user_txt, 'w+');
  324. file_put_contents($this->user_txt, serialize($user));
  325. $this->mvenv($set);
  326. if ($redis) {
  327. if(strtolower($redis['password']) == 'null' || empty($redis['password'])) {
  328. $redis['password'] = null;
  329. }
  330. $str = '<?php
  331. $redis = array();
  332. $redis[\'host\'] = \'' . $redis['host']. '\';
  333. $redis[\'password\'] = \'' . $redis['password'] . '\';
  334. $redis[\'port\'] = \'' . $redis['port'] . '\';
  335. $redis[\'database\'] = \'' . $redis['database']. '\';
  336. $redis[\'cache_database\'] = \'' . $redis['cache_database']. '\';
  337. ';
  338. file_put_contents(base_path('database/redis.php'), $str); //写入配置文件
  339. config(['database.redis.default.host' => $redis['host']]);
  340. config(['database.redis.default.password' => $redis['password']]);
  341. config(['database.redis.default.port' => $redis['port']]);
  342. config(['database.redis.default.database' => $redis['database']]);
  343. config(['database.redis.cache.host' => $redis['host']]);
  344. config(['database.redis.cache.password' => $redis['password']]);
  345. config(['database.redis.cache.port' => $redis['port']]);
  346. config(['database.redis.cache.database' => $redis['database']]);
  347. app()->singleton('redis', function ($app) {
  348. return new Database($app['config']['database.redis']);
  349. });
  350. //检测redis连接
  351. return $this->getRedisStatus();
  352. }
  353. return $this->successJson('成功');
  354. }
  355. /**
  356. * 迁移数据库信息
  357. */
  358. public function mvenv($set)
  359. {
  360. $str = '<?php
  361. $config = array();
  362. $config[\'db\'][\'master\'][\'host\'] = \'' . $set['DB_HOST'] . '\';
  363. $config[\'db\'][\'master\'][\'username\'] = \'' . $set['DB_USERNAME'] . '\';
  364. $config[\'db\'][\'master\'][\'password\'] = \'' .$set['DB_PASSWORD'] . '\';
  365. $config[\'db\'][\'master\'][\'port\'] = \'' .$set['DB_PORT'] . '\';
  366. $config[\'db\'][\'master\'][\'database\'] = \'' . $set['DB_DATABASE'] . '\';
  367. $config[\'db\'][\'master\'][\'tablepre\'] = \'' . $set['DB_PREFIX'] . '\';
  368. $config[\'db\'][\'slave_status\'] = false;
  369. $config[\'db\'][\'slave\'][\'1\'][\'host\'] = \'\';
  370. $config[\'db\'][\'slave\'][\'1\'][\'username\'] = \'\';
  371. $config[\'db\'][\'slave\'][\'1\'][\'password\'] = \'\';
  372. $config[\'db\'][\'slave\'][\'1\'][\'port\'] = \'\';
  373. $config[\'db\'][\'slave\'][\'1\'][\'database\'] = \'\';
  374. $config[\'db\'][\'slave\'][\'1\'][\'tablepre\'] = \'\';
  375. ';
  376. app(\Illuminate\Filesystem\Filesystem::class)->put(base_path('database/config.php'), $str);
  377. }
  378. /**
  379. * 创建数据
  380. */
  381. public function createData()
  382. {
  383. ini_set('max_execution_time','0');
  384. include_once base_path() . '/sql.php';
  385. // try{
  386. // exec('php artisan migrate',$result); //执行命令
  387. // }catch (\Exception $e) {
  388. // $e->getMessage();
  389. // }
  390. try {
  391. \Log::debug('安装初始数据迁移');
  392. \Artisan::call('migrate',['--force' => true]);
  393. \Artisan::call('db:seed', ['--force' => true, '--class' => 'YzSystemSettingTableSeeder']);
  394. }catch (\Exception $e) {
  395. return $this->errorJson('创建数据失败,请重新安装');
  396. }
  397. $user_model = new AdminUser;
  398. if ($user_model->find(1)) {
  399. return $this->successJson('成功');
  400. }
  401. // 取出账号设置的信息
  402. $user = unserialize(file_get_contents($this->user_txt));
  403. // 保存站点名称
  404. $site_name = SystemSetting::settingSave(['name' => $user['name']], 'copyright', 'system_copyright');
  405. if (!$site_name) {
  406. return $this->errorJson('创建数据失败,请重新安装');
  407. }
  408. $user['password'] = bcrypt($user['password']);
  409. $user['status'] = 0;
  410. $user['type'] = 0;
  411. $user['lastvisit'] = time();
  412. $user['lastip'] = Utils::getClientIp();
  413. $user['joinip'] = Utils::getClientIp();
  414. $mobile = $user['mobile'];
  415. unset($user['name']);
  416. unset($user['repassword']);
  417. unset($user['mobile']);
  418. $user_model->fill($user);
  419. if (!$user_model->save()) {
  420. $this->errorJson('创建数据失败,请重新安装');
  421. }
  422. // 保存用户信息关联表信息
  423. $user_profile = YzUserProfile::create(['uid' => $user_model['uid'], 'mobile' => $mobile]);
  424. if (!$user_profile) {
  425. $this->errorJson('创建数据失败,请重新安装');
  426. }
  427. @unlink(base_path().'/app/platform/controllers/user.txt');
  428. fopen(base_path()."/bootstrap/install.lock", "w+");
  429. return $this->successJson('成功');
  430. }
  431. public function downloadFree()
  432. {
  433. //①:下载压缩包到指定位置
  434. $fileURL = "https://downloads.yunzmall.com/bt_static/static.zip";
  435. $filename = date("Ymd")."_yun_shop.zip";
  436. $fh = fopen(base_path().'/'.$filename, 'w');
  437. $ch = curl_init();
  438. curl_setopt($ch, CURLOPT_URL, $fileURL);
  439. curl_setopt($ch, CURLOPT_FILE, $fh);
  440. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // this will follow redirects
  441. curl_exec($ch);
  442. curl_close($ch);
  443. fclose($fh);
  444. //②:解压覆盖当前文件夹,删除压缩包
  445. $path = pathinfo(realpath($filename), PATHINFO_DIRNAME);
  446. $file_name = $path."/".$filename;
  447. chmod($file_name,0755);
  448. $zip = new \ZipArchive();
  449. $res = $zip->open($file_name);
  450. if ($res === TRUE) {
  451. for($i=0;$i<$zip->numFiles;$i++){
  452. $entry_info = $zip->statIndex($i);
  453. if(substr($entry_info["name"],0,strlen("static/")) != "static/"){
  454. $zip->deleteIndex($i);
  455. }
  456. }
  457. }
  458. if ($res === TRUE) {
  459. $zip->extractTo($path);
  460. $zip->close();
  461. }
  462. @unlink(base_path().'/'.$filename);
  463. }
  464. public function delete()
  465. {
  466. if (env('APP_ENV') == 'production') {
  467. @unlink(base_path().'/app/platform/controllers/InstallController.php');
  468. }
  469. return $this->successJson('成功');
  470. }
  471. public function getRedisStatus()
  472. {
  473. try {
  474. if (!class_exists('Predis\Client')) {
  475. return $this->errorJson('Predis未安装');
  476. }
  477. $res = \Illuminate\Support\Facades\Redis::ping() == 'PONG';
  478. if ($res) {
  479. return $this->successJson('成功');
  480. }
  481. } catch (ConnectionException $exception) {
  482. return $this->errorJson('redis连接失败');
  483. } catch (\Exception $exception) {
  484. return $this->errorJson('redis无法使用');
  485. }
  486. }
  487. //生成6位随机账号
  488. public function getRandomUser()
  489. {
  490. $digits = array_flip(range('0', '9'));
  491. $lowercase = array_flip(range('a', 'z'));
  492. $combined = array_merge($digits, $lowercase);
  493. $password = str_shuffle(array_rand($digits) .
  494. array_rand($lowercase) .
  495. implode(array_rand($combined,4))
  496. );
  497. return $this->successJson('生成随机账号成功',$password);
  498. }
  499. //生成12位随机密码串
  500. public function getRandomPsw()
  501. {
  502. $digits = array_flip(range('0', '9'));
  503. $lowercase = array_flip(range('a', 'z'));
  504. $uppercase = array_flip(range('A', 'Z'));
  505. $special = array_flip(str_split('.!@#$%^&*()_+-?'));
  506. $combined = array_merge($digits, $lowercase, $uppercase, $special);
  507. $password = str_shuffle(array_rand($digits) .
  508. array_rand($lowercase) .
  509. array_rand($uppercase) .
  510. array_rand($special) .
  511. implode(array_rand($combined,8))
  512. );
  513. return $this->successJson('生成随机密码成功',$password);
  514. }
  515. }