[PHP] Variabele wijzigt bij invoeren in database

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Mijn vraag
Ik probeer momenteel een csv bestand in een mysql database te krijgen. Het uitlezen van de data gaat prima en als ik de data op het scherm echo word het ook keurig weergegeven maar als ik eerst een check inbouw die kijkt of het productnummer al ik de database staat dan voegt hij niet meer het productnummer in de database maar een heel ander veld terwijl $productnummer niet word gewijzigd.

Relevante software en hardware die ik gebruik
PHP, MySQL

Code:
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
28
$bestand = 'bestand.csv';
if(!file_exists($bestand)) {
    echo "File doesnt exist!";
} else {
    $file = fopen($bestand, "r");
    $i = 0;
    while (($emapData = fgetcsv($file)) !== FALSE) {
        if($i>0) {
            $data = explode(";", $emapData[0]);
            if(isset($data[0])) {
                $productnummer = $data[0];
            } else {
                $productnummer = '';
            }
           
            $sql = 'SELECT PRODUCT_NUMBER FROM tabelnaam WHERE PRODUCT_NUMBER = 
            "'.$productnummer.'" LIMIT 1'; 
            $result = mysqli_query($conn, $sql);
            if(mysqli_num_rows($result) == 0) {
                $sql_upload = 'INSERT INTO tabelnaam(product_number) VALUES("'.$productnummer.'")';
                mysqli_query($conn, $sql_upload);
            }
        }
        $i++;
    }
    echo 'Done';
    fclose($file);
}


Als ik dus de check weghaal die kijkt of het al in de database staat en $productnummer gewoon op het scherm echo geeft hij de juiste waarde aan. Maar op deze manier pakt hij een ander veld uit de array.

Wie helpt me een klein beetje opweg? :/

Beste antwoord (via Jasper_S1985 op 30-10-2020 14:49)


  • Orion84
  • Registratie: April 2002
  • Laatst online: 11:20

Orion84

Admin General Chat / Wonen & Mobiliteit

Fotogenie(k)?

Ziet er uit of fgetcsv splitst op , in plaats van ; waardoor het een bende wordt omdat sommige van je velden daadwerkelijk komma's bevatten.

Maar wat verwacht je in $productnummer en wat komt er in $productnummer?

En wat doet die $i variabele nu eigenlijk?

The problem with common sense is that it's not all that common. | LinkedIn | Flickr

Alle reacties


Acties:
  • +2 Henk 'm!

  • phYzar
  • Registratie: November 2001
  • Laatst online: 13:28
Wat is de opmaak van je csv file?

code:
1
$emapData = fgetcsv($file)


^^ Hier geeft de functie fgetcsv een array terug, met van 1 regel elke veld in een array-item.

code:
1
$data = explode(";", $emapData[0]);


^^ Hier pak je het eerste veld, maar gaat die weer opsplitsen alsof het je hele rij is? Als je puntkomma als delimiter wilt gebruiken kun je die beter opgeven aan fgetcsv:

https://www.php.net/manual/en/function.fgetcsv.php

code:
1
2
3
4
5
if(isset($data[0])) {
                $productnummer = $data[0];
            } else {
                $productnummer = '';
            }


^^ Hiermee check je of je wel of niet een productnummer hebt, maar vervolgens ga je hoe dan ook queries uitvoeren. In het geval van geen productnummer hoef je dat niet te doen toch?

En ik hoop dat je productnummer geen Bobby Tables heet.

Ik zou beginnen met zorgen dat wanneer je op regel 15 bent je zeker weet dat je een geldig productnummer hebt.

Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Hier pak je het eerste veld, maar gaat die weer opsplitsen alsof het je hele rij is? Als je puntkomma als delimiter wilt gebruiken kun je die beter opgeven aan fgetcsv:
Ja beetje rare file die we krijgen. Alle info staat in veld 1 en dan gesplitst met een ;. Rest van de velden zijn leeg vandaar dat ik alleen de eerste pak en daar een array van maak.

Ik zal je linkje eens gaan doorlezen
Wat is de opmaak van je csv file?
Behalve mijn uitleg hiervoor weet ik niet precies wat voor info je hier zoekt of wat ik uit moet leggen? :)
Hiermee check je of je wel of niet een productnummer hebt, maar vervolgens ga je hoe dan ook queries uitvoeren. In het geval van geen productnummer hoef je dat niet te doen toch?
Is inderdaad niet erg slim nee ik ga dit aanpassen thx

