Perl:CGI和DBI模块的变量范围问题

Perl:CGI和DBI模块的变量范围问题

Perl: variable scope issue with CGI & DBI modules

我遇到了一个以前从未遇到过的变量范围问题。我正在使用Perl的CGI模块和对DBI的do()方法的调用。这是代码结构,简化了一点:

1
2
3
4
5
6
use DBI;
use CGI qw(:cgi-lib);
&ReadParse;
my $dbh = DBI->connect(...............);
my $test = $in{test};
$dbh->do(qq{INSERT INTO events VALUES (?,?,?)},undef,$in{test},"$in{test}",$test);

#1占位符变量的求值方式好像是未初始化的。其他两个占位符变量起作用。

问题:为什么%in哈希在do()的上下文中不可用,除非我将其包装在双引号中(#2占位符)或将值重新分配给新变量(#3占位符)?

我认为这与CGI模块的ReadParse()函数如何将范围分配给%in哈希有关,但是我不知道Perl的作用域是否足以理解为什么%in在顶级可用,而在我自己的工作范围内不可用()声明。

如果有人确实了解范围问题,是否有更好的方法来解决?用双引号将所有%in引用包装起来似乎有些混乱。为每个查询参数创建新变量是不现实的。

明确地说,我的问题是关于变量范围界定问题。我意识到,不建议使用ReadParse()使用CGI来获取查询参数。

我正在使用Perl 5.8.8,CGI 3.20和DBI 1.52。预先感谢任何阅读此书的人。

@Pi和@Bob,感谢您的建议。预先声明%in的范围无效(并且我始终使用strict)。结果与之前相同:在数据库中,col1为null,而cols 2和3设置为期望值。

供参考,这里是ReadParse函数(见下文)。这是CGI.pm的一部分的标准功能。以我的理解,我不是为了设置作用域而初始化哈希中的%(不是满足严格条件),因为在我看来该函数可以处理该问题:

1
2
3
4
5
6
7
8
9
10
11
sub ReadParse {
    local(*in);
    if (@_) {
      *in = $_[0];
    } else {
    my $pkg = caller();
      *in=*{"${pkg}::in"};
    }
    tie(%in,CGI);
    return scalar(keys %in);
}

我想我的问题是在do()上下文中获取%in哈希的最佳方法是什么?再次感谢!我希望这是为我的原始问题提供更多信息的正确方法。

@丹:我听说有关&ReadParse语法。我通常使用CGI :: ReadParse(),但在这种情况下,我认为最好坚持使用CGI.pm文档的确切方式。


它实际上并不像您在使用文档中所述的那样:
https://metacpan.org/pod/CGI#COMPATIBILITY-WITH-CGI-LIB.PL

如果必须使用它,那么CGI :: ReadParse();似乎更明智,语法也更简洁。虽然我看不到它在这种情况下有什么大的不同,但是那是一个绑定变量,所以谁知道该怎么做;)

您是否有特定原因无法使用更常见的$ cgi-> param('foo')语法?它稍微干净一点,并且以相当可预测的方式隐藏了您的命名空间。


我不知道出了什么问题,但是我可以告诉您一些不是的事情:

  • 这不是范围问题。如果不是,则$in{test}的所有实例都不起作用。
  • 这不是古老的&调用语法。 (这不是"正确",但在这种情况下是无害的。)

ReadParse是令人讨厌的代码。它修改符号表以在调用包中创建全局变量%in。更糟糕的是,它是一个绑定变量,因此访问它(理论上)可以执行任何操作。查看CGI.pm的源代码,FETCH方法仅调用params()方法来获取数据。我不知道为什么$dbh->do()中的提取不起作用。


use strict;。总是。

尝试声明

1
our %in;

看看是否有帮助。如果失败,则strict可能会产生更有用的错误。


从您给出的示例来看,这不是范围问题,或者所有参数都不起作用。

看起来DBI(或DBD,不确定在何处使用绑定参数)没有兑现领带魔术。
解决方法是像传递第二个和第三个参数一样,对传递给它的内容进行字符串化或复制。

使用SQLite和DBI 1.53进行的简单测试表明它可以正常工作:

1
2
3
$ perl -MDBI -we'sub TIEHASH { bless {} } sub FETCH {"42" } tie %x,"main" or die; my $dbh = DBI->connect("dbi:SQLite:dbname=dbfile","",""); $dbh->do("create table foo (bar char(80))"); $dbh->do("insert into foo values (?)", undef, $x{foo}); print"got:" . $dbh->selectrow_array("select bar from foo") ."
"; $dbh->do("drop table foo")'

got: 42

想要共享您正在使用的数据库吗?


您正在使用哪个版本的DBI?从DBI changelog看,似乎1.00之前的版本不支持attribute参数。我怀疑"未初始化的" $in{test}实际上是您要传递给$dbh->do()undef


那里的东西很破。 Perl的作用域相对简单,除非您做些愚蠢的事情,否则您不太可能会偶然发现类似的事情。如建议的那样,打开严格的编译指示(以及警告。实际上,无论如何您都应同时使用两者)。

