"We are back" « oc.at

Photogallery (php,mysql)

fatmike182 15.04.2008 - 11:42 3468 39
Posts

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
ok, hab aber dennoch eine kleine Frage. Nachdems die praktische funktion getimagesize gibt welche ich in weiterer Folge in der fernen Zukunft dazu verwenden könnt um zu schaun wie ich die Bilder automatisch verkleinern könnte wollt ich Daten über diese Funktion auslesen.

Kurze Erklärung zur Struktur:
Localhost / photo_gallery / 225x168
die index.php liegt in photo_gallery
die Bilder selbst befinden sich in 225x168
$file_count gibt mir die richtige anzahl aus, und auch die erste Zeile von der for-schleife gibt mir sogar die Dateinamen richtig aus, also muss $files[$i] ja auch stimmen.
Jedenfalls bekomm ich aus der if-Abfrage kein true, also getimagesize($files[$i]) ist false.
Warum?
Code: PHP
<?php
	$dir = '/photo_gallery/225x168/';
	$files = scandir($_SERVER['DOCUMENT_ROOT'].$dir);
	$file_count = count($files);

	$sql = mysql_connect('localhost','root','pw');
		if (!$sql)
			{
			die('database suxxx: '.mysql_error());
			};
	mysql_select_db('gallery',$sql) or die('database not selected: '.mysql_error());
	
	
	for ($i=0; $i<$file_count; $i++)
		echo $files[$i]."<br />";
		{
		if ($info = getimagesize($files[$i]))
			{
				echo  "a <br />";
			}
		else 
			{
				echo $info[1]." ".$file_count." b<br />";
			}
	};
	mysql_close($sql);
?>

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4325
du mußt schon den pfad auch angeben.

wenn die index in phto_galery sich befindet und du nur den namen des files übergibst, das jedoch in einem unterordner liegt, kann es schlecht gefunden werden ;)

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
richtig - wollt nur schaun, ob ihr eh auch aufpassts. :D
thx - hab das eh probiert, also die 5 verschiedenen Arten die möglich wären (mit $_Serverblabla, ohne, mit Slash, ohne, ... ) und scheinbar einen Slash zuviel gesetzt.

btw: ich hoff, dass der rename() Befehl auf dem gratiswebspace auch funzt. copy() würd ja nicht gehen & afair enthält rename ja die altbewährte copy/unlink-Methodik.
Bearbeitet von fatmike182 am 16.04.2008, 16:25

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
Hallo,
zunächst möcht ich dir Funktion des Scripts erklären:
...connect.php + browse.php
Wenn das Formular nicht submitted wurde (also Grundzustand) bekommt man eine Tabelle die durch eine for-Schleife alle Bilder aus dem upload-Folder auflistet. Man erhält pro Zeile 2 radiobuttons für neue alben und 2 für bestehende. Außerdem bekommt man ein Textfeld um das Bild zu taggen. Alle 4 Radiobuttons gehören der selben Familie an. Sinn der Sache ist der, dass man ,wenn mann viele Bilder diese gleichzeitig mit nur einem submit 4 verschiedenen Alben zuordnen kann (das script lässt mehr zu, ich finde 4 ausreichend; 2 neue alben & 2 bestehende sind in dem Fall möglich)
Submit gedrückt -> crtl-hidden ist gesetzt, man kommt zur for-schleife ganz oben.

(connect.php)
Code: PHP
<?php
    $sql = mysql_connect('localhost','root','pw');
		if (!$sql)
			{
			die('database suxxx: '.mysql_error());
			};
	mysql_select_db('gallery',$sql) or die('database not selected: '.mysql_error());
	
	$dir = 'photo_gallery/';
	$fromdir = 'upload/';
	$thumbs = 'thumbs/';
	$todir = '225x168/';
	$files = scandir($_SERVER['DOCUMENT_ROOT']."/".$dir.$fromdir);
	$file_count = count($files);
	?>

(browse.php)
Code: PHP
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Photogallery</title>
</head>

<body bgcolor="#999966">
<?php include 'connect.php'; 
if (array_key_exists('crtl',$_POST))
	{
	include 'upload.php';
	} //if crtl-hidden was set; if submitted
