[PHP] Dynamische array in Database zetten

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Hallo medetweakers,

Ik heb een vraag die mij al enkele uren bezig houdt. Ik wil een functie schrijven die informatie voor mij in een database zet. Alleen die informatie die in de database moet komen zit in een array, en is dynamisch. Het aantal gegevens in de array wisselt.

Nu is de array zo opgebouwd:
PHP:
1
2
3
$array = array (
                    'field_name' => 'value'
);

Field_name is het veld van de database, en value de waarde die in de database gestopt moet worden.

Nu heb ik hele stukken op php.net gelezen, en daar kwam toch uit de functie implode. Nu ben ik daar mee aan de slag gegaan. Echter, de value's zijn niet statisch. Als je hem in dit formaat zet:
code:
1
'value',

dan krijg je op het einde
code:
1
VALUES('value1', 'value2','value2',);

(De laatste comma moet dus weg).

Tot nu toe heb ik dit:

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
29
30
31
32
    function mysql_insert_assoc ($dbTable, $userArray) {

       // Find all the keys (column names) from the array $my_array
       $columns = array_keys($userArray);

       // Find all the values from the array
       $values = array_values($userArray);

       // We compose the query
       $sql = "insert into `$dbTable` ";
       // implode the column names, inserting "\", \"" between each (but not after the last one)
       // we add the enclosing quotes at the same time
       $sql .= "(\"" . implode("\", \"", $columns) . "\")";
       $sql .= " values ";
       // Same with the values
        $sql .= "('" . implode(", ", $values) . "')";
        echo "<table bgcolor=yellow><tr><td>" . $sql . "</td></tr></table>";


       $result = mysql_query($sql);

       if ($result)
       {
           echo "The row was added sucessfully";
           return true;
       }
       else
       {
           echo ("The row was not added<br>The error was" . mysql_error());
           return false;
       }
   }


Bij de eerste implode schijnt het goed te gaan, krijg je netjes value,value,value alleen als er quote's aan te pas komen ('value','value') krijg ik het niet voor elkaar.

De output van bovenstaande is dan ook:
code:
1
insert into `users` ("uName", "uPassword") values ('harry, bc80c41c10827a38b1c65a40e8f6bf7180284909')


The quote's staan niet goed. Ik heb al alle, in mijn ogen mogelijke combinaties gedaan. PHP.net geraadpleegt, comments gelezen op php.net, echter kan ik zelfs nu nog niet aan een oplossing komen. En ik weet gewoon dat de oplossing héél simpel moet zijn, echter lukt niet.

En dan nog over de methode. Volgens mij moet dit beter/sneller kunnen? Of moet je persé met implode spelen.

Als ik de desbetreffende regel verander in dit:
PHP:
1
$sql .= "('" . implode(", '", $values) . "')";

word het al beter, output:

code:
1
insert into `users` ("uName", "uPassword") values ('harry, 'bc80c41c10827a38b1c65a40e8f6bf7180284909')



Bij een 3e variable word het duidelijker, de output is bij een LEEG id veld:

code:
1
insert into `users` ("uID", "uName", "uPassword") values (', 'harry, 'bc80c41c10827a38b1c65a40e8f6bf7180284909')


Je mist dus op het einde een quote, behalve bij de laatste value.

Ik hoop dat ik duidelijk ben geweest en genoeg werk van mijn topic heb gemaakt :)

update:

PHP:
1
$sql .= "('" . implode("', '", $values ) . "')";


Is hem geworden dus, deze werkt gelukkig wel. Ik denk dat ik te lang gespint heb op dit probleem waardoor je helemaal van de kaart raakt ;)

Maar goed, blijft nog wel; is er een betere, cq nettere manier?

[ Voor 4% gewijzigd door RedHat op 10-03-2009 20:13 ]


Acties:
  • 0 Henk 'm!

Verwijderd

PHP:
1
$sql .= "('" . implode("', '", $values) . "')";

Simpeler wordt het niet hoor :?

Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Verwijderd schreef op dinsdag 10 maart 2009 @ 20:11:
PHP:
1
$sql .= "('" . implode("', '", $values) . "')";

Simpeler wordt het niet hoor :?
Ik had hem zelf nu dus ook eindelijk ;)

Maar is dit een goede manier of zijn er betere manieren? Ik vind dit namelijk nogal veel code om een klein truukje toe te passen.

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
RedHat schreef op dinsdag 10 maart 2009 @ 20:16:
[...]

Ik had hem zelf nu dus ook eindelijk ;)

Maar is dit een goede manier of zijn er betere manieren? Ik vind dit namelijk nogal veel code om een klein truukje toe te passen.
Veel simpeler dan één functie-aanroep ga je het niet krijgen hè.

