Achot: MySQL Zugangsdaten

Guten Morgen,

ich arbeite auf zwei unterschiedlichen Webspace Paketen. Auf einem entwickel ich die Seite auf dem anderen ist die Live Seite. Bis jetzt hatte ich immer umständlich zwei Verzeichnisse auf der Festplatte. Dieses würde ich gerne zusammenfügen.

Nur ein Problem, ich habe unterschiedliche Zugangsdaten, die ich jetzt in eine Datei gepackt habe:

switch ($_SERVER['SERVER_NAME'])
{
  case 'https://example.com' :
    
    $mysqli = new mysqli("127.0.0.1", "xxxxx", "xxxxx", "xxxxx");

	if ($mysqli->connect_error) {
	  echo "Fehler bei der Verbindung: " . mysqli_connect_error();
	  exit();
	}
	
	if (!$mysqli->set_charset("utf8")) {
	  echo "Fehler beim Laden von UTF8 ". $mysqli->error;
	}
    
    break;
  
  default :
    $mysqli = new mysqli("localhost", "xxxxx", "xxxxx", "xxxxx");

	if ($mysqli->connect_error) {
	  echo "Fehler bei der Verbindung: " . mysqli_connect_error();
	  exit();
	}
	
	if (!$mysqli->set_charset("utf8")) {
	  echo "Fehler beim Laden von UTF8 ". $mysqli->error;
	}
    
    break;
}

