Passed
Branch feature/6.x (3df42d)
by Schlaefer
08:49
created

Installer::setFolderPermissions()   B

Complexity

Conditions 8
Paths 3

Size

Total Lines 55
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

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

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)
55
    {
56
        $io = $event->getIO();
57
58
        $rootDir = dirname(dirname(__DIR__));
59
60
        static::createAppLocalConfig($rootDir, $io);
61
        static::createWritableDirectories($rootDir, $io);
62
63
        static::setFolderPermissions($rootDir, $io);
64
        static::setSecuritySalt($rootDir, $io);
65
66
        $class = 'Cake\Codeception\Console\Installer';
67
        if (class_exists($class)) {
68
            $class::customizeCodeceptionBinary($event);
69
        }
70
    }
71
72
    /**
73
     * Create config/app_local.php file if it does not exist.
74
     *
75
     * @param string $dir The application's root directory.
76
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
77
     * @return void
78
     */
79
    public static function createAppLocalConfig($dir, $io)
80
    {
81
        $appLocalConfig = $dir . '/config/app_local.php';
82
        $appLocalConfigTemplate = $dir . '/config/app_local.example.php';
83
        if (!file_exists($appLocalConfig)) {
84
            copy($appLocalConfigTemplate, $appLocalConfig);
85
            $io->write('Created `config/app_local.php` file');
86
        }
87
    }
88
89
    /**
90
     * Create the `logs` and `tmp` directories.
91
     *
92
     * @param string $dir The application's root directory.
93
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
94
     * @return void
95
     */
96
    public static function createWritableDirectories($dir, $io)
97
    {
98
        foreach (static::WRITABLE_DIRS as $path) {
99
            $path = $dir . '/' . $path;
100
            if (!file_exists($path)) {
101
                mkdir($path);
102
                $io->write('Created `' . $path . '` directory');
103
            }
104
        }
105
    }
106
107
    /**
108
     * Set globally writable permissions on the "tmp" and "logs" directory.
109
     *
110
     * This is not the most secure default, but it gets people up and running quickly.
111
     *
112
     * @param string $dir The application's root directory.
113
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
114
     * @return void
115
     */
116
    public static function setFolderPermissions($dir, $io)
117
    {
118
        // ask if the permissions should be changed
119
        if ($io->isInteractive()) {
120
            $validator = function ($arg) {
121
                if (in_array($arg, ['Y', 'y', 'N', 'n'])) {
122
                    return $arg;
123
                }
124
                throw new Exception('This is not a valid answer. Please choose Y or n.');
125
            };
126
            $setFolderPermissions = $io->askAndValidate(
127
                '<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ',
128
                $validator,
129
                10,
130
                'Y'
131
            );
132
133
            if (in_array($setFolderPermissions, ['n', 'N'])) {
134
                return;
135
            }
136
        }
137
138
        // Change the permissions on a path and output the results.
139
        $changePerms = function ($path) use ($io) {
140
            $currentPerms = fileperms($path) & 0777;
141
            $worldWritable = $currentPerms | 0007;
142
            if ($worldWritable == $currentPerms) {
143
                return;
144
            }
145
146
            $res = chmod($path, $worldWritable);
147
            if ($res) {
148
                $io->write('Permissions set on ' . $path);
149
            } else {
150
                $io->write('Failed to set permissions on ' . $path);
151
            }
152
        };
153
154
        $walker = function ($dir) use (&$walker, $changePerms) {
155
            $files = array_diff(scandir($dir), ['.', '..']);
0 ignored issues
show
Bug introduced by
It seems like scandir($dir) can also be of type false; however, parameter $array1 of array_diff() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

155
            $files = array_diff(/** @scrutinizer ignore-type */ scandir($dir), ['.', '..']);
Loading history...
156
            foreach ($files as $file) {
157
                $path = $dir . '/' . $file;
158
159
                if (!is_dir($path)) {
160
                    continue;
161
                }
162
163
                $changePerms($path);
164
                $walker($path);
165
            }
166
        };
167
168
        $walker($dir . '/tmp');
169
        $changePerms($dir . '/tmp');
170
        $changePerms($dir . '/logs');
171
    }
172
173
    /**
174
     * Set the security.salt value in the application's config file.
175
     *
176
     * @param string $dir The application's root directory.
177
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
178
     * @return void
179
     */
180
    public static function setSecuritySalt($dir, $io)
181
    {
182
        $newKey = hash('sha256', Security::randomBytes(64));
183
        static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php');
184
    }
185
186
    /**
187
     * Set the security.salt value in a given file
188
     *
189
     * @param string $dir The application's root directory.
190
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
191
     * @param string $newKey key to set in the file
192
     * @param string $file A path to a file relative to the application's root
193
     * @return void
194
     */
195
    public static function setSecuritySaltInFile($dir, $io, $newKey, $file)
196
    {
197
        $config = $dir . '/config/' . $file;
198
        $content = file_get_contents($config);
199
200
        $content = str_replace('__SALT__', $newKey, $content, $count);
201
202
        if ($count == 0) {
203
            $io->write('No Security.salt placeholder to replace.');
204
205
            return;
206
        }
207
208
        $result = file_put_contents($config, $content);
209
        if ($result) {
210
            $io->write('Updated Security.salt value in config/' . $file);
211
212
            return;
213
        }
214
        $io->write('Unable to update Security.salt value.');
215
    }
216
217
    /**
218
     * Set the APP_NAME value in a given file
219
     *
220
     * @param string $dir The application's root directory.
221
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
222
     * @param string $appName app name to set in the file
223
     * @param string $file A path to a file relative to the application's root
224
     * @return void
225
     */
226
    public static function setAppNameInFile($dir, $io, $appName, $file)
227
    {
228
        $config = $dir . '/config/' . $file;
229
        $content = file_get_contents($config);
230
        $content = str_replace('__APP_NAME__', $appName, $content, $count);
231
232
        if ($count == 0) {
233
            $io->write('No __APP_NAME__ placeholder to replace.');
234
235
            return;
236
        }
237
238
        $result = file_put_contents($config, $content);
239
        if ($result) {
240
            $io->write('Updated __APP_NAME__ value in config/' . $file);
241
242
            return;
243
        }
244
        $io->write('Unable to update __APP_NAME__ value.');
245
    }
246
}
247