我在做什么
我正在开发一个聊天应用程序(用PHP编写),它允许用户创建自己的聊天室。用户可以将聊天室命名为他们喜欢的任何名称,并将该名称作为相应聊天室的表名称传递到预先准备好的语句中的MySQL数据库。
据了解,此应用程序没有登录/安全措施,持有聊天记录的表由只包含用户提交的文本和时间戳的记录组成(2列,不包括AUTO_INCREMENT
主要键)。
我面临的是什么
鉴于此应用程序的简单性质,我无意更改数据库的结构,但是当用户输入表情符号(或其他补充字符)作为名称时,我现在遇到了问题他们自己的聊天室。由于MySQL内部工作的方式(https://dev.mysql.com/doc/refman/5.7/en/identifiers.html),将这些信息传递给数据库会将字符转换为问号:
Identifiers are converted to Unicode internally. [..] ASCII NUL (U+0000) and supplementary characters (U+10000 and higher) are not permitted in quoted or unquoted identifiers.
我应该/我可以做些什么来避免这个问题?在这样的情况下,是否存在“转义”/“消毒”用户输入的最佳做法?我把相应的单词放在引号中,因为我知道这不是在数据库中处理用户输入的正确/典型方式。
我正在尝试
我的一个想法是使用rawurlencode()
将补充字符分解为可以传递给数据库的唯一序列,并且仍然确保名称为的聊天室不是与
混淆。但是,基于这个答案,我的印象是这不是一个好的做法:https://stackoverflow.com/a/8700296/1564356。
以另一种方式解决这个问题,我想到了base64_encode()
,但再次根据这个答案,这不是一个理想的方法:https://stackoverflow.com/a/24175941/1564356。我想知道,如果在这种情况下它仍然是可以接受的。
第三种选择是通过发布唯一标识符作为每个相应聊天室的表名并在列中存储utf8mb4
兼容字符串,以不同的方式构建数据库。然后,可以将具有实际聊天日志的第二个表与外键链接。然而,这使数据库的结构复杂化并且使所需的表的数量加倍。我不喜欢这种做法。
有什么想法吗?谢谢!
答案 0 :(得分:2)
动态创建的表,无论其命名方案如何,都很少是明智的设计选择。它们使您编写的每个查询都更加复杂,并消除了SQL作为语言和关系数据库作为概念的大部分用处。
此外,允许用户直接选择表名称听起来像是等待发生的安全灾难。准备好的语句不会以任何方式保存您,因为表名被视为查询的一部分,而不是数据的一部分。
除非您有非常令人信服的理由进行这种不寻常的设计,否则我强烈建议您更改为只有一个chat_logs
的表,其中chat_room_id
列引用chat_rooms
表。然后chat_rooms
表可以包含名称,该名称可以包含用户想要的任何字符,以及有关房间的其他数据 - 创建日期,描述,额外功能等。这种方法只需要2个表,但是很多聊天房间已经创建。
如果您真的认为每个聊天室都需要单独的表,因为您尝试进行一些聪明的分区/分片,我会仍建议使用chat_rooms
表,然后你可以简单地在chat_room_id
之后命名表格,例如chat_logs_1
,chat_logs_2
等。此方法只需要比当前方法多一个表,即num_tables = num_chat_rooms + 1.
答案 1 :(得分:0)
CHARACTER SET utf8mb4
。
在this中,当您未遵循最佳做法时,您会发现有关“最佳做法”和调试提示的更多信息。它不仅仅是列字符集,它也是客户端的字符集。
不要使用任何编码/解码程序;它只会使混乱变得更糟。
最好将实际字符放在MySQL表中,而不是像U+1F914
或\u1F914
等Unicode字符串。
是4字节的十六进制
F09FA494
。
而且,我同意IMSoP;不要动态创建表。
SQL注入应该使用mysqli_real_escape_string(或等效的,取决于API),而不是urlencode或base64。