Acties:
  • +1 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Een paar vragen;
1. Hoe zien de eerste twee regels van je CSV eruit. Kan je die plaatsen? Desnoods met dummy data.
2. Laat de output zien van print_r($emapData); en print_r($data); na regel 9.
3. Laat eens zien wat de daadwerkelijke output is van $sql op regel 16 en $sql_upload van regel 20.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
CurlyMo schreef op vrijdag 30 oktober 2020 @ 14:16:
Een paar vragen;
1. Hoe zien de eerste twee regels van je CSV eruit. Kan je die plaatsen? Desnoods met dummy data.
2. Laat de output zien van print_r($emapData); en print_r($data); na regel 9.
3. Laat eens zien wat de daadwerkelijke output is van $sql op regel 16 en $sql_upload van regel 20.
Vraag 1
Hoop dat je wat aan een screenshot hebt
Afbeeldingslocatie: https://tweakers.net/i/azsvJxDkQAoQqMS1y_5nufgKunA=/800x/filters:strip_icc():strip_exif()/f/image/YQCc9eJ6ePWb3KcKHIMDuC3X.jpg?f=fotoalbum_large

Vraag 2
Ff de eerste 2 items van de array want het gaat om een paar duizend producten

print_r($emapData)
Array ( [0] => UTPCAT6;"UTP CAT6 comp datakabel binnen [1] => 6 [2] => 8 aders [3] => gel mat cu. Blank p/m";"Diverse";"";"TU";"";"21.00";"1.24";"";"";"0.00";"1.24";"";"0.00";"0.00";"1.50";"0.00";"Leverbaar";"0.00";"0.00";"";"0.00";"";"0.00";"0.00";"1000000000016";"";"Leverbaar";"";"";"";"";"";"";"";"";"";"";"";"Z";"";"0.00" ) Array ( [0] => BEEKMANDIV;"Beekman Diversen Winkel";"Onderdelen";"";"Beekman";"";"21.00";"14.04";"";"";"0.00";"14.04";"";"0.00";"0.00";"16.99";"0.00";"Leverbaar";"0.00";"0.00";"";"0.00";"";"0.00";"0.00";"5000000000814";"";"Leverbaar";"";"";"";"";"";"";"";"";"";"";"";"Z";"";"0.00" )

