Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Super eval()
pp-layouts
post
Post #1





Grupa: Zarejestrowani
Postów: 53
Pomógł: 1
Dołączył: 28.09.2007
Skąd: Gdynia

Ostrzeżenie: (0%)
-----


Początkowo zadałem pytanie jak rozwiązać problem, i w jakimś amoku sam go rozwiązałem.

Problem jest stary jak PHP. Powiedzmy, że chcemy wykonać wygenerowany kod via eval(), ale nie mamy pewności, że nie spowoduje on błędu fatalnego - kładąc główny kod. Po co? Ja na przykład zrobiłem kompilator własnego języka. Nie będę się już wdawał w szczeóły po co. Był potrzebny i już. Klient zamówił - klient dostał. Problem jednak w tym, że klient skrypty w tym nowym języku musi dość często aktualizować. W dodatku klient nie jest programistą. Dlatego język skryptu maksymalnie przypomina naturalny język polski. Nie udało się jednak uciec przed jakąś podstawową składnią, w końcu to też język programowania, który w dodatku robi dość skomplikowane operacje na danych. Jeśli w skrypcie użytkownika pojawi się błąd, którego nie wykryje mój kompilator - powstanie błędny kod wynikowy, który wysypie kod główny. A to się po prostu nie ma prawa zdarzyć. Klient musi otrzymać informację, że ma w skrypcie błąd, dostać jakąś podpowiedź w postaci np fragmentu kodu, którego nie udało się wykonać. Ważne, żeby dostał informację KTÓRY z kilkunastu skryptów się wysypał. Pozostałe MUSZĄ się wykonać. Używając eval() - niewykonalne.

Prosty test: @eval('return test::test();'); Jeśli nie ma klasy test - kod się sypnie. Nic po eval() się już nie wykona. Bo jak czytałem na StackOverflow - błędy fatalne są fatalne.

Dobra, to teraz rozwiązanie, czyli SUPER EVAL (IMG:style_emoticons/default/smile.gif)

  1. function s_eval($code) {
  2. exec('php -r ' . escapeshellarg("function ___() { $code};echo serialize(___());"), $output, $retval);
  3. return $retval ? $output[1] : unserialize($output[0]);
  4. }
Uwaga: żeby nie było, poprawiłem tą funkcję - dodałem escapeshellarg, inaczej kod by się wysypał od pojedynczego quota.


Funkcja zachowuje się jak zwykły eval() z jednym wyjątkiem: w przypadku błędu fatalnego zwraca komunikat o błędzie jako string. Oczywiście można ją przerobić, żeby zwracała informację o tym, czy wystąpił błąd, i wartość wyjściową, to już kwestia trywialna. Oczywiście pewnie jest to wolniejsze od zwykłego evala, ale jest jedynym sposobem na uruchomienie kodu mogącego zawierać błąd.

Co istotne, w razie błędu zwracany jest właściwy numer linii w której wystąpił. Nie ma żadnych ograniczeń jeśli chodzi o używanie include, require i klas wewnątrz kodu.

Przyda się komuś?

Ten post edytował pp-layouts 14.01.2010, 12:57:46
Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
phpion
post
Post #2





Grupa: Moderatorzy
Postów: 6 072
Pomógł: 861
Dołączył: 10.12.2003
Skąd: Dąbrowa Górnicza




Nie prościej zrobić przycisk pod czas edycji "Uruchom kod", który otworzy np. popup ze skryptem, który wykona wpisany kod. Będziesz od razu widział czy działa czy nie.
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
2 Użytkowników czyta ten temat (2 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Aktualny czas: 10.10.2025 - 07:31