PluginProbe ʕ •ᴥ•ʔ
VikAppointments Services Booking Calendar / 1.2.21
VikAppointments Services Booking Calendar v1.2.21
1.2.21 1.2.20 trunk 1.2.17 1.2.18 1.2.19
vikappointments / site / helpers / libraries / backup / manager.php
vikappointments / site / helpers / libraries / backup Last commit date
export 4 days ago import 4 days ago index.html 4 days ago manager.php 4 days ago
manager.php
310 lines
1 <?php
2 /**
3 * @package VikAppointments
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2021 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 /**
15 * Backups director class.
16 *
17 * @since 1.7.1
18 */
19 class VAPBackupManager
20 {
21 /**
22 * Indicates the minimum required version while creating a
23 * new backup on Joomla. This value should be changed everytime
24 * something in the database structure is altered.
25 *
26 * @var string
27 */
28 const MINIMUM_REQUIRED_VERSION_JOOMLA = '1.7.4';
29
30 /**
31 * Indicates the minimum required version while creating a
32 * new backup on WordPress. This value should be changed everytime
33 * something in the database structure is altered.
34 *
35 * @var string
36 */
37 const MINIMUM_REQUIRED_VERSION_WORDPRESS = '1.2.11';
38
39 /**
40 * An associative array containing the supported export types, where the
41 * key is equals to the type ID and the value is the type instance.
42 *
43 * @var array
44 */
45 protected static $exportTypes = null;
46
47 /**
48 * Creates a new backup.
49 *
50 * @param string $type The type of backup to execute.
51 * @param array $options A configuration array.
52 * - folder string The path in which the archive should be saved.
53 * if not specified, the system temporary path will be used.
54 * - filename string An optional filename to use for the archive. If not specified
55 * the filename will be equals to the current time.
56 * - prefix string An optional prefix to prepend to the filename.
57 *
58 * @return string The path of the backup (a ZIP archive).
59 *
60 * @throws Exception
61 */
62 public static function create($type, array $options = [])
63 {
64 // ignore the maximum execution time
65 set_time_limit(0);
66
67 $dispatcher = VAPFactory::getEventDispatcher();
68
69 if (empty($options['folder']))
70 {
71 // before starting the export, make sure the temporary folder is supported
72 $options['folder'] = JFactory::getApplication()->get('tmp_path');
73
74 if (!$options['folder'] || !JFolder::exists($options['folder']))
75 {
76 throw new Exception('The temporary folder seems to be not set', 500);
77 }
78
79 // remove trailing directory separator
80 $options['folder'] = preg_replace("/[\/\\\\]$/", '', $options['folder']);
81 }
82
83 if (empty($options['filename']))
84 {
85 // use the current date and time as file name
86 $options['filename'] = 'backup_' . $type . '_' . JFactory::getDate()->format('Y-m-d H-i-s');
87 }
88
89 if (!empty($options['prefix']))
90 {
91 // include a prefix before the file name
92 $options['filename'] = $options['prefix'] . $options['filename'];
93 }
94
95 // build archive path
96 $path = $options['folder'] . DIRECTORY_SEPARATOR . $options['filename'];
97
98 // create backup export director
99 VAPLoader::import('libraries.backup.export.director');
100 $director = new VAPBackupExportDirector($path);
101
102 // set the manifest version equals to the minimum required one
103 $director->setVersion(static::MINIMUM_REQUIRED_VERSION_JOOMLA, 'joomla');
104 $director->setVersion(static::MINIMUM_REQUIRED_VERSION_WORDPRESS, 'wordpress');
105
106 // fetch all the supported export types
107 $exportTypes = static::getExportTypes();
108
109 // check whether the requested support type exists
110 if (!isset($exportTypes[$type]))
111 {
112 // type not found
113 throw new Exception(sprintf('Cannot import [%s] export type', $type), 404);
114 }
115
116 // get export type instance
117 $handler = $exportTypes[$type];
118
119 $error = null;
120
121 try
122 {
123 // build the installers manifest
124 $handler->build($director);
125
126 /**
127 * Trigger event to allow third party plugins to extend the backup feature.
128 * This hook is useful to include third-party tables and files into the
129 * backup archive.
130 *
131 * It is possible to attach a database table into the backup by using:
132 * $director->attachRule('sqlfile', '#__extensions');
133 *
134 * @param string $type The type of backup to execute.
135 * @param VAPBackupExportDirector $director The instance used to manage the backup.
136 * @param array $options An array of options.
137 *
138 * @return void
139 *
140 * @since 1.7.1
141 */
142 $dispatcher->trigger('onBuildBackupVikAppointments', [$type, $director, $options]);
143
144 // compress the archive and obtain the full path
145 $archivePath = $director->compress();
146 }
147 catch (Exception $e)
148 {
149 // catch any error
150 $error = $e;
151 }
152
153 // always delete archive folder
154 JFolder::delete($path);
155
156 if ($error)
157 {
158 // in case of error, propagate it only after cleaning the dump
159 throw $error;
160 }
161
162 return $archivePath;
163 }
164
165 /**
166 * Restores an existing backup.
167 *
168 * @param string $path The path of the backup to restore.
169 *
170 * @return void
171 *
172 * @throws Exception
173 */
174 public static function restore($path)
175 {
176 // ignore the maximum execution time
177 set_time_limit(0);
178
179 // make sure the archive exists
180 if (!JFile::exists($path))
181 {
182 // unable to find the specified archive
183 throw new Exception(sprintf('Backup [%s] not found', $path), 404);
184 }
185
186 // create a unique extraction folder
187 $extractdir = dirname($path) . DIRECTORY_SEPARATOR . uniqid();
188
189 // extract the given backup
190 VAPLoader::import('libraries.archive.factory');
191 $status = VAPArchiveFactory::extract($path, $extractdir);
192
193 if (!$status)
194 {
195 // cannot extract the archive
196 throw new Exception(sprintf('Unable to extract [%s] into [%s]', $path, $extractdir), 500);
197 }
198
199 // create backup import director
200 VAPLoader::import('libraries.backup.import.director');
201 $director = new VAPBackupImportDirector($extractdir);
202
203 // set the manifest version equals to the minimum required one, according to the CMS in use
204 if (VersionListener::isJoomla())
205 {
206 $director->setVersion(static::MINIMUM_REQUIRED_VERSION_JOOMLA);
207 }
208 else
209 {
210 $director->setVersion(static::MINIMUM_REQUIRED_VERSION_WORDPRESS);
211 }
212
213 $error = null;
214
215 try
216 {
217 // process the backup
218 $director->process();
219 }
220 catch (Exception $e)
221 {
222 $error = $e;
223 }
224
225 // always delete extracted folder
226 JFolder::delete($extractdir);
227
228 if ($error)
229 {
230 // in case of error, propagate it only after cleaning the dump
231 throw $error;
232 }
233 }
234
235 /**
236 * Returns a list of supported export types.
237 *
238 * @return array
239 */
240 public static function getExportTypes()
241 {
242 if (!is_null(static::$exportTypes))
243 {
244 // export types already fetched
245 return static::$exportTypes;
246 }
247
248 // register default include paths
249 $includePaths = [
250 dirname(__FILE__) . DIRECTORY_SEPARATOR . 'export' . DIRECTORY_SEPARATOR . 'type',
251 ];
252
253 /**
254 * Trigger event to allow third party plugins to register additional include paths,
255 * from which the system can load other backup handlers.
256 *
257 * @return mixed An array of include paths or a string.
258 *
259 * @since 1.7.1
260 */
261 $paths = VAPFactory::getEventDispatcher()->trigger('onLoadBackupExportTypesVikAppointments');
262
263 // merge returned paths with the existing ones
264 foreach ($paths as $path)
265 {
266 if (is_string($path))
267 {
268 $includePaths[] = $path;
269 }
270 else if (is_array($path))
271 {
272 $includePaths = array_merge($includePaths, $path);
273 }
274 }
275
276 static::$exportTypes = [];
277
278 // iterate include paths to fetch all the supported export types
279 foreach ($includePaths as $path)
280 {
281 // get all PHP files inside the folder
282 $files = JFolder::files($path, '\.php$', $recurse = false, $fullpath = true);
283
284 // iterate all PHP files
285 foreach ($files as $file)
286 {
287 // get file name without extension
288 $type = basename($file, '.php');
289
290 // load the file
291 require_once $file;
292
293 // build class name
294 $classname = 'VAPBackupExportType' . ucfirst($type);
295
296 // check whether the class exists
297 if (!class_exists($classname))
298 {
299 throw new Exception(sprintf('Cannot find [%s] export type class', $classname), 404);
300 }
301
302 // instantiate and register export type handler
303 static::$exportTypes[$type] = new $classname();
304 }
305 }
306
307 return static::$exportTypes;
308 }
309 }
310