Acties:
  • 0 Henk 'm!

  • Eegee
  • Registratie: Januari 2000
  • Laatst online: 21:42
De waardes zijn altijd strings?
De waardes zijn altijd veilig voor in een SQL-statement?

Acties:
  • 0 Henk 'm!

  • doeternietoe
  • Registratie: November 2004
  • Laatst online: 21:26
Eegee schreef op dinsdag 10 maart 2009 @ 21:27:
De waardes zijn altijd strings?
De waardes zijn altijd veilig voor in een SQL-statement?
Als de DB deze structuur heeft:
code:
1
2
3
4
       $sql = "insert into `$dbTable` ";
       $sql .= "(\"" . implode("\", \"", $columns) . "\")";
       $sql .= " values ";
       $sql .= "('" . implode(", ", $values) . "')";


dan gaat het waarschijnlijk om varchar-fields en zijn het dus allemaal strings. Zelfs als ze een numeriek waarde hebben :) Natuurlijk kunnen het blob, text, integer of wat dan ook voor velden zijn, maar het gebruik van quotes (waar je denk ik op doelt) is bij een gelijk veld altijd hetzelfde.

Als je dezelfde functie op veel verschillende tabellen, waarbij er wel integers zijn, dan zul je dat iets beter moeten controleren. Ik ging er eigenlijk vanuit dat het de oplossing van een specifiek probleem betrof.

De veiligheid als probleem zie ik niet zo. Allereerst ging het probleem van de TS daar niet over en ten tweede is dit een interne functie. Waar kun jij uit zien dat de data bijvoorbeeld afkomstig is van een gebruiker? De controle lijkt me buiten het bereik van dit topic vallen.

[ Voor 18% gewijzigd door doeternietoe op 10-03-2009 22:01 ]


Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Eegee schreef op dinsdag 10 maart 2009 @ 21:27:
De waardes zijn altijd strings?
De waardes zijn altijd veilig voor in een SQL-statement?
Die eerste is wel een héél goed punt. Het kan ook net zo goed een integer of boolean wezen. Dat maakt het wel een stukje 'lastiger'.

Ik heb een functie die hem SQL-injectie veilig maakt. Met een foreach loop ik de array langs.

Alleen bij ints, cast MySQL het zelf naar een int als het goed is. Dus in principe kan alle invoer gequote worden toch? VALUES (1,'blaat') of VALUES('1', 'blaat') maakt dan uiteindelijk geen verschil in de database. Als het veld een int is cast MySQL het om naar een int, ook al is de invoer geen int.

[ Voor 26% gewijzigd door RedHat op 10-03-2009 22:03 ]


Acties:
  • 0 Henk 'm!

  • doeternietoe
  • Registratie: November 2004
  • Laatst online: 21:26
RedHat schreef op dinsdag 10 maart 2009 @ 21:58:
[...]
Ik heb een functie die hem SQL-injectie veilig maakt. Met een foreach loop ik de array langs.
Dat zou misschien ook met http://nl.php.net/array_map kunnen :)

Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
RedHat schreef op dinsdag 10 maart 2009 @ 21:58:
[...]

Die eerste is wel een héél goed punt. Het kan ook net zo goed een integer of boolean wezen. Dat maakt het wel een stukje 'lastiger'.

Ik heb een functie die hem SQL-injectie veilig maakt. Met een foreach loop ik de array langs.

Alleen bij ints, cast MySQL het zelf naar een int als het goed is. Dus in principe kan alle invoer gequote worden toch? VALUES (1,'blaat') of VALUES('1', 'blaat') maakt dan uiteindelijk geen verschil in de database. Als het veld een int is cast MySQL het om naar een int, ook al is de invoer geen int.
Klopt. Andersom gaat uiteraard niet goed :P.

Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Dat is een handige tip. Array_map volstaat inderdaad en is volgens mij sneller dan een foreach. Dit zijn erg leuke tips waar ik veel aan heb.
HuHu schreef op dinsdag 10 maart 2009 @ 22:04:
[...]

Klopt. Andersom gaat uiteraard niet goed :P.
Het gaat hier om het toevoegen in de database. Als het eenmaal erinstaat, staat het goed en word het ook uitgelezen als een int. Nu kun je wel een hele moeilijke constructie gaan maken om het allemaal correct van php naar mysql te krijgen, maar mysql cast ze toch in een keer goed. Dat is volgens mij sneller en beter dan hele omwegen te bedenken :)

[ Voor 43% gewijzigd door RedHat op 10-03-2009 22:07 ]


Acties:
  • 0 Henk 'm!

  • Eegee
  • Registratie: Januari 2000
  • Laatst online: 21:42