Ist dieses so OK oder könnte man dieses auch noch vereinfacht schreiben?

  1. Eine Lösung die solche Daten elegant auslagert kenne ich nicht. Du könntest aber zumindest nur die eine Zeile mit den Zugangsdaten im switch halten und den Rest nur ein einziges mal außerhalb.

  2. Moin,

    Ist dieses so OK oder könnte man dieses auch noch vereinfacht schreiben?

    Eine Idee/Möglichkeit zur Vereinfachung besteht darin, eine Methode zu haben, die lediglich den Namen der Datenbank übergeben bekommt und dafür ein DB-Handle zurückliefert, etwa so:

    $dbh = $self->dbh('webdaten');

    Diese Methode arbeitet mit einer Konfigurationsdatei zusammen in welcher die Zugangsdaten hinterlegt sind. Ideal ist das .ini Format für die Konfig.Datei. Des Weiteren könnte man der Methode dbh() soviel Intelligenz einhauchen, dass sie selber merkt auf welchem Host sie aufgerufen wird.

    MfG

    PS: Statt dbh könnte man auch pdo schreiben.

  3. So was löst man eigentlich so, dass man beim Verteilen auf den oder die Server eine Datei hat, die serversspezifisch ist und nur auf den Server kopiert wird für den sie gültig ist. Und da ist dann alles drin, was speziell für diesen Server gilt. Das kann Verschiedenes sein. Z.B. eine DB-Konfiguration. Oder der Name einer Klasse, die Code enthält der nur für diesen Server gilt. Die Datei includest Du und hast die Serverspezifika zur Hand.

    In der einfachsten Form ist das eine Datei, die NUR auf dem Server existiert und dein Code fällt auf Entwicklerwerte zurück, wenn er die Datei nicht findet.

    Rolf

    1. Ups, sorry an pl, hab deinen Beitrag nicht genau genug gelesen. Configdateien sind ja eh dein Spezialgebiet ;-)

    2. In der einfachsten Form ist das eine Datei, die NUR auf dem Server existiert und dein Code fällt auf Entwicklerwerte zurück, wenn er die Datei nicht findet.

      Oh Vorsicht mit dem Setzen von Defaults -- da sind systematische Fehler quasi vorprogrammiert. Wenn zum Beispiel die richtige Tabelle vom falschen Host geladen wird, könnte das Ergebnis schonmal die Erwartung verfehlen ;)

      D.h., über Allem sollte auch die Fehlerbehandlung nicht vergessen werden, Versionskontrolle inbegriffen.

      MfG

  4. Nur ein Problem, ich habe unterschiedliche Zugangsdaten, die ich jetzt in eine Datei gepackt habe:

    Ein amtierendes best-practice ist es, die Konfiguration in Umgebungs-Variablen auszulagern. Beim Apache-Webserver erreichst du das zum Beispiel über die VHost-Konfiguration oder .htaccess-Datei:

    SetEnv databaseHost example.com
    SetEnv databaseUser user
    SetEnv databasePassword password
    SetEnv databaseName database
    

    In PHP kannst du Umgebungs-Variablen mit getenv auslesen:

    $mysqli = new mysqli(
       getenv('databaseHost'),
       getenv('databaseUser'),
       getenv('databasePassword'),
       getenv('databaseName')
    );
    
    1. Nur ein Problem, ich habe unterschiedliche Zugangsdaten, die ich jetzt in eine Datei gepackt habe:

      Ein amtierendes best-practice ist es, die Konfiguration in Umgebungs-Variablen auszulagern. Beim Apache-Webserver erreichst du das zum Beispiel über die VHost-Konfiguration oder .htaccess-Datei:

      SetEnv databaseHost example.com
      SetEnv databaseUser user
      SetEnv databasePassword password
      SetEnv databaseName database
      

      Ist ja Grausig. Ganz abgesehen davon, wenn es mehrere unterschiedliche Konfigurationen geben soll, würde ich Credentials, gleich welcher Art, niemals in globale Variablen setzen wollen und erst recht nicht in die Serverumgebung. Und schon gar nicht Passworte in Plaintext.

      So ein Unfug! Lass das bloß keinen sehen!

      MfG

      PS: Was in die Serverumgebung gehört, definiert der CGI/1.1 Standard.

      1. Hallo pl,

        Ist ja Grausig.

        Nö, das ist eigentlich eine clevere Methode, die das Deployment stark vereinfacht.

        Ganz abgesehen davon, wenn es mehrere unterschiedliche Konfigurationen geben soll […]

        Klasse. Work done, mission accomplished.

        Und schon gar nicht Passworte in Plaintext.

        Äh – wie denn sonst? Die Software muss sie doch verwenden können. Dazu müssen sie im Klartext vorliegen.

        LG,
        CK

        1. pl, wo liegen denn deine DB-Zugangsdaten? Im Code? Oder tippst Du sie beim Serverstart jeweils ein, so dass der Server sie im Speicher behält? Nee, oder? Ich würde wetten, dass sie im Rückgrat deines Frameworks stecken, also in den entsprechenden Config-Dateien, die schön versteckt im Hintergrund liegen, wo nur du als Admin schreiben darfst und nur deine laufenden Perlen lesen können.

          Ich denke, es ist relativ wurscht ob diese Informationen in Environment-Variablen liegen oder in einer Config-Datei, die man includet. Hat alles seine Vor- und Nachteile.

          Bei einer Config-Datei muss man den Server so einrichten, dass man sie nicht eben mal downloaden kann (z.B. per .htaccess, wenn Winnetou die Daten serviert). Liegt die Konfiguration im Environment, dürfte sich die Frage nicht stellen.

          Dafür hat man beim Environment ggf. das Problem der Datenvermischung; eine .htaccess Datei enthält viel mehr als nur Config-Daten für eine bestimmte Serverinstanz. Das kann Änderungen komplizierter machen.

          Muss man eben abwägen.

          Hauptsache, man hat die Config-Daten isoliert, an einem Ort platziert wo kein Unbefugter 'rankommt und kann beim Verteilen der Software auf den/die Server steuern, welche Konfiguration relevant ist. Auswahl der korrekten Konfiguration ist ein Job des Deployment-Scripts (bzw. ein Job des Admin, wenn das Deployment nicht silent-automagisch erfolgt).

          Rolf

          1. pl, wo liegen denn deine DB-Zugangsdaten? Im Code? Oder tippst Du sie beim Serverstart jeweils ein, so dass der Server sie im Speicher behält? Nee, oder? Ich würde wetten, dass sie im Rückgrat deines Frameworks stecken, also in den entsprechenden Config-Dateien, die schön versteckt im Hintergrund liegen, wo nur du als Admin schreiben darfst und nur deine laufenden Perlen lesen können.

            Zugangsdaten hab in der Website-Config nichts zu suchen. Von daher haben sie auch wieder aus dem Hauptspeicher zu verschwinden, wenn der Req/Res-Zyklus abgeschlossen ist.

            Ich denke, es ist relativ wurscht ob diese Informationen in Environment-Variablen liegen oder in einer Config-Datei, die man includet. Hat alles seine Vor- und Nachteile.

            Die Webserver-Umgebung ist dem Standard CGI/1.1 vorbehalten.

            Muss man eben abwägen.

            Globale Variablen habe sich immer wieder als problematisch erwiesen.

            Hauptsache, man hat die Config-Daten isoliert,

            Die Config für die gesamte WebSite darf schon komplett im Hauptspeicher liegen und das sollte sie auch. Und ja, bei meinem Framework sind die Zugangsdaten für Datenbanken über die Methode

            $dbh = $self->dbh('webdaten');

            gekapselt. Die Methode ist im Rahmen einer Factory aufgestellt und lädt eine eigene Konfiguration. In PHP würde ich das genauso machen:

            require 'credentials.php';
            $pdo = $this->pdo('webdaten');
            

            /pl

            1. Ok, d.h. der einzige Punkt wo wir zwei uns uneinig sind ist die Frage, ob man Defaults hinterlegen sollte oder auch auf der Entwicklermaschine eine Config-Datei voraussetzt :)

              Und natürlich hast Du recht, mit Defaults kann man auffe Fresse fliegen wenn auf der PROD-Maschine die Config-Datei fehlt. Fliegen tut man allerdings auf jeden Fall, egal ob man irrtümlich Defaults verwendet oder die Config-Datei nicht da ist. Denn Entwicklermaschinen-Defaults sollten schon so gestaltet sein, dass sie auf der PROD-Maschine zu laut rasselnden Fehlermeldungen führen (eine von diesen: DB-Server nicht erreichbar, DB existiert nicht, DB-Passwort falsch). Es wäre schon fatal, wenn die Entwickler-Config auf der Prod-Maschine funktionierte.

              Rolf

              1. Ok, d.h. der einzige Punkt wo wir zwei uns uneinig sind ist die Frage, ob man Defaults hinterlegen sollte oder auch auf der Entwicklermaschine eine Config-Datei voraussetzt :)

                Die Antwort heißt: Kapselung. In Fakt weiß nur die Funktion $this->pdo('database_name'); wo die Zugangsdaten hinterlegt sind.

                Und natürlich hast Du recht, mit Defaults kann man auffe Fresse fliegen wenn auf der PROD-Maschine die Config-Datei fehlt. Fliegen tut man allerdings auf jeden Fall, egal ob man irrtümlich Defaults verwendet oder die Config-Datei nicht da ist. Denn Entwicklermaschinen-Defaults sollten schon so gestaltet sein, dass sie auf der PROD-Maschine zu laut rasselnden Fehlermeldungen führen (eine von diesen: DB-Server nicht erreichbar, DB existiert nicht, DB-Passwort falsch). Es wäre schon fatal, wenn die Entwickler-Config auf der Prod-Maschine funktionierte.

                Man könnte die Methode $this->pdo('database_name'); so intelligent machen, dass sie den Namen des Hosts kennt auf dem sie aufgerufen wird. Btw., vor ein paar Jahren hab ich mal eine proprietäre Versionskontrolle fürs DB-Design pogrammiert. In die Fehlerbehandlung einbezogen, konnte ohne Umschweife festgestellt werden, ob ein Syntaxfehler vorliegt oder ein Versionskonflikt.

                mfg

                1. Man könnte die Methode $this->pdo('database_name'); so intelligent machen, dass sie den Namen des Hosts kennt auf dem sie aufgerufen wird.

                  Das ähnelt dem "Grouping"-Ansatz, der bei der Twelve-Factor-App auch diskutiert wird. Das Problem ist, dass dieser Ansatz nicht gut skaliert: Dein Code wächst mit der Anzahl der Deploys.

            2. Zugangsdaten hab[en] in der Website-Config nichts zu suchen.

              Bei der Twelve-Factor-App unterscheidet man auch nach bestimmten Arten der Konfiguration: Einstellungen, die pro Deploy (lies Installation) variieren können und anwendungs-interne Einstellungen, die sich nicht ändern. Datenbank-Zugangsdaten fallen in die erste Kategorie, als Beispiel für die zweite Kategorie wird die Router-Konfiguration von Rails genannt.

              Für kontextsensitive Einstellungen wird empfohlen, sie in Umgebungs-Variablen zu speichern, weil sie von dort aus nicht versehentlich in das VCS-Repository geraten können. App-interne Einstellungen sollten hingegen in den Source-Dateien im Versionskontrollsystem getrackt werden. Die Idee bei dieser Unterscheidung ist ganz einfach, dass sie erlaubt maximal viel Code zwischen Deploys zu teilen und gleichzeitig die Integrität sensibler Daten durch Isolation vom Code zu wahren. Das erleichtert das Deployment.

              Ich denke, es ist relativ wurscht ob diese Informationen in Environment-Variablen liegen oder in einer Config-Datei, die man includet. Hat alles seine Vor- und Nachteile.

              Die Webserver-Umgebung ist dem Standard CGI/1.1 vorbehalten.

              Zunächst ist CGI nicht der einzige Standard für Webserver. Aber wo du es schon ansprichst, Umgebungs-Variablen sind ausdrücklicher Teil der Schnittsellen-Spezifikation. Dort steht geschrieben:

              For UNIX compatible operating systems, the following are defined:

              Meta-Variables
              Meta-variables are passed to the script in identically named
              environment variables. These are accessed by the C library
              routine getenv() or variable environ.

              […]

              For POSIX compatible operating systems using the EBCDIC character set, the following are defined:\

              Meta-Variables
              Meta-variables are passed to the script in identically named
              environment variables. These are accessed by the C library
              routine getenv().

              Quelle: https://tools.ietf.org/html/rfc3875#section-7.2, https://tools.ietf.org/html/rfc3875#section-7.3

              Globale Variablen habe sich immer wieder als problematisch erwiesen.

              Umgebungs-Variablen sind etwas anderes als PHP globale Variablen, oder allgemein als globale Programm-Variablen. Sie existieren in völlig isolierten Kontexten, es gibt keine Verwechslungsgefahr beim Lesen oder Schreiben von Umgebungs-Variablen/globalen Variablen. Darüberhinaus sind Umgebungs-Variablen aus einer globalen Sicht auf die Deploys alles andere als global: Umgebungs-Variablen werden zwischen verschiedenen Deploys nicht geteilt. Sie gelten nur für die Umgebung, für die sie definiert wurden.

          2. Dafür hat man beim Environment ggf. das Problem der Datenvermischung; eine .htaccess Datei enthält viel mehr als nur Config-Daten für eine bestimmte Serverinstanz. Das kann Änderungen komplizierter machen.

            Um dem entgegen zu wirken, kann man die Konfiguration auch in eine eigene Datei auslagern und sie mittels include-Direktive in die VHost-Konfiguration einbetten. Das vereint die Vorteile beider Vorgehensweisen.

            1. Dafür hat man beim Environment ggf. das Problem der Datenvermischung; eine .htaccess Datei enthält viel mehr als nur Config-Daten für eine bestimmte Serverinstanz. Das kann Änderungen komplizierter machen.

              Um dem entgegen zu wirken, kann man die Konfiguration auch in eine eigene Datei auslagern und sie mittels include-Direktive in die VHost-Konfiguration einbetten. Das vereint die Vorteile beider Vorgehensweisen.

              Das wieder muss man aber erst einmal dürfen.

              Ansonsten bietet sich das Speichern in "/[ausserhalb von Document-Root]/server-spezische_dateien/settings-php" und dann auch ein Update vom Entwicklungs- auf den Produktivserver mit gescriptetem rsync an. Da kann man Dateien oder ganze Ordner hübsch ausschließen. Voraussetzung ist ssh auf beiden Servern und natürlich installiertes rsync.

              Ronald Schaukrug

              1. Dafür hat man beim Environment ggf. das Problem der Datenvermischung; eine .htaccess Datei enthält viel mehr als nur Config-Daten für eine bestimmte Serverinstanz. Das kann Änderungen komplizierter machen.

                Um dem entgegen zu wirken, kann man die Konfiguration auch in eine eigene Datei auslagern und sie mittels include-Direktive in die VHost-Konfiguration einbetten. Das vereint die Vorteile beider Vorgehensweisen.

                Das wieder muss man aber erst einmal dürfen.

                Ggf. muss man sich an den Server-Administrator wenden. Ich habe noch nie erfahren, dass sich ein Admin geweigert hätte Umgebungs-Variablen zu setzen. Sollte das mal vorkommen, würde ich ein Hoster-Upgrade in Erwägung ziehen.

                Ansonsten bietet sich das Speichern in "/[ausserhalb von Document-Root]/server-spezische_dateien/settings-php"

                Auch dafür benötigst man Berechtigungen, die der Server-Adminstrator einem einräumen muss.

                und dann auch ein Update vom Entwicklungs- auf den Produktivserver mit gescriptetem rsync an. Da kann man Dateien oder ganze Ordner hübsch ausschließen.

                Kennst du schon git? Das ist rsync auf Steroiden: Neben der Synchronisation von Dateien und Ordnern, wird auch eine Versionshistorie verwaltet. Es ermöglicht außerdem die Anbindung an Kollaborations-Platformen wie https://github.com und CI-Services wie https://travis-ci.org/ und https://scrutinizer-ci.com/