PHP en MySQL. Insert lukt niet.

Overzicht Reageren

Sponsored by: Vacatures door Monsterboard

Wilco Rakhorst

Wilco Rakhorst

28/10/2015 23:05:49
Quote Anchor link
Ik ben bezig met het maken van een prive website waarbij ik gebruik maak van PHP en een MySQL database. Nu heb ik er geen moeite mee om de querys via PHP MyAdmin de database te vullen.
Nu is het de bedoeling dat ik dat via een webpagina ga doen, zodat ik de data op een snelle(re) manier kan invoeren. Op termijn is het de bedoeling dat anderen ook toegang krijgen tot de pagina en hiermee dus ook de database kunnen vullen.

Ik heb hieronder een stuk tekst met daaronder de betreffende code geplaatst, met daaronder een nieuw stuk tekst en een nieuw stuk code, etc.

Ik heb hiervoor een script gebruikt via http://www.sitemasters.be/tutorials/2/1/78/MySQL/Formulier. Zie ook hieronder. Dit werkt prima.
Ik roep de php pagina db_config aan waarin mijn inloggegevens staan voor de (lokale) database.

Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php
require_once 'db_config.php'; //verbinding maken
mysql_select_db('rum') or die (mysql_error());  //errorhandling

if(isset($_POST['verzenden']))
  {

    $sVoornaam        =    addslashes($_POST['voornaam']);
    $sAchternaam      =    addslashes($_POST['achternaam']);
    $iLeeftijd        =    addslashes($_POST['leeftijd']);
    
    mysql_query("INSERT INTO formulier (voornaam, achternaam, leeftijd) VALUES ('".$sVoornaam."', '".$sAchternaam."', '".$iLeeftijd."')") or die (mysql_error());

    echo 'Je gegevens zijn succesvol in de database geplaatst';
  }

else
  {
?>

<form action=" <?=$_SERVER['PHP_SELF']?>  " method="POST">
 Voornaam: <input type="text" name="voornaam"><br />
Achternaam: <input type="text" name="achternaam"><br />
Leeftijd: <input type="text" name="leeftijd"><br />
<input type="submit" name="verzenden" value="verzenden">
</form>
<?
  }
?>



Ik heb een aantal waarden aangepast en ik heb er onderstaand van gemaakt. Als ik dit uitvoer krijg ik mijn pagina met textboxen en een verzend knop weer terug, maar er worden geen records in de tabel `nose` weggeschreven.


Code (php)
PHP script in nieuw venster Selecteer het PHP script
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
<?php    
require_once 'db_config.php'; //verbinding maken
mysql_select_db('rum') or die (mysql_error());  //errorhandling

if(isset($_POST['verzenden']))
  {

    $cRumName        =    addslashes($_POST['RumName']);
    $iAge             =    addslashes($_POST['Age']);
    
    mysql_query("INSERT INTO `nose` ('RumName', 'Age') VALUES ('".$cRumName."', '".$iAge."')") or die (mysql_error());
    

    
  }

else
{
 
?>

<form action=" <?=$_SERVER['PHP_SELF']?>  " method="POST">
Rumnaam: <input type="text" name="RumName"><br />
Leeftijd: <input type="text" name="Age"><br />
<input type="submit" name="Verzenden" value="Verzenden">
</form>
<?php
    }
?>



Ik heb ook een query gemaakt in PHP die uit dezelfde tabel de waarden naam en leeftijd teruggeeft en in een tabel plaatst op de site. Dit gaat zonder problemen. (De code hiervoor staat hieronder).


Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
require_once 'db_config.php'; //verbinding maken
mysql_select_db('rum') or die (mysql_error());  //errorhandling
$query = "SELECT `Age`,`RumName` FROM `nose` WHERE `Age` > '5' ";
//query is aangemaakt
$sql = mysql_query($query) or die ( mysql_error( ) );
//query is uitgevoerd
echo"<table>
 <tr><td>Naam</td><td>Leeftijd</td></tr>"
