Horst Hagedorn: mysql enum im zusammenspiel mit PHP

Hallo Forum,

ich habe ein Problem mit dem enum Datentyp in mySQL. Und zwar moechte ich auch in der Lage sein, dort Werte zu speichern, die Hochkommata enthalten. Zum Beispiel:

O'Neils
O'Learies
O'Brians

Nun ist es ja so, dass der enum Datentyp Hochkommata als Begrenzer fuer die einzelnen Werte einsetzt. Ansich ja kein Problem, mit addslashes() kann ich in PHP diese Hochkommata ja codieren, so dass sie mir keine Probleme machen. Anschliessend speichere ich diese Werte in der Datenbank.

Wenn ich nun die Werte von der Datenbank abfragen moechte, nutze ich einfach stripslashes() um sie wieder los zu werden.

Ist dies im generellen ein guter Ansatz? In der Theorie funktioniert es naemlich ganz gut, aber in der Praxis habe ich es nicht hinbekommen da immer zu viele oder zu wenige backslashes vorhanden waren. Generell besteht bei diesem Ansatz ja immer das Problem mit werten die Hochkommata oder backslashes enthalten.

  • Gedankensprung -

Wie verhalt es sich, wenn meine Wertemenge sehr gross ist, Beispielsweise ich speichere alle Haupstaedte der Welt. Ich moechte nur diese Hauptstaedte in meiner Datenbank haben, da wuerde sich ja auch der enum Datentyp anbieten oder? Oder sollte ich lieber eine extra Tabelle erzeugen, die alle gueltigen Staedtenamen enthaelt und dann mit PHP absichern, dass nur gueltige Werte in der anderen Tabelle gespeichert werden?

