PHP CSV Datei einlesen, bearbeiten/sortieren und ausgeben.

aldaric

Vice Admiral
Dabei seit
Juli 2010
Beiträge
6.792
Hallo Leute,

ich hatte zwar schon eine ganze Weile nichts mit Programmieren am Hut, aber ab und zu trifft man auch mal arbeitstechnisch auf ein kleines Problem welches man dann gerne lösen würde.

Und zwar habe ich eine CSV Datei, diese soll in PHP eingelesen werden. Die CSV Datei hat 6 Spalten, davon werden aber lediglich 4 benötigt. Das funktioniert auch soweit alles ohne Probleme, die Ausgabe als Tabelle funktioniert ebenso.

Die Tabelle soll nun aber nach dem Preis absteigend sortiert werden, und es sollen noch die Spalte "Lagerbestand Warenwert" ergänzt werden in dem einfach der Preis mit dem Bestand multipliziert wird.

Allerdings habe ich mich an die extra Spalte noch nicht rangewagt, da ich Probleme bei der Sortierung habe. Die Sortierung ist fehlerhaft, da er lediglich nach der ersten Zahl sortiert. Sprich er ordnet z. B. 2,50 höher ein als 15,60.

Hier stand Code...


Und hier mal ein Problem was er in der Tabelle dann ausgibt:

Hier war mal ein Bild...

Man sieht, er sortiert die 29,43 z.B. niedriger ein als die 3,01.

Ich hoffe mir kann jemand bei dem kleinen Problemchen helfen !
 
Zuletzt bearbeitet:

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
Das Problem ist, dass für PHP Zahlen kein Komma, sondern Punkte als Trennzeichen haben.
Daher die Spalte in floats umwandeln mit floatval und vorher Komma durch Punkt ersetzen.
PHP:
usort($zeilen,function($lhs,$rhs){
$a=floatval(str_replace(",",".",$lhs->VKPreis));
$b=floatval(str_replace(",",".",$rhs->VKPreis));
return $a<=>$b;
});
(Der Code sollte mit PHP7 funktionieren, für PHP5 musst du natürlich den Namen der Funktion übergeben und den Spaceship-Operator (<=>) durch if($a<$b)return -1;if($a>$b)return 1;return 0; ersetzen.)

Gibt es eigentlich ein Grund, warum du den ersten Wert weglässt? (for in Z.46 sollte von 0 statt 1 gehen.)
 
Zuletzt bearbeitet: (Klammern)

Andreas_

Commander
Dabei seit
Jan. 2017
Beiträge
2.077
@Hancock
In einer CSV-Datei stehen im Normalfall in der ersten Zeile die Spaltenbezeichnungen. Man könnte diese natürlich gleich beim Einlesen entsorgen, wenn man sie sowieso nicht benutzt.

@Aldaric87
Wie schon geschrieben zum Sortieren das Komma in einen Dezimalpunkt umwandeln. Wenn bei der Ausgabe Kommata gewünscht sind, könntest Du für die Ausgabe die Funktion money_format nutzen, sofern das ganze nicht auf einem Windows-System läuft (da gibt es die Funktion nicht) ... neben dem Komma als Dezimaltrenner hast Du dann auch den Punkt als Tausender-Markierung und die Währungsangabe.

PHP:
setlocale(LC_MONETARY, 'de_DE');
echo "<td width=\"80px\" height=\"10px\">".money_format("%.2n",  $data->VKPreis)."</td>";
 
Zuletzt bearbeitet: (Typo)

aldaric

Vice Admiral
Ersteller dieses Themas
Dabei seit
Juli 2010
Beiträge
6.792
@Hancock @Andreas_

Danke erstmal für eure Hilfe. :love:

Die Sortierung funktioniert jetzt einwandfrei, jedoch lässt er die letzte Zeile des CSV Dokuments aus, und gibt mir stattdessen nochmal die Objektnamen aus. Somit fehlt eine Zeile, zufällig die mit dem höchsten Preis.

Hier stand Code...

So habe ich sie jetzt eingebaut, damit er vom höchsten Wert zum niedrigsten runter zählt. Der höchste Wert (der in der CSV Tabelle in der letzten Zeile steht) fehlt leider, stattdessen stehen dort erneut die von mir benannten Objekte drin: ArtNr | Bezeichnung | VKPreis | Bestand

Wisst ihr was ich da nun versaut habe? :D

Mal noch einen Schritt weiter gedacht, wenn ich dann den Lagerbestand mit dem Preis multiplizieren will, funktioniert das bei Daten, wie sie hier jetzt vorliegen, einfach über VKPreis * Bestand ?
 
Zuletzt bearbeitet:

Hancock

Captain
Dabei seit
Nov. 2007
Beiträge
3.381
Schmeiß die erste Zeile aus deinem Array weg. Da dort die spaltenbezeichung drinsteht.

