diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml new file mode 100644 index 0000000..fe461b4 --- /dev/null +++ b/.github/workflows/dependency-review.yml @@ -0,0 +1,20 @@ +# Dependency Review Action +# +# This Action will scan dependency manifest files that change as part of a Pull Request, surfacing known-vulnerable versions of the packages declared or updated in the PR. Once installed, if the workflow run is marked as required, PRs introducing known-vulnerable packages will be blocked from merging. +# +# Source repository: https://github.com/actions/dependency-review-action +# Public documentation: https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement +name: 'Dependency Review' +on: [pull_request] + +permissions: + contents: read + +jobs: + dependency-review: + runs-on: ubuntu-latest + steps: + - name: 'Checkout Repository' + uses: actions/checkout@v3 + - name: 'Dependency Review' + uses: actions/dependency-review-action@v2 diff --git a/README.md b/README.md index 8f0af12..09dd861 100644 --- a/README.md +++ b/README.md @@ -232,22 +232,22 @@ userinfo: path: "Normal" URL path according to RFC3986 section 3.3. - REGEX: (/? | (/[a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=:@]+)+) + REGEX: (/? | (/[a-zA-Z0-9-\._~%!\$&'\(\)\*\+,;=:@]+)+) query: "Normal" URL query according to RFC3986 section 3.4. - REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=:@]+ + REGEX: [a-zA-Z0-9-\._~%!\$&'\(\)\*\+,;=:@]+ user: This value can be URL encoded. - REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+ + REGEX: [a-zA-Z0-9-\._~%!\$&'\(\)\*\+,;=]+ password: This value can be URL encoded. - REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+ + REGEX: [a-zA-Z0-9-\._~%!\$&'\(\)\*\+,;=]+ host: - REGEX: [a-zA-Z0-9-\._~%!\$&'\(\}\*\+,;=]+ + REGEX: [a-zA-Z0-9-\._~%!\$&'\(\)\*\+,;=]+ post: REGEX: [0-9]+ diff --git a/composer.json b/composer.json index f70f9ac..7384a99 100644 --- a/composer.json +++ b/composer.json @@ -1,32 +1,27 @@ { "name": "nyholm/dsn", - "type": "library", "description": "Parse your DSN strings in a powerful and flexible way", + "license": "MIT", + "type": "library", "keywords": [ "dsn", "parser", "dsn parser", "database" ], - "homepage": "http://tnyholm.se", - "license": "MIT", "authors": [ { "name": "Tobias Nyholm", "email": "tobias.nyholm@gmail.com" } ], + "homepage": "http://tnyholm.se", "require": { "php": ">=7.1" }, "require-dev": { "symfony/phpunit-bridge": "^5.1" }, - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, "autoload": { "psr-4": { "Nyholm\\Dsn\\": "src/" @@ -36,5 +31,10 @@ "psr-4": { "Nyholm\\Dsn\\Test\\": "tests/" } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } } } diff --git a/src/DsnParser.php b/src/DsnParser.php index 433964f..2c7f051 100644 --- a/src/DsnParser.php +++ b/src/DsnParser.php @@ -22,7 +22,7 @@ class DsnParser private const FUNCTION_REGEX = '#^([a-zA-Z0-9\+-]+):?\((.*)\)(?:\?(.*))?$#'; private const ARGUMENTS_REGEX = '#([^\s,]+\([^)]+\)(?:\?[^\s,]*)?|[^\s,]+)#'; private const UNRESERVED = 'a-zA-Z0-9-\._~'; - private const SUB_DELIMS = '!\$&\'\(\}\*\+,;='; + private const SUB_DELIMS = '!\$&\'\(\)\*\+,;='; /** * Parse A DSN thay may contain functions. If no function is present in the @@ -52,7 +52,10 @@ public static function parseFunc(string $dsn): DsnFunction $arguments = $matches[1]; } - return new DsnFunction($functionName, array_map(\Closure::fromCallable([self::class, 'parseArguments']), $arguments), $parameters); + return new DsnFunction( + $functionName, + array_map(\Closure::fromCallable([self::class, 'parseArguments']), $arguments), + $parameters); } /** @@ -113,7 +116,9 @@ private static function parseArguments(string $dsn) private static function getDsn(string $dsn): Dsn { // Find the scheme if it exists and trim the double slash. - if (!preg_match('#^(?:(?['.self::UNRESERVED.self::SUB_DELIMS.'%]+:[0-9]+(?:[/?].*)?)|(?[a-zA-Z0-9\+-\.]+):(?://)?(?.*))$#', $dsn, $matches)) { + if (!preg_match( + '#^(?:(?['.self::UNRESERVED.self::SUB_DELIMS.'%]+:[0-9]+(?:[/?].*)?)|(?[a-zA-Z0-9\+-\.]+):(?://)?(?.*))$#', + $dsn, $matches)) { throw new SyntaxException($dsn, 'A DSN must contain a scheme [a-zA-Z0-9\+-\.]+ and a colon.'); } $scheme = null; @@ -128,7 +133,9 @@ private static function getDsn(string $dsn): Dsn } // Parse user info - if (!preg_match('#^(?:(['.self::UNRESERVED.self::SUB_DELIMS.'%]+)?(?::(['.self::UNRESERVED.self::SUB_DELIMS.'%]*))?@)?([^\s@]+)$#', $dsn, $matches)) { + if (!preg_match( + '#^(?:(['.self::UNRESERVED.self::SUB_DELIMS.'%]+)?(?::(['.self::UNRESERVED.self::SUB_DELIMS.'%]*))?@)?([^\s@]+)$#', + $dsn, $matches)) { throw new SyntaxException($dsn, 'The provided DSN is not valid. Maybe you need to url-encode the user/password?'); } @@ -146,12 +153,22 @@ private static function getDsn(string $dsn): Dsn if ('/' === $matches[3][0]) { $parts = self::explodeUrl($matches[3], $dsn); - return new Path($scheme, $parts['path'], self::getQuery($parts), $authentication); + return new Path( + $scheme, + $parts['path'], + self::getQuery($parts), + $authentication); } $parts = self::explodeUrl('http://'.$matches[3], $dsn); - return new Url($scheme, $parts['host'], $parts['port'] ?? null, $parts['path'] ?? null, self::getQuery($parts), $authentication); + return new Url( + $scheme, + $parts['host'], + $parts['port'] ?? null, + $parts['path'] ?? null, + self::getQuery($parts), + $authentication); } /**