Permalink
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
match/app/src/Console/Installer.php
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

246 lines (215 sloc)
7.71 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org) | |
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) | |
* | |
* Licensed under The MIT License | |
* For full copyright and license information, please see the LICENSE.txt | |
* Redistributions of files must retain the above copyright notice. | |
* | |
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) | |
* @link https://cakephp.org CakePHP(tm) Project | |
* @since 3.0.0 | |
* @license https://opensource.org/licenses/mit-license.php MIT License | |
*/ | |
namespace App\Console; | |
if (!defined('STDIN')) { | |
define('STDIN', fopen('php://stdin', 'r')); | |
} | |
use Cake\Utility\Security; | |
use Composer\Script\Event; | |
use Exception; | |
/** | |
* Provides installation hooks for when this application is installed via | |
* composer. Customize this class to suit your needs. | |
*/ | |
class Installer | |
{ | |
/** | |
* An array of directories to be made writable | |
*/ | |
const WRITABLE_DIRS = [ | |
'logs', | |
'tmp', | |
'tmp/cache', | |
'tmp/cache/models', | |
'tmp/cache/persistent', | |
'tmp/cache/views', | |
'tmp/sessions', | |
'tmp/tests' | |
]; | |
/** | |
* Does some routine installation tasks so people don't have to. | |
* | |
* @param \Composer\Script\Event $event The composer event object. | |
* @throws \Exception Exception raised by validator. | |
* @return void | |
*/ | |
public static function postInstall(Event $event) | |
{ | |
$io = $event->getIO(); | |
$rootDir = dirname(dirname(__DIR__)); | |
static::createAppConfig($rootDir, $io); | |
static::createWritableDirectories($rootDir, $io); | |
// ask if the permissions should be changed | |
if ($io->isInteractive()) { | |
$validator = function ($arg) { | |
if (in_array($arg, ['Y', 'y', 'N', 'n'])) { | |
return $arg; | |
} | |
throw new Exception('This is not a valid answer. Please choose Y or n.'); | |
}; | |
$setFolderPermissions = $io->askAndValidate( | |
'<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ', | |
$validator, | |
10, | |
'Y' | |
); | |
if (in_array($setFolderPermissions, ['Y', 'y'])) { | |
static::setFolderPermissions($rootDir, $io); | |
} | |
} else { | |
static::setFolderPermissions($rootDir, $io); | |
} | |
static::setSecuritySalt($rootDir, $io); | |
if (class_exists('\Cake\Codeception\Console\Installer')) { | |
\Cake\Codeception\Console\Installer::customizeCodeceptionBinary($event); | |
} | |
} | |
/** | |
* Create the config/app.php file if it does not exist. | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @return void | |
*/ | |
public static function createAppConfig($dir, $io) | |
{ | |
$appConfig = $dir . '/config/app.php'; | |
$defaultConfig = $dir . '/config/app.default.php'; | |
if (!file_exists($appConfig)) { | |
copy($defaultConfig, $appConfig); | |
$io->write('Created `config/app.php` file'); | |
} | |
} | |
/** | |
* Create the `logs` and `tmp` directories. | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @return void | |
*/ | |
public static function createWritableDirectories($dir, $io) | |
{ | |
foreach (static::WRITABLE_DIRS as $path) { | |
$path = $dir . '/' . $path; | |
if (!file_exists($path)) { | |
mkdir($path); | |
$io->write('Created `' . $path . '` directory'); | |
} | |
} | |
} | |
/** | |
* Set globally writable permissions on the "tmp" and "logs" directory. | |
* | |
* This is not the most secure default, but it gets people up and running quickly. | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @return void | |
*/ | |
public static function setFolderPermissions($dir, $io) | |
{ | |
// Change the permissions on a path and output the results. | |
$changePerms = function ($path, $perms, $io) { | |
// Get permission bits from stat(2) result. | |
$currentPerms = fileperms($path) & 0777; | |
if (($currentPerms & $perms) == $perms) { | |
return; | |
} | |
$res = chmod($path, $currentPerms | $perms); | |
if ($res) { | |
$io->write('Permissions set on ' . $path); | |
} else { | |
$io->write('Failed to set permissions on ' . $path); | |
} | |
}; | |
$walker = function ($dir, $perms, $io) use (&$walker, $changePerms) { | |
$files = array_diff(scandir($dir), ['.', '..']); | |
foreach ($files as $file) { | |
$path = $dir . '/' . $file; | |
if (!is_dir($path)) { | |
continue; | |
} | |
$changePerms($path, $perms, $io); | |
$walker($path, $perms, $io); | |
} | |
}; | |
$worldWritable = bindec('0000000111'); | |
$walker($dir . '/tmp', $worldWritable, $io); | |
$changePerms($dir . '/tmp', $worldWritable, $io); | |
$changePerms($dir . '/logs', $worldWritable, $io); | |
} | |
/** | |
* Set the security.salt value in the application's config file. | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @return void | |
*/ | |
public static function setSecuritySalt($dir, $io) | |
{ | |
$newKey = hash('sha256', Security::randomBytes(64)); | |
static::setSecuritySaltInFile($dir, $io, $newKey, 'app.php'); | |
} | |
/** | |
* Set the security.salt value in a given file | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @param string $newKey key to set in the file | |
* @param string $file A path to a file relative to the application's root | |
* @return void | |
*/ | |
public static function setSecuritySaltInFile($dir, $io, $newKey, $file) | |
{ | |
$config = $dir . '/config/' . $file; | |
$content = file_get_contents($config); | |
$content = str_replace('__SALT__', $newKey, $content, $count); | |
if ($count == 0) { | |
$io->write('No Security.salt placeholder to replace.'); | |
return; | |
} | |
$result = file_put_contents($config, $content); | |
if ($result) { | |
$io->write('Updated Security.salt value in config/' . $file); | |
return; | |
} | |
$io->write('Unable to update Security.salt value.'); | |
} | |
/** | |
* Set the APP_NAME value in a given file | |
* | |
* @param string $dir The application's root directory. | |
* @param \Composer\IO\IOInterface $io IO interface to write to console. | |
* @param string $appName app name to set in the file | |
* @param string $file A path to a file relative to the application's root | |
* @return void | |
*/ | |
public static function setAppNameInFile($dir, $io, $appName, $file) | |
{ | |
$config = $dir . '/config/' . $file; | |
$content = file_get_contents($config); | |
$content = str_replace('__APP_NAME__', $appName, $content, $count); | |
if ($count == 0) { | |
$io->write('No __APP_NAME__ placeholder to replace.'); | |
return; | |
} | |
$result = file_put_contents($config, $content); | |
if ($result) { | |
$io->write('Updated __APP_NAME__ value in config/' . $file); | |
return; | |
} | |
$io->write('Unable to update __APP_NAME__ value.'); | |
} | |
} |