PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : $ENV{"REMOTE_ADDR"} klappt in Zählerscript nicht



Eagle
20-09-2006, 09:47
Hallo,

ich habe hier ein kleines Problem auf einem Webserver, wo der Benutzer Plattenplatz hat.
Mein Script, das ich mir mal zusammengebastelt habe und auf einem Server funktioniert, erzeugt einen graphischen Zähler auf der Website. Dabei sucht es im selben Verzeichnis nach einer Datei, in der eine IP drinsteht und vergleicht sie mit der gemeldeten Remote-IP des Browsers.
Sind die beiden verschieden, wird die Zahl in count.dat hochgezählt und als Bilddatei generiert an den Browser übergeben. Die IP wird gemerkt in visitor.dat, die neue Zahl in count.dat abgespeichert. Im Falle gleicher IPs findet keine Zählung statt, aber die Bildausgabe.

Hier mein Script zum Nachvollziehen:


#!/usr/bin/perl -w

# *** SETTINGS ***

use CGI qw(param);
use GD;

$width = "14"; # Width of the image
$height = "18"; # Height of the image
$digits_dir = "../images/digits"; # Relative path to the CGI-program
$ending = "gif"; # png, gif, jpg, change it also in the HTTP header

$lock = "1"; # Lock the counterfile at the moment of access, "1"=looked, "0"=unlooked

# *** PROGRAM ***

my $query = param("visible");

$host=$ENV{"REMOTE_ADDR"};

open (VISITOR, "<visitor.dat"),
$currentvisitor = <VISITOR>;
close (VISITOR);

open (COUNT, "<count.dat") || die "Can't Open Count Data File: $!\n";
if ($lock eq "1") {
flock COUNT, 2;
}
$counter =<COUNT>;
close (COUNT);

if ($host ne "$currentvisitor") {

$counter++;

open (WRITE, ">count.dat") || die "Can't Write Count Data File: $!\n";
print WRITE "$counter";
close (WRITE);

open (CURRENT, ">visitor.dat");
print CURRENT "$host";
close (CURRENT);

}

