str_replace in array

Haruzept

Mitglied
Hallo Zusammen,

ich bin noch nicht sehr lang mit PHP zugange.

Ich möchte gerne eine Datei einlesen.
In dieser Datei gibt es mehrere Zeilen.

Code:
[account]
user = test
pwd = test159
group = 1,2

user = blub
pwd = blub123
group = 1,2

usw....

Nun möchte ich wie bereits geschrieben, diese Datei einlesen. Am einfachsten und besten würde ich dies meiner Meinung nach mit einem Array sprich
PHP:
file('bla.txt');
machen.

Nach dem ich die Datei eingelesen habe, soll z.B. bei user test die Gruppe 1,2 auf 1,3 geändert werden. Dies soll natürlich nur bei einem bestimmten User und somit auch nur in einer bestimmten Zeile passieren.

Mein Problem ist nun, ich weiß nicht, wie die Datei als Array eingelesen und eine bestimmte Zeile des arrays verändert werden kann. Dies muss selbstverständlich auch alles zurück in die Datei geschrieben werden. Da ist auch das eigentliche Problem.

Wenn ich etwas zurück in eine Datei schreiben will, muss ich dies mit fwrite und fclose tun.
Dies setzt aber vorraus, dass ich fopen benutze um die Datei zu öffnen.

Bei php Manual bin ich mehr oder weniger auf dies gestoßen.

PHP:
<?php
$file = 'people.txt';
// Open the file to get existing content
$current = file_get_contents($file);
// Append a new person to the file
$current .= "John Smith\n";
// Write the contents back to the file
file_put_contents($file, $current);
?>

doch leider funktioniert das nicht so ganz.

Mein code:

PHP:
$datei1 = file('bla.txt');
$pz = "7";

$current = file_get_contents($datei1);
$current[$pz] = str_replace('2', '3', $current[$pz]);

file_put_contents($datei1, $current[$pz]);

Da ich bereits seit gut 2 Tagen an diesem Problem sitze und einfach nicht mehr weiter weiß, eine große Bitte an euch. Kann mir bitte jemand bei diesem script bzw. Problem helfen?

Ich wäre euch mehr als dankbar, wenn ihr mir diesen kleinen code bauen könntet.


Viele Grüße

Haruzept
 
Du vermischst hier [phpf]file[/phpf] und [phpf]file_get_contents[/phpf].

[phpf]file[/phpf] gibt die alle Zeilen einer Datei als Array zurück.
[phpf]file_get_contents[/phpf] gibt den kompletten Inhalt der Datei als String zurück (d.h. Zeilen werden entweder per LF, CR oder CR LF begrenzt).

Den Code, den du im Manual gefunden hast, sollte eigentlich funktionieren!

Nach dem ich die Datei eingelesen habe, soll z.B. bei user test die Gruppe 1,2 auf 1,3 geändert werden.
Du müsstest entscheiden anhand welcher Kriterien man diese Zeile finden kann.

Am einfachsten ist folgendes:
PHP:
<?php 
$file = 'people.txt'; 

$current = file_get_contents($file); 

$current = str_replace('group = 1,2', 'group = 1,3', $current);

file_put_contents($file, $current); 
?>

Es gibt übrigens auch die Funktion [phpf]parse_ini_file[/phpf] zum Einlesen von INI-Dateien.
 
Ich finde das ganze etwas dreckig. Ich würde mich eher für eine DB-Basierte Variante entscheiden. Zum lernen aber ein schönes Beispiel.

Um damit zu arbeiten würde ich die Datei zunächst parsen und als Array verarbeiten. Mit diesem kannst du dann später die Werte manipulieren und die Datei am Ende neu speichern.

Ich hab dir mal was vorbereitet:
PHP:
<?php
// file
$file		= 'settings.ini';
// muh
$fileArr	= file($file);
// init
$output		= array();
// skip N rows
$skipRow	= 1;

if(count($fileArr) > 0) {
	$row	= 0;
	for($i=0; $i<count($fileArr); $i++) {
		// val zwischenspeichern und whitespaces entfernen (trim)
		$value	= trim($fileArr[$i]);
		// setze row +1
		if($value == '') $row++;
		// skip N rows && skip wenn die val leer ist
		if($skipRow>$i OR $value == '') continue;
	
		// das zeug in das array packen
		$tmp[$row][]	= $value;
	}
}

