Beat: verschiedene Fragen zu Funktionen

Hallo Ich habe ein paar aktuelle Fragen, weil ich gerade mein Script am Überarbeiten bin.
Voraussetzung: Ich kann meine Scripts nur Online auf einem fernen Server testen, bin also defensiv in der Anwendung von mir noch unbekannten Funktionen.

ERSTE FRAGE

Wann eine Variable mit my deklarieren?
Die zwei unteren Varianten unterscheiden sich,
in Var 1 wird mit einer einzigen Variable gearbeitet
in Var 2 erhalte jedesmal ein frisches neues Array

was ist bessern
bezüglich Speicherverbrauch,

#Variante 1
for (my $1=1 , $i=100 , $i++){
  my $link = $i."html";
  open(DATENBLATT,"$basedir/$link") || die $! ;
  my @main = <DATENBLATT>;
  close(DATENBLATT);
  # mach was mit @main
}

#Variante 2
my @main;
for (my $1=1 , $i=100 , $i++){
  my $link = $i."html";
  open(DATENBLATT,"$basedir/$link") || die $! ;
  my @main = <DATENBLATT>;
  close(DATENBLATT);
  # mach was mit @main
}

ZWEITE FRAGE
Ich möchte nun
map()
anstelle von
foreach(){...}
verwenden

my @worklines;
    foreach my $lines(@main){
    if( $lines =~ /$wort1|$wort2/gi ){push(@worklines, $lines);}
  }

würde neu zu :

my @worklines = map( /$wort1|$wort2/gi , @main );

Hierzu auch wieder die Frage, abgesehen dass es sich einfacher schreibt.
Wie verhalten sich map() und foreach() in Bezug auf performance?
Kann ich RegExp in der map Funktion genau gleich anwenden wie mit dem üblichen =~ Operator?

Gibt es eine Seite, die die map() Funktion ausführlich beschreibt

DRITTE FRAGE
Irgendwie liesst man doch viel von Missbrauch durch Bufferoverflows.
Ist es ratsam, dass ich allen Usereingabe Variablen auf maximale Länge kontrolliere?

zum Beispiel:

if (length($userinput) > 1000){&error("Kein normaler User Input");}

danke für Antworten

