[PHP] Dateiendungen der hochgeladenen Bilder überprüfen

digiTALE

Lt. Junior Grade
Registriert
Juli 2004
Beiträge
270
Hey,

stecke jetzt irgendwie in der klemme. Habe ein Formular wo man ein Bild hochladen kann. Bei der übergabe soll auf die Dateiendung des Bildes überprüft werden.

Nur bekomme ich es nicht hin, das er mir die Datei auf die Endung überprüft. Das Formular habe ich schon mit enctype="multipart/form-data" versehen.

Hier der Codeschnipsel zur Überprüfung:
PHP:
if (isset($_FILES['userbild'])) {

	if ($_FILES['userbild']['type']!="image/gif" && $_FILES['userbild']['type']!="image/pjpeg") {
		print "<b>FEHLER:</b> Die von Ihnen ausgewählte Datei, ist kein Bild.<br><br>";

	} else {
		print "Bild konnte hochgeladen werden";
	}
} else {
	print "Userbild Feld war leer";
}

Wo steckt der Fehler?


mfg digiTALE
 
überprüf den dateinamen der besteht doch aus ner kombination von zeichen + .jpg / .gif

p.s.: welche PHP und MySQL versionen laufen bei funpic? die geben mir über email keine auskunft darüber!
 
das "pjpeg" hat irgendwie die normalen jpeg's nicht erkannt. habe das mitlerweile umgeschrieben.

Die PHP Version auf Funpic ist 4.4.0...

Habe jetzt aber noch ein Problem, die Grösse in bytes zu überprüfen:
PHP:
if (empty($_FILES['userbild'])) {	//Prueft ob das Feld leer ist, ansonsten...
		print "Userbild Feld war leer";
	
} else {
		
	if($_FILES['userbild']['size'] > "10240") {	//Soll pruefen ob das Bild unter 10kb liegt

		if ($_FILES['userbild']['type']!="image/gif" &&
$_FILES['userbild']['type']!="image/jpeg" &&
$_FILES['userbild']['type']!="image/jpg" &&
$_FILES['userbild']['type']!="image/png") {	//Prueft ob die Endungen zulaessig sind...
			print "<b>FEHLER:</b> Die von Ihnen ausgewaehlte Datei, ist kein Bild.<br><br>";

		} else {
				print "Bild konnte hochgeladen werden";
		}
	} else {
		print "Die Datei ist zu gross";
	}
}

So sagt mir die Überprüfung immer das Bild wurde hochgeladen obwohl es über 10kb liegt.
 
Hallo,

eine Überprüfung der Dateien über das "type"-Element des Arrays ist nicht zu empfehlen.
Die entsprechende Angabe wird vom Browser zur verfügung gestellt und kann somit leicht manipuliert werden.
Eine Überprüfung der Dateityps anhand der Dateiendung des Dateinamens ist in diesem Fall die sinnvollere Variante.
Diese kannst du zum Beispiel mit strrchr() und substr() ermitteln.

Da du keine Strings vergleichen möchtest gehören um die "10240" auch keine Anführungszeichen. ;)
Zudem ist die Bedingung falsch herum aufgestellt. So gibt er dir deine Fehlermeldung immer dann aus, wenn das Bild unter der entsprechenden Größe liegt.

MfG mh1001
 
Zuletzt bearbeitet:
und die dateiendung zu ändern ist komplizierter als den mimetype den der browser mitschickt?


wenn die mime funktionen(oder das neue pear modul) von php aktiviert sind wäre es am besten diese zu benutzen. das erschwert das "fälschen" des dateitypes sehr.

ansonsten kann man sich auf die daten des browser ganz sicher noch eher verlassen als auf die des benutzers. jeder weiß wie man eine datei umbenennt, das wissen darum wie man selbst http packete verschickt oder seinen browser manipuliert, ist allerdings nicht besonders verbreitet.
 
