https://github.com/nyholm/dsn
A powerful DSN parser.
https://github.com/nyholm/dsn
dsn
Last synced: 6 months ago
JSON representation
A powerful DSN parser.
- Host: GitHub
- URL: https://github.com/nyholm/dsn
- Owner: Nyholm
- License: mit
- Created: 2018-03-03T09:49:55.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2023-03-18T14:18:35.000Z (over 2 years ago)
- Last Synced: 2024-10-16T12:41:34.601Z (12 months ago)
- Topics: dsn
- Language: PHP
- Homepage:
- Size: 59.6 KB
- Stars: 103
- Watchers: 5
- Forks: 11
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# DSN parser
[](https://github.com/Nyholm/dsn/releases)
[](https://scrutinizer-ci.com/g/Nyholm/dsn)
[](https://insight.symfony.com/projects/fe1a70b7-6ba9-424d-9217-53833e47b07f)
[](https://packagist.org/packages/nyholm/dsn)Parse DSN strings into value objects to make them easier to use, pass around and
manipulate.## Install
Via Composer
``` bash
composer require nyholm/dsn
```## Quick usage
```php
use Nyholm\Dsn\DsnParser;$dsn = DsnParser::parse('http://127.0.0.1/foo/bar?key=value');
echo get_class($dsn); // "Nyholm\Dsn\Configuration\Url"
echo $dsn->getHost(); // "127.0.0.1"
echo $dsn->getPath(); // "/foo/bar"
echo $dsn->getPort(); // null
```## The DSN string format
A DSN is a string used to configure many services. A common DSN may look like a
URL, other look like a file path.```text
memcached://127.0.0.1
mysql://user:password@127.0.0.1:3306/my_table
memcached:///var/local/run/memcached.socket?weight=25
```Both types can have parameters, user, password. The exact definition we are using
is found [at the bottom of the page](#definition).### DSN Functions
A DSN may contain zero or more functions. The DSN parser supports a function syntax
but not functionality itself. The function arguments must be separated with space
or comma. Here are some example functions.```
failover(dummy://a dummy://a)
failover(dummy://a,dummy://a)
failover:(dummy://a,dummy://a)
roundrobin(dummy://a failover(dummy://b dummy://a) dummy://b)
```## Parsing
There are two methods for parsing; `DsnParser::parse()` and `DsnParser::parseFunc()`.
The latter is for situations where DSN functions are supported.```php
use Nyholm\Dsn\DsnParser;$dsn = DsnParser::parse('scheme://127.0.0.1/foo/bar?key=value');
echo get_class($dsn); // "Nyholm\Dsn\Configuration\Url"
echo $dsn->getHost(); // "127.0.0.1"
echo $dsn->getPath(); // "/foo/bar"
echo $dsn->getPort(); // null
```If functions are supported (like in the Symfony Mailer component) we can use `DsnParser::parseFunc()`:
```php
use Nyholm\Dsn\DsnParser;$func = DsnParser::parseFunc('failover(sendgrid://KEY@default smtp://127.0.0.1)');
echo $func->getName(); // "failover"
echo get_class($func->first()); // "Nyholm\Dsn\Configuration\Url"
echo $func->first()->getHost(); // "default"
echo $func->first()->getUser(); // "KEY"
``````php
use Nyholm\Dsn\DsnParser;$func = DsnParser::parseFunc('foo(udp://localhost failover:(tcp://localhost:61616,tcp://remotehost:61616)?initialReconnectDelay=100)?start=now');
echo $func->getName(); // "foo"
echo $func->getParameters()['start']; // "now"$args = $func->getArguments();
echo get_class($args[0]); // "Nyholm\Dsn\Configuration\Url"
echo $args[0]->getScheme(); // "udp"
echo $args[0]->getHost(); // "localhost"echo get_class($args[1]); // "Nyholm\Dsn\Configuration\DsnFunction"
```When using `DsnParser::parseFunc()` on a string that does not contain any DSN functions,
the parser will automatically add a default "dsn" function. This is added to provide
a consistent return type of the method.The string `redis://127.0.0.1` will automatically be converted to `dsn(redis://127.0.0.1)`
when using `DsnParser::parseFunc()`.```php
use Nyholm\Dsn\DsnParser;$func = DsnParser::parseFunc('smtp://127.0.0.1');
echo $func->getName(); // "dsn"
echo get_class($func->first()); // "Nyholm\Dsn\Configuration\Url"
echo $func->first()->getHost(); // "127.0.0.1"$func = DsnParser::parseFunc('dsn(smtp://127.0.0.1)');
echo $func->getName(); // "dsn"
echo get_class($func->first()); // "Nyholm\Dsn\Configuration\Url"
echo $func->first()->getHost(); // "127.0.0.1"
```### Parsing invalid DSN
If you try to parse an invalid DSN string a `InvalidDsnException` will be thrown.
```php
use Nyholm\Dsn\DsnParser;
use Nyholm\Dsn\Exception\InvalidDsnException;try {
DsnParser::parse('foobar');
} catch (InvalidDsnException $e) {
echo $e->getMessage();
}
```## Consuming
The result of parsing a DSN string is a `DsnFunction` or `Dsn`. A `DsnFunction` has
a `name`, `argument` and may have `parameters`. An argument is either a `DsnFunction`
or a `Dsn`.A `Dsn` could be a `Path` or `Url`. All 3 objects has methods for getting parts of
the DSN string.- `getScheme()`
- `getUser()`
- `getPassword()`
- `getHost()`
- `getPort()`
- `getPath()`
- `getParameters()`You may also replace parts of the DSN with the `with*` methods. A DSN is immutable
and you will get a new object back.```php
use Nyholm\Dsn\DsnParser;$dsn = DsnParser::parse('scheme://127.0.0.1/foo/bar?key=value');
echo $dsn->getHost(); // "127.0.0.1"
$new = $dsn->withHost('nyholm.tech');echo $dsn->getHost(); // "127.0.0.1"
echo $new->getHost(); // "nyholm.tech"
```## Not supported
### Smart merging of options
The current DSN is valid, but it is up to the consumer to make sure both host1 and
host2 has `global_option`.```
redis://(host1:1234,host2:1234?node2_option=a)?global_option=b
```### Special DSN
The following DSN syntax are not supported.
```
// Rust
pgsql://user:pass@tcp(localhost:5555)/dbname// Java
jdbc:informix-sqli://[:]/:informixserver=```
We do not support DSN strings for ODBC connections like:
```
Driver={ODBC Driver 13 for SQL Server};server=localhost;database=WideWorldImporters;trusted_connection=Yes;
```However, we do support "only parameters":
```
ocdb://?Driver=ODBC+Driver+13+for+SQL+Server&server=localhost&database=WideWorldImporters&trusted_connection=Yes
```## Definition
There is no official DSN RFC. We have defined a DSN configuration string as
using the following definition. The "URL looking" parts of a DSN is based from
[RFC 3986](https://tools.ietf.org/html/rfc3986).```
configuration:
{ function | dsn }function:
function_name[:](configuration[,configuration])[?query]function_name:
REGEX: [a-zA-Z0-9\+-]+dsn:
{ scheme:[//]authority[path][?query] | scheme:[//][userinfo]path[?query] | host:port[path][?query] }scheme:
REGEX: [a-zA-Z0-9\+-\.]+authority:
[userinfo@]host[:port]userinfo:
{ user[:password] | :password }path:
"Normal" URL path according to RFC3986 section 3.3.
REGEX: (/? | (/[a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=:@]+)+)query:
"Normal" URL query according to RFC3986 section 3.4.
REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=:@]+user:
This value can be URL encoded.
REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+password:
This value can be URL encoded.
REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+host:
REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+post:
REGEX: [0-9]+```
Example of formats that are supported:
- scheme://127.0.0.1/foo/bar?key=value
- scheme://user:pass@127.0.0.1/foo/bar?key=value
- scheme:///var/local/run/memcached.socket?weight=25
- scheme://user:pass@/var/local/run/memcached.socket?weight=25
- scheme:?host[localhost]&host[localhost:12345]=3
- scheme://a
- scheme://
- server:80