PHP import CSV

Pagina: 1
Acties:

Onderwerpen

Vraag


Acties:
  • 0 Henk 'm!

  • josvane
  • Registratie: Oktober 2002
  • Laatst online: 16:14
Al enige tijd ben ik aan het proberen om een CSV bestand met PHP in te lezen in een mysql database.
Via een formulier upload ik een CSV file welke dit omzet in een array.

Om dubbele records te voorkomen in de database wil ik op basis van het artikelnummer controleren of het bestaand artikel is of dat het gaat om een nieuw artikel.

Het zijn er natuurlijk meerdere maar een array ziet er zo uit
code:
1
2
3
4
5
6
7
8
9
10
11
12
Array
(
    [sku] => USG-3
    [search_code] => Ubiquiti
    [description] => Ubiquiti USG 3 security gateway
    [article_group] => 8000
    [is_divisible] => 0
    [journal_code_credit] => 8000
    [journal_code_debit] => 7000
    [is_active] => 1
    [exact] => 0
)

sku is degene die niet dubbel mag voorkomen. Als ik in mijn where statement deze waarde gebruik dan krijg ik geen resultaat. Vul ik USG-3 handmatig in dan werkt de query wel.

Als ik mijn sql code vergelijk zijn deze letterlijk identiek.
SQL code met variabele
code:
1
SELECT crm_articles.id, crm_articles.article_group, crm_articles.sku, crm_articles.is_active, crm_articles.created_at, crm_articles.description, crm_articles.price, crm_article_groups.label AS type FROM crm_articles LEFT JOIN crm_article_groups ON crm_articles.article_group = crm_article_groups.id WHERE crm_articles.sku = "USG-3"


SQL code met handmatig ingevulde sku
code:
1
SELECT crm_articles.id, crm_articles.article_group, crm_articles.sku, crm_articles.is_active, crm_articles.created_at, crm_articles.description, crm_articles.price, crm_article_groups.label AS type FROM crm_articles LEFT JOIN crm_article_groups ON crm_articles.article_group = crm_article_groups.id WHERE crm_articles.sku = "USG-3"


Zoals te zien totaal geen verschil.

Als ik onderstaande doe, dan is het resultaat string.
PHP:
1
echo gettype($data['sku']);

Daarnaast heb ik het geprobeerd zonder qoutes.
Iemand tips?

Beste antwoord (via josvane op 31-12-2020 11:48)


  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Anoniem: 1302638 schreef op woensdag 30 december 2020 @ 21:49:
dan is dit de snelste methode om het verschil te zien.
Nee, de snelste manier om te zien óf er verschil is ;) Hét verschil zie je als je gewoon ASCII waardes dumpt ofzo. Er is inderdaad kans dat er een 'tab' of ander 'onzichtbaar' teken in je waarde zit.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
function dump_string($value) {
  $result = '';
  for ($i = 0; $i < strlen($value); $i++) {
    $hexval = dechex(ord($value[$i]));
    $result .= "$value[$i] $hexval\n";
  }
  return $result;
}

echo dump_string($data['sku']);
?>

Geeft iets als:
U 55
S 53
G 47
- 2d
3 33


Verder eens met @Daos: gebruik parameterized queries.

Even los van dat alles: "Om dubbele records te voorkomen" heb je gewoon een unique constraint. Laat heel die select lekker zitten en laat je DB het lekker uitzoeken. Nu is 't maar een import scriptje, maar als je met meerdere gebruikers (of scripts die tegelijkertijd lopen enzo) te maken krijgt dan heb je een race condition. MySQL heeft daar een (non-ANSI SQL) on duplicate key voor, waar dat in veel andere RDBMS'en merge is.

[ Voor 40% gewijzigd door RobIII op 30-12-2020 22:31 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Alle reacties


Acties:
  • 0 Henk 'm!

  • Daos
  • Registratie: Oktober 2004
  • Niet online
Prepared statements gebruiken. Is sowieso nodig als je sql-injection wilt voorkomen. Je moet zelf even zoeken op die prepared statements in combinatie met pdo of mysqli (welke van de 2 je gebruikt in je project)

Acties:
  • 0 Henk 'm!

Anoniem: 1302638

Wat is het verschil tussen md5($deEneSKU) en md5($deAndereSKU)?

Ik weet het, md5, bla bla bla, maar als je extra spaties hebt of gekke leestekens ofzo dan is dit de snelste methode om het verschil te zien.

Acties:
  • Beste antwoord
  • +3 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Anoniem: 1302638 schreef op woensdag 30 december 2020 @ 21:49:
dan is dit de snelste methode om het verschil te zien.
Nee, de snelste manier om te zien óf er verschil is ;) Hét verschil zie je als je gewoon ASCII waardes dumpt ofzo. Er is inderdaad kans dat er een 'tab' of ander 'onzichtbaar' teken in je waarde zit.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
function dump_string($value) {
  $result = '';
  for ($i = 0; $i < strlen($value); $i++) {
    $hexval = dechex(ord($value[$i]));
    $result .= "$value[$i] $hexval\n";
  }
  return $result;
}