Zuletzt bearbeitet:
Siberian..Husky schrieb:
und die dateiendung zu ändern ist komplizierter als den mimetype den der browser mitschickt? [...]
Nein, natürlich ist es das nicht. Eine Dateiendung ist sicherlich schneller getauscht.
Allerdings ging es mir hierbei weniger um die Überprüfung, welchen Inhalt die Datei letzendlich hat, sondern eher darum, den Server vor Angriffen zu schützen, indem zum Beispiel Dateien hochgeladen werden, die dann bei einem Aufruf vom Server geparsed oder entsprechend interpretiert werden (bspw. PHP-Files, .htaccess-Dateien ...).

Wie zuverlässig die mime-Funktionen arbeiten und in wie weit diese durch manipulierte Dateien zu beeinflussen sind kann ich leider nicht sagen, da ich mich damit noch nicht näher beschäftigt habe.

Wenn es nur um Bilddateien geht wäre eine Validierung der Dateien mit der Funktion getimagesize() wohl die sicherste Variante.

Wobei ich bei allen Varianten zusätzlich noch die Dateiendungen überprüfen würde.
Auch eine tatsächliche Bilddatei mit dem Dateinamen ".htaccess" kann auf einen Apache-Server beispielsweise Schaden anrichten. ;)

MfG mh1001
 
Hmm, schade das es immer so ne spezialisten gibt die alles manipulieren müssen.
Mal schauen ob ich das mit den Funktionen strrchr() und substr() hinbekomme

Soweit Funktioniert das Script schoneinmal:
PHP:
if (is_uploaded_file($_FILES['userbild']['tmp_name'])) {	//Prueft ob das Feld einen Wert enthaelt, ansonsten...
		
	if($_FILES['userbild']['size'] < 10240) {	//Soll pruefen ob das Bild unter 10kb liegt
		print "Das Bild hat die richtige groesse";
		
	} else {
		print "Das Bild war zu gross, bitte beachten das das Bild nur 10kb gross sein darf";
	}

} else {
	print "Userbildfeld war leer, der Eintrag wurde trotzdem gespeichert";
		
}

ich meld mich nochmal wenn ich das nicht hinbekomme :lol:

mfg digiTALE
 
mh1001 schrieb:
[...]
Wobei ich bei allen Varianten zusätzlich noch die Dateiendungen überprüfen würde.
Auch eine tatsächliche Bilddatei mit dem Dateinamen ".htaccess" kann auf einen Apache-Server beispielsweise Schaden anrichten. ;)

MfG mh1001


daran hatte ich natürlich garnicht gedacht =). ich hab zwar was solche dinge angeht nicht besonders viel erfahrungen, allerdings wird es wohl so oder so keine gute idee sein die dateien mit ihrem richtigen namen auf dem server zu speichern. schon alein weil es ja durchaus passieren kann das 2 user verschiedene dateien mit den selben namen hochladen wollen.

ich würde also die dateien einfach vortlaufend nummeriert ohne endung in ein verzeichniss speichern, und die "metadaten" wie type, filename und z.b. wers hochgeladen hat in die datenbank packen.


allerdings hast du wohl recht, das eine zustzliche überprüung der dateiendung keine schlechte idee ist.


P.S.: die mime funktionen sind soweit ich weiß in der regel nicht auf sicherheit ausgelegt. es ist also durchaus möglich dieses system zu täuschen. allerdings ist es kompliziert, da man dazu wissen muss wie die einzelnen dateien direkt aufgebaut sind. in in manchen fällen ist es sogar unmöglich. wenn z.b. die dateitypen die man austauschen will beide verschiedene header an der selben stelle im binary haben(in der regel sind die ja ganz vorn ;)) dann kann man das in der regel vergessen.
 
Wie wäre es mit dieser Variante!? Sollte doch noch einwenig sicherer sein.

