Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: [PHP] Problem z tablica z polskimi znakiami
Forum PHP.pl > Forum > Przedszkole
tomas3man
Witam,

jestem poczatkujacy w temacie PHP i oraz pisze pierwszy raz na tym forum. Dlatego z gory przepraszam za bledy.

Mam problem z wczytaniem pliku tekstowego, z danymi przelewow bankowch w formacie zblizonym do CSV (nie prawdziwy CSV). Najpier wczytuje plik do zmiennej $content.

Potem parsuje w petli zmienna $content w poszukiwaniu oddzielonych przecinkami, lub innymi znakami separacji pol danych, pole po polu i linia po linni.
Parsowane dane sa wrzucane do wielowymiarowej tablicy, gdzie lokalizuje wszystkie przelwy oraz wszystkie pola dla danego przelewu.
Skrypt pracuje poprawnie jak w polach tekstowych nie ma polskiego znaku. Jezeli chociaz w jednym polu danego wiersza znajduje sie polski znak, to wszystkie elementy tablicy dotyczacej danego wiersza sa puste.
Dlaczego?

Tutaj wrzuam petle ktora parsuje:

  1.  
  2. $buffer = '';
  3. $field = 't_date';
  4. $row=0;
  5. $cvs = array();
  6. $byte_number = 0;
  7. $lenght = strlen($content);
  8.  
  9. echo "<font color=white><pre>";
  10. echo $content;
  11.  
  12. while( $byte_number <= $lenght) {
  13. $ch = $content[$byte_number]; $byte_number++;
  14. echo '<br>'.'('.$ch.') ('.ord($ch).') '; echo $field;
  15.  
  16. if ( $ch == ' ' ) {
  17. $save = $ch;
  18. while ( $ch == ' ' ) {
  19. $ch = $content[$byte_number]; $byte_number++;
  20. }
  21. $ch = $save.$ch;
  22. }
  23. if ( $ch == ';' and $field == 't_date' ) {
  24. $cvs[$field]=$buffer; echo debug($cvs);
  25. $buffer = '';
  26. $field ='t_acounting_date';
  27. $ch = '';
  28. }
  29. if ( $ch == ';' and $field == 't_acounting_date' ) {
  30. $cvs[$field]=$buffer; echo debug($cvs);
  31. $buffer = '';
  32. $field ='t_side';
  33. $ch = '';
  34. }
  35. if ( $ch == ';' and $field == 't_side' ) {
  36. $cvs[$field]=$buffer; echo debug($cvs);
  37. $buffer = '';
  38. $field ='t_title';
  39. $ch = '';
  40. }
  41. if ( $ch == ';' and $field == 't_title' ) {
  42. $cvs[$field] = substr ($buffer, 1, -1); echo debug($cvs);
  43. $buffer = '';
  44. $field ='t_sender';
  45. $ch = '';
  46. }
  47. if ( $ch == ';' and $field == 't_sender' ) {
  48. $cvs[$field] = substr ($buffer, 1, -1) ; echo debug($cvs);
  49. $buffer = '';
  50. $field ='t_account';
  51. $ch = '';
  52. }
  53. if ( $ch == ';' and $field == 't_account' ) {
  54. $cvs[$field] = substr ($buffer, 1, -1); echo debug($cvs);
  55. $buffer = '';
  56. $field ='t_volume';
  57. $ch = '';
  58. }
  59. if ( $ch == ';' and $field == 't_volume' ) {
  60. $cvs[$field] = substr ($buffer, 0, -3); echo debug($cvs);
  61. $buffer = '';
  62. $field ='t_balance';
  63. $ch = '';
  64. }
  65. if ( $ch == ';' and $field == 't_balance' ) {
  66. $cvs[$field] = $buffer; echo debug($cvs);
  67. $ch = $content[$byte_number]; $byte_number++;
  68. $ch = $content[$byte_number]; $byte_number++;
  69. $row++;
  70. $field = 't_date';
  71. $ch = '';
  72. $buffer = '';
  73. $cvs = '';
  74. }
  75. $buffer .= $ch; echo ' '.$buffer;
  76.  
  77. }



Nie moge wrzucic screen shootu, ale wglada to w ten sposob, ze kiedy pointer parsujacy natrafi na bajt zawierajacy polski znak, to element tablicy jest pelen znakow, dopiero kiedy pointer parsujacy dojdzie do konca pola, to element tablicy zastepowany jest nul.