OK, netjes. Ik gaf even die twee puntjes aan omdat je er wel even aan/over moet denken. Maar dat heb je gedaan, dus da's goed :)

Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Eegee schreef op dinsdag 10 maart 2009 @ 22:34:
OK, netjes. Ik gaf even die twee puntjes aan omdat je er wel even aan/over moet denken. Maar dat heb je gedaan, dus da's goed :)
Dat eerste puntje had ik niet over nagedacht. (Over het type dat geinsert word in de database). Die implode maakte me helemaal blind. Soms heb je dat, dan staar je je zo blind op iets dat het never nooit meer gaat lukken.

Omdat ik het goed moest krijgen van mijzelf, heb ik na een aantal uur documentatie en boeken doornemen toch besloten om een topic op GoT te openen. Toen hij open was en ik een bakje koffie ging drinken was m'n geest blijkbaar helder.

Het is dan ook simpel... (' implode array ' , ' $array ' ) (even simpel gezegd. Maar het waren 2 hele goede tips. Vooral over SQL injectie. Het is een offline projectje wat ik gestart ben. Heb toch al zo'n 3 á 4 jaar PHP helemaal niet meer aangeraakt en ben na een aantal weken inlezen toch maar eens begonnen. Héél rustig aan, veel lezen, met wat boeken en de php manual.

Hier is ook uitgekomen dat een foreach niet het beste idee was om een anti-sqlinjectie-functie over een array te laten gaan. Ik heb dit overigens toch even gebenchmarkt, en de array_map functie is toch een stuk sneller. Hiervoor dus ook erg bedankt!

En de functie is vooral voor varchars, en af en toe een int. Het is nu allemaal heel simpel opgezet, namelijk een userID, een userName en een userPassword. Die velden worden of kunnen natuurlijk uitgebreid worden. Maar ik wou meer een algemene functie omdat het aantal velden van te voren niet duidelijk is. Straks wil ik er een veld userMail bij hebben b.v., dan kun je dat straks doen buiten deze class om. Het idee is namelijk om een soort van MVC pattern aan te houden. Dit is het model, wat zo algemeen mogelijk moet zijn. En dus eigenlijk ook hergebruikt moet kunnen worden.

Als het model helemaal af is wil ik het eigenlijk "ongewijzigd" zijn werk kunnen laten doen. De "opties" en "settings" en de random zaken wil ik afhandelen in een soort van controller. In de controller worden dingen bepaald (b.v. hoeveel velden er ingevuld moeten worden bij registratie), en die controller zou dus bij verschillende projecten (niet dat ik ze heb :X ) wel aangepast moeten worden. En dan gebruik ik de view natuurlijk waar het boeltje op het scherm getoverd word (en dus het model en de controller aangesproken worden).

Het is gewoon een start. Na 4 jaar niet gephp't te hebben of iets in die vorm wil ik eens kijken of ik gewoon netjes kan scripten. En zo wil ik eigenlijk een soort library aanmaken. Mijn 2e projectje na m'n user-classje word een documentatie-class. Een scriptje waar alle classes en functies uitgelegd worden. Want nu je het script maakt en het nog overzichtelijk is omdat het vrij compact is snap je alles nog. Maar wat als je over een jaar terug moet duiken? Dan is de documentatie lezen makkelijker als die duizenden lijnen code.

[ Voor 38% gewijzigd door RedHat op 11-03-2009 10:46 ]


Acties:
  • 0 Henk 'm!

  • glashio
  • Registratie: Oktober 2001
  • Laatst online: 18-09 10:13

glashio

C64 > AMIGA > PC

Er vanuitgaande dat je waarde's ge-escape'd zijn in je array :)

glashio in "[PHP] Key en Value uit Array imploden na..."

> Google Certified Searcher
> Make users so committed to Google that it would be painful to leave
> C64 Gospel
> [SjoQ] = SjoQing


Acties:
  • 0 Henk 'm!

  • RedHat
  • Registratie: Augustus 2000
  • Laatst online: 18:54
Dat zijn ze niet.

Dit is mijn hele functie tot nu toe.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
    public function mysql_insert_assoc ($dbTable, $userArray) {
        
        /**
         * Make the input SQL-Inject proof
         */
         foreach ($userArray as $c => $f) $user[$c] = $this->EscapeInput($f);

        /**
         * Find all the keys and collums in the arrays
         */
        $columns = array_keys($userArray);
        $values = array_values($userArray);
        
        /**
         * Compose the mysql query
         */
         
        $sql = "insert into `$dbTable` ";
        /**
         * Implode the column names 
         * Inserting ", " between each (but not after the last one)
         * Then add the enclosing quotes at the end
         */
        $sql .= "(" . implode(", ", $columns) . ")"; 
        $sql .= " values ";
        
        /**
         * We do the same to the value's
         * But now with single quote's
         */
        $sql .= "('" . implode("', '", $values ) . "')";
        
        /**
         * If DEVELOPMENT_MODE is defined this will output the query to the screen
         * With this you can see if the implode's did the job
         */
        if (DEFINED('DEVELOPMENT_MODE')) echo "<table bgcolor=yellow><tr><td>" . $sql . "</td></tr></table>";

        /**
         *  $result gives true or false
         */
        $result = mysql_query($sql);

        if ($result) {
           return true;
        }
        else {
           return false;
        }
   }


