2012-07-17 45 views
8

我正面临一个小问题。我正在开发一个应用程序,需要在MySQL中使用动态表名。使用Codeigniter安全地转义MySQL中的动态表名称

基本上,我有一个基于多种因素(风格,播放长度,发布日期等)从数据库中选择专辑的过程 - 这个过程中有一部分允许用户创建一堆自定义过滤器。

自定义过滤器会向该选择条件中的所有相册的用户返回一个计数。这些相册的ID然后存储在随机生成的散列/序列号表(例如albumSelect_20880f9c05d68a)

我这样做是因为我不想在字段中存储巨大的逗号分隔列表(真的愚蠢) - 我不喜欢发送一个值的数组到一个隐藏的领域,因为这只会增加数据吞吐量(可能一次成千上万的行)

在CodeIgniter中,我使用查询绑定来生成我的SQL查询,如下所示:

select * from artists where artistName = ? AND albumTitle = ? 

当我参数化查询时,查询会自动转义

$query = $this->db->query($sql,array("Singer","Album")); 

现在到了棘手的部分

如果我写我的查询看起来是这样的:

$sql = "select albumid from albums where albumid in (select albumid from albumSelect_?)"; 
$this->db->query($sql,array('20880f9c05d68a')); 

结果查询变为:

select `albumid` from `albums` where `albumid` in (select `albumid` from `albumSelect_'20880f9c05d68a'`) 

而且相当正确如此,但很显然,查询无效。

编辑:更多信息

查询可能是一个更大的查询的一部分,根据用户选择的标准是什么。例如

$sql = "select albumid from albums where albumid in(select albumid from tags where tag = ?) AND albumid in(select albumid from albumSelect_?)"; 

我只是想知道如果有办法得到这个工作,或者如果任何人都可以提出一个更好的选择..表名的级联显然是不选择。

在此先感谢!

戴夫

+0

如果您规范化了数据,则不需要执行此操作*或*存储逗号分隔的相册列表。这被称为“有许多通过”的关系。 – Xeoncross 2012-07-18 20:07:58

回答

1

转义机制仅适用于数据字符串,不适用于模式名称。换句话说,只适用于内容的表格,而不适用于其结构。因此,您必须自己将该字符串粘贴到查询中,或者避免以这种方式使用表格。查询模板的?不会帮助您。

如果将字符串粘贴到表名中,可以使用通常的PHP字符串连接机制。您应该额外确保您检查字符串是否适合严格的正则表达式,以避免SQL注入。确保你确实只粘贴一个你生成的格式的随机字符串,没有别的。

作为一种替代方案,您可以使用一个包含所有选择的大表,并使用附加列来保存识别哈希或其他一些合适的键以识别单个选项。这样,在正常操作期间,您不必修改数据库模式。我相信大多数开发人员,包括我在内,都宁愿通过程序代码来避免这种修改。良好的数据库设计适用于固定模式。

+0

嗨MvG,我决定按照你的建议去创建一张高大的桌子。这样做实际上更符合预期的工作流程,说实话,我不知道为什么我会想到以另一种方式来做这件事。谢谢你的帮助! – Dave 2012-07-20 21:09:17

0

像你想使用动态SQL的声音给我。您可能不得不走prepared statements的路径。有了它们,你可以在字符串上调用PREPARE,然后EXECUTE它。正常连接工作得很好。

这应该允许您将SQL构建为字符串并执行它。如果您将CodeIgniter的参数化与MySQL存储过程结合使用,则可以调用类似"CALL selectAlbums(?, ?)"的查询(假设selectAlbums是包含PREPARE的存储过程用于实际查询),它将返回该集合。

如果你想摆脱输出中的' s,通过CONCAT通道参数,这将产生一个正常的字符串。

+0

准备好的陈述不适用于这种事情。他们使用正常的语句语法,所以他们不会更容易地使用动态表名。准备好的语句只是通过缓存给定语句的执行计划来提高性能的一种方式,因此服务器已经知道如何计算给定类型的结果。 – MvG 2012-07-18 19:55:44

+1

不,这正是你可以用它们做的事情。甚至有一个例子在文档中使用了一个表名字符串变量。请阅读。你在谈论存储的例程。或者,也许是CodeIgniter'准备好的语句',它们是MySQL API准备好的语句,而不是集成在引擎中的动态SQL机制。这里有一个非常大的差异。 – Naltharial 2012-07-18 22:03:40

+0

好的,我的错。我记住了C API,并认为服务器端准备好的语句元素几乎可以做同样的事情。它们似乎在许多方面都有所作用,但使用字符串和服务器端的'CONCAT'开辟了新的途径。对不起,这里有噪音。我真的应该阅读文档,比我做的还多两个句子。 – MvG 2012-07-18 22:15:52