Tutaj wklejam wynik ekranu podczas uruchomienia kodu, w celu debugu dodalem tam wyswietlanie zmiennych:

  1.  
  2. (2) (50) t_date 2
  3. (0) (48) t_date 20
  4. (1) (49) t_date 201
  5. (4) (52) t_date 2014
  6. (-) (45) t_date 2014-
  7. (0) (48) t_date 2014-0
  8. (9) (57) t_date 2014-09
  9. (-) (45) t_date 2014-09-
  10. (0) (48) t_date 2014-09-0
  11. (9) (57) t_date 2014-09-09
  12. (;) (59) t_date
  13. /app/Controller/PaymentsController.php (line 378)
  14.  
  15. 't_date' => '2014-09-09'
  16. )
  17.  
  18.  
  19. (2) (50) t_acounting_date 2
  20. (0) (48) t_acounting_date 20
  21. (1) (49) t_acounting_date 201
  22. (4) (52) t_acounting_date 2014
  23. (-) (45) t_acounting_date 2014-
  24. (0) (48) t_acounting_date 2014-0
  25. (9) (57) t_acounting_date 2014-09
  26. (-) (45) t_acounting_date 2014-09-
  27. (0) (48) t_acounting_date 2014-09-0
  28. (9) (57) t_acounting_date 2014-09-09
  29. (;) (59) t_acounting_date
  30. /app/Controller/PaymentsController.php (line 384)
  31.  
  32. 't_date' => '2014-09-09',
  33. 't_acounting_date' => '2014-09-09'
  34. )
  35.  
  36.  
  37. (P) (80) t_side P
  38. (R) (82) t_side PR
  39. (Z) (90) t_side PRZ
  40. (E) (69) t_side PRZE
  41. (L) (76) t_side PRZEL
  42. (E) (69) t_side PRZELE
  43. (W) (87) t_side PRZELEW
  44. ( ) (32) t_side PRZELEW Z
  45. (E) (69) t_side PRZELEW ZE
  46. (W) (87) t_side PRZELEW ZEW
  47. (N) (78) t_side PRZELEW ZEWN
  48. (E) (69) t_side PRZELEW ZEWNE
  49. (T) (84) t_side PRZELEW ZEWNET
  50. (R) (82) t_side PRZELEW ZEWNETR
  51. (Z) (90) t_side PRZELEW ZEWNETRZ
  52. (N) (78) t_side PRZELEW ZEWNETRZN
  53. (Y) (89) t_side PRZELEW ZEWNETRZNY
  54. ( ) (32) t_side PRZELEW ZEWNETRZNY P
  55. (R) (82) t_side PRZELEW ZEWNETRZNY PR
  56. (Z) (90) t_side PRZELEW ZEWNETRZNY PRZ
  57. (Y) (89) t_side PRZELEW ZEWNETRZNY PRZY
  58. (C) (67) t_side PRZELEW ZEWNETRZNY PRZYC
  59. (H) (72) t_side PRZELEW ZEWNETRZNY PRZYCH
  60. (O) (79) t_side PRZELEW ZEWNETRZNY PRZYCHO
  61. (D) (68) t_side PRZELEW ZEWNETRZNY PRZYCHOD
  62. (Z) (90) t_side PRZELEW ZEWNETRZNY PRZYCHODZ
  63. (A) (65) t_side PRZELEW ZEWNETRZNY PRZYCHODZA
  64. (C) (67) t_side PRZELEW ZEWNETRZNY PRZYCHODZAC
  65. (Y) (89) t_side PRZELEW ZEWNETRZNY PRZYCHODZACY
  66. (;) (59) t_side
  67. /app/Controller/PaymentsController.php (line 390)
  68.  
  69. 't_date' => '2014-09-09',
  70. 't_acounting_date' => '2014-09-09',
  71. 't_side' => 'PRZELEW ZEWNETRZNY PRZYCHODZACY'
  72. )
  73.  
  74.  
  75. (") (34) t_title "
  76. (O) (79) t_title "O
  77. (P) (80) t_title "OP
  78. (L) (76) t_title "OPL
  79. (A) (65) t_title "OPLA
  80. (T) (84) t_title "OPLAT
  81. (A) (65) t_title "OPLATA
  82. ( ) (32) t_title "OPLATA Z
  83. (A) (65) t_title "OPLATA ZA
  84. ( ) (32) t_title "OPLATA ZA K
  85. (U) (85) t_title "OPLATA ZA KU
  86. (R) (82) t_title "OPLATA ZA KUR
  87. (S) (83) t_title "OPLATA ZA KURS
  88. (,) (44) t_title "OPLATA ZA KURS,
  89. ( ) (32) t_title "OPLATA ZA KURS, M
  90. (I) (73) t_title "OPLATA ZA KURS, MI
  91. (C) (67) t_title "OPLATA ZA KURS, MIC
  92. (H) (72) t_title "OPLATA ZA KURS, MICH
  93. (A) (65) t_title "OPLATA ZA KURS, MICHA
  94. (Ł) (163) t_title "OPLATA ZA KURS, MICHAŁ
  95. ( ) (32) t_title "OPLATA ZA KURS, MICHAŁ G
  96. (R) (82) t_title "OPLATA ZA KURS, MICHAŁ GR
  97. (A) (65) t_title "OPLATA ZA KURS, MICHAŁ GRA
  98. (B) (66) t_title "OPLATA ZA KURS, MICHAŁ GRAB
  99. (C) (67) t_title "OPLATA ZA KURS, MICHAŁ GRABC
  100. (Z) (90) t_title "OPLATA ZA KURS, MICHAŁ GRABCZ
  101. (A) (65) t_title "OPLATA ZA KURS, MICHAŁ GRABCZA
  102. (K) (75) t_title "OPLATA ZA KURS, MICHAŁ GRABCZAK
  103. (") (34) t_title "OPLATA ZA KURS, MICHAŁ GRABCZAK"
  104. (;) (59) t_title
  105. /app/Controller/PaymentsController.php (line 396)
  106.  
  107.  


Dla wygoty debugowania w nawiasie wyswietla znak (A) oraz jego kod ASCII (65) przy kazdym wczytanym znaku.
Widac ze skrypt prawidlowo odczytal pola w liniach drugiego listningu debugujacego 13,31,69 i tablica $csv zawiera dane,
ale poczawszy od linii (tu mowie caly czas o debugu) 108, tablic $csv znika, zamienia sie w null, bo w polu byl polski znak,
widac to w linni 97.
Jezeli usune polski znak Ł z pliku tekstowego, to petla parsujaca przejdzie poprawnie.

Czy ktos moze mi pomoc?
Pyton_000
pokaż kilka wierszy z pliku

I prawie na pewno da się dobrać do tego tym: http://pl1.php.net/manual/en/function.fgetcsv.php
kreatiff
Wykorzystaj mb_strlen zamiast strlen.
tomas3man
Cytat(Pyton_000 @ 22.10.2014, 20:45:05 ) *
pokaż kilka wierszy z pliku


Przykladowy pierwszy wiersz:

------------
2014-09-09;2014-09-09;PRZELEW ZEWNETRZNY PRZYCHODZACY;"OPLATA ZA KURS, MICHA£ XXXXXXXX";"ANDRZEJ JERZY XXXXXXXX UL. XXXXXXXX M.16 08-110 SIEDLCE";'1111102020202010101020949505';200,00;250,67;
----------

Cytat(Pyton_000 @ 22.10.2014, 20:45:05 ) *
I prawie na pewno da się dobrać do tego tym: http://pl1.php.net/manual/en/function.fgetcsv.php


Probowalem na samym poczatku ta funkcja. Napotkalem problem ze znakami cudzyslowu (''). W definicji funkcji :

  1. array fgetcsv ( resource $handle [, int $length = 0 [, string $delimiter = "," [, string $enclosure = '"' [, string $escape = "\\" ]]]] )


nie mozna ustawic, aby usuwac znaki ('') dlatego wykonalem to samodzielnie. W przykladzie widac, ze pole banku jest otoczone znakiem (') a pole adresu ('') a pole daty nie ma znaku (''), to powodowalo mi trudnosc, potem musialem kasowac te znaki dodatkowe, ale juz nie pamietam czy plik poprawnie sie wczytal, bo zrezygnowalem na samym poczatku z tej funkcji. Uwazas ze ona moze pomoc?

Wszystko jest postawione na serverze Linux oraz Apache, zaczynam przypuszczac, moze jest jakis blad w konfiguracji polskich liter w systemie. Albo to jest BUG w PHP?

Cytat(kreatiff @ 22.10.2014, 22:23:52 ) *
Wykorzystaj mb_strlen zamiast strlen.


Dlaczego tak uwazasz? Nie rozumiem. Petla iteracyjna poprawnie docodzi do konca zmiennej typu string, co oznacza ze dlugosc jest poprawnie odczytana, ilosc znakow jest prawidlowa, nawet widac to na zrzucie ekranu. Nie rozumiem tego wpisu, jaki ma zwiazek z problemem.
Pyton_000
jak użyjesz funkcji którą podałem to przy odczycie możesz zrobić

coś takiego:
  1. while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
  2. foreach ($data as $key => $value) {
  3. $data[$key] = trim($value, '"\'');
  4. }
  5. var_dump($data);
  6. }

dzięki temu szybko pozbędziesz się cudzysłowie z wiersza
kreatiff
Cytat
Dlaczego tak uwazasz? Nie rozumiem. Petla iteracyjna poprawnie docodzi do konca zmiennej typu string, co oznacza ze dlugosc jest poprawnie odczytana, ilosc znakow jest prawidlowa, nawet widac to na zrzucie ekranu. Nie rozumiem tego wpisu, jaki ma zwiazek z problemem.

Dlatego:
  1. $a = 'żółw';
  2. echo strlen($a) . '<br>'; // 7
  3. echo mb_strlen($a, 'UTF-8'); // 4
Ja zawsze korzystam z funkcji mb_*, jeśli tylko mam do czynienia z polskimi ogonkami. Jednak przyznam, że nie zagłębiałem się dokładnie w Twój kod. Po prostu jak tylko słyszę polskie znaczki czy UTF-8, od razu "przełączam się" na mb_*.
tomas3man
Cytat(kreatiff @ 23.10.2014, 11:38:11 ) *
Dlatego:
  1. $a = 'żółw';
  2. echo strlen($a) . '<br>'; // 7
  3. echo mb_strlen($a, 'UTF-8'); // 4
Ja zawsze korzystam z funkcji mb_*, jeśli tylko mam do czynienia z polskimi ogonkami. Jednak przyznam, że nie zagłębiałem się dokładnie w Twój kod. Po prostu jak tylko słyszę polskie znaczki czy UTF-8, od razu "przełączam się" na mb_*.


Rozumiem juz dlaczego. To dobra rada, dzieki bardzo. Faktycnie nie wiedzialem, ze takie jest zjawisko. Zamienie w kodzie. Ale mysle ze to nie wplywa na blad ktory opisalem.

Cytat(Pyton_000 @ 23.10.2014, 10:35:30 ) *
jak użyjesz funkcji którą podałem to przy odczycie możesz zrobić

coś takiego:
  1. while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
  2. foreach ($data as $key => $value) {
  3. $data[$key] = trim($value, '"\'');
  4. }
  5. var_dump($data);
  6. }

dzięki temu szybko pozbędziesz się cudzysłowie z wiersza


Super, dziekuje bardzo, nie wiedzialem ze moge uzyc kilka znakow jak '' lub ' w parametrze dla funkcji TRIM. Dziekuje bardzo, sprobuje uzy tego kodu i sprawdze jak dziala. Dam odpowiedz jeszcze dzis wieczorem po pracy, jak sie uda to klikne na klawisz POMOGL.

Mam jeszcze pytnie, dlaczego ustawiasz 1000 jako parametr w fgetcsv? Poprostu tak z random?
Pyton_000
To po prostu przykład z manuala smile.gif Nie chciało mi się pisać i tak zostało smile.gif
tomas3man
Cytat(Pyton_000 @ 23.10.2014, 10:35:30 ) *
jak użyjesz funkcji którą podałem to przy odczycie możesz zrobić

coś takiego:
  1. while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
  2. foreach ($data as $key => $value) {
  3. $data[$key] = trim($value, '"\'');
  4. }
  5. var_dump($data);
  6. }