echo dump_string($data['sku']);
?>

Geeft iets als:
U 55
S 53
G 47
- 2d
3 33


Verder eens met @Daos: gebruik parameterized queries.

Even los van dat alles: "Om dubbele records te voorkomen" heb je gewoon een unique constraint. Laat heel die select lekker zitten en laat je DB het lekker uitzoeken. Nu is 't maar een import scriptje, maar als je met meerdere gebruikers (of scripts die tegelijkertijd lopen enzo) te maken krijgt dan heb je een race condition. MySQL heeft daar een (non-ANSI SQL) on duplicate key voor, waar dat in veel andere RDBMS'en merge is.

[ Voor 40% gewijzigd door RobIII op 30-12-2020 22:31 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Wim-Bart
  • Registratie: Mei 2004
  • Laatst online: 10-01-2021

Wim-Bart

Zie signature voor een baan.

Codering, ASCII UTF-8 UTF-16 Unicode...... In de editor ziet het er allemaal het zelfde uit maar voor een applicatie kan het zo maar verschillende gegevens zijn.

Overigens EAN code moet uniek zijn en SKU hoeft dat niet.

Beheerders, Consultants, Servicedesk medewerkers. We zoeken het allemaal. Stuur mij een PM voor meer info of kijk hier De mooiste ICT'er van Nederland.


Acties:
  • 0 Henk 'm!

  • josvane
  • Registratie: Oktober 2002
  • Laatst online: 16:14
RobIII schreef op woensdag 30 december 2020 @ 21:58:
[...]

Nee, de snelste manier om te zien óf er verschil is ;) Hét verschil zie je als je gewoon ASCII waardes dumpt ofzo. Er is inderdaad kans dat er een 'tab' of ander 'onzichtbaar' teken in je waarde zit.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
function dump_string($value) {
  $result = '';
  for ($i = 0; $i < strlen($value); $i++) {
    $hexval = dechex(ord($value[$i]));
    $result .= "$value[$i] $hexval\n";
  }
  return $result;
}

echo dump_string($data['sku']);
?>

Geeft iets als:
U 55
S 53
G 47
- 2d
3 33


Verder eens met @Daos: gebruik parameterized queries.

Even los van dat alles: "Om dubbele records te voorkomen" heb je gewoon een unique constraint. Laat heel die select lekker zitten en laat je DB het lekker uitzoeken. Nu is 't maar een import scriptje, maar als je met meerdere gebruikers (of scripts die tegelijkertijd lopen enzo) te maken krijgt dan heb je een race condition. MySQL heeft daar een (non-ANSI SQL) on duplicate key voor, waar dat in veel andere RDBMS'en merge is.
Thx voor je feedback, ik heb weer leesvoer.
Anoniem: 1302638 schreef op woensdag 30 december 2020 @ 21:49:
Wat is het verschil tussen md5($deEneSKU) en md5($deAndereSKU)?

Ik weet het, md5, bla bla bla, maar als je extra spaties hebt of gekke leestekens ofzo dan is dit de snelste methode om het verschil te zien.
Er zit inderdaad een verschil tussen de md5 waardes

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
josvane schreef op woensdag 30 december 2020 @ 22:41:

Er zit inderdaad een verschil tussen de md5 waardes
Nou, dan laat je de dump_string(...) op beide waardes los en kijk je naar de verschillen.

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Mr. HTTP
  • Registratie: November 2020
  • Laatst online: 09-03-2022
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php


$sku = " \tUSG-3\r\n";
// $sku = "USG-3";


// Identify at least one white space character in UTF-8 mode (debug use-case)
// Does SKU have any white space?
if ( preg_match('/\s/u',$sku) === 1 ) {
  echo 'Hello kind sir, I have some of the finest white space for you!' . PHP_EOL;
  // debug
  var_dump($sku);
  // do json_encode to see characters encoded as \r \n \t \u0000 etc
  echo json_encode($sku);
}


// Make sure SKU from a CSV import is in the correct format/syntax (production use-case)
// SKU validation approach
if ( preg_match('/^[A-Za-z0-9\-]{1,32}$/',$sku) === 1 ) {
  echo 'SKU is a string with at least one character from the ranges A-Z, a-z, 0-9 or a dash (-), with a max of 32 characters' . PHP_EOL;
} else {
  echo 'You got problems buddy!' . PHP_EOL;
}

?>

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// more PCRE love

// remove all white space
$sku = 'A1  -  B2  -   C3';
$sku_no_wsp = preg_replace('/\s{1,}/u','',$sku);
var_dump($sku_no_wsp); // A1-B2-C3

// remove all that is NOT from the ranges A-Z, a-z, 0-9 or a dash (-)
$sku = 'A1 !@ - B2 - ^$  C3';
$sku_cleaned = preg_replace('/[^A-Za-z0-9\-]{1,}/u','',$sku);
var_dump($sku_cleaned); // A1-B2-C3

?>


