PageRenderTime 85ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Console/Installer.php

https://gitlab.com/vortexadventures/void
PHP | 246 lines | 138 code | 31 blank | 77 comment | 19 complexity | 5869bd1847fcc9c781545ee6e72fa747 MD5 | raw file
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice.
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
  11. * @link https://cakephp.org CakePHP(tm) Project
  12. * @since 3.0.0
  13. * @license https://opensource.org/licenses/mit-license.php MIT License
  14. */
  15. namespace App\Console;
  16. if (!defined('STDIN')) {
  17. define('STDIN', fopen('php://stdin', 'r'));
  18. }
  19. use Cake\Utility\Security;
  20. use Composer\Script\Event;
  21. use Exception;
  22. /**
  23. * Provides installation hooks for when this application is installed via
  24. * composer. Customize this class to suit your needs.
  25. */
  26. class Installer
  27. {
  28. /**
  29. * An array of directories to be made writable
  30. */
  31. const WRITABLE_DIRS = [
  32. 'logs',
  33. 'tmp',
  34. 'tmp/cache',
  35. 'tmp/cache/models',
  36. 'tmp/cache/persistent',
  37. 'tmp/cache/views',
  38. 'tmp/sessions',
  39. 'tmp/tests'
  40. ];
  41. /**
  42. * Does some routine installation tasks so people don't have to.
  43. *
  44. * @param \Composer\Script\Event $event The composer event object.
  45. * @throws \Exception Exception raised by validator.
  46. * @return void
  47. */
  48. public static function postInstall(Event $event)
  49. {
  50. $io = $event->getIO();
  51. $rootDir = dirname(dirname(__DIR__));
  52. static::createAppConfig($rootDir, $io);
  53. static::createWritableDirectories($rootDir, $io);
  54. // ask if the permissions should be changed
  55. if ($io->isInteractive()) {
  56. $validator = function ($arg) {
  57. if (in_array($arg, ['Y', 'y', 'N', 'n'])) {
  58. return $arg;
  59. }
  60. throw new Exception('This is not a valid answer. Please choose Y or n.');
  61. };
  62. $setFolderPermissions = $io->askAndValidate(
  63. '<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ',
  64. $validator,
  65. 10,
  66. 'Y'
  67. );
  68. if (in_array($setFolderPermissions, ['Y', 'y'])) {
  69. static::setFolderPermissions($rootDir, $io);
  70. }
  71. } else {
  72. static::setFolderPermissions($rootDir, $io);
  73. }
  74. static::setSecuritySalt($rootDir, $io);
  75. $class = 'Cake\Codeception\Console\Installer';
  76. if (class_exists($class)) {
  77. $class::customizeCodeceptionBinary($event);
  78. }
  79. }
  80. /**
  81. * Create the config/app.php file if it does not exist.
  82. *
  83. * @param string $dir The application's root directory.
  84. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  85. * @return void
  86. */
  87. public static function createAppConfig($dir, $io)
  88. {
  89. $appConfig = $dir . '/config/app.php';
  90. $defaultConfig = $dir . '/config/app.default.php';
  91. if (!file_exists($appConfig)) {
  92. copy($defaultConfig, $appConfig);
  93. $io->write('Created `config/app.php` file');
  94. }
  95. }
  96. /**
  97. * Create the `logs` and `tmp` directories.
  98. *
  99. * @param string $dir The application's root directory.
  100. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  101. * @return void
  102. */
  103. public static function createWritableDirectories($dir, $io)
  104. {
  105. foreach (static::WRITABLE_DIRS as $path) {
  106. $path = $dir . '/' . $path;
  107. if (!file_exists($path)) {
  108. mkdir($path);
  109. $io->write('Created `' . $path . '` directory');
  110. }
  111. }
  112. }
  113. /**
  114. * Set globally writable permissions on the "tmp" and "logs" directory.
  115. *
  116. * This is not the most secure default, but it gets people up and running quickly.
  117. *
  118. * @param string $dir The application's root directory.
  119. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  120. * @return void
  121. */
  122. public static function setFolderPermissions($dir, $io)
  123. {
  124. // Change the permissions on a path and output the results.
  125. $changePerms = function ($path) use ($io) {
  126. $currentPerms = fileperms($path) & 0777;
  127. $worldWritable = $currentPerms | 0007;
  128. if ($worldWritable == $currentPerms) {
  129. return;
  130. }
  131. $res = chmod($path, $worldWritable);
  132. if ($res) {
  133. $io->write('Permissions set on ' . $path);
  134. } else {
  135. $io->write('Failed to set permissions on ' . $path);
  136. }
  137. };
  138. $walker = function ($dir) use (&$walker, $changePerms) {
  139. $files = array_diff(scandir($dir), ['.', '..']);
  140. foreach ($files as $file) {
  141. $path = $dir . '/' . $file;
  142. if (!is_dir($path)) {
  143. continue;
  144. }
  145. $changePerms($path);
  146. $walker($path);
  147. }
  148. };
  149. $walker($dir . '/tmp');
  150. $changePerms($dir . '/tmp');
  151. $changePerms($dir . '/logs');
  152. }
  153. /**
  154. * Set the security.salt value in the application's config file.
  155. *
  156. * @param string $dir The application's root directory.
  157. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  158. * @return void
  159. */
  160. public static function setSecuritySalt($dir, $io)
  161. {
  162. $newKey = hash('sha256', Security::randomBytes(64));
  163. static::setSecuritySaltInFile($dir, $io, $newKey, 'app.php');
  164. }
  165. /**
  166. * Set the security.salt value in a given file
  167. *
  168. * @param string $dir The application's root directory.
  169. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  170. * @param string $newKey key to set in the file
  171. * @param string $file A path to a file relative to the application's root
  172. * @return void
  173. */
  174. public static function setSecuritySaltInFile($dir, $io, $newKey, $file)
  175. {
  176. $config = $dir . '/config/' . $file;
  177. $content = file_get_contents($config);
  178. $content = str_replace('__SALT__', $newKey, $content, $count);
  179. if ($count == 0) {
  180. $io->write('No Security.salt placeholder to replace.');
  181. return;
  182. }
  183. $result = file_put_contents($config, $content);
  184. if ($result) {
  185. $io->write('Updated Security.salt value in config/' . $file);
  186. return;
  187. }
  188. $io->write('Unable to update Security.salt value.');
  189. }
  190. /**
  191. * Set the APP_NAME value in a given file
  192. *
  193. * @param string $dir The application's root directory.
  194. * @param \Composer\IO\IOInterface $io IO interface to write to console.
  195. * @param string $appName app name to set in the file
  196. * @param string $file A path to a file relative to the application's root
  197. * @return void
  198. */
  199. public static function setAppNameInFile($dir, $io, $appName, $file)
  200. {
  201. $config = $dir . '/config/' . $file;
  202. $content = file_get_contents($config);
  203. $content = str_replace('__APP_NAME__', $appName, $content, $count);
  204. if ($count == 0) {
  205. $io->write('No __APP_NAME__ placeholder to replace.');
  206. return;
  207. }
  208. $result = file_put_contents($config, $content);
  209. if ($result) {
  210. $io->write('Updated __APP_NAME__ value in config/' . $file);
  211. return;
  212. }
  213. $io->write('Unable to update __APP_NAME__ value.');
  214. }
  215. }