dzięki temu szybko pozbędziesz się cudzysłowie z wiersza


DZIEKUJE!!!

Musialem zmienic lekko twoj skrypt bazujac na pomocy z podrrecznika i udalo sie, polskie litery nie powoduja bledow.

Oto skrypt:

  1.  
  2. function upload( $bank = null ) {
  3.  
  4. if ($this->request->is('post')) {
  5. $filename = TMP .$this->data['Payment']['file']['name'];
  6. /* copy uploaded file */
  7. if (move_uploaded_file($this->data['Payment']['file']['tmp_name'], $filename)) {
  8. echo "<font color=white><pre>";
  9. $fh = fopen($filename, 'r');
  10. $row = 1;
  11. while (($data = fgetcsv($fh, 1000, ";")) !== FALSE) {
  12. $num = count($data);
  13. echo "<p> $num fields in line $row: <br /></p>\n";
  14. $row++;
  15. for ($c=0; $c < $num; $c++) {
  16. echo trim( $data[$c], '"\'') . "<br />\n";
  17. }
  18. echo debug($data); <<<<===== tutaj
  19. }
  20. }
  21. fclose($fh);
  22. echo debug($data);
  23. }
  24. }
  25.  


------

Edytuje po okolo 30 minutach. Sytuacja sie nie zmienia. Skrypt pracuje prawidlowo, gdy nie polskiego znaku. To znaczy, jezeli w pliku CSV znajdzie sie polski znak to echo debug($data) zwraca pustke NULL. To samo zbadalem, ze jezeli wstawie w miejsce oznaczone przezemnie w petli echo debug($data) to w kazdej iteracji, ktora wczytuje jedna linie pliku CSV moge widziec co zawiera zmienna i widac dokladnie ze zmienna $data zamienia sie w NULL gdy w linni wystapi polski znak.

