Gå til innhold

Lagre mye info i arrays. Problemer.


Anbefalte innlegg

Hei.

 

En liten bakgrunn for koden min. Jeg har ca 30 bilder som jeg ønsker å vise fram. Disse skal hentes inn. Jeg lagrer info om tittel, filnavn og beskrivelse i en/et array. Via $_GET viser jeg ønsket bilde. Bildene er lagret flatt og vises via "filename"-greia i arrayene.

 

Et lite utdrag:

<?php

$bilder = array();

$get_query = "SELECT * FROM bilder";

$result = mysql_query($get_query) or die(mysql_error());

while($row = mysql_fetch_array($result)) {

$imgID 		= $row["imgID"];
$imgNavn	= $row["imgNavn"];
$imgFNavn	= $row["imgFNavn"];
$imgBeskr	= $row["imgBeskr"];

// Putter DB-resultat inn i arrays....
$bilder[$imgID] = array(
'filename' 		=> $imgFNavn, 
'title' 		=> $imgNavn,
'description' 	=> $imgBeskr
);
}
?>

 

Det erstater i grunn alle arrayene jeg må skrive manuelt tidligere. Jeg kunne jo tråla gjennom mysql-resultatet og printa ut det jeg trengte, men da får jeg ikke sortert miniatyrbildene i den rekkefølgen jeg vil (derfor putter jeg resultatet i arrays igjen).

 

Spørsmålet er, er dette "riktig"? Slik jeg forstår, vil jo mysql_fetch_array returnere en array.. Blir dette smør på flesk? Håpløs kode?

Endret av dan1el
Lenke til kommentar
Videoannonse
Annonse

Den koden er elendig, med tanke på optimisering og koding.

  • Du bruker extract
  • Du bruker globals
  • Du henter alle bildene, uansett om de blir vist eller ikke

Her er den måten jeg ville ha gjort det på:

<?php
/*
	Database:

	CREATE TABLE images(
		id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY UNIQUE,
		name VARCHAR(64) NOT NULL,
		description VARCHAR(512) NOT NULL,
		file VARCHAR(128) NOT NULL,
		cat_id INT(11) NOT NULL
	);

	CREATE TABLE categories(
		id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY UNIQUE,
		name VARCHAR(64)
	);
*/
if(isset($_GET['category'])){
	$sql = null;
	if(is_numeric($_GET['category'])){
		$sql = "SELECT id, name, file FROM images WHERE cat_id = {$_GET['category']};"; // SQL injection is not a problem as category is an integer
	} else {
		// Can this be done in one query?
		$cat = mysql_real_escape_string($_GET['category']);
		$sql = "SELECT img.name, img.file FROM categories cat, images img WHERE cat.name = '{$cat}' AND img.cat_id = cat.id;"; // 
	}
	$q = mysql_query($sql);

	if(mysql_num_rows($q)){
		while($row = mysql_fetch_assoc($q)){
			// TODO: echo HTML
		}
	} else {
		echo 'No images (Invalid category?)';
	}
} else if(isset($_GET['image'])){
	$sql = null;

	if(is_numeric($_GET['image'])){
		$sql = "SELECT name, desc, file FROM images WHERE id = {$_GET['image']};"; // SQL injection is not a problem as image is an integer
	} else {
		$img = mysql_real_escape($_GET['image']);
		$sql = "SELECT name, desc, file FROM images WHERE name = '{$img}';";
	}

	$q = mysql_query($sql);
	if(mysql_num_rows($q)){
		list($name, $desc, $file) mysql_fetch_array($q);
		// TODO: echo HTML
	} else {
		echo 'Image not found';
	}
}
?>

 

PS: Det er ikke meningen å være frekk eller noe.

 

EDIT: Fiksa is_int (Takk, Ernie)

 

EDIT #2: Fiksa på tabellen (desc er et reservert ord) + bare en query for å finne bilder fra kategorinavn

 

EDIT #3: Testet SQLen http://pastebin.com/f384f08cb

Endret av itsmebth
Lenke til kommentar

Den koden din vil jo ikke fungere siden du bruker is_int (nei, tall som kommer via $_GET/$_POST/$_COOKIE blir ikke automagisk til en int nei ;)). is_numeric derimot ...

 

Red.: Forøvrig, siden du er litt opptatt av optimalisering her, så vil nok en JOIN passe bedre enn å kjøre to separate spørringer.

Endret av Ernie
Lenke til kommentar

Hei.

 