else 
	{
?>


<form action="<? $_SERVER['PHP_SELF']; ?>" method="post" name="upload_form">
	<table>
    <thead>
    <tr>
        	<? for ($i=0; $i<2; $i++) {?>
    	<th>
           		<span>new album</span><br />
            	<input type="text" name="<? echo "new_album".$i; ?>" /><br />
            <a>de</a><a>select all</a>
        </th>
            <? };?>
        <th></th>
        <th></th>
        	<? for ($i=0; $i<2; $i++) {?>
        <th>
            	<span>join album</span><br />
            	<select name="<? echo "join_album".$i; ?>">
            	<option value="">---</option>
            	<? $selectalbum = mysql_query("SELECT * FROM albums");
				while ($row = mysql_fetch_array($selectalbum))
					{
					echo "<option value=".$row['albumid'].">".$row['album']."</option>";
					}; ?>	     
            	</select><br />
            	<a>de</a><a>select all</a>
        </th>
        	<? };?>
    </tr>
	</thead>
    <tbody>
	<?php
		for ($i=0; $i<$file_count; $i++)
			{
			if ($info = getimagesize($fromdir.$files[$i]))
				{
				$width = $info[0];
				$height = $info[1];
				$type = $info[2];
				?>
		<tr>
        	<td><input type="radio" name=" <? echo "radio".$i; ?>" value="new_album0" /></td>
            <td><input type="radio" name=" <? echo "radio".$i; ?>" value="new_album1" /></td>
            <td><input type="text" name="<? echo "file".$i; ?>" value="<? echo $files[$i]; ?>" readonly="readonly"/></td>
            <td><input type="text" name="<? echo "tag".$i; ?>" /></td>
            <td><input type="radio" name=" <? echo "radio".$i; ?>" value="join_album0" /></td>
            <td><input type="radio" name=" <? echo "radio".$i; ?>" value="join_album1" /></td>
		</tr>
				<? }
			};
		mysql_close($sql);
	?>
	</tbody>
	</table>
    <input type="hidden" name="crtl" />
	<button type="reset">reset</button>
    <button type="submit">submit</button>
</form>
	<? 
	}; ?>
</body>
</html>

...upload.php
knapp über der Schleife sieht man die Variable addalbum0 bzw 1. Diese wird vor der Schleife auf 0 gesetzt und hat folgende Funktion: Damit ein neu angelegtes Album nur 1x angelegt wird wird nach dem Insert eines neuen Albums in die Tabelle diese Variable auf 1 gesetzt, somit ist die if-Bedingung in Zeile 14 & 26 nichtmehr erfüllt.
Im oberen Teil gehts prinzipiell eh nur darum die Radiobuttons zuzuordnen und daraus die Albumsinfo zu bekommen (albumid bzw vom Namen auf die ID zurückschließen)
Der untere Teil ab 43 macht dann nichts anderes als, dass es dann abfragt ob überhaupt diese id vorhanden ist (diese wird nach dem Eintragen in die Tabelle auf '' gesetzt ... bis ich das überrissen hab hats eh gedauert) und $info von der anfänglichen if-Bedingung holt. Das alles wird in die Tabelle geschriben und die, in der Tabelle erfassten, Bilder 1.) in ein thumb-Verzeichnis kopiert und 2.) in ein anderes Verzeichnis gemoved

