Brombeermilchtrinker: Datenbenkverbindung mit mysqli-Extension

Hallo!

Ich fang grad damit an, mich nach längerer Zeit wieder mit der Kombination php und einer mysql-Datenbank zu beschäftigen und lese da im entsprechenden php Quakenet Tutorial, dass man jetzt die mysqli-Extension verwenden soll.

Früher sah die Verbindung zur DB so aus bei mir:

<?php  
 $verbindung_server=mysql_connect("mysql4.example.com","db12345","meinpasswort");  
 if(!$verbindung_server)  
  {  
   die("Verbindung zum Server nicht möglich: ".mysql_error());  
  }  
 $verbindung_db=mysql_select_db("db12345");  
 if(!$verbindung_db)  
  {  
   die("Verbindung zur Datenbank nicht möglich: ".mysql_error());  
  }  
?>

Jetzt steht da im Tutorial:

Die mysqli-Extension stellt eingie Klassen bereit um mit MySQL zu arbeiten. Wir benutzen dabei die MySQLi  Klasse. Über den Konstruktor geben wir die Zugangsinformationen an um auf die Datenbank zuzugreifen.

Und der Code dazu:

<?php  
$db = new mysqli('localhost', 'username', 'password', 'database');  
?>

Kann mir jemand sagen, was ich jetzt bei "database" schreiben soll? Die ersten 3 Parameter wären ja wieder die selben wie früher, oder?

Danke für die Hilfe!