Takk for svar, men jeg tror du gjorde ting litt mer komplisert enn jeg hadde tenkt. Jeg har ikke kategorisert bildene. Hvis jeg eventuelt kommer til å gjøre det, bruker jeg ganske enkelt flere tabeller i databasen.

 

Og for å svare på "tiltale". Grunnen til at jeg henter alle bildene, er nettop fordi jeg *trenger* alle bildene. Som du ser ut i fra min første post, lager jeg miniatyrer av de bildene jeg vil, i den rekkefølgen jeg ønsker. Og jeg viser til slutt "hovedbildet".

 

Her har du/dere et eksempel av hele min side, som fungerer med arrays:

http://pastebin.no/3191

 

Og, hva er dårlig med extract? Finnes det andre lure måter å hente ut info fra arrays og putte de i variabler? Global trenger jeg for at funksjonen printThumb skal få bruke $imgdir.

 

 

Hele poenget mitt er altså å erstatte array-måten å lagre data om bildene på, med databaser. Det mest ideelle hadde vært å brukt SQL-spørringer hele veien, men da blir det ganske komplisert å lage minatyrbildene i den rekkefølgen jeg ønsker. Jeg vil ikke lage ett ekstra felt i databasen som "prioritet" eller lignende. Det blir bare kluss.

 

Her kan dere se sida mi i praksis:

http://danielforsbakk.com/div/new/1/

Endret av dan1el
Lenke til kommentar

Vel, hvis du skal ha alle ut uannsett hva så er det jo intet poeng å dytte det inn i en database. Da vil det være mye enklere å bare dytte de inn i en fil på disk på et format ala dette:

id|tittel|filnavn|beskrivelse
superduperunikid|enda en tittel|fil|en eller annen beskrivelse

osv.

 

For å hente det ut er det ikke stort verre en å lese en linje (hint: fgets) og bruke explode for å dytte det inn i en array ala. den du har fra før.

 

Det siste der kan vel skrives noe ala dette (ikke ta koden for god fisk, jeg er trøtt og koden er utestet):

$linje = explode('|', $linje, 4);
$array[$linje[0]] = array('filename'	=> $linje[2], 
					  'title'	   => $linje[1],
					  'description' => rtrim($linje[3])	//Rtrim fordi det er et linjeskift 
					  );								   // som kanskje ikke er så ideelt å få med;)

Mangler såklart innlesing av fila da, men litt må du gjøre selv :p

 

Red.: Ja, og som en bonus er det høyst sannsynligvis raskere enn å lagre det som en PHP-array på fil.

Endret av Ernie
Lenke til kommentar

Hvis du først skal ha det i en fil er det enkleste å ha det i en komma separert liste som dette:

"brannmann","brannmann.jpg",Brannmann,""
"katt","katt.jpg",Katt,""
[...osv...]

 

Dette kan ganske enkelt hentes ut med en fin funksjon PHP har som heter fgetcsv():

$images = Array();
$filressurs = fopen("minBildefil.csv", "r");
while ( ($a /*En linje i fil, som array*/ = fgetcsv($filressurs)) !== false ) {
 list($id, $filnavn, $tittel, $beskrivelse) = $a;
 $images[$id] = Array(
"filename"	=> $filnavn,
"title"	   => $tittel,
"beskrivesle" => $beskrivelse
 );
}

Nå burde du ha samme array som du hadde i PHP fila di før, bare innlest fra fil.

 

Og btw, fgetcsv() kunne også bli brukt på Ernies kode, men da bare med en parameter som styrer hvilket tegn seperatoren er. Fordelen med fgetcsv i forhold til explode i denne sammenheng er at explode ville fått problemer hvis linjen innehold seperator midt i en string, som egentlig ikke var ment som en seperator... F.eks. om linjen er : "bildeId", "filnavn.jpg", "Skogen", "Dette er et fint bilde, tatt i skogen". Explode ville her sittet igjen med en array med lengde 5, mens fgetcsv ville hatt riktig lengde på 4. (Dvs, ser at explode var limted i Ernies kode, så han hadde sittet igjen med halve beskrivelsen). At seperatoren var | minsker jo denne faren, men utelukker den ikke.

 

 

 

Når det gjelder utskriving av thumb bildene dine burde ordet "løkke" eller "loop" dukke opp når man gjør en ting mange ganger :-) Så en enklere løsning på utskriften av bildene, så lenge bildene nå ligger i riktig rekkefølge i CSV filen, er:

