CSV in PHP einlesen und als Tabelle ausgeben
#1
geschrieben 11. Januar 2018 - 00:28
Ich werde langsam ratlos.
Ich bin kein Programmierer und habe relativ wenig mit Informatik zu tun als Anfang.
Ich bekomme jede Stunde eine CSV Datei per Mail gesendet. Diese wird automatisch gespeichert unter A1.csv
Die Date sieht beispielsweise folgendermassen aus (habe Dorf und Namen geändert):
Hamburg;AM1;;;
Montag 08/01/2018;;;;
00:00;06:00;5555 KLEIN Peter;1234 MÜLLER Jakob;
06:00;08:00;2222 MÜLLER Jakob;4567 KLEIN Peter;
Dienstag 09/01/2018;;;;
12:00;13:00;6666 PETRA Petra;9999 TOBI Tobias; usw und so fort
Manchmal steht auch ein dritter Name mit drin:
18:00;20:00;7777 MÜLLER Paul;1111 KLEIN Kleini;2555 HOFFMANN Petra;
Hamburg und AM1 sollten ignoriert werden.
Danach sollten folgende Tabellen erscheinen:
Datum, Schichtbeginn, Schichtende, Personal 1, Personal 2, Personal 3
Ich habe folgenden Code eingebaut:
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SCHICHTEN</title>
<link rel="stylesheet" href="../formate.css">
</head>
<body>
<p><img id="logo-l" src="../img/logo.png" width="201" height="216" alt="Logo"</p>
<p><img id="logo-r" src="../img/logo.png" width="201" height="216" alt="Logo"</p>
<h2>SCHICHT A1</h2>
<nav>
<div id="Schichten">
<ul>
<li><a tabindex="0" aria-current="page">SCHICHT A1</a></li>
<li><a href=../index.html>SCHICHTEN</a></li>
<li>SCHICHT A2</li>
<li>SCHICHT A3</li>
</ul>
</div>
</nav>
<table border="1">
<tr><td>Datum</td><td>Schichtbeginn</td><td>Schichtende</td><td>Personal 1</td><td>Personal 2</td><td>Personal 3</td></tr>
<?php
$feld = file(a1.csv);
foreach($feld as $zeile)
(
$i = explode(";" , $zeile);
echo <tr><td>$i(0)</td><td>$i(1)</td><td>$i(2)</td><td>$i(3)</td><td>$i(4)</td><td>$i(5)</td><tr>
)
?>
</body>
</html>
Heraus kommt folgendes: siehe anhängdes Foto
Kann mir dort irgendwer behilflich sein? Ich google mich dumm und dämlich...
Anzeige
#2
geschrieben 11. Januar 2018 - 02:43
damit PHP funktioniert, muss PHP auch installiert sein. D.h. Du benötigst einen Server (z.B. Apache) auf dem PHP installiert ist. Das Script wird dann vom PHP entsprechend den Vorgaben verarbeitet und als HTML ausgegeben.
Dein <tr> wird nicht geschlossen.
#3
geschrieben 11. Januar 2018 - 06:31
Option 1: Dem Burschen, der die CSV erstellt, hinten rein treten und ihm erklären, daß eine zweidimensionale Tabelle auch zweidimensional zu sein hat. Also von links nach rechts eine Zeile mit Personendaten und von oben nach unten die Einträge. Für extra Datum ist eigentlich kein Platz -- das muß in CSV Teil der Personendaten sein.
Option 2: Wenn das nicht geht oder nicht zielführend ist, mußt Du Dein Script schon ein bißchen aufwendiger gestalten.
Der einfachste Weg ist:
- Zeile lesen
-In ein Array umbauen entlang Trennzeichen (hier: ; ).
- Gucken wie lang das Array ist UND ob Eintrag 1 (nicht 0!) leer ist oder nicht.
=> Ein Eintrag bzw Eintrag 1 ist leer: Aha, ein Datum. Entsprechend eine Datumszeile ausgeben. In HTML geht das mit colspan=<Spaltenzahl>, hier also wahrscheinlich colspan=4 (HTML zählt wieder ab 1).
=> MEHR als nur ein Eintrag im Array UND insbesondere Eintrag 1 ist NICHT leer: aha, augenscheinlich Personendaten. Das dann also wie Personendaten ausgeben.
Kann man übrigens auch in javascript/jscript implementieren. Unterscheidet sich kaum von PHP (syntaktisch). Für den Dateisystemzugriff gibt es Scripting.FileSystemObject. Vorteil: Man spart sich die PHP-Installation und den Server. Ist für so eine Aufgabe auch nicht erforderlich.
Dieser Beitrag wurde von RalphS bearbeitet: 11. Januar 2018 - 06:32
#4
geschrieben 11. Januar 2018 - 06:36
- nicht geschlossene HTML Tags
- nicht terminierte PHP Befehle
- HTML und PHP Ausgabe nicht getrennt
- Datei nicht geöffnet, eingelesen und geschlossen
...
HTML5 Tutorial
PHP 5 Tutorial
PHP-Handbuch
#5
geschrieben 11. Januar 2018 - 07:51
Für unseren Gipselmob ein Stück lauffähigen Code (keine weitergehenden Änderungen):
# cat test.php <!doctype html> <html lang="de" > <head> <meta charset="utf-8" > <meta name="viewport" content="width=device-width, initial-scale=1.0" > <title>SCHICHTEN</title>title> <link rel="stylesheet" href="../formate.css" > </head>head> <body> <p><img id="logo-l" src="../img/logo.png" width="201" height="216" alt="Logo" </p>p> <p><img id="logo-r" src="../img/logo.png" width="201" height="216" alt="Logo" </p>p> <h2>SCHICHT A1</h2>h2> <nav> <div id="Schichten" > <ul> <li><a tabindex="0" aria-current="page" >SCHICHT A1</a>a></li>li> <li><a href="../index.html>SCHICHTEN</a>a>li> <li>SCHICHT A2</a>li> <li>SCHICHT A3</a>li> </a>ul> </a>div> </a>nav> <table border="1"> <tr><td>Datum</td>td><td>Schichtbeginn</td>td><td>Schichtende< /td><td>Personal 1</td>td><td>Personal 2</td>td><td>Personal 3</td>td></td>tr> <?php $feld = file("a1.csv"); foreach($feld as $zeile) { $i = explode(";" , $zeile); echo "<tr><td>$i[0]</td><td>$i[1]</td><td> $i[2]</td><td>$i[3]</td><td>$i[4]</td> <td>$i[5]</td><tr>"; } ?> </body></html>
Das merkt man natürlich alles selber, wenn man das erstmal ausführt. Nicht jeder kommt als Programmierguru zur Welt.
NB: der Code ist zwar lauffähig, aber macht fast garantiert nicht das, was er soll.
Dieser Beitrag wurde von RalphS bearbeitet: 11. Januar 2018 - 07:52
#6
geschrieben 11. Januar 2018 - 10:07
@Wiesel Apache ist heruntergeladen, muss nur noch schauen wie ich das genau installieren soll und der <tr> ist mittlerweile auch schon ein </tr>
@RalphS Wie bereits gesagt habe ich null Ahnung von Informatik. Ich verstehe also nur Bahnhof was du da schreibst :/
Option 1 klappt nicht, da es leider keine Person, sondern ein Programm ist was die CSV Datei erstellt und versendet.
@Gipselmob wenn du mir sagen könntest WO im Code die Fehler sind, würde mir das sehr hilfreich sein..
#7
geschrieben 11. Januar 2018 - 10:30
#8
geschrieben 11. Januar 2018 - 10:56
Zitat (frankc: 11. Januar 2018 - 10:07)
Um deinen Code zu testen braucht du dir kein Apache runterladen, sondern du nimmst XAMPP und dort die portable Version, das reicht um zu testen.
Zitat (frankc: 11. Januar 2018 - 10:07)
die Liste der Fehler ist lang und es geht schon mit den HTML Tags los
<meta> wird mit / terminiert, also so <meta charset="utf-8" />
<link> wird mit </link> terminiert, also so <link rel="stylesheet" href="../formate.css"></link>
<img wird auch mit / terminiert, außerdem fehlt das schließende >, also so <img id="logo-l" src="../img/logo.png" width="201" height="216" alt="Logo" />
am Ende der Tabelle fehlt das schließende </table>
Trotz dieser Fehler zeigen die Browser das an. Die sind da relativ resistent. Früher wäre da nicht viel rausgekommen als Anzeige. Trotzdem sollte man sich bemühen immer validen Code zu schreiben, denn das erleichter die Fehlersuche ungemein.
Jetzt zum PHP Code:
- PHP Zeilen in denen Befehle verwendet werden, werden mit ; terminiert, also anstatt echo ... muss das so aussehen: echo ... ;
- die Inhalte von PHP Funktion wie foreach werden nicht in runden Klammern sondern in geschweifeten Klammern genutzt, also so foreach(Argumente) { Inhalt; }
- wenn man mit echo oder print neben Variablen auch Strings ausgeben will, dann müssen diese 1. in Hochkomma ' oder Gänsefüßchen " eingeschlossen sein und 2. mittels Punkt . mit den Variablen verbunden werden, die Zeile würde richtig so aussehen:
echo "<tr><td>" . $i(0) . "</td><td>" . $i(1) . "</td><td>" . $i(2) . "</td><td>" . $i(3) . "</td><td>" . $i(4) . "</td><td>" . $i(5) . "</td></tr>";
- Indexes von Arrays werden in eckige Klammern [] eingeschlosssen und nicht in runde, also echo $i[0]; anstatt echo $i(0);
- möchte man Inhalte von Dateien anzeigen, dann müssen diese Dateien erstmal mit fopen geöffnet und ihr Inhalt mit fread eingelesen werden. Danach sind die Dateien wieder mit fclose zu schließen.
- willst du dein $feld = file(a1.csv); verwenden, so ist die Umsetzung falsch. Es müsste so aussehen:
$lines = file("a1.csv"); foreach ($lines as $line_num => $line) { $i = explode(";" , $line); echo "<tr><td>" . $i[0] . "</td><td>" . $i[1] . "</td><td>" . $i[2] . "</td><td>" . $i[3] . "</td><td>" . $i[4] . "</td><td>" . $i[5] . "</td></tr>"; }
(ich hab das jetzt nicht getestet^^ )
$lines ist der Dateiinhalt
$line_num ist die Zeilennummer
$line ist der Zeileninhalt
$i ist hier schlecht gewählt, du sollstest die Variablen nach Funktion benennen. In dem Fall wäre ein $part besser, denn $i wird normal immer für die Indexnummer genutzt.
Für csv Dateien hat PHP auch eigene Funktionen wie fgetcsv.
Insgesamt würde ich aber PHP und HTML umdrehen. Also kein HTML nehmen und PHP einbetten, sondern gleich in PHP schreiben und dort den HTML Code ausgeben lassen.
Dieser Beitrag wurde von Gispelmob bearbeitet: 11. Januar 2018 - 11:19
#9
geschrieben 11. Januar 2018 - 11:30
#10
geschrieben 11. Januar 2018 - 13:05
pssst - table is nich zu. Au sehe gerade, da sind irgendwie einige Tags beim Kopieren durcheinander gekommen oder?
Na meine Variante wäre jedenfalls so. Wobei der style-Teil natürlich in die css übernommen werden kann. Das Durchzählen ist jetzt nur, weil ich immer gern die Anzahl der Datensätze gern schonmal in einer Variable habe. Oft braucht man die ja für irgendwas und hier habe ich das genutzt, um die erste Zeile wegzulassen. Ansonsten war mir noch aufgefallen, dass der Dateinamen mit A1.csv angegeben war aber im Code a1.csv steht. Groß-/Kleinschreibung beachten.
<?php $durchzaehlen = 0 ; echo '<!doctype html> <html lang="de"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="../formate.css" /> <title>SCHICHTEN</title> <style> .table {display: table ; border-left:1px solid #888888; border-top:1px solid #888888;} .tr {display: table-row ;} .td {display: table-cell ; padding:3px; border-right:1px solid #888888; border-bottom:1px solid #888888;} </style> </head>' ; echo ' <body> <p><img id="logo-l" src="../img/logo.png" width="201" height="216" alt="Logo"</p> <p><img id="logo-r" src="../img/logo.png" width="201" height="216" alt="Logo"</p> <h2>SCHICHT A1</h2> <nav> <div id="Schichten"> <ul> <li><a tabindex="0" aria-current="page">SCHICHT A1</a></li> <li><a href=../index.html>SCHICHTEN</a></li> <li>SCHICHT A2</li> <li>SCHICHT A3</li> </ul> </div> </nav>'; $tabelle = '<div class="table"> <div class="tr"> <div class="td">Schichtbeginn</div> <div class="td">Schichtende</div> <div class="td">Personal 1</div> <div class="td">Personal 2</div> <div class="td">Personal 3</div> </div> ' ; $feld = file('a1.csv'); foreach($feld as $zeile) { $i = explode(';' , $zeile) ; if ($durchzaehlen > 0) { $tabelle .= '<div class="tr"> <div class="td">'.$i[0].'</div> <div class="td">'.$i[1].'</div> <div class="td">'.$i[2].'</div> <div class="td">'.$i[3].'</div> <div class="td">'.$i[4].'</div> </div> ' ; } $durchzaehlen ++ ; } $tabelle .= '</div>' ; echo $tabelle ; echo '</body> </html>'; ?>
Dieser Beitrag wurde von Holger_N bearbeitet: 11. Januar 2018 - 14:01
#11
geschrieben 11. Januar 2018 - 17:42
Ich hab's noch hier:
</tr></a></li></ul></div></nav></body></html>
Um Konfusion zu vermeiden hab ich das dann rausgekürzt. Und "lauffähiger Code" hieß wirklich nur "php.exe kann das ausführen, ohne mit Fehlern auszusteigen".
Was das Ursprungsproblem angeht, so lautet meine ernstgemeinte Empfehlung: Such Dir bzw ggf Euch jemanden, der von sowas Ahnung hat. Klar könnten wir das jetzt umsetzen, aber früher oder später hakt es dann und dann ist keiner da, der weiß, was da geht (oder nicht geht).
Die Problemstellung selber ist vergleichsweise einfach. Wenn man davon nix versteht, ist das auch keine Schande, aber man muß dann auf der anderen Seite bereit sein, jemanden zu greifen, DER das dann kann. Notfalls wen einstellen.
Alles andere fährt im Produktivbereich nur sehenden Auges und ungebremst gegen die Wand. Das kann man nicht ruhigen Gewissens empfehlen.
#12
geschrieben 11. Januar 2018 - 20:40
Ja ich hatte nur beim ersten Gucken gesehen, dass der table-Tag nicht geschlossen ist. Dann hatte ich bemerkt, dass nicht Du den vergessen hast, sondern dass das ja am Anfang schon fehlt und der ganze Code beim Kopieren schon einen weg hat.
Mein Code war dann auch nicht mehr Teil der Antwort an Dich, also keine »Verbesserung« sondern nur, weil ich dann auch noch einen Code mit in die Gesamtrunde schmeißen wollte.
#13
geschrieben 11. Januar 2018 - 21:08
<?php $durchzaehlen = 0; ?> <!doctype html> <html lang="de"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="../formate.css" /> <title>SCHICHTEN</title> <style> .table {display: table ; border-left:1px solid #888888; border-top:1px solid #888888;} .tr {display: table-row ;} .td {display: table-cell ; padding:3px; border-right:1px solid #888888; border-bottom:1px solid #888888;} </style> </head> <body> <p><img id="logo-l" src="../img/logo.png" width="201" height="216" alt="Logo"</p> <p><img id="logo-r" src="../img/logo.png" width="201" height="216" alt="Logo"</p> <h2>SCHICHT A1</h2> <nav> <!-- Hä? Was sucht das NAV-Tag hier? *kopfkratz* NAV beschreibt die Seitennavigation, nicht den Seiteninhalt. In die Tabelle läßt sich auch kaum reinnavigieren. --> <div id="Schichten"> <!-- Klassen sollten immer vor IDs gesetzt werden. Und natürlich den STYLE nicht vergessen per CSS. --> <ul> <li><a tabindex="0" aria-current="page">SCHICHT A1</a></li> <li><a href=../index.html>SCHICHTEN</a></li><!-- Wo verweist das denn hin? --> <li>SCHICHT A2</li> <li>SCHICHT A3</li> </ul> </div> </nav> <div class="table"><!-- Oder mit TABLE(TH). Immerhin SIND das strukturierte Daten. --> <div class="tr"> <div class="td">Schichtbeginn</div> <div class="td">Schichtende</div> <div class="td">Personal 1</div> <div class="td">Personal 2</div> <div class="td">Personal 3</div> </div> <?php // Hier hüpfen wir jetzt in den PHP-Modus, deswegen sehen Kommentare plötzlich anders aus $feld = file('a1.csv'); /* * file() ist immer schlecht. Nicht nehmen, sondern fopen/fread. Was, wenn die Datei * bissel größer ist? file() liest alles. fread() liest byteweise. */ foreach($feld as $zeile) { $i = explode(';' , $zeile); if ($durchzaehlen > 0) /* Oder man nimmt einen booleschen Wert mit, von wegen HeaderGelesen = $false, * den man außerhalb der Schleife definiert und am Ende der Schleife auf $true setzt. * Dann bloß noch gucken, ob $true oder $false. */ { /* Erwähnenswert: Man muß das natürlich nicht fünfmal hintippen. * Eine innere Schleife wie... * for($zelle = 0; $zelle < 5; $zelle++) * { * // und hier eine allgemeine Kopie der fünf Zeilen rein, mit einem $i[$zelle] an der richtigen Stelle * } * ... genügt völlig. */ // Und hier geht es jetzt regulär weiter und es wird interessanter: Raus aus PHP } ?> <div class="tr"> <div class="td"><?php printf('%s', $i[0]);?></div> <!-- Für die Werte wird kurz in den PHP-Modus gewechselt --> <div class="td"><?php printf('%s', $i[1]);?></div> <div class="td"><?php printf('%s', $i[2]);?></div> <div class="td"><?php printf('%s', $i[3]);?></div> <div class="td"><?php printf('%s', $i[4]);?></div> </div> <?php } // Auch sowas geht. Nur, Preisfrage: Wo gehört jetzt diese Klammer überhaupt hin? Das muß man dann gut dokumentieren. $durchzaehlen ++ ; } ?> </div> </body> </html>
... ist überhaupt kein Problem.
Und der Vollständigkeit halber: Formatierung hat in HTML-Tags spätestens seit XHTML/HTML5 nichts mehr zu suchen. Formatiert wird über CSS. Außerdem ist inzwischen per Standard und der Barrierefreiheit wegen ein ALT-Attribut für IMG-Tags verpflichtend. Hier rein kommt ein Beschreibungstext. Also zB so:
<img class="logo" alt="Firmenlogo" src="images/logo_wide.gif" />ALT ist aber nicht TITLE, wenn man ein Popup haben will, muß man TITLE außerdem noch angeben. Mit PHP einfach in eine Variable stopfen und die zweimal zuweisen.
Natürlich kompletter Overkill für die Anforderung. Wie erwähnt reicht hier javascript vollkommen. Wozu PHP, wenn das direkt in der HTML-Datei laufen kann? Keine Sau braucht extra einen Webserver UND ne Serversprache wie PHP, nur um Daten aus einer Textdatei zu lesen. Da schießt man mit Holgern auf Dartpfeile.
Dieser Beitrag wurde von RalphS bearbeitet: 11. Januar 2018 - 21:16
#14
geschrieben 11. Januar 2018 - 21:40
Ansonsten mag ich dieses Gestückel nicht. Im html-Text immer diese <?php … ?> Schnipsel drin. Da sieht doch aus wie Kraut und Rüben und man sieht gar nicht mehr durch, wenn man da nach einem halben Jahr nochmal ran muß.
#15
geschrieben 11. Januar 2018 - 21:46
Mit HTML-Fragmenten wird es immer unübersichtlich. Mit Perl konnte man das mal schön machen (weiß gar nicht mehr ob das noch geht): damit konnte man per definiertem Macro Funktionen live übersetzen. Ergebnis davon war, man hat Funktionsname(Text) geschrieben und durch das Macro kam hinten <funktionsname>Text</funktionsname> raus.
Hey presto, kein HTML-Code mehr, sondern nur noch h1("Überschrift"); gleich viel übersichtlicher.
- ← Duplikat eines Prozesses live erstellen/zweimal laufen lassen
- Skript/Web-Programmierung
- MS Access Daten nach Web →