commit | author | age
|
f17718
|
1 |
<?php |
FS |
2 |
/* |
|
3 |
Copyright (c) 2013, Florian Schaal, info@schaal-24.de |
|
4 |
All rights reserved. |
|
5 |
|
|
6 |
Redistribution and use in source and binary forms, with or without modification, |
|
7 |
are permitted provided that the following conditions are met: |
|
8 |
|
|
9 |
* Redistributions of source code must retain the above copyright notice, |
|
10 |
this list of conditions and the following disclaimer. |
|
11 |
* Redistributions in binary form must reproduce the above copyright notice, |
|
12 |
this list of conditions and the following disclaimer in the documentation |
|
13 |
and/or other materials provided with the distribution. |
|
14 |
* Neither the name of ISPConfig nor the names of its contributors |
|
15 |
may be used to endorse or promote products derived from this software without |
|
16 |
specific prior written permission. |
|
17 |
|
|
18 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
|
19 |
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
20 |
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
|
21 |
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
|
22 |
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
|
23 |
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
24 |
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
25 |
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
26 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, |
|
27 |
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
28 |
*/ |
|
29 |
|
955491
|
30 |
class cronjob_backup_mail extends cronjob { |
f17718
|
31 |
|
FS |
32 |
// job schedule |
|
33 |
protected $_schedule = '0 0 * * *'; |
f339eb
|
34 |
private $tmp_backup_dir = ''; |
f17718
|
35 |
|
FS |
36 |
/* this function is optional if it contains no custom code */ |
|
37 |
public function onPrepare() { |
|
38 |
global $app; |
|
39 |
|
|
40 |
parent::onPrepare(); |
|
41 |
} |
|
42 |
|
|
43 |
/* this function is optional if it contains no custom code */ |
|
44 |
public function onBeforeRun() { |
|
45 |
global $app; |
|
46 |
|
|
47 |
return parent::onBeforeRun(); |
|
48 |
} |
|
49 |
|
|
50 |
public function onRunJob() { |
|
51 |
global $app, $conf; |
|
52 |
|
|
53 |
$server_config = $app->getconf->get_server_config($conf['server_id'], 'server'); |
c220da
|
54 |
$mail_config = $app->getconf->get_server_config($conf['server_id'], 'mail'); |
6b166b
|
55 |
$global_config = $app->getconf->get_global_config('sites'); |
DM |
56 |
|
b48a0b
|
57 |
$backup_dir = trim($server_config['backup_dir']); |
c220da
|
58 |
$backup_dir_permissions =0750; |
FS |
59 |
|
f17718
|
60 |
$backup_mode = $server_config['backup_mode']; |
FS |
61 |
if($backup_mode == '') $backup_mode = 'userzip'; |
|
62 |
|
|
63 |
if($backup_dir != '') { |
|
64 |
$run_backups = true; |
990ca8
|
65 |
//* mount backup directory, if necessary |
FS |
66 |
if( $server_config['backup_dir_is_mount'] == 'y' && !$app->system->mount_backup_dir($backup_dir) ) $run_backups = false; |
f17718
|
67 |
|
cc7a82
|
68 |
$records = $app->db->queryAllRecords("SELECT * FROM mail_user WHERE server_id = ? AND maildir != ''", intval($conf['server_id'])); |
2e1453
|
69 |
if(is_array($records) && $run_backups) { |
c220da
|
70 |
if(!is_dir($backup_dir)) { |
FS |
71 |
mkdir(escapeshellcmd($backup_dir), $backup_dir_permissions, true); |
|
72 |
} else { |
|
73 |
chmod(escapeshellcmd($backup_dir), $backup_dir_permissions); |
|
74 |
} |
|
75 |
|
f17718
|
76 |
foreach($records as $rec) { |
FS |
77 |
//* Do the mailbox backup |
66fa9b
|
78 |
$email = $rec['email']; |
FS |
79 |
$temp = explode("@",$email); |
|
80 |
$domain = $temp[1]; |
|
81 |
unset($temp); |
|
82 |
$domain_rec=$app->db->queryOneRecord("SELECT * FROM mail_domain WHERE domain = ?", $domain); |
|
83 |
|
f17718
|
84 |
if($rec['backup_interval'] == 'daily' or ($rec['backup_interval'] == 'weekly' && date('w') == 0) or ($rec['backup_interval'] == 'monthly' && date('d') == '01')) { |
370c6a
|
85 |
|
D |
86 |
$backupusername = 'root'; |
|
87 |
$backupgroup = 'root'; |
|
88 |
if ($global_config['backups_include_into_web_quota'] == 'y') { |
|
89 |
// this only works, if mail and webdomains are on the same server |
|
90 |
// find webdomain fitting to maildomain |
cc7a82
|
91 |
$sql = "SELECT * FROM web_domain WHERE domain = ?"; |
MC |
92 |
$webdomain = $app->db->queryOneRecord($sql, $domain_rec['domain']); |
370c6a
|
93 |
// if this is not also the website, find website now |
D |
94 |
if ($webdomain && ($webdomain['parent_domain_id'] != 0)) { |
|
95 |
do { |
cc7a82
|
96 |
$sql = "SELECT * FROM web_domain WHERE domain_id = ?"; |
MC |
97 |
$webdomain = $app->db->queryOneRecord($sql, $webdomain['parent_domain_id']); |
370c6a
|
98 |
} while ($webdomain && ($webdomain['parent_domain_id'] != 0)); |
D |
99 |
} |
|
100 |
// if webdomain is found, change username/group now |
|
101 |
if ($webdomain) { |
|
102 |
$backupusername = $webdomain['system_user']; |
|
103 |
$backupgroup = $webdomain['system_group']; |
|
104 |
} |
|
105 |
} |
f17718
|
106 |
|
c220da
|
107 |
$mail_backup_dir = $backup_dir.'/mail'.$domain_rec['domain_id']; |
f17718
|
108 |
if(!is_dir($mail_backup_dir)) mkdir($mail_backup_dir, 0750); |
FS |
109 |
chmod($mail_backup_dir, $backup_dir_permissions); |
370c6a
|
110 |
chown($mail_backup_dir, $backupusername); |
D |
111 |
chgrp($mail_backup_dir, $backupgroup); |
c220da
|
112 |
|
FS |
113 |
$mail_backup_file = 'mail'.$rec['mailuser_id'].'_'.date('Y-m-d_H-i'); |
f17718
|
114 |
|
f339eb
|
115 |
// in case of mdbox -> create backup with doveadm before zipping |
D |
116 |
if ($rec['maildir_format'] == 'mdbox') { |
|
117 |
if (empty($this->tmp_backup_dir)) $this->tmp_backup_dir = $rec['maildir']; |
|
118 |
// Create temporary backup-mailbox |
|
119 |
exec("su -c 'dsync backup -u \"".$rec["email"]."\" mdbox:".$this->tmp_backup_dir."/backup'", $tmp_output, $retval); |
|
120 |
|
|
121 |
if($backup_mode == 'userzip') { |
|
122 |
$mail_backup_file.='.zip'; |
|
123 |
exec('cd '.$this->tmp_backup_dir.' && zip '.$mail_backup_dir.'/'.$mail_backup_file.' -b /tmp -r backup > /dev/null && rm -rf backup', $tmp_output, $retval); |
|
124 |
} |
|
125 |
else { |
|
126 |
$mail_backup_file.='.tar.gz'; |
|
127 |
exec(escapeshellcmd('tar pczf '.$mail_backup_dir.'/'.$mail_backup_file.' --directory '.$this->tmp_backup_dir.' backup && rm -rf '.$this->tmp_backup_dir.'/backup'), $tmp_output, $retval); |
|
128 |
} |
|
129 |
|
|
130 |
if ($retval != 0) { |
|
131 |
// Cleanup |
|
132 |
if (file_exists($this->tmp_backup_dir.'/backup')) exec('rm -rf '.$this->tmp_backup_dir.'/backup'); |
|
133 |
} |
f17718
|
134 |
} |
f339eb
|
135 |
else { |
D |
136 |
$domain_dir=explode('/',$rec['maildir']); |
|
137 |
$_temp=array_pop($domain_dir);unset($_temp); |
|
138 |
$domain_dir=implode('/',$domain_dir); |
|
139 |
|
|
140 |
$parts=explode('/',$rec['maildir']); |
|
141 |
$source_dir=array_pop($parts); |
|
142 |
unset($parts); |
|
143 |
|
|
144 |
//* create archives |
|
145 |
if($backup_mode == 'userzip') { |
|
146 |
$mail_backup_file.='.zip'; |
|
147 |
exec('cd '.$domain_dir.' && zip '.$mail_backup_dir.'/'.$mail_backup_file.' -b /tmp -r '.$source_dir.' > /dev/null', $tmp_output, $retval); |
|
148 |
} else { |
|
149 |
/* Create a tar.gz backup */ |
|
150 |
$mail_backup_file.='.tar.gz'; |
|
151 |
exec(escapeshellcmd('tar pczf '.$mail_backup_dir.'/'.$mail_backup_file.' --directory '.$domain_dir.' '.$source_dir), $tmp_output, $retval); |
|
152 |
} |
|
153 |
} |
|
154 |
|
f17718
|
155 |
if($retval == 0){ |
6b166b
|
156 |
chown($mail_backup_dir.'/'.$mail_backup_file, $backupusername); |
DM |
157 |
chgrp($mail_backup_dir.'/'.$mail_backup_file, $backupgroup); |
f17718
|
158 |
chmod($mail_backup_dir.'/'.$mail_backup_file, 0640); |
FS |
159 |
/* Insert mail backup record in database */ |
6b166b
|
160 |
$filesize = filesize($mail_backup_dir.'/'.$mail_backup_file); |
bc0ad0
|
161 |
$sql = "INSERT INTO mail_backup (server_id, parent_domain_id, mailuser_id, backup_mode, tstamp, filename, filesize) VALUES (?, ?, ?, ?, ?, ?, ?)"; |
6b166b
|
162 |
$app->db->query($sql, $conf['server_id'], $domain_rec['domain_id'], $rec['mailuser_id'], $backup_mode, time(), $mail_backup_file, $filesize); |
DM |
163 |
if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql, $conf['server_id'], $domain_rec['domain_id'], $rec['mailuser_id'], $backup_mode, time(), $mail_backup_file, $filesize); |
|
164 |
unset($filesize); |
f17718
|
165 |
} else { |
FS |
166 |
/* Backup failed - remove archive */ |
|
167 |
if(is_file($mail_backup_dir.'/'.$mail_backup_file)) unlink($mail_backup_dir.'/'.$mail_backup_file); |
f339eb
|
168 |
// And remove backup-mdbox |
D |
169 |
if ($rec['maildir_format'] == 'mdbox') { |
|
170 |
if(file_exists($rec['maildir'].'/backup')) exec("su -c 'rm -rf ".$rec['maildir']."/backup'"); |
|
171 |
} |
2e1453
|
172 |
$app->log($mail_backup_file.' NOK:'.implode('',$tmp_output), LOGLEVEL_DEBUG); |
f17718
|
173 |
} |
FS |
174 |
/* Remove old backups */ |
|
175 |
$backup_copies = intval($rec['backup_copies']); |
|
176 |
$dir_handle = dir($mail_backup_dir); |
|
177 |
$files = array(); |
|
178 |
while (false !== ($entry = $dir_handle->read())) { |
e336d6
|
179 |
if($entry != '.' && $entry != '..' && substr($entry,0,5+strlen($rec['mailuser_id'])) == 'mail'.$rec['mailuser_id'].'_' && is_file($mail_backup_dir.'/'.$entry)) { |
f17718
|
180 |
$files[] = $entry; |
FS |
181 |
} |
|
182 |
} |
|
183 |
$dir_handle->close(); |
|
184 |
rsort($files); |
|
185 |
for ($n = $backup_copies; $n <= 10; $n++) { |
|
186 |
if(isset($files[$n]) && is_file($mail_backup_dir.'/'.$files[$n])) { |
|
187 |
unlink($mail_backup_dir.'/'.$files[$n]); |
bc0ad0
|
188 |
$sql = "DELETE FROM mail_backup WHERE server_id = ? AND parent_domain_id = ? AND filename = ?"; |
FS |
189 |
$app->db->query($sql, $conf['server_id'], $domain_rec['domain_id'], $files[$n]); |
|
190 |
if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql, $conf['server_id'], $domain_rec['domain_id'], $files[$n]); |
f17718
|
191 |
} |
FS |
192 |
} |
|
193 |
unset($files); |
|
194 |
unset($dir_handle); |
|
195 |
} |
|
196 |
/* Remove inactive backups */ |
66fa9b
|
197 |
if($rec['backup_interval'] == 'none' || $rec['backup_interval'] == '') { |
FS |
198 |
|
|
199 |
/* remove archives */ |
|
200 |
$mail_backup_dir = realpath($backup_dir.'/mail'.$domain_rec['domain_id']); |
f56297
|
201 |
$mail_backup_file = 'mail'.$rec['mailuser_id'].'_'; |
66fa9b
|
202 |
if(is_dir($mail_backup_dir)) { |
FS |
203 |
$dir_handle = opendir($mail_backup_dir.'/'); |
|
204 |
while ($file = readdir($dir_handle)) { |
|
205 |
if(!is_dir($file)) { |
ef5c45
|
206 |
if(substr($file,0,strlen($mail_backup_file)) == $mail_backup_file) { |
FS |
207 |
unlink ($mail_backup_dir.'/'.$file); |
|
208 |
} |
66fa9b
|
209 |
} |
FS |
210 |
} |
ef5c45
|
211 |
if(count(glob($mail_backup_dir."/*", GLOB_NOSORT)) === 0) { |
FS |
212 |
rmdir($mail_backup_dir); |
|
213 |
} |
66fa9b
|
214 |
} |
f17718
|
215 |
/* remove backups from db */ |
bc0ad0
|
216 |
$sql = "DELETE FROM mail_backup WHERE server_id = ? AND parent_domain_id = ? AND mailuser_id = ?"; |
FS |
217 |
$app->db->query($sql, $conf['server_id'], $domain_rec['domain_id'], $rec['mailuser_id']); |
|
218 |
if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql, $conf['server_id'], $domain_rec['domain_id'], $rec['mailuser_id']); |
66fa9b
|
219 |
|
f17718
|
220 |
} |
FS |
221 |
} |
634132
|
222 |
|
D |
223 |
// remove non-existing backups from database |
|
224 |
$backups = $app->db->queryAllRecords("SELECT * FROM mail_backup WHERE server_id = ?", $conf['server_id']); |
|
225 |
if(is_array($backups) && !empty($backups)){ |
|
226 |
foreach($backups as $backup){ |
2bc9e1
|
227 |
$mail_backup_dir = $backup_dir.'/mail'.$backup['parent_domain_id']; |
R |
228 |
if(!is_file($mail_backup_dir.'/'.$backup['filename'])){ |
634132
|
229 |
$sql = "DELETE FROM mail_backup WHERE server_id = ? AND parent_domain_id = ? AND filename = ?"; |
D |
230 |
$app->db->query($sql, $conf['server_id'], $backup['parent_domain_id'], $backup['filename']); |
|
231 |
if($app->db->dbHost != $app->dbmaster->dbHost) $app->dbmaster->query($sql); |
|
232 |
} |
|
233 |
} |
|
234 |
} |
52fe9e
|
235 |
if( $server_config['backup_dir_is_mount'] == 'y' ) $app->system->umount_backup_dir($backup_dir); |
66fa9b
|
236 |
//* end run_backups |
FS |
237 |
} |
f17718
|
238 |
} |
FS |
239 |
|
|
240 |
parent::onRunJob(); |
|
241 |
} |
|
242 |
|
|
243 |
/* this function is optional if it contains no custom code */ |
|
244 |
public function onAfterRun() { |
|
245 |
global $app; |
|
246 |
|
|
247 |
parent::onAfterRun(); |
|
248 |
} |
|
249 |
|
|
250 |
} |
|
251 |
|
|
252 |
?> |