Navigation
 Startseite
 Fachbücher
 Anzeigenmarkt
 Forum
 Webmaster News
 Script Newsletter
 Push Meldungen
 Kontakt
 Script Installation
 Php
 Php Tutorials
 Lernpfade
 Webhoster Vergleich
 Impressum

Community-Bereich
 kostenlos Registrieren
 Anmelden
 Benutzerliste

Script Datenbank
 Script Archiv
 Script Top 20
 Screenshots
 Testberichte

Suche
 

Unsere Php Scripts
 Counter Script
 Umfrage Script
 Bilder Upload Script
 Terminverwaltung
 Simple PHP Forum
 RSS Grabber

Tools und Generatoren
 .htpasswd Generator
 md5 Generator
 base64 Generator
 Markdown to HTML
 Colorpicker
 Unix timestamp Tool
 Unit Test Generator
 TLD Liste
 Webkatalog‑Verzeichnis

Artfiles.de
Bietet Serviceorientierte...
https://www.Artfiles.de
Hosterplus.de
Bekommen Sie Speicherplatz (Webspace), Domains...
https://www.Hosterplus.de
 
 
 

PHP chgrp() Function: Gruppe setzen, chown und chmod

Sie befinden sich: Home > Php Tutorial > PHP chgrp() Function: Grupp...

PHP chgrp() Function: Gruppe setzen, chown und chmod
Veröffentlicht am:
08.10.2026
Hits / Besucher:
7
Sprache:
  Deutsch
Tutorial Art:
eigenes
Eingetragen von:
Merkliste:
 
Beschreibung

Der Webserver legt eine Datei im gemeinsamen Verzeichnis ab, und das nächtliche Wartungsskript kommt nicht heran. Beide Systembenutzer arbeiten auf demselben Pfad, trotzdem steht im Protokoll ein Zugriffsfehler. PHP chgrp() löst genau diesen Fall, weil es nicht am Recht dreht, sondern am Adressaten des Rechts. Wie Rechte gesetzt werden, steht im Tutorial zu chmod, und ob ein gesetztes Recht am Ende greift, klärt die Prüfseite mit is_executable(). Hier geht es um die zweite Hälfte derselben Regel: für wen ein gesetztes Recht überhaupt gilt.

Illustration zum Tutorial: PHP chgrp() Function: Gruppe setzen, chown und chmod

Eine Datei trägt zwei Etiketten: den Eigentümer auf der einen Seite, die Gruppe auf der anderen. Das zweite Etikett ist das, um das es hier geht.

PHP chgrp(), chown() und chmod(): was sich jeweils ändert

Jede Datei unter Linux und macOS hängt an zwei Angaben, die gern verwechselt werden. Die Rechtebits sagen, was erlaubt ist: lesen, schreiben, starten. Eigentümer und Gruppe sagen, für wen das jeweils gilt. Ein Recht ohne passenden Adressaten ist wirkungslos, und genau an dieser Stelle setzt der Aufruf an. Er verschiebt die Datei in eine andere Gruppe und lässt die Rechtebits unangetastet.

Daraus folgt eine Empfehlung, die dem üblichen Reflex widerspricht. Wer bei einem Zugriffsproblem zu chmod 0777 greift, öffnet die Datei für jeden Prozess auf der Maschine, auch für den fremden Kundenaccount nebenan. Eine gemeinsame Gruppe zusammen mit chmod 0770 öffnet sie für genau zwei Systembenutzer. chgrp() ist deshalb oft das präzisere Mittel und nicht nur das seltenere.

Funktion Ändert Typische Frage dahinter
chmod() die Rechtebits, also Lesen, Schreiben und Starten je Klasse Was ist erlaubt?
chown() den Eigentümer, also den einen zuständigen Systembenutzer Wem gehört die Datei?
chgrp() die Gruppe, also den Kreis der mitlesenden Benutzer Wer darf noch dazu?

Syntax und Parameter: $filename, $group und der Rückgabewert

Zwei Parameter, ein Wahrheitswert als Ergebnis. Die englische Fassung mitsamt der beiden Nachbarfunktionen sieht so aus:

chgrp(string $filename, string|int $group): bool


/* filename - path to the file to change
group - group name or numeric group id
return - true on success, false on failure

Attempts to change the group of the file
filename to group. Only the superuser may
change the group arbitrarily; other users
may change the group of a file to any group
of which that user is a member.

Related calls used in this tutorial:
chown(string $filename,
string|int $user): bool
filegroup(string $filename): int|false */

Der zweite Parameter steht ausdrücklich als string|int da: PHP chgrp() nimmt Gruppennamen und Gruppen-ID gleichermaßen entgegen. Der Rückgabetyp ist schlicht bool, einen dritten Zustand für „teilweise gelungen“ gibt es nicht. Das Gegenstück filegroup() liefert int|false, weil es eine Nummer zurückgibt und keine Zusage.

Gruppenname oder Gruppen-ID

Beide Formen sind erlaubt und im Ergebnis nicht zu unterscheiden. Der Name ist lesbar, aber nicht überall gleich: Auf Debian heißt die Webservergruppe www-data, auf Red Hat dagegen apache. Die Nummer ist innerhalb einer Maschine eindeutig, zwischen zwei Maschinen aber keineswegs dieselbe.

<?php

$pfad = '/var/www/app/cache/liste.json';

var_dump(chgrp($pfad, 'www-data'));
/* bool(true) */

clearstatcache(true, $pfad);
var_dump(filegroup($pfad));
/* int(33) */

var_dump(chgrp($pfad, 33));
/* bool(true), dieselbe Wirkung */

Für Skripte, die auf fremden Servern landen, gehört der Name in die Konfiguration und die Auflösung ins Programm. Zuständig sind posix_getgrnam() und posix_getgrgid() aus der POSIX-Erweiterung. Garantiert ist die nicht: Sie kann beim Übersetzen abgeschaltet oder per disable_functions gesperrt sein, und im Windows-Build von PHP 8.4.8 fehlt sie gemessen vollständig. Ein function_exists() vor dem Auflösen kostet eine Zeile.

<?php

function gruppenNummer(string $name): ?int
{
if (!function_exists('posix_getgrnam')) {
return null;
}
$eintrag = posix_getgrnam($name);

return is_array($eintrag)
? $eintrag['gid']
: null;
}

var_dump(gruppenNummer('www-data'));
/* int(33) */

var_dump(gruppenNummer('gibtsnicht'));
/* NULL */

Wer die Gruppe überhaupt setzen darf

In vielen Quellen steht, nur der Systemverwalter dürfe die Gruppe setzen. Das ist die halbe Wahrheit. Er darf jede Datei in jede Gruppe stellen, richtig. Nach der dokumentierten POSIX-Regel darf aber auch ein gewöhnlicher Benutzer wechseln, sofern er die Datei besitzt und der Zielgruppe selbst angehört. Darauf beruht der häufigste Praxisfall: Ausrollbenutzer und Webserverbenutzer kommen in eine gemeinsame Gruppe, und danach reicht ein PHP chgrp() ohne erhöhte Rechte.

Was dagegen nicht hilft, ist ein Schreibrecht an der Datei. Der folgende Lauf fand im Container statt, als Benutzer www-data mit der Nummer 33, auf einer Datei, die root gehört und mit Modus 0666 für jeden beschreibbar ist:

<?php

var_dump(is_writable($pfad));
/* bool(true) */

var_dump(chgrp($pfad, 'www-data'));
/* Warning: chgrp():
Operation not permitted
bool(false) */

Das Schreibrecht an einer Datei und das Recht, ihre Gruppe zu ändern, sind zwei verschiedene Dinge. Wer vorher is_writable() abfragt und daraus schließt, PHP chgrp() werde schon klappen, liegt falsch. Die Datei ließ sich in diesem Lauf beschreiben, ihre Gruppenzugehörigkeit aber nicht antasten.

Nach dem Ausrollen: Besitz und Gruppe geraderücken

Der Entscheidungsweg vor einem Gruppenwechsel lässt sich in ein Bild bringen. Er beantwortet drei Fragen nacheinander, und jede davon kann den Aufruf schon vorher erledigen.

flowchart TD
    A[Gruppe setzen] --> B{eigene Datei?}
    B -->|nein| C[nur Systemverwalter]
    B -->|ja| D{in Zielgruppe?}
    D -->|nein| E[Aufruf schlägt fehl]
    D -->|ja| F[chgrp aufrufen]
    F --> G{Rückgabe wahr?}
    G -->|nein| H[Grund protokollieren]
    G -->|ja| I[filegroup prüfen]

Im Ausrollskript stehen chown() und PHP chgrp() meist direkt nebeneinander, weil nach dem Entpacken eines Archivs beide Angaben falsch sind. Wichtig ist die Sammelmeldung: Ein Abbruch beim ersten Pfad hinterlässt einen halb umgestellten Baum, und der ist schwerer zu reparieren als eine Fehlerliste am Ende. Wo PHP chgrp() im gesamten Ausrollvorgang steht, zeigt das Tutorial zu den Deployment-Strategien.

<?php

$gruppe = 'www-data';
$fehler = [];

foreach ($pfade as $pfad) {
if (!chown($pfad, 'deploy')) {
$fehler[] = "$pfad: Besitzer";
}
if (!chgrp($pfad, $gruppe)) {
$fehler[] = "$pfad: Gruppe";
}
}

if ($fehler !== []) {
fwrite(STDERR, implode("\n", $fehler));
exit(1);
}

Einen ganzen Verzeichnisbaum umstellen: rekursiv geht es nicht

Der Schalter -R vom gleichnamigen Kommandozeilenwerkzeug hat in PHP keine Entsprechung. PHP chgrp() bearbeitet genau einen Pfad. Wer einen Verzeichnisbaum umstellen will, läuft ihn selbst ab und ruft je Eintrag auf. Zwei Zähler sagen am Ende, wie viele Einträge wirklich umgestellt wurden.

<?php

$basis = '/var/www/app';
$gruppe = 'www-data';
$ok = 0;
$fehl = 0;

$baum = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$basis,
FilesystemIterator::SKIP_DOTS
),
RecursiveIteratorIterator::SELF_FIRST
);

foreach ($baum as $eintrag) {
$p = $eintrag->getPathname();
if (chgrp($p, $gruppe)) {
$ok++;
} else {
$fehl++;
}
}

printf("%d gesetzt, %d offen\n", $ok, $fehl);

SELF_FIRST ist hier kein Detail. Damit erscheinen Verzeichnisse vor ihrem Inhalt, und der Durchlauf bearbeitet nie ein Verzeichnis, dessen Einträge schon durch sind.

Nachlesen mit filegroup() und fileowner()

Beide Funktionen liefern eine Zahl, keinen Namen. Im Protokoll steht dann 33 statt www-data, und niemand erinnert sich zwei Wochen später, wofür die 33 stand. Die Auflösung gehört deshalb in die Berichtszeile hinein: posix_getgrgid() für die Gruppe, posix_getpwuid() für den Eigentümer. So zeigt die Protokollzeile nach jedem Lauf, ob PHP chgrp() wirklich durchgekommen ist.

<?php

function bericht(string $pfad, string $soll): string
{
clearstatcache(true, $pfad);
$gid = filegroup($pfad);
$uid = fileowner($pfad);
if ($gid === false || $uid === false) {
return "$pfad: nicht lesbar";
}

$name = (string) $gid;
if (function_exists('posix_getgrgid')) {
$e = posix_getgrgid($gid);
if (is_array($e)) {
$name = $e['name'];
}
}

$besitzer = (string) $uid;
if (function_exists('posix_getpwuid')) {
$e = posix_getpwuid($uid);
if (is_array($e)) {
$besitzer = $e['name'];
}
}

$stand = $name === $soll ? 'ok' : 'abweichend';

return "$pfad besitzer=$besitzer"
. " gruppe=$name $stand";
}

echo bericht('/var/www/app/cache', 'www-data');
/* /var/www/app/cache besitzer=deploy
gruppe=www-data ok */

Das clearstatcache(true, $pfad) ganz oben hat einen Grund: filegroup() gehört zur stat-Familie und wird zwischengespeichert. Eine Messung im Container zeigt, dass PHP diesen Zwischenspeicher für genau einen Pfad hält. Ohne weiteren Dateizugriff blieb der alte Wert 33 stehen, obwohl ein Fremdprozess die Gruppe längst auf 0 gesetzt hatte. Lag ein stat auf einen anderen Pfad dazwischen, kam sofort die 0. Deshalb fällt der Zwischenspeicher nach einem Gruppenwechsel selten auf, und deshalb sollte man sich darauf nicht verlassen. Wie er arbeitet, steht im Tutorial zu fstat() und dem Stat-Cache.

Das setgid-Bit statt des wiederholten Aufrufs

Ein chgrp() nach jedem Schreibvorgang ist eine Einladung zum Vergessen. Eine einzige Stelle, an der die Zeile fehlt, und das Problem ist zurück. Das setgid-Bit dreht die Sache um: Trägt ein Verzeichnis dieses Bit, erben alle darin neu angelegten Dateien und Unterverzeichnisse dessen Gruppe. Gesetzt wird es über chmod() mit vorangestellter Ziffer 2, was die bekannte Oktalschreibweise um eine Stelle erweitert. Welche Rechte ein neu angelegtes Verzeichnis von sich aus mitbekommt, regelt die umask, nachzulesen im Tutorial zu mkdir() und umask.

<?php

$v = '/var/www/gemeinsam';

chgrp($v, 'www-data');
chmod($v, 02775);

clearstatcache(true, $v);
printf("%o\n", fileperms($v) & 07777);
/* 2775 */

file_put_contents($v . '/neu.txt', 'x');
clearstatcache();
var_dump(filegroup($v . '/neu.txt'));
/* int(33), ohne weiteren Aufruf */

Der Lauf oben stammt aus dem Container: Das Verzeichnis steht auf Modus 2775, die anschließend angelegte Datei trägt Gruppe 33. Erledigt ist die Sache damit trotzdem nicht. Das Bit wirkt nur nach vorne. Der Bestand, der vor dem Setzen schon dort lag, bleibt in seiner alten Gruppe.

Wo der Aufruf nichts bewirkt: gemeinsames Hosting und Windows

Auf gemeinsamem Webhosting laufen die Kundenprozesse unter getrennten Systembenutzern, und niemand darf Dateien in fremde Gruppen schieben. Ein falsches Ergebnis ist dort kein Defekt, sondern die Absicht der Plattform. Wer hier Zugriff regeln muss, arbeitet mit den Rechtebits.

Eine zweite Grenze nennt das Handbuch ausdrücklich: PHP chgrp() arbeitet nur auf Pfaden, die im Dateisystem des Servers liegen. Ein Pfad hinter einem Stream-Wrapper, also etwa eine Adresse mit http:// oder ftp://, ist für die Funktion nicht erreichbar. Gemessen im Container kommt dort false und die Warnung chgrp(): Cannot call chgrp() for a non-standard stream. Ein eingehängtes Netzlaufwerk wiederum richtet sich nach den Regeln des einhängenden Systems und nicht nach denen von PHP.

Unter Windows ist die Lage unangenehmer: PHP chgrp() schlägt nicht laut fehl, es schlägt still fehl. Gemessen unter PHP 8.4.8 mit error_reporting(E_ALL) und ohne Unterdrückungsoperator: kein Wort auf dem Bildschirm, kein Eintrag in error_get_last(), nur ein false.

Gemessen Linux-Container Windows 8.4.8
Aufruf gelingt ja, bool(true) nie, immer bool(false)
Meldung bei Fehlschlag Warnung mit Grund im Klartext keine, auch nicht in error_get_last()
filegroup() die echte Gruppen-ID, etwa int(33) konstant int(0)
POSIX-Funktionen vorhanden, sofern nicht gesperrt fehlen ganz, ebenso lchgrp()

Wer plattformübergreifend liefert, lässt den Aufruf unter Windows deshalb bewusst aus, statt ihn ins Leere laufen zu lassen. Eine Verzweigung über PHP_OS_FAMILY macht das im Code sichtbar, und die Meldung sagt dem nächsten Leser, dass hier nichts vergessen wurde.

<?php

if (PHP_OS_FAMILY === 'Windows') {
echo "Gruppen gibt es hier nicht\n";
return;
}

if (!chgrp($pfad, 'www-data')) {
throw new RuntimeException("Gruppe: $pfad");
}

Fehlerbehandlung: was gemeldet wird und was nicht

Der Rückgabewert ist die einzige Rückmeldung, auf die in jeder Umgebung Verlass ist. Unter Linux kommt eine Warnung dazu, und die ist nützlich, weil sie den Grund nennt. Zwei davon sind im Container wörtlich festgehalten und wollen unterschiedlich behandelt werden: chgrp(): Unable to find gid for gibtsnicht zeigt auf einen Tippfehler in der Konfiguration, chgrp(): No such file or directory auf einen Pfad, der nicht existiert. Eine dritte Meldung, chgrp(): Operation not permitted, bedeutet dagegen: Der Pfad stimmt, die Gruppe stimmt, nur die Rechte des laufenden Benutzers reichen nicht.

Wer die Warnung nicht im Ausgabestrom haben will, fängt sie mit einem eigenen Fehlerbehandler ab. Der Unterdrückungsoperator wäre hier die schlechtere Wahl, weil er den Text vernichtet, statt ihn umzuleiten.

<?php

set_error_handler(
static function (int $n, string $text): bool {
error_log('chgrp: ' . $text);
return true;
},
E_WARNING
);

$ok = chgrp('/var/www/app/log', 'www-data');

restore_error_handler();

if ($ok === false) {
throw new RuntimeException('Gruppe offen');
}

Im laufenden Betrieb gehört hinter jeden Aufruf eine Auswertung des Rückgabewerts, auch dort, wo sie den Code um zwei Zeilen verlängert.

Fazit

PHP chgrp() beantwortet eine schmale Frage: Zu welchem Kreis von Systembenutzern gehört diese Datei? Die Rechtebits bleiben dabei unberührt, und genau diese Arbeitsteilung macht den Aufruf nützlich. Eine gemeinsame Gruppe mit eng gesetzten Rechten löst das Problem, für das sonst chmod 0777 herhalten muss.

Schreibrecht und Gruppenrecht sind getrennt, gemessen an einer Datei mit Modus 0666, die sich beschreiben, aber nicht umgruppieren ließ. Rekursiv arbeitet die Funktion nicht, den Verzeichnisbaum läuft man selbst ab, und das setgid-Bit erspart alle künftigen Aufrufe im selben Verzeichnis. Unter Windows liefert PHP chgrp() stumm false, weshalb eine Verzweigung über PHP_OS_FAMILY dort ehrlicher ist als ein Aufruf, der nichts tut.

 

Tags:

 

 

Kommentare (0)

Noch keine Kommentare. Sei der Erste!

Melde dich an, um einen Kommentar zu schreiben.
Bücherregal mit drei Büchern: 'PHP 4 - Grundlagen und Profiwissen' von Hanser Verlag, 'Webdesign in a Nutshell' von O'Reilly Verlag, und 'Webgestaltung' von Galileo Computing.