// debug!
echo '<pre>';
print_r($tmp);
echo '</pre>';
?>

Damit hast du schon mal ein kleinen Grundstein gelegt und kannst die Werte vernünftig in ein Array speichern. Du müsstest jetzt nur noch die einzelnen Values in das Array splitten. Da würde ich aber evtl. eher mit explode arbeiten. Zu str_replace würde ich eher nicht greifen.

Möp ... parse_ini_file scheint hier die bessere Variante sein zum einlesen :-) Arbeit umsonst, egal. Schau dir trotzdem mein Code an und versuche ihn zu verstehen. Gibt nichts besseres zum lernen.

Erstell dir daraus am besten ein Formular welches du dann wieder als Array einlesen kannst und so nach und nach die Datei neu schreiben kannst.
 
parse_ini_file() funktioniert hier nicht, da er gleiche Keys hat. parse_ini_file() nimmt nur ein User....
 
Erst mal vielen vielen Dank für deine Arbeit :)

Als ergebnis bekomme ich jedoch nur "s" in die Datei geschrieben. @Laser

@ComFreek die genaue Zeile im array weiß mein php script bereits. Ich habe nur kein plan, wie ich auch nur etwas in dieser Zeile ändere.

Viele Grüße

Haru
 
Zuletzt bearbeitet:
Dann machst du was falsch. Hab es getestet. Hier mein Datei-Inhalt:

Code:
[account]
user = test
pwd = test159
group = 1,2

user = blub
pwd = blub123
group = 1,2
 
Die Problematik ist, dass es kein ini- und kein xml-File ist.
Man muss auf einer Zeile feststellen, dass ein User beginnt und dann folgen die Details. Dann eine Leerzeile und wieder ein User. Ergo muss das gaze Schrittweise durchgeackert werden.

Nunja, meine Lösung ist wahrscheinlich etwas zu komplex am Anfang. Dafür ist der Aufruf umso einfacher. Ich habe mich für ein ArrayObjekt entschieden, das alle User aus dem File aufnimmt. Man kann jeden Parameter jedes Users verändern und das ganze wieder speichern. Man könnte die Klasse auch noch ausbauen, damit man User hinzufügen und löschen könnte. Das ist aber im Moment nicht umgesetzt. Im Moment ist nur Lesen und Ändern.

Der Aufruf
PHP:
//Vorgaben
$user = 'test';
$newGroup = '2,3';
$fileName = 'people.txt';

//Users anlegen
$users = new MyUsers($fileName);
//Beim User $user den Wert von group ändern
$users[$user]->group = $newGroup;
//Die Änderung speichern
$users->save();

Die Klasse
PHP:
/**
 * Die Klasse MyUsers
 */
class MyUsers extends ArrayObject{
    const C_USER_KEY = 'user';
    private $rowIndex = array();
    
    /**
     * Konstrukteur
     * @param   String      Pfad zum Settingfile
     */
    public function __construct($filePath){
        $this->filePath = $filePath;

        //Durchgehen von jeder Zeile
        foreach(array_map('trim', file($filePath)) as $rowNum => $line){
            $item = parse_ini_string($line);
            if(self::extract($item, $param, $value)){
                if($param == self::C_USER_KEY){
                    //Ein neuer User ($block) beginnt
                    $block = $value;
                    $this[$block] = new stdClass();
                }
                $this[$block]->$param = $value;                
                $this->rowIndex[$rowNum][$block] = $param;
            }else{
                //User ist fertig
                unset($block);
                $this->rowIndex[$rowNum] = $line;
            }            
        }
    }
    
    /**
     * Speichert den ganzen Karsumpel
     * @param   Boolean     Wenn true, dann nur mit var_dump() ausgeben
     */
    public function save($debug = false){
        $outputLine = array();
        foreach($this->rowIndex as $item){
            if(self::extract($item, $block, $param)){
                $outputLine[] = "{$param} = {$this[$block]->$param}";
            }else{
                $outputLine[] = $item;
            }
        }
        if($debug){
            var_dump(implode("\n", $outputLine));          
        }else{
            file_put_contents($this->filePath, implode("\n", $outputLine));
        }
    }
    
