Bekijk Volledige Versie : Ongelukkig php scriptje crasht standaard DA server
Christophe1
17/04/14, 21:30
Hallo iedereen
Graag had ik volgend probleem aangekaart:
Het proberen openen van een niet-bestaande map in php, zorgt voor een apache proces dat ongeveer 90% van de cpu gebruikt en, hoe langer het loopt, ook steeds meer geheugen gebruikt. Een dergelijk proces blijft draaien tot het manueel wordt afgesloten of het hele boeltje uiteindelijk crasht. Geheugenbeperkingen en timeouts die zijn ingesteld in php, lijken niks uit te halen.
Gaat om een vrij standaard directadmin server met Apache 2.2.27, php 5.3.28 en suPHP 0.7.1.
Een identiek scriptje zorgde in vorige versies van Apache (en php) eveneens voor een hoge load, maar slechts tijdelijk. Dergelijke processen werden na een tijdje automatisch beƫindigd en de server ondervond er verder geen hinder van.
Iemand suggesties? Een gekend probleem?
Mvg
Christophe
Hallo iedereen
Graag had ik volgend probleem aangekaart:
Het proberen openen van een niet-bestaande map in php, zorgt voor .....
Iemand suggesties? Een gekend probleem?
Uuum ja, een check inbouwen om te zien of de directory effectief bestaat voor je er iets gaat mee doen :p.
<?php
$dir = '/this/directory/does/not/exist';
if (file_exists($dir)) {
echo "The directory $dir exists";
} else {
echo "The directory $dir does not exist";
}
?>
Of als je echt hardcore wil gaan een try/catch inbouwen met exceptions (dat zoude eigenlijk alle software/programmeurs moeten doen).
Christophe1
17/04/14, 23:28
Dank je wel voor de snelle reactie.
Vanuit programmeer oogpunt inderdaad een goed idee om voor het openen van een map te controleren of die wel bestaat, maar waar het om gaat is dat de server blijkbaar zomaar crasht door dergelijke ongelukkige scriptjes. Klanten gebruiken wel vaker scripts die je eigenlijk liever niet wil draaien...
Dank je wel voor de snelle reactie.
Vanuit programmeer oogpunt inderdaad een goed idee om voor het openen van een map te controleren of die wel bestaat, maar waar het om gaat is dat de server blijkbaar zomaar crasht door dergelijke ongelukkige scriptjes. Klanten gebruiken wel vaker scripts die je eigenlijk liever niet wil draaien...
Dan heb je nog opties genoeg om dat tegen te gaan, ik noem er enkele op: cagefs, ulimits (moet je wel php als user draaien), psacct, jailed, ... of je maakt zelf een scriptje wat bvb elke minuut door middel van cron een "ps aux | grep php" doet en elk script dat meer dan XXMB verbruikt of langer dan XX minuten runt geef je een kill -9.
(dat zoude eigenlijk alle software/programmeurs moeten doen).
Dat vind ik toch redelijk kort door de bocht...
Het opvangen van exceptions is 'duur'. Als het om eenvoudige checks die vaak falen is een 'if' doorgaans toch beter.
Dat vind ik toch redelijk kort door de bocht...
Het opvangen van exceptions is 'duur'. Als het om eenvoudige checks die vaak falen is een 'if' doorgaans toch beter.
En een volledige server die crashed is dan wel acceptabel? Ik zeg toch ook niet dat je elke if, case, while, ... in een apparte try/catch moet steken, maar je kunt wel het grootste stuk van je code waar geen controle op plaats vindt in een try/catch zetten.
Uiteraard is dat beter een try/catch te hebben dan helemaal niets!
Ik had uit je eerste post gewoon opgemaakt dat je try/catch altijd beter achtte dan checken met een if/else...
Met je tweede bericht ben ik het dus wel zeker eens :)
Yourwebhoster
18/04/14, 19:28
Hallo iedereen
Graag had ik volgend probleem aangekaart:
Het proberen openen van een niet-bestaande map in php, zorgt voor een apache proces dat ongeveer 90% van de cpu gebruikt en, hoe langer het loopt, ook steeds meer geheugen gebruikt. Een dergelijk proces blijft draaien tot het manueel wordt afgesloten of het hele boeltje uiteindelijk crasht. Geheugenbeperkingen en timeouts die zijn ingesteld in php, lijken niks uit te halen.
Gaat om een vrij standaard directadmin server met Apache 2.2.27, php 5.3.28 en suPHP 0.7.1.
Een identiek scriptje zorgde in vorige versies van Apache (en php) eveneens voor een hoge load, maar slechts tijdelijk. Dergelijke processen werden na een tijdje automatisch beƫindigd en de server ondervond er verder geen hinder van.
Iemand suggesties? Een gekend probleem?
Mvg
Christophe
Los van de controle zou dit niet PHP moeten opslokken en zou je een fout in PHP krijgen. Heb je een code voorbeeld?
Christophe1
18/04/14, 23:21
Code voorbeeld:
<?php
$dir = "onbestaande-map";
$dh = opendir($dir);
while (false !== ($filename = readdir($dh)))
{
$files[] = $filename;
}
?>
In het proces-overzicht duikt zoals verwacht een proces op dat draait onder de user van de hostingaccount en hier zie ik dus ook welk script voor problemen zorgt (laat ons dit proces 1 noemen). Naast dit 1ste proces, is het een ander proces dat draait onder user Apache dat voor de hoge load zorgt (laat ons dit proces 2 noemen).
Normaalgezien wordt proces 1 na een tijdje gestopt door de beperkingen die zijn ingesteld in php.ini, waardoor proces 2 vervolgens normaliseert.
Het script in kwestie waaruit ik bovenstaand stukje code heb gekopieerd, draait al jaren en zorgde nooit voor problemen.
Sinds ik Apache heb geupdate naar versie 2.2.27 (en ik tegelijkertijd ook php heb geupdate naar versie 5.3.28 - ik weet niet in hoeverre dit er eventueel ook mee te maken zou kunnen hebben), wordt proces 1 niet meer gestopt door de beperkingen die zijn ingesteld in php.ini en blijft proces 2 draaien tot de server crasht.
Yourwebhoster
19/04/14, 09:25
Code voorbeeld:
In het proces-overzicht duikt zoals verwacht een proces op dat draait onder de user van de hostingaccount en hier zie ik dus ook welk script voor problemen zorgt (laat ons dit proces 1 noemen). Naast dit 1ste proces, is het een ander proces dat draait onder user Apache dat voor de hoge load zorgt (laat ons dit proces 2 noemen).
Normaalgezien wordt proces 1 na een tijdje gestopt door de beperkingen die zijn ingesteld in php.ini, waardoor proces 2 vervolgens normaliseert.
Het script in kwestie waaruit ik bovenstaand stukje code heb gekopieerd, draait al jaren en zorgde nooit voor problemen.
Sinds ik Apache heb geupdate naar versie 2.2.27 (en ik tegelijkertijd ook php heb geupdate naar versie 5.3.28 - ik weet niet in hoeverre dit er eventueel ook mee te maken zou kunnen hebben), wordt proces 1 niet meer gestopt door de beperkingen die zijn ingesteld in php.ini en blijft proces 2 draaien tot de server crasht.
Het probleem met je code is dat je een loop veroorzaakt die niet stopt. Daarom moet je een check inbouwen of de map wel bestaat. Met PHP 5.4.24 (zonder Apache aan te raken) heb je hetzelfde probleem.
Normaal staat PHP ingesteld om na 30 seconden te stoppen of kom je tegen het geheugenlimiet aan. Hier gaan dus een aantal dingen fout:
1. Slecht programmeerwerk: altijd validatie uitvoeren voordat je daadwerkelijk iets met het stukje code doet.
2. Zorg dat die beperkingen gehandhaafd worden. Het kan zijn dat ergens in het script of een .htaccess dit tegen gegaan wordt.
De beperkingen gelden ook voor cli commando's tenzij je afwijkende instellingen geeft bij de commando.
Christophe1
19/04/14, 10:03
Ik weet dat dit slecht programmeerwerk is, maar dat is het punt hier niet. Scriptje is gewoon een voorbeeld.
Feit is dat de server blijkbaar crasht door het eerste het beste ongelukkige scriptje van een klant. En dat sinds de update naar apache 2.2.27 en php 5.3.28. Voor deze update is er een nooit een probleem geweest, werden deze scripts met oneindige loop correct automatisch afgesloten.
Verder geen speciale code of htaccess bestanden die instellingen overrulen. Mensen met een min of meer standaard DA server die met deze versies van apache en php werken, probeer gerust zelf; plak m'n voorbeeldje even in een bestand, voer het via je browser uit en je zal zien...
Yourwebhoster
19/04/14, 10:46
Ik weet dat dit slecht programmeerwerk is, maar dat is het punt hier niet. Scriptje is gewoon een voorbeeld.
Feit is dat de server blijkbaar crasht door het eerste het beste ongelukkige scriptje van een klant. En dat sinds de update naar apache 2.2.27 en php 5.3.28. Voor deze update is er een nooit een probleem geweest, werden deze scripts met oneindige loop correct automatisch afgesloten.
Verder geen speciale code of htaccess bestanden die instellingen overrulen. Mensen met een min of meer standaard DA server die met deze versies van apache en php werken, probeer gerust zelf; plak m'n voorbeeldje even in een bestand, voer het via je browser uit en je zal zien...
Zie daarvoor
2. Zorg dat die beperkingen gehandhaafd worden. Het kan zijn dat ergens in het script of een .htaccess dit tegen gegaan wordt.
De loop zal een een geheugen limiet halen of de uitvoertijd tenzij deze enorm hoog gezet zijn. Daar moet je naar kijken en die limieten zijn er met een reden. Dan krijg je met Apache het volgende in de logs:
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Warning: readdir() expects parameter 1 to be resource, boolean given in /path/to/file.php on line 6
[Sat Apr 19 10:43:30 2014] [error] [client ip] PHP Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /path/to/file.php on line 6
In het proces-overzicht duikt zoals verwacht een proces op dat draait onder de user van de hostingaccount en hier zie ik dus ook welk script voor problemen zorgt (laat ons dit proces 1 noemen). Naast dit 1ste proces, is het een ander proces dat draait onder user Apache dat voor de hoge load zorgt (laat ons dit proces 2 noemen).
Draai je mod_ruid?
Christophe1
19/04/14, 11:09
Probleem is net dat de ingestelde limieten niet gehandhaafd worden...
Voor de update van apache en php wel.
In de logs lijk ik deze errors overigens niet te krijgen.
Draai geen mod_ruid. Wel suPHP.
Yourwebhoster
19/04/14, 18:55
Probleem is net dat de ingestelde limieten niet gehandhaafd worden...
Voor de update van apache en php wel.
In de logs lijk ik deze errors overigens niet te krijgen.
Draai geen mod_ruid. Wel suPHP.
Stuur anders een pb dan kijk ik hier even naar.
Hier ook geen einde door max execution time, maar wel:
Fatal error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 36 bytes)
systemdeveloper
19/04/14, 23:18
Mja, onkunde mbt. de werking van php is geen 'probleem' natuurlijk. Dit is een schoolvoorbeeld van wat je niet moet doen. Want het is een scriptje dat gemaakt lijkt om foute foutafhandeling, validatie en memoryleaks in amper 4 regels php te stoppen.
Het probleem is dat je server op zijn bek gaat als iets of iemand al je resources ( ram of cpu ) opvreet.
Dit kun je voorkomen door bv. cloudlinux te gebruiken, iets met ulimit te spelen, eventueel mpm_itk te gebruiken als vervanger voor suphp (wat overigens in CGI mode, default een unlimited execution time heeft, niet die 30 seconden van de CLI versie, dus wellicht komt je er ver mee weg om de juiste configfiles even aan te passen.).
Cloudlinux is op dat gebied wel goed op weg. Er zijn meerdere manieren om het te limiteren, maar daar komt behoorlijk wat bij kijken om het goed voor elkaar te krijgen als je niet direct met wat kernelpatches aan de gang kunt maar het zelf moet verzinnen.