class-backup-engine-file-zip.php
3.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<?php
namespace HM\BackUpWordPress;
use Symfony\Component\Process\Process as Process;
/**
* Perform a file backup using the zip cli command
*/
class Zip_File_Backup_Engine extends File_Backup_Engine {
/**
* The path to the zip executable
*
* @var string
*/
private $zip_executable_path = '';
public function __construct() {
parent::__construct();
}
/**
* Calculate the path to the zip executable.
*
* The executable path can be overridden using either the `HMBKP_ZIP_PATH`
* Constant or the `hmbkp_zip_executable_path` filter.
*
* If neither of those are set then we fallback to checking a number of
* common locations.
*
* @return string|false The path to the executable or false.
*/
public function get_zip_executable_path() {
if ( defined( 'HMBKP_ZIP_PATH' ) ) {
return HMBKP_ZIP_PATH;
}
/**
* Allow the executable path to be set via a filter
*
* @param string The path to the zip executable
*/
$this->zip_executable_path = apply_filters( 'hmbkp_zip_executable_path', '' );
if ( ! $this->zip_executable_path ) {
// List of possible zip locations
$paths = array(
'zip',
'/usr/bin/zip',
'/usr/local/bin/zip',
'/opt/local/bin/zip',
);
$this->zip_executable_path = Backup_Utilities::get_executable_path( $paths );
}
return $this->zip_executable_path;
}
/**
* Perform the file backup.
*
* @return bool Whether the backup completed successfully or not.
*/
public function backup() {
if ( ! $this->get_zip_executable_path() ) {
return false;
}
// cd to the site root
$command[] = 'cd ' . escapeshellarg( Path::get_root() );
// Run the zip command with the recursive and quiet flags
$command[] = '&& ' . escapeshellcmd( $this->get_zip_executable_path() ) . ' -rq';
// Save the zip file to the correct path
$command[] = escapeshellarg( $this->get_backup_filepath() ) . ' ./';
// Pass exclude rules in if we have them
if ( $this->get_exclude_string() ) {
$command[] = '-x ' . $this->get_exclude_string();
}
$command = implode( ' ', $command );
$process = new Process( $command );
$process->setTimeout( HOUR_IN_SECONDS );
try {
$process->run();
} catch ( \Exception $e ) {
$this->error( __CLASS__, $e->getMessage() );
}
if ( ! $process->isSuccessful() ) {
/**
* Exit Code 18 is returned when an unreadable file is encountered during the zip process.
*
* Given the zip process still completes correctly and the unreadable file is simple skipped
* we don't want to treat 18 as an actual error.
*/
if ( $process->getExitCode() !== 18 ) {
$this->error( __CLASS__, $process->getErrorOutput() );
}
}
return $this->verify_backup();
}
/**
* Convert the exclude rules to a format zip accepts
*
* @return string The exclude string ready to pass to `zip -x`
*/
public function get_exclude_string() {
if ( ! $this->excludes ) {
return '';
}
$excludes = $this->excludes->get_excludes();
foreach ( $excludes as $key => &$rule ) {
$file = $absolute = $fragment = false;
// Files don't end with /
if ( ! in_array( substr( $rule, - 1 ), array( '\\', '/' ) ) ) {
$file = true;
} // If rule starts with a / then treat as absolute path
elseif ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
$absolute = true;
} // Otherwise treat as dir fragment
else {
$fragment = true;
}
$rule = str_ireplace( Path::get_root(), '', untrailingslashit( wp_normalize_path( $rule ) ) );
// Strip the preceeding slash
if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) ) {
$rule = substr( $rule, 1 );
}
// Wrap directory fragments and files in wildcards for zip
if ( $fragment || $file ) {
$rule = '*' . $rule . '*';
}
// Add a wildcard to the end of absolute url for zips
if ( $absolute ) {
$rule .= '*';
}
}
// Escape shell args for zip command
$excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
return implode( ' -x ', $excludes );
}
}