Blame view

src/Console/Installer.php 7.61 KB
6c4edfa3   Alexandre   First Commit LabI...
1
2
<?php
/**
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
3
4
 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
6c4edfa3   Alexandre   First Commit LabI...
5
6
7
8
9
 *
 * 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.
 *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
10
11
 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
 * @link      https://cakephp.org CakePHP(tm) Project
6c4edfa3   Alexandre   First Commit LabI...
12
 * @since     3.0.0
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
13
 * @license   https://opensource.org/licenses/mit-license.php MIT License
6c4edfa3   Alexandre   First Commit LabI...
14
15
16
 */
namespace App\Console;

07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
17
18
19
20
21
if (!defined('STDIN')) {
    define('STDIN', fopen('php://stdin', 'r'));
}

use Cake\Utility\Security;
6c4edfa3   Alexandre   First Commit LabI...
22
23
24
25
use Composer\Script\Event;
use Exception;

/**
66ad693c   Etienne Pallier   Evolution du fram...
26
 * Provides installation hooks for when this application is installed through
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
27
 * composer. Customize this class to suit your needs.
6c4edfa3   Alexandre   First Commit LabI...
28
29
30
31
32
 */
class Installer
{

    /**
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
33
34
35
36
37
38
39
40
41
42
     * 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',
66ad693c   Etienne Pallier   Evolution du fram...
43
        'tmp/tests',
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
44
45
46
    ];

    /**
6c4edfa3   Alexandre   First Commit LabI...
47
48
     * Does some routine installation tasks so people don't have to.
     *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
49
     * @param \Composer\Script\Event $event The composer event object.
6c4edfa3   Alexandre   First Commit LabI...
50
51
52
53
54
55
     * @throws \Exception Exception raised by validator.
     * @return void
     */
    public static function postInstall(Event $event)
    {
        $io = $event->getIO();
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
56

6c4edfa3   Alexandre   First Commit LabI...
57
        $rootDir = dirname(dirname(__DIR__));
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
58

66ad693c   Etienne Pallier   Evolution du fram...
59
        static::createAppLocalConfig($rootDir, $io);
6c4edfa3   Alexandre   First Commit LabI...
60
        static::createWritableDirectories($rootDir, $io);
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
61

6c4edfa3   Alexandre   First Commit LabI...
62
63
64
        // ask if the permissions should be changed
        if ($io->isInteractive()) {
            $validator = function ($arg) {
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
65
                if (in_array($arg, ['Y', 'y', 'N', 'n'])) {
6c4edfa3   Alexandre   First Commit LabI...
66
67
68
69
                    return $arg;
                }
                throw new Exception('This is not a valid answer. Please choose Y or n.');
            };
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
70
71
72
73
74
75
76
77
            $setFolderPermissions = $io->askAndValidate(
                '<info>Set Folder Permissions ? (Default to Y)</info> [<comment>Y,n</comment>]? ',
                $validator,
                10,
                'Y'
            );

            if (in_array($setFolderPermissions, ['Y', 'y'])) {
6c4edfa3   Alexandre   First Commit LabI...
78
79
80
81
82
                static::setFolderPermissions($rootDir, $io);
            }
        } else {
            static::setFolderPermissions($rootDir, $io);
        }
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
83

6c4edfa3   Alexandre   First Commit LabI...
84
        static::setSecuritySalt($rootDir, $io);
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
85
86
87
88

        $class = 'Cake\Codeception\Console\Installer';
        if (class_exists($class)) {
            $class::customizeCodeceptionBinary($event);
6c4edfa3   Alexandre   First Commit LabI...
89
90
91
92
        }
    }

    /**
66ad693c   Etienne Pallier   Evolution du fram...
93
     * Create config/app_local.php file if it does not exist.
6c4edfa3   Alexandre   First Commit LabI...
94
     *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
95
96
     * @param string $dir The application's root directory.
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
6c4edfa3   Alexandre   First Commit LabI...
97
98
     * @return void
     */
66ad693c   Etienne Pallier   Evolution du fram...
99
    public static function createAppLocalConfig($dir, $io)
6c4edfa3   Alexandre   First Commit LabI...
100
    {
66ad693c   Etienne Pallier   Evolution du fram...
101
102
103
104
105
        $appLocalConfig = $dir . '/config/app_local.php';
        $appLocalConfigTemplate = $dir . '/config/app_local.example.php';
        if (!file_exists($appLocalConfig)) {
            copy($appLocalConfigTemplate, $appLocalConfig);
            $io->write('Created `config/app_local.php` file');
6c4edfa3   Alexandre   First Commit LabI...
106
107
108
109
110
111
        }
    }