PHP:
if (is_uploaded_file($_FILES['userbild']['tmp_name'])) {	//Prueft ob das Feld einen Wert enthaelt, ansonsten...
		
	if($_FILES['userbild']['size'] < 10240) {	//Soll pruefen ob das Bild unter 10kb liegt
			
		$format = array("1" => "gif", "2" => "jpg", "3" => "png");
		$upbild = getimagesize ($_FILES['userbild']['tmp_name']);
			
		if ("$upbild[2]" == "$format") {
			print "Das ist ein gueltiges Bildformat";

		} else {
			print "Das Bildformat ist ungueltig. Erlaubt sind nur 'GIF', 'JPG' und 'PNG' Dateien";
		}
		
	} else {
		print "Das Bild war zu gross, bitte beachten das das Bild nur 10kb gross sein darf";
	}

} else {
	print "Userbildfeld war leer, der Eintrag wurde trotzdem gespeichert";
		
}
 
Zuletzt bearbeitet:
Der Ansatz ist auf jeden Fall schon einmal viel besser. ;)
Allerdings ist die Überprüfung des Bildformats nicht ganz richtig - Der Vegleich eines Arrayelements mit einem assoziativem Array wird immer "false" zurückgeben. ;)

Dies könnte zum Beispiel so aussehen:


PHP:
$zulaessige_formate = array(1, 2, 3);
$bildinformationen = @getimagesize($_FILES['userbild']['tmp_name']);

$fehler = true;
            
if ($bildinformationen != false)
{
  if(in_array($bildinformationen[2], $zulaessige_formate))
  {
    print "Das ist ein gueltiges Bildformat";

    $fehler = false;
  }
}

if($fehler)
{
  print "Das Bildformat ist ungueltig. Erlaubt sind nur 'GIF', 'JPG' und 'PNG' Dateien.";
}
MfG mh1001
 
Zuletzt bearbeitet:
Man was für arbeit die ganzen Eingabefelder zu überprüfen und hast nich gesehen.
Das mit dem Bildupload und die nachträgliche Überprüfung hab ich jetzt mit allen wichtigen Kriterien hinbekommen.

So sieht erstmal das Fertige Script aus, das das Bild auf seine Richtigkeit prüft

Edit
<!--
PHP:
if (is_uploaded_file($_FILES['userbild']['tmp_name'])) {	//Prueft ob das Feld einen Wert enthaelt, ansonsten...
		
	if($_FILES['userbild']['size'] < 10240) {	//Soll pruefen ob das Bild unter 10kb liegt...

		$upbild = @getimagesize ($_FILES['userbild']['tmp_name']);

		if($bild[0] < 97 && $bild[1] < 97) {	//Soll pruefen ob die Hohe und Breite unter 96px liegen...

			$format = array(1, 2, 3);
			$fehler = true;
			
			if ($upbild != false) {	//Soll pruefen ob es sich um ein echtes Bild handelt...

  				if(in_array($upbild[2], $format)) {
					print "Das ist ein gueltiges Bildformat";
					$fehler = false;
				}
			}

			if($fehler) {
				print "Das Bildformat ist ungueltig. Erlaubt sind nur 'GIF', 'JPG' und 'PNG' Dateien.";
			} 

		} else {
			print "Die Bildhoehe oder die Bildbreite ist nicht zulaessig.<br />Deine Bildmaße sind $upbild[0]x$upbild[1], zulaessig sind 96x96";
		}
		
	} else {
		print "Das Bild war zu gross, bitte beachten das das Bild nur 10kb gross sein darf";
	}

} else {
		print "Feld war leer, der Eintrag wurde trotzdem gespeichert";
		
}
//-->


@mh1001
Danke, hast mir sehr geholfen. Aber was ich noch nicht so verstehe warum du vor dem getimagesize ein @ vorgesetzt hast!?

mfg digiTALE
 
