From 2ed475fc7691ecee9795d26bd940e90f932c59ec Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Mon, 10 Jan 2022 14:37:44 +0100 Subject: [PATCH] Ensure database fields are created with proper charset and collation in MySQL --- .../Shlinkio.Shlink.Core.Entity.Domain.php | 8 ++++---- .../Shlinkio.Shlink.Core.Entity.ShortUrl.php | 8 ++++---- .../Shlinkio.Shlink.Core.Entity.Tag.php | 2 +- .../Shlinkio.Shlink.Core.Entity.Visit.php | 6 +++--- ...inkio.Shlink.Core.Entity.VisitLocation.php | 2 +- module/Core/functions/functions.php | 20 ++++++++++--------- 6 files changed, 24 insertions(+), 22 deletions(-) diff --git a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Domain.php b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Domain.php index 596f41da..68427b42 100644 --- a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Domain.php +++ b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Domain.php @@ -21,21 +21,21 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->option('unsigned', true) ->build(); - $builder->createField('authority', Types::STRING) + fieldWithUtf8Charset($builder->createField('authority', Types::STRING), $emConfig) ->unique() ->build(); - $builder->createField('baseUrlRedirect', Types::STRING) + fieldWithUtf8Charset($builder->createField('baseUrlRedirect', Types::STRING), $emConfig) ->columnName('base_url_redirect') ->nullable() ->build(); - $builder->createField('regular404Redirect', Types::STRING) + fieldWithUtf8Charset($builder->createField('regular404Redirect', Types::STRING), $emConfig) ->columnName('regular_not_found_redirect') ->nullable() ->build(); - $builder->createField('invalidShortUrlRedirect', Types::STRING) + fieldWithUtf8Charset($builder->createField('invalidShortUrlRedirect', Types::STRING), $emConfig) ->columnName('invalid_short_url_redirect') ->nullable() ->build(); diff --git a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.ShortUrl.php b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.ShortUrl.php index 83fd7e79..4aefe26b 100644 --- a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.ShortUrl.php +++ b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.ShortUrl.php @@ -23,12 +23,12 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->option('unsigned', true) ->build(); - $builder->createField('longUrl', Types::STRING) + fieldWithUtf8Charset($builder->createField('longUrl', Types::STRING), $emConfig) ->columnName('original_url') ->length(2048) ->build(); - $builder->createField('shortCode', Types::STRING) + fieldWithUtf8Charset($builder->createField('shortCode', Types::STRING), $emConfig, 'bin') ->columnName('short_code') ->length(255) ->build(); @@ -57,7 +57,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->nullable() ->build(); - $builder->createField('importOriginalShortCode', Types::STRING) + fieldWithUtf8Charset($builder->createField('importOriginalShortCode', Types::STRING), $emConfig) ->columnName('import_original_short_code') ->nullable() ->build(); @@ -85,7 +85,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { $builder->addUniqueConstraint(['short_code', 'domain_id'], 'unique_short_code_plus_domain'); - $builder->createField('title', Types::STRING) + fieldWithUtf8Charset($builder->createField('title', Types::STRING), $emConfig) ->columnName('title') ->length(512) ->nullable() diff --git a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Tag.php b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Tag.php index 97d15758..9f02ec72 100644 --- a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Tag.php +++ b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Tag.php @@ -21,7 +21,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->option('unsigned', true) ->build(); - $builder->createField('name', Types::STRING) + fieldWithUtf8Charset($builder->createField('name', Types::STRING), $emConfig) ->unique() ->build(); diff --git a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Visit.php b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Visit.php index 8886e141..969bfd1d 100644 --- a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Visit.php +++ b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.Visit.php @@ -23,7 +23,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->option('unsigned', true) ->build(); - $builder->createField('referer', Types::STRING) + fieldWithUtf8Charset($builder->createField('referer', Types::STRING), $emConfig) ->nullable() ->length(Visitor::REFERER_MAX_LENGTH) ->build(); @@ -40,7 +40,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->nullable() ->build(); - $builder->createField('userAgent', Types::STRING) + fieldWithUtf8Charset($builder->createField('userAgent', Types::STRING), $emConfig) ->columnName('user_agent') ->length(Visitor::USER_AGENT_MAX_LENGTH) ->nullable() @@ -55,7 +55,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ->cascadePersist() ->build(); - $builder->createField('visitedUrl', Types::STRING) + fieldWithUtf8Charset($builder->createField('visitedUrl', Types::STRING), $emConfig) ->columnName('visited_url') ->length(Visitor::VISITED_URL_MAX_LENGTH) ->nullable() diff --git a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.VisitLocation.php b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.VisitLocation.php index 955fa1fa..0216f7aa 100644 --- a/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.VisitLocation.php +++ b/module/Core/config/entities-mappings/Shlinkio.Shlink.Core.Entity.VisitLocation.php @@ -29,7 +29,7 @@ return static function (ClassMetadata $metadata, array $emConfig): void { ]; foreach ($columns as $columnName => $fieldName) { - $builder->createField($fieldName, Types::STRING) + fieldWithUtf8Charset($builder->createField($fieldName, Types::STRING), $emConfig) ->columnName($columnName) ->nullable() ->build(); diff --git a/module/Core/functions/functions.php b/module/Core/functions/functions.php index bba0c17b..567fde47 100644 --- a/module/Core/functions/functions.php +++ b/module/Core/functions/functions.php @@ -6,6 +6,7 @@ namespace Shlinkio\Shlink\Core; use Cake\Chronos\Chronos; use DateTimeInterface; +use Doctrine\ORM\Mapping\Builder\FieldBuilder; use Jaybizzle\CrawlerDetect\CrawlerDetect; use Laminas\InputFilter\InputFilter; use PUGX\Shortid\Factory as ShortIdFactory; @@ -13,13 +14,10 @@ use Shlinkio\Shlink\Common\Util\DateRange; use function Functional\reduce_left; use function is_array; -use function lcfirst; use function print_r; use function Shlinkio\Shlink\Common\buildDateRange; use function sprintf; use function str_repeat; -use function str_replace; -use function ucwords; function generateRandomShortCode(int $length): string { @@ -34,7 +32,7 @@ function generateRandomShortCode(int $length): string function parseDateFromQuery(array $query, string $dateName): ?Chronos { - return ! isset($query[$dateName]) || empty($query[$dateName]) ? null : Chronos::parse($query[$dateName]); + return empty($query[$dateName] ?? null) ? null : Chronos::parse($query[$dateName]); } function parseDateRangeFromQuery(array $query, string $startDateName, string $endDateName): DateRange @@ -100,11 +98,6 @@ function arrayToString(array $array, int $indentSize = 4): string }, ''); } -function kebabCaseToCamelCase(string $name): string -{ - return lcfirst(str_replace(' ', '', ucwords(str_replace('-', ' ', $name)))); -} - function isCrawler(string $userAgent): bool { static $detector; @@ -114,3 +107,12 @@ function isCrawler(string $userAgent): bool return $detector->isCrawler($userAgent); } + +function fieldWithUtf8Charset(FieldBuilder $field, array $emConfig, string $collation = 'unicode_ci'): FieldBuilder +{ + return match ($emConfig['connection']['driver'] ?? null) { + 'pdo_mysql' => $field->option('charset', 'utf8mb4') + ->option('collation', 'utf8mb4_' . $collation), + default => $field, + }; +}