KlausStein: TOCTTOU und ein paar Fragen zur Verhinderung

Hi,

ich muss leider in einigen Scripten mit Bezug auf die maximal vorhandene ID einer Tabelle arbeiten.

Deshalb locke ich die entsprechenden Tabellen vor der Arbeit und unlocke sie danach wieder.

Was passiert aber eigentlich, wenn bei gesperrten Tabellen der User im Scriptverlauf auf eine Fehlermeldung stößt, die nach Anzeige auch das Script stoppt.

Bleiben die Tabellen dann gelockt?

Sollte ich also in meine Fehlerfunktion ein unlock_tables einfügen? Aber unlockt das nicht dann auch ungewollt Tabellen, die von anderen Scripten gelockt wurden?

Wie geht man bei sowas vor?

Gruß, Klaus

Beispiel:

  
//-----------------------------------------------------------------------  
// Tabellen sperren  
//-----------------------------------------------------------------------  
  
lock_table("tabelle1");  
lock_table("tabelle2");  
  
...  
...  
...  
  
if (...) {  
error("Fehlermeldung1");  
}  
  
....  
....  
....  
  
  
//-----------------------------------------------------------------------  
// Tabellen entsperren  
//-----------------------------------------------------------------------  
  
unlock_table("tabelle1");  
unlock_table("tabelle2");  
  
  
function error($Meldung) {  
echo("$Meldung");  
exit;  
}  

  1. Ich glaube nicht dass der Unlock von selbst passiert wenn das Script fertig ist. Schau doch mal die Beschreibung dazu an. Tabellen sperren ist allgemein eine ziemlich tödliche Angelegenheit. Ich würd schauen dass du das umgehst wenn möglich.
    Denk auch daran dass dein Script vielleicht mal mit einem Fehler total unkontrolliert abbricht.

  2. Hello,

    Deshalb locke ich die entsprechenden Tabellen vor der Arbeit und unlocke sie danach wieder.

    Was passiert aber eigentlich, wenn bei gesperrten Tabellen der User im Scriptverlauf auf eine Fehlermeldung stößt, die nach Anzeige auch das Script stoppt.

    Angeblich werden auch Datenbankhandles (seit PHP 5.??) wieder sauber aufgelöst, wenn die Variable, die dieses speichert ihre Gültigkeit verliert.

    Bei Scriptabbruch (ohne dass PHP abstürzt) würde dies also geschehen. Theoretisch wäre damit die Funktion mysql_free_result() auch (nahezu) überflüssig.

    Mit Schließen der Datenbank-Cennection werden aber auf jeden Fall die Locks auf den table aufgehoben. Achte bitte auch darauf, dass Du keine einzelnen Tabellen unlocken kannst, sondern nur alle Locks gemeinsam aufgehoben werden.

    Seit MySQL 5.?? kann man sich aber oft mit einem Subselect das lästige Locken der Tabellen sparen. Dazu gab es neulich erst einen Thread hier, in dem ich das auch erst gelernt habe, dass es nun endlich funktioniert UND ZULÄSSIG IST.

    Such mal nach "subselect" ...

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

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

      Angeblich werden auch Datenbankhandles (seit PHP 5.??) wieder sauber aufgelöst, wenn die Variable, die dieses speichert ihre Gültigkeit verliert.

      Bei Scriptabbruch (ohne dass PHP abstürzt) würde dies also geschehen. Theoretisch wäre damit die Funktion mysql_free_result() auch (nahezu) überflüssig.

      Achso nochwas: Bei komplexeren DMS (datenverändernden Datenbankzugriffen) musst Du auf jeden Fall dafür sorgen, dass der angestoßene Prozess sauber zuende geführt wird, also bei einem Userabort also der User klappt noch bevor die Response (anfängt) einzutrudeln das Browserfnester zu.

      Dafür sind die Funktionen ignore_user_abort() und ihre Verwandten da.
      http://de3.php.net/manual/de/function.ignore-user-abort.php

      Und ich würde das Zurückgeben von Handles auf jeden Fall immer sauber ausprogrammieren, auch wenn sich PHP inzwischen angeblich selber darum kümmert ;-P

      Liebe Grüße aus dem schönen Oberharz

      Tom vom Berg

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

        Achso nochwas: Bei komplexeren DMS (datenverändernden Datenbankzugriffen) musst Du auf jeden Fall dafür sorgen, dass der angestoßene Prozess sauber zuende geführt wird, also bei einem Userabort also der User klappt noch bevor die Response (anfängt) einzutrudeln das Browserfnester zu.

        Dafür sind die Funktionen ignore_user_abort() und ihre Verwandten da.
        http://de3.php.net/manual/de/function.ignore-user-abort.php

        Danke für diesen Hinweis,

        ist es denn nicht sinnvoll, das einfach ins headerscript einzutragen, damit _immer_ alle Scripte sauber zuende geführt werden?

        Oder hat das irgendwelche gravierenden Nachteile?

        Grüße, KlausStein

        1. Hello,

          Achso nochwas: Bei komplexeren DMS (datenverändernden Datenbankzugriffen) musst Du auf jeden Fall dafür sorgen, dass der angestoßene Prozess sauber zuende geführt wird, also bei einem Userabort also der User klappt noch bevor die Response (anfängt) einzutrudeln das Browserfnester zu.

          Dafür sind die Funktionen ignore_user_abort() und ihre Verwandten da.
          http://de3.php.net/manual/de/function.ignore-user-abort.php

          Danke für diesen Hinweis,

          ist es denn nicht sinnvoll, das einfach ins headerscript einzutragen, damit _immer_ alle Scripte sauber zuende geführt werden?

          Oder hat das irgendwelche gravierenden Nachteile?

          Das würde ich nur bei DMS machen. Bei reinen Selects, also nicht verändernden Statements, ist es doch unnötig, noch aufwändig Ausgaben zu berechen, wenn der User sie nicht mehr sehen will. Überleg mal, was sonst mit der Anzahl von laufenden Prozessen passiert, wenn der User ein paarmal hintereinander seinen Aktualisieren-Button drückt am Browser.

          Standardeinstellung ist allerdings: Script wird abgebrochen, wenn der User abortet.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
           ☻_
          /▌
          / \ Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Das würde ich nur bei DMS machen. Bei reinen Selects, also nicht verändernden Statements, ist es doch unnötig, noch aufwändig Ausgaben zu berechen, wenn der User sie nicht mehr sehen will. Überleg mal, was sonst mit der Anzahl von laufenden Prozessen passiert, wenn der User ein paarmal hintereinander seinen Aktualisieren-Button drückt am Browser.

            Ok, das ist ein Argument.

            Dann also doch mühsam 'rausklamüsern :-(

            Danke für die Hilfe.

            Klaus

            1. Hello,

              Das würde ich nur bei DMS machen. Bei reinen Selects, also nicht verändernden Statements, ist es doch unnötig, noch aufwändig Ausgaben zu berechen, wenn der User sie nicht mehr sehen will. Überleg mal, was sonst mit der Anzahl von laufenden Prozessen passiert, wenn der User ein paarmal hintereinander seinen Aktualisieren-Button drückt am Browser.

              Ok, das ist ein Argument.

              Dann also doch mühsam 'rausklamüsern :-(

              Du kannst den aktuellen Zustand ja abfragen, ihn für die gekoppelten (zu koppelnden) Datenveränderungen auf "nicht abbrechen" einstellen und hinterher dann wieder auf den alten Zustand zurückstellen.

              Im Prinzip müsste das in der Schnittstelle zur Datenbank in der API geschehen, also in den Funktionen, die das Model ansprechen. Ins Model gehört das wohl eher nicht.

              Sollten mehrere manipuliernende Daten(bank)zugriffe stattfinden im Script, werden die ja bestimmt auch irgendwie wieder in einer Hüllfunktion stecken, sodass Du das dann dort vornehmen kannst.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

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

      Achte bitte auch darauf, dass Du keine einzelnen Tabellen unlocken kannst, sondern nur alle Locks gemeinsam aufgehoben werden.

      Gut zu wissen. Ich dachte nämlich ich könnte einzelne Locks aufheben.

      Seit MySQL 5.?? kann man sich aber oft mit einem Subselect das lästige Locken der Tabellen sparen. Dazu gab es neulich erst einen Thread hier, in dem ich das auch erst gelernt habe, dass es nun endlich funktioniert UND ZULÄSSIG IST.

      Such mal nach "subselect" ...

      DER war gut ;-)

      Aber das Thema interessiert mich wirklich.

      Schade, dass ich es bisher noch nicht finden konnte. Ich suche aber mal weiter.

      Gruß, Klaus

      1. Hello,

        Such mal nach "subselect" ...

        DER war gut ;-)

        Aber das Thema interessiert mich wirklich.
        Schade, dass ich es bisher noch nicht finden konnte. Ich suche aber mal weiter.

        Im Prinzip war es dieser Thread
        http://forum.de.selfhtml.org/archiv/2010/8/t199745/#m1344878

        Kommt jetzt darauf an, was Du benötigst.

        Eventuell hift Dir auch ein Trigger, der im Misserfolgsfall per absichtlich falschem Statement abgewürgt wird (falsche Spalte reicht). MySQL kennt mWn noch kein Throw_Userexeption.

        Ob Triggers allerdings inzwischen mit ihrem Mutterstatement atomar zusammengefasst sind, überschaue ich im Moment auch nicht. Kann sein, dass da das nächste Problem steckt.

        Liebe Grüße aus dem schönen Oberharz

        Tom vom Berg

        --
         ☻_
        /▌
        / \ Nur selber lernen macht schlau
        http://bergpost.annerschbarrich.de
        1. Im Prinzip war es dieser Thread
          http://forum.de.selfhtml.org/archiv/2010/8/t199745/#m1344878

          Hi Tom,

          dank fürs Mitsuchen! :-)

          Gruß, Klaus