(upload.php)
Code: PHP
<?
$addalbum0 = '0'; //if new album gets created, addalbum = 1 -> new album just 1x created
	$addalbum1 = '0';
	for ($i=0; $i<$file_count; $i++)
		{
		$filename = $_POST['file'.$i];
		$tag = $_POST['tag'.$i];
		if (($info = getimagesize($fromdir.$filename)) && array_key_exists('radio'.$i,$_POST)) //only if album selectd & if image format
				{
				$radio = $_POST['radio'.$i]; //possible radio values: newalbum0, newalbum1, joinalbum0, joinalbum1
				if ($radio == 'new_album0' && $_POST['new_album0'] != '') //newalbum0 selected, input-field not empty
					{
					$album = $_POST['new_album0']; //albumtitle from input = $album
					if ($addalbum0 == '0') //if 1st picture from new album: $album -> albums table, afterwards, addalbums = 1 for newalbum0
						{
						mysql_query("INSERT INTO albums (album) VALUES ('$album')");
						$addalbum0 = '1';
						}
					$albumreq = mysql_query("SELECT albumid FROM albums WHERE album like '$album'"); //albumid gets requested either addalbum=0 or 1
					$albumarray = mysql_fetch_array($albumreq);
					$albumid = $albumarray['albumid'];
					}
				elseif ($radio == 'new_album1' && $_POST['new_album1'] != '')
					{
					$album = $_POST['new_album1'];
					if ($addalbum1 == '0')
						{
						mysql_query("INSERT INTO albums (album) VALUES ('$album')");
						$addalbum1 = '1';
						}
					$albumreq = mysql_query("SELECT albumid FROM albums WHERE album like '$album'");
					$albumarray = mysql_fetch_array($albumreq);
					$albumid = $albumarray['albumid'];
					}	
				elseif ($radio == 'join_album0') //radio joinalbum selected, albumid from select-dropdown = $albumid
					{
					$albumid = $_POST['join_album0'];
					}
				elseif ($radio == 'join_album1')
					{
					$albumid = $_POST['join_album1'];
					}
				if (isset($albumid) && $albumid != '') //only if there is an albumid the pictureinfo gets stored in the Database
					{
					$width = $info[0]; //$info see line 18, was created as condition whether image or nor
					$height = $info[1];
					$type = $info[2];
					$insert_image = mysql_query("INSERT INTO images (albumid, filename, date, width, height, type, tag)
						VALUES ('$albumid', '$filename', now(), '$width', '$height', '$type', '$tag')");
					$albumid = ''; //reset albumid, so that the next run doesn't keep the albumid, if it is set, the new id is fetched from $_POST anyway
					if (!$insert_image) //if mysql-insert fails
						{
						die('upload to database failed: '.mysql_error());
						}
					else //mysql_insert successful -> file gets copied to thumbs-directory and moved to $todir:
						{ //won't be listed the next time when browsing since not in upload folder; todir is the later used image-folder for the gallery
						copy($fromdir.$filename, $thumbs.$filename);
						rename($fromdir.$filename, $todir.$filename);
						echo $filename." successfully uploaded and moved to the directory ".$todir."<br />";
						}	
					}	
				} //if radio-button is selected
		} //for loop
?>

Was jetzt noch dazukommt:
- die select/deselect all-Gschichten falls man alle Files von demUploadordner in zB ein bestehendes Album geben will
- thumb-fkt. Das sollt glaub ich flott gehn, also die Bilder die Kopiert werden resizen irgedwie
- ein Feld für die Kurzbeschreibung der neuerstellten Alben
... - eine Albumübersichtsseite, quasi die index.php auf der die Albentitel & die Kurzbeschreibung evtl 3 Beispielthumbs stehen
... - die eigentliche Gallerie

Meine Fragen jetzt:
- warum kann ich, wenn ich die neuen Alben in die albums-tabelle schreiben will nicht das erstellungsdatum eintragen? Hab in der Tabelle 2 weitere Felder: update & create die datetime sind, hab now() per INSERT versucht, aber funzt nicht.
- Welche Befehle sind unschön oder schwachsinnig? Bei den verschachtelten ifs in der Schleife bin ich mir nciht sicher, dass das die eleganteste variante war.
- Gibts codeteile/Befehle die man so nicht verwenden sollte?
- Wie wahrscheinlich ist es, dass das skript auf Freewebspaces mit php5 & mysql Datenbank trotzdem wegen versch. funktionen nicht rennt? (zB copy,... ich glaub das verwendet man ja auch für den Upload, also ist das häufig abgeschalten. evtl wär das ja in dem Fall per Email an den Provider regelbar)
- wie dämlich ist das mit der albumid wenn ich ein neues Album erstell: 2 mysql-abfragen, eine zum eintragen & dann eine zum Nachschaun welche ID das gerade eingetragene eigentlich hat. Soll ichd as lieber per abzählen der Zeilen machen oder so?

dass man sicha uch bissal was drunter vorstellen kann:
click to enlarge
(stylesheet usw kommt ja dann eh noch, geht nur mal um die Funktion)

tia, Michi
PS: bitte Codefladern wo geht & auch Kritik schreiben! Der link zur Initialidee ist in dem Thread & den Rest hab ich dann selbst ausgebaut, aber wie man sicher merkt hab ich schon lang nix mehr in php gemacht.

edit:
weitere Fragen
- bei der Übersicht (die wird nur per Schleife über getimagesize erstellt und steht nicht in einer DB) wärs evtl fürs taggen sinnvoll, wenn man da auch Bilder dabei hätte. Hab noch nie mit php Bilder verkleinert oder sonst was - das ist in dem Fall viel zu langsam, oder?
Wovon hängt die Geschwindigkeit des resizens ab? Würde 800x600 jpgs raufladen und 80x60 würd in dem Fall für die Vorschau reichen.
Bearbeitet von fatmike182 am 17.04.2008, 16:18

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25672
Keine Angst... den Code stiehlt dir keiner. Ist fast unlesbar mit deiner Klammerntechnik. Versuchs mal so:
Code: PHP
if (true)
{
      // *) Something happens here and I actually describe it!
      something();

      // => Exiting because ..
      return nothing();
}
else
// => We have to get out of the loop or something else..
      return anything();
Kommentare und richtig gesetzte Abstände und Klammern wirken Wunder. ;)