Zuletzt bearbeitet:
Das @-Zeichen bewirkt, dass im Fehlerfall die Ausgabe einer Fehlermeldung unterdrückt wird.
Da in dem Fall eine Fehlerausgabe nicht nötig ist und nur störend ist, habe ich deswegen das Zeichen vor die Funktion gesetzt.

Jetzt schaut das Script eigentlich ganz gut aus. ;) Ich persönlich würde zwar eher dazu tendiren, die Prüfungen unabhängig vonainander abzuhandeln um dem Benutzer beim Verstoß gegen mehrere Bedingungen gleich eine vollständige Fehlerausgabe bieten zu können, doch das ist immer geschmackssache. ;)

MfG mh1001

/Edit:

Da du Bildinformationen mit getimagesize() zur Überprüfung der Bildgröße bereits schon einmal ermittelst, brachst du diese anschließend nicht noch ein weiteres mal ermitteln. Da genügt es wenn du auf das vorherige Array zurückgreifst.
Die Bedingung zur Überprüfung des Rückgabewertes ist zwar eigentlich nicht unbedingt notwendig, doch habe ich diese deswegen eingesetzt, dass das ganze auch sauberes PHP ist. Ansonsten könnte im Fehlerfall ein Zugriff auf ein Element eines Array erfolgen, welches nicht existiert.
Allerdings macht das ganze auch nur dann Sinn, wenn du dies auch bei der größenüberprüfung machst, indem du diese zum Beispiel auch in die bestehende Bedingung verschiebst. ;)
 
Zuletzt bearbeitet:
mh1001 schrieb:
Jetzt schaut das Script eigentlich ganz gut aus. ;) Ich persönlich würde zwar eher dazu tendiren, die Prüfungen unabhängig vonainander abzuhandeln um dem Benutzer beim Verstoß gegen mehrere Bedingungen gleich eine vollständige Fehlerausgabe bieten zu können, doch das ist immer geschmackssache. ;)

Das wäre natürlich auch nicht schlecht, so gibt es dann kein hin und her wenn das Bild ein paar Kriterien nicht erfüllt. Werde ich dann noch in angriff nehmen. Will erstmal das das ganze steht und dann kann man den Code immer noch optimieren :) .

mfg digiTALE
 
Ich habe noch eine Frage. Ich habe beim Formular noch eine Vorschaufunktion eingebaut. Wenn der Besucher sein Userbild mit angegeben hat, dann soll dies auch temporär!? bei der Vorschaufunktion mit angezeigt werden. Wie kann ich das noch realisieren?

mfg digiTALE
 
Das Arbeiten mit temporären Binärdateien ist immer etwas komplizierter zu realisieren, da gegebenenfalls auch wieder dafür gesorgt werden muss, dass die entsprechenden Daten auch nur temporär gespeichert werden.
Da die Daten sich jedoch mit maximal 10KB relativ klein sind, würde ich - sofern vorhanden - das ganze datenbankgestützt realisieren.
Dabei bietet es sich dann an, die Datei (sofern diese gültig ist), direkt in eine seperate Tabelle zu schreiben und mit einer ID und dem aktuellem Datum zu versehen.
Dann kannst du diese auf der Vorschauseite nach dem Schema ausgeben:
PHP:
<img src="bild.php?bild=<?php echo $id; ?>" alt="Avatar" />
Mit der ID ist die ID gemeint, unter welcher das Bild in der Datenbank hinterlegt ist.
Hinter der Datei "bild.php" müsste dann ein Script stehen, der das Bild anhand der übergebenen ID ausliest und ausgibt und dieses dann am besten nach erfolgreichem senden an den Clienten auch gleich wieder aus der Datenbank löscht.
Damit sich kein unnötiger Datenbalast ansammelt, sollte dann am besten auch gleich noch anhand des Datums überprüft werden, ob noch weitere Datensätze vorhanden sind, die bereits "abgelaufen" sind.

MfG mh1001
 
Zurück
Oben