mfg Beat

  1. Wann eine Variable mit my deklarieren?
    Die zwei unteren Varianten unterscheiden sich,
    in Var 1 wird mit einer einzigen Variable gearbeitet
    in Var 2 erhalte jedesmal ein frisches neues Array
    was ist bessern

    Die zweite, weil die Variable am Ende des for{}-Blocks out of scope geht und damit nicht mehr den übergeordneten Namespace verunreinigt.

    bezüglich Speicherverbrauch,

    Der ist in beiden Varianten gleich schlecht.

    Stil-Tipp: Nutze den Aufzählungsoperator.
    for (1..100) {
     my $i = $_;
     # tue Zeug mit $i
     # $_ lässt sich auch direkt verwenden
    };

    Wie verhalten sich map() und foreach() in Bezug auf performance?

    MJD kommentiert: "Who the fuck cares which one is faster?"
    Du kannst für deinen speziellen Fall Benchmarks durchführen und die Ergebnisse vergleichen. Ich persönliche nehme foreach nur im void-Kontext, d.h. die Enumeration liefert nichts zurück; Performance spielt für mich keine Rolle in Perl.

    Kann ich RegExp in der map Funktion genau gleich anwenden wie mit dem üblichen =~ Operator?

    Ja!

    Gibt es eine Seite, die die map() Funktion ausführlich beschreibt

    http://perldoc.com/perl5.8.4/pod/func/map.html
    Camel book, §3.2.91., §8.4.
    Nutshell, §5.93.
    Cookbook, §4.15.

    Irgendwie liesst man doch viel von Missbrauch durch Bufferoverflows.
    Ist es ratsam, dass ich allen Usereingabe Variablen auf maximale Länge kontrolliere?

    Perl hat eine eigene Speicherverwaltung für seine Innereien, Bufferoverflows können nicht so wie bei C passieren.

    if (length($userinput) > 1000){&error("Kein normaler User Input");}

    Das ist aber trotzdem aus Sicherheitsgründen zu empfehlen. Führe immer einen Sanity Check auf Nutzereingaben durch. Wenn du Webprogramme schreibst, ist der Taint Mode unverzichtbar. Details: http://perldoc.com/perl5.8.4/pod/perlsec.html

    Stil-Tipp: Verzichte auf & für Funktionen. Nutze den if-Operator bei simplen Entscheidungen.
    error("Kein normaler User Input") if length $userinput > 1000;

    1. hi Beat,

      der Kollege hat ja schon einiges gesagt.
      Hier noch eine kl. Ergänzung von mir.

      In letzter Zeit benutze ich für den Zugriff auf Textdateien immer öfter DB_File und DB_RECNO. Das ist nicht so umständlich wie das hantieren mit einem FileHandle, open() und close().

      Derzeit baue ich an einem CGI, da brauche ich im gesamten Scriptverlauf den Vollzugriff auf eine Datei. Mit tie() und DB_RECNO binde ich dazu die Datei an ein globales Array (das Array liegt übrigens NICHT im Speicher rum), und wenn das Script zuende ist werden alle am Array gemachten Änderungen zurück in die Datei geschrieben ( untie() ).

      Wies geht habch hier mal aufgeschrieben (weiter unten...)
      http://perlbase.xwolf.de/cgi-bin/perlbase.cgi?display=16&id=9

      Viele Grüße
      Rolf

      --
      KnowHow veröffentlichen statt patentieren!
      1. Hy Rolf

        DB_File scheint ja mächtig viel Arbeit abzunehmen. Mann muss sich um (fast) keine Formatierung kümmern.
        Auch ist es anscheinend so dass ich keine Datei mehr zuerst zum lesen und dann nochmals zum schreiben öffnen muss.

        Immerhin lässt sich das ja auch auf normale htmlseiten (als Flatfiles) anwenden

        Nur eine Frage noch dazu
        wenn mit tie() eine Datei an einen Array/Hash mit dem Modul als Schnittstelle gebunden ist....
        dann dürfen anscheinden Manipulationen an dieser gebundenen Variable nur zwischen tie() und untie() stattfinden.

        MfG Beat

        1. hi Beat,

          wenn mit tie() eine Datei an einen Array/Hash mit dem Modul als Schnittstelle gebunden ist....
          dann dürfen anscheinden Manipulationen an dieser gebundenen Variable nur zwischen tie() und untie() stattfinden.

          Ganz genau.

          Bitte beachte die Flags
          O_RDWR|O_CREAT, # lesen, schreiben, ggf, anlegen der Datei

          und Berechtigung an Datei
          0644 # owner darf alles, alle anderen dürfen nur lesen
          0600 # nur der owner darf lesen, schreiben

          ############## tie() array an datei binden #################
          my $filename = 'c:/windows/services';
          my @filebody;
          tie @filebody, "DB_File", $filename, O_RDWR|O_CREAT, 0644, $DB_RECNO
           or die "Cannot open file $filename: $!\n" ;

          hier tut das Script

          ggf. haben wir hier eine Kontrollstruktur

          die den Ablauf des Scripts bestimmt

          ############## bindung aufheben, Änderungen werden geschrieben
          untie @filebody;

          exit; # Script ist zuende

          Gruss, Rolf

          --
          KnowHow veröffentlichen statt patentieren!
    2. Hallo JAPH

      Meine Scripts laufen derzeit mit dem Schalter -w

      use strict;
      use CGI::Carp qw(fatalsToBrowser);

      Ich bin eigentlich immer davon ausgegangen, dass:
      use strict
      allein schon verhindert dass Eingaben nicht nachträglich interpretiert werden

      Wie meine ich das

      ohne use strict

      Sinput = "wort1|wort2" ;
      $finde =~ /$input/;
      findet "wort1" oder "wort2"

      mit use strict

      Sinput = "wort1|wort2" ;
      $finde =~ /$input/;
      findet "wort1|wort2" , maskiert also die Pipe in der Eingabe

      Anyway... werde die perldoc Sicherheits Seite nochmals studieren.
      Die Seite zur map() habe ich schon konsultiert.

      also mal so
      #!/usr/bin/perl -w -T

      dies sollte eventuell noch zusätzlich Errormessages schreiben (denke ich)

      mfg Beat

      1. Ich bin eigentlich immer davon ausgegangen, dass:
        use strict
        allein schon verhindert dass Eingaben nicht nachträglich interpretiert werden

        Wer hat dir denn diesen Floh ins Ohr gesetzt? :)
        strict macht folgendes: http://perldoc.com/perl5.8.4/lib/strict.html

        Wie meine ich das

        ohne use strict

        Sinput = "wort1|wort2" ;
        $finde =~ /$input/;
        findet "wort1" oder "wort2"

        mit use strict

        Sinput = "wort1|wort2" ;
        $finde =~ /$input/;
        findet "wort1|wort2" , maskiert also die Pipe in der Eingabe

        Das ist Murks. Ich habe mal einen Testcase gebaut:

        use strict;
        my $muster     = 'wort1|wort2';
        my $vergleich1 = 'abcwort1xyz';
        my $vergleich2 = 'abcwort2xyz';
        my $vergleich3 = 'abcwort1|wort2xyz';
        print "true1\n" if $vergleich1 =~ /$muster/; # ist wahr
        print "true2\n" if $vergleich2 =~ /$muster/; # ist auch wahr
        print "true3\n" if $vergleich3 =~ /$muster/; # dito

        Dieser verhält sich mit oder ohne strict identisch. Ich glaube, was du suchst, ist quotemeta.

        use strict;
        my $muster     = 'Guten Tag.';
        my $vergleich1 = 'abcGuten Tag0xyz';
        my $vergleich2 = 'abcGuten Tag.xyz';
        print "true1\n" if $vergleich1 =~ /$muster/; # ist wahr
        print "true2\n" if $vergleich2 =~ /$muster/; # ist auch wahr

        my $musterquoted = quotemeta $muster;
        print "true1\n" if $vergleich1 =~ /$musterquoted/; # ist falsch!
        print "true2\n" if $vergleich2 =~ /$musterquoted/; # wahr

        print "true1\n" if $vergleich1 =~ /\Q$muster\E/; # ist falsch!
        print "true2\n" if $vergleich2 =~ /\Q$muster\E/; # wahr

        Erläuterung: Im ersten Abschnitt trifft die Übereinstimmung auf beide Strings zu, denn der Punkt am Ende wird als reguläres Zeichen gewertet. Im zweiten und dritten Abschnitt trifft die Übereinstimmung nur noch auf String 2 zu, denn der Punkt wird als literales Zeichen, d.h. als tatsächlicher Punkt, gewertet. Quotemeta tut Backslashes vor reguläre Zeichen und raubt ihnen damit ihren Sonderstatus.

        1. Ooops
          Erst mal danke..... man hat selten jemanden, der gleich testet.

          Aber mir ist folgendes aufgefallen:

          Bei mir

          Sinput = "wort1|wort2" ;

          Doppelte Anführungszeichen

          In deinem Experiment

          my $muster     = 'wort1|wort2';

          einfache Anführungszeichen, und das hat doch einen Einfluss

          Und der springende (oder doch bemerkenswerte) Punkt.
          auch in deinem Beispiel wird ein Punkt als Platzhalter interpretiert. (was mich wiederum überrascht)
          Das bedeutet, Benutzereingaben können eine RegExp doch mit seltsamen Sachen füttern, wobei man nur hoffen kann dass nicht ein ///e (Also eine evaluierte Regexp) gefüttert wird.

          Ich denke ich werde die Eigaben mit dem quotemeta Befehl bearbeiten, und mal schauen was mein  -T parameter sonst noch meldet.

          mfg Beat