PHP Problem - fgetcsv
uli
- php
0 Florian Stascheck0 uli0 Florian Stascheck0 uli0 ChrisB0 Der Martin
0 Christoph Jeschke
hallo,
habe gerade eine webseite auf einen neuen server gezogen. auf dem alten lief/läuft alles problemlos, beim neuen habe ich probleme mit fgetcsv.
und zwar öffne mit fopen und fgetcsv eine datei, trennzeichen ist §. wenn die zeile wie folgt lautet:
wert1§wert2§wert3
ist alles in ordnung. ist aber ein wert leer, zb:
wert1§§wert3
bekomme ich beim auslesen mit $zeile[1] den dritten wert statt den zweiten, welcher leer und nicht ausgeprägt ist. das bringt dann natürlich alles durcheinander..
auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6, beides linux.
lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles problemlos. falls das noch wichtig ist.
hat jemand eine idee woran das liegen könnte?
danke im voraus
gruss, uli
Hallo,
Auf php.net (Link) ist nicht festgelegt, wie ein leeres Element interpretiert wird. Hast du eine phpinfo() verfügbar von deinem neuen Server?
Achja: zwischen 5.2.4 und 5.2.6 hat sich mehr getan als die Versionsnummern vermuten lassen, gerade in diesem Bereich. Kann auch sein, dass das PHP auf dem Server anders kompiliert worden ist, habe aber auch nichts dergleichen gefunden. Ich würde eine Klasse machen, die eine CSV-Datei kapselt und man per Array darauf zugreifen kann. Dann kann man bei solchen Problem ganz schnell alles ändern. Ist aber wahrscheinlich schwer, das nachträglich zu machen :(
mfg, Flo
hi flo,
danke für deine fixe antwort. die ganze phpinfo kann ich hier leider nicht posten, einen link würde ich nur ungern posten, da auf dem server noch einige sachen offen sind, bevor das ganze wirklich life geht.
welchen abschnitt brauchst du denn, dann poste ich den hier.
danke und gruss, uli
Hallo,
Am besten PHP Core wo was mit CSV drin ist oder eine Extension, die etwas mit CSV-Dateien zu tun hat. Wenn du da nichts findest, kannst du wahrscheinlich nichts tun. Eine Idee hätte ich noch: Das ist ja nich schwer, fgetcsv selber zu machen (Kombination aus fgets und explode) und du kannst ja selber was in der Richtung proggen und dann mit einem Editor deiner Wahl beim kompletten Projekt fgetcsv durch myFgetCsv ersetzen. Dürfte nicht schwer zu realisieren sein.
mfg, Flo
ja, das mit dem selber basteln sollte kein problem sein, nur wollte ich mir das gerne ersparen. ;)
hier der auszug: PHP Core
Directive Local Value Master Value
allow_call_time_pass_reference On On
allow_url_fopen On On
allow_url_include Off Off
always_populate_raw_post_data Off Off
arg_separator.input & &
arg_separator.output & &
asp_tags Off Off
auto_append_file no value no value
auto_globals_jit On On
auto_prepend_file no value no value
browscap no value no value
default_charset no value no value
default_mimetype text/html text/html
define_syslog_variables Off Off
disable_classes no value no value
disable_functions no value no value
display_errors On On
display_startup_errors Off Off
doc_root no value no value
docref_ext no value no value
docref_root no value no value
enable_dl On On
error_append_string no value no value
error_log no value no value
error_prepend_string no value no value
error_reporting 6135 6135
expose_php On On
extension_dir ./ ./
file_uploads On On
highlight.bg #FFFFFF #FFFFFF
highlight.comment #FF8000 #FF8000
highlight.default #0000BB #0000BB
highlight.html #000000 #000000
highlight.keyword #007700 #007700
highlight.string #DD0000 #DD0000
html_errors On On
ignore_repeated_errors Off Off
ignore_repeated_source Off Off
ignore_user_abort Off Off
implicit_flush Off Off
include_path .:/usr/local/lib/php .:/usr/local/lib/php
log_errors Off Off
log_errors_max_len 1024 1024
magic_quotes_gpc On On
magic_quotes_runtime Off Off
magic_quotes_sybase Off Off
mail.force_extra_parameters no value no value
max_execution_time 30 30
max_input_nesting_level 64 64
max_input_time 60 60
memory_limit 128M 128M
open_basedir no value no value
output_buffering no value no value
output_handler no value no value
post_max_size 8M 8M
precision 12 12
realpath_cache_size 16K 16K
realpath_cache_ttl 120 120
register_argc_argv On On
register_globals On On
register_long_arrays On On
report_memleaks On On
report_zend_debug On On
safe_mode Off Off
safe_mode_exec_dir no value no value
safe_mode_gid Off Off
safe_mode_include_dir no value no value
sendmail_from no value no value
sendmail_path /usr/sbin/sendmail -t -i /usr/sbin/sendmail -t -i
serialize_precision 100 100
short_open_tag On On
SMTP localhost localhost
smtp_port 25 25
sql.safe_mode Off Off
track_errors Off Off
unserialize_callback_func no value no value
upload_max_filesize 2M 2M
upload_tmp_dir no value no value
user_dir no value no value
variables_order EGPCS EGPCS
xmlrpc_error_number 0 0
xmlrpc_errors Off Off
y2k_compliance On On
zend.ze1_compatibility_mode Off Off
Hi,
ja, das mit dem selber basteln sollte kein problem sein, nur wollte ich mir das gerne ersparen. ;)
Die Nutzerkommentare zur Funktion im Manual bieten einige fertige Vorschlaege.
MfG ChrisB
Hallo,
magic_quotes_gpc On On
register_globals On On
short_open_tag On On
wenn du Zugriff auf die Serverkonfiguration hast, würde ich dir dringend empfehlen, die genannten drei Parameter auf "off" zu setzen. Hat zwar mit deinem aktuellen Problem nichts zu tun, kann dir bei zukünftigen Projekten aber eine Menge Nerven und Ärger ersparen.
So long,
Martin
Guten Tag,
auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6,
beides linux.
lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles
problemlos. falls das noch wichtig ist.
Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.
In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.
Gruß
Christoph Jeschke
Hallo Christoph,
auf dem alten server ist ist php version 4.4.9 drauf, auf dem neuen 5.2.6,
beides linux.
lokal auf meinem laptop (vista) habe ich php 5.2.4 drauf, da läuft alles
problemlos. falls das noch wichtig ist.Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.
In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.
danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon. Für mich wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter Umgang.
Freundliche Grüße
Vinzenz
Guten Tag,
danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon. Für mich
wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien #
normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit
leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter
Umgang.
Streng genommen müssen Felder auch Zeichen enthalten (so sagt es RFC4180). Andererseits verstößt das Verhalten gegen RFC793.
Gruß
Christoph Jeschke
Hallo Christoph,
danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.
erst mal vielen Dank für das Eintragen in die Bugliste. Das hätte ich mir sonst für heute vorgenommen :-)
wäre dieses Verhalten ein Bug, denn leere Einträge sind in CSV-Dateien #
normal und eine Funktion, die mit CSV-Dateien umgehen können will, muss mit
leeren Einträgen korrekt umgehen können. Weglassen ist kein korrekter
Umgang.Streng genommen müssen Felder auch Zeichen enthalten (so sagt es RFC4180). Andererseits verstößt das Verhalten gegen RFC793.
Nein, RFC4180 erlaubt leere Einträge, schauen wir es uns an:
<zitat quelle = RFC4180, Abschnitt 2>
file = [header CRLF] record *(CRLF record) [CRLF]
header = name *(COMMA name)
record = field *(COMMA field)
name = field
field = (escaped / non-escaped)
escaped = DQUOTE *(TEXTDATA / COMMA / CR / LF / 2DQUOTE) DQUOTE
non-escaped = *TEXTDATA
<zitat>
mit RFC2234, in der die Augmented Backus-Naur-Form spezifiziert wird:
<zitat quelle = RFC2234, Abschnitt 3.6>
Default values are 0 and infinity so that *<element> allows any
number, including zero; 1*<element> requires at least one;
</zitat>
Da nun entweder *TEXTDATA oder DQUOTE *(TEXTDATA / ...) DQUOTE gilt, folgt, dass leere Einträge erlaubt sind, was sinnvoll und notwendig ist.
Freundliche Grüße
Vinzenz
Guten Tag,
Da nun entweder *TEXTDATA oder DQUOTE *(TEXTDATA / ...) DQUOTE gilt, folgt, dass leere Einträge erlaubt sind, was sinnvoll und notwendig ist.
Danke für die Korrektur.
Gruß
Christoph Jeschke
Guten Tag,
danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.
Gruß
Christoph Jeschke
Hallo Christoph,
danke für den Test. Ich bin verblüfft. Im Changelog habe ich dazu nichts
gefunden und auch die Bugliste zu fgetcsv() weiß nichts davon.
ich kann den Bug nicht reproduzieren. Ich kann nur nachvollziehen, dass es mit dem Paragraphenzeichen als Trennzeichen Probleme gibt. Bei mir sieht es so aus, dass das Paragraphenzeichen überhaupt nicht gefunden wird.
Skript sowie CSV-Datei sind UTF-8-codiert. Auch mit einer Kopie aus Deiner Bugmeldung erhalte ich das gleiche Resultat - genauso mit einer vom gleichen Skript geschriebenen CSV-Datei.
Mit typischen Trennzeichen wie dem Komma oder dem Semikolon erhalte ich das erwartete Resultat mit leeren Feldern.
Getestet mit:
PHP 5.2.6 unter Windows (Zip-Archiv von php.net)
PHP 5.2.6-5 unter Debian Lenny
Freundliche Grüße
Vinzenz
Hello,
Ich testete eben mal und kann bestätigen, dass sich das Verhalten von fgetcsv() zwischen PHP 4.4.8 und 5.2.6 geändert hat.
In PHP4(.3.0|.4.8) werden leere Element als ein String mit 0 Zeichen Länge zurückgeliefert, in PHP5 fehlt das Element einfach.
Ich habe das eben in ellenlanger Sitzung (das verflixte Semikolon hinter der while-Schleife *duck*) auch nochmal ausprobiert.
Hier das Ergebnis:
Das Script:
<?php ### fgetcsv01.php ###
#------------------------------------------------
function show(&$_data)
{
echo "<pre\r\n>";
# echo htmlspecialchars(print_r(func_get_args(),1));
var_dump($_data);
echo "</pre\r\n>";
}
#------------------------------------------------
$filename = "csv01.txt";
define('MAX_LINE_LENGTH', 4096);
define('FIELD_SEPARATOR', ';');
define('FIELD_ENCLOSURE', '"');
echo "<h2>PHP-Version: ".phpversion()."</h2>\r\n";
ini_set('auto_detect_line_endings','true');
$fh = fopen($filename, 'rb');
$_rec = array();
$_list = array();
if ($fh)
{
echo "<pre\r\n>";
while (!feof($fh))
{
$buffer = fgets($fh, MAX_LINE_LENGTH);
echo htmlspecialchars($buffer);
}
echo "</pre\r\n>";
rewind($fh);
while (( $_rec = fgetcsv($fh, MAX_LINE_LENGTH, FIELD_SEPARATOR, FIELD_ENCLOSURE)) !== false )
# while (( $_rec = fgetcsv($fh)) !== false )
{
show($_rec);
$_list[] = $_rec;
}
fclose($fh);
show($_list);
}
?>
PHP-Version: 5.2.5 im XAMPP
1;"Erste Zeile";0;"Text"
2;"Zeite Zeile";0.11;"mehr Text"
3;"Dritte Zeile";;"kein Eintrag vorhanden"
5;"nach der Leerzeile";22;"letzter Eintrag"
array(4) {
[0]=>
string(1) "1"
[1]=>
string(11) "Erste Zeile"
[2]=>
string(1) "0"
[3]=>
string(4) "Text"
}
array(4) {
[0]=>
string(1) "2"
[1]=>
string(11) "Zeite Zeile"
[2]=>
string(4) "0.11"
[3]=>
string(9) "mehr Text"
}
array(4) {
[0]=>
string(1) "3"
[1]=>
string(12) "Dritte Zeile"
[2]=>
string(0) ""
[3]=>
string(22) "kein Eintrag vorhanden"
}
array(1) {
[0]=>
string(0) ""
}
array(4) {
[0]=>
string(1) "5"
[1]=>
string(18) "nach der Leerzeile"
[2]=>
string(2) "22"
[3]=>
string(15) "letzter Eintrag"
}
Könnte es sein, dass in der nächsten PHP-Version versucht wurde, die Typenumsetzung einzubauen?
Wenn Enclosures angegeben werden, werden nicht eingeschlossene Felder als Numeric, eingeschlossene Felder als String und nicht eingeschlossene leere Felder als NULL dargestellt. Das hat es meiner Erinnerung nach schon mal bei einer älteren PHP-Version gegeben.
Leider kollidierte das mit dem Array-Verhalten. Ein Array-Element, dem man NULL zuwies, verschwand einfach aus der Liste.
Liebe Grüße aus Syburg bei Dortmund
Tom vom Berg