PluginProbe
VikBooking Hotel Booking Engine & PMS / trunk
VikBooking Hotel Booking Engine & PMS vtrunk
1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 All 35 releases
vikbooking / admin / controllers / sampledata.php

sampledata.php in VikBooking Hotel Booking Engine & PMS trunk, at admin/controllers/sampledata.php

507 lines 12.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikBooking
4 * @subpackage core
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2019 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 JLoader::import('adapter.mvc.controllers.admin');
15
16 /**
17 * VikBooking Sampledata controller.
18 *
19 * @since 1.3.9
20 * @see JControllerAdmin
21 */
22 class VikBookingControllerSampledata extends JControllerAdmin
23 {
24 /**
25 * AJAX endpoint to load the sample data available.
26 * JSON encoded string outputted upon result.
27 *
28 * @return void
29 */
30 public function load()
31 {
32 $data = $this->getSampleData();
33
34 echo json_encode($data);
35 exit;
36 }
37
38 /**
39 * AJAX endpoint to install one sample data ID.
40 * JSON encoded result outputted or exception thrown.
41 *
42 * @return void
43 *
44 * @throws Exception
45 */
46 public function install()
47 {
48 $sample_data_id = VikRequest::getInt('sample_data_id', 0, 'request');
49 if (empty($sample_data_id)) {
50 throw new Exception('Empty Sample Data ID', 500);
51 }
52
53 // load all sample data available
54 $data = $this->getSampleData();
55
56 $sample_data_obj = null;
57
58 foreach ($data as $sdata) {
59 if (!is_object($sdata) || empty($sdata->id)) {
60 continue;
61 }
62 if ((int)$sdata->id == $sample_data_id) {
63 $sample_data_obj = new JRegistry($sdata);
64 break;
65 }
66 }
67
68 if (!$sample_data_obj) {
69 throw new Exception(sprintf('Sample Data ID [%s] not found', $sample_data_id), 404);
70 }
71
72 // response object
73 $response = new stdClass;
74 $response->status = 0;
75 $response->error = '';
76
77 // download and install selected sample data
78 try {
79 $res = $this->downloadSampleData($sample_data_obj);
80 if ($res) {
81 $response->status = 1;
82 }
83 } catch (Exception $e) {
84 $response->error = $e->getMessage();
85 }
86
87 if ($response->status) {
88 // silently add shortcodes to new WordPress pages
89 $this->addShortcodesToPages($sample_data_obj);
90 }
91
92 echo json_encode($response);
93 exit;
94 }
95
96 /**
97 * Returns a list of supported sample data.
98 *
99 * @return array A list of sample data.
100 */
101 private function getSampleData()
102 {
103 // build transient key
104 $transient = 'vikbooking_sampledata_' . md5(VIKBOOKING_SOFTWARE_VERSION);
105
106 // get cached sample data list
107 $data = get_transient($transient);
108
109 if ($data) {
110 // return cached transient
111 $data = json_decode($data);
112
113 return is_array($data) ? $data : array();
114 }
115
116 // default empty list
117 $data = array();
118
119 // instantiate HTTP transport
120 $http = new JHttp();
121
122 // build end-point URI
123 $uri = 'https://vikwp.com/api/?task=sampledata.list';
124
125 // build post data
126 $post = array(
127 'sku' => 'vbo',
128 'version' => VIKBOOKING_SOFTWARE_VERSION,
129 );
130
131 // load sample data from server
132 $response = $http->post($uri, $post);
133
134 if ($response->code == 200) {
135 // decode response
136 $data = json_decode($response->body);
137
138 // cache sample data list for an hour
139 set_transient($transient, json_encode($data), HOUR_IN_SECONDS);
140 }
141
142 return $data;
143 }
144
145 /**
146 * Downloads and installs one sample data.
147 *
148 * @param JRegistry $data The sample data registry object.
149 *
150 * @return boolean
151 *
152 * @uses installSampleData()
153 */
154 private function downloadSampleData($data)
155 {
156 // instantiate HTTP transport
157 $http = new JHttp();
158
159 // get selected sample data
160 $id = $data->get('id');
161
162 JLoader::import('adapter.filesystem.folder');
163
164 // get temporary dir
165 $tmp = get_temp_dir();
166
167 // clean temporary path
168 $tmp = rtrim(JPath::clean($tmp), DIRECTORY_SEPARATOR);
169
170 // make sure the folder exists
171 if (!is_dir($tmp)) {
172 throw new Exception(sprintf('Temporary folder [%s] does not exist', $tmp), 404);
173 }
174
175 // make sure the temporary folder is writable
176 if (!wp_is_writable($tmp)) {
177 throw new Exception(sprintf('Temporary folder [%s] is not writable', $tmp), 403);
178 }
179
180 // download end-point
181 $url = 'https://vikwp.com/api/?task=sampledata.download';
182
183 // init HTTP transport
184 $http = new JHttp();
185
186 // build sample data file name
187 $packname = 'sampledata-' . uniqid();
188
189 // build request headers
190 $headers = array(
191 // turn on stream to push body within a file
192 'stream' => true,
193 // define the filepath in which the data will be pushed
194 'filename' => $tmp . DIRECTORY_SEPARATOR . $packname . '.zip',
195 // make sure the request is non blocking
196 'blocking' => true,
197 // force timeout to 60 seconds
198 'timeout' => 60,
199 );
200
201 // build post data
202 $body = array(
203 'id' => $id,
204 );
205
206 // make connection with VikWP server
207 $response = $http->post($url, $body, $headers);
208
209 if ($response->code != 200) {
210 // raise error returned by VikWP
211 throw new Exception($response->body, $response->code);
212 }
213
214 // make sure the file has been saved
215 if (!JFile::exists($headers['filename'])) {
216 throw new Exception('ZIP package could not be saved on disk', 404);
217 }
218
219 // create destination folder for extracted elements
220 $dest = $tmp . DIRECTORY_SEPARATOR . $packname;
221
222 // make sure the destination folder doesn't exist
223 if (JFolder::exists($dest)) {
224 // remove it before proceeding with the extraction
225 JFolder::delete($dest);
226 }
227
228 // import archive class handler
229 JLoader::import('adapter.filesystem.archive');
230
231 // the package was downloaded successfully, let's extract it (onto TMP folder)
232 $extracted = JArchive::extract($headers['filename'], $dest);
233
234 // we no longer need the archive
235 JFile::delete($headers['filename']);
236
237 if (!$extracted) {
238 // an error occurred while extracting the files
239 throw new Exception(sprintf('Cannot extract files to [%s]', $tmp), 500);
240 }
241
242 // make sure the folder is intact
243 if (!JFolder::exists($dest)) {
244 // impossible to access the extracted elements
245 throw new Exception(sprintf('Cannot access extracted elements from [%s] folder', $dest), 404);
246 }
247
248 $error = null;
249
250 try {
251 // run sample data installation
252 $this->installSampleData($dest);
253 } catch (Exception $e) {
254 // safely catch error to finalize process
255 $error = $e;
256 }
257
258 // process complete, clean up the temporary folder before exiting
259 JFolder::delete($dest);
260
261 // in case of error, propagate it after deleting the extracted folder
262 if ($error) {
263 throw $error;
264 }
265
266 return true;
267 }
268
269 /**
270 * Interprets the manifest contained within the folder
271 * to install the sample data.
272 *
273 * @param string $folder The sample data folder.
274 *
275 * @return void
276 *
277 * @throws Exception
278 *
279 * @uses uninstallShortcodes()
280 * @uses installSqlRole()
281 * @uses installFilesRole()
282 */
283 private function installSampleData($folder)
284 {
285 // load manifest.json file
286 if (!is_file($folder . DIRECTORY_SEPARATOR . 'manifest.json')) {
287 // missing JSON manifest
288 throw new Exception('Manifest file not found', 404);
289 }
290
291 // open manifest file in read mode
292 $manifestFile = fopen($folder . DIRECTORY_SEPARATOR . 'manifest.json', 'r');
293
294 $manifest = '';
295
296 // load manifest content
297 while (!feof($manifestFile)) {
298 $manifest .= fread($manifestFile, 8192);
299 }
300
301 // close file
302 fclose($manifestFile);
303
304 // decode JSON
305 $manifest = json_decode($manifest);
306
307 if (!$manifest) {
308 // unable to JSON decode manifest
309 throw new Exception('Manifest file contains an invalid JSON', 500);
310 }
311
312 $dbo = JFactory::getDbo();
313
314 // look for uninstall queries
315 if (isset($manifest->uninstall)) {
316 // iterate queries to clean any existing records
317 foreach ($manifest->uninstall as $q) {
318 try {
319 // check if we are uninstalling the shortcodes
320 if (preg_match("/vikbooking_wpshortcodes/i", $q)) {
321 // uninstall the existing shortcodes
322 $this->uninstallShortcodes();
323 }
324
325 // launch query
326 $dbo->setQuery($q);
327 $dbo->execute();
328 } catch (Exception $e) {
329 // malformed query, suppress error and go ahead
330 if (VIKBOOKING_DEBUG) {
331 // propagate error in case of debug mode enabled
332 throw $e;
333 }
334 }
335 }
336 }
337
338 // look for installers
339 if (isset($manifest->installers)) {
340 // iterate installers
341 foreach ($manifest->installers as $install) {
342 try {
343 // switch case role to invoke the proper installation method
344 switch ($install->role) {
345 case 'sql':
346 case 'insert':
347 $this->installSqlRole($install->data);
348 break;
349
350 case 'media':
351 case 'folder':
352 $this->installFilesRole($install->data->destination, $install->data->files, $folder);
353 break;
354 }
355 } catch (Exception $e) {
356 // malformed role, suppress error and go ahead
357 if (VIKBOOKING_DEBUG) {
358 // propagate error in case of debug mode enabled
359 throw $e;
360 }
361 }
362 }
363 }
364 }
365
366 /**
367 * Executes the specified queries.
368 *
369 * @param mixed $queries Either a query string or an array.
370 *
371 * @return void
372 */
373 private function installSqlRole($queries)
374 {
375 if (!is_array($queries)) {
376 $queries = array($queries);
377 }
378
379 $dbo = JFactory::getDbo();
380
381 // iterate queries one by one
382 foreach ($queries as $q) {
383 $dbo->setQuery($q);
384 $dbo->execute();
385 }
386 }
387
388 /**
389 * Moves the files into the related folders.
390 *
391 * @param string $dest The destination folder.
392 * @param mixed $files Either a file or an array.
393 * @param string $dir The current directory.
394 *
395 * @return void
396 */
397 private function installFilesRole($dest, $files, $dir)
398 {
399 // load update manager class for backup/mirroring of files
400 VikBookingLoader::import('update.manager');
401
402 // set destination by prepending plugin base path
403 $dest = VIKBOOKING_BASE . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $dest);
404
405 // make sure to always parse an array
406 if (!is_array($files)) {
407 $files = array($files);
408 }
409
410 // copy files and create a backup copy from each file
411 foreach ($files as $file) {
412 // fetch file path
413 $path = JPath::clean($dir . DIRECTORY_SEPARATOR . $file);
414
415 // fetch destination file path
416 $destFile = JPath::clean($dest . DIRECTORY_SEPARATOR . basename($file));
417
418 // copy file in its destination
419 $res = JFile::copy($path, $destFile);
420
421 if ($res) {
422 // trigger mirroring action for new file uploaded
423 VikBookingUpdateManager::triggerUploadBackup($destFile);
424 }
425 }
426 }
427
428 /**
429 * Uninstalls all the pages that have been assigned
430 * to the existing shortcodes.
431 *
432 * @return void
433 */
434 private function uninstallShortcodes()
435 {
436 // get shortcode admin model
437 $model = JModel::getInstance('vikbooking', 'shortcodes');
438
439 // get all existing shortcodes
440 $shortcodes = $model->all(array('createdon', 'post_id'));
441
442 // iterate all shortcodes found
443 foreach ($shortcodes as $shortcode) {
444 // make sure the shortcode has been assigned to a post
445 if ($shortcode->post_id) {
446 // get post details
447 $post = get_post((int) $shortcode->post_id);
448
449 // convert shortcode creation date
450 $shortcode->createdon = new JDate($shortcode->createdon);
451 // convert post creation date
452 $post->post_date_gmt = new JDate($post->post_date_gmt);
453
454 // compare ephocs and make sure the post was not created before the shortcode
455 if ((int) $shortcode->createdon->format('U') <= (int) $post->post_date_gmt->format('U')) {
456 // permanently delete post
457 wp_delete_post($post->ID, $force_delete = true);
458 }
459 }
460 }
461 }
462
463
464 /**
465 * Finalizes the installation of a sample data by creating one
466 * new WordPress page/post for each Shortcode installed.
467 *
468 * @param JRegistry $data The (optional) sample data chosen registry object.
469 *
470 * @return boolean
471 */
472 private function addShortcodesToPages($data = null)
473 {
474 $model = JModel::getInstance('vikbooking', 'shortcodes');
475
476 $shortcodes = $model->all();
477
478 if (!is_array($shortcodes) || !count($shortcodes)) {
479 return false;
480 }
481
482 foreach ($shortcodes as $item) {
483 if (!empty($item->post_id)) {
484 // shortcode already linked to a page
485 continue;
486 }
487
488 /**
489 * Add a new page (we allow a WP_ERROR to be returned in case of failure).
490 * This should automatically trigger the hook that we use to link the Shortcode
491 * to the new page/post ID, and so there's no need to update the item.
492 */
493 $new_page_id = wp_insert_post(array(
494 'post_title' => (!empty($item->name) ? $item->name : JText::translate($item->title)),
495 'post_content' => $item->shortcode,
496 'post_status' => 'publish',
497 'post_type' => 'page',
498 ), true);
499
500 // we ignore if the page was created or if an error occurred
501 }
502
503 return true;
504 }
505
506 }
507