Passed
Push — master ( 04e382...2cf682 )
by Richard
09:30 queued 13s
created

prepStats()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 19
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 15
dl 0
loc 19
rs 9.7666
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
/**
13
 * Installer mainfile creation page
14
 *
15
 * See the enclosed file license.txt for licensing information.
16
 * If you did not receive this file, get it at https://www.gnu.org/licenses/gpl-2.0.html
17
 *
18
 * @copyright    (c) 2000-2021 XOOPS Project (www.xoops.org)
19
 * @license          GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html)
20
 * @package          installer
21
 * @since            2.3.0
22
 * @author           Haruki Setoyama  <[email protected]>
23
 * @author           Kazumi Ono <[email protected]>
24
 * @author           Skalpa Keo <[email protected]>
25
 * @author           Taiwen Jiang <[email protected]>
26
 * @author           DuGris (aka L. JEN) <[email protected]>
27
 **/
28
29
require_once __DIR__ . '/include/common.inc.php';
30
defined('XOOPS_INSTALL') || die('XOOPS Installation wizard die');
31
32
$pageHasForm = false;
33
$pageHasHelp = false;
34
35
$vars =& $_SESSION['settings'];
36
37
if (empty($vars['ROOT_PATH'])) {
38
    $wizard->redirectToPage('pathsettings');
39
    exit();
40
} elseif (empty($vars['DB_HOST'])) {
41
    $wizard->redirectToPage('dbsettings');
42
    exit();
43
}
44
45
$writeFiles = array(
46
    $vars['ROOT_PATH'] . '/mainfile.php',
47
    $vars['VAR_PATH'] . '/data/secure.php',
48
);
49
50
$writeCheck = checkFileWriteablity($writeFiles);
51
if (true === $writeCheck) {
52
    $rewrite = array(
53
        'GROUP_ADMIN' => 1,
54
        'GROUP_USERS' => 2,
55
        'GROUP_ANONYMOUS' => 3);
56
    $rewrite = array_merge($rewrite, $vars);
57
58
    $result = writeConfigurationFile($rewrite, $vars['VAR_PATH'] . '/data', 'secure.dist.php', 'secure.php');
59
    $GLOBALS['error'] = ($result !== true);
60
    if ($result === true) {
61
        $result = copyConfigDistFiles($vars);
62
        $GLOBALS['error'] = ($result !== true);
63
    }
64
    if ($result === true) {
65
        $result = writeConfigurationFile($rewrite, $vars['ROOT_PATH'], 'mainfile.dist.php', 'mainfile.php');
66
        $GLOBALS['error'] = ($result !== true);
67
    }
68
69
    $_SESSION['settings']['authorized'] = false;
70
71
    if ($result === true) {
72
        $_SESSION['UserLogin'] = true;
73
        $_SESSION['settings']['authorized'] = true;
74
        ob_start();
75
        ?>
76
77
        <div class="alert alert-success"><span class="fa fa-check text-success"></span> <?php echo SAVED_MAINFILE; ?></div>
78
        <div class='well'><?php echo SAVED_MAINFILE_MSG; ?>
79
        <ul class='diags'>
80
            <?php
81
            foreach ($vars as $k => $v) {
82
                if ($k === 'authorized') {
83
                    continue;
84
                }
85
                echo "<li><strong>XOOPS_{$k}</strong> " . IS_VALOR . " {$v}</li>";
86
            }
87
            ?>
88
        </ul>
89
        </div>
90
        <?php
91
        $content = ob_get_contents();
92
        ob_end_clean();
93
    } else {
94
        $GLOBALS['error'] = true;
95
        $pageHasForm = true; // will redirect to same page
96
        $content = '<div class="alert alert-danger"><span class="fa fa-ban text-danger"></span> ' . $result . '</div>';
97
    }
98
} else {
99
    $content = '';
100
    foreach ($writeCheck as $errorMsg) {
101
        $GLOBALS['error'] = true;
102
        $pageHasForm = true; // will redirect to same page
103
        $content .= '<div class="alert alert-danger"><span class="fa fa-ban text-danger"></span> ' . $errorMsg . '</div>' . "\n";
104
    }
105
}
106
include __DIR__ . '/include/install_tpl.php';
107
108
/**
109
 * Copy a configuration file from template, then rewrite with actual configuration values
110
 *
111
 * @param string[] $vars       config values
112
 * @param string   $path       directory path where files reside
113
 * @param string   $sourceName template file name
114
 * @param string   $fileName   configuration file name
115
 *
116
 * @return true|string true on success, error message on failure
117
 */