Wklejam wynik ekranu, gdy w pierwszej linni jest brak polskich znakow:

  1.  
  2. 8 fields in line 1:
  3.  
  4. 1 2014-09-09
  5.  
  6. 2 2014-09-09
  7.  
  8. 3 PRZELEW ZEWNETRZNY PRZYCHODZACY
  9.  
  10. 4 OPLATA ZA KURS, MICHAL XXXXXXXXXXX
  11.  
  12. 5 ANDRZEJ JERZY GRABCZAK UL. XXXXXXXXXXXXX 16 08-110 SIEDLCE
  13.  
  14. 6 501000000000000505050505
  15. 7 200,00
  16.  
  17. 8 250,67
  18.  
  19. /app/Controller/PaymentsController.php (line 360)
  20.  
  21. (int) 0 => '2014-09-09',
  22. (int) 1 => '2014-09-09',
  23. (int) 2 => 'PRZELEW ZEWNETRZNY PRZYCHODZACY',
  24. (int) 3 => 'OPLATA ZA KURS, MICHAL GRABCZAK',
  25. (int) 4 => 'ANDRZEJ JERZY XXXXXXXXX UL. XXXXXXXXXXXXXX 16 08-110 SIEDLCE',
  26. (int) 5 => ''500000000000080808080808080'',
  27. (int) 6 => '200,00',
  28. (int) 7 => '250,67',
  29. (int) 8 => ''
  30. )
  31.  
  32. 8 fields in line 2:
  33.  