;
while($record = mysql_fetch_object($sql)){
echo"<tr><td>".$record->RumName."</td><td>".$record->Age."</td></tr>";
}

echo"</table>";

?>


Eerst dacht ik aan een rechten probleem, omdat ik wel kan lezen, maar niet kan schrijven. Ik heb daarom het gekopieerde script nog een keer in mijn PHP pagina gebruikt om te zien of ik de voornaam, achternaam en leeftijd in een andere tabel in dezelfde database wel weg kan schrijven. Dat lukte wel, dus ik denk dat het veilig is om de aanname te doen dat er voldoende rechten zijn.
Ik had eigenlijk gehoopt dat het gedeelte 'or die (mysql_error());' er voor zou zorgen dat ik een foutmelding zou zien, maar dat gebeurt ook niet. Ik heb dus nu geen idee wat ik fout doe en waar ik het nog moet zoeken.
Waarschijnlijk is het voor de toppers hier een peuleschilletje, dus als iemand me op weg zou willen helpen zou ik zeer dankbaar zijn.
- Ariën -:
Gelieve in het vervolg bij code de [code][/code]-tags gebruiken.
Hier kan je meer lezen over de mogelijke opmaakcodes.
Alvast bedankt!
Gewijzigd op 01/11/2015 09:52:44 door - Ariën -
 
PHP hulp

PHP hulp

27/04/2024 16:04:00
 
- SanThe -

- SanThe -

28/10/2015 23:22:57
Quote Anchor link
Je hebt de tabelnamen tussen quotes staan waardoor het als tekst wordt gezien en niet als tabel.
Verder is addslashes() geen beveiliging voor de database.
 
Wilco Rakhorst

Wilco Rakhorst

29/10/2015 00:11:19
Quote Anchor link
Bedankt voor je reactie. Ik heb deze regel aangepast:

mysql_query("INSERT INTO nose (RumName, Age) VALUES ('".$cRumName."', '".$iAge."')") or die (mysql_error());

Ook dat heeft niet geholpen.
Ook de volgende variaties werkten niet:
mysql_query("INSERT INTO nose (RumName, Age) VALUES ('.$cRumName.', '.$iAge.')") or die (mysql_error());

mysql_query("INSERT INTO nose (RumName, Age) VALUES (".$cRumName.", ".$iAge.")") or die (mysql_error());
 
Thomas van den Heuvel

Thomas van den Heuvel

29/10/2015 00:40:01
Quote Anchor link
<input type="submit" name="Verzenden" value="Verzenden">

if(isset($_POST['verzenden']))

Array indices zijn Case Sensitive.

Gebruik gewoon overal lowercase namen.

Ook is de volgende manier een betere om te kijken of er iets gesubmit is via POST:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
4
5
6
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // process form yolo
    // ...

}
?>
 
Willem vp

Willem vp

29/10/2015 07:43:04
Quote Anchor link
Nog even een paar puntjes aanstippen die niet de oorzaak zijn van dit probleem:

1) Je zet integer-waardes (zoals Age) tussen quotes. MySQL vindt het niet fout, maar het is altijd netter om getallen als getallen te behandelen en niet als strings. Hopelijk heb je Age gedefinieerd als een integer-type en niet als een (var)char, want dan kun je wel serieuze problemen verwachten.

2) De mysql-extensies gaan ergens in de toekomst vervallen. Als je dan niet je hele code wilt herschrijven, is het handig om nu alvast gebruik te maken van de mysqli-extensies of van PDO.
 
Thomas van den Heuvel

Thomas van den Heuvel

29/10/2015 11:07:30
Quote Anchor link
@opmerking 1 van Willem: ben ik het op zich wel mee eens, maar het is dan des te belangrijker dat je je invoer dan controleert (input filtert) om te zien of deze voldoet (de waarde ook daadwerkelijk numeriek is) voordat je deze in je query verwerkt.

Een typecast middels (int) is uit den boze, omdat er in dat geval mogelijk getracht wordt invoer die helemaal geen getal bevatte om te zetten naar een getal. Vaak levert dat dan het cijfer nul op, of een andere, maar tevens onvoorspelbare, waarde.
 