118
function writeConfigurationFile($vars, $path, $sourceName, $fileName)
119
{
120
    $path .= '/';
121
    if (!@copy($path . $sourceName, $path . $fileName)) {
122
        return sprintf(ERR_COPY_MAINFILE, $fileName);
123
    } else {
124
        clearstatcache();
125
        if (!$file = fopen($path . $fileName, 'r')) {
126
            return sprintf(ERR_READ_MAINFILE, $fileName);
127
        } else {
128
            $content = fread($file, filesize($path . $fileName));
129
            fclose($file);
130
131
            foreach ($vars as $key => $val) {
132
                if (is_int($val) && preg_match("/(define\()([\"'])(XOOPS_{$key})\\2,\s*(\d+)\s*\)/", $content)) {
133
                    $content = preg_replace("/(define\()([\"'])(XOOPS_{$key})\\2,\s*(\d+)\s*\)/", "define('XOOPS_{$key}', {$val})", $content);
134
                } elseif (preg_match("/(define\()([\"'])(XOOPS_{$key})\\2,\s*([\"'])(.*?)\\4\s*\)/", $content)) {
135
                    $val     = str_replace('$', '\$', addslashes($val));
136
                    $content = preg_replace("/(define\()([\"'])(XOOPS_{$key})\\2,\s*([\"'])(.*?)\\4\s*\)/", "define('XOOPS_{$key}', '{$val}')", $content);
137
                }
138
            }
139
            $file = fopen($path . $fileName, 'w');
140
            if (false === $file) {
141
                return sprintf(ERR_WRITE_MAINFILE, $fileName);
142
            }
143
            $writeResult = fwrite($file, $content);
144
            fclose($file);
145
            if (false === $writeResult) {
146
                return sprintf(ERR_WRITE_MAINFILE, $fileName);
147
            }
148
        }
149
    }
150
    return true;
151
}
152
153
154
/**
155
 * Get file stats
156
 *
157
 * @param string $filename file or directory name
158
 *
159
 * @return array|false false on error, or array of file stat information
160
 */
161
function getStats($filename)
162
{
163
    $stat = stat($filename);
164
    if (false === $stat) {
165
        return false;
166
    }
167
    return prepStats($stat);
168
}
169
170
/**
171
 * Get file stats on a created temp file
172
 *
173
 * @return array|false false on error, or array of file stat information
174
 */
175
function getTmpStats()
176
{
177
    $temp = tmpfile();
178
    if (false === $temp) {
179
        return false;
180
    }
181
    $stat = fstat($temp);
182
    fclose($temp);
183
    if (false === $stat) {
184
        return false;
185
    }
186
    return prepStats($stat);
187
}
188
189
/**
190
 * Get stat() info in a more usable form
191
 *
192
 * @param array $stat return from PHP stat()
193
 *
194
 * @return array selected information gleaned from $stat
195
 */
196
function prepStats($stat)
197
{
198
    $subSet = array();
199
    $mode = $stat['mode'];
200
    $subSet['mode'] = $mode;
201
    $subSet['uid'] = $stat['uid'];
202
    $subSet['gid'] = $stat['gid'];
203
204
    $subSet['user']['read']   = (bool) ($mode & 0400);
205
    $subSet['user']['write']  = (bool) ($mode & 0200);
206
    $subSet['user']['exec']   = (bool) ($mode & 0100);
207
    $subSet['group']['read']  = (bool) ($mode & 040);
208
    $subSet['group']['write'] = (bool) ($mode & 020);
209
    $subSet['group']['exec']  = (bool) ($mode & 010);
210
    $subSet['other']['read']  = (bool) ($mode & 04);
0 ignored issues
show
Bug introduced by
A parse error occurred: The alleged octal '4' is invalid
Loading history...
211
    $subSet['other']['write'] = (bool) ($mode & 02);
212
    $subSet['other']['exec']  = (bool) ($mode & 01);
213
214
    return $subSet;
215
}
216
217
/**
218
 * Attempt to check if a set of files can be written
219
 *
220
 * @param string[] $files fully qualified file names to check
221
 *
222
 * @return string[]|true true if no issues found, array
223
 */
