<?php
namespace WpInstaller;
class FileManager {
private $created_files = [];
private $created_folders = [];
public function copy_file($source, $dest, $overwrite = false) {
if (file_exists($dest) && !$overwrite) {
throw new \Exception("Failed to copy to: $dest. File exists.");
}
else {
if (copy($source, $dest) !== true) {
throw new \Exception("Failed to copy file to: $dest");
}
$this->created_files[$dest] = md5_file($dest);
}
}
public function copy_dir($source, $dest, $overwrite = false) {
// If the dest folder doesn't exist, create it.
$this->mkdir($dest);
$cur_dir = opendir($source);
if ($cur_dir === false) {
throw new \Exception("Failed to read from: $source");
}
while (($entry = readdir($cur_dir)) !== false) {
if ($entry != '.' && $entry != '..') {
$s_path = "$source/$entry";
$d_path = "$dest/$entry";
if (is_dir($s_path)) {
$this->copy_dir($s_path, $d_path, $overwrite);
}
else {
$this->copy_file($s_path, $d_path, $overwrite);
}
}
}
closedir($cur_dir);
}
public function mkdir($directory) {
if (!file_exists($directory) || !is_dir($directory)) {
if (mkdir($directory, 0755, true) !== true) {
throw new \Exception("Failed to create directory: $directory");
}
array_push($this->created_folders, $directory);
}
}
/* transform_file(string $file, callable $trans_func)
// Example: replace all instances of 'hello' with 'hi' in a file
$func = function ( $line ) { return str_replace( 'hello', 'hi', $line); }
transform_file('foo.txt', $func);
Note: Since copy_file() is used to overwrite the input file with the new file contents, a
call to rollback() will delete files modified by transform_file
*/
public function transform_file(string $file, callable $trans_func) {
// Open input file for reading
$input_handle = fopen($file, 'r');
if (!$input_handle) {
throw new \Exception("Could not open file: $file");
}
if( !flock($input_handle, LOCK_EX) ) {
throw new \Exception("Could not get lock on: $file for transform");
}
else {
// Write transformations out to a temp file
$output_handle = tmpfile();
while ( ($line = fgets($input_handle)) !== false ) {
if (fwrite($output_handle, $trans_func( $line )) === false) {
throw new \Exception("Failed to write to $file");
}
}
// Fail if we got 'false' from fgets() before reaching the end of the file
if (!feof($input_handle)) {
fclose($input_handle);
fclose($output_handle);
throw new \Exception("Error reading while transforming: $file");
}
if (!fflush($output_handle)) {
throw new \Exception("Failed to finish writing to $file");
}
fclose($input_handle);
// Replace the input file with the output file
$out_path = stream_get_meta_data($output_handle)['uri'];
$this->copy_file($out_path, $file, true);
fclose($output_handle);
}
}
public function rollback() {
$this->undo_created_files();
$this->undo_created_folders();
}
private function undo_created_files() {
foreach ($this->created_files as $file => $hash) {
if (md5_file($file) == $hash) {
unlink($file);
}
}
}
private function undo_created_folders() {
$created_folders = array_reverse($this->created_folders);
foreach ($created_folders as $folder) {
$is_empty = !(new \FilesystemIterator($folder))->valid();
if ($is_empty) {
rmdir($folder);
}
}
}
}
?>