Auch noch sehr wichtig: Du castest die Variablen nicht bzw. escapst die Variablen in den SQL-Queries nicht. Das macht deinen Code anfällig für SQL-Injections.

Also:
Code: PHP
$albumid = (int) $_POST['albumid'];
und/oder:
Code: PHP
mysql_query("SELECT * FROM album WHERE albumid=".mysql_escape_string($albumid));
Alles klar?

Zu den Fragen:

  • INSERT mit NOW() bei DATETIME-Variablen funktioniert. Da muss etwas anderes falsch gewesen sein.
  • Bitte mach Funktionen. addAlbum(), deleteAlbum() usw. und der Ablauf wäre um einiges leichter zu erkennen.
  • Siehe SQL-Injections.
  • Ausprobieren und Erfahrung sammeln. Host-unabhängige Anwendungen schreiben sind keinesfalls einfach.
  • mysql_insert_id()

Edit: Bilder verkleinern ist gar kein Problem. Mit den GD2-Funktionen von PHP5 geht das schön schnell (image_...). Am längsten dauert in unseren Breitengraden noch immer der Upload!

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
jo aber meine KLammerntechnik ist zeilensparender... um das gehts doch, oder :cool:

@casten:
tu ich für gewöhnlich, zumindest wenn ichs öfters als nur 1x benötige. War dann bisschen überrascht, dass ich viele öfters brauch. Wird gemacht!
Wie wichtig ist die Deklaration? Wie ich mich vor Jahren in php eingelesen hab war da nie die Rede davon. Hat das Vorteile oder dient das nur der Orientierung?

@escape & SQL injections
muss ich mir noch genauer anschaun, was das heißt. Hab das ehrlich gesagt noch nie so gesehn & keine Ahnung davon. Dachte, dass das mit '$variable' der übliche Weg wäre.

@ Fragen
now(): jo, nochmal überprüfen. evtl einen Schas bei der DB selbst zamgedraht
Funktionen: werd mich bemühen, wird schwierig (aber eine gute Übung
) da ich ja oft von anderen Stellen Variablen übernehm
insert_id(): yeehaaa! thx!

wie oben im edit erwähnt würd ich gern Vorschaubilder haben wenn ich im browse.php drinnen bin um das Tagging sinnvoll/leichter zu machen. Legt das die Seite wegen der Generierung der Thumbs (die 1% der Originale also 80x60 statt 800x600 sind) sehr lahm? Die Bilder selbst sind ja von der Größe her nicht das Problem glaub ich

THX fürs Ausbessern & die Tipps
Werd dich als user of the month vorschlagen ;)

edit:
ok, dann arbeit ich dann doch auch an den Previewbildern. Stichworte zu dem Thema hab ich bereits gefunden, war mir wegen der Generierung nicht sicher. Immerhin sind das ja tw 200 Fotos oder so die auf der browse.php angezeigt werden...
Aja: Vorschläge weden der Umsetzung bzgl Auswählen, also statt den Radiobuttons? Mir schien das kombiniert mit der select all/deselect all die praktischste Umsetzung zu sein. Werd noch die tab-reihenfolge evtl ändern (mal schaun wie das nochmal geht & ob in dem Fall hilfreich)
Bearbeitet von fatmike182 am 17.04.2008, 16:42

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25672
Keine Ahnung was du beim Casten mit den Deklarationen meinst. Prinzipiell geht es nur darum, dass eine Zahl - anders als ein String, der dein MySQL-Query verändern kann - keinen Schaden mehr anrichtet. Gehört also nicht nur zum feinen Coding um im Vorfeld Fehler im Umgang mit den Variablen auszumerzen, sondern auch zum Punkt SQL-Injections, die du dir dringend ansehen solltest!

