前提
JavaScript・php・SQLで掲示板サイトを作成しているのですが、絵文字を含む文字数のカウントで苦慮しています。
実現したいこと
次の条件でコメント入力を可能にしたいです。
・絵文字を含む(書記素単位で)「最大500文字まで」にしたい
・カラムにはインデックスを貼る
(合字は気にしません。)
発生している問題
まずは、JavaScriptで500文字の検証は出来ました。
ライブラリ「grapheme-splitter」を使います。
https://github.com/orling/grapheme-splitter
そして、PHPでも出来ました。
関数grapheme_strlen
を使います。
https://www.php.net/manual/ja/function.grapheme-strlen.php
しかし、SQLでは以下のように出来ません。
該当のソースコード・エラーメッセージ
SQLでは以下ソースコードとエラーメッセージになります。(実現したいのは500文字ですが、わかりやすくVARCHAR(10)
にしています。)
SQL
1-- ソースコード 2CREATE TABLE test_table ( 3 id INT UNSIGNED NOT NULL AUTO_INCREMENT 4 ,content VARCHAR(10) CHARACTER SET utf8mb4 NOT NULL 5 ,PRIMARY KEY (id) 6 ,INDEX idx_test_table_01 (content) 7); 8 9INSERT INTO test_table ( content ) 10VALUES ( 'abcdefghi🏴' ); -- 旗の絵文字のバイト数にご注意ください 11 12-- エラーメッセージ 13-- #1406 - Data too long for column 'content' at row 1
上記の'abcdefghi🏴'
は、JavaScriptとPHPでは10になるのですが、SQLのVARCHAR(10)
ではエラーになってしまうのです。
確認したこと
まず、DB接続はnew PDO
で行っておりますが、そのcharset
はutf8mb4
でした。
そして、SHOW VARIABLES LIKE '%char%';
を実行し、character_set_server
はutf8mb4
でした。
試したこと1 ( COLLATE 指定 )
次のALTER TABLE
を実行しても変わりありませんでした。
sql
1ALTER TABLE test_table MODIFY content VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 2ALTER TABLE test_table MODIFY content VARCHAR(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
試したこと2 ( CHAR_LENGTH でのカウント )
SQLだけで整合が取れないなら、SQLだけで文字数のカウントを行う次のCHAR_LENGTH
というアプローチも考えられます。が、しかしこれは「最大500文字まで」を実現することができません。
ユーザーにとって(書記素単位では)🏴
は1文字なのに、これではそういったカウントができないのです。
php
1<?php 2function getCharLength($str) { 3 $mysqli = new MySQLi('db_host', 'db_user', 'db_pass', 'db_name'); 4 $mysqli->set_charset('utf8mb4'); 5 $sql = sprintf('SELECT CHAR_LENGTH("%s")', $mysqli->real_escape_string($str)); 6 $result = (int)$mysqli->query($sql)->fetch_column(); 7 $mysqli->close(); 8 return $result; 9}
難しいポイント
難しいのは「最大500文字まで」という点です。
もし「最大10文字まで」ならJavaScriptとphpで10文字をカウントする検証を挟み、SQLはVARCHAR(100)
にでもしておけば済む話です。もし🏴
を10個入力されても問題ありません。
しかし「最大500文字まで」なので、もし🏴
を500個入力されたとき、JavaScriptとphpでは問題なく500文字なのに、SQLでは768を超えてしまうという点です。(SQLでインデックスを貼るとVARCHAR(768)
が限度)
ツールのバージョン
php: 8.1
MySQL: 5.7