在不能够看到%in是如何定义的情况下很难说出是怎么回事(这与看上去讨厌的ReadParse调用有关吗?为什么用前导&,btw调用它?该语法已被认为是无效的)并消失了很长时间)。我建议发布更多代码,以便我们了解发生了什么。


首先,这不在做的上下文/范围内。它仍然处于主要或全局范围内。除非以与Perl中的子例程或不同"类"相关的某种方式输入{},否则您不会离开上下文。在()内,您不会超出范围。

您提供给我们的样本是未初始化的哈希,并且正如Pi所建议的那样,使用strict肯定会阻止这些事件的发生。

您能给我们一个更具代表性的代码示例吗?您在哪里设置%IN以及如何设置?


根据DBI文档:当前,绑定绑定变量不起作用。

DBI的内幕非常复杂,不幸的是,经过一些回转才能有效地引起问题。我同意其他人所说的摆脱丑陋的cgi-lib风格代码的说法。如果没有很好的框架(去Catalyst),做CGI就很不愉快了,更不用说十年来已经过时的东西。


我刚刚从http://www.carcomplaints.com/test/test.pl.txt尝试了您的测试密码,它可以立即在我的计算机上运行,??没有问题。我得到了三个预期值。我没有将其作为CGI运行,而是使用:

1
2
3
...
use CGI qw/-debug/;
...

我在控制台上写了一个变量(test=test),并且您的脚本插入没有问题。

但是,如果您不进行此操作,则tt将插入一个空字符串和两个NULL。这是因为您将值插值到字符串中。这将创建一个值为$in{test}的字符串,该字符串当前为undefundef字符串化为一个空字符串,这是插入数据库的内容。


由于这开始看起来像是tie()问题,请尝试以下实验。将其另存为foo.pl并以perl foo.pl"x=1"身份运行

1
2
3
4
5
6
7
use CGI;

CGI::ReadParse();
p($in{x},"$in{x}");

sub p { my @a = @_; print"@a
"
}

它应该打印1 1。如果没有,我们就找到了罪魁祸首。


好的,试试这个:

1
2
3
use CGI;
my %in;
CGI::ReadParse(\%in);

这可能会有所帮助,因为它实际上使用的是您声明的变量,因此可以控制的范围(另外,它还会让您use strict而不出现其他可能使您感到困惑的麻烦)。


尝试这个

%in = ReadParse();

但我对此表示怀疑。您是否要获取查询参数或其他内容?


推荐阅读

    linux调用函数的命令?

    linux调用函数的命令?,系统,代码,策略,上调,时间,设计,通信,网络,设备,项目,

    linux外部命令调用?

    linux外部命令调用?,系统,软件,标准,命令,盘中,管理,外部,进程,程序,内存,lin

    linux怎么调用命令行?

    linux怎么调用命令行?,系统,地址,工具,工作,首页,终端,命令,密码,信息,情况,l

    linux变量释放命令?

    linux变量释放命令?,系统,环境,名称,工具,官网,简介,变量,环境变量,命令,内

    浏览器调用linux命令?

    浏览器调用linux命令?,系统,信息,人工智能,软件,数据,首次,地址,代码,咨询,

    py调用linux的命令?

    py调用linux的命令?,系统,代码,状态,环境,标准,工具,命令,文件,脚本,终端,lin

    浏览器调用linux命令?

    浏览器调用linux命令?,系统,信息,人工智能,软件,数据,首次,地址,代码,咨询,

    py调用linux的命令?

    py调用linux的命令?,系统,代码,状态,环境,标准,工具,命令,文件,脚本,终端,lin

    linux系统命令调用?

    linux系统命令调用?,系统,单位,工具,工作,管理,地址,权威,密码,电脑,信息,怎

    linux调用上一条命令?

    linux调用上一条命令?,系统,命令,一致,数字,名称,网上,电脑,目录,空格,终端,l

    linux命令行调用程序?

    linux命令行调用程序?,工具,环境,代码,初级,工程,系统,网上,服务,管理,发行,l

    linux调出变量的命令?

    linux调出变量的命令?,系统,工作,工具,信息,地址,代码,标准,名称,官网,命令,l

    linux使用命令的方法?

    linux使用命令的方法?,系统,信息,工具,标准,数据,命令,左下角,目录,文件夹,

    linux命令主机名变量?

    linux命令主机名变量?,系统,主机名,查询系统,命令,终端,编辑,提示符,根目

    脚本调用linux命令?

    脚本调用linux命令?,代码,系统,工作,底部,脚本,位置,环境,行用,官网,标准,typ

    调用函数命令linux?

    调用函数命令linux?,系统,管理,网络,通用,统一,观察,地址,代码,设备,地方,怎

    linux内核总调用命令?

    linux内核总调用命令?,工作,地址,系统,信息,管理,策略,命令,目录,时间,基础,

    linux编程调用命令?

    linux编程调用命令?,系统,标准,管理,工作,基础知识,情况,环境,设备,基础,首

    linux变量是一个命令?

    linux变量是一个命令?,系统,信息,变量,名称,官网,地址,环境,代码,地方,命令,$

    linux命令窗口调用?

    linux命令窗口调用?,系统,工具,首页,终端,命令,数据,盘中,代码,密码,快捷键,