Das Generieren der Thumbnails machst du ja nur 1x gleich beim Upload. Das legt gar nichts lahm...

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
mit deklarieren hab ich eiegtnlich eh das Casten gemeit...
Ist bei mir glaub ich eh selten da nur selten INTs übergeben werden.

escape_strings hab ich versucht wie guts geht.
aus dem '%s' usw werd ich aber nicht ganz schlau. Ich schätze mal, dass das s für string steht? nach dem Kürzel zu suchen hat ja leider auch keinen Sinn. Wie könnt ich das für die Zeile mit dem Input machen:
Code: PHP
$insert_image = mysql_query("INSERT INTO images (albumid, filename, date, width, height, type, tag)
				VALUES ('$albumid', '$filename', now(), '$width', '$height', '$type', '$tag')");

das hat leider einen error beim Eintragen in die Tabelle gegeben (also eh die query):
Code: PHP
$insert_image = mysql_query("INSERT INTO images (albumid, filename, date, width, height, type, tag)
				VALUES ('$albumid', '%s, now(), '$width', '$height', '$type', '%s')",
mysql_real_escape_string($filename),
mysql_real_escape_string($tag));

nichtmal, wenn ich nur das $tag escape (hab mir gedacht, evtl liegts an der Position oder so). naja, wenigstens weiß ich jetzt was man damit machen könnte. Hab versucht paar Schwachstellen auszubessern, werds aber glaub ich bzgl sql-injections dabeibelassen und spiel ich jetzt mit den previewbildern herum

insert_id war zwar bissi tricky irgendwie aber ich habs mit bissal überlegen überrissen und es funktioniert (wobei mich die usercomments auf php.net schon bisschen abschrecken)

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4325
Code: PHP
$insert_image = mysql_query("INSERT INTO images (albumid, filename, date, width, height, type, tag)
				VALUES ('$albumid', '$filename', now(), '$width', '$height', '$type', '" . mysql_escape_string($tag) . "')");

usw. mit den anderen

hth

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
so funktionierts bei mir eh, aber hab so gemeint wies im bsp1 & 3 gezeigt wird
http://uk.php.net/function.mysql-real-escape-string

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25672
Schau dir die Beispiele mal genau an. Da wird zuerst per sprintf() der String generiert und dann erst das Query abgeschossen.

kleinerChemiker

Here to stay
Avatar
Registered: Feb 2002
Location: Wien
Posts: 4325
oder du verwendest prepared statements

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
Hallo,
das Problem beim Datum in der albums Tabelle (2 Daten: create und update) ist nach wie vor da und nachdem ichs über phpmyadmin versucht hab, hab ich zumindest den Errorcode:
Warning: #1264 Out of range value adjusted for column ....

leider hat mich google zu keiner sinnvollen Lösung gebracht. Das update-felt hab ich in timestamp mit "current_timestamp" als default geädert, create ist nochimmer datetime (und hätte mit now() gefüttert werden sollen)

mat

Administrator
Legends never die
Avatar
Registered: Aug 2003
Location: nö
Posts: 25672
Stimmt die Serverzeit von deinem Dev-Host? Mach mal "SELECT NOW( ) AS curtime" im phpMyAdmin.

fatmike182

Agnotologe
Registered: Oct 2005
Location: VIE
Posts: 4223
2008-04-21 00:17:02 ... bin in GMT und mein Notebook hat die gleiche Zeit eingestellt. timestamp funktioniert ja wie gesagt auch.
Hab nur paar Seiten in fremdländischen Sprachen gefunden, bei denen auch manchmal now() vorgekommen ist... Naja, werd das glaub ich ändern müssen.
(bei den Bildern funktioniert now() aber; hab wahrscheinlich nur einen verdammt deppaden Fehler irgendwo)
Kontakt | Unser Forum | Über overclockers.at | Impressum | Datenschutz