224
function checkFileWriteablity($files)
225
{
226
    if (isset($_POST['op']) && $_POST['op'] === 'proceed') {
227
        return true; // user said skip this
228
    }
229
    $tmpStats = getTmpStats();
230
    if (false === $tmpStats) {
231
        return true; // tests are not applicable
232
    }
233
234
    $message = array();
235
236
    foreach ($files as $file) {
237
        $dirName = dirname($file);
238
        $fileName = basename($file);
239
        $dirStat = getStats($dirName);
240
        if (false !== $dirStat) {
241
            $uid = $tmpStats['uid'];
242
            $gid = $tmpStats['gid'];
243
            if (!(($uid === $dirStat['uid'] && $dirStat['user']['write'])
244
                || ($gid === $dirStat['gid'] && $dirStat['group']['write'])
245
                || (file_exists($file) && is_writable($file))
246
                || (false !== stripos(PHP_OS, 'WIN'))
247
            )
248
            ) {
249
                $uidStr = (string) $uid;
250
                $dUidStr = (string) $dirStat['uid'];
251
                $gidStr = (string) $gid;
252
                $dGidStr = (string) $dirStat['gid'];
253
                if (function_exists('posix_getpwuid')) {
254
                    $tempUsr = posix_getpwuid($uid);
255
                    $uidStr = isset($tempUsr['name']) ? $tempUsr['name'] : (string) $uid;
256
                    $tempUsr = posix_getpwuid($dirStat['uid']);
257
                    $dUidStr = isset($tempUsr['name']) ? $tempUsr['name'] : (string) $dirStat['uid'];
258
                }
259
                if (function_exists('posix_getgrgid')) {
260
                    $tempGrp = posix_getgrgid($gid);
261
                    $gidStr = isset($tempGrp['name']) ? $tempGrp['name'] : (string) $gid;
262
                    $tempGrp = posix_getgrgid($dirStat['gid']);
263
                    $dGidStr = isset($tempGrp['name']) ? $tempGrp['name'] : (string) $dirStat['gid'];
264
                }
265
                $message[] = sprintf(
266
                    CHMOD_CHGRP_ERROR,
267
                    $fileName,
268
                    $uidStr,
269
                    $gidStr,
270
                    basename($dirName),
271
                    $dUidStr,
272
                    $dGidStr
273
                );
274
            }
275
        }
276
    }
277
    return empty($message) ? true : $message;
278
}
279
280
/**
281
 * Install working versions of various *.dist.php files to xoops_data/configs/
282
 *
283
 * @param $vars array of system variables, we care about ROOT_PATH and VAR_PATH keys
284
 *
285
 * @return true|string true if all files were copied, otherwise error message
286
 */
287
function copyConfigDistFiles($vars)
288
{
289
    $copied = 0;
290
    $failed = 0;
291
    $logs = array();
292
293
    /* xoopsconfig.php */
294
    $source = $vars['VAR_PATH'] . '/configs/xoopsconfig.dist.php';
295
    $destination = $vars['VAR_PATH'] . '/configs/xoopsconfig.php';
296
    if (!file_exists($destination)) { // don't overwrite anything
297
        $result = copy($source, $destination);
298
        $result ? ++$copied : ++$failed;
299
        if (false === $result) {
300
            $logs[] = sprintf(ERR_COPY_CONFIG_FILE,  'configs/' . basename($destination));
301
        }
302
    }
303
304
    /* captcha files */
305
    $captchaConfigFiles = array(
306
        'config.dist.php'            => 'config.php',
307
        'config.image.dist.php'      => 'config.image.php',
308
        'config.recaptcha2.dist.php' => 'config.recaptcha2.php',
309
        'config.text.dist.php'       => 'config.text.php',
310
    );
311
312
    foreach ($captchaConfigFiles as $source => $destination) {
313
        $src  = $vars['ROOT_PATH'] . '/class/captcha/' . $source;
314
        $dest = $vars['VAR_PATH'] . '/configs/captcha/' . $destination;
315
        if (!file_exists($dest) && file_exists($src)) {
316
            $result = copy($src, $dest);
317
            $result ? ++$copied : ++$failed;
318
            if (false === $result) {
319
                $logs[] = sprintf('captcha config file copy to %s failed', $destination);
320
                $logs[] = sprintf(ERR_COPY_CONFIG_FILE,  'captcha/' . $destination);
321
            }
322
        }
323
    }
324
325
    /* text sanitizer  files */
326
    $textsanitizerConfigFiles = array(
327
        'config.dist.php'                 => 'config.php',
328
        'censor/config.dist.php'          => 'config.censor.php',
329
        'flash/config.dist.php'           => 'config.flash.php',
330
        'image/config.dist.php'           => 'config.image.php',
331
        'mms/config.dist.php'             => 'config.mms.php',
332
        'rtsp/config.dist.php'            => 'config.rtsp.php',
333
        'syntaxhighlight/config.dist.php' => 'config.syntaxhighlight.php',
334
        'textfilter/config.dist.php'      => 'config.textfilter.php',
335
        'wiki/config.dist.php'            => 'config.wiki.php',
336
        'wmp/config.dist.php'             => 'config.wmp.php',
337
    );
338
    foreach ($textsanitizerConfigFiles as $source => $destination) {
339
        $src  = $vars['ROOT_PATH'] . '/class/textsanitizer/' . $source;
340
        $dest = $vars['VAR_PATH'] . '/configs/textsanitizer/' . $destination;
341
        if (!file_exists($dest) && file_exists($src)) {
342
            $result = copy($src, $dest);
343
            $result ? ++$copied : ++$failed;
344
            if (false === $result) {
345
                $logs[] = sprintf(ERR_COPY_CONFIG_FILE, 'textsanitizer/' . $destination);
346
            }
347
        }
348
    }
349
350
    return $failed === 0 ? true : implode('<br>', $logs);
351
}
352