File: UnexpectedFiles.php

package info (click to toggle)
matomo 5.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 95,068 kB
  • sloc: php: 289,425; xml: 127,249; javascript: 112,130; python: 202; sh: 178; makefile: 20; sql: 10
file content (138 lines) | stat: -rw-r--r-- 4,660 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
<?php

/**
 * Matomo - free/libre analytics platform
 *
 * @link    https://matomo.org
 * @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 */

namespace Piwik\Plugins\Diagnostics\Commands;

use Piwik\Development;
use Piwik\FileIntegrity;
use Piwik\Filesystem;
use Piwik\Plugin\ConsoleCommand;

/**
 * Diagnostic command that finds all unexpected files in the Matomo installation directory and provides an option to
 * delete them
 *
 * ./console diagnostics:unexpected-files                           # show a list of unexpected files
 * ./console diagnostics:unexpected-files --delete                  # delete the unexpected files with confirmation
 * ./console diagnostics:unexpected-files --delete --no-interaction # delete the unexpected files without confirmation
 *
 */
class UnexpectedFiles extends ConsoleCommand
{
    protected function configure()
    {
        $this->setName('diagnostics:unexpected-files')
            ->setDescription('Show a list of unexpected files found in the Matomo installation directory and optionally delete them.')
            ->addNoValueOption('delete', null, 'Delete all the unexpected files');
    }

    /**
     * Execute the command
     *
     */
    protected function doExecute(): int
    {
        $input = $this->getInput();
        $output = $this->getOutput();

        // Prevent running in development mode
        if (Development::isEnabled()) {
            $output->writeln("Aborting - this command cannot be used in development mode as it requires a release manifest file");
            return 1;
        }

        // Prevent running if there is no release manifest file
        $manifest = PIWIK_INCLUDE_PATH . '/config/manifest.inc.php';
        if (!file_exists($manifest)) {
            $output->writeln("Release manifest file '" . $manifest . "' not found.");
            $output->writeln("Aborting - this command can only be used when a release manifest file is present.");
            return 1;
        }


        $delete = $input->getOption('delete');
        if ($delete) {
            $output->writeln("<info>Preparing to delete all unexpected files from the Matomo installation directory</info>");

            if (!$this->askForDeleteConfirmation()) {
                $output->writeln("Aborted - no files were deleted");
                return 1;
            }

            return $this->runUnexpectedFiles(true);
        }

        return $this->runUnexpectedFiles(false);
    }

    /**
     * Handle unexpected files command options
     *
     *
     */
    private function runUnexpectedFiles(bool $delete = false): int
    {
        $output = $this->getOutput();

        // A list of files that should never be deleted under any circumstances, this acts as a backup safety check
        // for the FileIntegrity class which should already be excluding these files.
        $excludedFiles = [
            '/^config\/config.ini.php$/',        // main config file
            '/^config\/common.config.ini.php$/', // multi-tenant config file
            '/\.htaccess$/',                     // apache directory access rules
            '/^config\/config.php$/',            // DI customisation
            '/^misc\/.*$/',                       // everything in the misc/ directory (geo databases, multi-tenant, etc)
        ];

        $files = FileIntegrity::getUnexpectedFilesList();
        $fails = 0;

        foreach ($files as $f) {
            foreach ($excludedFiles as $ef) {
                if (preg_match($ef, $f)) {
                    continue 2;
                }
            }

            $fileName = realpath($f);

            if ($delete) {
                if (Filesystem::deleteFileIfExists($fileName)) {
                    $output->writeln("Deleted unexpected file '" . $fileName);
                } else {
                    $output->writeln("Failed to delete unexpected file '" . $fileName);
                    $fails++;
                }
            } else {
                $output->writeln($fileName);
            }
        }
        if ($delete && $fails) {
            $output->writeln("Failed to delete " . $fails . " unexpected files");
            return 1;
        }
        return 0;
    }

    /**
     * Interact with the user to confirm the deletion
     *
     */
    private function askForDeleteConfirmation(): bool
    {
        if (!$this->getInput()->isInteractive()) {
            return true;
        }

        return $this->askForConfirmation(
            '<comment>You are about to delete files. This action cannot be undone, are you sure you want to continue? (Y/N)</comment>',
            false
        );
    }
}