Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
621 lars 1
<?php
2
 
3
namespace Doctrine\DBAL\Tools;
4
 
5
use Doctrine\DBAL\DriverManager;
6
use Doctrine\DBAL\Exception\MalformedDsnException;
7
use SensitiveParameter;
8
 
9
use function array_merge;
10
use function assert;
11
use function is_string;
12
use function parse_str;
13
use function parse_url;
14
use function preg_replace;
15
use function rawurldecode;
16
use function str_replace;
17
use function strpos;
18
use function substr;
19
 
20
/** @psalm-import-type Params from DriverManager */
21
final class DsnParser
22
{
23
    /** @var array<string, string> */
24
    private array $schemeMapping;
25
 
26
    /** @param array<string, string> $schemeMapping An array used to map DSN schemes to DBAL drivers */
27
    public function __construct(array $schemeMapping = [])
28
    {
29
        $this->schemeMapping = $schemeMapping;
30
    }
31
 
32
    /**
33
     * @psalm-return Params
34
     *
35
     * @throws MalformedDsnException
36
     */
37
    public function parse(
38
        #[SensitiveParameter]
39
        string $dsn
40
    ): array {
41
        // (pdo_)?sqlite3?:///... => (pdo_)?sqlite3?://localhost/... or else the URL will be invalid
42
        $url = preg_replace('#^((?:pdo_)?sqlite3?):///#', '$1://localhost/', $dsn);
43
        assert($url !== null);
44
 
45
        $url = parse_url($url);
46
 
47
        if ($url === false) {
48
            throw MalformedDsnException::new();
49
        }
50
 
51
        foreach ($url as $param => $value) {
52
            if (! is_string($value)) {
53
                continue;
54
            }
55
 
56
            $url[$param] = rawurldecode($value);
57
        }
58
 
59
        $params = [];
60
 
61
        if (isset($url['scheme'])) {
62
            $params['driver'] = $this->parseDatabaseUrlScheme($url['scheme']);
63
        }
64
 
65
        if (isset($url['host'])) {
66
            $params['host'] = $url['host'];
67
        }
68
 
69
        if (isset($url['port'])) {
70
            $params['port'] = $url['port'];
71
        }
72
 
73
        if (isset($url['user'])) {
74
            $params['user'] = $url['user'];
75
        }
76
 
77
        if (isset($url['pass'])) {
78
            $params['password'] = $url['pass'];
79
        }
80
 
81
        $params = $this->parseDatabaseUrlPath($url, $params);
82
        $params = $this->parseDatabaseUrlQuery($url, $params);
83
 
84
        return $params;
85
    }
86
 
87
    /**
88
     * Parses the given connection URL and resolves the given connection parameters.
89
     *
90
     * Assumes that the connection URL scheme is already parsed and resolved into the given connection parameters
91
     * via {@see parseDatabaseUrlScheme}.
92
     *
93
     * @see parseDatabaseUrlScheme
94
     *
95
     * @param mixed[] $url    The URL parts to evaluate.
96
     * @param mixed[] $params The connection parameters to resolve.
97
     *
98
     * @return mixed[] The resolved connection parameters.
99
     */
100
    private function parseDatabaseUrlPath(array $url, array $params): array
101
    {
102
        if (! isset($url['path'])) {
103
            return $params;
104
        }
105
 
106
        $url['path'] = $this->normalizeDatabaseUrlPath($url['path']);
107
 
108
        // If we do not have a known DBAL driver, we do not know any connection URL path semantics to evaluate
109
        // and therefore treat the path as a regular DBAL connection URL path.
110
        if (! isset($params['driver'])) {
111
            return $this->parseRegularDatabaseUrlPath($url, $params);
112
        }
113
 
114
        if (strpos($params['driver'], 'sqlite') !== false) {
115
            return $this->parseSqliteDatabaseUrlPath($url, $params);
116
        }
117
 
118
        return $this->parseRegularDatabaseUrlPath($url, $params);
119
    }
120
 
121
    /**
122
     * Normalizes the given connection URL path.
123
     *
124
     * @return string The normalized connection URL path
125
     */
126
    private function normalizeDatabaseUrlPath(string $urlPath): string
127
    {
128
        // Trim leading slash from URL path.
129
        return substr($urlPath, 1);
130
    }
131
 
132
    /**
133
     * Parses the query part of the given connection URL and resolves the given connection parameters.
134
     *
135
     * @param mixed[] $url    The connection URL parts to evaluate.
136
     * @param mixed[] $params The connection parameters to resolve.
137
     *
138
     * @return mixed[] The resolved connection parameters.
139
     */
140
    private function parseDatabaseUrlQuery(array $url, array $params): array
141
    {
142
        if (! isset($url['query'])) {
143
            return $params;
144
        }
145
 
146
        $query = [];
147
 
148
        parse_str($url['query'], $query); // simply ingest query as extra params, e.g. charset or sslmode
149
 
150
        return array_merge($params, $query); // parse_str wipes existing array elements
151
    }
152
 
153
    /**
154
     * Parses the given regular connection URL and resolves the given connection parameters.
155
     *
156
     * Assumes that the "path" URL part is already normalized via {@see normalizeDatabaseUrlPath}.
157
     *
158
     * @see normalizeDatabaseUrlPath
159
     *
160
     * @param mixed[] $url    The regular connection URL parts to evaluate.
161
     * @param mixed[] $params The connection parameters to resolve.
162
     *
163
     * @return mixed[] The resolved connection parameters.
164
     */
165
    private function parseRegularDatabaseUrlPath(array $url, array $params): array
166
    {
167
        $params['dbname'] = $url['path'];
168
 
169
        return $params;
170
    }
171
 
172
    /**
173
     * Parses the given SQLite connection URL and resolves the given connection parameters.
174
     *
175
     * Assumes that the "path" URL part is already normalized via {@see normalizeDatabaseUrlPath}.
176
     *
177
     * @see normalizeDatabaseUrlPath
178
     *
179
     * @param mixed[] $url    The SQLite connection URL parts to evaluate.
180
     * @param mixed[] $params The connection parameters to resolve.
181
     *
182
     * @return mixed[] The resolved connection parameters.
183
     */
184
    private function parseSqliteDatabaseUrlPath(array $url, array $params): array
185
    {
186
        if ($url['path'] === ':memory:') {
187
            $params['memory'] = true;
188
 
189
            return $params;
190
        }
191
 
192
        $params['path'] = $url['path']; // pdo_sqlite driver uses 'path' instead of 'dbname' key
193
 
194
        return $params;
195
    }
196
 
197
    /**
198
     * Parses the scheme part from given connection URL and resolves the given connection parameters.
199
     *
200
     * @return string The resolved driver.
201
     */
202
    private function parseDatabaseUrlScheme(string $scheme): string
203
    {
204
        // URL schemes must not contain underscores, but dashes are ok
205
        $driver = str_replace('-', '_', $scheme);
206
 
207
        // If the driver is an alias (e.g. "postgres"), map it to the actual name ("pdo-pgsql").
208
        // Otherwise, let checkParams decide later if the driver exists.
209
        return $this->schemeMapping[$driver] ?? $driver;
210
    }
211
}