Obelix Idefix

Obelix Idefix

29/10/2015 12:11:16
Quote Anchor link
Waarom sla je een leeftijd op en niet de geboortedatum?
Over drie jaar is iemand in jouw database nog net zo oud als nu...
 
Wilco Rakhorst

Wilco Rakhorst

29/10/2015 13:28:17
Quote Anchor link
Iedereen bedankt voor de input. Voor de volledigheid zal ik wat meer achtergrond info over dit project geven.

Een paar keer per jaar komen we met vrienden bij elkaar om een rum en whiskey proeverij te houden. Iedereen neemt 1 of meerdere flessen mee en laat de overige deelnemers er van proeven.
Omdat we op de avond zelf alleen aan het genieten zijn en geen notities maken rees het plan om hiervoor een website op te zetten, zodat je kon kijken welke rum of whiskey de revue zijn gepasseerd en wat de verschillende smaken en stadia (geur, pallet en afdronk) zijn. Op die manier kun je ook gaan vergelijken op soorgelijke whiskeys of rums.
Dat is ook direct de reden dat ik de leeftijd opsla, omdat een rum of whiskey gebotteld wordt en op dat moment de leeftijd wordt meegegeven. Ook al bewaar je de fles daarna 100 jaar, de leeftijd is de leeftijd wanneer er gebotteld is.

Mochten er nog vragen zijn over dit project hoor ik het graag.
 
Wilco Rakhorst

Wilco Rakhorst

30/10/2015 21:22:22
Quote Anchor link
En ondertussen even wat tijd gemaakt om te bekijken waar mijn fouten zaten. En omdat ik nog redelijk in de beginfase van mijn project zit, ga ik me wat meer richten op de mysqli-extensies.
En de fouten waren inderdaad de "" en de hoofdlettergevoeligheid.

Iedereen bedankt voor de tips. Ik kan er weer verder mee en het is me inmiddels gelukt om een paar velden in MySQL te inserten via de php pagina.
 
Pg Vincent

Pg Vincent

31/10/2015 10:30:49
Quote Anchor link
"maar het is altijd netter om getallen als getallen te behandelen en niet als strings"

Quotes geven in SQL alleen aan waar de data begint en eindigt, het heeft niets te maken met datatypen, dat komt pas wanneerde waarde wordt aangeboden aan de uiteindelijke kolom endie zal de *string* interpreteren om te zien of de inhoud past in het kolomformaat. Omdat quotes alleen de waarden afbakenen is het altijd beter om ze wel te gebruiken, dan om de queryparser te laten gokken over wat je bedoelt.
Als je waarden direct in een query plakt dan is het sowieso altijd verplicht om ze te quoten, want anders zet je je script open voor SQL injectie.
 
Willem vp

Willem vp

01/11/2015 01:45:54
Quote Anchor link
> Quotes geven in SQL alleen aan waar de data begint en eindigt,

Dat is niet waar. Als je naar de BNF van SQL kijkt, zie je dat quotes alleen worden gebruikt voor string literals.

> het heeft niets te maken met datatypen, dat komt pas wanneer de waarde wordt
> aangeboden aan de uiteindelijke kolom en die zal de *string* interpreteren om
> te zien of de inhoud past in het kolomformaat. Omdat quotes alleen de waarden
> afbakenen is het altijd beter om ze wel te gebruiken, dan om de queryparser
> te laten gokken over wat je bedoelt.

Leuke theorie, maar hij slaat nergens op. ;-) De query parser voert een lexicale analyse uit op de query en zal dus een integer/decimal/etc zien als je geen quotes gebruikt, en een string als je wel quotes om de waarde zet. Dat wordt vervolgens vertaald in tokens die aan de SQL engine worden doorgegeven.