Bij dit soort problemen is er meestal hetvolgende aan de hand;
  • Er wordt geen rekening gehouden met een BOM (byte order mark) aan het begin van het CSV bestand.
  • Er wordt geen rekening gehouden met character encoding (UTF-8 of Latin1).
  • Er wordt geen rekening gehouden met verschil in EOL (end of line characters), \r\n (CRLF) op Windows, \n (LF) op Linux.
  • Er wordt geen schema validatie gedaan. - Geen checks of de input data klopt.
  • De CSV wordt steeds opgeslagen met extra markup (voorloopnullen, whitespace padding, locale conversion) of onzichtbare tekens vanwege wild copy-paste gedrag (RightToLeft of NonBreakingSpace markers).

[ Voor 46% gewijzigd door Mr. HTTP op 31-12-2020 00:11 ]


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
josvane schreef op woensdag 30 december 2020 @ 22:41:
Er zit inderdaad een verschil tussen de md5 waardes
Gebruik eens bin2hex() op die waarde, dan weet je exact het probleem.

Maak je niet druk, dat doet de compressor maar


  • Voutloos
  • Registratie: Januari 2002
  • Niet online
RobIII geeft al een gebruiksvriendelijke debug functie, dus vanwaar de drang om als spuit 11 incomplete suggesties te geven?

{signature}


Anoniem: 80910

Een goede functie is trim() te gebruiken op elk veld van je CSV, dan haal je die whitespace zo weg. Indien je geen str_getcsv() hebt gebruikt zie https://stackoverflow.com...647/multibyte-trim-in-php voor meer dan trim ascii karakters

[ Voor 27% gewijzigd door Anoniem: 80910 op 31-12-2020 21:47 ]


  • DJMaze
  • Registratie: Juni 2002
  • Niet online
Voutloos schreef op donderdag 31 december 2020 @ 11:37:
RobIII geeft al een gebruiksvriendelijke debug functie, dus vanwaar de drang om als spuit 11 incomplete suggesties te geven?
Rob zijn functie is correct voor standaard latin, niet voor unicode.
bin2hex is gewoon ook een manier, net als mb_strlen enzo.

Maak je niet druk, dat doet de compressor maar


  • Mr. HTTP
  • Registratie: November 2020
  • Laatst online: 09-03-2022
Anoniem: 80910 schreef op donderdag 31 december 2020 @ 18:18:
Een goede functie is trim() te gebruiken op elk veld van je CSV, dan haal je die whitespace zo weg. Indien je geen str_getcsv() hebt gebruikt
Als toevoeging; werkt dus alleen voor ASCII white space (single bytes characters). Een onzichtbare NBSP \u{00A0} haal je er niet mee weg.

  • Mr. HTTP
  • Registratie: November 2020
  • Laatst online: 09-03-2022
DJMaze schreef op donderdag 31 december 2020 @ 18:40:
[...]

Rob zijn functie is correct voor standaard latin, niet voor unicode.
bin2hex is gewoon ook een manier, net als mb_strlen enzo.
Rob is idd correct voor single byte characters/binary, vandaar was ook mijn aanvulling op Rob. Met UTF-8 PCRE (/u modifier) en json_encode als maniertjes om snel bijzondere tekens en white space te spotten vanwege de conversie naar \t \n \u0000 (multi-byte characters) etc. in JSON strings. (Er vanuit gaande dat de workflow van TS in UTF-8 is en daar ook bij de import op getoetst wordt en er eventueel een conversie plaatsvindt. )

De opmerking van @Voutloos is waarschijnlijk omdat bin2hex niets meer toevoegt in deze context. Het ziet ook geen Unicode ofzo, als je dat denkt.

Zie dit voorbeeldje met CRLF (carriage return, line feed)
PHP:
1
2
3
4
5
6
7
8
9
$a = dechex(ord("\r"));
$b = dechex(ord("\n"));
$a_and_b = bin2hex("\r\n");

print_r([
  'a' => $a,
  'b' => $b,
  'a_b' => $a_and_b
]);


code:
1
2
3
4
5
6
Array
(
    [a] => d
    [b] => a
    [a_b] => 0d0a
)

[a] en [b] mist de voorloopnul, dat is normaal.

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
DJMaze schreef op donderdag 31 december 2020 @ 18:40:
[...]

Rob zijn functie is correct voor standaard latin, niet voor unicode.
Dat is helemaal niet relevant hier. Ja, er zijn vele mitsen rnaren en subtiliteiten in strings en hun encodings. Hier wil je gewoon even de "rauwe bytes" zien en dat komt, sorta-min-of-meer, neer op een "ASCII dump". Boeie. We kunnen hier in al die subtiliteiten gaan verzanden en het allemaal veel moeilijker maken dan nodig voor TS en er een wedstrijdje ver-pissen van maken óf TS gewoon even een inzicht verschaffen dat er waarschijnlijk iets onverwachts, en waarschijnlijk "onzichtbaars", in z'n string zit (en wáár dan). En mijn voorgestelde code werkt daar prima voor, unicode of niet.

[ Voor 26% gewijzigd door RobIII op 31-12-2020 21:58 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij

Pagina: 1