X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/kivitendo-erp.git/blobdiff_plain/91ab1ef646193de9359076a876a33a74d7691145..de998cce754a73341988441034e2649f3ded6c54:/SL/Form.pm diff --git a/SL/Form.pm b/SL/Form.pm index f43578bb6..4c630f119 100644 --- a/SL/Form.pm +++ b/SL/Form.pm @@ -38,16 +38,21 @@ package Form; use Data::Dumper; -use Cwd; -use Template; -use SL::Template; +use CGI; use CGI::Ajax; +use Cwd; +use List::Util qw(min max); +use SL::Auth; +use SL::Auth::DB; +use SL::Auth::LDAP; +use SL::AM; +use SL::Common; use SL::DBUtils; use SL::Mailer; use SL::Menu; +use SL::Template; use SL::User; -use SL::Common; -use CGI; +use Template; use List::Util qw(max min sum); my $standard_dbh; @@ -59,36 +64,71 @@ sub DESTROY { } } +sub _store_value { + $main::lxdebug->enter_sub(2); + + my $self = shift; + my $key = shift; + my $value = shift; + + my $curr = $self; + + while ($key =~ /\[\+?\]\.|\./) { + substr($key, 0, $+[0]) = ''; + + if ($& eq '.') { + $curr->{$`} ||= { }; + $curr = $curr->{$`}; + + } else { + $curr->{$`} ||= [ ]; + if (!scalar @{ $curr->{$`} } || $& eq '[+].') { + push @{ $curr->{$`} }, { }; + } + + $curr = $curr->{$`}->[-1]; + } + } + + $curr->{$key} = $value; + + $main::lxdebug->leave_sub(2); + + return \$curr->{$key}; +} + sub _input_to_hash { $main::lxdebug->enter_sub(2); - my $input = $_[0]; - my %in = (); + my $self = shift; + my $input = shift; + my @pairs = split(/&/, $input); foreach (@pairs) { - my ($name, $value) = split(/=/, $_, 2); - $in{$name} = unescape(undef, $value); + my ($key, $value) = split(/=/, $_, 2); + $self->_store_value($self->unescape($key), $self->unescape($value)); } $main::lxdebug->leave_sub(2); - - return %in; } sub _request_to_hash { $main::lxdebug->enter_sub(2); - my ($input) = @_; + my $self = shift; + my $input = shift; if (!$ENV{'CONTENT_TYPE'} || ($ENV{'CONTENT_TYPE'} !~ /multipart\/form-data\s*;\s*boundary\s*=\s*(.+)$/)) { + + $self->_input_to_hash($input); + $main::lxdebug->leave_sub(2); - return _input_to_hash($input); + return; } - my ($name, $filename, $headers_done, $content_type, $boundary_found, $need_cr); - my %params; + my ($name, $filename, $headers_done, $content_type, $boundary_found, $need_cr, $previous); my $boundary = '--' . $1; @@ -96,9 +136,9 @@ sub _request_to_hash { last if (($line eq "${boundary}--") || ($line eq "${boundary}--\r")); if (($line eq $boundary) || ($line eq "$boundary\r")) { - $params{$name} =~ s|\r?\n$|| if $name; + ${ $previous } =~ s|\r?\n$|| if $previous; - undef $name; + undef $previous; undef $filename; $headers_done = 0; @@ -130,8 +170,8 @@ sub _request_to_hash { substr $line, $-[0], $+[0] - $-[0], ""; } - $params{$name} = ""; - $params{FILENAME} = $filename if ($filename); + $previous = $self->_store_value($name, ''); + $self->{FILENAME} = $filename if ($filename); next; } @@ -143,15 +183,14 @@ sub _request_to_hash { next; } - next unless $name; + next unless $previous; - $params{$name} .= "${line}\n"; + ${ $previous } .= "${line}\n"; } - $params{$name} =~ s|\r?\n$|| if $name; + ${ $previous } =~ s|\r?\n$|| if $previous; $main::lxdebug->leave_sub(2); - return %params; } sub new { @@ -176,17 +215,86 @@ sub new { $_ = $ARGV[0]; } - my %parameters = _request_to_hash($_); - map({ $self->{$_} = $parameters{$_}; } keys(%parameters)); + bless $self, $type; + + $self->_request_to_hash($_); - $self->{action} = lc $self->{action}; - $self->{action} =~ s/( |-|,|\#)/_/g; + $self->{action} = lc $self->{action}; + $self->{action} =~ s/( |-|,|\#)/_/g; - $self->{version} = "2.4.3"; + $self->{version} = "2.4.3"; $main::lxdebug->leave_sub(); - bless $self, $type; + return $self; +} + +sub _flatten_variables_rec { + $main::lxdebug->enter_sub(2); + + my $self = shift; + my $curr = shift; + my $prefix = shift; + my $key = shift; + + my @result; + + if ('' eq ref $curr->{$key}) { + @result = ({ 'key' => $prefix . $key, 'value' => $curr->{$key} }); + + } elsif ('HASH' eq ref $curr->{$key}) { + foreach my $hash_key (sort keys %{ $curr->{$key} }) { + push @result, $self->_flatten_variables_rec($curr->{$key}, $prefix . $key . '.', $hash_key); + } + + } else { + foreach my $idx (0 .. scalar @{ $curr->{$key} } - 1) { + my $first_array_entry = 1; + + foreach my $hash_key (sort keys %{ $curr->{$key}->[$idx] }) { + push @result, $self->_flatten_variables_rec($curr->{$key}->[$idx], $prefix . $key . ($first_array_entry ? '[+].' : '[].'), $hash_key); + $first_array_entry = 0; + } + } + } + + $main::lxdebug->leave_sub(2); + + return @result; +} + +sub flatten_variables { + $main::lxdebug->enter_sub(2); + + my $self = shift; + my @keys = @_; + + my @variables; + + foreach (@keys) { + push @variables, $self->_flatten_variables_rec($self, '', $_); + } + + $main::lxdebug->leave_sub(2); + + return @variables; +} + +sub flatten_standard_variables { + $main::lxdebug->enter_sub(2); + + my $self = shift; + my %skip_keys = map { $_ => 1 } (qw(login password header stylesheet titlebar version), @_); + + my @variables; + + foreach (grep { ! $skip_keys{$_} } keys %{ $self }) { + push @variables, $self->_flatten_variables_rec($self, '', $_); + } + + $main::lxdebug->leave_sub(2); + + return @variables; } sub debug { @@ -201,6 +309,24 @@ sub debug { $main::lxdebug->leave_sub(); } +sub dumper { + $main::lxdebug->enter_sub(2); + + my $self = shift; + my $password = $self->{password}; + + $self->{password} = 'X' x 8; + + local $Data::Dumper::Sortkeys = 1; + my $output = Dumper($self); + + $self->{password} = $password; + + $main::lxdebug->leave_sub(2); + + return $output; +} + sub escape { $main::lxdebug->enter_sub(2); @@ -256,10 +382,11 @@ sub quote_html { my ($self, $str) = @_; my %replace = - ('order' => ['"', '<', '>'], - '<' => '<', - '>' => '>', - '"' => '"', + ('order' => ['&', '"', '<', '>'], + '<' => '<', + '>' => '>', + '"' => '"', + '&' => '&', ); map({ $str =~ s/$_/$replace{$_}/g; } @{ $replace{"order"} }); @@ -269,6 +396,33 @@ sub quote_html { return $str; } +sub unquote_html { + $main::lxdebug->enter_sub(2); + + my ($self, $str) = @_; + + my %replace = + ('ä' => 'ä', + 'ö' => 'ö', + 'ü' => 'ü', + 'Ä' => 'Ä', + 'Ö' => 'Ö', + 'Ü' => 'Ü', + 'ß' => 'ß', + '>' => '>', + '<' => '<', + '"' => '"', + ); + + map { $str =~ s/\Q$_\E/$replace{$_}/g; } keys %replace; + $str =~ s/\&/\&/g; + + $main::lxdebug->leave_sub(2); + + return $str; +} + + sub hide_form { my $self = shift; @@ -336,13 +490,16 @@ sub info { # can be capped with maxrows sub numtextrows { $main::lxdebug->enter_sub(); - my ($self, $str, $cols, $maxrows) = @_; + my ($self, $str, $cols, $maxrows, $minrows) = @_; + + $minrows ||= 1; my $rows = sum map { int((length() - 2) / $cols) + 1 } split /\r/, $str; $maxrows ||= $rows; $main::lxdebug->leave_sub(); - return min $rows, $maxrows; + + return max(min($rows, $maxrows), $minrows); } sub dberror { @@ -360,9 +517,14 @@ sub isblank { my ($self, $name, $msg) = @_; - if ($self->{$name} =~ /^\s*$/) { - $self->error($msg); + my $curr = $self; + foreach my $part (split '.', $name) { + if (!$curr->{$part} || ($curr->{$part} =~ /^\s*$/)) { + $self->error($msg); + } + $curr = $curr->{$part}; } + $main::lxdebug->leave_sub(); } @@ -376,6 +538,9 @@ sub header { return; } + my $cgi = $main::cgi; + $cgi ||= CGI->new(''); + my ($stylesheet, $favicon); if ($ENV{HTTP_USER_AGENT}) { @@ -436,9 +601,32 @@ sub header { foreach $item (@ { $self->{AJAX} }) { $ajax .= $item->show_javascript(); } - print qq|Content-Type: text/html; charset=${db_charset}; -${doctype} + my $base_path; + + if ($ENV{HTTP_X_FORWARDED_FOR}) { + $base_path = $ENV{HTTP_REFERER}; + $base_path =~ s|^.*?://.*?/|/|; + } else { + $base_path = $ENV{REQUEST_URI}; + } + $base_path =~ s|[^/]+$||; + $base_path =~ s|/$||; + + my $session_cookie; + if (defined $main::auth) { + my $session_cookie_value = $main::auth->get_session_id(); + $session_cookie_value ||= 'NO_SESSION'; + + $session_cookie = $cgi->cookie('-name' => $main::auth->get_session_cookie_name(), + '-value' => $session_cookie_value, + '-path' => $base_path); + } + + print $cgi->header('-type' => 'text/html', + '-charset' => $db_charset, + '-cookie' => $session_cookie); + print qq|${doctype}