【问题标题】:Perl program reads POST string length but won't read stringPerl 程序读取 POST 字符串长度但不会读取字符串
【发布时间】:2020-06-16 05:30:51
【问题描述】:

我最近从 IIS 主机迁移到 Apache 主机,但我的 perl 脚本不再工作。我退回到一个简单的固定字符串 POST。 perl 脚本将从 $ENV{\'CONTENT_LENGTH\'} 读取正确的值,但不会读取字符串值。

HTML 文件是

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Mail Test</title>
        <meta charset="utf-8">
        <meta name="description" content="This is a simple mail test. So far the mailtest.pl program won't even read any input.">
        <meta name="keywords" content="">
    </head>
    <body>
        <h1>
            Email Us
        </h1>
        <!-- Starting out with a simple two value POST submit -->
        <form id="email_form" target="_blank" method="POST" action="cgi-bin/mailtest.pl">
            <input type="hidden" name="mytest" value="foo" >
            <input type="hidden" name="mytest2" value="bar" >
            <input type="submit" id="email_submit" value="Send Email" >
            <input type="reset" />
        </form>
    </body>
</html>

perl文件,包括一堆调试语句是

#!/usr/bin/perl

use strict;
use warnings;

use CGI;
print CGI::header();
# If you don't output a header, apache will not work.


print "<DOCTYPE! html>\n<html lang=\"en\">\n";
print "<header>\n<title>\"Simple POST Test Result\"</title>\n";
print "<meta charset=\"utf-8\">\n</header>\n<body>\n";
print "<h1>Simple POST test.</h1>\n";

my $buffer = ''; # Raw POST data

print "<p>(1) Going to get the data.</p>\n";

&get_data;

print "<p>(8) Returned from get_data.</p>";
print "<p> I will only get this far if everything works</p>\n</body>\n</html>";

sub get_data {
 print '<p>(2) Getting the data.</p>';
 if ($ENV{'REQUEST_METHOD'} eq 'POST') {
   print "<p>(3) Verified: It's a POST request.</p>";
   print ("<p>(4) The length of the post data string as reported in ", '$ENV{\'CONTENT_LENGTH\'}', "is ", $ENV{'CONTENT_LENGTH'}, "</p>");
   print "<p>(5) The data should be \"mytest=foo&mytest2=bar\" so the length should be 22.";
   # Get the input
   print "<p>(6) If the POST data is read, it will be printed on the next line</p>";
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'}) or die "POST data could not be read, why? Stopped ";
   print ("The buffer contained ", $buffer);
   print '<p>(7) Got the data.</p>';
  }
 else {
  print "<p3b> It wasn't a POST request so I will die soon.";
  die "The request method must be POST for this application. Stopped ";
  }

}

html响应是

简单的 POST 测试。 (1) 去获取数据。

(2) 获取数据。

(3) 已验证:这是一个 POST 请求。

(4) $ENV{'CONTENT_LENGTH'}报告的post数据字符串长度为22

(5) 数据应为“mytest=foo&mytest2=bar”,因此长度应为 22。

(6)如果POST数据被读取,则打印在下一行

错误日志只包含 die 语句:

AH01215:无法读取 POST 数据,为什么?停在 mailtest.pl 第 33 行。:/home/fffwweb/fffw.org/cgi-bin/mailtest.pl,referer:https://fffw.org/mailtest.html

所有目录中的 .htaccess 文件(当然这是矫枉过正)是:

RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
AddHandler cgi-script .pl
Options +ExecCGI
AddType application/pdf pdf

我怀疑我的问题很明显,但我花了三天时间试图找到它但没有任何结果,包括与网络托管技术支持聊天。

任何建议表示赞赏。 谢谢, 兰迪T

【问题讨论】:

  • read 有多种返回可能性。如果没有要读取的内容,它可能返回 0,如果有错误,它可能返回 undef,在后一种情况下,$! 也被设置;这两个都将失败or。所以你想检查返回值属于哪一个,如果返回值是 undef,则在你的 die 中包含$!
  • 忘了说文件权限是mailtest.html 644, .htaccess 644, cgi-bin/mailtest.pl 755, cgi-bin/.htaccess 755,
  • 你为什么要从 STDIN 阅读?这就是 CGI 模块为您所做的,即使这样也被认为有些过时了。
  • 我想我需要再看看 CGI。我对它不是很熟悉。在我迁移之前我不需要它。我从几年前开发的脚本开始,我想我没有跟上。什么取代了CGI?我得检查一下主机是否在那里。
  • 使用 CGI 读取 POST 参数是通过 param 方法完成的(但请确保阅读那里的警告!并且您可能或许多没有足够新的版本来支持 multi_param)。有关现在的工作方式,请参阅blogs.perl.org/users/grinnz/2018/11/modern-perl-cgi.htmlCGI::Alternatives

标签: html perl post


【解决方案1】:

嗯,我觉得阅读您的代码太难了。我冒昧地清理了它。

请看看你是否觉得下面的样式更合适

#!/usr/bin/perl

use strict;
use warnings;

use CGI;
print CGI::header();
# If you don't output a header, apache will not work.

my $buffer = ''; # Raw POST data

print 
'<DOCTYPE! html>
<html lang="en">
<header>
    <title>"Simple POST Test Result"</title>
    <meta charset="utf-8">
</header>
<body>
    <h1>Simple POST test.</h1>
    <p>(1) Going to get the data.</p>
';

&get_data;

print '
    <p>(8) Returned from get_data.</p>
    <p> I will only get this far if everything works</p>
</body>
</html>
';

sub get_data {
 print '<p>(2) Getting the data.</p>';
 if ($ENV{'REQUEST_METHOD'} eq 'POST') {
   read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'})
        or die 'POST data could not be read, why? Stopped';

   print '
        <p>(3) Verified: It\'s a POST request.</p>
        <p>(4) The length of the post data string as reported in $ENV{CONTENT_LENGTH} is '
        . $ENV{'CONTENT_LENGTH'} . '
        </p>
        <p>(5) The data should be "mytest=foo&mytest2=bar" so the length should be 22.
        <p>(6) If the POST data is read, it will be printed on the next line</p>
        The buffer contained '
        . $buffer . '
        <p>(7) Got the data.</p>
        ';
  }
 else {
      print '<p3b> It wasn\'t a POST request so I will die soon.';
      die 'The request method must be POST for this application. Stopped';
  }
}

另外请看下面webpage

注意:你无缘无故地过度使用双引号,它们旨在用于变量的插值。无故使用双引号会浪费 CPU 周期(perl 仍然会在此类字符串中查找变量以将其名称替换为它们的值)。

【讨论】:

    【解决方案2】:

    如果你注释掉这两行:

    # use CGI;
    # print CGI::header();
    

    并用手动编写的标题替换它们:

    # Note: Fixed line endings
    print "Content-type: text/html\015\012\015\012";
    

    然后它将按预期工作。但我不建议这样做。我推荐使用 CGI.pm,因为它期望被使用 - 并使用它的机制来读取输入参数。

    问题是 CGI.pm 为您做的太多了。只需加载它,它就会读取您的所有参数——包括从STDIN 读取所有数据。由于 CGI.pm 已从 STDIN 读取数据,因此没有更多数据可供您的代码读取。 CONTENT_LENGTH 环境变量仍设置为其原始值,但您不能再期望在文件句柄上找到那么多数据。

    解决方案是不要尝试自己重新读取数据。而是使用param() 方法来获取您输入的值。

    my $mytest  = CGI::param('mytest');
    my $mytest2 = CGI::param('mytest2');
    

    【讨论】:

    • 您手动编写的标题也是错误的;它必须以两个 CRLF 结尾,而不仅仅是两个 LF,这与操作系统无关。
    • @Grinnz:我认为“应该”而不是“必须”。但是 Postel 定律适用,所以我已经修复了它:-)
    猜你喜欢
    • 2016-04-19
    • 2011-10-12
    • 2013-01-23
    • 2011-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-24
    相关资源
    最近更新 更多