foreach ( $images as $imgId => $imgArray ) {
 /**
  * Jeg velger og sende inn $array'et her også, som altså inneholder
  * filnavn, tittel og beskrivelse, for da kan du f.eks. bruke tittelen i
  * img-tagens alt-atributt :-)
  */
 printThumb($imgId, $imgArray);
}

Disse 3 kodelinjene burde altså gjøre samme nytte som:

 

120 <ul id="thumb">

121 <?php

122

123

124 printThumb("utforsker");

125 printThumb("katt3");

126 printThumb("smil");

127 printThumb("brannmann");

128 printThumb("katt2");

129 printThumb("nysgjerrig");

130 printThumb("hoyfrekvens");

131 printThumb("barn");

132 printThumb("katt");

133 printThumb("jaggu");

134 printThumb("trapper");

135 printThumb("portrett");

136 printThumb("nam");

137 printThumb("barn2");

138

139 ?>

140 </ul>

 

 

Helt til slutt: Jeg hadde valgt database til å holde på informasjonen hvis jeg hadde hatt mulighet til det. Dette er mye mer utvidbart, og man kan enklere holde på informasjon som statistikk, dele opp i kategorier osv etterhvert hvis det er ønskelig.

Endret av luxus
Lenke til kommentar
Og btw, fgetcsv() kunne også bli brukt på Ernies kode, men da bare med en parameter som styrer hvilket tegn seperatoren er. Fordelen med fgetcsv i forhold til explode i denne sammenheng er at explode ville fått problemer hvis linjen innehold seperator midt i en string, som egentlig ikke var ment som en seperator... F.eks. om linjen er : "bildeId", "filnavn.jpg", "Skogen", "Dette er et fint bilde, tatt i skogen". Explode ville her sittet igjen med en array med lengde 5, mens fgetcsv ville hatt riktig lengde på 4. (Dvs, ser at explode var limted i Ernies kode, så han hadde sittet igjen med halve beskrivelsen). At seperatoren var | minsker jo denne faren, men utelukker den ikke.

Ser du det 4-tallet jeg har satt som 3. parameter i explode? Den sier at jeg vil ha 4. elemeneter ut. Dvs. når explode har funnet den 3. separatoren så lar den resten av strengen være det 4. elementet, ergo vil jeg bare få problemer hvis id, filnavn eller tittel inneholder separatoren. Det er vel ikke akkurat så sannsynlig, eller hva? ;)

Endret av Ernie
Lenke til kommentar
Ser du det 4-tallet jeg har satt som 3. parameter i explode? Den sier at jeg vil ha 4. elemeneter ut. Dvs. når explode har funnet den 3. separatoren så lar den resten av strengen være det 4. elementet, ergo vil jeg bare få problemer hvis id, filnavn eller tittel inneholder separatoren. Det er vel ikke akkurat så sannsynlig, eller hva? ;)

 

Ja, jeg ser 4 tallet (da jeg også kommenterte det), men jeg tok dog feil da jeg trodde limit begrenset antallet til 4 og kappet vekk resten. Sannsynlig eller ikke; som jeg sa: Siden du har valgt | til seperator er ikke sannsynligheten så stor for at dette skal inntreffe, men sjansen er tilstedet og generelt sett ville jeg derfor valgt å bruke en innebygget funksjon som er laget spesifikk til denne jobben, og som ikke minst utelukker problemet, istedenfor explode :-)

Lenke til kommentar

Hei. Takker for svar og engasjement!

 

Metoden med å putte data inn i tekstdokumenter virker veldig lur. Det er mulig jeg går for den. Når det gjelder foreach-løkka for å skrive ut alle miniatyr-bildene, så vil den etter hva jeg forstår, skrive ut bildene i den rekkefølga som ligger i tekstdokumentet. Det er forsåvidt et OK kompromiss.

 

Tilbake på databaser-løsningen min... ville ikke mitt noe ambisiøse forsøk ha gjort biffen?

$bilder	  = array();
$get_query   = "SELECT * FROM bilder";
$result	  = mysql_query($get_query) or die(mysql_error());

while($row = mysql_fetch_array($result)) {

 $imgID	   = $row["imgID"];
 $imgNavn	 = $row["imgNavn"];
 $imgFNavn	= $row["imgFNavn"];
 $imgBeskr	= $row["imgBeskr"];

 $bilder[$imgID] = array(
 'filename'	=> $imgFNavn, 
 'title'	   => $imgNavn,
 'description' => $imgBeskr);
}

 

Grunnen til at jeg putter resultatet tilbake i arrays, er for å kunne sortere miniatyrbildene (med den omtalte printThumb-funksjonen =p). Jeg har ikke funnet noen annen løsning.

 

