Wann (wenn überhaupt) ist eval NICHT böse?

Ich habe viele Orte gehört, dass PHP eval function oft nicht die Antwort ist . Angesichts von LSB und Closures von PHP 5.3 gehen uns die Gründe dafür aus, dass wir auf eval oder create_function .

Gibt es denkbare Fälle, in denen eval die beste (einzige?) Antwort in PHP 5.3 ist?

In dieser Frage geht es nicht darum, ob eval böse ist, wie es offensichtlich nicht ist.

Zusammenfassung der Antworten:

  • Auswerten von numerischen Ausdrücken (oder anderen “sicheren” PHP-Teilmengen)
  • Komponententest
  • Interaktive PHP “Shell”
  • Deserialisierung von vertrauenswürdigem var_export
  • Einige Vorlagensprachen
  • Erstellen von Hintertüren für Administratoren und / oder Hacker
  • Kompatibilität mit <PHP 5.3
  • Syntax überprüfen (möglicherweise nicht sicher)

Solutions Collecting From Web of "Wann (wenn überhaupt) ist eval NICHT böse?"

Eric Lippert summiert sich über drei Blogposts. Es ist eine sehr interessante Lektüre.

Soweit ich weiß, sind die folgenden einige der einzigen Gründe, die Eval verwendet wird.

Zum Beispiel, wenn Sie komplexe mathematische Ausdrücke basierend auf Benutzereingaben erstellen oder wenn Sie den Objektstatus in eine Zeichenfolge serialisieren, so dass sie gespeichert oder übertragen und später wiederhergestellt werden kann.

Wenn Sie Malware schreiben und dem Sysadmin, der nach Ihnen aufräumen will, das Leben schwer machen wollen. Dies scheint der häufigste Anwendungsfall meiner Erfahrung zu sein.

Das Hauptproblem von eval ist, dass es ein Gateway für bösartigen Code ist. Daher sollten Sie es niemals in einem Kontext verwenden, in dem es von außen genutzt werden kann, z. B. vom Benutzer bereitgestellte Eingaben.

Ein gültiges UseCase wäre in Mocking Frameworks.

Beispiel aus PHPUnit_Framework_TestCase::getMock()

 // ... some code before $mock = PHPUnit_Framework_MockObject_Generator::generate( $originalClassName, $methods, $mockClassName, $callOriginalClone, $callAutoload ); if (!class_exists($mock['mockClassName'], FALSE)) { eval($mock['code']); } // ... some code after 

Es gibt tatsächlich eine Menge Dinge in der Generate-Methode. In layers ausgedrückt: PHPUnit nimmt die Argumente, generate daraus eine classnvorlage zu generate und zu erstellen. Anschließend wird diese classnvorlage ausgewertet, um sie für die Instanziierung verfügbar zu machen. Der Zweck davon ist, TestDoubles zu haben, um Abhängigkeiten in UnitTests natürlich zu verspotten.

