Ein Benutzer darf beliebige mathematische Gleichungen eingeben (mit einer Variablen):
x + 5
1 - x/2
(x/3) * (56/13)
Diese werden als Strings in der Datenbank gespeichert. Wenn sie abgerufen werden, muss ich "x" für eine Zahl ersetzen und den Wert der Gleichung überprüfen.
Wie könnte ich das tun?
Ich habe erwogen, einen Parser zu schreiben, um die Strings zu dekonstruieren und sie in Gleichungen umzuwandeln, aber das klingt teuer und problematisch. Die andere Möglichkeit besteht darin, sie durch eval zu leiten (aber ich bin kein großer Fan von eval, wenn ich ihm helfen kann).
Irgendwelche Ideen?
UPDATE: Ich muss auch in der Lage sein, den booleschen Wert von etwas wie "(x & gt; 5)" zu erhalten. Dies ist mit evalMath
nicht möglichUPDATE 2: Ich muss viele davon eine Sekunde abfeuern. Ich habe in PHP nach eval geschaut, kann es aber nicht dazu bringen, einen booleschen Wert für (5 & gt; 4) zurückzugeben, aber ich bemerkte, dass js es tun würde ... vielleicht sollte ich node.js untersuchen ...
UPDATE 3: Nachdem ich ein wenig Spaß dabei hatte, node.js auszuprobieren (und es zum Laufen zu bringen), ging ich zurück und bekam eval, um in PHP zu arbeiten, siehe: Kann php eval einen booleschen Wert zurückgeben?
Also werde ich mit eval mit einem sehr sehr hardcore Filter auf Benutzereingaben gehen.
Eval ist nicht böse !!!!!
Ja, es kann Ihr System komplett stopfen, wenn Sie schlechten Code schreiben - aber neuere PHP-Versionen können einen ungültigen Ausdruck parsen, ohne das ganze Skript zu stürzen. Und es gibt viele andere Möglichkeiten, Ihr System durch das Schreiben von schlechtem Code zu entlarven.
Das lässt nur die Möglichkeit von Code-Injection-Angriffen - was leicht vermieden werden kann, indem ein preg_replace auf jedem Tag ausgeführt wird, der kein sicheres Zeichen ist (zB 0 .... 9, (,), +, -, *, / , ^,.)
Meine Standardantwort auf diese Frage, wann immer sie auftaucht:
Benutze eval nicht (vor allem, weil du feststellst, dass dies eine Benutzereingabe ist) oder erfinde das Rad neu, indem du deinen eigenen Formel-Parser schreibst.
Sehen Sie sich die evalMath Klasse von PHPClasses an. Es sollte alles tun, was Sie hier aufgelistet haben.
BEARBEITEN
re: Leider behandelt evalMath keine Dinge wie (x & gt; 5)
Ändern Sie die Zeilen 177-179 zu
%Vor%Ändern Sie die Zeile 184 nach
%Vor%hinzufügen
%Vor%nach Zeile 321
und evalMath behandeln jetzt (x & gt; 5), (x & lt; 5) oder (x = 5)
%Vor%Weitere Bearbeitung
Verpasste Zeile 307, die geändert werden sollte, um zu lesen:
%Vor%Wenn Sie mit Benutzereingaben zu tun haben, würde ich mich von eval fernhalten. Schreiben Sie einen Parser und brechen Sie die Formel in verschachtelte Arrays.
%Vor%wird
%Vor%Es ist ein wenig schwierig, den Parser zu schreiben, aber es ist wirklich einfach, eine geparste Formel auszuwerten.
etwas riskante Möglichkeit, wenn Sie Ihren Code auf einer Linux-Box ausgeführt wurde, verwenden Sie den Befehl bc (Achten Sie darauf, Ihre Eingaben ordnungsgemäß zu entkommen, bevor Sie es an das System cmd). Ich kann nicht sagen, System zu verwenden ist viel besser als die Risiken von Eval, also erwarte ich einige downvotes hier.
Auch wenn du eval passierst, musst du x durch eine Zahl ersetzen. Die Art von Strategie, die ich haben würde, besteht darin, einen Wert für x zu übergeben und zu sehen, was der bewertete Wert ist. Wenn es mehr als 0 ist, würde ich eine kleinere Zahl versuchen, und wenn es kleiner als 0 ist, würde ich eine größere Zahl rekursiv versuchen, bis es eine Fehlergrenze (& lt; & gt; & gt; 0,001%) erfüllt.
Hängt davon ab ...
Welche Komplexität wird es akzeptieren? Weil für allgemeine mathematische Gleichungen (wie die, die Sie gepostet haben), sehe ich nicht zu viel Problem beim Schreiben eines Parsers. Die wichtigste problematische Frage wäre, die Zahlen zu runden und die richtigen Klammern zu setzen.
Aber wenn die Gleichungen "fortgeschrittene" Eingaben akzeptieren, wie {[()]}, oder X², X³, oder weiter kommen, Differentialrechnung und Mathematik, so können die Dinge verrückt werden.
Wenn die Komplexität die symbolische Handhabung erreicht, versuchen Sie, etwas über CAS (Algebra-Systeme berechnen) zu lesen und zu suchen.
Natürlich empfehle ich Ihnen dringend, Ihr eigenes System für Eingaben zu erstellen, dagegen zu validieren und Benutzer zu evangelisieren, um Eingaben an sie zu binden. Nichts zu komplex, aber genug, um Sie (und andere) komfortabel und sicher zu erreichen, was Sie brauchen.
eval ()
Hängt davon ab, was Sie tun müssen, aber der billigste Weg ist die Verwendung einer Replace-Funktion für die Variablen und die Ausführung des Ausdrucks mit eval ().
Natürlich müssen Sie zuerst sicherstellen, dass Ihre Formeln in PHP-Syntax sind.
Die gute Sache ist, dass Sie jede mathematische Funktion verwenden können, die von PHP unterstützt wird, die schlechte Sache ist, es ist nie nett, das eval () zu verwenden :)
PHPClasses
Die andere gute Option ist das Surfen im Internet, bis Sie einen Parser finden: P Ссылка