Als je quotes om een integer zet, zal de SQL engine dus een string aangeleverd krijgen in plaats van een integer. Vervolgens ziet de engine in de datadefinitie dat het een integerveld betreft, en zal hij de string naar een integer moeten typecasten. Overigens is dit qua performance verwaarloosbaar. Wat echter niet verwaarloosbaar is, is het gedrag van MySQL als je gequote integers gebruikt.

Wanneer je een insert doet op een enum-veld met numerieke waardes, moet je bijvoorbeeld goed opletten of je wel of geen quotes om je integer zet. Zonder quotes zal de waarde gezien worden als index van de enum, en met quotes wordt eerst gekeken of de enum een string bevat met die waarde. Zo niet, dan wordt het te inserten getal alsnog als index geïnterpreteerd. (Nu kun je je afvragen of het uberhaupt verstandig is je database op die manier in te richten, maar het gaat mij even om het voorbeeld dat je niet zomaar overal quotes omheen kunt zetten.)

Een ander leuk probleem dat je kunt tegenkomen is als je integerwaardes gebruikt die groter zijn dan de hardware van je systeem aankan. Die worden namelijk eerst gecast naar floating pointwaardes en pas daarna vergeleken. Het is echter mogelijk dat een integer op een andere manier wordt gecast dan een string (dat kan worden beïnvloed door bijvoorbeeld je hardware-architectuur of de versie/instellingen van de compiler) en omdat floats niet exact zijn, kan het dus voorkomen dat 'integer' <> integer.

De eerlijkheid gebiedt me te zeggen dat ik dit niet in de praktijk heb kunnen reproduceren, maar dit is wel zo'n probleem waar je rustig maanden naar kunt zoeken als je er last van hebt.

Iets wat je vaker in de praktijk zult tegenkomen, is het gebruik van een decimale komma in plaats van een decimale punt, omdat we dat nu eenmaal gewend zijn in Nederland. Stel dat je een waarde als 3,14 wilt inserten in een decimal/float-veld. Als je er quotes omheen zet, zal die waarde niet worden geconverteerd naar 3.14, maar naar 3.0. Zonder quotes krijg je een SQL-error en is het meteen duidelijk dat je input niet klopt. Dat heeft toch wel mijn voorkeur boven het inserten van verminkte data in een tabel.

> Als je waarden direct in een query plakt dan is het sowieso altijd verplicht
> om ze te quoten, want anders zet je je script open voor SQL injectie.

Ook als je waardes quote blijft je script openstaan voor SQL-injectie. Je kan immers ook quotes injecteren. ;-) De enige manier om je script te beveiligen is door alle input te sanitizen. En als het even kan prepared statements gebruiken, al moet ik zeggen dat ik dat in PHP nogal bewerkelijk vind...
 
Eddy E

Eddy E

01/11/2015 08:24:40
Quote Anchor link
Mooi stuk.
En wat zou het mooi zijn als de topicstarter antwoordt met "k"... :D
 
Thomas van den Heuvel

Thomas van den Heuvel

01/11/2015 13:54:51
Quote Anchor link
kk :)

@Pg Vincent
Quote:
Omdat quotes alleen de waarden afbakenen is het altijd beter om ze wel te gebruiken, dan om de queryparser te laten gokken over wat je bedoelt.
Als je waarden direct in een query plakt dan is het sowieso altijd verplicht om ze te quoten, want anders zet je je script open voor SQL injectie.

Ben ik het niet helemaal mee eens. Als je zorgt dat je je input filtert voor numerieke waarden zijn quotes (zelfs) helemaal niet nodig.

Het toevoegen van quotes alleen is ook niet genoeg, want magic_quotes_gpc() bestaat niet meer in nieuwere PHP-versies (dit biedt ook geen absolute garanties want en het was naar verluid niet eens voor security bedoeld maar kan wel wat (toevallige) bescherming bieden). Je kunt dus makkelijk uit deze quotes springen door constructies als ...' OR '1' = '1...

