Server::validateName()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
1
<?php
2
3
namespace Lagdo\DbAdmin\Driver\Sqlite\Db;
4
5
use Lagdo\DbAdmin\Driver\Db\Server as AbstractServer;
6
use Lagdo\DbAdmin\Driver\Db\StatementInterface;
7
8
use DirectoryIterator;
9
use Exception;
10
11
use function is_a;
12
use function count;
13
use function rtrim;
14
use function intval;
15
use function preg_match;
16
use function file_exists;
17
use function str_replace;
18
use function unlink;
19
use function explode;
20
use function rename;
21
22
class Server extends AbstractServer
23
{
24
    use ConfigTrait;
25
26
    /**
27
     * The database file extensions
28
     *
29
     * @var string
30
     */
31
    protected $extensions = "db|sdb|sqlite";
32
33
    /**
34
     * @var array
35
     */
36
    protected $variableNames = ["auto_vacuum", "cache_size", "count_changes", "default_cache_size",
37
        "empty_result_callbacks", "encoding", "foreign_keys", "full_column_names", "fullfsync",
38
        "journal_mode", "journal_size_limit", "legacy_file_format", "locking_mode", "page_size",
39
        "max_page_count", "read_uncommitted", "recursive_triggers", "reverse_unordered_selects",
40
        "secure_delete", "short_column_names", "synchronous", "temp_store", "temp_store_directory",
41
        "schema_version", "integrity_check", "quick_check"];
42
43
    /**
44
     * @inheritDoc
45
     */
46
    public function databases(bool $flush)
47
    {
48
        $databases = [];
49
        $directory = $this->directory($this->driver->options());
50
        $iterator = new DirectoryIterator($directory);
51
        // Iterate on dir content
52
        foreach($iterator as $file)
53
        {
54
            // Skip everything except Sqlite files
55
            if(!$file->isFile() || !$this->validateName($filename = $file->getFilename()))
56
            {
57
                continue;
58
            }
59
            $databases[] = $filename;
60
        }
61
        return $databases;
62
    }
63
64
    /**
65
     * @inheritDoc
66
     */
67
    public function databaseSize(string $database)
68
    {
69
        $connection = $this->driver->connect($database); // New connection
70
        if (!$connection) {
0 ignored issues
show
introduced by
$connection is of type Lagdo\DbAdmin\Driver\Db\ConnectionInterface, thus it always evaluated to true.
Loading history...
71
            return 0;
72
        }
73
        $pageSize = 0;
74
        $statement = $connection->query('pragma page_size');
75
        if (is_a($statement, StatementInterface::class) && ($row = $statement->fetchRow())) {
76
            $pageSize = intval($row[0]);
77
        }
78
        $pageCount = 0;
79
        $statement = $connection->query('pragma page_count');
80
        if (is_a($statement, StatementInterface::class) && ($row = $statement->fetchRow())) {
81
            $pageCount = intval($row[0]);
82
        }
83
        return $pageSize * $pageCount;
84
    }
85
86
    /**
87
     * @inheritDoc
88
     */
89
    public function databaseCollation(string $database, array $collations)
90
    {
91
        // there is no database list so $database == $this->driver->database()
92
        return $this->driver->result("PRAGMA encoding");
93
    }
94
95
    /**
96
     * @inheritDoc
97
     */
98
    public function collations()
99
    {
100
        $create = $this->util->input()->hasTable();
101
        return ($create) ? $this->driver->values("PRAGMA collation_list", 1) : [];
102
    }
103
104
    /**
105
     * Validate a name
106
     *
107
     * @param string $name
108
     *
109
     * @return bool
110
     */
111
    private function validateName(string $name)
112
    {
113
        // Avoid creating PHP files on unsecured servers
114
        return preg_match("~^[^\\0]*\\.({$this->extensions})\$~", $name) > 0;
115
    }
116
117
    /**
118
     * @inheritDoc
119
     */
120
    public function createDatabase(string $database, string $collation)
121
    {
122
        $options = $this->driver->options();
123
        if ($this->fileExists($database, $options)) {
124
            $this->driver->setError($this->trans->lang('File exists.'));
125
            return false;
126
        }
127
        $filename = $this->filename($database, $options);
128
        if (!$this->validateName($filename)) {
129
            $this->driver->setError($this->trans->lang('Please use one of the extensions %s.',
130
                str_replace("|", ", ", $this->extensions)));
131
            return false;
132
        }
133
        try {
134
            $connection = $this->driver->connect($database, '__create__'); // New connection
135
            $connection->query('PRAGMA encoding = "UTF-8"');
136
            $connection->query('CREATE TABLE dbadmin (i)'); // otherwise creates empty file
137
            $connection->query('DROP TABLE dbadmin');
138
        } catch (Exception $ex) {
139
            $this->driver->setError($ex->getMessage());
140
            return false;
141
        }
142
        return true;
143
    }
144
145
    /**
146
     * @inheritDoc
147
     */
148
    public function dropDatabase(string $database)
149
    {
150
        $filename = $this->filename($database, $this->driver->options());
151
        if (!@unlink($filename)) {
152
            $this->driver->setError($this->trans->lang('File exists.'));
153
            return false;
154
        }
155
        return true;
156
    }
157
158
    /**
159
     * @inheritDoc
160
     */
161
    public function renameDatabase(string $database, string $collation)
162
    {
163
        $options = $this->driver->options();
164
        $filename = $this->filename($database, $options);
165
        if (!$this->validateName($filename)) {
166
            $this->driver->setError($this->trans->lang('Please use one of the extensions %s.',
167
                str_replace("|", ", ", $this->extensions)));
168
            return false;
169
        }
170
        return @rename($this->filename($this->driver->database(), $options), $filename);
171
    }
172
173
    /**
174
     * @inheritDoc
175
     */
176
    public function variables()
177
    {
178
        $variables = [];
179
        foreach ($this->variableNames as $key) {
180
            $variables[$key] = $this->driver->result("PRAGMA $key");
181
        }
182
        return $variables;
183
    }
184
185
    /**
186
     * @inheritDoc
187
     */
188
    public function statusVariables()
189
    {
190
        $variables = [];
191
        if (!($options = $this->driver->values("PRAGMA compile_options"))) {
192
            return [];
193
        }
194
        foreach ($options as $option) {
195
            $values = explode("=", $option, 2);
196
            $variables[$values[0]] = count($values) > 1 ? $values[1] : "true";
197
        }
198
        return $variables;
199
    }
200
}
201