Pyton_000
zamiast echo debug daj po prostu var_dump (cake?)
tomas3man
Cytat(Pyton_000 @ 23.10.2014, 19:39:07 ) *
zamiast echo debug daj po prostu var_dump (cake?)


A co moze zmienic? Myslisz, ze to jest blad Framework'a? Tak to jest Cake. Sprobuje dzis i dam ci znac.


Cytat(Pyton_000 @ 23.10.2014, 19:39:07 ) *
zamiast echo debug daj po prostu var_dump (cake?)


Wiesz Pyton_000, okazuje sie, że pomogło, to znaczy polecenie var_dump pokazuje, że zawartość tablicy $data zawiera dane, natomiast echo debug($data) pokazuje puste.

Dziwne to jest.
Pyton_000
Pokaż wynik z tego vd
tomas3man
Cytat(Pyton_000 @ 24.10.2014, 19:54:17 ) *
Pokaż wynik z tego vd


Dopisalem do pętli zapisywanie do bazy. Udalo sie, wszystkie pola przelewow i linie pliku CSV zapisaly sie w bazie. Ale zauwazylem, ze wszedzie gdzie w polu bazy wystepuje znak polski diakrytyczny, to ciag znakow jest urwany, np. "Janusz Łuczak" => "Janusz ".

Wklejam moj kod:

  1. if (move_uploaded_file($this->data['Payment']['file']['tmp_name'], $filename)) {
  2. $fh = fopen($filename, 'r');
  3. $row = 1;
  4. while (($data = fgetcsv($fh, 1000, ";")) !== FALSE) {
  5. $num = count($data)-1;
  6. $row++;
  7. for ($c=0; $c < $num; $c++) {
  8. $value = str_replace(" ", "", trim( $data[$c], '"\''));
  9. $csv[($row-1)][$c] = $value;
  10. } //end of for
  11. // Writting to transfer
  12. $t_volume = str_replace( ",", ".", $csv[($row-1)][6]);
  13. $t_volume2 = str_replace( " ", "", $t_volume);
  14. $this->Transfer->set(array(
  15. 'destination_bank' => 'mBank',
  16. 't_date' => $csv[($row-1)][0],
  17. 't_acounting_date' => $csv[($row-1)][1],
  18. 't_side' => $csv[($row-1)][2],
  19. 't_title' => $csv[($row-1)][3],
  20. 't_sender' => $csv[($row-1)][4],
  21. 't_account' => $csv[($row-1)][5],
  22. 't_volume' => $t_volume2
  23. ));
  24. $this->Transfer->save();
  25. $this->Transfer->clear();
  26. //end Writting to transfer
  27. }
  28. fclose($fh);
  29.  


To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.