Ein DB-Dummy

  1. Hi,

    wie wär's mit dem Wert, den du hier:

    $verbindung_db=mysql_select_db("db12345");

    verwendet hast? Klingt zumindest für mich (als mysql DAU) recht plausibel.

    Ciao, Frank

    1. Hallo!

      wie wär's mit dem Wert, den du hier:
      $verbindung_db=mysql_select_db("db12345");
      verwendet hast? Klingt zumindest für mich (als mysql DAU) recht plausibel.

      Hä? Ich hatte früher 3 Paramater. Und jetzt sind es 4. Ich würd gerne wissen, ob der erste oder der vierte neu dazugekommen ist und was ich da als Wert verwende.

      LG!

      1. Mahlzeit Brombeermilchtrinker,

        wie wär's mit dem Wert, den du hier:
        $verbindung_db=mysql_select_db("db12345");
        verwendet hast? Klingt zumindest für mich (als mysql DAU) recht plausibel.

        Hä? Ich hatte früher 3 Paramater.

        Falsch, früher waren es auch mehr als 3 ... zumindest gab es noch weitere optionale.

        Und jetzt sind es 4. Ich würd gerne wissen, ob der erste oder der vierte neu dazugekommen ist und was ich da als Wert verwende.

        Wieso schaust Du dann nicht einfach mal in die Dokumentation und vergleichst?

        Außerdem solltest Du sowohl Deinen Code als auch die Antworten hier sorgfältig lesen ...

        MfG,
        EKKi

        --
        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
      2. Hi,

        wie wär's mit dem Wert, den du hier:
        $verbindung_db=mysql_select_db("db12345");
        verwendet hast? Klingt zumindest für mich (als mysql DAU) recht plausibel.

        Hä? Ich hatte früher 3 Paramater. Und jetzt sind es 4. Ich würd gerne wissen, ob der erste oder der vierte neu dazugekommen ist und was ich da als Wert verwende.

        Vier minus drei - sind gleich zwei neu dazugekommene?
        Also auch vom Rechnen scheinst du eine merkwuerdige Vorstellung zu haben ...

        Also vorher hast du erst eine Verbindung zum Datenbank-Server aufgebaut, und anschliessend eine Datenbank ausgewaehlt.
        Und jetzt hast du ploetzlich einen "neuen" vierten Parameter, der mit 'database' bezeichnet wird. Ja, was koennte man da wohl jetzt angeben ...?

        Ich bin auch total ratlos. An deiner Stelle wuerde ich es mit der Telefonnummer meines Muellmanns versuchen - das erscheint mir doch total logisch.

        MfG ChrisB

        --
        „This is the author's opinion, not necessarily that of Starbucks.“
        1. Hi,

          Vier minus drei - sind gleich zwei neu dazugekommene?

          Oh, da stand ein oder, kein und.
          Na gut, dann ziehe ich *diesen* Einwand schnell zurueck.

          MfG ChrisB

          --
          „This is the author's opinion, not necessarily that of Starbucks.“
          1. Hallo!

            OK, ich war deshalb so verwirrt, weil bei mir (Webspacehoster bedingt) User und Name der Datenbank den selben Namen haben. Ich schaffe nun die Datenbankverbindung, bekomme aber eine Fehlermeldung. :-(

              
            <?php  
            $db = new MySQLi('mysql4.example.com', 'db123456', 'meinpasswort', 'db123456');  
            $sql = 'INSERT INTO `beispieltabelle001` (`bt001_name`, `bt001_ort`) VALUES (?, ?)';  
            $kommando = $db->prepare($sql);  
            $kommando->bind_param('ss', 'Horst Lichter', 'Köln');  
            $kommando->execute();  
            $db->close();  
            ?>
            

            Bringt ein => "Fatal error: Cannot pass parameter 2 by reference in /kunden/123456_1234/webseiten/dbtest002.php on line 20" Das wäre die Zeile "$kommando->bind_param('ss', 'Horst Lichter', 'Köln');"

            Was übersehe ich?

            LG!

            1. Hi,

              $kommando->bind_param('ss', 'Horst Lichter', 'Köln');

              Bringt ein => "Fatal error: Cannot pass parameter 2 by reference in /kunden/123456_1234/webseiten/dbtest002.php on line 20" Das wäre die Zeile "$kommando->bind_param('ss', 'Horst Lichter', 'Köln');"

              Was übersehe ich?

              Du *musst* Variablen als Parameter an das Statement "binden" - direkt skalare Werte anzugeben, ist nicht moeglich.

              In aller Regel hat man ja sowieso die Werte, die man dynamisch in einer Query benutzen moechte, in Variablen vorliegen - sollte also kein Problem sein.

              Wenn du wirklich die Werte 'Horst Lichter' und 'Köln' im Script vorliegen haben willst, dann muesstest du sie trotzdem vorher in Variablen "stecken", und diese beim binden angeben.

              MfG ChrisB

              --
              „This is the author's opinion, not necessarily that of Starbucks.“
              1. Moin!

                $kommando->bind_param('ss', 'Horst Lichter', 'Köln');

                Bringt ein => "Fatal error: Cannot pass parameter 2 by reference in /kunden/123456_1234/webseiten/dbtest002.php on line 20" Das wäre die Zeile "$kommando->bind_param('ss', 'Horst Lichter', 'Köln');"

                Was übersehe ich?

                Du *musst* Variablen als Parameter an das Statement "binden" - direkt skalare Werte anzugeben, ist nicht moeglich.

                Weil es auch unsinnig wäre, statische Werte als Prepared Statement dynamisch an das Statement zu binden. Sowas fügt man direkt in den Query ein.

                Wenn du wirklich die Werte 'Horst Lichter' und 'Köln' im Script vorliegen haben willst, dann muesstest du sie trotzdem vorher in Variablen "stecken", und diese beim binden angeben.

                Alternativ einen statischen Query durchführen mit $db->query(). Prepared Statements sind zwar auch nett, aber nicht der 100%-Ersatz für das alte mysql_query, sondern für die Fälle geeignet, bei denen man eben Prepared Statements verwenden möchte. Das Escaping dabei aber nicht vergessen, wenn mysqli_query() verwendet wird!

                - Sven Rautenberg

              2. Hallo!

                Wenn du wirklich die Werte 'Horst Lichter' und 'Köln' im Script vorliegen haben willst, dann muesstest du sie trotzdem vorher in Variablen "stecken", und diese beim binden angeben.

                Danke, Chris, soweit klappt es. Wenn ich da gleich 2 Folgefragen stellen darf:

                1. Ich habe im php-Header utf-8 als Codierung angegeben, zusätzlich hat die entstehende Seite ein "<meta http-equiv="content-type" content="text/html; charset=utf-8" />", die Datenbank hat Standartmäßig als Kollation "utf8_unicode_ci". Zusätzlich hat jede Zeile der Tabelle die selbe Kollation. Ich wüßte also nicht, wo ich NOCH utf-8 als Kodierung einstellen soll.

                Trotzdem landet mein "Köln" als "Köln" in der DB. (Wenn ich es _direkt_ eingebe, also über phpmyadmin, wird es korrekt angezeigt!)

                Was muß ich denn tun/ändern, damit Köln auch als Köln in der DB steht, wenn es via php zur Datenbank kommt?

                1. Auf php Buddy habe ich zum "binding" Folgendes gefunden:

                "Hier binden wir Variablen an das Statement das wir zuvor an die DB geschickt haben. Der erste Parameter, hier 'ss', teilt der Datenbank mit um welche Daten es sich handeln wird, die in die DB geschrieben werden sollen. Anhand dessen wird die DB eigenständig das escapen (unschädlich machen von Benutzereingaben) übernehmen - dieser Parameter stellt also eine Typbezeichnung dar."

                Heißt das etwa jetzt, daß ich mich nicht mehr um SQL Injection kümmern muß? Oder anders ausgedrückt: Ist das, was auf der mysql_real_escape_string-Seite im PHP-handbuch unter Beispiel 3 steht, jetzt zu vergessen, wenn ich bei mysqli bleibe???

                Danke im Voraus!

                1. Hi,

                  1. Ich habe im php-Header utf-8 als Codierung angegeben, zusätzlich hat die entstehende Seite ein "<meta http-equiv="content-type" content="text/html; charset=utf-8" />", die Datenbank hat Standartmäßig als Kollation "utf8_unicode_ci". Zusätzlich hat jede Zeile der Tabelle die selbe Kollation. Ich wüßte also nicht, wo ich NOCH utf-8 als Kodierung einstellen soll.

                  In der Verbindung zur Datenbank - PHP und MySQL muessen sich auch darauf verstaendigen, in welchem "Dialekt" sie sich unterhalten.

                  Was muß ich denn tun/ändern, damit Köln auch als Köln in der DB steht, wenn es via php zur Datenbank kommt?

                  Zum Beispiel ueber mysqli::options kannst du ein MYSQLI_INIT_COMMAND angeben, dass nach dem Herstellen der Verbindung ausgefuehrt werden soll.
                  Und zum setzen der Kodierung fuer die Verbindung verwendet man das MySQL-Statement SET NAMES.

                  Heißt das etwa jetzt, daß ich mich nicht mehr um SQL Injection kümmern muß? Oder anders ausgedrückt: Ist das, was auf der mysql_real_escape_string-Seite im PHP-handbuch unter Beispiel 3 steht, jetzt zu vergessen, wenn ich bei mysqli bleibe???

                  Wenn du bei Prepared Statements bleibst - ja.

                  Wie Sven aber gerade schon sagte, wenn du bspw. ueber mysqli_query() direkt eine Query an die Datenbank absetzt, dann musst du dich um das Escaping wieder selber kuemmern.

                  MfG ChrisB

                  --
                  „This is the author's opinion, not necessarily that of Starbucks.“
                  1. Hi,

                    Zum Beispiel ueber mysqli::options kannst du ein MYSQLI_INIT_COMMAND angeben, dass nach dem Herstellen der Verbindung ausgefuehrt werden soll.
                    Und zum setzen der Kodierung fuer die Verbindung verwendet man das MySQL-Statement SET NAMES.

                    Warum kompliziert, wenn's auch einfach geht - man kann natuerlich auch mysqli::set_charset verwenden.

                    MfG ChrisB

                    --
                    „This is the author's opinion, not necessarily that of Starbucks.“
                    1. Halo!

                      So, _jetzt_ ist es soweit, dass ich GANZ aussetiege. :-(

                      wenn du bspw. ueber mysqli_query() direkt eine Query an die Datenbank absetzt

                      Wie meinst Du das? Könntest Du mir da ein Besipiel geben, was der Unterscheid zu dem ist, was ich vorher gemacht habe?

                      Und das mit der Codierung bekomm ich einfach nicht hin. Und ich verstehe auch nicht, warum das Problem überhaupt da ist, wenn ich schon in der DB-Grundeinstellung utf-8 festgelegt habe. UND zusätzlich noch für jede Tabellenzeile!

                      MFG

                      Brombeermilchtrinker

                      1. Hi,

                        wenn du bspw. ueber mysqli_query() direkt eine Query an die Datenbank absetzt

                        Wie meinst Du das? Könntest Du mir da ein Besipiel geben, was der Unterscheid zu dem ist, was ich vorher gemacht habe?

                        Wenn du mit mysqli_query eine Query an die Datenbank absetzt, dann machst du das nach wie vor so:

                        mysql_query("SELECT ... FROM WHERE xyz = '".$variable."'");

                        Hier hast du jetzt also nach wie vor, wie auch bei der Verwendung der alten MySQL-Erweiterung, ein Problem, wenn $variable beispielsweise ein Zeichen wie ' enthaelt, dass im Kontext MySQL-Query ein Sonderzeichen darstellt.
                        Also muss du hier nach wie vor diese Variable vorher entsprechend behandeln.
                        Denn sonst kann der Parser, mit dem MySQL die Query analysiert, im Zweifelsfalle nicht mehr entscheiden, was an der Query jezt Befehls-Schluesselwoerter, und was Daten sein sollen.

                        Bei Prepared Statements entfaellt dies - weil der Befehlsteil der Query und die Daten auf getrennten "Kanaelen" zur Datenbank transportiert werden.

                        Und das mit der Codierung bekomm ich einfach nicht hin. Und ich verstehe auch nicht, warum das Problem überhaupt da ist, wenn ich schon in der DB-Grundeinstellung utf-8 festgelegt habe. UND zusätzlich noch für jede Tabellenzeile!

                        Die Kollation ist lediglich eine Sortiervorschrift, die bei Vergleiche und beim Sortieren zum tragen kommt - bspw., dass ein ü und ue im Deutschen gleich behandelt werden sollen, wird ueber die Angabe einer entsprechenden Kollation festgelegt.

                        Wenn PHP aber (bspw.) UTF-8 kodierte Daten an die Datenbank uebergibt, oder umgekehrt die Datenbank zurueck an PHP, dann muessen sich beide auch vorher darueber geeinigt haben, *dass* sie die Daten in UTF-8 kodiert uebergeben wollen.
                        Wenn jetzt die Default-Einstellung fuer die Verbindungskodierung bspw. eine der Latin-Varianten ist - dann wuerde MySQL die Daten automatisch umkodieren, wenn PHP ihm UTF-8 liefert. Das gibt aber Chaos.
                        Deshalb vor dem Absetzen der ersten Query im Script, die Daten holen oder uebertragen soll, die fuer die Verbindung zu verwendenden Kodierung aushandeln.

                        MfG ChrisB

                        --
                        „This is the author's opinion, not necessarily that of Starbucks.“
                        1. Hallo!

                          Danke, ich habe jetzt das gewünschte Ergebnis, in dem ich den Code folgendermaßen erweitert habe:

                          <?php  
                          $koch="Horst Lichter";  
                          $wohnort="Köln";  
                          $db = new MySQLi('mysql4.example.com', 'db123456', 'meinpasswort', 'db123456');  
                          $sql = 'INSERT INTO `beispieltabelle001` (`bt001_name`, `bt001_ort`) VALUES (?, ?)';  
                          $db->set_charset("utf8");  
                          $kommando = $db->prepare($sql);  
                          $kommando->bind_param('ss', $koch, $wohnort);  
                          $kommando->execute();  
                          $db->close();  
                          ?>  
                          
                          

                          Wenn du mit mysqli_query eine Query an die Datenbank absetzt, dann machst du das nach wie vor so:
                          mysql_query("SELECT ... FROM WHERE xyz = '".$variable."'");
                          Hier hast du jetzt also nach wie vor, wie auch bei der Verwendung der alten MySQL-Erweiterung, ein Problem, wenn $variable beispielsweise ein Zeichen wie ' enthaelt, dass im Kontext MySQL-Query ein Sonderzeichen darstellt.

                          Hm, das verstehe ich halbwegs, aber wenn ich zB auf die Erklärung beim Traumprojekt schaue, dann kommt dort beim Punkt "Datensätze auslesen (Query Methode)" überhaupt kein "mysql_query" vor. Gehts dort um was anderes als das, was DU gemeint hast?

                          Bei Prepared Statements entfaellt dies - weil der Befehlsteil der Query und die Daten auf getrennten "Kanaelen" zur Datenbank transportiert werden.

                          Ich traus mich fast nicht sagen, aber ich versteh nicht ganz, was Du meinst und von welchem Unterschied Du sprichst. Für mich ist das Arbeiten mit DB wirkliches Neuland! Das scheint ja jetzt alles _noch_ komplizierter zu sein als mit der "alten" Methode. Sorry, dass ich mich so dumm anstelle! :-(

                          LG!

                          1. Hi,

                            Hm, das verstehe ich halbwegs, aber wenn ich zB auf die Erklärung beim Traumprojekt schaue, dann kommt dort beim Punkt "Datensätze auslesen (Query Methode)" überhaupt kein "mysql_query" vor.

                            Doch, kommt es.
                            Nur nicht in der prozeduralen, sondern in der objektorientierten Variante - $db ist dort die Instanz der MySQLi-Klasse, und auf der wird die Methode query aufgerufen:
                            $ergebnis = $db->query( $sql );

                            Bei Prepared Statements entfaellt dies - weil der Befehlsteil der Query und die Daten auf getrennten "Kanaelen" zur Datenbank transportiert werden.

                            Ich traus mich fast nicht sagen, aber ich versteh nicht ganz, was Du meinst und von welchem Unterschied Du sprichst.

                            OK, noch mal gaaanz langsam:

                            Wenn du mysqli_query nutzt - egal ob prozedural oder objektorientiert - dann baust du dir dein SQL-Statement selber zusammen, und hast Befehl-Schluesselwoerter (wie SELECT, INSERT, ...) *und* deine Daten in einem String stehen:
                            INSERT INTO beispieltabelle001 (bt001_name, bt001_ort) VALUES ('blah', 'blubb')
                            blah und blubb waeren hier die Daten, die wir in die Tabelle einfuegen wollen. Da dies Strings im MySQL-Kontext sind, muessen sie innerhalb des Statements in Hochkommata (oder Anfuehrungszeichen) stehen.

                            So, jetzt sind diese Daten aber nicht fix, sondern dynamisch - sie koennten beispielsweise aus einem Formular kommen. Und jetzt sei mal der erste Wert nicht blah, sondern O'Connor - dann erhielten wir folgendes Statement:
                            INSERT INTO beispieltabelle001 (bt001_name, bt001_ort) VALUES ('O'Connor', 'blubb')
                            Du siehst, schon am Syntaxhighlighting hier, dass das mit den Hochkommata jetzt Probleme macht - der MySQL-Textstring endet jetzt schon wieder nach dem 'O', und danach folgt jetzt etwas, was keine gueltige SQL-Syntax mehr darstellt - also haben wir da ein Problem. Und deshalb muessen wir unseren Wert O'Connor fuer den Kontext MySQL behandeln - und zwar so, dass das Sonderzeichen ' durch einen vorgestellten \ "maskiert" wird:
                            INSERT INTO beispieltabelle001 (bt001_name, bt001_ort) VALUES ('O\'Connor', 'blubb')
                            Damit hat das Zeichen ' hier nicht mehr die Bedeutung "String ist zu Ende", und damit ist das Statement fuer den MySQL-Parser wieder verstaendlich.
                            (Das Maskieren machen wir aber nicht selber "per Hand" - sondern dafuer gibt's die Funktion mysqli_real_escape_string - die weiss, welche Zeichen im Kontext eines MySQL-Statements Sonderbedeutung, und behandelt sie entsprechend.)

                            So, das ganze Problem haben wir aber nur, weil wir bei dieser Art, eine Query an MySQL zu uebergeben, Befehl und Daten "in einem" an MySQL uebergeben - und dessen Parser muss erst mal analysieren, was davon eigentlich Befehl, und was Daten sind.

                            Bei den Prepared Statement wird das getrennt - erst mal wird der eigentliche Befehl uebergeben,
                            INSERT INTO beispieltabelle001 (bt001_name, bt001_ort) VALUES (?, ?)
                            Das ist fuer den Parser ganz eindeutig, "Aha, ein INSERT-Statement, in dem zwei Platzhalter vorkommen, an denen ich spaeter irgendwelche Daten einsetzen muss".
                            Das Statement ist jetzt analysiert, uebersetzt, vorbereitet - auf Englisch "prepared".

                            Ueber das Binding der Variablenwerte ans Statement uebergeben jetzt anschliessend unsere Daten. Da dies jetzt aber einen separaten Schritt darstellt, kann auch nichts mehr missverstanden werden - sowohl blah als auch O'Connor koennen wir jetzt direkt und unbehandelt uebergeben, weil wir dies jetzt nicht mehr in einem Kontext tun, in dem das Zeichen ' eine Sonderbedeutung haette. Wir uebergeben ja nur noch reine Daten, diese muessen nicht mehr geparst und dabei von Befehlswoertern getrennt werden.

                            MfG ChrisB

                            --
                            „This is the author's opinion, not necessarily that of Starbucks.“
                            1. VIELEN Dank, daß Du Dir die Zeit genommen hast, mir das so ausführlich und einfach zu erklären. Ich weiß jetzt nämlich _wirklich_, was Du gemeint hast! Danke für die Hilfe. Chris!

                              Der Brombeermilchtrinker

                              PS: Entschuldige, dass ich erst jetzt antworte, aber ich hab daheim keinen PC und komm nur sehr unregelmäßig ins Netz!

                              1. Hi,

                                VIELEN Dank, daß Du Dir die Zeit genommen hast, mir das so ausführlich und einfach zu erklären. Ich weiß jetzt nämlich _wirklich_, was Du gemeint hast!

                                Das freut mich, gern geschehen.

                                MfG ChrisB

                                --
                                „This is the author's opinion, not necessarily that of Starbucks.“
                    2. Moin!

                      Zum Beispiel ueber mysqli::options kannst du ein MYSQLI_INIT_COMMAND angeben, dass nach dem Herstellen der Verbindung ausgefuehrt werden soll.
                      Und zum setzen der Kodierung fuer die Verbindung verwendet man das MySQL-Statement SET NAMES.

                      Warum kompliziert, wenn's auch einfach geht - man kann natuerlich auch mysqli::set_charset verwenden.

                      Das ist kein "kann", sondern ein "sollte wirklich immer" - sowohl was die Notwendigkeit generell angeht, als auch die Wahl zwischen diesem Befehl und dem Query "SET NAMES..." - denn in der Wirkung unterscheiden sich beide Befehle, "SET NAMES..." hat bei exotischeren Konstellationen Nachteile, weil die Clientseite der MySQL-Lib vom Encoding nichts mitbekommt. Das ist potentiell böse, bei UTF-8 fällt es allerdings nicht ins Gewicht.

                      - Sven Rautenberg