<?php 
// предполагаем вызов бекапера один раз в день. 
// создаем архов состоянием на начало месяца + по дополнительному архиву на каждый день с инкриментом относительно начала месяца
// т.е. для разворачивания состояния на 15 число надо 2 файла: на 1 и на 15 число.
// удаление файлов НЕ ОТСЛЕЖИВАНИЕМ
//
// в первый вызов в текущем месяце создаем полную копию (исключая те каталоги что запрещены DIR_BACKUP_EXCLUDEDS) в DIR_BACKUP . date("Y/Y-m/") . 'www/'
// плюс все эти файлы пакуем в главный архив с именем DIR_BACKUP . date("Y/Y-m/") . '/file-backup-'.date("Y-m-d_H-i-s") . '.zip'
// при других вызовах создается архив новых и измененных файлов в DIR_BACKUP . date("Y/Y-m/Y-m-d") . '/file-backup-'.date("Y-m-d_H-i-s") . '.zip'
// при вызове в последний день месяца удаляются все файлы и каталоги из DIR_BACKUP/date("Y/Y-m/").'/www/'
// при повторном вызове в последний день месяца (отсутствие www/) - игнорируем вызов
// работу и ошибки логируем в DIR_BACKUP . date("Y/Y-m/") . 'backup.log'

	require_once('config.php');

	toLog('старт');
	$listdir = [];	// Массив с списком уже существующих каталогов
	$allfiles = []; // Массив со списком файлов подлежащих архивированию
	
	if (date('t')==date('d') AND !file_exists(DIR_BACKUP . date("Y/Y-m/") . 'www')){ // последний день месяца и www уже почистили
		toLog('попытка повторного запуска в последний день месяца');
	}elseif (date('t')==date('d')){ // последний день месяца, уходя гасите всех

		toLog('последний день месяца');
		
		recoursiveDir('');
		
		$basetime = filemtime(DIR_BACKUP . date("Y/Y-m/") . 'www.label');
		to_zip(DIR_BACKUP . date("Y/Y-m/") . 'file-backup-' . date("Y-m-d_H-i-s") . '.zip', $basetime);
		
		recoursiveDirDELETE(date("Y/Y-m/") . 'www');
		unlink(DIR_BACKUP . date("Y/Y-m/") . 'www.label');
		toLog("удалили www" . $num);

	}elseif(!file_exists(DIR_BACKUP . date("Y/Y-m/") . 'www')){ // первый запуск в этом месяце
		toLog('первый запуск в этом месяце');
		recoursiveDir('');

		foreach ($allfiles as $val){
			
			createDirFromNameFile(date("Y/Y-m/") . 'www/' . $val);
			
			if (!copy(	DIR_TO_BACKUP . $val,
						DIR_BACKUP . date("Y/Y-m/") . 'www/' . $val)) {
				toLog( 'Ошибка копирования ' . DIR_TO_BACKUP . $val . ' в ' . DIR_BACKUP . date("Y/Y-m/") . 'www/' . $val);
			}
		}
		
		file_put_contents(DIR_BACKUP . date("Y/Y-m/") . 'www.label', 'метка для определения даты-времени когда скопированы файлы' . $text, FILE_APPEND | LOCK_EX);
		
		to_zip(DIR_BACKUP . date("Y/Y-m/") . 'file-backup-' . date("Y-m-d_H-i-s") . '.zip');
		
	}else{ // обычный запуск
		
		toLog('обычный запуск');
		
		recoursiveDir('');
		
		$basetime = filemtime(DIR_BACKUP . date("Y/Y-m/") . 'www.label');
		to_zip(DIR_BACKUP . date("Y/Y-m/") . 'file-backup-' . date("Y-m-d_H-i-s") . '.zip', $basetime);
		
	}
	toLog('стоп');
	toLog('');

function to_zip($zipname, $basetime = 0){ 

	global $allfiles;

	if(extension_loaded('zip')){
		$zip = new ZipArchive();
		createDir ( date("Y/Y-m"), 0777);
		toLog("сохраняю " . $zipname);
		$num = 0;
		if($zip->open($zipname, ZIPARCHIVE::CREATE) == TRUE){

			foreach ($allfiles as $val){
				if (!file_exists(DIR_BACKUP . date("Y/Y-m/") . 'www/' . $val) OR filemtime(DIR_TO_BACKUP . $val) > $basetime) {
					$zip->addFile(DIR_TO_BACKUP . $val); // отсутствующие или с датой изменения больше чем у начальной копии
					$num++;
				}
			}
			$zip->close();
		}
		toLog("всего " . $num);
	}	
}
	
function createDir($dir){ // присылаем хвост пути (без DIR_BACKUP)
	global $listdir;
	$entries = explode('/', $dir);
	$base = DIR_BACKUP;
	foreach($entries as $entry){
		$base .= $entry;
		if (!in_array($base, $listdir)){
			if(!file_exists($listdir)){
				mkdir ( $listdir, 0777);
			}
			$listdir[] = $base;
		}
		$base .= '/';
	}
}

function toLog($text){
	file_put_contents(DIR_BACKUP . date("Y/Y-m/") . 'backup.log', chr(13) . chr(10) . date('d/m/Y H:i:s') . chr(9) . 'инкремент:' . chr(9) . $text, FILE_APPEND | LOCK_EX);
}

function createDirFromNameFile($dir){ // присылаем хвост пути (без DIR_BACKUP)
	global $listdir;
	$entries = explode('/', $dir);
	array_pop($entries);
	$base = DIR_BACKUP;
	foreach($entries as $entry){
		$base .= $entry;
		if (!in_array($base, $listdir)){
			if(!file_exists($base)){
				mkdir ( $base, 0777);
			}
			$listdir[] = $base;
		}
		$base .= '/';
	}
}

function recoursiveDir($dir){
	global $allfiles;
	if ($dir==''){
		$dir = DIR_TO_BACKUP;
	}else{
		$dir = DIR_TO_BACKUP . $dir . '/';
	}
	if ($files = glob($dir . "{,.}*", GLOB_BRACE)) {
		foreach($files as $file){
			$b_name = basename($file);
			if (($b_name == ".") OR ($b_name == "..") OR in_array($b_name, explode(',', DIR_BACKUP_EXCLUDEDS))) {
				continue;
			}
			if (is_dir($file)) {
				$file = substr($file, strlen(DIR_TO_BACKUP));
				recoursiveDir($file);
			}else{
				$file = substr($file, strlen(DIR_TO_BACKUP));
				$allfiles[] = $file;
			}
		}
	}
}

function recoursiveDirDELETE($dir){
	$dir_ = DIR_BACKUP . $dir;
	$dir = DIR_BACKUP . $dir . '/';

	if ($files = glob($dir . "{,.}*", GLOB_BRACE)) {
		foreach($files as $file){
			$b_name = basename($file);
			if (($b_name == ".") OR ($b_name == "..")) {
				continue;
			}
			if (is_dir($file)) {
				recoursiveDirDELETE(substr($file, strlen(DIR_BACKUP)));
				rmdir($file);
			}else{
				unlink($file);
			}
		}
	}
	rmdir($dir_);
}
 
?>