W3docs

flock()

Die Funktion flock() ist eine eingebaute PHP-Funktion für einfaches Dateisperren, die verhindert, dass mehrere Prozesse eine Datei gleichzeitig beschädigen.

Was ist die Funktion flock()?

Die Funktion flock() führt Dateisperrung in PHP durch. Eine Sperre ermöglicht es einem Prozess, anderen mitzuteilen: „Ich arbeite gerade mit dieser Datei — wartet euren Zug ab." Ohne sie können zwei gleichzeitig laufende Skripte ihre Schreibvorgänge verschränken und eine Datei beschädigen. Dies ist eine klassische Race Condition, und flock() ist das einfachste Werkzeug, das PHP zur Verfügung stellt, um sie zu verhindern.

Diese Seite erklärt, was die Funktion tut, welche Sperrtypen es gibt, ein vollständiges, lauffähiges Beispiel, häufige Fallstricke und wo sie sich unter PHPs anderen Dateifunktionen einordnet.

Ein Wort zu „beratender" Sperrung

Auf Unix-ähnlichen Systemen ist flock() beratend (advisory): Die Sperre wird nur von Prozessen respektiert, die ebenfalls flock() auf derselben Datei aufrufen. Ein Programm, das Sperren ignoriert, kann die Datei weiterhin frei lesen oder überschreiben. Sperrung schützt also nur, wenn alle Skripte, die auf die Datei zugreifen, kooperieren. Unter Windows ist die Sperrung obligatorisch (vom Betriebssystem erzwungen), sodass das Verhalten plattformübergreifend leicht abweicht — verlassen Sie sich in portablem Code nicht auf obligatorische Erzwingung.

Syntax

flock($stream, $operation, &$would_block = null): bool
ParameterBeschreibung
$streamEin Datei-Zeiger, der von fopen() zurückgegeben wird.
$operationEine der unten stehenden Sperrkonstanten, optional mit LOCK_NB per OR verknüpft.
$would_blockOptional. Wird auf 1 gesetzt, wenn die Sperre blockiert hätte (nur mit LOCK_NB sinnvoll). Wird als Referenz übergeben.

Die Funktion gibt bei Erfolg true oder bei Misserfolg false zurück.

Sperrtypen

KonstanteBedeutung
LOCK_SHGemeinsame Sperre (Leser). Viele Prozesse können gleichzeitig eine gemeinsame Sperre halten, aber keine exklusive Sperre in der Zwischenzeit. Verwenden Sie sie beim Lesen.
LOCK_EXExklusive Sperre (Schreiber). Nur ein Prozess kann sie halten; alle anderen — Leser und Schreiber — warten. Verwenden Sie sie beim Schreiben.
LOCK_UNGibt die aktuell gehaltene Sperre auf dem Stream frei.
LOCK_NBNicht-blockierender Modifikator. Verknüpfen Sie ihn per OR mit LOCK_SH oder LOCK_EX (z. B. `LOCK_EX

Standardmäßig blockiert flock(): Hält ein anderer Prozess eine exklusive Sperre, wartet Ihr Aufruf, bis die Sperre frei ist. Fügen Sie LOCK_NB hinzu, wenn Sie lieber sofort scheitern möchten.

Verwendung der Funktion flock()

Das Muster besteht immer aus denselben vier Schritten:

  1. Öffnen Sie die Datei mit fopen() in einem Modus, der zu Ihrem Vorhaben passt ('r+', 'c', 'a', …).
  2. Erwerben Sie die Sperre mit flock($file, LOCK_EX) (oder LOCK_SH zum Lesen).
  3. Lesen oder schreiben Sie in die Datei.
  4. Geben Sie die Sperre frei mit flock($file, LOCK_UN) und schließen Sie mit fclose().

Ein vollständiges, lauffähiges Beispiel

Dieses Skript öffnet eine Zählerdatei, sperrt sie exklusiv, erhöht die gespeicherte Zahl und schreibt sie zurück — die Art von Lesen-Ändern-Schreiben-Vorgang, der zwingend gesperrt werden muss, um unter gleichzeitigem Zugriff sicher zu sein:

<?php

$filename = 'counter.txt';

// 'c' opens for read/write, creating the file if missing,
// and does NOT truncate it (unlike 'w').
$file = fopen($filename, 'c+');

if ($file === false) {
    exit("Could not open file.\n");
}

if (flock($file, LOCK_EX)) {        // block until we hold the lock
    $current = (int) stream_get_contents($file);
    $current++;

    rewind($file);                  // back to the start
    ftruncate($file, 0);            // clear old contents
    fwrite($file, (string) $current);
    fflush($file);                  // push to disk before unlocking

    flock($file, LOCK_UN);          // release the lock
    echo "Counter is now: $current\n";
} else {
    echo "Could not acquire lock.\n";
}

fclose($file);

Dreimaliges Ausführen gibt Counter is now: 1, dann 2, dann 3 aus. Da das Lesen-Inkrementieren-Schreiben unter LOCK_EX stattfindet, können zwei Prozesse nie denselben Wert lesen und beide 2 schreiben.

Sofortiges Scheitern mit nicht-blockierender Sperre

Wenn Sie nicht warten möchten — etwa bei einem Cron-Job, der den Lauf überspringen soll, wenn ein vorheriger noch läuft — kombinieren Sie LOCK_EX mit LOCK_NB:

<?php

$file = fopen('job.lock', 'c');

if (flock($file, LOCK_EX | LOCK_NB)) {
    echo "Got the lock, doing work...\n";
    // ... long-running task ...
    flock($file, LOCK_UN);
} else {
    echo "Another instance is already running. Exiting.\n";
}

fclose($file);

Häufige Fallstricke

  • Sperren hängen am offenen Datei-Handle, nicht am Pfad. Zweimaliges Aufrufen von fopen() auf derselben Datei liefert zwei unabhängige Handles, und eine Sperre auf einem blockiert das andere nicht im selben Prozess.
  • Verwenden Sie 'c'/'c+', nicht 'w', beim Sperren. Der Modus 'w' kürzt die Datei in dem Moment, in dem Sie sie öffnen — bevor Sie die Sperre erworben haben — und untergräbt damit den Zweck. Kürzen Sie mit ftruncate() explizit, nachdem Sie die Sperre halten.
  • flock() funktioniert über NFS oder bestimmten vernetzten/FAT-Dateisystemen nicht zuverlässig. Für die serverübergreifende Koordination verwenden Sie stattdessen einen echten Sperrdienst (eine Datenbankzeilensperre, Redis usw.).
  • fclose() gibt alle verbleibenden Sperren frei, aber entsperren Sie explizit mit LOCK_UN, damit die Datei sofort wieder verfügbar ist, sobald Sie fertig sind.

Fazit

flock() ist PHPs eingebautes Werkzeug zur Koordination des gleichzeitigen Zugriffs auf eine Datei. Verwenden Sie LOCK_EX rund um Schreibvorgänge, LOCK_SH rund um Lesevorgänge und LOCK_NB, wenn Sie lieber scheitern als warten möchten. Beachten Sie, dass das Sperren unter Unix beratend ist — es schützt Sie nur, wenn alle Skripte, die auf die Datei zugreifen, mitmachen. Für übergeordnete Dateiarbeiten siehe fwrite(), fread() und file_put_contents().

Übungen

Übung
Was ist die Funktion von flock() in PHP?
Was ist die Funktion von flock() in PHP?
Was this page helpful?