PHP:
1
2
3
4
5
6
7
8
9
10
11
    /**
     * Function: EscapeInput
     * @access public
     * @param string $input
     * @return string
     */
    public function EscapeInput ($input) {
        $input =  get_magic_quotes_gpc()?stripslashes($input):$input;
        $input = mysql_real_escape_string ($input);
        return $input;
    }


De functie EscapeInput is als volgt; hij werkt nog niet helemaal goed maar dat is voor iets latere zorg :)

Acties:
  • 0 Henk 'm!

  • Sgreehder
  • Registratie: Juni 2004
  • Laatst online: 24-06 14:35
Ik zou met een "SHOW COLUMNS FROM table" query even achterhalen hoe of wat, dan kun je zo een op maat gemaakte query opstellen. Het is ook logischer, want dan wordt je code onafhankelijk van je data schema. Zet tevens een kleine cache op om die minimale overhead van die extra query weg te moffelen, et voila.

Acties:
  • 0 Henk 'm!

  • CodeCaster
  • Registratie: Juni 2003
  • Niet online

CodeCaster

Can I get uhm...

PHP:
1
2
3
4
5
6
7
foreach ($userArray as $c => $f) $user[$c] = $this->EscapeInput($f);

/**
* Find all the keys and collums in the arrays
*/
$columns = array_keys($userArray);
$values = array_values($userArray);

Ik geloof niet dat je escape-functie veel doet zo.

https://oneerlijkewoz.nl
Op papier is hij aan het tekenen, maar in de praktijk...


Acties:
  • 0 Henk 'm!

  • XWB
  • Registratie: Januari 2002
  • Niet online

XWB

Devver
Ik doe het altijd zo:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function sql_array ( $queryString, $queryData )
{
  $tableFields = array ();
  $tableValues = array ();
  
  switch ( $queryString )
  {
    case 'INSERT' :
          foreach ( $queryData as $arrayKey => $arrayValue )
          {
              $tableFields[] = $arrayKey;
    
              if ( is_null ( $arrayValue ) )
              {
                  $tableValues[] = 'NULL';
              }          
              elseif ( is_string ( $arrayValue ) )
              {
                  $tableValues[] = mysql_real_escape_string ( $arrayValue );
              }
              else
              {
                  $tableValues[] = ( is_bool ( $arrayValue ) ) ? intval ( $arrayValue ) : $arrayValue;
              }
          }
    
          $queryString = ' (' . implode ( ', ', $tableFields ) . ') VALUES (' . implode ( ', ', $tableValues ) . ')';   
    break;
    case 'UPDATE' :
          foreach ( $queryData as $arrayKey => $arrayValue )
          {
              if ( is_null ( $arrayValue ) )
              {
                  $tableValues[] = $arrayKey . ' = NULL';
              }            
              elseif ( is_string ( $arrayValue ) )
              {
                  $tableValues[] = $arrayKey . ' = ' . mysql_real_escape_string ( $arrayValue );
              }
              else
              {
                  $tableValues[] = ( is_bool ( $arrayValue ) ) ? $arrayKey . ' = ' . intval ( $arrayValue ) : $arrayKey . ' = ' . $arrayValue;
              }
          }
          
          $queryString = ' SET ' . implode ( ', ', $tableValues );  
    break;
  }
  
  return $queryString;
}

$data = array ();
$data['field1'] = 4;
$data['field2'] = 'test';


printf ( 'INSERT INTO table %s', sql_array ( 'INSERT', $data ) );

March of the Eagles


Acties:
  • 0 Henk 'm!

  • PainkillA
  • Registratie: Augustus 2004
  • Laatst online: 26-08 19:26
en ik gebruik gewoon een bestaand framework zodat ik mij meer kan focussen op de echte problemen :D

Acties:
  • 0 Henk 'm!

  • Sgreehder
  • Registratie: Juni 2004
  • Laatst online: 24-06 14:35
PainkillA schreef op woensdag 11 maart 2009 @ 16:44:
en ik gebruik gewoon een bestaand framework zodat ik mij meer kan focussen op de echte problemen :D
Natuurlijk, maar het kan geen kwaad hier af en toe eens over na te denken. Dan pas kun je frameworks echt leren waarderen.
Pagina: 1