Cruz: Variable dereferenzieren

Hallo Leuts,

ich hoffe es weiß jemand Rat zu folgender Problematik:

Ich versuche im Query String den Namen einer Variable zu übergeben und dies dann im nächsten Script zu
dereferenzieren, um den Inhalt dieser Variable zu bekommen. (ich übergebe nicht direkt den Inhalt, weil ihn
nicht jeder sehen soll).

Die geheime Variable soll $secret heißen und den wert "humbug" haben.
D.h. also im Query String steht irgendwo var_name=secret
Also habe ich im Script ein $input{'var_name'}="secret".

Nach den Referrenz Regeln müsste also $$input{'var_name'}="humbug" sein. Ist es aber nicht.
auch nicht so:  ${$input{'var_name'}}
auch nicht so:  $($input{'var_name'})
schon gar nicht so: eval($$input{'var_name'})

Wieso klappt hier die Referenzierung nicht?
Und wie kann ich es DOCH referenzieren) ;)

Gruß
Cruz

  1. Tag Cruz

    Ich versuche im Query String den Namen einer Variable zu übergeben und dies dann im nächsten Script zu
    dereferenzieren, um den Inhalt dieser Variable zu bekommen. (ich übergebe nicht direkt den Inhalt, weil ihn
    nicht jeder sehen soll).

    Verstehe ich das richtig? Du willst ein Script zweimal aufrufen. Beim ersten mal gibst Du der Variablen $secret den Wert "humbug", schreibst den *Namen* der Variablen ("secret") irgendwo hin (z.B. in ein Formularfeld eines erzeugten HTML-Dokuments) und beendest das Script. Irgendwann (z.B. Jahre spaeter) wird das Script ein zweites Mal aufgerufen, bekommt den Namen einer Variable uebergeben, die es irgendwann vor langer Zeit in einem Script mal gab ("secret"), und Du willst ueber diesen Namen den Wert wiederherstellen, den die Variable damals hatte?

    Das geht natuerlich nicht! Wenn Dein erstes Script beendet ist, ist es aus und vorbei. Alles vergessen, was jemals existierte. Tot, sozusagen. Du kannst Dir natuerlich den Namen der Variable merken, aber wo soll denn der zugehoerige Wert herkommen? Der hat schliesslich im Speicherraum des ersten Scripts irgendwo gestanden, aber der Speicherraum betritt natuerlich die ewigen Perlgruende und unterhaelt sich dort mit Manitou, dem Gott des Quelltextes, wenn das Script beendet wird.

    Oder habe ich Dich einfach missverstanden?

    Calocybe

    1. Hi Calocybe,

      ja, daß die Variablen verschwinden wenn das Script vorbei ist das ist mir schon klar. Ich habe eine config Datei, in der die Variable $secret hinterlegt ist, und sie ist in mehreren Scripten bekannt.

      Ein Script generiert einen Link, der einen anderen aufruft, das sind 2 Scripte, in beiden ist die Variable $secret bekannt.

      Das Problem ist eigentlich, daß ich mehrere secret Variablen habe, und das Script das durch den Link aufgerufen wird muss wissen welchen der secret Variablen er nehmen soll. Daher die Referenzierung. Ich habe die Referenzierung schon etliche male eingesetzt und es funktionierte immer toll (eigentlich finde ich, daß man in Perl wunderbar referenzieren kann), aber jetzt wo meine Referenz durch den Query String kommt, tut es nicht.

      Du kannst es ja mal ausprobieren, vielleicht passiert dir das selbe.

      $$input{'var_name'} ist einfach leer, obwohl $input{'var_name'}="secret" ist und $secret="humbug" ist.

      Gruß
      Cruz

      1. Hallo Cruz,

        ja, daß die Variablen verschwinden wenn das Script vorbei ist das ist mir schon klar. Ich habe eine config Datei, in der die Variable $secret hinterlegt ist, und sie ist in mehreren Scripten bekannt.
        Ein Script generiert einen Link, der einen anderen aufruft, das sind 2 Scripte, in beiden ist die Variable $secret bekannt.
        Das Problem ist eigentlich, daß ich mehrere secret Variablen habe, und das Script das durch den Link aufgerufen wird muss wissen welchen der secret Variablen er nehmen soll. Daher die Referenzierung. Ich habe die Referenzierung schon etliche male eingesetzt und es funktionierte immer toll (eigentlich finde ich, daß man in Perl wunderbar referenzieren kann), aber jetzt wo meine Referenz durch den Query String kommt, tut es nicht.

        Entschuldige, wenn ich nicht gleich verstanden habe, was Du mit dem Variablennamen anfangen willst <sorry>.
        Wenn ichs jetzt richtig kapiert habe, möchtest Du einfach den Namen der Variablen übergeben, und dann die Variable mit diesem Namen im neuen Skript ansprechen !?! Wie wärs wenn Du einen Hash produzierst, in dem die Werte der Variablen stehen:

        $variablen{'bezeichner'} = $wert;

        Dann erhälst Du den Wert der Variablen mit:

        $hash{$input{'var_name'}};

        Dabei kann naturlich $wert auch eine beliebige Referenz auf eine Variable sein. Ich verwende das selbst bei einem SSI-Parser zum Aufruf von Subroutinen (möchte mich hiermit offiziell beim Archiv für die Hinweise bedanken :-).
        Hoffentlich hat das diesmal geholfen, und nix für ungut, daß ich nicht gleich durchschaut habe, was Du vorhattest :-)

        $$input{'var_name'} ist einfach leer, obwohl $input{'var_name'}="secret" ist und $secret="humbug" ist.

        In einer Referenz wird die Adresse eines Speicherbereichs referenziert, die für die "selbe" Variable in unterschiedlichen Prozessen natürlich auch unterschiedlich sein kann. So weit ich weis, sorgt ja erst der Interpreter zur Laufzeit dafür, daß ein Speicherbereich reserviert wird.

        Gruß AlexBausW

        1. Hi,

          Trotz nochmaligem Durchlesen, ist mir der Fehler erst im Moment des Abschickens aufgefallen (ja, ich hab` die FAQ gelesen ;-)

          $variablen{'bezeichner'} = $wert;

          $hash{$input{'var_name'}};

          muß natürlich auch hier "$variablen{'.....'}" lauten

          Gruß AlexBausW

          1. Hi Alex,

            vielen Dank für deine Antwort.
            Ich nehme es dir ja nicht im geringsten übel, daß du nicht gleich verstanden hast was ich meinte! Es war ja schließlich mein Fehler, weil ich nicht erwähnt habe, daß die Variable in beiden Scripten bekannt ist.

            Die Antwort auf meine Frage hast du ja auch gegeben:

            "In einer Referenz wird die Adresse eines Speicherbereichs referenziert, die für die "selbe" Variable in unterschiedlichen Prozessen natürlich auch unterschiedlich sein kann."

            Das kam sogar irgendwann mal in meinem Studium vor hihi...ich hätte eigentlich dran denken können.

            Der Lösungsvorschlag mit den Hashes ist auch super...also vielen vielen Dank.

            Gruß
            Cruz

            1. Hallo Ihr drei!!!

              Ich muß mich hier auch mal zu Wort melden. Die Sache mit den Referenzen und dem Speicher ist prinzipiell richtig. ABer, Perl wäre nicht Perl, wenn man mit Texten nur eingeschränkt umgehen kann. Es geibt auch sogenannte "symbolische Referenzen". Diese kommen der Idee von Cruz eigentlich mehr als ziemlich entgegen:

              $a = 3;
              %c = ('b' => 'a');
              print ${$c{'b'}};     # hier wird der Wert von $a, also 3 ausgegeben.

              Stellt sich eigentlich nur noch die Frage, warum Cruz hiermit Probleme hatte

              »»»»»»> auch nicht so:  ${$input{'var_name'}}

              Gruß,
                 Jörk

              1. Stellt sich eigentlich nur noch die Frage, warum Cruz hiermit Probleme hatte

                »»»»»»> auch nicht so:  ${$input{'var_name'}}

                Gruß,
                   Jörk

                Hi Jörk,

                genau das habe ich auch grade überlegt! Perl ist hauptsächlich Text basiert, dann müsste ich doch in einer Referenz nicht die Speicheradresse, sondern einfach den Namen einer Variable als ein String speichern können. Dann müsste ich im nächsten Script einfach den Veriablennamen wieder zusammensetzen können. (Eigentlich dachte ich es wäre grundsätzlich so, bis der Alex sagte, daß dort die Speicheradresse gespeichert wird.
                Ich übergebe ja auch einen String in meinem Aufruf an das nächste Script, nämlich "secret". Aber es klappt irgendwie trotzdem nicht. Wäre auch zu schön.

                Gruß
                Cruz

              2. Hi Jörk

                Ich muß mich hier auch mal zu Wort melden.

                Ich mich auch nochmal ;-)

                $a = 3;
                %c = ('b' => 'a');
                print ${$c{'b'}};     # hier wird der Wert von $a, also 3 ausgegeben.

                Stellt sich eigentlich nur noch die Frage, warum Cruz hiermit Probleme hatte
                »»»»»»> auch nicht so:  ${$input{'var_name'}}

                Ich fand die Idee von Dir gut und hab sie gleich ausprobiert, bin aber auf folgendes Problem gestoßen:

                $secret = "Hallo Welt";
                $input{'var_name'} = 'secret';

                $a = $input{'var_name'};

                %c = ('b' => 'a');
                print ${$c{'b'}};

                Ob über $a oder direkt an $c{'b'} überwiesen (ob das auch mit der DB geht ? {Deutsche Bank natürlich, und nicht Deutsche Bundesbahn ;-)}) , heist das Ergebnis nun "secret" !
                Daraus schließe ich, daß Du also im Skript bereits wissen musst, wie Deine Referenz heist, und kannst (wie ich leider feststellen musste) keine dynamische Bezeichner verwenden.
                Ich denke, so lässt sich auch erklären, warum ${$input{'var_name'}} nicht funktioniert.
                Zudem bekomme ich (hoffentlich liegt das nicht an mir ;-) Ärger mit use strict;

                Gruß AlexBausW

                1. Alex,

                  $a = 3;
                  %c = ('b' => 'a');
                  print ${$c{'b'}};     # hier wird der Wert von $a, also 3 ausgegeben.

                  Stellt sich eigentlich nur noch die Frage, warum Cruz hiermit Probleme hatte
                  »»»»»»> auch nicht so:  ${$input{'var_name'}}

                  Ich fand die Idee von Dir gut und hab sie gleich ausprobiert, bin aber auf folgendes Problem gestoßen:

                  $secret = "Hallo Welt";
                  $input{'var_name'} = 'secret';

                  $a = $input{'var_name'};

                  %c = ('b' => 'a');
                  print ${$c{'b'}};

                  Ob über $a oder direkt an $c{'b'} überwiesen (ob das auch mit der DB geht ? {Deutsche Bank natürlich, und nicht Deutsche Bundesbahn ;-)}) , heist das Ergebnis nun "secret" !

                  Ist doch eigentlich auch klar, oder?
                  $a = $input{'var_name'}; Setzt $a auf 'secret'. Da über $c{'b'} ein 'a' zurückgegeben wird, erhalt man nun auch über die dereferenzierung ${...} den Wert von $a also 'secret'.

                  Dein Beispiel müßte also durch eine weitere Dereferenzierung zum Laufen zu bringen sein:
                  print ${${$c{'b'}}};

                  Ich frage mich nur, warum Du hier einen solchen Weg gehst. In Deinem Beispiel hast Du doch schon ein Hash namens input. Verwende dieses enstelle von c und benutze 'var_name' als Index:
                  ${$input{'var_name'}}

                  Oder anders gesagt - so wie ursprünglich mal von Cruz angedacht ...

                  Ich bleibe also dabei: Eigentlich müßte es so funktionieren, wie Cruz es probiert hat, aber ...

                  Grüß,
                     Jörk

                  1. Hi Jörk

                    Dein Beispiel müßte also durch eine weitere Dereferenzierung zum Laufen zu bringen sein:
                    print ${${$c{'b'}}};

                    Treffer versenkt ;-) Da hab ich ein Eigentor fabriziert. An die Mehrfachreferenzierung hätte ich auch selbst denken können <g> schließlich hab ich eigentlich lange genug mit perlref zugebracht (scheinbar nicht lange genug) </g>

                    Ich frage mich nur, warum Du hier einen solchen Weg gehst. In Deinem Beispiel hast Du doch schon ein Hash namens input. Verwende dieses enstelle von c und benutze 'var_name' als Index:
                    ${$input{'var_name'}}

                    Das war nur der umständliche Weg, den String 'secret' als symbolische Referenz zu einzuflechten *g*  (und die Mehrfachreferenzierung nicht zu beachten <schlagmichselbst>).

                    Oder anders gesagt - so wie ursprünglich mal von Cruz angedacht ...
                    Ich bleibe also dabei: Eigentlich müßte es so funktionieren, wie Cruz es probiert hat, aber ...

                    Funktioniert jetzt - zumindest von der Kommandozeile aus - bei mir (hätte vielleicht vorher mal alle Möglichkeiten ausprobieren sollen ;-).
                    Allerdings müsste man entweder use strict; weglassen oder den Block mit der symbolischen Referenz in no strict; einschließen.
                    Zumindest bei mir gibt`s immer folgende Fehlermeldung bei Gebrauch von use strict;
                    Can't use string ("secret") as a SCALAR ref while "strict refs" in use at .... [str2ref.pl line 19.]
                    (Obwohl strict 'refs' gar nicht verwendet wurde !? Ich dacht eigentlich man könnte das unabhängig verwenden )

                    Vielleicht kannst Du mir dabei weiterhelfen, denn - wie im Thread weiter oben angemerkt - fand ich die Idee, so Daten zu referenzieren echt gut.

                    Gruß AlexBausW

                    1. Hi Alex,

                      Dein Beispiel müßte also durch eine weitere Dereferenzierung zum Laufen zu bringen sein:
                      print ${${$c{'b'}}};

                      »»

                      Treffer versenkt ;-) Da hab ich ein Eigentor fabriziert. An die Mehrfachreferenzierung hätte ich auch selbst denken können <g> schließlich hab ich eigentlich lange genug mit perlref zugebracht (scheinbar nicht lange genug) </g>

                      gern geschehen ;-)

                      Allerdings müsste man entweder use strict; weglassen oder den Block mit der symbolischen Referenz in no strict; einschließen.
                      Zumindest bei mir gibt`s immer folgende Fehlermeldung bei Gebrauch von use strict;
                      Can't use string ("secret") as a SCALAR ref while "strict refs" in use at .... [str2ref.pl line 19.]
                      (Obwohl strict 'refs' gar nicht verwendet wurde !? Ich dacht eigentlich man könnte das unabhängig verwenden )

                      Vielleicht kannst Du mir dabei weiterhelfen, denn - wie im Thread weiter oben angemerkt - fand ich die Idee, so Daten zu referenzieren echt gut.

                      Es gibt drei Varianten von strict:
                      use strict 'refs';
                      use strict 'vars';
                      use strict 'subs';

                      Per "use strict;" werden alle drei aktiviert. strict 'refs' ist gerade dazu da, bei symbolischen Referenzen zu meckern - man weiß ja nie, was in den "Texten" drin steht, muß ja nicht immer eine passende Variable dazu existieren.

                      Jetzt kannst Du entweder nur vars und subs einschalten, oder (was ich bevorzugen würde) alles einschalten und per "no strict 'refs'" diesen Teil wieder abschalten. Ob Du das nun generell gleich hinter dem use strict machst, oder aber an den Stellen, wo Du bewußt symbolische Referenzen einsetzt, sei Dir überlassen.

                      Gruß,
                         Jörk

                      1. Hi Jörk,

                        Per "use strict;" werden alle drei aktiviert. strict 'refs' ist gerade dazu da, bei symbolischen Referenzen zu meckern - man weiß ja nie, was in den "Texten" drin steht, muß ja nicht immer eine passende Variable dazu existieren.
                        Jetzt kannst Du entweder nur vars und subs einschalten, oder (was ich bevorzugen würde) alles einschalten und per "no strict 'refs'" diesen Teil wieder abschalten. Ob Du das nun generell gleich hinter dem use strict machst, oder aber an den Stellen, wo Du bewußt symbolische Referenzen einsetzt, sei Dir überlassen.

                        Danke für die Müh die isch Ihne gemacht hab <g> Ich glaub jetzt hab ich`s :-). Aber so wie ich die Dokumentation verstanden habe, werde ich wohl doch bei "harten" Referenzen bleiben bzw. bei dynamischen Variablenbezeichnern die "Hashmethode" verwenden. <g>So wie ich mich kenne wären bei symbolischen Referenzen die Bugs schon <doppeldeut> vorprogrammiert </doppeldeut> </g>.

                        mit dankendem Gruß
                           AlexBausW

                  2. Ich bleibe also dabei: Eigentlich müßte es so funktionieren, wie Cruz es probiert hat, aber ...

                    Hallo Jungs,

                    ich verfogle immer noch interessiert eure Diskussion. Jetzt habt ihr euch beide schon so viel Mühe gegeben. Warum probiert nicht mal einer von euch genau auf die selbe Weise aus, wie ich es versucht habe? Dann werden wir wissen ob es wirklich nicht funktioniert, oder es nur ein "User Error Cruz" war.

                    Nochmal Kurzfassung:

                    Wir haben eine Variable $secret="humbug", die in beiden Scripten bekannt ist. Ein Script übergibt var_name="secret" an das nächste, wo dann $input{'var_name'}="secret" ist. Also müsste (theoretisch) im nächsten Script ${$input{'var_name'}}="humbug" sein.

                    Wenn es bei euch auch nicht klappt, finde ich die Hash-Referenzierung Lösungsvorschlag von Alex fast genau so schön. :)

                    Gruß
                    Cruz

            2. Hi Cruz,

              vielen Dank für deine Antwort.
              Ich nehme es dir ja nicht im geringsten übel, daß du nicht gleich verstanden hast was ich meinte! Es war ja schließlich mein Fehler, weil ich nicht erwähnt habe, daß die Variable in beiden Scripten bekannt ist.
              Die Antwort auf meine Frage hast du ja auch gegeben:

              Gern geschehen :-)

              Es ging ja allgemein darum, den Inhalt eines Strings als Variablenbezeichner zu verwenden,  weshalb ich mir eval() noch mal durch den Kopf gehen lassen habe ;-).
              Hier noch mal eine "Lösung" der Vollständigkeit halber und fürs Archiv (auch wenn <../../sfarchiv/1999_3/t05324.htm> ein wenig ähnelt, und doch anders ist ;-) Als Beispiel hab ich folgendes Skript zusammengestellt:

              my $secret = "Hallo Welt";
              my $referenz = $secret;
              my (%input, $variable, $variable2);

              als Alternative zum Evaluieren anhängen (funktioniert auch):

              $input{'var_name'} = 'secret';

              $input{'referenz'} = 'referenz';

              eval ('$variable = $'.'secret');
              eval ('$variable2 = $$'.'referenz');

              print $variable."\n";
              print $variable2."\n";

              Anstelle der Strings hinter dem Punkt im eval(String) kann natürlich auch das(der?) Hash{Key} stehen.
              Das obige Skript funktioniert, wenn es auch mit Vorsicht zu genießen ist. Es könnte ja jemand Deinen Query_String mit allerlei Unsinn füttern <g>

              Gruß AlexBausW

              1. Hi!

                Es ging ja allgemein darum, den Inhalt eines Strings als Variablenbezeichner zu verwenden,  weshalb ich mir eval() noch mal durch den Kopf gehen lassen habe ;-).
                Hier noch mal eine "Lösung" der Vollständigkeit halber und fürs Archiv (auch wenn <../../sfarchiv/1999_3/t05324.htm> ein wenig ähnelt, und doch anders ist ;-) Als Beispiel hab ich folgendes Skript zusammengestellt:

                my $secret = "Hallo Welt";
                my $referenz = $secret;
                my (%input, $variable, $variable2);

                als Alternative zum Evaluieren anhängen (funktioniert auch):

                $input{'var_name'} = 'secret';

                $input{'referenz'} = 'referenz';

                eval ('$variable = $'.'secret');
                eval ('$variable2 = $$'.'referenz');

                print $variable."\n";
                print $variable2."\n";

                »»

                Anstelle der Strings hinter dem Punkt im eval(String) kann natürlich auch das(der?) Hash{Key} stehen.
                Das obige Skript funktioniert, wenn es auch mit Vorsicht zu genießen ist. Es könnte ja jemand Deinen Query_String mit allerlei Unsinn füttern <g>

                Ich denke eher, daß der Weg über die CGI-Parameter gehen sollte. Also unter Verwendung des input-Hashes:

                $wert = eval( '$' . $input{'var_name'} );

                Bei solchen eval-Lösungen ist aber generell Vorsicht geboten. Man weiß ja nie, was für Parameter ein paar hinterlistige Anwender sich aus den Finger ziehen:

                $input{'var_name'} = "a; rmdir(../cgi-bin);";

                Gruß,
                   Jörk

  2. Hi Cruz,

    Die geheime Variable soll $secret heißen und den wert "humbug" haben.
    D.h. also im Query String steht irgendwo var_name=secret
    Also habe ich im Script ein $input{'var_name'}="secret".

    Aus Deinen Angaben schließe ich, daß Du mit einem Skript im Browser einen Link erzeugst, der einen Variablennamen als Parameterwert angehängt bekommt:
    Allerdings vergisst afaik Perl Variablen und deren Werte, wenn Du das Skript beendest, und ein neues aufrufst (über den vom ersten Skript generierten Link).
    Durch beenden des Skriptes verlässt Du ja den Prozess des ersten Skriptes, und alle reservierten Speicherbereiche (mit Variablen oder referenzierte Bereiche) werden wieder freigegeben (bitte korrigiert mich, wenn ich falsch liege :-).
    Eine Möglichkeit wäre allerdings, eine ID zu generieren, die Du als Dateinamen (zur Speicherung der geheimen Variable) und als Parameter für den Link in der Ausgabe verwenden kannst. Beim Aufrufen des zweiten Skriptes könnte dieses die Datei unter dieser ID öffnen, und schon wäre die Variable wieder da :-).
    Jedoch sollte bei Parameterübergabe überprüft werden, ob nicht irgendwelcher Unfug im Parameter steht (wenn jemand das Skript über die Adresszeile aufruft), der Schaden anrichten könnte.

    Zum Dereferenzieren ("echte" Referenzen sind - ich hab`s noch mal nachgeschlagen - erst ab Perl 5 möglich) :

    Nach den Referrenz Regeln müsste also $$input{'var_name'} =  ...[(Anm. d. A.: == !? :-)]... "humbug" sein. Ist es aber nicht.

    $var = $$hash{key} ist schon korrekt, genauso wie das folgende Konstrukt:

    auch nicht so:  ${$input{'var_name'}}

    auch nicht so:  $($input{'var_name'})

    das geht afaik nicht!

    schon gar nicht so: eval($$input{'var_name'})

    und das denke ich auch nicht!

    Wieso klappt hier die Referenzierung nicht?

    Siehe Calocybe :-) (<g>Ich lösch aber nicht jetzt nicht den Großteil des Postings, um eine Sinnverzerrung zu vermeiden </g>)

    Und wie kann ich es DOCH referenzieren) ;)

    Siehe oben :-)

    Gruß AlexBausW

    1. Hallo Alex,

      lies mal meine Antwort zu Calocybe.
      (ich bin kein Anfänger, ich weiß daß die Variablen mit dem Script sterben :) )

      Dank und Gruß
      Cruz