Passed
Push — master ( 6f8ce3...5bb18a )
by Nils
02:17
created

WordPressCollector   A

Complexity

Total Complexity 22

Size/Duplication

Total Lines 113
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 59
dl 0
loc 113
rs 10
c 2
b 0
f 0
wmc 22

5 Methods

Rating   Name   Duplication   Size   Complexity  
A setInventory() 0 3 1
A parsePluginHeader() 0 21 4
A extractVersion() 0 14 3
B extractPlugins() 0 34 8
A collect() 0 27 6
1
<?php
2
3
namespace Startwind\Inventorio\Collector\Website\WordPress;
4
5
use Startwind\Inventorio\Collector\Application\WebServer\Apache\ApacheServerNameCollector;
6
use Startwind\Inventorio\Collector\BasicCollector;
7
use Startwind\Inventorio\Collector\InventoryAwareCollector;
8
9
class WordPressCollector extends BasicCollector implements InventoryAwareCollector
10
{
11
    protected string $identifier = "WordPress";
12
13
    private array $inventory;
14
15
    public function setInventory(array $inventory): void
16
    {
17
        $this->inventory = $inventory;
18
    }
19
20
    public function collect(): array
21
    {
22
        if (!array_key_exists(ApacheServerNameCollector::COLLECTION_IDENTIFIER, $this->inventory)
23
            || !is_array($this->inventory[ApacheServerNameCollector::COLLECTION_IDENTIFIER])
24
        ) return [];
25
26
        $configs = $this->inventory[ApacheServerNameCollector::COLLECTION_IDENTIFIER];
27
28
        $wordPressInstallations = [];
29
30
        foreach ($configs as $config) {
31
            $domain = $config[ApacheServerNameCollector::FIELD_SERVER_NAME];
32
            $documentRoot = $config[ApacheServerNameCollector::FIELD_DOCUMENT_ROOT];
33
34
            if (file_exists($documentRoot . '/wp-config.php')) {
35
36
                if (!str_ends_with($documentRoot, '/')) $documentRoot = $documentRoot . '/';
37
38
                $wordPressInstallations[$domain] = [
39
                    'domain' => $domain,
40
                    'version' => $this->extractVersion($documentRoot),
41
                    'plugins' => $this->extractPlugins($documentRoot)
42
                ];
43
            }
44
        }
45
46
        return $wordPressInstallations;
47
    }
48
49
    private function extractPlugins(string $documentRoot): array
50
    {
51
        $pluginDir = $documentRoot . '/wp-content/plugins';
52
        $plugins = array_diff(scandir($pluginDir), ['.', '..']);
53
54
        $pluginArray = [];
55
56
        foreach ($plugins as $pluginFolder) {
57
            $path = $pluginDir . '/' . $pluginFolder;
58
59
            if (is_dir($path)) {
60
                $phpFiles = glob("$path/*.php");
61
                foreach ($phpFiles as $phpFile) {
62
                    $info = $this->parsePluginHeader($phpFile);
63
                    if (!empty($info['Name'])) {
64
                        $pluginArray[] = [
65
                            'name' => $info['Name'],
66
                            'version' => $info['Version']
67
                        ];
68
                        break;
69
                    }
70
                }
71
            } elseif (is_file($path) && substr($pluginFolder, -4) === '.php') {
72
                $info = $this->parsePluginHeader($path);
73
                if (!empty($info['Name'])) {
74
                    $pluginArray[] = [
75
                        'name' => $info['Name'],
76
                        'version' => $info['Version']
77
                    ];
78
                }
79
            }
80
        }
81
82
        return $pluginArray;
83
    }
84
85
    private function parsePluginHeader($file): array
86
    {
87
        $headers = [
88
            'Name' => 'Plugin Name',
89
            'Version' => 'Version',
90
        ];
91
92
        $fp = fopen($file, 'r');
93
        if (!$fp) return [];
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
94
95
        $data = fread($fp, 8192);
96
        fclose($fp);
97
98
        $info = [];
99
        foreach ($headers as $key => $header) {
100
            if (preg_match('/' . preg_quote($header, '/') . ':\s*(.+)/i', $data, $matches)) {
101
                $info[$key] = trim($matches[1]);
102
            }
103
        }
104
105
        return $info;
106
    }
107
108
    private function extractVersion(string $documentRoot): string
109
    {
110
        $wpVersionFile = $documentRoot . 'wp-includes/version.php';
111
112
        $version = 'unknown';
113
114
        if (file_exists($wpVersionFile)) {
115
            $content = file_get_contents($wpVersionFile);
116
            if (preg_match("/\\\$wp_version\s*=\s*'([^']+)'/", $content, $matches)) {
117
                $version = $matches[1];
118
            }
119
        }
120
121
        return $version;
122
    }
123
}
124