Во-первых, давайте посмотрим на утверждение, которое доставляет вам неприятности:
die "The specified user contains illegal characters!"
unless($user =~/^\w+$/);
Это еще один способ записи:
if ( $user !~ /^\w+$/ ) {
die "...";
}
Что означает шаблон?
^ the beginning of the string
\w+ one or more word characters
$ before an optional \n, and the end of the
string
Таким образом, код будет считать допустимыми строки имен пользователей, состоящие только из символов слова и, возможно, новой строки. Есть две проблемы с этим:
Во-первых, я сомневаюсь, что вы намеревались принимать строки с новой строкой. Исправить это легко: используйте \z
для однозначного обозначения конца строки, а не $
.
Во-вторых, \w
соответствует набору, значительно большему, чем просто [A-Z_a-z0-9]
. Без других переключателей он может соответствовать многим другим символам слова на разных языках. См. ** Символы слов в самых последних perlrecharclass
:
\w matches a single alphanumeric character (an alphabetic character, or a decimal digit) or a connecting punctuation character, such as an underscore ("_"). It does not match a whole word. To match a whole word, use \w+ . This isn't the same thing as matching an English word, but in the ASCII range it is the same as a string of Perl-identifier characters.
If the /a modifier is in effect ...
\w matches the 63 characters [a-zA-Z0-9_].
otherwise ...
For code points above 255 ...
\w matches the same as \p{Word} matches in this range. That is, it matches Thai letters, Greek letters, etc. This includes connector punctuation (like the underscore) which connect two words together, or diacritics, such as a COMBINING TILDE and the modifier letters, which are generally used to add auxiliary markings to letters.
For code points below 256 ...
if locale rules are in effect ...
\w matches the platform's native underscore character plus whatever the locale considers to be alphanumeric.
if Unicode rules are in effect or if on an EBCDIC platform ...
\w matches exactly what \p{Word} matches.
otherwise ...
\w matches [a-zA-Z0-9_].
Таким образом, до тех пор, пока 5.14 не получит более широкое признание, безопаснее всего явно указать [a-z_A-Z0-9]
, если это единственные символы, которые вы хотите сопоставить.
$user=~/^\w+;\w$/
Учитывая вышесказанное, теперь должно быть ясно, что
$user =~ /^\w+;\w$/
будет соответствовать только вводу, содержащему символы слова, a
точка с запятой, завершающий символ слова и, возможно, символ новой строки.
Что касается вашего кода,
#!/usr/bin/perl
use CGI;
use CGI::Carp qw(fatalsToBrowser);
$q = new CGI;
Во-первых, вам не хватает
use strict;
use warnings;
Эти прагмы не необязательны, если вы хотите спасти себя и, возможно, остальную часть
В мире одни головные боли.
Во-вторых, use CGI::Carp qw(fatalsToBrowser);
следует использовать только как
кратковременное сцепление, если у вас нет доступа к журналам веб-сервера.
Третий,
$q = new CGI;
должно быть
my $q = CGI->new;
new CGI
называется косвенной нотацией объекта и оставляет вас во власти
perl
относительно того, что в итоге делает ваш код. CGI->new
однозначно призывает
new
метод, предоставляемый CGI
. Кроме того, я ненавижу $q
или $query
как
имена переменных, содержащих CGI
объектов. Просто $cgi
больше
осмысленный.
Наконец, глядя на:
print $q->header,
$q->start_html('Finger User'),
$q->h1('Finger User'),
print "<pre>";
Итак, вы печатаете HTML, используя методы генерации HTML, предоставляемые CGI
а некоторые вручную. Этот стиль мешанины и некоторые из громоздких запутанных
беспорядок, заканчивающийся тем, что вставляешь код, является хорошей причиной, чтобы избежать использования HTML
методы генерации, предоставляемые CGI
.
Переключитесь вместо CGI :: Simple и
используйте шаблонный пакет, такой как
HTML :: Template для разделения кода
из содержимого HTML. Что-то вроде следующего не проверено
скрипт должен работать. Имейте в виду, что вы всегда можете проверить это, используя один
из двух режимов отладки, предоставляемых CGI::Simple
:
<code>#!/usr/bin/env perl
use strict;
use warnings;
use CGI::Simple;
use HTML::Template;
run();
sub run {
my $cgi = CGI::Simple->new;
my $tmpl = HTML::Template->new(filehandle => \*DATA);
my $user = $cgi->param('finger_user');
unless (defined $user) {
show_form($cgi, $tmpl);
return;
}
if (($user) = ($user =~ /^([A-Z_a-z0-9]{1,40})\z/)) {
show_output($cgi, $tmpl, $user);
}
else {
show_error($cgi, $tmpl, "Invalid user name");
}
return;
}
sub show_form {
my ($cgi, $tmpl) = @_;
$tmpl->param(FORM => 1);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
sub show_error {
my ($cgi, $tmpl, $msg) = @_;
$tmpl->param(ERRORMSG => $msg);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
sub show_output {
my ($cgi, $tmpl, $user) = @_;
$tmpl->param(
USER => $user,
OUTPUT => scalar `finger -s $user`,
);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
__DATA__
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>finger
<TMPL_IF USER>
<TMPL_VAR USER>
<TMPL_ELSE>
a user
</TMPL_IF>
on our system</title>
</head>
<body>
<TMPL_IF ERRORMSG>
<p syle="color:#e11"><TMPL_VAR ERRORMSG></p>
</TMPL_IF>
<TMPL_IF OUTPUT>
<h1>finger <TMPL_VAR USER></h1>
<pre><TMPL_VAR OUTPUT>
</ TMPL_if>
</ TMPL_if>