2009-10-06 15 views
14

Mam aplikację PHP "index.php", która z różnych powodów musi uruchamiać inne skrypty PHP przy użyciu include_once tego innego skryptu. Ten inny skrypt nie jest bardzo stabilny, więc czy istnieje sposób na bezpieczne wykonanie połączenia, które nie powstrzyma dzwoniącego?PHP jest odporne na błędy?

tj:

<?php 

safely_include_once('badfile.php'); // MAY throw syntax error, parse error, other badness 
echo "I can continue execution after error"; 

?> 

(wiem co to zły pomysł, to może być, itd., Pewni, to nie jest produkcja, środowisko rzeczy.)

Odpowiedz

6

można po prostu

@include "fileWithBadSyntax.php"; 

Który z moich szybkich testów działa zarówno w przypadku błędów analizy, jak i błędów generowanych przez trigger_error().

EDYTOWANIE: To jest całkowicie błędne. Zobacz odpowiedź ukradkiem, która jest poprawna, jeśli nieco niepomocna.

+0

Czy praca, czy możliwe byłoby uchwycenie szczegółów błędu za pomocą tego podejścia? –

+0

To podejście uciszy wszystkie błędy. Zobacz odpowiedź KyleFarris dla metody, która będzie łapała błędy i opcjonalnie może utrzymywać je w spokoju (IE, niestandardowa obsługa błędów). –

+0

Rzeczywiście, odpowiedź Kyle'a jest potężniejsza. – timdev

2

Czy można zmienić architekturę i zmienić "badfile.php" w usługę sieciową? Zamiast umieszczać go bezpośrednio w bazie kodu, wywołasz go przez sieć i przeanalizujesz lub umieścisz jego wynik. Pozwoli to uniknąć błędów analizy, możesz także uniknąć potencjalnie szkodliwego kodu, jeśli środowisko badfile.php jest odpowiednio ograniczone (używając safe_mode lub uruchamiając oddzielny proces serwera WWW z ograniczonymi uprawnieniami).

+1

@ pix0r: To z pewnością zadziałałoby, ale w zależności od zakresu jego projektu może być nieco przesadzone i nieeleganckie. – KyleFarris

2

Można zrobić bloku try/catch

<?php 
try { 
    include("someFile.php"); 
} catch (Exception $e) { 
    // Should probably write it to a log file, but... for brevity's sake: 
    echo 'Caught exception: ', $e->getMessage(), "\n"; 
} 
?> 

Teraz będzie to plik tylko wtedy, gdy nie ma błędu. Jeśli wystąpi błąd, po prostu pominie te rzeczy i zapisze wyjątek (np. W komentarzach, najlepiej w pliku dziennika lub czymś podobnym).

o więcej informacji: http://us2.php.net/manual/en/language.exceptions.php

+10

Błąd parsowania zatrzyma PHP w środku dołączonego pliku i nie powróci do bloku 'catch'. – erjiang

+0

Hmm ... masz rację. Shucks. – KyleFarris

-1

W badfile.php można uczynić go zwrócić wartość:

<?php 
//inestable instructions. 


return true; ?> 

następnie na głównym pliku można zrobić:

<?php 

if (require($badFile)) { 
    //if it was true continue with normal execution 
} else { 
    echo "Error: ". error_get_last(); 
} 
36

Żadne te odpowiedzi będą działać. Najwyżej głosowany, który mówi do @include(), będzie nadal kończył pierwszy skrypt, jeśli w dołączonym pliku wystąpił błąd analizy.

Nie można eval() go, nie można spróbować/przechwycić, a każdy sposób wywołania włącza lub wymaga, kończy się wykonywanie w kodzie wszystkich.

To pytanie pozostaje OPEN i UNSOLVED.

http://bugs.php.net/bug.php?id=41810

Jest to błąd w PHP, a ta funkcja jest już brakuje co najmniej od roku 2006. Są one sklasyfikowane błąd jako „fałszywe”, ponieważ, jak twierdzą, zawiera() i wymaga() stało się compile- czas.