$length = length($counter);
@digit = split(//, $counter);

# Create a new Image

if ($query eq "yes") {
$image_width = $length * $width + 32 + $width;
# Width = length * width of single image + 2*border + point

$counterimage = new GD::Image($image_width,$height);

$a = 0;
while ($a < $length) {
open (GIF, "$digits_dir/$digit[$a]\.$ending");
$image[$a] = newFromGif GD::Image(GIF);
close (GIF);
$a++;
}
open (LEFT, "$digits_dir/left.gif");
$leftborder = newFromGif GD::Image(LEFT);
close (LEFT);

open (RIGHT, "$digits_dir/right.gif");
$rightborder = newFromGif GD::Image(RIGHT);
close (RIGHT);
open (POINT, "$digits_dir/point.gif");
$point = newFromGif GD::Image(POINT);
close (POINT);


$counterimage->copy($leftborder,0,0,0,0,$width,$height);
$b = 0;
$position = 5;
while ($b < $length) {
$counterimage->copy($image[$b],$position,0,0,0,$width,$height);
$position = $position + $width;
$b++;
}
$counterimage->copy($point,$position,0,0,0,$width,$height);
$position = $position + $width;
$counterimage->copy($rightborder,$position,0,0,0,$width,$height);

# print HTTP header for GIF
print "Content-type: image/gif\n\n";

# print the image
print $counterimage->gif;
}
# end of program
exit;

Mein Problem ist jetzt beim Aufruf von

./counter.cgi
auf dem Server im SSH, kommen folgende Fehlermeldungen:


Use of uninitialized value in string ne at ./counter.cgi line 38.
Use of uninitialized value in string at ./counter.cgi line 47.
Use of uninitialized value in string eq at ./counter.cgi line 57.

Line 38 will er die Remote-IP einlesen, aber irgenwie klappt das nicht. Warum verstehe ich nicht. Ihr? Und Line 57 habe ich auch nicht verstanden.

Ich meine, der kann

$host=$ENV{"REMOTE_ADDR"};
nicht ausführen. Und da komme ich nicht weiter, vor allem weil dasselbe Script auf einem anderen Rechner super läuft.
Na ja, und irgendwie will die Inhaberin unbedingt Ihren Zähler mit ihren eigenen Ziffern.

Kann mir hier jemand den Fehler zeigen?

Grüsse und vielen Dank!

Ohne Wachs!

Eagle

reneeb
25-09-2006, 14:17
Lies Dir mal http://wiki.perl-community.de/bin/view/Wissensbasis/UseStrict durch und passe das Skript dementsprechend an. Du solltest auch Fehlerabfragen einabuen.

Z.B.:

open(DATEI,"<",$dateiname) or die $!

Wichtig ist der or die-Teil, denn damit bekommst Du eine Fehlermeldung wenn was schief läuft. Bist Du Dir denn sicher, dass die entsprechenden Dateien auf dem Server existieren und dass Du darauf leserechte hast?

Wenn Du das gemacht hast, poste mal die Fehlermeldung!

Eagle
26-09-2006, 09:21
Guten Morgen und vielen Dank,

für die Tipps. "use strict;" hat zumindest einmal soweit geholfen, dass ich die Fehler mit der Variablendefinition kapiert und mit "my" behoben habe.

Was ich nicht ganz verstehe ist, dass das ursprüngliche Script (s. oben) auf einer anderen Maschine richtig läuft. Auf der neuen Maschine ist Linux mit Perl v5.8.6 drauf.

Zurück zu meinem Problem, dass ich den Fehler finde. Dazu noch einmal das modifizierte Script:


#!/usr/bin/perl -w
# *** SETTINGS ***

use strict;
use warnings;
use CGI qw(param);
use GD;

my $width = "14"; # Width of the image
my $height = "18"; # Height of the image
my $digits_dir = "../images/digits"; # Relative path to the CGI-program
my $ending = "gif"; # png, gif, jpg, change it also in the HTTP header

my $lock = "1"; # Lock the counterfile at the moment of access, "1"=looked, "0"=unlooked
my $counter = "0";
my $currentvisitor = "0";
my $hosts = "0";
my $length = "0";
my $image = "0";
my $image_width = "0";
my $leftborder = "0";
my $rightborder = "0";
my $counterimage = "0";
my $point = "0";
my $position = "0";
my @image = "0";
my @digit = "0";


# *** PROGRAM ***

my $query = param("visible");

$hosts = $ENV{'REMOTE_ADDR'};

open (VISITOR, "<", "visitor.dat"),
$currentvisitor = <VISITOR>;
close (VISITOR);

open (COUNT, "<", "count.dat") || die "Can't Open Count Data File: $!\n";
if ($lock eq "1") {
flock COUNT, 2;
}
$counter =<COUNT>;
close (COUNT);

if ($hosts ne $currentvisitor) {

$counter++;

open (WRITE, ">","count.dat") || die "Can't Write Count Data File: $!\n";
print WRITE "$counter";
close (WRITE);

open (CURRENT, ">","visitor.dat");
print CURRENT "$hosts";
close (CURRENT);

}

#open (DATEI,"<",$hosts) or die $!;

$length = length($counter);
@digit = split(//, $counter);

# Create a new Image

if ($query eq "yes") {
$image_width = $length * $width + 32 + $width;
# Width = length * width of single image + 2*border + point
$counterimage = new GD::Image($image_width,$height);

my $a = 0;
while ($a < $length) {
open (GIF, "$digits_dir/$digit[$a]\.$ending");
$image[$a] = newFromGif GD::Image(GIF);
close (GIF);
$a++;
}
open (LEFT, "$digits_dir/left.gif");
$leftborder = newFromGif GD::Image(LEFT);
close (LEFT);

open (RIGHT, "$digits_dir/right.gif");
$rightborder = newFromGif GD::Image(RIGHT);
close (RIGHT);
open (POINT, "$digits_dir/point.gif");
$point = newFromGif GD::Image(POINT);
close (POINT);


$counterimage->copy($leftborder,0,0,0,0,$width,$height);
my $b = 0;
$position = 5;
while ($b < $length) {
$counterimage->copy($image[$b],$position,0,0,0,$width,$height);
$position = $position + $width;
$b++;
}
$counterimage->copy($point,$position,0,0,0,$width,$height);
$position = $position + $width;
$counterimage->copy($rightborder,$position,0,0,0,$width,$height);

# print HTTP header for GIF
print "Content-type: image/gif\n\n";

# print the image
print $counterimage->gif;
}
# end of program
exit;

Vor der Definition aller Variablen mit "my" bekam ich eine ganze Reihe Fehlermeldungen der Art:

Global symbol "$length" requires explicit package name at ./counter.cgi line 57.
Das ist jetzt weg, nachdem ich jede Variable definitiert und zumindest mit "0" bestückt habe.
Wenn ich jetzt
./counter.cgi
ausführe, dann tauchen diese Meldungen auf:


Bareword "GIF" not allowed while "strict subs" in use at ./counter.cgi line 84.
Bareword "LEFT" not allowed while "strict subs" in use at ./counter.cgi line 89.
Bareword "RIGHT" not allowed while "strict subs" in use at ./counter.cgi line 93.
Bareword "POINT" not allowed while "strict subs" in use at ./counter.cgi line 96.
Execution of ./counter.cgi aborted due to compilation errors.


Und wenn ich in dem Script alle Zeilen zwischen "Create a new Image" und "end of program" kommentiere, dann kommt wieder die Fehlermeldung:


Use of uninitialized value in string ne at ./counter.cgi line 54.
Use of uninitialized value in string ne at ./counter.cgi line 54.

Denn Grund für diese Meldung finde in line 54

if ($hosts ne $currentvisitor) {
nicht.

Und Deine Fehleabfrage
open(DATEI,"<",$dateiname) or die $! habe ich nicht ganz verstanden. Kann ich damit abchecken, ob z.B.
$currentvisitor einen Wert erhalten hat, wenn ich

open(DATEI,"<",$currentvisitor) or die $!
schreibe? Bisher hatte ich open so verstanden, dass ich auf diese Art auf der Platte liegende Dateien öffnen und auslesen lassen kann.

Die beiden Dateien count.dat und visitor.dat haben die Rechte -rw-rw-rw-, werden aber nicht befüllt.

Grüsse

Eagle

reneeb
26-09-2006, 11:38
Mach mal aus
open (GIF, "$digits_dir/$digit[$a]\.$ending");
$image[$a] = newFromGif GD::Image(GIF);
close (GIF);

das hier:
open (my $gifh, "$digits_dir/$digit[$a]\.$ending");
$image[$a] = newFromGif GD::Image($gifh);
close ($gifh);

und bei den anderen Bildern genauso. Damit speicherst Du die Filehandles in Skalare.

Die Fehlerabfrage bei dem open erklärt Dir warum Du z.B. eine Datei nicht öffnen kannst (natürlich nur, wenn das open fehlschlägt). Mach die Fehlerabfrage auch beim Einlesen von visitor.dat. Und ersetz das , mal durch ;

Du brauchst auch die Zahlen nicht in "" zu schreiben. Also sollte es
my $image = 0;
heißen. Und die ganzen Vergleiche zwischen den Zahlen solltest Du mit == machen und nicht mit eq.

Das ist zwar nicht direkt das Problem, macht Deinen Code aber besser lesbar...

OpOs
27-09-2006, 10:18
aehm... hast du schonmal geprueft, ob die environmentvariable ueberhaupt existiert?

REMOTE_ADDR wird vom apache (oder wie dein server auch heissen mag) gesetzt. wenn du dein script per ssh in der shell ausfuehrst, ist der apache gar nicht an der ausfuehrung beteiligt, es gibt demzufolge keine GET oder POST parameter, keine keine cookies, kein REMOTE_ADDR usw...

probier mal
REMOTE_ADDR="1.1.1.1" ./counter.cgi

Eagle
27-09-2006, 15:33
Hallo Ihr Beiden,

also die Tipps von reneeb habe ich umgesetzt, mit dem Resultat, dass nur noch die Fehlermeldung


Use of uninitialized value in string ne at ./counter.cgi line 54.
Use of uninitialized value in string at ./counter.cgi line 63.
Use of uninitialized value in string eq at ./counter.cgi line 73.

auftritt. Das mit der Umgebungsvariablen, das die nicht ausgelesen wird, habe ich mir bereits gedacht, wusste aber nicht, wie ich die bei Perl ohne Script testen kann. Zum System, Linux (möglicherweise Debian) mit Apache (1.3 oder 2).

OpOs, wenn ich das Script, wie von Dir vorgeschlagen aufrufe, dann kommt die Meldung:

Use of uninitialized value in string ne at ./counter.cgi line 54.
Use of uninitialized value in string eq at ./counter.cgi line 73.

Es fehlt also der Code aus Line 63, und das wäre dieser hier:

open (CURRENT, ">","visitor.dat") or die $!;
print CURRENT "$hosts"; # line 63
close (CURRENT);


Immerhin schreibt er jetzt die aktuelle IP in visitor.dat und zählt count.dat um eins hoch. Also wäre auch noch Zeile 73:


if ($query eq "yes") { # line 73
$image_width = $length * $width + 32 + $width;
# Width = length * width of single image + 2*border + point
$counterimage = new GD::Image($image_width,$height);


Müsste hier eventuell auch noch "==" statt "eq" stehen. Aber wie bekomme ich das Script dazu die Remote-IP auszulesen? Also auf einem anderen Webserver (1&1) läuft in der ursprünglichen Version.

Eagle
27-09-2006, 16:31
Also meine phpinfo.php wirft die Umgebungsvariable REMOTE_ADDR richtig aus.
Vom Ausgangsverzeichnis kann das auf dem Server doch auch nicht ausgehen, oder? Das ist eine TYPO3-Verzeichnisstruktur. In

/home/projekt1/fileadmin/scripts

liegt das Script und in fileadmin die vom CMS benötigten HTML-Templates, die dann den Pfad zum Script wie gewöhnlich anzeigen.

OpOs
27-09-2006, 16:37
1. kann leider kein perl, darum erstmal 'ne frage: ist "param()" 'ne funktion um request parameter auszulesen?
falls ja, lies dir nochmal meinen post durch: es gibt keine request parameter... waere also die frage, was param() zurueck gibt, wenn es einen wert nicht findet. gibt es sowas wie null in perl?

2. steht in count.dat ueberhaupt 'ne zahl.

ueberhaupt liest, schreibst und rechnest du mit variablen und dateien in der gegend rum, ohne deren gueltigkeit zu testen oder default values zu setzen... never trust the client

Eagle
27-09-2006, 16:48
Also wie gesagt, wenn ich die IP direkt mitschicke, liest er die beiden Dateien count.dat und visitor.dat und schreibt die neuen Werte rein.

Ich habe gerade nur noch das Problem mit Zeile 73 und der Tatsache, dass die IP mit der Abfrage der Umgebungsvariablen geholt wird. Und die param-Funktion des CGI-Moduls liefert eine Liste der Namen aller Parameter, mit denen das Skript aufgerufen wurde.

Eagle
27-09-2006, 16:52
Also ich habe definitiv nur noch das Problem mit der Umgebungsvariable. Das mit Zeile 73 versuche ich rauszukriegen. Aber gerade hat eine GIF.Datei als Output generiert. Und die Funktion param("visible") sucht im HTML-Code, ob eben da "visible" als Parameter beim Aufruf der Funktion mitgegeben wird.

Ich setze mal die Abfrage
$query eq "yes"

auf

$query == 1

Eagle
27-09-2006, 17:00
Also, wenn ich auf der Console teste und my query=1 setzte, also param rauslasse, dann läuft das Script.
Wie gesagt habe ichnur noch das Problem mit der Abfrage der Umgebungsvariablen.

OpOs
27-09-2006, 17:17
bindest du den counter mit
<img src="counter.cgi?visible=yes">ein? uebergibst du den parameter auch richtig an das script?
falls ja, dann liegt es wirklich am vergleich von $query und "yes"...

Eagle
27-09-2006, 17:27
Im HTML-Code steht:


<img src="scripts/counter.cgi?visible=yes" align="bottom" border="0">

Aber das habe ich ja gerade eruiert, dass das beim Testen auf der Console den einen Fehler liefert. Ergo habe ich die Variable mit 1 versehen.

Problem macht mir wirklich eher die Übergabe der Umgebungsvariablen, hier benötige ich die Lösung.

Eagle
28-09-2006, 08:18
Hallo,

ich stelle mein Problem einfach mal anders, da die anderen Stolperstricke aus meinem Script raus sind.

Wenn ich auf besagten Server ein kleines Perlscript env.pl schreibe


#!/usr/bin/perl -w

use strict;

print $ENV{'SERVER_NAME'};
#print "hello \n";

exit;


habe ich wieder die bekannten Fehlermeldungen. In diesem Fall


Use of uninitialized value in print at ./env.pl line 5.

Also bekommt das Script die Umgebungsvariablen nicht geliefert, egal welche und egal von welcher Verzeichnisebene.
Wie bekomme ich das hin? Respektive wo liegt dann der Fehler, dass die Variablen nicht abrufbar sind?

Grüsse

Eagle

OpOs
28-09-2006, 09:06
rufst du es denn ueber den browser oder durch ssh konsole auf?

Eagle
28-09-2006, 09:15
Ich bin über ssh auf der Konsole. Aber ich glaube, dass der Provider die Direktive "SetEnvIf" nicht erlaubt hat. Was ich aber nicht verstehe, weil phpinfo.php die Variablen auswirft.

Das funktioniert aber auch vom Browser aus nicht. Wenn ich die Adresse
http://www.domaine.de/scripts/counter.cgi?visible=yes

eingebe, kommt die 404er-Fehlermeldung.

OpOs
28-09-2006, 10:24
dass es ueber ssh nicht funzt iss doch klar... wie ich schon sagte, existiert die $REMOTE_ADDR nur im apache kontext und der fehlt dir bei ssh.

die 404 sagt dir, dass er das script nicht finden kann. wenn es fehlerhaft waere, wuerde als ergebnis eine meldung ueber ungueltige header kommen.
kümmer dich erstmal drum, dass apache dein script auch finden und ausfuehren kann...