質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

1回答

787閲覧

入力文字数を、フロントエンドとバックエンドで統一する方法

nikuatsu

総合スコア177

MySQL

MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

SQL

SQL(Structured Query Language)は、リレーショナルデータベース管理システム (RDBMS)のデータベース言語です。大きく分けて、データ定義言語(DDL)、データ操作言語(DML)、データ制御言語(DCL)の3つで構成されており、プログラム上でSQL文を生成して、RDBMSに命令を出し、RDBに必要なデータを格納できます。また、格納したデータを引き出すことも可能です。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2022/11/24 19:27

編集2022/11/24 19:38

前提

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で行っておりますが、そのcharsetutf8mb4でした。

そして、SHOW VARIABLES LIKE '%char%';を実行し、character_set_serverutf8mb4でした。

試したこと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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2022/11/24 23:52

> SQLでインデックスを貼るとVARCHAR(768)が限度 設定次第でその上限は外せるという情報もありましたが、そういう手段は取れないのでしょうか?
nikuatsu

2022/11/25 02:21

いえ、そういう手段があれば是非知りたいです。 早速検索し次の3つの手段を見つけましたが、それぞれ微妙な印象です。 https://blog.e2info.co.jp/2017/04/17/mysqlのインデックスサイズに767byteまでしかつかえない/ 1:絵文字を諦める → 諦めたくありません 2:191バイトにする → 768以上使いたいのに、191にしてどうするのか、理解ができません 3:innodb_large_prefix → レンタルサーバーのため権限なしです もしmaisumakun様の方で他にお心当たりございましたらご教示いただけませんでしょうか。
maisumakun

2022/11/25 02:27

あと、全文にインデックスを入れたいのはどんな事情でしょうか(プレフィックスインデックスでは不足する状況でしょうか)。
nikuatsu

2022/11/25 02:36

検索したいという事情でインデックスを条件にしたのですが、プレフィックスインデックスというのを初めて知りました。アドバイスありがとうございます。 早速調べてみると以下見つけました。 http://hono-linux.seesaa.net/article/416490499.html どうやらテストデータが必要なようなので、いくつかINSERTした上でまたコメントさせて頂ければと思います。
maisumakun

2022/11/26 04:44

> 検索したいという事情でインデックスを条件にしたのですが 完全一致以外の検索をかけたいのであれば、全文検索インデックスのほうが適当かもしれません。
nikuatsu

2022/12/03 07:04

なるほど。全文検索インデックスというのも良さそうに思えてきました。取り組んで比べてみたいと思います。ありがとうございます。
guest

回答1

0

utf8mb4で処理する限りvarchar(10)レベルなら特に問題おきてないですね

SQL

1create table test_table ( 2id int(10) unsigned primary key auto_increment, 3content varchar(10) NOT NULL, 4index(content) 5) engine = innodb default character set utf8mb4 collate utf8mb4_general_ci; 6 7INSERT INTO test_table ( content ) 8VALUES ( 'abcdefghi' ),( 'abcdefghi🏴󠁧󠁢󠁥󠁮󠁧󠁿' ),( 'abcdefghi🏴󠁧󠁢󠁥󠁮󠁧󠁿j' );

投稿2022/11/25 00:24

yambejp

総合スコア114843

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nikuatsu

2022/11/25 02:13

ありがとうございます。妙ですね。そちらは質問のALTER TABLEで同じテーブルになると思いますし、とはいえyambejp様のご回答ならばと思ってそちらコピペし実行致しましたが、やはりData too longのエラーでした。何か設定があるのでしょうか。
yambejp

2022/11/25 02:25

my.cnfの設定で[mysqld]にsql_mode=''を設定するとエラーは回避できるかもしれません utf8mb4なので普通なら絵文字は1文字計算されるんですけどね
yambejp

2022/11/25 02:30

なお、長い文字列をvarchar指定するのはあまり意味がありません text型などに切り替えた方がよいでしょう。 文字数制限は生成列を利用すれば制限を設定できるかもしれません
nikuatsu

2022/11/25 02:45

なるほど。sql_mode='' にしてしまうのはアリかもしれません。ありがとうございます。考えつきませんでした。 TEXTは遅そうという先入観があったのですが、検索するとあまり大きな差はでないとのことでしたのでこちらも検討させて頂きます。
yambejp

2022/11/25 08:36 編集

🏴󠁧󠁢󠁥󠁮󠁧󠁿はchar_lengthで5文字カウントですね varchar(10)にすると2つしか保持できずvarchar(11)にすると3つ保持できるという ちょっと特殊な状況ですね。 SQL側でこの手の絵文字を1文字カウントするのは難しそうです。 ミドルウェア側で調整し、DBでは多めにバッファを取って処理するのが限界かもしれません もしくは「&#127988;」のようにエンティティ化して文字単位ではない工夫をするとか・・・
nikuatsu

2022/12/03 07:05

ありがとうございます。多めにバッファという案が良さそうです。参考にさせて頂きます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問