Sie können eval verwenden, um Ad-hoc-classn zu erstellen:

 function myAutoLoad($sClassName){ # classic part if (file_exists($sClassName.'.php'){ require $sClassName.'.php'; } else { eval(" class $sClassName{ public function __call($sMethod,$aArgs){ return 'No such class: ' . $sClassName; } }"); } } 

Obwohl die Nutzung natürlich ziemlich begrenzt ist (einige APIs oder vielleicht DI-Container, Test-Frameworks, ORMs, die mit databaseen mit dynamischer Struktur umgehen müssen, Code-Spielplätze)

Wenn Sie eine Website schreiben, die PHP-Code interpretiert und ausführt, würde dies wie eine interaktive Shell aussehen.

Ich bin ein System-Typ, mehr habe ich nicht.

eval ist ein Konstrukt, mit dem Syntaxerrors überprüft werden können.

Angenommen, Sie haben diese zwei PHP-Skripte:

script1.php

 < ?php // This is a valid syntax $a = 1; 

script2.php

 < ?php // This is an invalid syntax $a = abcdef 

Sie können mit eval nach Syntaxerrorsn eval :

 $code1 = 'return true; ?>'.file_get_contents('script1.php'); $code2 = 'return true; ?>'.file_get_contents('script2.php'); echo eval($code1) ? 'script1 has valid syntax' : 'script1 has syntax errors'; echo eval($code2) ? 'script2 has valid syntax' : 'script2 has syntax errors'; 

Im Gegensatz zu php_check_syntax (die sowieso veraltet ist), wird der Code nicht ausgeführt.

BEARBEITEN:

Die andere (bevorzugte) Alternative ist php -l . Sie können die obige Lösung verwenden, wenn Sie keinen Zugriff auf die Befehle system () oder Shell ausführen.

Diese Methode kann classn / functionen in Ihren Code einfügen. Stellen Sie sicher, dass Sie zuvor einen preg_replace Aufruf oder einen namespace erzwingen, um zu verhindern, dass sie in nachfolgenden Aufrufen ausgeführt werden.

Wie für das OP-Thema: Wann (wenn überhaupt) ist eval nicht böse? eval ist einfach nicht böse. Programmierer sind böse für eval ohne Grund verwenden. eval kann Ihren Code verkürzen (mathematische Ausdrucksevaluierung, pro Beispiel).

Ich habe festgestellt, dass es Zeiten gibt, in denen die meisten functionen einer Sprache nützlich sind. Schließlich hat sogar GOTO seine Befürworter gehabt . Eval wird in einer Reihe von Frameworks verwendet und es wird gut verwendet. Zum Beispiel verwendet CodeIgniter eval , um zwischen classnhierarchien von PHP 4 und PHP 5 Implementierungen zu unterscheiden. Blog-Plugins, die die Ausführung von PHP-Code ermöglichen, benötigen sie (und das ist eine function, die in Expression Engine, WordPress und anderen verfügbar ist). Ich habe es auch für eine Website verwendet, auf der eine Reihe von Ansichten fast identisch ist, aber für jeden Code wurde ein eigener Code benötigt, und eine Art verrückter Regel-Engine zu erstellen war viel komplizierter und langsamer.

Während ich weiß, dass dies nicht PHP ist, fand ich, dass Pythons Eval die Implementierung eines einfachen Rechners viel einfacher macht.

Im Grunde ist hier die Frage:

  1. Erleichtert eval das Lesen ? Eines unserer Hauptziele ist es, anderen Programmierern zu vermitteln, was uns durch den Kopf ging. Im CodeIgniter-Beispiel ist sehr klar, was sie erreichen wollten.
  2. Gibt es eine andere Art und Weise? Die Chancen stehen gut, wenn Sie eval (oder Variablenvariablen oder eine andere Form der Suche nach Zeichenfolgen oder Reflektionssyntax) verwenden, gibt es eine andere Möglichkeit, dies zu tun. Hast du deine anderen Möglichkeiten ausgeschöpft? Haben Sie einen vernünftig begrenzten Eingabesatz? Kann eine switch-statement verwendet werden?

Andere Überlegungen:

  1. Kann es sicher gemacht werden? Gibt es eine Möglichkeit, dass sich ein verirrter Code in die Evaluierungsanweisung einarbeiten kann?
  2. Kann es konsistent gemacht werden? Können Sie bei einer Eingabe immer die gleiche Ausgabe erzeugen?

Eine geeignete Gelegenheit (angesichts des Mangels an einfachen Alternativen) wäre, wenn vertrauenswürdige Daten mit var_export serialisiert var_export und es notwendig ist, sie zu deserialisieren. Natürlich hätte es niemals auf diese Weise serialisiert werden sollen, aber manchmal ist der Fehler bereits erledigt.

Ich nehme an, Eval sollte verwendet werden, wo der Code tatsächlich kompiliert werden muss . Ich meine solche Fälle wie Template-File-Compilations (Template-Sprache in PHP aus Gründen der Performance), Plugin-Hook-Compilation, Compilations aus Performance-Gründen etc.

Sie könnten eval verwenden, um ein Setup zum Hinzufügen von Code nach der Installation des Systems zu erstellen. Normalerweise, wenn Sie den Code auf dem Server ändern möchten, müssen Sie vorhandene PHP-Dateien hinzufügen / ändern. Eine Alternative dazu wäre, den Code in einer database zu speichern und eval zum Ausführen zu verwenden. Sie müssen jedoch sicher sein, dass der hinzugefügte Code sicher ist.

Stellen Sie es sich wie ein Plugin vor, nur eines, das alles kann …

Sie könnten sich eine Website vorstellen, auf der Nutzer Code-Snippets beisteuern können, die die Nutzer dann dynamisch in ihre Webseiten einfügen können – ohne dass sie tatsächlich Code im Webserver-Dateisystem speichern. Was Sie benötigen, ist ein Genehmigungsprozess obwohl …

Kompatibilität . Es ist ziemlich häufig, PHP4-Fallbacks zur Verfügung zu stellen. Es ist aber auch möglich, die PHP5.4-functionalität in 5.3 als Beispiel für SplString zu emulieren. Während zwei Include-Varianten (include.php4 vs. include.php5) einfach zur Verfügung stehen, ist es manchmal effizienter oder lesbarer, auf eval () zurückzugreifen:

  $IMPL_AA = PHP_VERSION >= 5 ? "implements ArrayAccess" : ""; eval(< < 

In diesem Fall würde der Code auf PHP4 funktionieren, aber die schönere API / Syntax nur auf PHP5 verfügbar machen. Beachten Sie, dass das Beispiel fiktiv ist.

Ich habe eval benutzt, als ich einen php-motorisierten Bot hatte, der mit mir kommunizierte, und ich konnte ihm sagen, Befehle über EVAL: php commands here . Immer noch böse, aber wenn Ihr Code keine Ahnung hat, was Sie erwarten können (falls Sie einen Teil PHP-Code aus einer database ziehen), ist eval die einzige Lösung.

Dies sollte also für alle Sprachen mit eval :

Im Grunde genommen, mit ein paar Ausnahmen, machen Sie etwas falsch, wenn Sie den Wert erstellen, der an eval oder wenn Sie ihn von einer nicht-richtigen Quelle beziehen. Dasselbe gilt, wenn Sie eval für eine statische Zeichenfolge aufrufen.

Neben den Performanceproblemen bei der Initialisierung des Parsers zur Laufzeit und den Sicherheitsproblemen mischt man sich in der Regel mit dem Typsystem herum.

Im Ernst, es wurde gerade gezeigt, dass es in den allermeisten Fällen viel elegantere Lösungsansätze gibt. Anstatt jedoch das Konstrukt direkt zu verbieten, ist es nett, darüber nachzudenken, wie man es könnte. Es gibt legitime Verwendungen für beide, aber es ist eine gute rote Flagge, die Sie darüber nachdenken sollte, wenn Sie das Problem auf die richtige Weise nähern.

Meiner Erfahrung nach habe ich nur legitime Anwendungen gefunden, die in die Kategorien von Plugins und privilegierten Benutzern (z. B. der Administrator einer Website, nicht der Benutzer solcher) Erweiterungen fallen. Grundsätzlich Dinge, die als Code aus vertrauenswürdigen Quellen handeln.

Nicht direkt verwenden, aber der / e Modifikator zu preg_replace nutzt eval und kann ziemlich praktisch sein. Siehe Beispiel 4 auf http://php.net/preg_replace .

Ob es böse / böse ist, ist subjektiv und hängt ganz davon ab, was man in einem bestimmten Kontext für “gut” hält. Bei nicht vertrauenswürdigen Eingaben wird dies normalerweise als schlecht angesehen. In anderen Situationen kann es jedoch nützlich sein. Stellen Sie sich vor, Sie schreiben ein einmaliges Datenumwandlungsskript unter extremem Termindruck. In dieser Situation, wenn eval funktioniert und die Dinge einfacher macht, hätte ich Schwierigkeiten, es als böse zu bezeichnen.

Diese Eval-Debatte ist eigentlich ein großes Missverständnis im Zusammenhang mit PHP. Die Leute sind Gehirnwäsche unterzogen, weil Eval schlecht ist, aber normalerweise haben sie kein Problem mit include , obwohl Include im Wesentlichen das Gleiche ist. Include foo ist das selbe wie eval file_get_contents foo, also jedesmal, wenn du etwas eingibst, begehst du die Todsünde von eval.