Når jeg tenker meg om, er det kanskje hensiktsmessig å bruke noe Ala SELECT imgID FROM bilder WHERE imgID = '$get...', isteden for explode?

 

Og helt til slutt, dette er første gang jeg bruker mysql og arrays, så hold ut =p.

Lenke til kommentar

Joda, din databaseløsning er helt grei :) Litt nedkutting av kode som faktisk trengs:

$bilder	= array();
$get_query = <<<EOSQL
 SELECT imgID, imgFNavn AS filename, imgNavn AS title, imgBeskr AS description
 FROM bilder
EOSQL;

$result = mysql_query($get_query) or die(mysql_error());

/**
* fetch assoc henter ut bare assosiativ array (altså $row["kolonnenavn"]) istedenfor fetch array
* som også henter ut $row[0] -> første kolonne osv.
*/
while($row = mysql_fetch_assoc($result)) {
 $imgID		  = array_shift($row);
 $bilder[$imgID] = $row;
}

I SQL queryen har jeg renamet kolonnenavnene til å matche dine opprinnelige nøkkelnavn i bildearrayet.

 

Sortering kan du forresten fikse ved å legge til en kollone til i databasen med navn sortering eller noe. Så fyller du inn 1, 2, 3, 4 osv slik at når du henter ut bildene kan du ha en SQL query som er:

SELECT kolonne1, kolonne2 osv.. FROM bilder ORDER BY sortering.

 

Når du først henter ut alle bildene kan du like godt bare hente ut bildet som skal vises ved å hente ut bilde-data i fra bilde-arrayet ditt, og ikke bruke en SQL setning til med WHERE.

Endret av luxus
Lenke til kommentar
  • Hvordan vil du sortere bildene?
  • Så vidt jeg ser sorterer ikke printThumb

Bildene blir "sortert" i den grad at jeg velger hvilken rekkefølge de vil komme i. Altså, i hvilken rekkefølge jeg bruker printThumb på miniatyrbildene.

 

printThumb("barn");

printThumb("katt");

printThumb("jaggu");

 

Her vil altså barn komme først, så katt og til slutt jaggu. Det er bare å flytte funksjonen ett hakk opp/ned og vips så er rekkefølgen forrandret. Egentlig ikke så vanskelig =p. Hadde jeg brukt en foreach ville den tråla gjennom arrayen og returnert bilder sortert etter kritierier som alfabetisk, numerisk osv...

 

 

@luxus: Slik jeg forstår det, får jeg da en array som ser slik ut: $bilder['1'] = array("katt.jpg", "Katt", "En kul katt"), siden fetch_assoc høvler vekk "titler" og array_shift fjerner $imgID. Koooorrekt?

 

Dersom Ja: Det vil isåfall skape litt trøbbel med extract... leste nettopp om list. Kunne jeg brukt list = ($filename, $title, $desc) = $bilder['1']; for å putte ting i variabler? Eller er jeg helt på jordet nå?

 

PS: Sitter på jobb, så jeg får ikke testa kode :)

Endret av dan1el
Lenke til kommentar
@luxus: Slik jeg forstår det, får jeg da en array som ser slik ut: $bilder['1'] = array("katt.jpg", "Katt", "En kul katt"), siden fetch_assoc høvler vekk "titler" og array_shift fjerner $imgID. Koooorrekt?

 

Nei, du sitter igjen med et array som har beholdt nøklene sine. fetch_assoc fjerner ikke titler/nøkler i arrayet, det beholder nøkler lik kolonnenavn som du har i SQL spørringen. Derfor valgte jeg også i SQL spørringen jeg skrev å bruke "kolonnenavn AS etAnnetNavnSomMatchetNøkleneDuHaddeIDetOrginaleImageArrayet" :-)

 

fetch_row vil derimot returnere et array med numeriske nøkler, mens fetch_array vil så vidt jeg husker gi et array som inneholder både numeriske nøkler og kolonnenavn som nøkler. Jeg ser derfor egentlig ingen grunn til å bruke fetch_array, da man som oftest ønsker en av de to.

 

array_shift() fjerner det første elementet i arrayet ja, som var $imgId, men den verdien tok vi jo vare på, og brukte det som nøkkel i $image-arrayet :)

 

Så da sitter vi igjen med $bilder[$imgId (f.eks. "katt")] = Array("filename" => "katt.jpg", "title" => "katt", "description" => "");

Endret av luxus
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...