    /**
     * Extrahiert den Schlüssel ($key) und den Wert ($value) 
     * @param   Array oder String
     * @param   String      Schlüssel des ersten EIntrages im Array
     * @param   String      Wert des ersten EIntrages im Array
     * @return  Boolean     Ob $array ein Array war.
     */
    private static function extract($array, &$key, &$value){
        if(!is_array($array) || count($array) == 0) return false;
        $value = reset($array);
        $key = key($array);
        return true;
    }
}

Wenn du PHP unter 5.3 hast, msst du noch die Funktion parse_ini_string() implementieren
PHP:
//http://php.net/manual/de/function.parse-ini-string.php
//vor PHP 5.3:
if(!function_exists('parse_ini_string')){
    function parse_ini_string($str, $ProcessSections=false){
        $lines  = explode("\n", $str);
        $return = Array();
        $inSect = false;
        foreach($lines as $line){
            $line = trim($line);
            if(!$line || $line[0] == "#" || $line[0] == ";")
                continue;
            if($line[0] == "[" && $endIdx = strpos($line, "]")){
                $inSect = substr($line, 1, $endIdx-1);
                continue;
            }
            if(!strpos($line, '=')) // (We don't use "=== false" because value 0 is not valid as well)
                continue;
           
            $tmp = explode("=", $line, 2);
            if($ProcessSections && $inSect)
                $return[$inSect][trim($tmp[0])] = ltrim($tmp[1]);
            else
                $return[trim($tmp[0])] = ltrim($tmp[1]);
        }
        return $return;
    }
}
 
*blöng* War ich gestern müde und habe im Kreis gedacht. Wenn es nur darum geht, die Gruppe zu ändern, dann bietet sich da natürlich preg_replace() an.

PHP:
//Vorgaben
$user = 'test';
$newGroup = '2,3';
$fileName = 'people.txt';


//Pattern zusammenstellen
$pattern = "/(user[[:blank:]]*=[[:blank:]]*{$user}[^[:alnum:]].*group[[:blank:]]*=[[:blank:]]*)[,[:digit:]]+[^,[:alnum:]]/isU";
//Ersatzstring zusammenstellen
$replace = "\${1}{$newGroup}\n";

//Datei vollständig laden
$fileString = file_get_contents($fileName);
//Gruppe ersetzen
$newFileString = preg_replace($pattern, $replace, $fileString);
//Datei speichern
file_put_contents($fileName, $newFileString);
 
MEGA MEGA vieln DANK!

Ihr macht euch richtig viel mühe.

@Yaslaw mit deinem Script habe ich ein kleines Problem.

PHP:
<?php
//Vorgaben
$user = 'blub';
$newGroup = '2,3';
$fileName = 'user.txt';
 
 
//Pattern zusammenstellen
$pattern = "/(user[[:blank:]]*=[[:blank:]]*{$user}[^[:alnum:]].*group[[:blank:]]*=[[:blank:]]*)[,[:digit:]]+[^,[:alnum:]]/isU";
//Ersatzstring zusammenstellen
$replace = "\${1}{$newGroup}\n";
 
//Datei vollständig laden
$fileString = file_get_contents($fileName);
//Gruppe ersetzen
$newFileString = preg_replace($pattern, $replace, $fileString);
//Datei speichern
file_put_contents($fileName, $newFileString);
?>

Wenn ich den User test auf blub ändern, passiert nichts mehr. Woran liegt es?
 
mach in deinem User.txt am Ende noch ein Enter ran. Dann gehts. Ich musste den Pattern ungierig machen um nicht immer die letzte Gruppe zu ändern. Doch um festzulegen wo die Gruppe fertig ist, prüfe ich auf ein Zeichen das weder ein Komma, noch ein Buchstabe oder eine Ziffer ist (Der Teil [^,[:alnum:]]). Wenn du aber nach der letzten Gruppe kein Zeichen mehr hast und das die gesuchte ist, dann findet er sie nicht.
 
Zurück