Installer.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace App\Console\Commands;
  3. use Illuminate\Console\Command;
  4. use Illuminate\Support\Facades\Redis;
  5. class Installer extends Command
  6. {
  7. /**
  8. * The name and signature of the console command.
  9. *
  10. * @var string
  11. */
  12. protected $signature = 'install';
  13. /**
  14. * The console command description.
  15. *
  16. * @var string
  17. */
  18. protected $description = 'CLI Installer';
  19. /**
  20. * Create a new command instance.
  21. *
  22. * @return void
  23. */
  24. public function __construct()
  25. {
  26. parent::__construct();
  27. }
  28. /**
  29. * Execute the console command.
  30. *
  31. * @return mixed
  32. */
  33. public function handle()
  34. {
  35. $this->welcome();
  36. }
  37. protected function welcome()
  38. {
  39. $this->info(' ____ _ ______ __ ');
  40. $this->info(' / __ \(_) _____ / / __/__ ____/ / ');
  41. $this->info(' / /_/ / / |/_/ _ \/ / /_/ _ \/ __ / ');
  42. $this->info(' / ____/ /> </ __/ / __/ __/ /_/ / ');
  43. $this->info(' /_/ /_/_/|_|\___/_/_/ \___/\__,_/ ');
  44. $this->info(' ');
  45. $this->info(' Welcome to the Pixelfed Installer!');
  46. $this->info(' ');
  47. $this->info(' ');
  48. $this->info('Pixelfed version: ' . config('pixelfed.version'));
  49. $this->line(' ');
  50. $this->info('Scanning system...');
  51. $this->preflightCheck();
  52. }
  53. protected function preflightCheck()
  54. {
  55. $this->line(' ');
  56. $this->info('Checking for installed dependencies...');
  57. $redis = Redis::connection();
  58. if($redis->ping()) {
  59. $this->info('- Found redis!');
  60. } else {
  61. $this->error('- Redis not found, aborting installation');
  62. exit;
  63. }
  64. $this->checkPhpDependencies();
  65. $this->checkPermissions();
  66. $this->envCheck();
  67. }
  68. protected function checkPhpDependencies()
  69. {
  70. $extensions = [
  71. 'bcmath',
  72. 'ctype',
  73. 'curl',
  74. 'json',
  75. 'mbstring',
  76. 'openssl'
  77. ];
  78. $ffmpeg = exec('which ffmpeg');
  79. if(empty($ffmpeg)) {
  80. $this->error('FFmpeg not found, please install it.');
  81. $this->error('Cancelling installation.');
  82. exit;
  83. } else {
  84. $this->info('- Found FFmpeg!');
  85. }
  86. $this->line('');
  87. $this->info('Checking for required php extensions...');
  88. foreach($extensions as $ext) {
  89. if(extension_loaded($ext) == false) {
  90. $this->error("- {$ext} extension not found, aborting installation");
  91. exit;
  92. } else {
  93. }
  94. }
  95. $this->info("- Required PHP extensions found!");
  96. }
  97. protected function checkPermissions()
  98. {
  99. $this->line('');
  100. $this->info('Checking for proper filesystem permissions...');
  101. $paths = [
  102. base_path('bootstrap'),
  103. base_path('storage')
  104. ];
  105. foreach($paths as $path) {
  106. if(is_writeable($path) == false) {
  107. $this->error("- Invalid permission found! Aborting installation.");
  108. $this->error(" Please make the following path writeable by the web server:");
  109. $this->error(" $path");
  110. exit;
  111. } else {
  112. $this->info("- Found valid permissions for {$path}");
  113. }
  114. }
  115. }
  116. protected function envCheck()
  117. {
  118. if(!file_exists(base_path('.env')) || filesize(base_path('.env')) == 0) {
  119. $this->line('');
  120. $this->info('No .env configuration file found. We will create one now!');
  121. $this->createEnv();
  122. } else {
  123. $confirm = $this->confirm('Found .env file, do you want to overwrite it?');
  124. if(!$confirm) {
  125. $this->info('Cancelling installation.');
  126. exit;
  127. }
  128. $confirm = $this->confirm('Are you really sure you want to overwrite it?');
  129. if(!$confirm) {
  130. $this->info('Cancelling installation.');
  131. exit;
  132. }
  133. $this->error('Warning ... if you did not backup your .env before its overwritten it will be permanently deleted.');
  134. $confirm = $this->confirm('The application may be installed already, are you really sure you want to overwrite it?');
  135. if(!$confirm) {
  136. $this->info('Cancelling installation.');
  137. exit;
  138. }
  139. }
  140. $this->postInstall();
  141. }
  142. protected function createEnv()
  143. {
  144. $this->line('');
  145. // copy env
  146. if(!file_exists(app()->environmentFilePath())) {
  147. exec('cp .env.example .env');
  148. $this->call('key:generate');
  149. }
  150. $name = $this->ask('Site name [ex: Pixelfed]');
  151. $this->updateEnvFile('APP_NAME', $name ?? 'pixelfed');
  152. $domain = $this->ask('Site Domain [ex: pixelfed.com]');
  153. $this->updateEnvFile('APP_DOMAIN', $domain ?? 'example.org');
  154. $this->updateEnvFile('ADMIN_DOMAIN', $domain ?? 'example.org');
  155. $this->updateEnvFile('SESSION_DOMAIN', $domain ?? 'example.org');
  156. $this->updateEnvFile('APP_URL', 'https://' . $domain ?? 'https://example.org');
  157. $database = $this->choice('Select database driver', ['mysql', 'pgsql'], 0);
  158. $this->updateEnvFile('DB_CONNECTION', $database ?? 'mysql');
  159. switch ($database) {
  160. case 'mysql':
  161. $database_host = $this->ask('Select database host', '127.0.0.1');
  162. $this->updateEnvFile('DB_HOST', $database_host ?? 'mysql');
  163. $database_port = $this->ask('Select database port', 3306);
  164. $this->updateEnvFile('DB_PORT', $database_port ?? 3306);
  165. $database_db = $this->ask('Select database', 'pixelfed');
  166. $this->updateEnvFile('DB_DATABASE', $database_db ?? 'pixelfed');
  167. $database_username = $this->ask('Select database username', 'pixelfed');
  168. $this->updateEnvFile('DB_USERNAME', $database_username ?? 'pixelfed');
  169. $db_pass = str_random(64);
  170. $database_password = $this->secret('Select database password', $db_pass);
  171. $this->updateEnvFile('DB_PASSWORD', $database_password);
  172. break;
  173. }
  174. $cache = $this->choice('Select cache driver', ["redis", "apc", "array", "database", "file", "memcached"], 0);
  175. $this->updateEnvFile('CACHE_DRIVER', $cache ?? 'redis');
  176. $session = $this->choice('Select session driver', ["redis", "file", "cookie", "database", "apc", "memcached", "array"], 0);
  177. $this->updateEnvFile('SESSION_DRIVER', $session ?? 'redis');
  178. $redis_host = $this->ask('Set redis host', 'localhost');
  179. $this->updateEnvFile('REDIS_HOST', $redis_host);
  180. $redis_password = $this->ask('Set redis password', 'null');
  181. $this->updateEnvFile('REDIS_PASSWORD', $redis_password);
  182. $redis_port = $this->ask('Set redis port', 6379);
  183. $this->updateEnvFile('REDIS_PORT', $redis_port);
  184. $open_registration = $this->choice('Allow new registrations?', ['true', 'false'], 1);
  185. $this->updateEnvFile('OPEN_REGISTRATION', $open_registration);
  186. $enforce_email_verification = $this->choice('Enforce email verification?', ['true', 'false'], 0);
  187. $this->updateEnvFile('ENFORCE_EMAIL_VERIFICATION', $enforce_email_verification);
  188. }
  189. protected function updateEnvFile($key, $value)
  190. {
  191. $envPath = app()->environmentFilePath();
  192. $payload = file_get_contents($envPath);
  193. if ($existing = $this->existingEnv($key, $payload)) {
  194. $payload = str_replace("{$key}={$existing}", "{$key}=\"{$value}\"", $payload);
  195. $this->storeEnv($payload);
  196. } else {
  197. $payload = $payload . "\n{$key}=\"{$value}\"\n";
  198. $this->storeEnv($payload);
  199. }
  200. }
  201. protected function existingEnv($needle, $haystack)
  202. {
  203. preg_match("/^{$needle}=[^\r\n]*/m", $haystack, $matches);
  204. if ($matches && count($matches)) {
  205. return substr($matches[0], strlen($needle) + 1);
  206. }
  207. return false;
  208. }
  209. protected function storeEnv($payload)
  210. {
  211. $file = fopen(app()->environmentFilePath(), 'w');
  212. fwrite($file, $payload);
  213. fclose($file);
  214. }
  215. protected function postInstall()
  216. {
  217. $this->callSilent('config:cache');
  218. //$this->callSilent('route:cache');
  219. $this->info('Pixelfed has been successfully installed!');
  220. }
  221. }