絵文字のバイト数についての質問ですね。絵文字はUnicodeで表現され、通常は1文字あたりのバイト数が可変です。一般的に、絵文字は以下のようにバイト数が異なります。
3バイト: 多くの一般的な絵文字は3バイトで表現されます。
4バイト: 一部の絵文字、特に特定の漢字や複雑な絵文字は4バイトを必要とします。
最近のUnicode標準では、最もバイト数が多い絵文字は、複数の要素を組み合わせたものです。例えば、2人の人がキスをしている絵文字(🧑🏻❤️💋🧑🏼)は、スキントーン修飾子を含むため、合計で35バイトを必要とします。
このように、絵文字のバイト数はその構成によって大きく異なるため、特定の絵文字が何バイトかを知ることは、使用する場面によって重要です。
大きい目の笑顔:😃
直でもいいの?😃
どちらを使っても表示されるので、基本的には好きな方を選んで問題ありません!ただ、状況によって使い分けることをおすすめします。
😀 (絵文字そのものを入力する方法)
この方法はシンプルで直感的ですが、ファイルのエンコーディングがUTF-8である必要があります。もしエンコーディングが適切でない場合、文字化けが発生する可能性があります。
😀 (文字参照を使う方法)
HTMLエンティティを使うと、エンコーディングに依存しないので安全性が高まります。また、コードを扱う際に明示的でわかりやすい点も利点です。ただし、読みづらくなる可能性があるので、複数の絵文字を使う場合は注意が必要です。
つまり、簡単な作業や個人用のページでは「😀」を使い、エンコーディングの問題や他人が読むことを考慮する場面では「😀」を選ぶのが良いかもしれません。
「絵文字そのもの」をMySQLに保存する
CREATE TABLE emojis ( id INT AUTO_INCREMENT PRIMARY KEY, emoji_text VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL );
指定する文字数(例: 255)は文字数そのものを指します。つまり、絵文字そのものを保存した場合でも、文字参照(例: 😀)を保存した場合でも、MySQLの文字列の長さとして扱われるのはエンコード後のバイト数ではなく、論理的な文字数です。
ただし、以下の点に注意してください:
絵文字そのもの(例: 😀)は通常1文字とカウントされます。ただし、utf8mb4を使用している場合に限ります。
文字参照(例: 😀)はそのまま保存すると、その文字列の全体の長さがカウントされます。例えば、😀は9文字としてカウントされます。
AES_ENCRYPT('データ', '鍵')
キーの長さ: AESではキーの長さが暗号化の強度に影響します。AES_ENCRYPTでは、使用するキーの長さに基づいて暗号化が行われますが、長さが16バイト、24バイト、32バイト(128ビット、192ビット、256ビット)である必要があります。
指定したキーがそれ以外の長さの場合、MySQLは自動的にキーを適切な長さに切り詰めたり、ゼロ埋めを行う場合があります。
キーの長さが正確に16、24、32バイトの場合は、何の調整も行われずそのまま使用されます。
ゼロ埋めや切り捨ては、意図しない暗号化結果を引き起こす可能性があるため、使用するキーは明示的に適切な長さで生成することが推奨されます。
MySQLのAES_ENCRYPT関数は、ECBモードを使用します。このモードは各ブロックを独立して暗号化するため、初期化ベクトルを必要としません。
ECBモードの欠点として、同じ平文が同じ暗号文になるという特徴があります。これにより、暗号のパターンが推測されやすくなるという弱点があります。
AES_ENCRYPT(str, key) を使った場合、暗号化されたデータのサイズは以下のように決まります:
AESのブロックサイズは 16バイト(128ビット)です。
暗号化する文字列のサイズが 16バイトの倍数でない場合、パディングによってサイズが増加します。
暗号化後のデータサイズ ≈ 元のデータサイズ + (16 - 元のデータサイズ % 16)(パディングを考慮)
MySQL 8.0以降では、AES_ENCRYPTとAES_DECRYPTでAES-GCMモードをサポートするようになり、このモードでは暗号化に初期化ベクトル(IV)が内部的に使用されます。ただし、IVをユーザーが直接指定することはできません。システムが自動で管理します。
MariaDBでは、AES-GCMモードはサポートされていません。
暗号文サイズ = 平文のサイズ(バイト) + IVサイズ(12バイト) + 認証タグサイズ(16バイト)
AES-GCM以外の暗号化モード(例: AES-CBC, AES-ECBなど)では、認証タグが生成されない。
AES-GCMではパディングは発生しない。
MySQLのAES_ENCRYPT()はバイナリデータとして暗号化結果を返すため、保存するときはVARBINARYを使うのが適切です。
Fedora 42 users can install gnome-shell-extension-appindicator which is already ready for Gnome 48
$ sudo dnf install gnome-shell-extension-appindicator Package Arch Version Repository Size Installing: gnome-shell-extension-appindicator noarch 59-2.fc41 fedora 246.0 KiB Installing dependencies: libappindicator-gtk3 x86_64 12.10.1-5.fc41 fedora 108.6 KiB libdbusmenu x86_64 16.04.0-28.fc41 fedora 540.3 KiB libdbusmenu-gtk3 x86_64 16.04.0-28.fc41 fedora 88.5 KiB Transaction Summary: Installing: 4 packages $ sudo dnf install libappindicator-gtk3
「NOT NULL」を指定しない場合、デフォルトでそのカラムはNULL値を許容します。つまり、データを挿入するときにそのカラムの値を指定しなくても、NULL値が設定されます。
「NULL値を許容している場合」に「DEFAULT NULL」を明示的に指定しなくても、結果として同じ動作になります。つまり、デフォルトでNULL値が設定可能な状態となり、値を挿入しない場合そのカラムの値はNULLになります。
CREATE TABLE example_table1 ( column1 INT -- デフォルトでNULLが許容される );
CREATE TABLE example_table2 ( column1 INT DEFAULT NULL -- 明示的にNULLをデフォルト値として指定 );
この2つは動作に違いはなく、どちらの定義でもcolumn1に値を挿入しない場合はNULLが自動的に設定されます。ただし、「DEFAULT NULL」を明示することには利点があります。
例えば:
テーブルの定義をより読みやすくする(意図が明確になる)
他の開発者への理解を助ける
文字列の比較
文字列の並べ替え(ソート)
LIKE句での部分一致検索
UNIONやDISTINCTでの重複排除
全文検索インデックス(FULLTEXT)
CREATE TABLE `table_name` ( `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT, `name` varchar(191) NOT NULL, `hash` varchar(255) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `token` char(64) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, `url` varchar(2083) COLLATE utf8mb4_bin NOT NULL, `mail` varchar(254) COLLATE utf8mb4_general_ci NOT NULL, `color` varchar(7) CHARACTER SET ascii COLLATE ascii_general_ci NOT NULL DEFAULT '#0000ff', `timezone` varchar(50) CHARACTER SET ascii COLLATE ascii_bin NOT NULL DEFAULT 'Asia/Tokyo', `file` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `unique_mail` (`mail`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
UNIQUE KEY:重複を許可しないユニークな制約を付ける場合に使用します。
UNIQUE KEY キー名 (カラム名)の形式です。
キー名は省略可能ですが、指定すると管理しやすくなります。
パスワードハッシュ値
文字コード (Character Set):
utf8mb4またはascii パスワードハッシュ値は通常英数字や特殊文字を含む固定長の文字列であるため、ASCII文字だけでも十分対応可能です。特にasciiは効率的で、ストレージ使用量を最小限に抑えます。ただし、環境や拡張性の観点でutf8mb4も一般的に使われます。
照会順序 (Collation):
utf8mb4_binまたはascii_bin ハッシュ値は大小文字やバイナリデータをそのまま比較する必要があるため、_binのようなバイナリ照会順序を使用するべきです。これにより、ハッシュ値同士を正確に比較することができます。
補足:
PASSWORD_DEFAULTは将来的に別のアルゴリズムに変更される可能性があります。そのため将来のアルゴリズムがより長いハッシュ値を生成する可能性を考慮し、VARCHAR(255) のように余裕を持たせて設計するのが一般的です。
ハッシュ値を保存する際に使用する文字コードと照会順序は、asciiとascii_binが最適です。効率的で正確に比較が可能です。
bin2hex(random_bytes(32))で生成されるURLトークン
asciiとascii_binが最適です。
さらに、トークンの安全な保存や運用を考慮して、以下の点を押さえておくとよいでしょう:
カラム長の設定: bin2hex(random_bytes(32))は64文字の固定長文字列を生成します。そのため、データ型はCHAR(64)を使用すると適切です。
インデックスの設定: トークンが検索や確認に頻繁に使われる場合、カラムにインデックスを設定することでパフォーマンスが向上します。
メールアドレス
文字コード (Character Set):
utf8mb4
メールアドレスには、国際化ドメイン名や特殊文字(たとえば、非ASCII文字を含むアドレス)が含まれることがあり得ます。utf8mb4を使用することで、すべての可能性を包括的にサポートできます。
英数字のみのメールアドレスが多い場合でも、柔軟性のためutf8mb4が推奨されます。
照会順序 (Collation):
utf8mb4_general_ci
メールアドレスのドメイン部分(例:@example.com)は大小文字を区別しないことが標準です。そのため、_ci(case-insensitive)の照会順序を使用することで、大小文字の違いを無視した比較が可能になります。
補足:
保存するカラムのデータ型:
メールアドレスの長さは通常最大254文字です。そのため、データ型はVARCHAR(254)を設定するのが一般的です。
一意性の保証:
メールアドレスはユニークな値であることが多いので、UNIQUE制約をカラムに追加することを検討してください。
Webの色指定
例えば#ff00ff(16進数表現)やrgb(0, 0, 255)、さらにはgreenのような英語名についても、データベースで保存する場合はasciiとascii_binが適しています。
1. 各形式に対する適合性
16進数カラーコード(例:#ff00ff) 文字列はASCII範囲内の文字(0-9, a-f, #)のみで構成されています。そのため、ascii文字コードで効率よく保存できます。
RGB形式(例:rgb(0, 0, 255)) この形式もASCII範囲内の文字(英数字と括弧、カンマ、スペース)で表現されるため、同様にasciiで対応可能です。
色名(例:green) 色名はすべて英字で表記されるため、ASCII文字セットで完全にカバーされます。
2. 照会順序(Collation)
色指定は正確な比較が必要になることが多い(特に16進数やRGB値)ため、大小文字区別をするascii_binが推奨されます。例えば、#FF00FFと#ff00ffを別々の値として扱いたい場合に役立ちます。#FF00FFと#ff00ffを同じものとして扱いたい場合は、ascii_general_ciの照会順序が適しています。
タイムゾーン名(例:Asia/Tokyo)
asciiとascii_binの設定で問題ありません。
理由
ASCII文字のみを使用
タイムゾーン名は英字、数字、スラッシュ(/)、およびアンダースコア(_)のみで構成されており、これらはすべてASCII文字セットに収まるため、asciiが適しています。
正確な比較が必要
タイムゾーン名は一般的に正確な一致が必要なデータ(Asia/Tokyoとasia/tokyoを区別するなど)なので、大小文字を区別するascii_binの照会順序が最適です。
カラムの最大文字数
タイムゾーン名は現在のIANAタイムゾーンデータベース(TZ Database)に基づいており、一番長いものは35文字程度です(例:America/Argentina/ComodRivadavia)。そのため、余裕を見て以下を推奨します:
データ型: VARCHAR(50) これにより将来の更新にも対応可能です。
URLアドレス
文字コード (Character Set):
utf8mb4 URLには英数字だけでなく、特殊文字や国際化ドメイン名(非ASCII文字を含む)が含まれることがあります。そのため、utf8mb4を使用することで、すべての可能性を包括的にサポートできます。
照会順序 (Collation):
utf8mb4_bin URLの正確な比較が必要な場合、大文字小文字や特殊文字の違いを区別する照会順序であるutf8mb4_binを使用すると適切です。URLアドレスは通常、完全一致で判定することが求められるため、バイナリ順序が最適です。
カラムの最大文字数:
データ型: VARCHAR(2083) 一般的に、URLの最大長はウェブブラウザの制限(例えば2083文字)を考慮して設定されます。これにより長いURLも問題なく保存できます。
短いURLだけを使用する場合は、必要に応じて制限を減らすことができますが、将来の拡張性を考慮して余裕を持たせるのが理想的です。
補足
インデックスの設定: URLが検索や一致判定に頻繁に使われる場合、インデックスを付与することで検索パフォーマンスが向上します。
ファイル名
文字コード (Character Set):
utf8mb4 ファイル名には国際化された文字や特殊文字が含まれる可能性があります。utf8mb4を使用することで、ASCII文字だけでなく、全ての非ASCII文字も安全に保存できます。この設定は広範な文字セットに対応するため推奨されます。
照会順序 (Collation):
utf8mb4_bin ファイル名は通常正確な一致が必要なので、大文字小文字や特殊文字を区別する照会順序であるutf8mb4_binが最適です。たとえば、File.txtとfile.txtを別々に扱う場合に役立ちます。
カラムの最大文字数:
データ型: VARCHAR(255) 多くのファイルシステムでは、ファイル名の長さが最大255文字までに制限されています(例: NTFSやext4)。これに合わせてデータベース側もVARCHAR(255)を設定するのが一般的です。
補足:
一意性の保証: ファイル名が一意である必要がある場合は、UNIQUE制約を追加して重複を防ぐことができます。
インデックス: ファイル名で頻繁に検索や比較を行う場合は、インデックスを設定することで効率を向上させます。
ディレクトリパスの扱い: ファイル名にディレクトリパスを含む場合は、より長いカラム(例: VARCHAR(1000)など)が必要になる可能性があります。
SQL
SELECT VERSION();
Bash
mysql --version
MySQL 8.0以降では、AES_ENCRYPTとAES_DECRYPTでAES-GCMモードをサポートするようになり、このモードでは暗号化に初期化ベクトル(IV)が内部的に使用されます。ただし、IVをユーザーが直接指定することはできません。
現時点では、MariaDBはAES-GCMモードをサポートしていません。
MySQL 8.0以降では、AES_ENCRYPTおよびAES_DECRYPT関数でAES-GCMモードを利用する際、追加のオプションを指定することで有効化できます。
SET block_encryption_mode = 'aes-256-gcm'; -- 暗号化モードをAES-GCMに設定 SELECT AES_ENCRYPT('テキスト', '鍵');
SET block_encryption_mode = 'aes-256-gcm'; -- 同じ暗号化モードを設定 SELECT AES_DECRYPT(暗号化されたデータ, '鍵');
AES-GCMモードを使用する場合、暗号化されたデータは初期化ベクトル(IV)や認証タグの追加により、元のデータよりもサイズが増加します。
暗号化データの合計サイズの増加は以下の通り:
12バイト(IV) + 16バイト(認証タグ) = 28バイトの増加。
IVの役割について
初期化ベクトル(IV)は、暗号化アルゴリズム(特にAES-CBCなどのブロック暗号モード)において、暗号化の際に予測可能性を排除し、同じ平文でも異なる暗号文を生成するために使われます。これにより、暗号化の安全性が向上します。
キーを変えることでも「同じ平文でも異なる暗号文を生成する」。
キーを変える場合
キーを変えることで異なる暗号文が生成されます。これは、暗号化アルゴリズムにおいて暗号文がキーに依存するためです。
メリット:
毎回異なるキーを使うことで、同じ平文でも完全に異なる暗号文が得られ、予測可能性を排除できます。
デメリット:
キー管理が複雑になる: 多くの異なるキーを管理する必要があるため、特に大規模システムでは運用が困難になります。
キー共有の課題: 復号化のために暗号化と同じキーを安全に相手と共有する手段が必要です。
IVを使う場合
IV(初期化ベクトル)は、固定されたキーを使い続けても平文が同じ場合に暗号文を異なるものにするための手段として設計されています。IVはランダムに生成され、通常、暗号文と一緒に保存または伝達されます。
メリット:
キーを変えなくても効果を得られる: 固定された1つのキーで運用でき、管理が容易になります。
アルゴリズム的なセキュリティ強化: 平文のパターンが暗号文に現れることを防ぎます(例:AES-CBC、AES-GCM)。
デメリット:
IV自体がランダムである必要があるため、その生成プロセスやストレージに注意が必要です。
1. utf8mb4_general_ci
特徴:
一般的な(general)目的で設計された照会順序。
大文字・小文字を区別しない(ci = case insensitive)。
比較やソートの処理が軽量で高速。
動作の簡易性:
複雑なユニコードルールを無視し、簡易的な方法で文字列比較を行います。
特殊な文字やアクセントの扱いが少し粗くなる(例: "ö" と "o" を同一視するなど)。
適している場面:
速度重視の場合。
言語の細かな違いにこだわらない単純な文字列比較が必要な場面。
2. utf8mb4_unicode_ci
特徴:
ユニコード標準(Unicode Collation Algorithm)に基づいた照会順序。
より正確で複雑な文字列比較を実現。
大文字・小文字を区別しない(ci = case insensitive)。
アクセントや特殊文字の正確性:
特殊なアクセント記号や文字の違いを認識する(例: "ö" と "o" は異なる文字と認識)。
適している場面:
多言語対応が必要な場合。
言語に固有の文字の違いを正確に扱いたい場面。
性能の違い
utf8mb4_general_ciは比較処理が軽量で高速ですが、文字列の正確性を犠牲にしています。
utf8mb4_unicode_ciはユニコード標準に準拠するため、比較処理が少し重くなりますが、文字列の正確性が向上します。
選択のポイント
utf8mb4_general_ciを選ぶべき場合:
パフォーマンスを重視し、細かな文字の違いが重要でない場合。
utf8mb4_unicode_ciを選ぶべき場合:
多言語データや特殊文字を扱う場面で、正確な文字列比較が必要な場合。
例えば、日本語や絵文字を含むデータを扱う場合には、ユニコードの標準的な動作を提供するutf8mb4_unicode_ciが適しています。
utf8mb4_binについて
utf8mb4_binは、大文字小文字を区別しながらも、文字列の並べ替え(ソート)を行うことができます。ただし、並べ替えはバイナリ値(文字の内部表現)に基づいて行われるため、言語や文化に依存した「辞書順」の並べ替えとは異なります。
utf8mb4_binは、文字列をバイト単位で評価します。
この結果、文字列の内部バイナリ値に基づいてソートされます。
例えば、ASCIIコードで「A」が「a」より小さいため、utf8mb4_binでは「A」が「a」の前に来ます。