Installer::setFolderPermissions()   B
last analyzed

Complexity

Conditions 8
Paths 3

Size

Total Lines 55
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 33
nc 3
nop 2
dl 0
loc 55
rs 8.1475
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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