DarkoWho: [PHP] MySQL-Prozeduren in PHP verwenden

Hallo,
ich bin grade dabei, mich mit Prozeduren in MySQL vertraut zu machen - womit ich bis jetzt leider noch nicht so erfolreich war.

Im Moment lasse ich z.B. Daten durch folgenden Code in meine Datenbank eintragen:

  
if (isset($submitbutton))  
{  
  $sql = "INSERT INTO TABELLE (user, task, credate) VALUES('$user', '$task', 'CURRENT_DATE()')";  
    if (mysql_query($sql))  
          echo "";  
           else  
          echo "<br><b>Nicht</b> eingetragen. Bitte Admin informieren!</br>";  
}  

Verstehe ich das jetzt richtig, dass ich mit MySQL, z.B. in PHPMyAdmin, eine Prozedur erstellen muss, die quasi den INSERT-Befehl enthält?

Würde die Prozedur dann so aussehen?

  
delimiter //  
drop procedure sql_insert;  
  
create procedure sql_insert ()  
begin  
 INSERT INTO DATENBANK.TABELLE (user, task, credate) values  
('$User', '$task', CURRENT_DATE());  
end;  

Wenn ja, wie rufe ich diese Prozedur dann in PHP auf?

Danke schonmal!

  1. Moin!

    ich bin grade dabei, mich mit Prozeduren in MySQL vertraut zu machen - womit ich bis jetzt leider noch nicht so erfolreich war.

    Im Moment lasse ich z.B. Daten durch folgenden Code in meine Datenbank eintragen:

    Du benutzt die alte mysql-Extension für den Zugriff auf MySQL. Das ist ok für alles "normale" Query-Zeugs, aber spätestens bei fortgeschrittenen Dingen, wie du sie vorhast, wirst du an irgendeinem Punkt scheitern - weil die Features, die du benutzen willst, teilweise nur mit der neueren Extension mysqli funktionieren. Grundsätzlich wird empfohlen, nur noch mysqli zu verwenden - es bietet auch rein PHP-seitig Features an, die man gerne haben will, beispielsweise objektorientiertes Arbeiten.

    if (isset($submitbutton))
    {
      $sql = "INSERT INTO TABELLE (user, task, credate) VALUES('$user', '$task', 'CURRENT_DATE()')";
        if (mysql_query($sql))
              echo "";
               else
              echo "<br><b>Nicht</b> eingetragen. Bitte Admin informieren!</br>";
    }

    
    >   
    > Verstehe ich das jetzt richtig, dass ich mit MySQL, z.B. in PHPMyAdmin, eine Prozedur erstellen muss, die quasi den INSERT-Befehl enthält?  
      
    Die Frage ist, was du dir von sowas versprichst? So oder so würde in der Datenbank immer ein INSERT ausgeführt. Eine Prozedur würde dir eventuell ein wenig Komplexitätsarbeit abnehmen, wenn du in mehr als eine Tabelle schreiben musst. Und natürlich könnte man auch Validierung der übergebenen Daten dort reinschreiben.  
      
    Das aber würde dann bedeuten, dass ein größerer Teil deiner Programmlogik nicht mehr in PHP programmiert ist, sondern in MySQL. Das ist nicht unbedingt so schön. Es ist wahrscheinlich, dass deine Anwendung niemals in einen Nutzungsbereich gerät, wo Performance eine Rolle spielt, aber trotzdem will ich anmerken, dass es aus dieser Sicht sehr hinderlich ist, wenn die Datenbank noch mehr tun muss, als nur die Daten schreiben zu müssen.  
      
    Dein oben gezeigter Code enthält allerdings etliche sofort offensichtliche Schwachstellen:  
      
    1\. Du verlässt dich auf register\_globals = on, oder du kopierst sämtliche Variablen aus $\_POST in neue Einzelvariablen. Das ist sehr ungünstig. register\_globals steht auf der Abschussliste und wird aus PHP entfernt, d.h. du hast nicht automatisch `$submitbutton`{:.language-php}, wenn du `<input type="submit" name="submitbutton">`{:.language-html} in deinem Formular stehen hast, sondern nur $\_POST['submitbutton']. Und das Umkopieren mit `$submitbutton = $_POST['submitbutton']`{:.language-php} ist nicht nur ziemlich überflüssig (kostet halt Rechenzeit), sondern es verschleiert dir auch die Herkunft der Werte. Denn es ist nicht irrelevant, ob der Inhalt einer Variablen von außen vom bösen User gekommen ist, oder tatsächlich intern aus vertrauenswürdigerer Quelle.  
      
    2\. Du hast keinerlei Escaping in dein Query eingebaut. Damit zerschießt dir der User dein SQL-Statement potentiell - außer es ist magic\_quotes\_gpc = on gesetzt. Diese Magic Quotes sind aber auch ein ekliges Feature, denn sie retten zwar deinen Query, aber stören bei jeder sonstigen Ausgabe von Variablen. magic\_quotes\_gpc können auch abgeschaltet sein - wenn dein Provider an der Einstellung was ändert, oder du den Provider wechselst, wäre dein Skript plötzlich ungeschützt.  
      
    3\. Deine Fehlerbehandlung ist ziemlich rauh. Immerhin ist sie vorhanden, aber "Bitte Admin informieren" ist nicht wirklich das, was man sich als Admin wünscht. Weil das die User nicht hinkriegen. PHP bietet etliche Methoden, Fehler zu loggen und so für den Admin zu konservieren.  
      
    
    > Würde die Prozedur dann so aussehen?  
    >   
    > ~~~sql
      
    
    > delimiter //  
    > drop procedure sql_insert;  
    >   
    > create procedure sql_insert ()  
    > begin  
    >  INSERT INTO DATENBANK.TABELLE (user, task, credate) values  
    > ('$User', '$task', CURRENT_DATE());  
    > end;  
    > 
    
    

    Wenn ja, wie rufe ich diese Prozedur dann in PHP auf?

    Zu deiner Prozedur kann ich nix sagen. Hab ich noch nicht ausprobiert, war in meinen Projekten noch nicht notwendig - eben aus oben genannten Gründen.

    Der Aufruf aber geschieht ganz simpel über einen MySQL-Query, der die Prozedur aufruft. Näheres dazu steht in der MySQL-Dokumentation. Da du dich offenbar in die Programmierung von SQL stürzen willst, bleibt dir ohnehin nichts anderes übrig, als dich mit der Doku auseinanderzusetzen.

    - Sven Rautenberg

    1. Die Frage ist, was du dir von sowas versprichst? So oder so würde in der Datenbank immer ein INSERT ausgeführt. Eine Prozedur würde dir eventuell ein wenig Komplexitätsarbeit abnehmen, wenn du in mehr als eine Tabelle schreiben musst. Und natürlich könnte man auch Validierung der übergebenen Daten dort reinschreiben.

      Das aber würde dann bedeuten, dass ein größerer Teil deiner
      Programmlogik nicht mehr in PHP programmiert ist, sondern in MySQL. Das »» ist nicht unbedingt so schön. Es ist wahrscheinlich, dass deine
      Anwendung niemals in einen Nutzungsbereich gerät, wo Performance eine
      Rolle spielt, aber trotzdem will ich anmerken, dass es aus dieser Sicht »» sehr hinderlich ist, wenn die Datenbank noch mehr tun muss, als nur die »» Daten schreiben zu müssen.

      Der Ansicht bin ich eigentlich auch, ich dümpel nur grad im Praktikum rum und mein "Chef", für den ich eine Anwendung zur Arbeitszeitenerfassung bauen soll, ist fest davon überzeugt, dass "alles" über SQL laufen soll.

      Dein oben gezeigter Code enthält allerdings etliche sofort
      offensichtliche Schwachstellen:

      1. Du hast keinerlei Escaping in dein Query eingebaut. Damit zerschießt »» dir der User dein SQL-Statement potentiell - außer es ist
        magic_quotes_gpc = on gesetzt. Diese Magic Quotes sind aber auch ein
        ekliges Feature, denn sie retten zwar deinen Query, aber stören bei
        jeder sonstigen Ausgabe von Variablen. magic_quotes_gpc können auch
        abgeschaltet sein - wenn dein Provider an der Einstellung was ändert,
        oder du den Provider wechselst, wäre dein Skript plötzlich ungeschützt.

      Keine Sorge, das steht noch auf meiner Liste :)

      1. Deine Fehlerbehandlung ist ziemlich rauh. Immerhin ist sie vorhanden, »» aber "Bitte Admin informieren" ist nicht wirklich das, was man sich als »» Admin wünscht. Weil das die User nicht hinkriegen. PHP bietet etliche
        Methoden, Fehler zu loggen und so für den Admin zu konservieren.

      Natürlich könnte man das noch wesentlich hübscher gestalten, war für mich fürs Erste aber eher nebensächlich, daher nur diese Knappe Angabe :)

      Würde die Prozedur dann so aussehen?

      delimiter //
      drop procedure sql_insert;

      create procedure sql_insert ()
      begin
      INSERT INTO DATENBANK.TABELLE (user, task, credate) values
      ('$User', '$task', CURRENT_DATE());
      end;

      
      > >   
      > > Wenn ja, wie rufe ich diese Prozedur dann in PHP auf?  
      >   
      > Zu deiner Prozedur kann ich nix sagen. Hab ich noch nicht ausprobiert, war in meinen Projekten noch nicht notwendig - eben aus oben genannten Gründen.  
      >   
      > Der Aufruf aber geschieht ganz simpel über einen MySQL-Query, der die  
      > Prozedur aufruft. Näheres dazu steht in der MySQL-Dokumentation. Da du »» dich offenbar in die Programmierung von SQL stürzen willst, bleibt dir »» ohnehin nichts anderes übrig, als dich mit der Doku auseinanderzusetzen.  
      
      Problem ist nur, dass ich gar nicht erst eine Prozedur erstellen kann.  
        
      ~~~sql
        
      DELIMITER //  
      DROP PROCEDURE sql_insert;  
        
      CREATE PROCEDURE sql_insert()  
      begin  
      SELECT * FROM TABELLE;  
      end;  
      
      

      Selbst diese einfach Prozedur lässt sich nicht erstellen und gibt mir als Fehler aus, dass ich die Syntax bei '; überprüfen soll...

      1. Moin!

        DELIMITER //
        DROP PROCEDURE sql_insert;

        CREATE PROCEDURE sql_insert()
        begin
        SELECT * FROM TABELLE;
        end;

        
        > Selbst diese einfach Prozedur lässt sich nicht erstellen und gibt mir als Fehler aus, dass ich die Syntax bei '; überprüfen soll...  
          
        Wenn dein PHP kein mysqli unterstützt, weil die Extension nicht installiert ist, dann kannst du dein Vorhaben vergessen.  
          
        Um einen Query an die Datenbank zu senden, in dem Semikolons enthalten sind, die Statements trennen, benötigst du zwingend die Funktionalität von mysqli\_multi\_query - das geht mit der mysql-Extension grundsätzlich NICHT.  
          
        PHPmyAdmin würde mysqli nutzen, wenn es verfügbar und konfiguriert ist, und wenn es in einer ausreichend aktuellen Version zur Verfügung steht.  
          
        Sieht so aus, als ob du den Server erstmal komplett umkonfigurieren müsstest, damit dein Chef zufrieden gestellt wird, um Dinge zu erledigen, die keinerlei Vorteil bringen.  
          
         - Sven Rautenberg
        
        1. Moin!

          DELIMITER //
          DROP PROCEDURE sql_insert;

          CREATE PROCEDURE sql_insert()
          begin
          SELECT * FROM TABELLE;
          end;

          
          > > Selbst diese einfach Prozedur lässt sich nicht erstellen und gibt mir als Fehler aus, dass ich die Syntax bei '; überprüfen soll...  
          >   
          > Wenn dein PHP kein mysqli unterstützt, weil die Extension nicht  
          > installiert ist, dann kannst du dein Vorhaben vergessen.  
          
          Doch doch, das ist alles vorhanden und eingerichtet. Und funktioniert bisher auch :)  
            
          
          > Sieht so aus, als ob du den Server erstmal komplett umkonfigurieren  
          > müsstest, damit dein Chef zufrieden gestellt wird, um Dinge zu erledigen, die keinerlei Vorteil bringen.  
          >   
          >  - Sven Rautenberg  
          
          Seltsamerweise funktioniert folge Erstellung einer Prozedur, obwohl es auf diversen anderen Seiten nicht so beschrieben wird und trotzdem funktioniert. (Siehe anderes Beispiel von mir)  
            
          ~~~sql
            
          DELIMITER //  
            
          DROP PROCEDURE IF EXISTS `sql_select_output`//  
          CREATE DEFINER=`root`@`localhost` PROCEDURE `sql_select_output`()  
          begin  
          insert into perprop.ppp_guest_tasks (user, task, credate) values ('User2', 'Test3', CURRENT_DATE());  
          end  
          
          
          1. Moin!

            Moin!

            DELIMITER //
            DROP PROCEDURE sql_insert;

            CREATE PROCEDURE sql_insert()
            begin
            SELECT * FROM TABELLE;
            end;

            
            > > > Selbst diese einfach Prozedur lässt sich nicht erstellen und gibt mir als Fehler aus, dass ich die Syntax bei '; überprüfen soll...  
            > >   
            > > Wenn dein PHP kein mysqli unterstützt, weil die Extension nicht  
            > > installiert ist, dann kannst du dein Vorhaben vergessen.  
            > Doch doch, das ist alles vorhanden und eingerichtet. Und funktioniert bisher auch :)  
              
            Dann fang doch einfach mal an, mysqli zu benutzen. :) Sonst stößt du immer wieder auf Probleme.  
              
            
            > Seltsamerweise funktioniert folge Erstellung einer Prozedur, obwohl es auf diversen anderen Seiten nicht so beschrieben wird und trotzdem funktioniert. (Siehe anderes Beispiel von mir)  
            >   
            > ~~~sql
              
            
            > DELIMITER //  
            >   
            > DROP PROCEDURE IF EXISTS `sql_select_output`//  
            > CREATE DEFINER=`root`@`localhost` PROCEDURE `sql_select_output`()  
            > begin  
            > insert into perprop.ppp_guest_tasks (user, task, credate) values ('User2', 'Test3', CURRENT_DATE());  
            > end  
            > 
            
            

            mysql_query teilt den als Parameter übergebenen String an jedem Semikolon auf und sendet dann nur den ersten Teil an MySQL ab. Heißt: Hier fehlt dir am Ende des Querys vermutlich der Befehl "end" - und wahrscheinlich korrigiert MySQL das stillschweigend (oder du ignorierst den Fehler), weil danach der Query sowieso zu Ende ist.

            Sprich: Weil du den DELIMITER geändert hast, greift der Standardmechanismus von mysql_query nicht mehr.

            Da du aber sowieso mysqli benötigst, erscheint es sehr unsinnig, sich eine Sonderlösung für mysql zu bauen.

            - Sven Rautenberg

            1. Dann fang doch einfach mal an, mysqli zu benutzen. :) Sonst stößt du immer wieder auf Probleme.

              Würde ich ja gerne, aber leider gibt es zu dem Thema noch nicht sonderlich viel hilfreiches zu finden. Wie ich mit MySQLI eine Datenbankverbindung aufbaut, wüsste ich jetzt zwar, aber nicht wie Prozeduren einbinde. Besonders im Fall von INSERT, da bekomm ich immer den Fehler: Unknown column '$variablenname' in 'field list'.

              SELECT funktioniert ohne Probleme, INSERT hingegen funktioniert gar nicht.

              1. Moin!

                Dann fang doch einfach mal an, mysqli zu benutzen. :) Sonst stößt du immer wieder auf Probleme.

                Würde ich ja gerne, aber leider gibt es zu dem Thema noch nicht sonderlich viel hilfreiches zu finden. Wie ich mit MySQLI eine Datenbankverbindung aufbaut, wüsste ich jetzt zwar, aber nicht wie Prozeduren einbinde. Besonders im Fall von INSERT, da bekomm ich immer den Fehler: Unknown column '$variablenname' in 'field list'.

                Tja, und da kann man dir ja jetzt echt prima helfen, weil alle den Code in ihrer Glaskugel sehen können.

                SELECT funktioniert ohne Probleme, INSERT hingegen funktioniert gar nicht.

                "Funzt nicht" ist keine Problembeschreibung.

                - Sven Rautenberg

                1. Moin!

                  Dann fang doch einfach mal an, mysqli zu benutzen. :) Sonst stößt du immer wieder auf Probleme.

                  Würde ich ja gerne, aber leider gibt es zu dem Thema noch nicht sonderlich viel hilfreiches zu finden. Wie ich mit MySQLI eine Datenbankverbindung aufbaut, wüsste ich jetzt zwar, aber nicht wie Prozeduren einbinde. Besonders im Fall von INSERT, da bekomm ich immer den Fehler: Unknown column '$variablenname' in 'field list'.

                  Tja, und da kann man dir ja jetzt echt prima helfen, weil alle den Code in ihrer Glaskugel sehen können.

                  Der PHP-Code zum Eintragen von Datensätzen:

                    
                  if (isset($submitbutton))  
                  {  
                  $conn = mysql_pconnect( "localhost", "****", "******", 65536 )  
                  or die( "Failed to connect to MySQL server" );  
                    
                  mysql_select_db( "perprop", $conn ) or die( "Could not select database" );  
                    
                  $result = mysql_query( "CALL ppp_guest_newtask()" )  
                  or die( mysql_error() );  
                  }  
                  
                  

                  MySQL-Prozedur sieht so aus:

                    
                  DELIMITER //  
                  DROP PROCEDURE IF EXISTS `ppp_guest_newtask`//  
                  CREATE DEFINER=`root`@`localhost` PROCEDURE `ppp_guest_newtask`()  
                  begin  
                  INSERT INTO ppp_guest_tasks (credate, task, project, customer, closed) VALUES(`credate`, `task`, `project`, `customer`, `closed`);  
                  end  
                    
                  
                  

                  Fehlercode:

                  Unknown column '$credate' in 'field list'

                  Variable ist vorhanden, kann also eigentlich nicht unbekannt sein.

                  1. Hi!

                    MySQL-Prozedur sieht so aus:

                    DELIMITER //

                    DROP PROCEDURE IF EXISTS ppp_guest_newtask//
                    CREATE DEFINER=root@localhost PROCEDURE ppp_guest_newtask()
                    begin
                    INSERT INTO ppp_guest_tasks (credate, task, project, customer, closed) VALUES(credate, task, project, customer, closed);
                    end

                      
                    Zeig bitte das, was im DBMS steht, nicht was du denkst, dass es drin stünde. Du kannst dafür den phpMyAdmin nehmen und bei der Datenbank die Export-Funktion verwenden. Struktur sollte angehakt sein, Daten nicht.  
                      
                    
                    > Fehlercode:  
                    > Unknown column '$credate' in 'field list'  
                    > Variable ist vorhanden, kann also eigentlich nicht unbekannt sein.  
                      
                    Die Fehlermeldung passt nicht zum gezeigten Code der SP. Und im anderen Code kommt weder explizit ein String mit dem Inhalt '$credate' vor, noch gibt es implizit eine Möglichkeit, einen solchen in Richtung DBMS zu befördern. Es geht nicht um eine PHP-Variable, die haben aus Sicht von MySQL keine Bedeutung. Es interessieren nur fertige Statements.  
                      
                      
                    Lo!
                    
                  2. Hi,

                    DELIMITER //
                    DROP PROCEDURE IF EXISTS ppp_guest_newtask//
                    CREATE DEFINER=root@localhost PROCEDURE ppp_guest_newtask()
                    begin
                    INSERT INTO ppp_guest_tasks (credate, task, project, customer, closed) VALUES(credate, task, project, customer, closed);
                    end

                    
                    >   
                    > Fehlercode:  
                    >   
                    > Unknown column '$credate' in 'field list'  
                    >   
                    > Variable ist vorhanden, kann also eigentlich nicht unbekannt sein.  
                      
                    Wer (ausser dir) redet hier von einer Variablen?  
                      
                    MySQL sagt dir, dass es den \*Spaltennamen\* nicht kennt.  
                    Und warum der in der Fehlermeldung mit einem führenden Dollarzeichen versehen ist, obwohl dies im Statement selber gar nicht vorkommt, müsstest du auch mal erklären.  
                      
                      
                    MfG ChrisB  
                      
                    
                    -- 
                    “Whoever best describes the problem is the person most likely to solve the problem.” [Dan Roam]
                    
                  3. Moin!

                    $result = mysql_query( "CALL ppp_guest_newtask()" )

                    In diesem Query stehen nirgendwo irgendwelche variablen Daten drin, die dem INSERT innerhalb der Prozedur dann zugewiesen werden könnten. Wie soll MySQL wissen, welche Daten du speichern willst? Deine Stored Procedure kann nicht auf PHP-Variablen zugreifen!

                    MySQL-Prozedur sieht so aus:

                    Da stehen keine PHP-Variablen drin. Aber fehlerhafte Angaben zu den VALUES.

                    INSERT INTO ppp_guest_tasks (credate, task, project, customer, closed) VALUES(credate, task, project, customer, closed);

                    Wenn das Daten sein sollen, sind die Anführungszeichen falsch. Korrekt wäre 'credate', 'task'... Aber nur rein technisch - sachlich wäre es unsinnig, immer dieselben konstanten Strings speichern zu wollen.

                    Also musst du dich mit Variablen in MySQL beschäftigen. Und mit Parameterübergabe in Stored Procedures.

                    Unknown column '$credate' in 'field list'

                    Variable ist vorhanden, kann also eigentlich nicht unbekannt sein.

                    Du hast nirgends einen Code $credate stehen. Weder in deinem PHP-Teil, noch in deinem MySQL-Teil. Also kann diese Meldung nicht von deinem Code kommen, den du hier gepostet hast. Sie dürfte so überhaupt nicht kommen, wenn du diesen Code benutzen würdest.

                    Das wiederum zeigt, dass du einen anderen Code nutzt, also du gepostest hast.

                    Abgesehen davon nutzt du immer noch mysql, nicht mysqli. Du hast behauptet, das wäre problemlos zu tauschen. Dann tu das auch, ansonsten funktioniert es nämlich garantiert nie.

                    - Sven Rautenberg

  2. Hi!

    Verstehe ich das jetzt richtig, dass ich mit MySQL, z.B. in PHPMyAdmin, eine Prozedur erstellen muss, die quasi den INSERT-Befehl enthält?

    Neben den anderen von Sven schon angesprochenen Punkten stelle auch ich noch einmal die Frage: Was versprichst du dir davon?

    Würde die Prozedur dann so aussehen?

    delimiter //
    drop procedure sql_insert;

    create procedure sql_insert ()
    begin
    INSERT INTO DATENBANK.TABELLE (user, task, credate) values
    ('$User', '$task', CURRENT_DATE());
    end;

    
    >   
    > Wenn ja, wie rufe ich diese Prozedur dann in PHP auf?  
      
    Eine Procedure ruft man mit CALL auf. Das steht aber in der Dokumentation zu Stored Procedures (oder allgemein: Stored Programs) dabei.  
      
    Der Punkt hier ist aber, dass du nun dein INSERT-Statement nicht mehr auf die bekannte Weise aus variablen Werten zurechtbauen kannst. Bisher war es so, dass MySQL ein fertiges Statement vorgesetzt bekam, fix und fertig zusammengebaut in PHP. Wenn eine SP verwendet werden soll, um variable Werte in eine Tabelle einzufügen, musst du Parameter an die SP übergeben, diese dort übernehmen und dann an das INSERT-Statement (und die anderen in der SP verwendeten) weiterleiten. Reinweg ein INSERT zu kapseln bringt erst einmal noch sehr wenig Nutzen. Sinnvoll ist es nur dann, wenn die SP (später) noch um diverses anderes ergänzt werden soll, das sich vom Client aus nicht mit einem einfachen INSERT erledigen lässt.  
      
      
    Lo!
    
    1. Der Punkt hier ist aber, dass du nun dein INSERT-Statement nicht mehr auf die bekannte Weise aus variablen Werten zurechtbauen kannst. Bisher war es so, dass MySQL ein fertiges Statement vorgesetzt bekam, fix und fertig zusammengebaut in PHP. Wenn eine SP verwendet werden soll, um variable Werte in eine Tabelle einzufügen, musst du Parameter an die SP übergeben, diese dort übernehmen und dann an das INSERT-Statement (und die anderen in der SP verwendeten) weiterleiten. Reinweg ein INSERT zu kapseln bringt erst einmal noch sehr wenig Nutzen. Sinnvoll ist es nur dann, wenn die SP (später) noch um diverses anderes ergänzt werden soll, das sich vom Client aus nicht mit einem einfachen INSERT erledigen lässt.

      Lo!

      Gilt das nur für INSERT? Kann ich zum Auslesen von Datenbank-Daten in PHP eine Prozedur verwenden oder gibts da auch Probleme?

      1. Hi!

        Der Punkt hier ist aber, dass du nun dein INSERT-Statement nicht mehr auf die bekannte Weise aus variablen Werten zurechtbauen kannst. Bisher war es so, dass MySQL ein fertiges Statement vorgesetzt bekam, fix und fertig zusammengebaut in PHP. Wenn eine SP verwendet werden soll, um variable Werte in eine Tabelle einzufügen, musst du Parameter an die SP übergeben, diese dort übernehmen und dann an das INSERT-Statement (und die anderen in der SP verwendeten) weiterleiten. Reinweg ein INSERT zu kapseln bringt erst einmal noch sehr wenig Nutzen. Sinnvoll ist es nur dann, wenn die SP (später) noch um diverses anderes ergänzt werden soll, das sich vom Client aus nicht mit einem einfachen INSERT erledigen lässt.

        Gilt das nur für INSERT? Kann ich zum Auslesen von Datenbank-Daten in PHP eine Prozedur verwenden oder gibts da auch Probleme?

        Lies doch erst einmal, was überhaupt mit einer SP möglich ist, und wie dort Daten rein und wieder raus kommen. Üblicherweise geben SELECTs, die man auf herkömmliche Weise anwendet eine Ergebnismenge zurück, die von der SP als _jeweils_eine_ Ergebnismenge zurückgegeben werden. Durch diese eventuell mehrfachen Ergebnismengen musst du dich einzeln durcharbeiten, wofür es spezielle Funktionen in der mysqli-Extension gibt. Ausgehend von mysqli_multi_query() findest du alles weitere dazu.

        Auch hier ist die Sinnfälligkeit des Einsatzes von SPs abhängig davon, was man noch alles mehr macht als nur ein einzelnes Statement abzusetzen.

        Lo!

  3. Hello,

    Stored Programs eignen sich immer dann besonders gut, wenn man

    • dem User den direkten Zugriff auf Tabellen nicht gestatten will,
        sondern nur streng formalisierte (vorgegebene) Zugriffe zulassen will
    • Die Zugriffe loggen will (z.B. in Behörden oder banken: Wer hat wann welche Daten angefordert?)
    • zusätzlich eine vertikale Rechtestruktur in die Datenbank einbauen will, bei der
        nicht jeder User mit jedem Datensatz alles darf
    • die Datenbank über unterschiedliche APIs/GUIs ansprechen will, also z.B. per HTTPS mit PHP,
        direkt im LAN per C++-Frontend, usw.

    Ich vermisse bei MySQLs Stored Programs und Triggers immer noch die gezielt erzeugbaren Exceptions. Solange es die nicht gibt, lassen sich Triggers und Stored Programs nur bedingt sauber einsetzen.

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
     ☻_
    /▌
    / \ Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    1. Hi!

      Stored Programs eignen sich immer dann besonders gut, wenn man

      • dem User den direkten Zugriff auf Tabellen nicht gestatten will,
          sondern nur streng formalisierte (vorgegebene) Zugriffe zulassen will
      • zusätzlich eine vertikale Rechtestruktur in die Datenbank einbauen will, bei der
          nicht jeder User mit jedem Datensatz alles darf

      Beide Punkte müssen dann aber auf einer höheren Ebene gesichert werden, denn zumindest MySQL reicht nicht allein das Zugriffrecht auf eine SP, es werden auch noch alle erforderlichen Zugriffsrechte für die darin angesprochenen Elemente benötigt.

      • die Datenbank über unterschiedliche APIs/GUIs ansprechen will, also z.B. per HTTPS mit PHP,
          direkt im LAN per C++-Frontend, usw.

      Wo ist da der direkte Zusammenhang zu Stored Procedures, und was spielt im Speziellen HTTPS für eine Rolle?

      Lo!

      1. Hello,

        Hi!

        Stored Programs eignen sich immer dann besonders gut, wenn man

        • dem User den direkten Zugriff auf Tabellen nicht gestatten will,
            sondern nur streng formalisierte (vorgegebene) Zugriffe zulassen will
        • zusätzlich eine vertikale Rechtestruktur in die Datenbank einbauen will, bei der
            nicht jeder User mit jedem Datensatz alles darf

        Beide Punkte müssen dann aber auf einer höheren Ebene gesichert werden, denn zumindest MySQL reicht nicht allein das Zugriffrecht auf eine SP, es werden auch noch alle erforderlichen Zugriffsrechte für die darin angesprochenen Elemente benötigt.

        Das habe ich anders ermittelt. Es ist möglich, einem User die Zugriffsrechte auf Tabellen zu verbieten und ihm nur die Benutzungsrechte an einer SP zu geben. Diese kann er dann über sein Interface aufrufen. In der SP kann festgelegt werden, dass diese mit den Rechten des Erstellers ausgeführt wird. Oder war das bei einem anderen DBMS?

        Viiinzeeenz :-))

        • die Datenbank über unterschiedliche APIs/GUIs ansprechen will, also z.B. per HTTPS mit PHP,
            direkt im LAN per C++-Frontend, usw.

        Wo ist da der direkte Zusammenhang zu Stored Procedures, und was spielt im Speziellen HTTPS für eine Rolle?

        Na, ist es denn nicht möglich per HTTPS ein PHP-Script aufzurufen, das dann die Datenbank anspricht? Hast Du vielleicht das 'z.B.' überlesen? Sicherlich wird es auch über andere Protokolle möglich sein, PHP-Scripte aufzurufen. Die wollte ich hier aber nicht gerne aufzählöen. Und HTTPS steht hier bei mir für ein relativ sicheres Protokoll, das man mit handelsüblichen Browsern nutzen kann.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Hi!

          Beide Punkte müssen dann aber auf einer höheren Ebene gesichert werden, denn zumindest MySQL reicht nicht allein das Zugriffrecht auf eine SP, es werden auch noch alle erforderlichen Zugriffsrechte für die darin angesprochenen Elemente benötigt.

          Das habe ich anders ermittelt. Es ist möglich, einem User die Zugriffsrechte auf Tabellen zu verbieten und ihm nur die Benutzungsrechte an einer SP zu geben. Diese kann er dann über sein Interface aufrufen. In der SP kann festgelegt werden, dass diese mit den Rechten des Erstellers ausgeführt wird.

          Der letzte Satz ist entscheidend. Per Default wird SQL SECURITY DEFINER gesetzt und da reicht tatsächlich das EXECUTE-Privileg. Stellt man das explizit auf SQL SEQURITY INVOKER braucht es auch noch alle notwendigen data-spezifischen Rechte (SELECT-, INSERT-, UPDATE- und/oder DELETE-Privileg). Also ziehe ich meine ursprüngliche Aussage zurück.

          • die Datenbank über unterschiedliche APIs/GUIs ansprechen will, also z.B. per HTTPS mit PHP,
              direkt im LAN per C++-Frontend, usw.
            Wo ist da der direkte Zusammenhang zu Stored Procedures, und was spielt im Speziellen HTTPS für eine Rolle?
            Na, ist es denn nicht möglich per HTTPS ein PHP-Script aufzurufen, das dann die Datenbank anspricht? Hast Du vielleicht das 'z.B.' überlesen?

          Sicherlich wird es auch über andere Protokolle möglich sein, PHP-Scripte aufzurufen. Die wollte ich hier aber nicht gerne aufzählöen. Und HTTPS steht hier bei mir für ein relativ sicheres Protokoll, das man mit handelsüblichen Browsern nutzen kann.

          Ja, aber mir ist nicht klar, was das besondere an HTTPS gegenüber allen anderen Protokollen oder einem protokoll-losen Aufruf von PHP von der Kommanzozeile ist. Du irritierst mich hier mit der expliziten Erwähnung von HTTPS, obwohl das überhaupt keine Rolle spielt. 'PHP' allein hätte jedenfalls nicht impliziert, dass es einen Unterschied zwischen HTTPS und anderen Aufrufvarianten geben könnte.

          Lo!

          1. Hello,

            Ja, aber mir ist nicht klar, was das besondere an HTTPS gegenüber allen anderen Protokollen oder einem protokoll-losen Aufruf von PHP von der Kommanzozeile ist. Du irritierst mich hier mit der expliziten Erwähnung von HTTPS, obwohl das überhaupt keine Rolle spielt. 'PHP' allein hätte jedenfalls nicht impliziert, dass es einen Unterschied zwischen HTTPS und anderen Aufrufvarianten geben könnte.

            Wir reden hier wohl aneinander vorbei.

            Wenn ich die Zugriffsbeschränkungen und -Historie der Geschäftslogik in der Datenbank zusammenfasse, dann kann ich eben über diverse unterschiedliche Wege auf die DB zugreifen, ohne dass die Daten gefährdet würden.

            Ob ich dann per C++-API über ein Frontend im LAN/WAN oder über eine Kombination aus HTTP/HTTPS und PERL/PHP/sonstigen zugreife, macht keinen Unterschied mehr. Ich muss die Geschäftslogik nur einmal im DBMS abbilden. Nur noch die Daten-Darstellung/-beitstellung ist dann über die unterschiedlichen Interfaces und ihre Helferlein durchzuführen. Das hat für die Dartenintegrität erhebliche Vorteile, ist aber entsprechend schwerer zu planen, bzw. MUSS gut geplant werden.

            Während PHP-Scripte ja häufig einfach sukzessive "entstehen", ist das bei Benutzung der zusätzlichen Datenbank-Kapselung durch Stored Programs nicht mehr so einfach "aus dem Bauch raus" möglich.

            Es gibt dann aber keinen Weg mehr vorbei an den Regeln.

            Liebe Grüße aus dem schönen Oberharz

            Tom vom Berg

            --
             ☻_
            /▌
            / \ Nur selber lernen macht schlau
            http://bergpost.annerschbarrich.de
            1. Hi!

              Ja, aber mir ist nicht klar, was das besondere an HTTPS gegenüber allen anderen Protokollen oder einem protokoll-losen Aufruf von PHP von der Kommanzozeile ist. Du irritierst mich hier mit der expliziten Erwähnung von HTTPS, obwohl das überhaupt keine Rolle spielt. 'PHP' allein hätte jedenfalls nicht impliziert, dass es einen Unterschied zwischen HTTPS und anderen Aufrufvarianten geben könnte.

              Wir reden hier wohl aneinander vorbei.

              Ja, es mir ging nicht darum, was man mit SPs gegenüber Einzel-Statements für Vorteile hat, sondern dass du explizit, auch wenn es aus deiner Sicht nur ein Beispiel war, "per HTTPS mit PHP" schriebst und nicht nur "mit PHP" oder noch genereller "mit jedem beliebigen Programm". Denn es ist aus Sicht des DBMS völlig belanglos, welche Ambitionen der Client hat, Daten abzufragen, oder welchen Weg der Aufruf ging. Deswegen ist es irritierend, wenn du da einen speziellen Weg erwähnst, den man noch dazu mit einigem Aufwand (SSL-Konfiguration) erstellen muss. Wenn du als Beispiel solch ein spezialisiertes nimmst, muss man denken, dass auch diese Spezialisierung im Gegensatz zu anderen eine Bedeutung hat.

              Eigentlich wolltest du nur zeigen, dass es egal ist, ob eine Webanwendung oder eine Desktopanwendung mit dem DBMS kommuniziert. Die Kapselung in SPs versteckt die DBMS-Logik und teilweise auch Geschäftslogik und bietet allen Beteiligten eine einheitliche vereinfachte Schnittstelle. Durch die spezialisierten Beispiele bringst du nur mehr Komplexität in die Erklärung rein, die nicht notwendig ist.

              Lo!

              1. Hello,

                Eigentlich wolltest du nur zeigen, dass es egal ist, ob eine Webanwendung oder eine Desktopanwendung mit dem DBMS kommuniziert. Die Kapselung in SPs versteckt die DBMS-Logik und teilweise auch Geschäftslogik und bietet allen Beteiligten eine einheitliche vereinfachte Schnittstelle. Durch die spezialisierten Beispiele bringst du nur mehr Komplexität in die Erklärung rein, die nicht notwendig ist.

                Jein.

                Ein wenig habe ich mir dabei schon gedacht. Man muss schließlich die Diskussion auch mal anstoßen. Und Du hast mir nun den Gefallen getan, diese auch zu beginnen. ;-)

                Wenn man eine Datenbank betreibt, in der man relevante, wenn auch nicht geheime, Daten verwaltet und diese über verschiedene Wege zugänglich macht, dann sollten sich diese Wege in ihrer Sicherheit schon ähneln. Eine Freigabe einer solchen Datenbank über HTTP und PHP, so wie das im Hobbybereich üblich ist, halte ich dann für bedenklich. Wie wir in letzter Zeit ja leider immer öfter feststellen müssen, werden Accounts für Domains gerne gehackt und die Daten missbraucht. Wenn sie nicht auch verändert werden dabei, merkt man das eventuell gar nicht.

                Wenn man also die Vorteile von Stored Programs und die dadurch zusätlich mögliche Kapselung konsequent nutzen will, dann muss man auch die Anmeldung des Users absichern und zwar so, dass sie nicht gefaked werden kann. Sonst kann man sich den erhöhten Aufwand eher sparen.

                Dass es theoretisch trotzdem noch besser ist, Geschäftslogik und Zugriffsrechte/-historie mit zu kapseln, soll diese Überlegung nicht in Frage stellen. Aber praktisch würde man den Aufwand nur treiben, wenn es bis zum Ende durchgängig für Sicherheitszuwachs sorgt.

                Liebe Grüße aus dem schönen Oberharz

                Tom vom Berg

                --
                 ☻_
                /▌
                / \ Nur selber lernen macht schlau
                http://bergpost.annerschbarrich.de