    /**
     * Create the `logs` and `tmp` directories.
     *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
112
113
     * @param string $dir The application's root directory.
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
6c4edfa3   Alexandre   First Commit LabI...
114
115
116
117
     * @return void
     */
    public static function createWritableDirectories($dir, $io)
    {
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
118
        foreach (static::WRITABLE_DIRS as $path) {
6c4edfa3   Alexandre   First Commit LabI...
119
            $path = $dir . '/' . $path;
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
120
            if (!file_exists($path)) {
6c4edfa3   Alexandre   First Commit LabI...
121
122
123
124
125
126
127
128
129
130
131
                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.
     *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
132
133
     * @param string $dir The application's root directory.
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
6c4edfa3   Alexandre   First Commit LabI...
134
135
136
137
138
     * @return void
     */
    public static function setFolderPermissions($dir, $io)
    {
        // Change the permissions on a path and output the results.
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
139
        $changePerms = function ($path) use ($io) {
6c4edfa3   Alexandre   First Commit LabI...
140
            $currentPerms = fileperms($path) & 0777;
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
141
142
            $worldWritable = $currentPerms | 0007;
            if ($worldWritable == $currentPerms) {
6c4edfa3   Alexandre   First Commit LabI...
143
144
                return;
            }
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
145
146

            $res = chmod($path, $worldWritable);
6c4edfa3   Alexandre   First Commit LabI...
147
148
149
150
151
152
            if ($res) {
                $io->write('Permissions set on ' . $path);
            } else {
                $io->write('Failed to set permissions on ' . $path);
            }
        };
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
153
154
155

        $walker = function ($dir) use (&$walker, $changePerms) {
            $files = array_diff(scandir($dir), ['.', '..']);
6c4edfa3   Alexandre   First Commit LabI...
156
157
            foreach ($files as $file) {
                $path = $dir . '/' . $file;
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
158
159

                if (!is_dir($path)) {
6c4edfa3   Alexandre   First Commit LabI...
160
161
                    continue;
                }
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
162
163
164

                $changePerms($path);
                $walker($path);
6c4edfa3   Alexandre   First Commit LabI...
165
166
            }
        };
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
167
168
169
170

        $walker($dir . '/tmp');
        $changePerms($dir . '/tmp');
        $changePerms($dir . '/logs');
6c4edfa3   Alexandre   First Commit LabI...
171
172
173
174
175
    }

    /**
     * Set the security.salt value in the application's config file.
     *
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
176
177
     * @param string $dir The application's root directory.
     * @param \Composer\IO\IOInterface $io IO interface to write to console.
6c4edfa3   Alexandre   First Commit LabI...
178
179
180
181
     * @return void
     */
    public static function setSecuritySalt($dir, $io)
    {
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
182
        $newKey = hash('sha256', Security::randomBytes(64));
66ad693c   Etienne Pallier   Evolution du fram...
183
        static::setSecuritySaltInFile($dir, $io, $newKey, 'app_local.php');
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
184
185
186
187
188
189
190
191
192
193
194
195
196
197
    }

    /**
     * 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;
6c4edfa3   Alexandre   First Commit LabI...
198
        $content = file_get_contents($config);
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
199

6c4edfa3   Alexandre   First Commit LabI...
200
        $content = str_replace('__SALT__', $newKey, $content, $count);
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
201

6c4edfa3   Alexandre   First Commit LabI...
202
203
        if ($count == 0) {
            $io->write('No Security.salt placeholder to replace.');
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
204

6c4edfa3   Alexandre   First Commit LabI...
205
206
            return;
        }
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
207

6c4edfa3   Alexandre   First Commit LabI...
208
209
        $result = file_put_contents($config, $content);
        if ($result) {
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
210
211
            $io->write('Updated Security.salt value in config/' . $file);

6c4edfa3   Alexandre   First Commit LabI...
212
213
214
215
            return;
        }
        $io->write('Unable to update Security.salt value.');
    }
07e4c3fb   Etienne Pallier   v4.108.0-3.7.9 - ...
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

    /**
     * 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.');
    }
6c4edfa3   Alexandre   First Commit LabI...
246
}