Ordner am Linux Server mit PHP synchronisieren

Technik
Ordner am Linux Server mit PHP synchronisieren

Bei Website-Projekten verwende ich immer zumindest eine Betaumgebung und eine Produktivumgebung, bei Bedarf auch eine separate Entwicklungsumgebung. Dazu liegen am Server die jeweiligen Unterordner.

Im Beta- (oder Dev-) Bereich wird entwickelt und im Produktivbereich sieht der Besucher nur das fertige Ergebnis. Bis dato habe ich zum Synchronisieren der beiden Ordner, also wenn eine neue Version online gehen soll, ein umfangreiches PHP-Script mit der DirectoryIterator Klasse verwendet. Nichts ahnend, dass es doch viel einfacher ginge.

Linux hat einen eigenen Befehl zum rekursiven Synchronisieren: rsync. Dieser funktioniert nicht nur lokal, sondern kann über FTP ganze Ordner sogar über die Ferne synchronisieren. Soweit geht die Klasse hier zwar nicht, sie kann aber leicht angepasst werden. Die wichtigste Zeile ist jedenfalls die Befehlszeile, der Rest ist nur Vorbereitung.

Achtung: Durch einen Fehler kann leicht der gesamte Inhalt eurer Seite verloren bzw. überspielt werden. Als Standard wird daher nur eine Simulation durchgeführt, für den echten Durchlauf, müsst ihr den vierten Parameter auf false stellen.

<?php
class Rsync {
  private $command;
  
  public function __construct($source, $dest, $exclude=array(), $simulate=true){
    try{
      // check if source directory exists
      if(!file_exists($source))
        throw new Exception('source directory not found');
      
      // check if destination directory exists
      if(!file_exists($dest))
        throw new Exception('destination directory not found');
      
      // check if exclude is an array
      if(!is_array($exclude))
        throw new Exception('exclude not an array');
      
      // secure user input and prepare for command line
      foreach($exclude as $k=>$v){
        if(is_string($v))
          $exclude[$k] = "--exclude=".escapeshellarg($v);
        else
          unset($exclude[$k]);
      }
      
      // change working directory to source
      chdir($source);
      
      // save shell execution command
      $this->command = 'rsync -trv'.($simulate ? 'n' : '').' --progress '.(implode(' ', $exclude)).' --delete  . '.$dest;
    }
    catch(Exception $e){
      die('Error: '. $e);
    }
  }
  
  public function execute(){
    $returnlines = array();
    $r = exec($this->command, $returnlines);
    if($r)
      return $returnlines;
    else
      return false;
  }
}
?>

Und so wird es dann ausgeführt. Einfach die Klasse einbinden, alle auszuschließenden Dateien und Ordner in ein Array schreiben und die Klasse Rsync mit folgenden Parametern aufrufen:

  • $source (string): Quellenordner
  • $dest (string): Zielordner
  • $exclude (array): auszuschließende Dateien und Ordner
  • $simulate (bool): ob der Durchlauf simuliert werden soll, true oder false

Nun ist alles vorbereitet, zum Ausführen nur noch den execute Befehl laufen lassen:

Rückgabewert: Die Funktion gibt false zurück, falls ein Fehler aufgetreten ist, ansonsten wird ein Array mit den einzelnen Rückgabezeilen zurückgegeben.

<?php
require_once('Rsync.php');

$exclude = array();
$exclude[] = '*.LCK'; // all files with .LCK extension
$exclude[] = '/data';
$exclude[] = '/img';
$exclude[] = '/Rsync.php';

$rsync = new Rsync('/source', '/dest', $exclude, true);
print_r($rsync->execute());
?>

Der rsync Befehl wird über die PHP Funktion exec mit folgenden Parametern übergeben:

  • -t: behält die Bearbeitungszeit der Datei bei
  • -r: läuft Ordner rekursiv durch, notwendig zum Kopieren von Ordnern und Dateien
  • -v: erhöht die Menge der zurückgegebenen Informationen während des Durchlaufs
  • -n: simuliert den Durchlauf ohne tatsächlich Dateien und Ordner zu ändern
  • --progress: zeigt Details zum Transferprozess an
  • --delete: löscht Dateien aus dem Zielordner, die nicht im Quellordner vorhanden sind (ignoriert alle ausgeschlossenen Ordner, --exclude)

Ab einer gewissen Projektgröße ist jedoch eine genauere Versionierung sinnvoll, z.B. mit SVN oder GIT.

Permalink: https://to.ptmr.io/1s95j0D