To wychodzi poza okno, jeśli generujesz argumenty, które włączają() i/lub wymagają() w RUNTIME, lub robisz eval() przez ciąg zawierający kod, który uruchamia include().

+0

Najlepsza odpowiedź IMHO – Janning

+0

Musi być sposób, że Wordpress jest w stanie to zrobić. Jeśli aktywujesz wtyczkę, która ma błąd składni lub generuje ostrzeżenie/błąd krytyczny, informuje cię o tym i kontynuuje skrypt (wyłączając wtyczkę i wyświetlając komunikat o błędzie). np .: "Wtyczka nie mogła zostać aktywowana, ponieważ spowodowała błąd krytyczny." Wierzę, że robi to poprzez oszustwo iframe, co nie jest idealne. Ale nie jestem pewien. –

+0

Odpowiedź Grabena, używając linii komend tłumacza z flagą '-f', będzie działać. Jest powolny i wygląda na włamywacz, ale robi to. –

-3

Oto jedyne realne rozwiązanie udało mi się znaleźć:

function safe_include($fn) { 
     $fc = file_get_contents($fn); 
     if(!eval($fc)) { 
       return 0; 
     } 
     return 1; 
} 

Zauważ, że powyższy kod oznacza, że ​​trzeba wyjąć sprawozdania otwarcia od do-włączonych plików lub wykonaj następujące:

eval("?>" . $fc) 

Problemem jest to, że nie można nazwać require() lub include() lub ich _once() warianty w dowolnym momencie i nie oczekiwać, żeby zakończyć wszystko, w tym wszelkie obsługą błędów. PHP przestanie całkowicie przetwarzać wszystko, gdy napotka błąd parsowania.

Jedynym wyjątkiem jest ciąg wewnątrz eval(). Problemem jest jednak, że tak naprawdę nie można tego zrobić:

eval('require($fn);'); 

... bo require() wewnątrz łańcucha eval'd będzie nadal zatrzymania. Musisz przeczytać w treści, modlić się, że dany plik nie zawiera() lub wymagają() dalej, i eval() to.

Prawdziwe rozwiązanie? Pomiń PHP. :/

2

Płynnego obejście to-file-not-found ....

 
function safe_require($incfile, $showfn=1) { 
    $a = explode(":", get_include_path()) ; 
    $a[] = ""; 
    $b = 0; 
    foreach($a as $p) { 
    if(!empty($p)) $p .= "/"; 
    $f = $p.$incfile; 
    if(file_exists($f)) { 
     $b = 1; 
     break; 
    } 
    } 
    if(!$b) 
    exit("Cannot proceed, required file " . 
      (($showfn) ? $incfile : "") . " is unavailable or server has timed out." 
     ); 
    require_once("$f"); 
} 
+0

Całkiem niezłe, ale wciąż nie można tego zrobić. Wyobraź sobie, że plik został usunięty po zweryfikowaniu go jako istniejącego .... – Pacerier

10

Jedynym rozwiązaniem, nie myślał najbardziej elegancki jeden, ale działa to zadzwonić do innego tłumacza php, który analizuje i wykonać skrypt dla niczego innego niż sprawdzanie, czy daje on błąd parsowania lub komunikat "Nie wykryto błędów" do filtrowania komunikatów o błędach, takich jak Błąd parse PHP blablabla. jak robi to kod:

<?php 
function ChkInc($file){ 
    return file_exists($file) && (substr(exec("php -l $file"), 0, 28) == "No syntax errors detected in"); 
} 
?> 

Ten pomysł wyszedł od gillis' comment do include funkcji ręcznego na stronie PHP doc.

+2

Jest to obecnie jedyny sposób, aby to zrobić. –

+1

Używanie 'if' do zwracania wartości true lub false?Czy to nie brzmi jak szaleństwo? Co jest nie tak z konwersją twojego rozwiązania na jednolinijkową: 'return (substr (exec (" php -l $ file "), 0, 28) ==" Nie wykryto błędów składniowych w ");'? – trejder

+0

Dobrze, zaktualizowano odpowiedź do wersji z jednym linerem. – Graben

Powiązane problemy