Ergebnis 1 bis 8 von 8

Thema: Array-Parameter für Datenbase->prepare->execute

  1. #1
    Contao-Nutzer
    Registriert seit
    19.04.2010.
    Ort
    Frankfurt
    Beiträge
    19

    Standard Array-Parameter für Datenbase->prepare->execute

    Hallo Comunity,

    ich hatte versucht eine SELECT-Abfrage mit einem IN-Parameter aus einem Array zu erstellen und bin erst einmal gescheitet. Hier ein Beispiel was ich meine:
    PHP-Code:
    $citys = array("Bonn""Kiel""Berlin");
    $this->Database->prepare("SELECT * FROM table WHERE city IN (?)")
                   ->
    execute($citys); 
    Gehofft hatte ich, dass damit ein
    Code:
    SELECT * FROM table WHERE city IN ("Bonn", "Kiel", "Berlin")
    damit entsteht.
    Die Profis werden schon erkennen, dass mir die Database::escapeParams() diese Idee durch ein simples serialize() verhagelt hat.

    Da ich aber gene mal ein IN-Statement in SQL-Querys verwende, hätte ich folgenden Vorschlag, den ich gerne durch eure Meinung abgesichert hätte. Ist ja immerhin eine wichtige Funktion um SQL-Injections zu verhindern.

    Meine Idee ist, da Arrays und Objects per serialize behandelt werden, eine spezielle Klasse für ein Array von Parametern zu definieren. Wird dieses dann erkannt, werden die einzelnen Parameter per escape behandelt und dann mit Kommas verknüpft.
    PHP-Code:
    class DBParamArray {  // special class which will not serialize
      
    public $Array;
      protected function 
    __construct($Array)
      {  
    $this->$Array $Array;  }
    }

    Database::escapeParams() 
    {
      
    //[..]  Anfang unverändert
        
    case 'object':
          if (
    $arrParams[$k] instanceof DBParamArray)
          {
            
    $arrParam[$k] = implode(","$this->escapeParams($arrParam[$k]));
            break;
          }
          
    $arrParams[$k] = $this->string_escape(serialize($v));
          break;

      
    //[..] Ende unverändert

    Damit sollte es doch möglich sein mit folgendem Aufruf:
    PHP-Code:
         ->execute(new DBParamArray($Citys)); 
    aus obigem Beispiel eine Parameterliste sauber durch die vorhandenen Funktionen aufbereiten lassen zu können.
    Jeder einzelen Wert aus dem Array wird dann per escapeParam bearbeitet und die Änderung sollte auch abwärtskompatibel sein.

    Wie seht ihr das?
    Oder gibt es schon eine Möglichkeit für mein Problem, das ich leider nicht gefunden hatte?

    PS: Gibt es vielleicht noch andere Abfragearten, bei denen ein Array mit Parametern übergeben werden soll, dass dann nicht mit einem Komma aneinander gehängt werden soll?
    Geändert von styx7 (25.04.2010 um 10:35 Uhr)

  2. #2
    Contao-Urgestein Avatar von FloB
    Registriert seit
    19.06.2009.
    Ort
    Sonnensystem
    Beiträge
    1.618

    Standard

    Interessante Idee. Damit hätte man auch bei der Behandlung eine Unterscheidung zwischen Arrays und Objekten (wenn auch nicht logisch nachvollziehbar). Allerdings – nach dem Code zu urteilen – werden Objekte bisher auch serialisiert gespeichert, was man nicht ohne weiteres ändern kann (es sei denn man nutzt eine Extraklasse und instanceof). Ich frage mich auch wie du darauf kommst, dass ein Array als alleiniges Parameter bei Database::execute() serialisiert wird – meines Wissens werden die Elemente des Arrays jeweils für einen Platzhalter eingesetzt. Und im Core werden (nach schnellem grep'en sichtbar) SQL-IN's immer im Code direkt implode'd.

    Eine Pseudoklasse ist (bei deinem Beispiel) nicht nötig, es gibt in PHP ein nicht so bekanntes Feature: stdClass ist eine einfache leere Klasse, die man initialisieren kann, um Daten in einem Objekt (und nicht Array) zu speichern.
    So long,
    FloB since Nov. 2007 +706P +115P and counting

  3. #3
    Contao Core-Team
    Association Vorstand
    Avatar von andreas.schempp
    Registriert seit
    15.06.2009.
    Ort
    Lyss
    Beiträge
    5.619
    Partner-ID
    8667
    Contao-Projekt unterstützen

    Support Contao

    Standard

    Warum machst du nicht einfach folgendes:

    PHP-Code:
    $this->Database->prepare("SELECT * FROM table WHERE city IN (?)")
    ->
    execute(implode("', '"$citys)); 
    terminal42 gmbh
    Wir sind Contao Premium-Partner! Für Modulwünsche oder Programmierungen kannst du uns gerne kontaktieren.
    Hilfe für Isotope eCommerce kann man auch kaufen: Isotope Circle

  4. #4
    Contao-Nutzer
    Registriert seit
    19.04.2010.
    Ort
    Frankfurt
    Beiträge
    19

    Standard

    Hallo FloB
    Zitat Zitat von FloB Beitrag anzeigen
    Allerdings – nach dem Code zu urteilen – werden Objekte bisher auch serialisiert gespeichert, was man nicht ohne weiteres ändern kann (es sei denn man nutzt eine Extraklasse und instanceof).
    Ja, aber das beschreibe ich doch, oder was meinst du?

    Zitat Zitat von FloB Beitrag anzeigen
    Ich frage mich auch wie du darauf kommst, dass ein Array als alleiniges Parameter bei Database::execute() serialisiert wird – meines Wissens werden die Elemente des Arrays jeweils für einen Platzhalter eingesetzt. Und im Core werden (nach schnellem grep'en sichtbar) SQL-IN's immer im Code direkt implode'd.
    Das ein alleiniger Parameter nicht serialisiert wird, wusste ich nicht. Ich habe bisher immer mit mehreren Parametern gearbeitet und da werden Arrays serialisiert. Muss ich mal testen! Löst aber, glaube ich, nicht das Problem für IN-Statements.
    Zu dem bisherigen SQL-IN: Wenn ich das immer im Code direkt implode, dann muss ich auch selbst für das richtige escapen sorgen. D.h. ich muss eigentlich eine eigene escapeParams schreiben. Bei reinen Integer-Werten, welche nicht als Parameter vom Browser kommen, ist das noch schnell erledigt. Bei Strings vom Browser würde ich schon gerne auf das bisherige zurück greifen. Also inklusive der Unterscheidung der gewählten Datenbank.

    Zitat Zitat von FloB Beitrag anzeigen
    Eine Pseudoklasse ist (bei deinem Beispiel) nicht nötig, es gibt in PHP ein nicht so bekanntes Feature: stdClass ist eine einfache leere Klasse, die man initialisieren kann, um Daten in einem Objekt (und nicht Array) zu speichern.
    Das mit der Pseudoklasse basiert auf mehreren Überlegungen.
    1. Es könnte schon eine Extension exisiteren, die eine stdClass verwendet. Dann würde es dort krachen. (Thema Abwertskompatibilität)
    2. Vielleicht wäre es auch sinnvoll das implode in die Klasse zu verschieben. Dann könnten auch andere Seperatoren als das Komma definiert werden. (Habe aber noch keine Idee wozu)
    3. Deine Antwort hat mich aber auf die Idee gebracht, dass z.B. für ein LIKE ein prä- oder postfix "%" gebraucht werden könnte. So wie ich das aktuell sehe, werden die % auch escaped. So könnte die Pseudoklasse entsprechend erweitert werden.

    So mal aus der Hüfte geschossen etwa so was (ungeprüft):
    PHP-Code:
    class DBParamArray {  // special class which will not serialize 
      
    public $Array
      public 
    $Separator;
      protected function 
    __construct($Array
      {
        
    $this->$Array $Array;  
        
    $this->Separator ",";
      } 
      function 
    Get()
      { return 
    implode($this->Separator$this->$Array); }

    Und in der escapeParams Funktion müsste dann die folgende Zeile (im ersten Post leider unvollständig)
    PHP-Code:
    $arrParam[$k] = implode(","$this->escapeParams($arrParam[$k]->Array)); 
    geändert werden in
    PHP-Code:
    $arrParam[$k]->Array $this->escapeParams($arrParam[$k]->Array);
    $arrParam[$k] = $arrParam[$k]->Get(); 
    Natürlich kann das auch schöner codiert werden...

    PS: Kann man eigentlich auch die Database Classe gegen was eigenes austauschen, also so wie in bei den Modulen in https://contao.org/methoden-ueberschreiben.html beschreiben?

  5. #5
    Contao-Nutzer
    Registriert seit
    19.04.2010.
    Ort
    Frankfurt
    Beiträge
    19

    Standard

    Hallo Andreas,
    Zitat Zitat von andreas.schempp Beitrag anzeigen
    Warum machst du nicht einfach folgendes:

    PHP-Code:
    $this->Database->prepare("SELECT * FROM table WHERE city IN (?)")
    ->
    execute(implode("', '"$citys)); 
    Wird dabei nicht folgendes gemacht:
    1. implode ergibt dann "Bonn', 'Kiel', 'Berlin"
    2. escapeParams mach daraus dann "Bonn\', \'Kiel\', \'Berlin"
    Ergo werden aus drei Parametern einer.

    Die ' müssten doch escaped werden, sind also für die Abfrage nicht mehr als Parameterbegrenzer nutzbar.
    Das ist doch IMHO das schöne an der escapeParams-Funktion. Damit werden SQL-Injections schwerer, wenn nicht sogar verhindert. Den Ansatz hatte ich als erstes versucht und bin deshalb zu meinem ersten Vorschlag gekommen

  6. #6
    Contao-Urgestein Avatar von FloB
    Registriert seit
    19.06.2009.
    Ort
    Sonnensystem
    Beiträge
    1.618

    Standard

    Zitat Zitat von styx7 Beitrag anzeigen
    PS: Kann man eigentlich auch die Database Classe gegen was eigenes austauschen, also so wie in bei den Modulen in https://contao.org/methoden-ueberschreiben.html beschreiben?
    Nicht direkt, es gibt aber einen kleinen Trick: Da die Klassen erst per Autoloader eingebunden werden, kannst du vor dem ersten Aufruf der Klasse eine eigene Datenbankklasse mit dem selben Namen einbinden. Diese muss dann aber eine komplette Kopie sein, und kann nicht die alte Klasse erweitern (sonst gibt es natürlich einen Namensraumkonflikt). Eine eigene Klasse kannst du beispielsweise updatesicher in der initconfig.php einbinden.
    So long,
    FloB since Nov. 2007 +706P +115P and counting

  7. #7
    Contao-Nutzer
    Registriert seit
    19.04.2010.
    Ort
    Frankfurt
    Beiträge
    19

    Standard

    @FloB: Danke, werde ich mal Testen.
    TL macht mir immer mehr Spaß!

  8. #8
    Contao-Nutzer
    Registriert seit
    03.01.2015.
    Beiträge
    5

    Standard

    Zitat Zitat von andreas.schempp Beitrag anzeigen
    Warum machst du nicht einfach folgendes:

    PHP-Code:
    $this->Database->prepare("SELECT * FROM table WHERE city IN (?)")
    ->
    execute(implode("', '"$citys)); 
    Perfekt, das hat meinen Tag gerettet.

    EDIT:

    muss mich korrigieren, das serialize() liegt dort wirklich quer.

    Irgendwie fehlt mir dann aber die Idee wie ich nun mehrere Optionen in so einem SELECT benutzen soll.
    Geändert von palettenmann (19.01.2015 um 14:22 Uhr)

Aktive Benutzer

Aktive Benutzer

Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)

Ähnliche Themen

  1. Frage zu Datenbank-Zugriff (prepare, execute, etc.)
    Von DerWolf im Forum Sonstiges zu Contao
    Antworten: 3
    Letzter Beitrag: 17.02.2011, 18:48
  2. Antworten: 0
    Letzter Beitrag: 16.10.2010, 14:27
  3. 2.8.x: Database::execute() vs. Database::executeUncached()
    Von deerwood im Forum Entwickler-Fragen
    Antworten: 11
    Letzter Beitrag: 03.03.2010, 09:31
  4. Antworten: 0
    Letzter Beitrag: 18.08.2009, 09:24

Lesezeichen

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •