MaximilianK: Benutzer aus htacces Datei löschen

Hallo liebe SELFHTML User,
ich sitze schon seit einiger Zeit an einem eigentlich garnicht so schwierigen Code zum Anlegen und Löschen von Usern in htaccess per PHP Oberfläche.

Die Oberfläche sieht so aus:

Der Admin soll einen Benutzernamen eingeben können (vorhandene Nutzer werden ja oben angezeigt - wenn auch noch nicht so schön) und PHP soll dann die htpasswd Datei mit file () in ein Array laden, dieses nach dem zu löschenden Namen durchsuchen und diesen mit dem ":" und Passwort löschen.

Bisher habe ich das so lösen wollen:

  
<?php  
  
$Benutzername =$_POST ["Benutzerloeschen"]; //Name aus der Maske  
  
// Liest htpasswd Datei in ein Array - liegt oberhalb des Document Root  
$htpasswd_a = file ('../../../htaccess/user/.htpasswd');  
  
//prüft, ob Benutzername in Datei  
if ( false !== ($index=array_search($Benutzername,$htpasswd_a)))  
{  
	unset ($htpasswd_a[$index]);  
	$fp = fopen('../../../htaccess/user/.htpasswd', 'w');  
	foreach($htpasswd_a as $values) fwrite($fp, $values."\n");  
	fclose($fp);  
  
} else  
{  
	echo "Benutzer nicht gefunden.";  
}  
?>  

Ich könnte mir gut vorstellen, dass array_search () nicht ganz passt, weil er mir immer sagt "Benutzer nicht gefunden.". Ich habe mir auch schon mal mit print_r ($htpasswd_a) das Array zeigen lassen. Das Einlesen funktioniert wunderbar. Ich bekomme der Benutzernamen:Passwort<br> abgezeigt.

Würde mich über Eure Hilfe sehr freuen.
Gruß
Max

  1. Ich könnte mir gut vorstellen, dass array_search () nicht ganz passt, weil er mir immer sagt "Benutzer nicht gefunden.".

    array_search will den kompletten String haben, also username:passwort, nicht nur den Usernamen..
    Ich würde in dem Fall der Arraywert am : splitten und dann nur den ersten Teil vergleichen. Am besten beim Einlesen gleich zwei Arrays anlegen, bzw. ein Array mit Usernamen als Key und Passwort als Wert.

  2. Lieber MaximilianK,

    vielleicht hilft Dir der relevante Teil in meiner Dateiverwaltung?

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  3. Vielen Dank für Eure Hilfe. Den Vorschlag von Multi und die Dateiverwaltung von Felix  werde ich gleich mal ausprobieren.

    Gruß
    Max

    1. Vielen Dank für Eure Hilfe. Den Vorschlag von Multi und die Dateiverwaltung von Felix  werde ich gleich mal ausprobieren.

      Gruß
      Max

      Edit: Hallo Felix, ich habe mir gerade mal deine Dateiverwaltung angesehen. Meinen Respekt, die ist ja super!

      1. Lieber MaximilianK,

        Edit: Hallo Felix, ich habe mir gerade mal deine Dateiverwaltung angesehen. Meinen Respekt, die ist ja super!

        freut mich, wenn sie Dir nützt. Sie ist nicht perfekt, aber man kann sie für viele Dinge benutzen, vor allem, wenn kein FTP zur Verfügung steht (deswegen ist sie überhaupt erst entstanden).

        Liebe Grüße,

        Felix Riesterer.

        --
        ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
  4. Moin!

    htpasswd-Generator - Eine Lösung für kleine Webs

    MFFG (Mit freundlich- friedfertigem Grinsen)

    fastix

    --
    Als Freiberufler bin ich immer auf der Suche nach Aufträgen: Schulungen, Seminare, Training, Development
  5. Nochmal vielen vielen Dank für Eure Hilfe. Ich habe mir auch nochmal einen Kopf gemacht - möchte ja ordentlich PHP lernen. :-)

    Es fehlt an der ein oder anderen Stelle noch ein Fehlerabfang, aber es funktioniert. Hat jemand was am Stil oder Performance auszusetzen? ;-) Bin über Kritik dankbar.

    <?php  
    $Benutzerloeschen =$_POST ["Benutzerloeschen"]; //zu löschender Name aus der Maske  
      
    $BenutzerPasswortArray = file ("../../../htaccess/user/.htpasswd"); //laden der .htpasswd in Array  
    $keys = count ($BenutzerPasswortArray); //Benutzer zählen  
      
    $fp=fopen ("../../../htaccess/user/.htpasswd","w"); //öffnen der .htpasswd zum schreiben  
      
    for ($i=0; $i < $keys; $i++) //solange Zahl < Anz. Benutzer  
    {  
    	$pass = substr($BenutzerPasswortArray[$i],  strpos($BenutzerPasswortArray[$i],':')); //":Passwort"  
    	$name = substr($BenutzerPasswortArray[$i],0,strpos($BenutzerPasswortArray[$i],':')); //"Benutzername"  
    	  
    	if ($name !== $Benutzerloeschen) //Namensvergleich  
    	{  
    		fwrite($fp,$name.$pass); //"Benutzername:Passwort" in .htpasswd  
    	} else  
    	{  
    		continue; //kein Schreiben in .htpasswd  
    	}  
    }  
      
    fclose ($fp); //.htpasswd schließen  
      
    ?>
    
    1. Hi!

      $Benutzerloeschen =$_POST ["Benutzerloeschen"]; //zu löschender Name aus der Maske

      Das reine Umkopieren in eine andre Variable ist und bleibt Unfug. Zumal du die neue Variable nur ein einziges Mal verwendest kann auch das Argument der Schreibvereinfachung nicht herhalten.

      $BenutzerPasswortArray = file ("../../../htaccess/user/.htpasswd"); //laden der .htpasswd in Array
      $keys = count ($BenutzerPasswortArray); //Benutzer zählen

      $fp=fopen ("../../../htaccess/user/.htpasswd","w"); //öffnen der .htpasswd zum schreiben

      An dieser Stelle hat der Request den Dateiinhalt gelöscht. Nicht weiter schlimm, er hat die Daten ja im Array. Jetzt kommt ein zweiter Request des Wegs und liest mit file() den Inhalt aus - steht nichts (mehr) drin. Der erste Request ist mittlerweile fertig und hat alles wieder brav zurückgeschrieben. Der zweite öffnet nun die Datei und verwirft den vom ersten Request geschriebenen Inhalt.

      for ($i=0; $i < $keys; $i++) //solange Zahl < Anz. Benutzer

      $keys ist 0, die Schleife wird nicht ausgeführt.

      fclose ($fp); //.htpasswd schließen

      Die leere Daten wird geschlossen. Und du fragst dich, wo deine Benutzer hin sind und warum dieser Fehler immer nur sehr spradisch auftritt und nicht wirklich nachvollziehbar ist. => Sperren von Dateien

      Lo!

      1. Danke für dein Feedback.

        • Die Variable aus $_POST habe ich korrigiert, ist mir garnicht aufgefallen, danke.

        $BenutzerPasswortArray = file ("../../../htaccess/user/.htpasswd"); //laden der .htpasswd in Array
        $keys = count ($BenutzerPasswortArray); //Benutzer zählen

        $fp=fopen ("../../../htaccess/user/.htpasswd","w"); //öffnen der .htpasswd zum schreiben

        An dieser Stelle hat der Request den Dateiinhalt gelöscht. Nicht weiter schlimm, er hat die Daten ja im Array. Jetzt kommt ein zweiter Request des Wegs und liest mit file() den Inhalt aus - steht nichts (mehr) drin. Der erste Request ist mittlerweile fertig und hat alles wieder brav zurückgeschrieben. Der zweite öffnet nun die Datei und verwirft den vom ersten Request geschriebenen Inhalt.

        for ($i=0; $i < $keys; $i++) //solange Zahl < Anz. Benutzer

        Das verstehe ich jetzt nicht ganz. file () läd die .htpasswd in ein Array (löscht meines Wissens nichts - oder?) und legt für jeden "Benutzernamen:Passwort" ein neues Feld an.
        Mit count gehe ich nun durch das Array und zähle die Schlüssel, um zu ermitteln wie oft ich durch die Schleife muss und Feld für Feld prüfen, ob der Feldinhalt der Eingabe entspricht.

        $keys ist 0, die Schleife wird nicht ausgeführt.

        Wenn ich mir $key ausgeben lasse stehen dort immer die Anzahl der vorhanden Schlüssel des $BenutzerPasswortArray drin.

        fclose ($fp); //.htpasswd schließen

        Die leere Daten wird geschlossen. Und du fragst dich, wo deine Benutzer hin sind und warum dieser Fehler immer nur sehr spradisch auftritt und nicht wirklich nachvollziehbar ist. => Sperren von Dateien

        Hmm, meine Datei ist aber nicht leer. Sie beinhaltet nun die Benutzer (kommend aus $BenutzerPasswortArray), die ich haben möchte, also ohne den zu löschenden Benutzer aus $_POST.

        1. Mahlzeit MaximilianK,

          $fp=fopen ("../../../htaccess/user/.htpasswd","w"); //öffnen der .htpasswd zum schreiben

          Das verstehe ich jetzt nicht ganz. file () läd die .htpasswd in ein Array (löscht meines Wissens nichts - oder?)

          Das nicht - aber fopen('foobar', 'w') löscht (effektiv) den Inhalt der Datei. Und wenn jetzt genau kurz nach diesem Moment ein anderer Benutzer dieses Skript aufruft? Richtig: dessen "Version" versucht mittels file() den Inhalt einzulesen und findet ... genau nix.

          Eine klassische Race Condition ... lies und lerne.

          Mit count gehe ich nun durch das Array und zähle die Schlüssel, um zu ermitteln wie oft ich durch die Schleife muss und Feld für Feld prüfen, ob der Feldinhalt der Eingabe entspricht.

          Ja, wenn *EIN* Benutzer dieses Skript *EINMAL* zur gleichen Zeit startet.

          Hmm, meine Datei ist aber nicht leer. Sie beinhaltet nun die Benutzer (kommend aus $BenutzerPasswortArray), die ich haben möchte, also ohne den zu löschenden Benutzer aus $_POST.

          Ja, wenn *EIN* Benutzer dieses Skript *EINMAL* zur gleichen Zeit startet.

          Merke: Web-Anwendungen sind prinzipbedingt Mehrbenutzeranwendungen (außer, dieses Verhalten wird explizit verhindert) - das bedeutet, Du musst genau die Probleme, die sich bei gleichzeitigem lesenden und schreibenden Zugriff auf die gleichen Daten ergeben, behandeln.

          MfG,
          EKKi

          --
          sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
          1. Vielen Dank für deine Hilfe. Daran habe ich nicht gedacht.

            Gruß
            Max

        2. Hi!

          Das verstehe ich jetzt nicht ganz.

          Dein Verständnis vom Ablauf ist soweit in Ordnung. Aber nur, wenn du ihn alleinstehend betrachtest. In Wirklichkeit hast du ein Mehrnutzer-System vorliegen, bei dem viele Prozesse parallel ablaufen können. Und wenn der eine Prozess gerade Daten lesen will, die ein anderer vorübergehend gelöscht hat, findet der eine nichts mehr. Deswegen musst du verhindern, dass, während der andere an den Daten arbeitet, weitere Prozesse darauf zugreifen und diese solange aussperren, bis der andere fertig ist, damit sie mit dessen Ergebnis und nicht irgendeinem Zwischenschritt weiterarbeiten.

          Lo!

          1. Ahhhhhh, *Licht aufgeh* alles klar :-)

            Danke für den Link. Ich werde mich gleich daran setzen.