Z19:
PHP:
fgetcsv($handle, 500, ';')//Throw away column names
$aktuelleZeile = 0;
while($data = fgetcsv($handle, 500, ';'))
...
und dann Z.46
PHP:
for ($dl=0; $dl<count($zeilen); $dl++) {
Erklärung: Du hast das Array inklusive den Namen, das heißt, das erste Feld enthält "Preis" als Preis, was als Zahl zu einer 0 wird, daher sortiert das als letztes (da du abwärts sortierst, was ich aus gesehen nicht gemacht habe). Der größte Preis steht ganz oben, wird aber nicht ausgegeben, da du immer das erste Element im Array übersprungen hast (PHP zählt die Arrays von 0).

Wie kannst du die Preise jetzt multiplizieren? Dazu musst du die Zahlen wieder in eine float umwandeln (floatval(str_replace…)). Dann kannst du diese einfach multiplizieren. Bei der Ausgabe kommt halt wieder ein Punkt.

Falls du das ganze Konvertieren weglassen willst, einfach mal am Anfang
PHP:
setlocale(LC_ALL,"de_DE");
aufrufen. Dann sollte eigentlich PHP für dich alles machen (dann brauchst du zum Sortieren auch kein str_replace mehr).
 
Zuletzt bearbeitet:

aldaric

Vice Admiral
Ersteller dieses Themas
Dabei seit
Juli 2010
Beiträge
6.792
@Hancock

Hi, vielen dank erneut für deine Hilfe ! Und danke das du so viel Geduld mit mir hast.

Hier stand Code...

Ich hab jetzt noch nicht ganz verstanden was du meinst mit der ersten Zeile aus dem Array kicken?

Wie du siehst, habe ich ein Objekt Bestandswarenwert hinzugefügt für die Berechnung von diesem. Das klappt auch wuderbar, siehe hier:



Die nächste Frage die ich hier noch habe, ob ich es forcieren kann, dass er zwei Nachkommastellen anzeigt ?

Grundsätzlich habe ich aber nur noch mit dem Array das Problem das ich unten nochmal die Objektnamen sehe. Ich scheine grad auf dem Schlauch zu stehen, denn sobald ich deinen Code da reinschreibe, geht gar nichts mehr.

Es tut mir leid das ich da auch so auf dem Schlauch stehe ! :D

Edith: Code gekürzt zur Übersichtlichkeit.

Edith: Da fällt mir noch eine Frage ein. Wenn ich unter der Tabelle noch die Gesammtsumme des Warenwertes und die Gesamtsumme des Bestandes berechnen möchte, wie stelle ich das an ? :freaky:

Edith2:
Code und Bilder auf Wunsch entfernt.
 
Zuletzt bearbeitet:

psYcho-edgE

Admiral
Dabei seit
Apr. 2013
Beiträge
7.561
In einer CSV-Datei stehen im Normalfall in der ersten Zeile die Spaltenbezeichnungen.
Nicht notwendigerweise. Mir sind bisher jeweils ca. die Hälfte mit bzw. ohne Kopfzeile untergekommen.


Die nächste Frage die ich hier noch habe, ob ich es forcieren kann, dass er zwei Nachkommastellen anzeigt ?
Da der Wert so ist, wie er ist, musst du das Ergebnis in einen String konvertieren. Am besten mit sprintf(string $format[, mixed $...]) um die Darstellung im String zu beeinflussen:
PHP:
sprintf("%.2d",$val);
Edit: ich sehe gerade Hancock war schneller... :rolleyes:


Noch ein Tip: du kommst einfacher über ein Array zu iterieren mit der foreach($arr as [$key->]$val){ ... } Kontrollstruktur. Für deine Gesamtzahl also:

PHP:
$totalcount = 0;
$totalvalue = 0;
foreach($zeilen as $zeile){
$totalcount += $zeile->Bestand;
$totalvalue += $zeile->Bestandswarenwert;
}
Bevor du aber zweimal in deiner Ausgabe über das Array iterierst (Stichwort: ineffizient) schlage ich dir folgendes vor:

PHP:
// Ausgabe
$totalcount = 0;
$totalvalue = 0;
echo "</tr>";
foreach ($zeilen as $zeile) {
  echo "<tr>";
  echo "<td width=\"80px\" height=\"10px\">".$zeile->ArtNr."</td>";
  echo "<td width=\"80px\" height=\"10px\">".$zeile->Bezeichnung."</td>";
  echo "<td width=\"80px\" height=\"10px\">".$zeile->Bestand."</td>";
  echo "<td width=\"80px\" height=\"10px\">".$zeile->VKPreis."</td>";
  echo "<td width=\"80px\" height=\"10px\">".$zeile->Bestandswarenwert."</td>";
  echo "</tr>\n";
  // Gesamtwerte in der Schleife zur Ausgabe gleich mitzählen
  $totalcount += $zeile->Bezeichnung;
  $totalvalue += $zeile->Bestandswarenwert;
}
// Gesamtwerte nach der Schleife echoen
echo "<tr>
  <td width=\"80px\" height=\"10px\">Gesamt:</td>
  <td width=\"80px\" height=\"10px\"></td>
  <td width=\"80px\" height=\"10px\">".$totalcount."</td>".
  <td width=\"80px\" height=\"10px\"></td>
  <td width=\"80px\" height=\"10px\">".$totalvalue."</td>";
echo "</table>";
P.S. wenn du einfache Anführungszeichen bei echo nutzt, brauchst du die doppelten Anführungszeichen vom HTML nicht escapen.

echo "<a href=\"google.com\">"; wird so zu echo '<a href="google.com">';
 
Zuletzt bearbeitet:
Top