diff --git a/.github/ISSUE_TEMPLATE/Bug.md b/.github/ISSUE_TEMPLATE/Bug.md index 59f71b26..25a433c2 100644 --- a/.github/ISSUE_TEMPLATE/Bug.md +++ b/.github/ISSUE_TEMPLATE/Bug.md @@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information * Shlink Version: x.y.z * PHP Version: x.y.z * How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image -* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z) +* Database engine used: MySQL|MariaDB|PostgreSQL|MicrosoftSQL|SQLite (x.y.z) #### Summary diff --git a/.github/ISSUE_TEMPLATE/Question_Support.md b/.github/ISSUE_TEMPLATE/Question_Support.md index 885f866f..5d4f55c6 100644 --- a/.github/ISSUE_TEMPLATE/Question_Support.md +++ b/.github/ISSUE_TEMPLATE/Question_Support.md @@ -18,7 +18,7 @@ With that said, please fill in the information requested next. More information * Shlink Version: x.y.z * PHP Version: x.y.z * How do you serve Shlink: Self-hosted Apache|Self-hosted nginx|Self-hosted swoole|Docker image -* Database engine used: MySQL|MariaDB|PostgreSQL|SQLite (x.y.z) +* Database engine used: MySQL|MariaDB|PostgreSQL|MicrosoftSQL|SQLite (x.y.z) #### Summary diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e19191d..3ed83602 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com), and this project adheres to [Semantic Versioning](https://semver.org). +## [Unreleased] + +#### Added + +* [#626](https://github.com/shlinkio/shlink/issues/626) Added support for Microsoft SQL Server. + +#### Changed + +* *Nothing* + +#### Deprecated + +* *Nothing* + +#### Removed + +* *Nothing* + +#### Fixed + +* *Nothing* + + ## 2.0.5 - 2020-02-09 #### Added diff --git a/Dockerfile b/Dockerfile index 01a93c26..23a142f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ -FROM php:7.4.1-alpine3.10 +FROM php:7.4.2-alpine3.11 LABEL maintainer="Alejandro Celaya " -ARG SHLINK_VERSION=2.0.0 +ARG SHLINK_VERSION=2.0.5 ENV SHLINK_VERSION ${SHLINK_VERSION} -ENV SWOOLE_VERSION 4.4.12 -ENV COMPOSER_VERSION 1.9.1 +ENV SWOOLE_VERSION 4.4.15 +ENV LC_ALL "C" WORKDIR /etc/shlink @@ -24,17 +24,22 @@ RUN \ apk add --no-cache libzip-dev zlib-dev libpng-dev && \ docker-php-ext-install -j"$(nproc)" zip gd -# Install swoole -# First line fixes an error when installing pecl extensions. Found in https://github.com/docker-library/php/issues/233 -RUN apk add --no-cache --virtual .phpize-deps ${PHPIZE_DEPS} && \ - pecl install swoole-${SWOOLE_VERSION} && \ - docker-php-ext-enable swoole && \ - apk del .phpize-deps +# Install swoole and sqlsrv driver +RUN wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_17.5.1.1-1_amd64.apk && \ + wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted msodbcsql17_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \ + pecl install swoole-${SWOOLE_VERSION} pdo_sqlsrv && \ + docker-php-ext-enable swoole pdo_sqlsrv && \ + apk del .phpize-deps && \ + rm msodbcsql17_17.5.1.1-1_amd64.apk && \ + rm mssql-tools_17.5.1.1-1_amd64.apk # Install shlink COPY . . +COPY --from=composer:1.9.3 /usr/bin/composer ./composer.phar RUN rm -rf ./docker && \ - wget https://getcomposer.org/download/${COMPOSER_VERSION}/composer.phar && \ php composer.phar install --no-dev --optimize-autoloader --prefer-dist --no-progress --no-interaction && \ php composer.phar clear-cache && \ rm composer.* diff --git a/README.md b/README.md index 3eb8a33d..414cb656 100644 --- a/README.md +++ b/README.md @@ -35,8 +35,8 @@ A PHP-based self-hosted URL shortener that can be used to serve shortened URLs u First, make sure the host where you are going to run shlink fulfills these requirements: -* PHP 7.4 or greater with JSON, APCu, intl, curl, PDO and gd extensions enabled. -* MySQL, MariaDB, PostgreSQL or SQLite. +* PHP 7.4 or greater with JSON, curl, PDO and gd extensions enabled. +* MySQL, MariaDB, PostgreSQL, Microsoft SQL Server or SQLite. * The web server of your choice with PHP integration (Apache or Nginx recommended). ### Download @@ -67,7 +67,7 @@ In order to run Shlink, you will need a built version of the project. There are Despite how you built the project, you now need to configure it, by following these steps: -* If you are going to use MySQL, MariaDB or PostgreSQL, create an empty database with the name of your choice. +* If you are going to use MySQL, MariaDB, PostgreSQL or Microsoft SQL Server, create an empty database with the name of your choice. * Recursively grant write permissions to the `data` directory. Shlink uses it to cache some information. * Setup the application by running the `bin/install` script. It is a command line tool that will guide you through the installation process. **Take into account that this tool has to be run directly on the server where you plan to host Shlink. Do not run it before uploading/moving it there.** * Generate your first API key by running `bin/cli api-key:generate`. You will need the key in order to interact with shlink's API. diff --git a/composer.json b/composer.json index 908b9af3..f26c9eec 100644 --- a/composer.json +++ b/composer.json @@ -40,16 +40,16 @@ "mezzio/mezzio-helpers": "^5.3", "mezzio/mezzio-platesrenderer": "^2.1", "mezzio/mezzio-problem-details": "^1.1", - "mezzio/mezzio-swoole": "^2.4", + "mezzio/mezzio-swoole": "^2.6", "monolog/monolog": "^2.0", "nikolaposa/monolog-factory": "^3.0", - "ocramius/proxy-manager": "^2.6.0", + "ocramius/proxy-manager": "^2.7.0", "phly/phly-event-dispatcher": "^1.0", "predis/predis": "^1.1", "pugx/shortid-php": "^0.5", "shlinkio/shlink-common": "^2.7.0", "shlinkio/shlink-event-dispatcher": "^1.3", - "shlinkio/shlink-installer": "^4.0.1", + "shlinkio/shlink-installer": "^4.1.0", "shlinkio/shlink-ip-geolocation": "^1.3.1", "symfony/console": "^5.0", "symfony/filesystem": "^5.0", @@ -115,7 +115,8 @@ "@test:db:sqlite", "@test:db:mysql", "@test:db:maria", - "@test:db:postgres" + "@test:db:postgres", + "@test:db:ms" ], "test:db:ci": [ "@test:db:sqlite", @@ -126,6 +127,7 @@ "test:db:mysql": "DB_DRIVER=mysql composer test:db:sqlite", "test:db:maria": "DB_DRIVER=maria composer test:db:sqlite", "test:db:postgres": "DB_DRIVER=postgres composer test:db:sqlite", + "test:db:ms": "DB_DRIVER=mssql composer test:db:sqlite", "test:api": "bin/test/run-api-tests.sh", "test:unit:pretty": "phpdbg -qrr vendor/bin/phpunit --order-by=random --colors=always --coverage-html build/coverage", "infect": "infection --threads=4 --min-msi=80 --log-verbosity=default --only-covered", diff --git a/config/test/test_config.global.php b/config/test/test_config.global.php index c4556b8b..fa51c240 100644 --- a/config/test/test_config.global.php +++ b/config/test/test_config.global.php @@ -45,6 +45,13 @@ $buildDbConnection = function (): array { 'dbname' => 'shlink_test', 'charset' => 'utf8', ], + 'mssql' => [ + 'driver' => 'pdo_sqlsrv', + 'host' => $isCi ? '127.0.0.1' : 'shlink_db_ms', + 'user' => 'sa', + 'password' => $isCi ? '' : 'Passw0rd!', + 'dbname' => 'shlink_test', + ], ]; $driverConfigMap['maria'] = $driverConfigMap['mysql']; diff --git a/data/infra/php.Dockerfile b/data/infra/php.Dockerfile index e92cc815..c5401651 100644 --- a/data/infra/php.Dockerfile +++ b/data/infra/php.Dockerfile @@ -1,4 +1,4 @@ -FROM php:7.4.1-fpm-alpine3.10 +FROM php:7.4.2-fpm-alpine3.11 MAINTAINER Alejandro Celaya ENV APCU_VERSION 5.1.18 @@ -65,6 +65,18 @@ RUN docker-php-ext-configure xdebug\ # cleanup RUN rm /tmp/xdebug.tar.gz +# Install sqlsrv driver +RUN wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_17.5.1.1-1_amd64.apk && \ + wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted msodbcsql17_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \ + pecl install pdo_sqlsrv && \ + docker-php-ext-enable pdo_sqlsrv && \ + apk del .phpize-deps && \ + rm msodbcsql17_17.5.1.1-1_amd64.apk && \ + rm mssql-tools_17.5.1.1-1_amd64.apk + # Install composer RUN php -r "readfile('https://getcomposer.org/installer');" | php RUN chmod +x composer.phar diff --git a/data/infra/swoole.Dockerfile b/data/infra/swoole.Dockerfile index 8bc821d9..3f7a1513 100644 --- a/data/infra/swoole.Dockerfile +++ b/data/infra/swoole.Dockerfile @@ -1,10 +1,10 @@ -FROM php:7.4.1-alpine3.10 +FROM php:7.4.2-alpine3.11 MAINTAINER Alejandro Celaya ENV APCU_VERSION 5.1.18 ENV APCU_BC_VERSION 1.0.5 ENV INOTIFY_VERSION 2.0.0 -ENV SWOOLE_VERSION 4.4.12 +ENV SWOOLE_VERSION 4.4.15 RUN apk update @@ -66,12 +66,17 @@ RUN docker-php-ext-configure inotify\ # cleanup RUN rm /tmp/inotify.tar.gz -# Install swoole -# First line fixes an error when installing pecl extensions. Found in https://github.com/docker-library/php/issues/233 -RUN apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS && \ - pecl install swoole-${SWOOLE_VERSION} && \ - docker-php-ext-enable swoole && \ - apk del .phpize-deps +# Install swoole and mssql driver +RUN wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/msodbcsql17_17.5.1.1-1_amd64.apk && \ + wget https://download.microsoft.com/download/e/4/e/e4e67866-dffd-428c-aac7-8d28ddafb39b/mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted msodbcsql17_17.5.1.1-1_amd64.apk && \ + apk add --allow-untrusted mssql-tools_17.5.1.1-1_amd64.apk && \ + apk add --no-cache --virtual .phpize-deps $PHPIZE_DEPS unixodbc-dev && \ + pecl install swoole-${SWOOLE_VERSION} pdo_sqlsrv && \ + docker-php-ext-enable swoole pdo_sqlsrv && \ + apk del .phpize-deps && \ + rm msodbcsql17_17.5.1.1-1_amd64.apk && \ + rm mssql-tools_17.5.1.1-1_amd64.apk # Install composer RUN php -r "readfile('https://getcomposer.org/installer');" | php diff --git a/docker-compose.yml b/docker-compose.yml index 99cc93fb..c78cf85f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,7 +25,10 @@ services: - shlink_db - shlink_db_postgres - shlink_db_maria + - shlink_db_ms - shlink_redis + environment: + LC_ALL: C shlink_swoole: container_name: shlink_swoole @@ -42,7 +45,10 @@ services: - shlink_db - shlink_db_postgres - shlink_db_maria + - shlink_db_ms - shlink_redis + environment: + LC_ALL: C shlink_db: container_name: shlink_db @@ -82,6 +88,15 @@ services: MYSQL_DATABASE: shlink MYSQL_INITDB_SKIP_TZINFO: 1 + shlink_db_ms: + container_name: shlink_db_ms + image: mcr.microsoft.com/mssql/server:2019-latest + ports: + - "1433:1433" + environment: + ACCEPT_EULA: Y + SA_PASSWORD: "Passw0rd!" + shlink_redis: container_name: shlink_redis image: redis:5.0-alpine diff --git a/docker/README.md b/docker/README.md index 0af66442..76c47a09 100644 --- a/docker/README.md +++ b/docker/README.md @@ -56,9 +56,9 @@ docker exec -it shlink_container shlink The image comes with a working sqlite database, but in production you will probably want to usa a distributed database. -It is possible to use a set of env vars to make this shlink instance interact with an external MySQL, MariaDB or PostgreSQL database. +It is possible to use a set of env vars to make this shlink instance interact with an external MySQL, MariaDB, PostgreSQL or Microsoft SQL Server database. -* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql**, **maria** or **postgres** to prevent the sqlite database to be used. +* `DB_DRIVER`: **[Mandatory]**. Use the value **mysql**, **maria**, **postgres** or **mssql** to prevent the sqlite database to be used. * `DB_NAME`: [Optional]. The database name to be used. Defaults to **shlink**. * `DB_USER`: **[Mandatory]**. The username credential for the database server. * `DB_PASSWORD`: **[Mandatory]**. The password credential for the database server. @@ -67,8 +67,9 @@ It is possible to use a set of env vars to make this shlink instance interact wi * Default value is based on the value provided for `DB_DRIVER`: * **mysql** or **maria** -> `3306` * **postgres** -> `5432` + * **mssql** -> `1433` -> PostgreSQL is supported since v1.16.1 of this image. Do not try to use it with previous versions. +> PostgreSQL is supported since v1.16.1 and Microsoft SQL server since v2.1.0. Do not try to use them with previous versions. Taking this into account, you could run shlink on a local docker service like this: @@ -92,7 +93,7 @@ This is the complete list of supported env vars: * `SHORT_DOMAIN_HOST`: The custom short domain used for this shlink instance. For example **doma.in**. * `SHORT_DOMAIN_SCHEMA`: Either **http** or **https**. -* `DB_DRIVER`: **sqlite** (which is the default value), **mysql**, **maria** or **postgres**. +* `DB_DRIVER`: **sqlite** (which is the default value), **mysql**, **maria**, **postgres** or **mssql**. * `DB_NAME`: The database name to be used when using an external database driver. Defaults to **shlink**. * `DB_USER`: The username credential to be used when using an external database driver. * `DB_PASSWORD`: The password credential to be used when using an external database driver. @@ -101,6 +102,7 @@ This is the complete list of supported env vars: * Default value is based on the value provided for `DB_DRIVER`: * **mysql** or **maria** -> `3306` * **postgres** -> `5432` + * **mssql** -> `1433` * `DISABLE_TRACK_PARAM`: The name of a query param that can be used to visit short URLs avoiding the visit to be tracked. This feature won't be available if not value is provided. * `DELETE_SHORT_URL_THRESHOLD`: The amount of visits on short URLs which will not allow them to be deleted. Defaults to `15`. * `VALIDATE_URLS`: Boolean which tells if shlink should validate a status 20x is returned (after following redirects) when trying to shorten a URL. Defaults to `false`. diff --git a/docker/config/shlink_in_docker.local.php b/docker/config/shlink_in_docker.local.php index 7eba5560..9e10d419 100644 --- a/docker/config/shlink_in_docker.local.php +++ b/docker/config/shlink_in_docker.local.php @@ -16,11 +16,13 @@ $helper = new class { 'mysql' => 'pdo_mysql', 'maria' => 'pdo_mysql', 'postgres' => 'pdo_pgsql', + 'mssql' => 'pdo_sqlsrv', ]; private const DB_PORTS_MAP = [ 'mysql' => '3306', 'maria' => '3306', 'postgres' => '5432', + 'mssql' => '1433', ]; public function getDbConfig(): array