YaWK  24.1
Yet another WebKit
backup-fileBackup.php
Go to the documentation of this file.
1 <?php
3 {
4  /**
5  * @details <b>YaWK Backup Component: File Backup Class</b>
6  * <p>Methods to backup folders and files</p>
7  *
8  * @package YAWK
9  * @author Daniel Retzl <[email protected]>
10  * @copyright 2018 Daniel Retzl
11  * @license https://opensource.org/licenses/MIT
12  * @version 1.0.0
13  * @brief This class serves methods to create backup from files.
14  */
15  class fileBackup extends \YAWK\BACKUP\backup
16  {
17  /** @param object zip object */
18  public $zip;
19  /** @param string source folder to backup */
20  public $sourceFolder = '';
21  /** @param string path, where the backup will be stored */
22  public $targetFolder = '../system/backup/current/';
23  /** @param string default filename of .zip file */
24  public $backupZipFile = 'backup-custom.zip';
25  /** @param string hash value of .zip file */
26  public $hashValue = '';
27  /** @param string content folder */
28  public $contentFolder = '../content/';
29  /** @param string media folder */
30  public $mediaFolder = '../media/';
31  /** @param string system folder */
32  public $systemFolder = '../system/';
33  /** @param string current processing folder */
34  public $currentFolder = '';
35  /** @param string final filename*/
36  public $finalFilename = '';
37 
38 
39  /**
40  * @brief Initialize and start file backup
41  * @param object $db database object
42  * @param string $overwriteBackup if overwrite backup is allowed or not "true" | "false"
43  * @param string $zipBackup if backup should be zipped or not "true" | "false"
44  * @return bool
45  * @version 1.0.0
46  * @link http://yawk.io
47  * @author Daniel Retzl <[email protected]>
48  */
49  public function initFolderBackup(object $db, string $overwriteBackup, string $zipBackup): bool
50  {
51  // start file backup
52  $this->overwriteBackup = $overwriteBackup;
53  $this->zipBackup = $zipBackup;
54 
55  if ($this->startFileBackup($db) === true)
56  { // file backup done
57  return true;
58  }
59  else
60  { // file backup failed
61  return false;
62  }
63  }
64 
65 
66  /**
67  * @brief Check if .zip backup file exists
68  * @brief return bool if $this->backupZipFile exists
69  * @return bool true|false
70  */
71  public function zipFileExists(): bool
72  {
73  // set path + filename (store as string in $this->backupZipFile)
74  $this->backupZipFile = $this->targetFolder.$this->backupZipFile;// .sql backup file exists
75  // check if .zip file is already there
76  if (is_file($this->backupZipFile))
77  {
78  // .zip file exists
79  return true;
80  }
81  else
82  {
83  // .zip file does not exist
84  return false;
85  }
86  }
87 
88  /**
89  * @brief Write backup.ini file (used by backup restore methods)
90  * @brief write all relevant backup information into this file
91  * @return array $this->backupSettings
92  */
93  public function setBackupSettings()
94  {
95  // set some backup info variables
96  $this->backupSettings['DATE'] = \YAWK\sys::now();
97  $this->backupSettings['METHOD'] = $this->backupMethod;
98  $this->backupSettings['FILE'] = $this->finalFilename;
99  $this->backupSettings['PATH'] = $this->targetFolder;
100  $this->backupSettings['USER_ID'] = $_SESSION['uid'];
101  return $this->backupSettings;
102  }
103 
104  /**
105  * @brief Get and return hash value of $file
106  * @brief return hashed string or false
107  * @return string|bool
108  */
109  public function getHashValue($db, $file)
110  {
111  // check if file is set
112  if (!isset($file) || (empty($file)))
113  { // file not set
114  return false;
115  }
116 
117  // check if sql backup file is accessable
118  if (is_file($file))
119  { // generate hash value
120  return $this->hashValue = hash_file('md5', $file);
121  }
122  else
123  { // file not found: unable to generate hash value
124  \YAWK\sys::setSyslog($db, 52, 2, "failed to generate hash value - $file is not accessable", 0, 0, 0, 0);
125  return false;
126  }
127  }
128 
129  /**
130  * @brief Copy files to tmp folder, zip it and move it to the place
131  * where this backup should be stored (current or archive...)
132  * @brief return bool if $this->backupZipFile exists
133  * @return bool true|false
134  */
135  public function doFolderBackup($db)
136  {
137  // check if temp folder is writeable
138  if (!is_writeable($this->tmpFolder) && (!empty($this->tmpFolder)))
139  { // tmp folder not writeable...
140  return false;
141  }
142 
143  // CONTENT FOLDER PROCESSING
144  if (isset($_POST['contentFolder']) && (!empty($_POST['contentFolder'])))
145  { // create content folder
146  if (!is_dir($this->tmpFolder.'content'))
147  {
148  if (!mkdir($this->tmpFolder . 'content'))
149  {
150  // return false
151  \YAWK\sys::setSyslog($db, 51, 2, "failed to create " . $this->tmpFolder . "content", 0, 0, 0, 0);
152  }
153  }
154 
155  // walk through content folder subdirectories
156  foreach ($_POST['contentFolder'] as $folder)
157  {
158  // set current content folder property
159  $this->currentFolder = $this->contentFolder;
160  $this->targetFolder = $this->tmpFolder.'content/';
161  // check if parent dir exists
162  if (is_dir($this->currentFolder.$folder))
163  {
164  // check if subdir NOT exists
165  if (!is_dir($this->targetFolder.$folder))
166  {
167  // create subdir
168  mkdir($this->targetFolder.$folder);
169  $this->targetFolder = $this->tmpFolder.'content/'.$folder;
170  }
171  else
172  { // subdir exists, set target path
173  $this->targetFolder = $this->tmpFolder.'content/'.$folder;
174  }
175  }
176  // copy content subfolder
177  if ($this->copyFolder($db, $folder, $this->targetFolder) !== true)
178  {
179  \YAWK\sys::setSyslog($db, 51, 2, "failed to create ".$this->contentFolder."$folder", 0, 0, 0, 0);
180  }
181  }
182  }
183 
184 
185  // MEDIA FOLDER PROCESSING
186  if (isset($_POST['mediaFolder']) && (!empty($_POST['mediaFolder'])))
187  { // create content folder
188  if (!is_dir($this->tmpFolder.'media'))
189  {
190  if (!mkdir($this->tmpFolder . 'media'))
191  {
192  // return false
193  \YAWK\sys::setSyslog($db, 51, 2, "failed to create " . $this->tmpFolder . "media", 0, 0, 0, 0);
194  }
195  }
196 
197  // walk through content folder subdirectories
198  foreach ($_POST['mediaFolder'] as $folder)
199  {
200  // set current content folder property
201  $this->currentFolder = $this->mediaFolder;
202  $this->targetFolder = $this->tmpFolder.'media/';
203  // check if parent dir exists
204  if (is_dir($this->currentFolder.$folder))
205  {
206  // check if subdir NOT exists
207  if (!is_dir($this->targetFolder.$folder))
208  {
209  // create subdir
210  mkdir($this->targetFolder.$folder);
211  $this->targetFolder = $this->tmpFolder.'media/'.$folder;
212  }
213  else
214  { // subdir exists, set target path
215  $this->targetFolder = $this->tmpFolder.'media/'.$folder;
216  }
217  }
218  // copy media subfolder
219  if ($this->copyFolder($db, $folder, $this->targetFolder) !== true)
220  {
221  \YAWK\sys::setSyslog($db, 51, 2, "failed to create ".$this->mediaFolder."$folder", 0, 0, 0, 0);
222  }
223  }
224  }
225 
226  // SYSTEM FOLDER PROCESSING
227  if (isset($_POST['systemFolder']) && (!empty($_POST['systemFolder'])))
228  { // create content folder
229  if (!is_dir($this->tmpFolder.'system'))
230  {
231  if (!mkdir($this->tmpFolder . 'system'))
232  {
233  // return false
234  \YAWK\sys::setSyslog($db, 51, 2, "failed to create " . $this->tmpFolder . "system", 0, 0, 0, 0);
235  }
236  }
237 
238  // walk through system folder subdirectories
239  foreach ($_POST['systemFolder'] as $folder)
240  {
241  // set current content folder property
242  $this->currentFolder = $this->systemFolder;
243  $this->targetFolder = $this->tmpFolder.'system/';
244  // check if parent dir exists
245  if (is_dir($this->currentFolder.$folder))
246  {
247  // check if subdir NOT exists
248  if (!is_dir($this->targetFolder.$folder))
249  {
250  // create subdir
251  mkdir($this->targetFolder.$folder);
252  $this->targetFolder = $this->tmpFolder.'system/'.$folder;
253  }
254  else
255  { // subdir exists, set target path
256  $this->targetFolder = $this->tmpFolder.'system/'.$folder;
257  }
258  }
259  // copy system subfolder
260  if ($this->copyFolder($db, $folder, $this->targetFolder) !== true)
261  {
262  \YAWK\sys::setSyslog($db, 51, 2, "failed to create ".$this->systemFolder."$folder", 0, 0, 0, 0);
263  }
264  }
265  }
266 
267  // PREPARE FINAL FILENAME
268  // set filename of backup .zip archive (including path to tmp folder)
269  // check, which filename the backup should have:
270  if (isset($_POST['backupMethod']) && (!empty($_POST['backupMethod'])))
271  {
272  switch ($_POST['backupMethod'])
273  {
274  case "complete" :
275  {
276  $this->finalFilename = "complete-backup.zip";
277  $this->backupMethod = "complete";
278  }
279  break;
280 
281  case "mediaFolder" :
282  {
283  $this->finalFilename = "mediafolder-backup.zip";
284  $this->backupMethod = "mediaFolder";
285  }
286  break;
287 
288  case "custom" :
289  {
290  $this->finalFilename = "custom-backup.zip";
291  $this->backupMethod = "custom";
292  }
293  break;
294 
295  default:
296  {
297  $this->finalFilename = "backup.zip";
298  $this->backupMethod = "unknown";
299  }
300 
301  }
302  }
303 
304  // set backup settings
305  $this->backupSettings = $this->setBackupSettings();
306 
307  // check if ini file was written
308  if (\YAWK\sys::writeIniFile($this->backupSettings, $this->tmpFolder.$this->configFilename) === true)
309  {
310  // check if config file is there
311  if (!is_file($this->tmpFolder.$this->configFilename))
312  { // config file not found
313  \YAWK\sys::setSyslog($db, 51, 1, "backup ini file written, but not found - please check: $this->configFilename", 0, 0, 0, 0);
314  return false;
315  }
316  }
317 
318  // ZIP FOLDER + COPY TO FINAL DESTINATION
319  // try to zip the whole tmp/ folder
320  if ($this->zipFolder($db, $this->tmpFolder, $this->tmpFolder."$this->finalFilename") == true)
321  {
322  // check if POST data is sent
323  if (isset($_POST))
324  {
325  // check if backup overwrite is allowed
326  if (isset($_POST['overwriteBackup']) && ($_POST['overwriteBackup'] == "false"))
327  {
328  // check if new folder was entered by user
329  if (isset($_POST['newFolder']) && (!empty($_POST['newFolder'])))
330  {
331  // create new archive sub folder path
332  $this->archiveBackupSubFolder = $this->archiveBackupFolder.$_POST['newFolder']."/";
333 
334  // create new directory in archive
335  if (!is_dir($this->archiveBackupSubFolder))
336  {
337  if (mkdir($this->archiveBackupSubFolder))
338  { // all good, new archive subfolder created
339  // set syslog entry: dir created
340  \YAWK\sys::setSyslog($db, 49, 0, "archive directory created: $this->archiveBackupSubFolder", 0, 0, 0, 0);
341  }
342  else
343  { // failed to create new archive subfolder
344  // set syslog entry: failed
345  \YAWK\sys::setSyslog($db, 52, 0, "failed to create archive directory: $this->archiveBackupSubFolder", 0, 0, 0, 0);
346  }
347  }
348  }
349  // check if existing folder was selected by user
350  else if (isset($_POST['selectFolder']) && (!empty($_POST['selectFolder'])))
351  { // set archive sub foder path
352  $this->archiveBackupSubFolder = $this->archiveBackupFolder.$_POST['selectFolder']."/";
353  }
354 
355  // STORE TO ARCHIVE FOLDER
356  // move final *****-backup .zip to archive backup folder
357  if (rename($this->tmpFolder.$this->finalFilename, $this->archiveBackupSubFolder.$this->finalFilename))
358  { // check if final filename exists
359  if (is_file($this->archiveBackupSubFolder.$this->finalFilename))
360  {
361  // ok, delete tmp folder recursive
362  \YAWK\sys::recurseRmdir($this->tmpFolder);
363  // set positive syslog entry
364  \YAWK\sys::setSyslog($db, 49, 3, "created ".$this->archiveBackupSubFolder."$this->finalFilename", 0, 0, 0, 0);
365  return true;
366  }
367  else
368  { // failed to create backup
369  \YAWK\sys::setSyslog($db, 52, 0, "failed to create ".$this->archiveBackupSubFolder."$this->finalFilename", 0, 0, 0, 0);
370  return false;
371  }
372  }
373  else
374  { // failed to move final backup file
375  \YAWK\sys::setSyslog($db, 52, 0, "failed to move ".$this->archiveBackupSubFolder."$this->finalFilename", 0, 0, 0, 0);
376  return false;
377  }
378  }
379  else
380  { // STORE TO CURRENT FOLDER
381  // move final *****-backup .zip to current backup folder
382  if (rename($this->tmpFolder.$this->finalFilename, $this->currentBackupFolder.$this->finalFilename))
383  {
384  // check if final backup file is available in current folder
385  if (is_file($this->currentBackupFolder.$this->finalFilename))
386  { // ok, remove tmp dir recursivly
387  \YAWK\sys::recurseRmdir($this->tmpFolder);
388  // set positive syslog entry
389  \YAWK\sys::setSyslog($db, 49, 3, "created ".$this->currentBackupFolder."$this->finalFilename", 0, 0, 0, 0);
390  return true;
391  }
392  else
393  { // failed to create current backup
394  \YAWK\sys::setSyslog($db, 52, 0, "failed to create ".$this->currentBackupFolder."$this->finalFilename", 0, 0, 0, 0);
395  return false;
396  }
397  }
398  else
399  { // failed to move backup archive to current folder
400  \YAWK\sys::setSyslog($db, 52, 0, "failed to move ".$this->currentBackupFolder."$this->finalFilename", 0, 0, 0, 0);
401  return false;
402  }
403  }
404  }
405  else
406  { // post data not sent
407  \YAWK\sys::setSyslog($db, 52, 0, "failed to backup: POST data not sent", 0, 0, 0, 0);
408  return true;
409  }
410  }
411  else
412  { // failed to zip final backup file
413  \YAWK\sys::setSyslog($db, 52, 0, "unable to zip ".$this->finalFilename."", 0, 0, 0, 0);
414  return false;
415  }
416  }
417 
418 
419  /**
420  * @brief Copy a folder from source to target, including all subdirectories
421  * @param $db
422  * @param $folder
423  * @param $targetFolder
424  * @return bool
425  */
426  public function copyFolder($db, $folder, $targetFolder)
427  {
428  // set source folder
429  $this->sourceFolder = $this->currentFolder.$folder;
430  // set target folder
431  $this->targetFolder = $targetFolder;
432 
433  // copy source folder to target folder
434  if (\YAWK\sys::xcopy($this->sourceFolder, $this->targetFolder) === false)
435  { // failed to copy content folder
436  \YAWK\sys::setSyslog($db, 52, 2, "failed to copy $this->sourceFolder to $this->targetFolder", 0, 0, 0, 0);
437  return false;
438  }
439  else
440  { // copy folder successful
441  return true;
442  }
443  }
444 
445  /**
446  * @brief Check settings and start file backup
447  * @brief return bool if zip archive exists
448  * @return bool true|false
449  */
450  public function startFileBackup($db)
451  {
452  // check if backup overwrite is allowed
453  if ($this->overwriteBackup == "false")
454  { // check if POST array is set (form was sent)
455  if (isset($_POST))
456  {
457  // check if new folder was entered by user
458  if (isset($_POST['newFolder']) && (!empty($_POST['newFolder'])))
459  {
460  // create new archive sub folder path
461  $this->archiveBackupSubFolder = $this->archiveBackupFolder.$_POST['newFolder']."/";
462 
463  // create new directory in archive
464  if (!is_dir($this->archiveBackupSubFolder))
465  { // try to create archive subfolder
466  if (mkdir($this->archiveBackupSubFolder))
467  { // all good, new archive subfolder created
468  // set syslog entry: dir created
469  \YAWK\sys::setSyslog($db, 49, 0, "archive directory created: $this->archiveBackupSubFolder", 0, 0, 0, 0);
470  }
471  else
472  { // failed to create new archive subfolder
473  // set syslog entry: failed
474  \YAWK\sys::setSyslog($db, 52, 0, "failed to create archive directory: $this->archiveBackupSubFolder", 0, 0, 0, 0);
475  }
476  }
477  }
478  // check if existing folder was selected by user
479  else if (isset($_POST['selectFolder']) && (!empty($_POST['selectFolder'])))
480  { // set archive sub folder path
481  $this->archiveBackupSubFolder = $this->archiveBackupFolder.$_POST['selectFolder']."/";
482  }
483 
484  // set backup target folder
485  $this->targetFolder = $this->archiveBackupSubFolder;
486  }
487  }
488 
489  // check if a backup exists
490  if ($this->zipFileExists() === true)
491  {
492  // do folder backup
493  if ($this->doFolderBackup($db) === true)
494  { // ok, backup done
495  \YAWK\sys::setSyslog($db, 50, 3, "file backup overwritten", 0, 0, 0, 0);
496  return true;
497  }
498  else
499  { // backup failed - unable to overwrite - check chmod settings!
500  \YAWK\sys::setSyslog($db, 52, 2, "failed to overwrite file backup", 0, 0, 0, 0);
501  return false;
502  }
503  }
504  else
505  { // file does not exist - do file backup
506  if ($this->doFolderBackup($db) === true)
507  { // ok, backup done!
508  // \YAWK\sys::setSyslog($db, 50, 3, "created file backup", 0, 0, 0, 0);
509  return true;
510  }
511  else
512  { // backup failed!
513  \YAWK\sys::setSyslog($db, 52, 2, "failed to write file backup", 0, 0, 0, 0);
514  return false;
515  }
516  }
517  }
518  }
519 }
$folder
Definition: actions.php:9
doFolderBackup($db)
Copy files to tmp folder, zip it and move it to the place where this backup should be stored (current...
startFileBackup($db)
Check settings and start file backup.
setBackupSettings()
Write backup.ini file (used by backup restore methods)
copyFolder($db, $folder, $targetFolder)
Copy a folder from source to target, including all subdirectories.
initFolderBackup(object $db, string $overwriteBackup, string $zipBackup)
Initialize and start file backup.
getHashValue($db, $file)
Get and return hash value of $file.
zipFileExists()
Check if .zip backup file exists.
zipFolder($db, $source, $destination)
Zip a whole folder from $source to $destination.zip.
Definition: backup.php:440
static xcopy($source, $dest, $permissions=0755)
Copy a file, or recursively copy a folder and its contents.
Definition: sys.php:473
static recurseRmdir($dir)
remove a directory recurse
Definition: sys.php:1127
static writeIniFile($array, $file)
write ini file
Definition: sys.php:2085
static now()
returns the current datetime
Definition: sys.php:1492
This class serves methods to create backup from files.
Definition: AdminLTE.php:2