print_r($data)
Array ( [0] => UTPCAT6 [1] => "UTP CAT6 comp datakabel binnen ) Array ( [0] => BEEKMANDIV [1] => "Beekman Diversen Winkel" [2] => "Onderdelen" [3] => "" [4] => "Beekman" [5] => "" [6] => "21.00" [7] => "14.04" [8] => "" [9] => "" [10] => "0.00" [11] => "14.04" [12] => "" [13] => "0.00" [14] => "0.00" [15] => "16.99" [16] => "0.00" [17] => "Leverbaar" [18] => "0.00" [19] => "0.00" [20] => "" [21] => "0.00" [22] => "" [23] => "0.00" [24] => "0.00" [25] => "5000000000814" [26] => "" [27] => "Leverbaar" [28] => "" [29] => "" [30] => "" [31] => "" [32] => "" [33] => "" [34] => "" [35] => "" [36] => "" [37] => "" [38] => "" [39] => "Z" [40] => "" [41] => "0.00" )

Vraag 3
In principe gooi ik telkens bij het testen de database eerst weer leeg dus geeft de query 0 resultaat aan.

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

  • Orion84
  • Registratie: April 2002
  • Laatst online: 11:20

Orion84

Admin General Chat / Wonen & Mobiliteit

Fotogenie(k)?

Ziet er uit of fgetcsv splitst op , in plaats van ; waardoor het een bende wordt omdat sommige van je velden daadwerkelijk komma's bevatten.

Maar wat verwacht je in $productnummer en wat komt er in $productnummer?

En wat doet die $i variabele nu eigenlijk?

The problem with common sense is that it's not all that common. | LinkedIn | Flickr


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
De $i variabele zorgt er puur voor dat de eerste rij waar de tabelnamen staan wordt overgeslagen.

$productnummer moet de eerste tabel in het csv bestand weergeven. Die heeft PRODUCT_NUMBER.

Zoals ik zei.. Als ik $productnummer.'<br>' echo dan geeft hij netjes de juiste waardes weer. Alleen moet ik eerst weten of hij al in de database staat. En gooi ik die check erin dan gooit hij hele andere velden in de PRODUCT_NUMBER tabel.

Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Ik heb

while (($emapData = fgetcsv($file)) !== FALSE) {

veranderd naar

while (($emapData = fgetcsv($file,$delimiter=';')) !== FALSE) {

en nu werkt het :)

Bedankt voor het meedenken !

Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 03-10 23:11

DataGhost

iPL dev

Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 14:42:
De $i variabele zorgt er puur voor dat de eerste rij waar de tabelnamen staan wordt overgeslagen.
Dat kan je veel netter oplossen door iets als
code:
1
2
3
if(0 == $i++) {
    continue;
}

Dan is al veel duidelijker wat je bedoelt en hoeft de rest van wat je nu in de body van de if hebt daar niet te staan, maar erbuiten. Ook had je kunnen kiezen voor een losse fgetcsv- of fgets-call buiten je loop.

Wat is de structuur van je tabel, wat zijn eventuele errors/warnings die je krijgt (want daar check je nergens op)? En gebruik alsjeblieft prepared statements in plaats van deze string-prut-rommel. Wat je nu hebt gaat gegarandeerd een keer fout, en het is al minimaal een jaar of 10 geen gangbare manier van werken/aanleren meer. Ook voor "ja maar het is maar iets simpels" is het beter (en weinig extra werk) om het gewoon direct netjes te doen zodat dat een automatisme wordt.
Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 14:42:
Zoals ik zei.. Als ik $productnummer.'<br>' echo dan geeft hij netjes de juiste waardes weer.
Gezien de codewijziging die voor je oplossing gezorgd heeft kan ik me enorm goed voorstellen dat hij niet netjes de juiste waardes weergaf. Zoals @CurlyMo zei is het beter om print_r te gebruiken, of var_dump is de functie die ik zelf het liefst gebruik. Dan zie je ook of er niet toevallig rommel omheen staat zoals whitespace of wat anders.

[ Voor 26% gewijzigd door DataGhost op 30-10-2020 14:57 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 14:32:
[...]
Vraag 3
In principe gooi ik telkens bij het testen de database eerst weer leeg dus geeft de query 0 resultaat aan.
Daar bedoelde ik:
PHP:
1
2
$sql = 'SELECT PRODUCT_NUMBER FROM tabelnaam WHERE PRODUCT_NUMBER = "'.$productnummer.'" LIMIT 1'; 
echo $sql;

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Die eerste sql klopt alleen bij de sql_upload zie ik

INSERT INTO vendit_upload(product_number, product_description) VALUES("UTPCAT6", ""UTP CAT6 comp datakabel binnen")

Op 1 of andere manier gooit hij 2x een " voor UTP CAT6

Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 03-10 23:11

DataGhost

iPL dev

Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 16:16:
Die eerste sql klopt alleen bij de sql_upload zie ik

INSERT INTO vendit_upload(product_number, product_description) VALUES("UTPCAT6", ""UTP CAT6 comp datakabel binnen")

Op 1 of andere manier gooit hij 2x een " voor UTP CAT6
Daardoor is je query ongeldig en zal je een error gehad hebben, maar daar check je niet op. Goede reden om te error-checken dus.
Met prepared statements had je geen error gehad en was de query gewoon goedgegaan, dan had je die extra " gewoon in je database teruggevonden. Goede reden om prepared statements te gebruiken dus. Wat je nu hebt is een klassiek geval SQL-injectie.

Je uiteindelijk correcte gebruik van fgetcsv() heeft het "gefixt", de aanhalingstekens konden daardoor wel fatsoenlijk geïnterpreteerd worden.

En je hebt het wel voor elkaar gekregen om de code te wijzigen voor het maken van je startpost (zodanig dat de query die ik hier van je quote niet terug te vinden is in je code) maar hebt die code vervolgens niet getest. In dit specifieke geval zou de code in je TS wel gewoon goedgegaan zijn denk ik. Ik vond het al ontzettend raar dat alleen de wijziging van die call je oplossing was, aangezien er met $productnummer nog niks aan de hand was. Volgende keer dus graag de code ongewijzigd, op het *eventueel* redacten van tabelnamen na, of in ieder geval de code die je wilt laten zien even testen om te zien of het nog steeds fout gaat. Ik weet zeker dat @CurlyMo je dan ook om een print_r van je $productdescription (oid) had gevraagd en dan was de aap daar uit de mouw gekomen. Nou ja, het was eigenlijk al wel te zien in de print_r van je $data
[1] => "UTP CAT6 comp datakabel binnen
maar niemand zag jou ergens $data[1] gebruiken.

[ Voor 35% gewijzigd door DataGhost op 30-10-2020 16:35 ]


Acties:
  • +1 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Leren debuggen kan niet losstaan van leren programmeren.

Oftewel, nu je een beetje door hebt hoe je simpele (maar uiterst foutgevoelige) code weet te schrijven, wordt het tijd te leren debuggen.

Les 1 van debuggen: Controleer al je aannames.

In dit topic hebben we de aandacht op de volgende punten gelegd:
- Controleer de inhoud van al je variabelen
- Controleer de return codes van je functies
- Controleer de standaard waardes van optionele parameters van de gebruikte functies.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Les 0, als je hulp vraag op tweakers, leer dan wat ubb codes zijn en specifiek de code tags.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Het probleem zat hem schijnbaar in de haakjes.

Heb alles veranderd naar dubbele quotes met de variabelen tussen enkele en het werkt zoals het hoort.

Ik snap dat dit een oude manier van php is. Ik heb het geleerd van oude tutorials denk ik. Gelukkig is dit voor een klein projectje en niet voor een webshop of iets dergelijks. Uiteraard neem ik de tips mee en ga me focussen om iets meer bij de tijd te komen. Dank allen!

Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 16:53:
Het probleem zat hem schijnbaar in de haakjes.
Hoe dan?
Heb alles veranderd naar dubbele quotes met de variabelen tussen enkele en het werkt zoals het hoort.
Totdat in je CSV een enkele quote voorkomt. En dat hoeft niet alleen als begin/eind quotes te zijn maar kan ook door de Nederlandse taal komen zoals bij het woord cafe's.

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 03-10 23:11

DataGhost

iPL dev

Ik snap dat dit een oude manier van php is. Ik heb het geleerd van oude tutorials denk ik. Gelukkig is dit voor een klein projectje en niet voor een webshop of iets dergelijks. Uiteraard neem ik de tips mee en ga me focussen om iets meer bij de tijd te komen. Dank allen!
:(
Ik heb precies gezegd dat dit een grote denkfout is en een verkeerd argument. Ik zag het al aankomen en heb jouw woorden al bijna letterlijk gequote nog voordat jij ze opschreef. Straks wordt je project groter, of ben je een keer aan iets anders, groters aan het werken en heb je nooit wat anders geleerd, sta je er niet eens bij stil wat de implicaties kunnen zijn en dan komt jouw eindproduct een keer op de frontpage van Tweakers te staan als zoveelste datalek.
Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 16:53:
Het probleem zat hem schijnbaar in de haakjes.
Nee, het probleem zit in de manier waarop jij je queries maakt en uitvoert.
Heb alles veranderd naar dubbele quotes met de variabelen tussen enkele en het werkt zoals het hoort.
Dan hoop ik bijna dat je straks een product tegenkomt met een apostrof in de naam, zodat je het weer kapot kan zien gaan. Prepared statements zijn niet veel lastiger te gebruiken maar je hebt gewoon geen zin om er uberhaupt naar te kijken. Als je nou eventjes een klein beetje moeite steekt in het uitzoeken hoe het fatsoenlijk moet kan je dat voortaan bij al je projecten direct goed doen. Er is geen enkele reden om een tig jaar oude, verouderde en afgekeurde methode te blijven gebruiken.

Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 03-10 23:11

DataGhost

iPL dev

If I had to guess:
code:
1
'INSERT ... VALUES("'.$productnummer.'", "'.$productnaam.'")'

veranderd in
code:
1
"INSERT ... VALUES('".$productnummer."', '".$productnaam."')"

:X

Edit: met haakjes bedoelt 'ie waarschijnlijk aanhalingstekens dus.

Edit2: met prepared statements wordt het iets als
code:
1
"INSERT ... VALUES(?, ?)"

of
code:
1
"INSERT ... VALUES(:nummer, :naam)"

en dat scheelt een heel gekut met "'. ."' '". ."', het schelden daarop als je het weer eens fout typt en de leesbaarheid wordt stukken beter. Daarna kan je de variabelen aan de placeholders binden, wederom zonder geklooi met aanhalingstekens en punten.

Een van de grootste leugens van programmeurs (in ieder geval als ik naar mezelf kijk) is "dat zoek ik later wel een keer goed uit en dan fix ik het". De kans op later uitzoeken is sowieso al klein en mocht dat dan tóch gebeuren, is de kans op het fixen in je bestaande code echt nihil. Als je toch de tijd erin wilt gaan steken om het uit te gaan zoeken kan je dat net zo goed nu doen en dan ook direct goed doen. Dan is daar direct het incentive om het goed aan te pakken.
Begin maar eens met een product in je csv te zetten waar een apostrof in zit en ook eentje met aanhalingstekens. Dus productnamen als
code:
1
2
It's-a-me, Mario
The "best" product

ofzo, en zorg dat je script dat aankan. Ga dan alsjeblieft niet eigenwijs doen met de vele lelijke manieren om dat zonder prepared statements te bewerkstelligen want voor de meeste daarvan zijn weer andere exploits te vinden.

[ Voor 77% gewijzigd door DataGhost op 30-10-2020 17:19 ]


Acties:
  • 0 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Maar dat heeft niks met haakjes te maken :s

Sinds de 2 dagen regel reageer ik hier niet meer


Acties:
  • 0 Henk 'm!

  • Jasper_S1985
  • Registratie: Februari 2015
  • Laatst online: 03-10 17:50
Ondanks dat jullie boos worden nog steeds bedankt voor jullie hulp.
maar je hebt gewoon geen zin om er uberhaupt naar te kijken
Volgens mij zei ik net dat ik me erin ging verdiepen. Dan kan ik het daarna namelijk aanpassen.
Wederom dit is een hobbyprojectje.. Al lekt de hele database en word alles gestolen boeit dat nog niet.
Ik ben niet te lui om te leren. Ik vind het voor nu gewoon ff prettig dat het werkt en nu kan ik me gaan verdiepen in betere methodes. Niet nodig om gelijk zo chagie te worden.

Acties:
  • +1 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 03-10 23:11

DataGhost

iPL dev

Zie het vooral als hulp die we je graag willen bieden, waardoor het voor jou in de toekomst alleen maar makkelijker wordt. Als je het binnenkort uit wilt zoeken vraag ik: waarom niet nu direct al? Daag jezelf uit met de input die op dit moment misschien niet in je dump zit maar wel je script kapot zal maken, en zorg dat dat geen probleem gaat vormen op het moment dat het er misschien wel in komt. Programmeren kán snel en makkelijk maar zo is het eigenlijk niet bedoeld. Je moet een heleboel saaie shit eromheen doen om te zorgen dat alles blijft werken en zodat je weet wat waar waarom misgaat.

Misschien dat mijn posts een beetje chagrijnig overkomen en dat is niet zozeer als aanval op jou bedoeld maar als hopelijk constructieve kritiek :) Ik zit persoonlijk met de frustratie dat ik tig mensen op dezelfde manier als beginner PHP heb zien leren of als "veteraan" nog krampachtig vast heb zien houden aan het oude "want dat werkt toch gewoon?". Daarnaast voelt het "negeren" van het direct toepassen van de aangedragen oplossingsrichting en het daarbij juist gebruiken van (ik zeg het maar bot) zo ongeveer het slechtste alternatief waarvan ik hoopte dat het niet eens in je opkwam, als een bevestiging van de gedachte "ohjee dat is er weer zo eentje". Vanuit mijn eigen ervaring statistisch gezien is het niet heel waarschijnlijk dat je met de mindset die ik uit je posts opmaak heel veel aan verbetering gaat doen. Dat is geen aanval op jou direct, maar dat is de verwachting die ik heb gebaseerd op anderen. Dat is gewoon doodzonde en ik hoop inderdaad dat jij niet bij dat rijtje komt te staan en mijn voorspelling bevestigt.

PHP is een prima taal met helaas een hoop legacy-crap, en het tot in het einde der tijden blijven bestaan van een enorme hoeveelheid oude, slechte tutorials zorgt ervoor dat het niveau van de gemiddelde PHP-developer een beetje onder dat van andere developers ligt. Aangezien het wel allemaal "werkt" schrijven die op een gegeven moment weer nieuwe "oude, slechte tutorials" waardoor dit specifiek een erg hardnekkige manier van verkeerd programmeren met databases is geworden. Daarom probeer ik vooral beginners zo snel mogelijk een betere kant op te duwen.

Acties:
  • +2 Henk 'm!

  • CurlyMo
  • Registratie: Februari 2011
  • Laatst online: 12:02
Jasper_S1985 schreef op vrijdag 30 oktober 2020 @ 17:20:
Ondanks dat jullie boos worden nog steeds bedankt voor jullie hulp.
Nu wel ja :(
...
...
...
...
...
...

:P

Sinds de 2 dagen regel reageer ik hier niet meer

Pagina: 1