Beat hat Recht: Wenn einmal decodieren nicht den Klartext rausgibt, ist das Encoding im QUERY_STRING falsch.
Und normalerweis wird uri_unescape nicht auf den ganzen Querystring angewandt sondern nur auf den Parameter:
my($k,$par) = split /=/, $ENV{QUERY_STRING};
$par =~ s/\+/ /g;
$par =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
#$par =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
print $par;
MfG