【问题标题】:special Characters in PerlPerl 中的特殊字符
【发布时间】:2011-03-10 09:34:25
【问题描述】:

我正在创建一个 CGI 表单来更新 Sybase 存储过程。

qq {execute procedure test(123,45,date,'$note');}; $note 变量是从包含故障单日志信息的文本框中获得的信息。因此,输入此类信息的人可以并且很可能会使用特殊字符,例如 '|"{} 等。我很想知道是否有办法通过变量 $note 将这些信息输入数据库。

我的大部分研究都产生了 DBI->quote() 函数,但它们似乎不起作用,而且我不确定它们的相关性,因为这是一个存储过程。

现在我正在尝试以下方法:

use DBI; <br>$livedb = DBI-&gt;connect("dbi:Sybase:server=test","admin","pass") || die "could not connect to live DB, $DBI::errstr"; <br>$note = "testing special characters:"; <br>$livedb-&gt;do(qq {execute procedure jinsert(5304905,65,getdate,?);},undef,(param('$note')));

我收到以下错误:

Undefined subroutine &amp;main::param called at test.cgi line 11.

当我使用以下方法时,如果$note 中存在',则代码将失败:

$qy = $livedb->prepare($note);
$qy->execute($test) || die "could not journal: $DBI::errstr";
$qy->finish();

【问题讨论】:

  • 能否包含用于与数据库句柄对话的代码(即 DBI 调用)。
  • 现在我正在尝试以下操作: $livedb = DBI-&gt;connect("dbi:Sybase:server=test","admin","pass") || die "无法连接到实时数据库,$DBI::errstr"; $note = "测试特殊字符:"; $livedb-&gt;do(qq {执行过程 jinsert(5304905,65,getdate,?);},undef,(param('$note'))); 我得到以下错误:未定义在 test.cgi 第 11 行调用子例程 &amp;main::param。
  • param 是来自 CGI 包的方法。您必须“使用”它并实例化。
  • @mose:请将该代码编辑到您的问题中,以便您可以使用正确的格式等。

标签: perl cgi special-characters quotes


【解决方案1】:

首先,直接回答您的问题:DBI->quote() 确实是您的朋友 :-) 它以正确的方式为您使用的数据库的语言在字符串周围加上引号(这总是SELECT/UPDATE/INSERT/DELETE 查询与存储过程相同,因为后者通常由前者的组合组成!)。

例如,假设$dbh 已设置为您到数据库的 DBI 连接,那么

my $string = "Here's a string that needs \"quoting\"!";

print $dbh->quote($string);

打印类似:

'Here''s a string that needs "quoting"!'

注意方法:

  • 它是'Here's 中的两倍
  • 它在整个字符串周围加上'' 引号。

它打印的确切字符串取决于您的数据库 - 有些使用略有不同的约定。

不过……

看看你在做什么,你实际上不应该做任何引用:让 DBI 为你做所有的工作,就像这样:

$livedb->do(qq {execute procedure jinsert(5304905,65,getdate,?);}, undef, $note);

DBI 代码知道要执行什么引用才能将 ? 替换为 $note

【讨论】:

  • DBI->quote 并不是真正的首选方法。代替原始示例代码中经典的 SQL 注入漏洞,更好的方法是使用占位符('?')并将值作为额外参数传递给 $sth->execute()。
  • @Grant McLean: DBI->quote and "?"占位符是等价的,并且都解决了 SQL 注入问题——事实上,一个是根据另一个来实现的!当然,“?”占位符在许多情况下更整洁,但有时(例如,以编程方式构建复杂查询时)提前明确引用更有意义,而不是必须跟踪“?”的序列。整个查询的构造参数。从问题中不清楚正在生成的字符串是否构成要执行的更大序列的一部分,因此显式引用并非完全不合理......
  • 我看到的不仅仅是单引号,$note 字段与本论坛中的“添加评论”字段的用途相同。我只是在寻找一种方法将 $note 中的所有字符传递给 qq {execute procedure test(123,45,date,'$note');}; 并插入他们到数据库。
  • @mose:是的,DBI->quote() 会为你做这件事,“?”也一样。格兰特提到的方法。如果以后有时间,我会更新我的答案以描述这两种方法以及使用每种方法的原因。
  • @mose:如果您看到了,那么问题一定出在代码的其他地方...您确定 (1) 变量 $note 具有您期望的值吗(即$ 是否可能已被事先解释),以及(2)值在从数据库中读出后没有被破坏(即上面的工作正常,但是从数据库中检索它的代码被打破)?从您所说的来看,这听起来像是在某处对eval 进行了额外的调用(或者结果被不带引号地传递给了shell脚本或类似的东西)...但是上面的代码是正确的,我保证:-)
【解决方案2】:

我终于弄清楚了问题所在。我可以使用q {$note}; 转义 perl 中的所有特殊字符。 dbh-&gt;quote 在这里不适用,因为它调用了存储过程,而且问题不仅仅是匹配 qoutes。单个 qoutes 必须转义到存储过程。 q 和 sed 的组合修复了它:

use DBI;
$livedb = DBI->connect("dbi:Sybase:server=test","admin","pass") || die "could not connect to live DB, $DBI::errstr";
$note = q {testing special characters:''''''''''''''!@#$%^%^&*()};
$note =~ s/'/\\'/g;
$livedb->do(qq {execute procedure jinsert(5304905,65,getdate,?);},undef,(param('$note')))

所以简而言之,当调用像这样的存储过程时,单个 qoutes 需要转义两次(一次在 perl 中,第二种类型用于存储过程)。

【讨论】:

  • dbh->quote() is 适用于此,因为您正在使用它!正如我在回答中所说,这就是“?”您正在使用的机制有效。这与匹配引号无关
  • dbh->qoute() 不会在存储过程中转义 qoutes。如果我删除 $note =~ s/'/\\'/g;它坏了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 2021-07-11
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多