Daarnaast mogen de DATA-delen in je query niet behandeld worden als SQL, daarvoor is de MySQL-context-specifieke escaping functie/methode real_escape_string().
Het toevoegen van real_escape_string() alleen (zonder quotes) is OOK niet genoeg omdat er niets ge-escaped wordt als er niets te escapen valt, bijvoorbeeld met ...OR 1=1.... Het komt nogal eens voor dat real_escape_string() als een soort toverformule gebruikt wordt (SIMSALABIM!) en dat na afloop (ten onrechte) verondersteld wordt dat alles veilig is (terwijl geen quotes om het geheel waren geplaatst).

Alleen de combinatie van beide middelen (het toevoegen van quotes en het escapen van de inhoud met de daarvoor bestemde functie/methode) is veilig, en dan alleen wanneer je character encoderingen kloppen. Als deze niet kloppen / uit de pas lopen kan niet gegarandeerd worden dat de escaping goed gaat. Daarom geeft een (andere) escaping functie als htmlspecialchars() ook een lege string terug als de encodering van de string-parameter niet overeenkomt met de opgegeven encodering, omdat er dan simpelweg niet gegarandeerd kan worden dat het resultaat "HTML safe" is.

@Willem vp
Quote:
De enige manier om je script te beveiligen is door alle input te sanitizen.

Als je met sanitizen bedoelt "repareren tot iets geldigs", ik zou het niet doen. Dat is toch net zoiets als typecasting. Als je bedoelt "filteren" dan ben ik akkoord. Als je input "niet past", gewoon weigeren.

Ik zie dit soort constructies te vaak:
Code (php)
PHP script in nieuw venster Selecteer het PHP script
1
2
3
<?php
$q
= 'SELECT * FROM whatever WHERE id = '.((int) $_GET['id']);
?>

Als $_GET['id'] vervolgens 'aap' bevat wordt dit getypecast naar het cijfer 0. Maar het heeft (mogelijk) totaal geen zin om zo'n query uit te voeren omdat deze of geen, of onvoorspelbare resultaten oplevert. Onvoorspelbaar, omdat er met een typecast een interpretatiestap wordt uitgevoerd, "Oh hij zal wel X of Y bedoeld hebben".

Als je met sanitizen bedoelt "repareren tot iets veiligs", dan ben ik het daar ook niet mee eens, wat je dan in feite doet is 'escape-on-input'. Ook dat lijkt mij een slecht idee.

Idealiter sla je "geldige" data (dit hoeft niet per sé "wenselijke" data te zijn, hier mogen nog best dingen in zitten die bij een later gebruik schade aan kunnen richten) rauw op, zodat je deze later weer makkelijk kunt bewerken. Als je deze bijvoorbeeld opslaat met htmlentities() ofzo (Joost mag weten waarom), dan zul je op een zeker moment weer de omgekeerde bewerking uit moeten voeren. Dit brengt ook weer allemaal problemen met zich mee en in zijn algemeenheid wordt je applicatie complexer door dit soort vertaalslagen.

Ik ben van mening dat je invoer exact moet kloppen nog voordat je een query of wat dan ook uitvoert. Wat als dit een kostbare operatie is? Het is een verspilling van resources. Filter input, klopt je invoer niet, pech (maar doe niets!).

Als iederen zich nou gewoon van het devies filter input, escape output zou bedienen (en tevens begrijpt wat dit inhoudt)...
Gewijzigd op 02/11/2015 16:50:27 door Thomas van den Heuvel
 
Wilco Rakhorst

Wilco Rakhorst

02/11/2015 15:46:29
Quote Anchor link
Eddy E op 01/11/2015 08:24:40:
Mooi stuk.
En wat zou het mooi zijn als de topicstarter antwoordt met "k"... :D


"k"...
En gaaf om te zien hoe een vraag in een beginnersforum zo'n geweldige discussie ontketent!
 



Overzicht Reageren

 
 

Om de gebruiksvriendelijkheid van onze website en diensten te optimaliseren maken wij gebruik van cookies. Deze cookies gebruiken wij voor functionaliteiten, analytische gegevens en marketing doeleinden. U vindt meer informatie in onze privacy statement.