Danke fuer eure Ratschlaege!

  1. Hi,

    also du könntest deine string bevor du sie in dein mysql-query schreibst auch mit htmlentities($string,ENT_QUOTES) behandeln.
    Mit dem zusatz ENT_QUOTES werden nämlich Anführungszeichen sowie Hochkommata durch HTML-Tags ersetzt.

    Vielleicht hilft dir das, theoretisch müsstest du dann addslashes() und stripslashes() weglassen können.

    grieß

    1. echo $begrüßung;

      also du könntest deine string bevor du sie in dein mysql-query schreibst auch mit htmlentities($string,ENT_QUOTES) behandeln.

      Das ist eine ganz schlechte Idee, weil damit die Daten bereits in eine bestimmte Ausgabeformatierung gebracht werden. Möchte man später diese Daten anderswo verwenden ist diese Ausgabeformatierung möglicherweise ungeeignet und man wandelt zurück und wieder neu. Das ist unnötig komplex und fehleranfällig. In einer Datenbank sollen Daten in ihrer Roh-Form abgelegt werden.

      Außerdem berücksichtigt htmlentities() nicht alle Zeichen, die auf der Text-Schnittstelle "SQL-Statement" zu berücksichtigen sind. mysql_real_escape_string() kann das im Hinblick auf MySQL wesentlich besser.

      echo "$verabschiedung $name";

  2. Hallo

    ich habe ein Problem mit dem enum Datentyp in mySQL. Und zwar moechte ich auch in der Lage sein, dort Werte zu speichern, die Hochkommata enthalten. Zum Beispiel:

    Kein Problem bei keinem mir bekannten Datenbankmanagementsystem. Für so etwas gibt es Escapemechanismen.

    O'Neils
    O'Learies
    O'Brians

    Nun ist es ja so, dass der enum Datentyp Hochkommata als Begrenzer fuer die einzelnen Werte einsetzt. Ansich ja kein Problem, mit addslashes() kann ich in PHP diese Hochkommata ja codieren, so dass sie mir keine Probleme machen. Anschliessend speichere ich diese Werte in der Datenbank.

    Verwende lieber mysql_real_escape_string(). Beachte Beispiel 3, das Zusammenspiel mit den schrecklichen Magic Quotes.

    Wenn ich nun die Werte von der Datenbank abfragen moechte, nutze ich einfach stripslashes() um sie wieder los zu werden.

    Das ist einfach fehlerhaftes Vorgehen. Es gibt kein Hochkomma (auch keine Hochkommata) im Rückgabewert, den es loszuwerden gälte. stripslashes() ist überflüssig. Überlege Dir, aus welchem Grund Hochkommata und ähnliche Zeichen maskiert werden müssen. Überlege Dir, aus welchem Grund MySQL keine Maskierung zurückliefert.

    Ist dies im generellen ein guter Ansatz?

    Nein.

    In der Theorie funktioniert es naemlich ganz gut,

    in der Theorie ist er fehlerbehaftet.

    aber in der Praxis habe ich es nicht hinbekommen da immer zu viele oder zu wenige backslashes vorhanden waren.

    was mich nicht wundert.

    • Gedankensprung -

    Wie verhalt es sich, wenn meine Wertemenge sehr gross ist, Beispielsweise ich speichere alle Haupstaedte der Welt.

    das ist keine sehr große Wertemenge. ENUM hätte damit kein Problem. Ich halte ENUM in diesem speziellen Beispiel für ungeeignet.

    Ich moechte nur diese Hauptstaedte in meiner Datenbank haben, da wuerde sich ja auch der enum Datentyp anbieten oder?

    Nein. Meiner Meinung nach nicht.

    Oder sollte ich lieber eine extra Tabelle erzeugen, die alle gueltigen Staedtenamen enthaelt und dann mit PHP absichern, dass nur gueltige Werte in der anderen Tabelle gespeichert werden?

    Nein. Wozu?

    Wenn Du z.B. eine Tabelle Länder hast, eine Tabelle Städte, so könntest Du eine Tabelle Hauptstädte haben, in der die ID des Landes und die ID der Hauptstadt (bzw. der Hauptstädte) eingetragen ist. Wo ist das Problem? Ach so ja. Ein Frontend für diese Tabelle ist nicht unbedingt erforderlich. Aktualisierungen werden mit einem kleinen SQL-Skript erledigt. Solche Sachen sind Stammdaten, an denen sich recht selten etwas ändert. Daher hielte ich den Aufwand für die Datenpflege in diesem Bereich klein.

    Freundliche Grüße

    Vinzenz

  3. echo $begrüßung;

    ich habe ein Problem mit dem enum Datentyp in mySQL. Und zwar moechte ich auch in der Lage sein, dort Werte zu speichern, die Hochkommata enthalten.

    Das ist kein enum-spezifisches Problem sondern ein generelles.

    Nun ist es ja so, dass der enum Datentyp Hochkommata als Begrenzer fuer die einzelnen Werte einsetzt.

    Nicht wirklich. Es sind ganz normale String, die in Hochkomma oder Gänsefüßchen eingeschlossen werden müssen, wenn man sie über eine Text-Schnittstelle, wie es so ein SQL-Statement darstellt, übertragen werden sollen. Dabei sind gewisse Maskierungsregeln zu beachten, wenn Begrenzungszeichen und noch einige andere als Daten in diesen Strings vorkommen sollen.

    Ansich ja kein Problem, mit addslashes() kann ich in PHP diese Hochkommata ja codieren, so dass sie mir keine Probleme machen. Anschliessend speichere ich diese Werte in der Datenbank.

    addslashes() ist vielleicht für die Hochkommas ausreichend, aber es berücksichtigt nicht sämtliche kritische Zeichen. Für MySQL ist es besser, mysql_real_escape_string() zu verwenden.

    Wenn ich nun die Werte von der Datenbank abfragen moechte, nutze ich einfach stripslashes() um sie wieder los zu werden.

    Das ist überflüssig, da sie nur zum Transport im SQL-Statement benötigt und hinzugefügt wurden. In der Ergebnismenge stehen die Daten so wie sie in der Datenbank stehen: in ihrer Roh-Form.

    Ist dies im generellen ein guter Ansatz? In der Theorie funktioniert es naemlich ganz gut, aber in der Praxis habe ich es nicht hinbekommen da immer zu viele oder zu wenige backslashes vorhanden waren.

    Es könnte noch sein, dass dir hier Magic Quotes dazwischenfunkt. Dieses Feature wendet selbständig addslashes() auf die EGPCS-Variablen an. addslashes() ist jedoch wie gesagt nicht ausreichend. Ab PHP6 hat sich das mit den Magic Quotes auch erledigt, dieses Feature wird es dann nicht mehr geben. Bis dahin ist es eine gute Idee, sie auszuschalten, oder ihre Auswirkungen am Scriptanfang rückgängig zu machen. Siehe Disabling Magic Quotes.

    Generell besteht bei diesem Ansatz ja immer das Problem mit werten die Hochkommata oder backslashes enthalten.

    Generell bei Strings. Dagegen hilft immer mysql_real_escape_string().

    Wie verhalt es sich, wenn meine Wertemenge sehr gross ist, Beispielsweise ich speichere alle Haupstaedte der Welt.

    ENUM kann bis zu 65535 Werte haben. Das Problem ist eigentlich nur, dass bei einer Pflege der Werte das Tabellenlayout geändert werden muss. Weiterhin ist dieser Typ auf eine Tabelle beschränkt. Braucht man die Aufzählung in einer weiteren Tabelle empfiehlt es sich stattdessen eher eine eigene Tabelle zu erstellen - jedenfalls aus Datenpflegesicht. Wenn Performance eine größere Rolle spielt, ist auch doppelte Datenhaltung "gestattet". Eine weitere Tabelle bedeutet nämlich auch einen zusätzlichen Join.

    Ich moechte nur diese Hauptstaedte in meiner Datenbank haben, da wuerde sich ja auch der enum Datentyp anbieten oder? Oder sollte ich lieber eine extra Tabelle erzeugen, die alle gueltigen Staedtenamen enthaelt und dann mit PHP absichern, dass nur gueltige Werte in der anderen Tabelle gespeichert werden?

    In die "andere Tabelle" schreibt man einen Verweis auf den Primärschlüssel der Städtenamentabelle. Ändert sich mal die Hauptstadt, ändert man den Wert in der Städtenamentabelle und die Zuordnung zum Primärschlüssel in der "anderen Tabelle" bleibt erhalten.

    Abgesehen davon ist eine Liste der Hauptstädte möglicherweise ein schlechtes Beispiel. Die Hauptstadt ist sicher günstiger als ein Feld in der Ländertabelle aufgehoben - oder ein Verweis auf eine allgemeine Städteliste.

    echo "$verabschiedung $name";

    1. echo $begrüßung;

      Was ebenfalls noch bei ENUM-Feldern im Zusammenspiel mit einer Benutzeroberfläche zu beachten ist: Man möchte ja dem Benutzer sicherlich eine Auswahlmöglichkeit aus einer Liste vorgegebener Werte zur Verfügung stellen. Aus welchen Daten erzeugt man nun diese Liste? Fragt man die Tabellenstruktur ab und parst dann die Werte aus dem ENUM-Feld? Oder hat man noch eine Datenhaltung, nur für diese Liste? Oder bildet man diese Liste lieber durch Abfragen einer weiteren Tabelle mit den üblichen dafür vorgesehenen Funktionen?

      echo "$verabschiedung $name";

  4. Hallo,

    und vielen Dank erstmal für eure Antworten. Danke für den Tip mit mysql_real_escape_string(), ich werde diese Funktion auf meine Werte anwenden, bevor ich sie in der Datenbank speichere. Dann müsste ich valide Werte in der Datenbank haben und meine enum-Definition wird nicht durcheinander gebracht, wenn ein Wert ein Hochkomma enthält.

    Also seid ihr der Meinung, dass ein enum mit ca. 1000 Werten Sinn macht um Datenintegrität zu gewährleisten? Oder sollte man lieber eine zusätzliche Tabelle erstellen, die alle gültigen Werte enthält und ich überprüfe mit PHP ob vom Benutzer eingegebene Werte in dieser Tabelle vorhanden sind?

    1. Moin!

      Also seid ihr der Meinung, dass ein enum mit ca. 1000 Werten Sinn macht um Datenintegrität zu gewährleisten?

      Nein, das kann man so nicht sagen.

      Wenn sichergestellt ist, dass sich die 1000 Werte des ENUM niemals ändern können - dann ist ENUM gerechtfertigt. Die sieben Wochentage beispielsweise (mo, di, mi, do, fr, sa, so) werden sich niemals ändern, daher dürfen sie als ENUM in der Datenbank gespeichert werden (wenn man das nicht mit einem Datumsfeld machen kann, weil man kein Datum hat).

      Ebenso sind Informationen wie "männlich/weiblich", "ja/nein" oder sonstige feste Aufzählungen typische Kandidaten für ENUM.

      Aber Dinge, die sich potentiell ändern während der Lebenszeit der Datenbank, sind keine Kandidaten für ENUM.

      Deine Hauptstädteliste gehört dazu. Hauptstädte ändern sich mal. Ist doch in Deutschland erst "unlängst" vorgekommen. Weil sich auch Länder ändern können. Ist doch in Deutschland erst "unlängst" vorgekommen.

      Eine Aufzählung aller existierenden Hauptstädte ist daher wenig sinnvoll als ENUM. Ebenso wie eine Liste aller Länder der Erde. Weil du die Definition der Datenbank ändern mußt, wenn sich da was ändert, und nicht die Daten.

      Oder sollte man lieber eine zusätzliche Tabelle erstellen, die alle gültigen Werte enthält und ich überprüfe mit PHP ob vom Benutzer eingegebene Werte in dieser Tabelle vorhanden sind?

      Du kriegst doch vermutlich sowieso nur eine ID aus einer SELECT-Liste (wobei 1000 Wahlmöglichkeiten für SELECT deutlich zu lang ist).

      - Sven Rautenberg

      --
      "Love your nation - respect the others."