Merge pull request #7535 from stephenwaite/bug_fix_w1
[openemr.git] / interface / main / backup.php
blobeb7628ab92bc42f5c2e4db66fd5bcfabd86926f5
1 <?php
3 /**
4 * This script creates a backup tarball, emr_backup.tar, and sends
5 * it to the user's browser for download. The tarball includes:
7 * an OpenEMR database dump (openemr.sql.gz)
8 * the OpenEMR web directory (openemr.tar.gz)
10 * The OpenEMR web directory is important because it includes config-
11 * uration files, patient documents, and possible customizations, and
12 * also because the database structure is dependent on the installed
13 * OpenEMR version.
15 * This script depends on execution of some external programs:
16 * mysqldump & pg_dump. It has been tested with Debian and Ubuntu
17 * Linux and with Windows XP.
19 * DO NOT PRESUME THAT IT WORKS FOR YOU until you have successfully
20 * tested a restore!
22 * @package OpenEMR
23 * @link http://www.open-emr.org
24 * @author Rod Roark <rod@sunsetsystems.com>
25 * @author Bill Cernansky (www.mi-squared.com)
26 * @author Brady Miller <brady.g.miller@gmail.com>
27 * @author Stephen Waite <stephen.waite@cmsvt.com>
28 * @copyright Copyright (c) 2008-2014, 2016, 2021-2022 Rod Roark <rod@sunsetsystems.com>
29 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
30 * @copyright Copyright (c) 2019 Stephen Waite <stephen.waite@cmsvt.com>
31 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
34 set_time_limit(0);
35 require_once("../globals.php");
36 require_once("$srcdir/layout.inc.php");
37 require_once("$srcdir/patient.inc.php");
39 use OpenEMR\Common\Acl\AclMain;
40 use OpenEMR\Common\Csrf\CsrfUtils;
41 use OpenEMR\Common\Logging\EventAuditLogger;
42 use OpenEMR\Common\Twig\TwigContainer;
43 use OpenEMR\Core\Header;
45 if (!empty($_POST)) {
46 if (!CsrfUtils::verifyCsrfToken($_POST["csrf_token_form"])) {
47 CsrfUtils::csrfNotVerified();
51 if (!extension_loaded('zlib')) {
52 die('Abort ' . basename(__FILE__) . ' : Missing zlib extensions');
55 if (!function_exists('gzopen') && function_exists('gzopen64')) {
56 function gzopen($filename, $mode, $use_include_path = 0)
58 return gzopen64($filename, $mode, $use_include_path);
62 if (!AclMain::aclCheckCore('admin', 'super')) {
63 echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Backup")]);
64 exit;
67 // When automatically including lists used in selected layouts, these lists are not included.
68 $excluded_lists = array(
69 'allergy_issue_list',
70 'boolean',
71 'education_level',
72 'ethrace',
73 'Gender',
74 'genhivhist',
75 'occupations',
76 'Relation_to_Client',
77 'sex',
78 'Sexual_Orientation',
79 'yesno',
82 $BTN_TEXT_CREATE = xl('Create Backup');
83 $BTN_TEXT_EXPORT = xl('Export Configuration');
84 $BTN_TEXT_IMPORT = xl('Import Configuration');
85 $BTN_TEXT_LOG = xl('Backup/Delete Log Data');
86 // ViSolve: Create Log Backup button
87 $BTN_TEXT_CREATE_EVENTLOG = xl('Create Eventlog Backup');
89 $form_step = isset($_POST['form_step']) ? trim($_POST['form_step']) : '0';
90 $form_status = isset($_POST['form_status' ]) ? trim($_POST['form_status' ]) : '';
92 if (!empty($_POST['form_export'])) {
93 $form_step = 101;
96 if (!empty($_POST['form_import'])) {
97 $form_step = 201;
100 //ViSolve: Assign Unique Number for the Log Creation
101 if (!empty($_POST['form_backup'])) {
102 $form_step = 301;
105 if (!empty($_POST['form_logarchive'])) {
106 $form_step = 401;
109 // When true the current form will submit itself after a brief pause.
110 $auto_continue = false;
112 # set up main paths
113 $backup_file_prefix = "emr_backup";
114 $backup_file_suffix = ".tar";
115 $TMP_BASE = $GLOBALS['temporary_files_dir'] . "/openemr_web_backup";
116 $BACKUP_DIR = $TMP_BASE . "/emr_backup";
117 $TAR_FILE_PATH = $TMP_BASE . DIRECTORY_SEPARATOR . $backup_file_prefix . $backup_file_suffix;
118 $EXPORT_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_config.sql";
119 $MYSQL_PATH = realpath($GLOBALS['mysql_bin_dir']);
120 $PERL_PATH = realpath($GLOBALS['perl_bin_dir']);
122 if ($form_step == 6) {
123 header("Pragma: public");
124 header("Expires: 0");
125 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
126 header("Content-Type: application/force-download");
127 header("Content-Length: " . filesize($TAR_FILE_PATH));
128 header("Content-Disposition: attachment; filename=" . basename($TAR_FILE_PATH));
129 header("Content-Description: File Transfer");
131 if (is_file($TAR_FILE_PATH)) {
132 $chunkSize = 1024 * 1024;
133 $handle = fopen($TAR_FILE_PATH, 'rb');
134 while (!feof($handle)) {
135 $buffer = fread($handle, $chunkSize);
136 echo $buffer;
137 ob_flush();
138 flush();
140 fclose($handle);
141 } else {
142 obliterate_dir($BACKUP_DIR);
143 $dieMsg = xlt("Backup Failed missing generated file");
144 die($dieMsg);
146 unlink($TAR_FILE_PATH);
147 obliterate_dir($BACKUP_DIR);
148 exit(0);
151 if ($form_step == 104) {
152 header("Pragma: public");
153 header("Expires: 0");
154 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
155 header("Content-Type: application/force-download");
156 header("Content-Length: " . filesize($EXPORT_FILE));
157 header("Content-Disposition: attachment; filename=" . basename($EXPORT_FILE));
158 header("Content-Description: File Transfer");
159 readfile($EXPORT_FILE);
160 unlink($EXPORT_FILE);
161 exit(0);
164 // CSV export of lists.
166 if ($form_step == 102.1) {
167 if (is_array($_POST['form_sel_lists'] ?? '')) {
168 header("Pragma: public");
169 header("Expires: 0");
170 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
171 header("Content-Type: application/force-download; charset=utf-8");
172 header("Content-Disposition: attachment; filename=lists.csv");
173 header("Content-Description: File Transfer");
174 // Prepend a BOM (Byte Order Mark) header to mark the data as UTF-8. See:
175 // http://stackoverflow.com/questions/155097/microsoft-excel-mangles-diacritics-in-csv-files
176 // http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html
177 echo "\xEF\xBB\xBF";
178 // CSV headers:
179 echo csvEscape(xl('List')) . ',';
180 echo csvEscape(xl('ID')) . ',';
181 echo csvEscape(xl('Title')) . ',';
182 echo csvEscape(xl('Translated')) . ',';
183 echo csvEscape(xl('Order')) . ',';
184 echo csvEscape(xl('Default')) . ',';
185 echo csvEscape(xl('Active')) . ',';
186 echo csvEscape(xl('Global ID')) . ',';
187 echo csvEscape(xl('Notes')) . ',';
188 echo csvEscape(xl('Codes')) . '';
189 echo "\n";
190 foreach ($_POST['form_sel_lists'] as $listid) {
191 $res = sqlStatement(
192 "SELECT * FROM list_options WHERE list_id = ? ORDER BY seq, title",
193 array($listid)
195 while ($row = sqlFetchArray($res)) {
196 $xtitle = xl_list_label($row['title']);
197 if ($xtitle === $row['title']) {
198 $xtitle = '';
200 echo csvEscape($row['list_id']) . ',';
201 echo csvEscape($row['option_id']) . ',';
202 echo csvEscape($row['title']) . ',';
203 echo csvEscape($xtitle) . ',';
204 echo csvEscape($row['seq']) . ',';
205 echo csvEscape($row['is_default']) . ',';
206 echo csvEscape($row['activity']) . ',';
207 echo csvEscape($row['mapping']) . ',';
208 echo csvEscape($row['notes']) . ',';
209 echo csvEscape($row['codes']) . '';
210 echo "\n";
214 exit(0);
217 // CSV export of layouts.
219 if ($form_step == 102.2) {
220 if (is_array($_POST['form_sel_layouts'] ?? '')) {
221 header("Pragma: public");
222 header("Expires: 0");
223 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
224 header("Content-Type: application/force-download; charset=utf-8");
225 header("Content-Disposition: attachment; filename=layouts.csv");
226 header("Content-Description: File Transfer");
227 // Prepend a BOM (Byte Order Mark) header to mark the data as UTF-8. See:
228 // http://stackoverflow.com/questions/155097/microsoft-excel-mangles-diacritics-in-csv-files
229 // http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html
230 echo "\xEF\xBB\xBF";
231 // CSV headers:
232 echo csvEscape(xl('Form')) . ',';
233 echo csvEscape(xl('Order')) . ',';
234 echo csvEscape(xl('Source')) . ',';
235 echo csvEscape(xl('Group')) . ',';
236 echo csvEscape(xl('ID')) . ',';
237 echo csvEscape(xl('Label')) . ',';
238 echo csvEscape(xl('Translated')) . ',';
239 echo csvEscape(xl('UOR')) . ',';
240 echo csvEscape(xl('Type')) . ',';
241 echo csvEscape(xl('Width')) . ',';
242 echo csvEscape(xl('Height')) . ',';
243 echo csvEscape(xl('Max')) . ',';
244 echo csvEscape(xl('List')) . ',';
245 echo csvEscape(xl('Label Cols')) . ',';
246 echo csvEscape(xl('Data Cols')) . ',';
247 echo csvEscape(xl('Options')) . ',';
248 echo csvEscape(xl('Description')) . ',';
249 echo csvEscape(xl('Translated')) . ',';
250 echo csvEscape(xl('Conditions')) . '';
251 echo "\n";
252 foreach ($_POST['form_sel_layouts'] as $layoutid) {
253 $res = sqlStatement(
254 "SELECT l.*, p.grp_title FROM layout_options AS l " .
255 "JOIN layout_group_properties AS p ON p.grp_form_id = l.form_id AND " .
256 "p.grp_group_id = l.group_id AND p.grp_activity = 1 " .
257 "WHERE l.form_id = ? ORDER BY l.group_id, l.seq, l.title",
258 array($layoutid)
260 while ($row = sqlFetchArray($res)) {
261 $xtitle = xl_layout_label($row['title']);
262 if ($xtitle === $row['title']) {
263 $xtitle = '';
265 $xdesc = $row['description'];
266 if (substr($xdesc, 0, 1) != '<') {
267 $xdesc = xl_layout_label($xdesc);
269 if ($xdesc === $row['description']) {
270 $xdesc = '';
272 echo csvEscape($row['form_id' ]) . ',';
273 echo csvEscape($row['seq' ]) . ',';
274 echo csvEscape($sources[$row['source']]) . ',';
275 echo csvEscape($row['grp_title' ]) . ',';
276 echo csvEscape($row['field_id' ]) . ',';
277 echo csvEscape($row['title' ]) . ',';
278 echo csvEscape($xtitle) . ',';
279 echo csvEscape($UOR[$row['uor']]) . ',';
280 echo csvEscape($datatypes[$row['data_type']]) . ',';
281 echo csvEscape($row['fld_length' ]) . ',';
282 echo csvEscape($row['fld_rows' ]) . ',';
283 echo csvEscape($row['max_length' ]) . ',';
284 echo csvEscape($row['list_id' ]) . ',';
285 echo csvEscape($row['titlecols' ]) . ',';
286 echo csvEscape($row['datacols' ]) . ',';
287 echo csvEscape($row['edit_options']) . ',';
288 echo csvEscape($row['description' ]) . ',';
289 echo csvEscape($xdesc) . ',';
290 echo csvEscape($row['conditions' ]) . '';
291 echo "\n";
295 exit(0);
298 // CSV export of old log entries.
300 if ($form_step == 402) {
301 if (!empty($_POST['form_end_date'])) {
302 $end_date = DateToYYYYMMDD($_POST['form_end_date']);
303 // This is the "filename" for the Content-Disposition header.
304 $filename = "log_archive_{$end_date}.csv";
306 $outfile = tempnam($GLOBALS['temporary_files_dir'], 'OET');
307 if ($outfile === false) {
308 die("tempnam('" . text($GLOBALS['temporary_files_dir']) . "','OET') failed.\n");
310 $hout = fopen($outfile, "w");
311 $wcount = 0;
313 // Prepend a BOM (Byte Order Mark) header to mark the data as UTF-8. See:
314 // http://stackoverflow.com/questions/155097/microsoft-excel-mangles-diacritics-in-csv-files
315 // http://crashcoursing.blogspot.com/2011/05/exporting-csv-with-special-characters.html
316 $out = "\xEF\xBB\xBF";
317 // CSV headers:
318 $out .= csvEscape(xl('id')) . ',';
319 $out .= csvEscape(xl('date')) . ',';
320 $out .= csvEscape(xl('event')) . ',';
321 $out .= csvEscape(xl('user')) . ',';
322 $out .= csvEscape(xl('groupname')) . ',';
323 $out .= csvEscape(xl('comments')) . ',';
324 $out .= csvEscape(xl('user_notes')) . ',';
325 $out .= csvEscape(xl('patient_id')) . ',';
326 $out .= csvEscape(xl('success')) . ',';
327 $out .= csvEscape(xl('checksum')) . ',';
328 $out .= csvEscape(xl('crt_user')) . '';
329 $out .= "\n";
330 fwrite($hout, $out);
332 // Somewhere there's a memory leak in the ADODB stuff. We do multiple selects to
333 // work around this.
334 $lastid = 0;
335 while (true) {
336 $res = sqlStatementNoLog(
337 "SELECT * FROM `log` WHERE `date` <= ? AND `id` > ? ORDER BY `id` LIMIT 50000",
338 array("$end_date 23:59:59", $lastid)
340 if (!sqlNumRows($res)) {
341 break;
343 while ($row = sqlFetchArray($res)) {
344 $out = csvEscape($row['id' ]) . ',' .
345 csvEscape($row['date' ]) . ',' .
346 csvEscape($row['event' ]) . ',' .
347 csvEscape($row['user' ]) . ',' .
348 csvEscape($row['groupname' ]) . ',' .
349 csvEscape($row['comments' ]) . ',' .
350 csvEscape($row['user_notes']) . ',' .
351 csvEscape($row['patient_id']) . ',' .
352 csvEscape($row['success' ]) . ',' .
353 csvEscape($row['checksum' ]) . ',' .
354 csvEscape($row['crt_user' ]) . '' .
355 "\n";
356 if (!fwrite($hout, $out)) {
357 die("fwrite() failed!");
359 $lastid = $row['id'];
363 fclose($hout);
365 // Do compression if requested (it is!)
366 if (true) {
367 $zip = new ZipArchive();
368 $zippedoutfile = tempnam($GLOBALS['temporary_files_dir'], 'OEZ');
369 if ($zippedoutfile === false) {
370 die("tempnam('" . text($GLOBALS['temporary_files_dir']) . "','OEZ') failed.\n");
372 if ($zip->open($zippedoutfile, ZIPARCHIVE::OVERWRITE) !== true) {
373 die(xlt('Cannot create file') . " '$zipname'\n");
375 if (!$zip->addFile($outfile, $filename)) {
376 die(xlt('Cannot add to archive') . " '$zipname'\n");
378 $zip->close();
379 $filename .= '.zip';
380 unlink($outfile);
381 $outfile = $zippedoutfile;
384 header("Pragma: public");
385 header("Expires: 0");
386 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
387 header("Content-Type: application/force-download; charset=utf-8");
388 header("Content-Disposition: attachment; filename=$filename");
389 header("Content-Description: File Transfer");
390 header("Content-Length: " . filesize($outfile));
391 readfile($outfile);
392 unlink($outfile);
393 } else {
394 die(xlt("End date is missing!"));
396 exit(0);
400 <html>
402 <head>
403 <?php Header::setupHeader(['datetime-picker']); ?>
404 <title><?php echo xlt('Backup'); ?></title>
406 <script>
408 $(function () {
409 $('.datepicker').datetimepicker({
410 <?php $datetimepicker_timepicker = false; ?>
411 <?php $datetimepicker_showseconds = false; ?>
412 <?php $datetimepicker_formatInput = true; ?>
413 <?php require($GLOBALS['srcdir'] . '/js/xl/jquery-datetimepicker-2-5-4.js.php'); ?>
414 <?php // can add any additional javascript settings to datetimepicker here; need to prepend first setting with a comma ?>
418 // Called from export page or log archive page to specify what it will do.
419 // 102 = SQL export of selected tables, lists and layouts
420 // 102.1 = Download selected lists as CSV
421 // 102.2 = download selected layouts as CSV
422 // 402 = CSV export of log archive
423 // 405 = Delete from the log
425 function export_submit(step) {
426 var f = document.forms[0];
427 f.form_step.value = step;
428 top.restoreSession();
429 f.submit();
432 </script>
434 </head>
436 <body class="body_top">
437 <center>
438 &nbsp;<br />
439 <form method='post' action='backup.php' enctype='multipart/form-data' onsubmit='return top.restoreSession()'>
440 <input type="hidden" name="csrf_token_form" value="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
442 <table<?php echo ($form_step != 101) ? " style='width:50em'" : ""; ?>>
443 <tr>
444 <td>
446 <?php
447 $cmd = '';
448 // $cmdarr exists because some commands may be too long for a single exec.
449 $cmdarr = array();
450 $mysql_cmd = $MYSQL_PATH . DIRECTORY_SEPARATOR . 'mysql';
451 $mysql_dump_cmd = $mysql_cmd . 'dump';
452 $mysql_ssl = '';
453 if (file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-ca")) {
454 // Support for mysql SSL encryption
455 $mysql_ssl = " --ssl-ca=" . escapeshellarg($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-ca") . " ";
456 if (
457 file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-key") &&
458 file_exists($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-cert")
460 // Support for mysql SSL client based cert authentication
461 $mysql_ssl .= "--ssl-cert=" . escapeshellarg($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-cert") . " ";
462 $mysql_ssl .= "--ssl-key=" . escapeshellarg($GLOBALS['OE_SITE_DIR'] . "/documents/certificates/mysql-key") . " ";
466 $file_to_compress = ''; // if named, this iteration's file will be gzipped after it is created
467 $eventlog = 0; // Eventlog Flag
469 if ($form_step == 0) {
470 echo "<table>\n";
471 echo " <tr>\n";
472 echo " <td><input class='btn btn-secondary' type='submit' name='form_create' value='" . attr($BTN_TEXT_CREATE) . "' /></td>\n";
473 echo " <td>" . xlt('Create and download a full backup') . "</td>\n";
474 echo " </tr>\n";
475 // The config import/export feature is optional.
476 if (!empty($GLOBALS['configuration_import_export'])) {
477 echo " <tr>\n";
478 echo " <td><input class='btn btn-secondary' type='submit' name='form_export' value='" . attr($BTN_TEXT_EXPORT) . "' /></td>\n";
479 echo " <td>" . xlt('Download configuration data') . "</td>\n";
480 echo " </tr>\n";
481 echo " <tr>\n";
482 echo " <td><input class='btn btn-secondary' type='submit' name='form_import' value='" . attr($BTN_TEXT_IMPORT) . "' /></td>\n";
483 echo " <td>" . xlt('Upload configuration data') . "</td>\n";
484 echo " </tr>\n";
485 echo " <tr>\n";
486 echo " <td><input class='btn btn-secondary' type='submit' name='form_logarchive' value='" . attr($BTN_TEXT_LOG) . "' /></td>\n";
487 echo " <td>" . xlt('Download and/or delete log data') . "</td>\n";
488 echo " </tr>\n";
491 // ViSolve : Add ' Create Log table backup Button'
492 echo " <tr>\n";
493 echo " <td><input class='btn btn-secondary' type='submit' name='form_backup' value='" . attr($BTN_TEXT_CREATE_EVENTLOG) . "' /></td>\n";
494 echo " <td>" . xlt('Create Eventlog Backup') . "</td>\n";
495 echo " </tr>\n";
496 echo " <tr>\n";
497 echo " <td></td><td class='text'>" . xlt('Note that the Eventlog Backup is currently set to save in the following folder') . ": " . text($GLOBALS['backup_log_dir']) . " . " . xlt('Recommend setting the Path for Event Log Backup in Globals settings in the Miscellaneous section to something other than your tmp/temp directory.') . " " . xlt('Please refer to') . ' README-Log-Backup.txt ' . xlt('file in the Documentation directory to learn how to automate the process of creating log backups') . ".</td>\n";
498 echo " </tr>\n";
499 echo "</table>\n";
502 if ($form_step == 1) {
503 $form_status .= xl('Dumping OpenEMR database') . "...||br-placeholder||";
504 echo brCustomPlaceholder(text($form_status));
505 if (file_exists($TAR_FILE_PATH)) {
506 if (! unlink($TAR_FILE_PATH)) {
507 die(xlt("Couldn't remove old backup file:") . " " . text($TAR_FILE_PATH));
511 if (! obliterate_dir($TMP_BASE)) {
512 die(xlt("Couldn't remove dir:") . " " . text($TMP_BASE));
515 if (! mkdir($BACKUP_DIR, 0777, true)) {
516 die(xlt("Couldn't create backup dir:") . " " . text($BACKUP_DIR));
519 $file_to_compress = "$BACKUP_DIR/openemr.sql"; // gzip this file after creation
521 if ($GLOBALS['include_de_identification'] == 1) {
522 //include routines during backup when de-identification is enabled
523 $cmd = escapeshellcmd($mysql_dump_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
524 " -p" . escapeshellarg($sqlconf["pass"]) .
525 " -h " . escapeshellarg($sqlconf["host"]) .
526 " --port=" . escapeshellarg($sqlconf["port"]) .
527 " --routines" .
528 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
529 " --hex-blob --opt --quote-names --no-tablespaces -r " . escapeshellarg($file_to_compress) . " $mysql_ssl " .
530 escapeshellarg($sqlconf["dbase"]);
531 } else {
532 $cmd = escapeshellcmd($mysql_dump_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
533 " -p" . escapeshellarg($sqlconf["pass"]) .
534 " -h " . escapeshellarg($sqlconf["host"]) .
535 " --port=" . escapeshellarg($sqlconf["port"]) .
536 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
537 " --hex-blob --opt --quote-names --no-tablespaces -r " . escapeshellarg($file_to_compress) . " $mysql_ssl " .
538 escapeshellarg($sqlconf["dbase"]);
541 $auto_continue = true;
544 if ($form_step == 2) {
545 ++$form_step;
548 if ($form_step == 3) {
549 $form_status .= xl('Dumping OpenEMR web directory tree') . "...||br-placeholder||";
550 echo brCustomPlaceholder(text($form_status));
551 $cur_dir = getcwd();
552 chdir($webserver_root);
554 // Select the files and directories to archive. Basically everything
555 // except site-specific data for other sites.
556 $file_list = array();
557 $dh = opendir($webserver_root);
558 if (!$dh) {
559 die("Cannot read directory '" . text($webserver_root) . "'.");
562 while (false !== ($filename = readdir($dh))) {
563 if ($filename == '.' || $filename == '..') {
564 continue;
567 if ($filename == 'sites') {
568 // Omit other sites.
569 $file_list[] = "$filename/" . $_SESSION['site_id'];
570 } else {
571 $file_list[] = $filename;
575 closedir($dh);
577 $arch_file = $BACKUP_DIR . DIRECTORY_SEPARATOR . "openemr.tar.gz";
578 if (!create_tar_archive($arch_file, "gz", $file_list)) {
579 die(xlt("An error occurred while dumping OpenEMR web directory tree"));
582 chdir($cur_dir);
583 $auto_continue = true;
586 if ($form_step == 4) {
587 ++$form_step;
590 if ($form_step == 5) { // create the final compressed tar containing all files
591 $form_status .= xl('Backup file has been created. Will now send download.') . "||br-placeholder||";
592 echo brCustomPlaceholder(text($form_status));
593 $cur_dir = getcwd();
594 chdir($BACKUP_DIR);
595 $file_list = array('.');
596 if (!create_tar_archive($TAR_FILE_PATH, '', $file_list)) {
597 die(xlt("Error: Unable to create downloadable archive"));
600 chdir($cur_dir);
601 /* To log the backup event */
602 if ($GLOBALS['audit_events_backup']) {
603 EventAuditLogger::instance()->newEvent("backup", $_SESSION['authUser'], $_SESSION['authProvider'], 0, "Backup is completed");
606 $auto_continue = true;
609 if ($form_step == 101) {
610 echo "<p class='font-weight-bold'>&nbsp;" . xlt('Select the configuration items to export') . ":</p>";
612 echo "<table cellspacing='10' cellpadding='0'>\n<tr>\n<td valign='top' nowrap>\n";
614 echo "<strong>" . xlt('Tables') . "</strong><br />\n";
615 echo "<input type='checkbox' name='form_cb_services' value='1' />\n";
616 echo " " . xlt('Services') . "<br />\n";
617 echo "<input type='checkbox' name='form_cb_products' value='1' />\n";
618 echo " " . xlt('Products') . "<br />\n";
619 echo "<input type='checkbox' name='form_cb_prices' value='1' />\n";
620 echo " " . xlt('Prices') . "<br />\n";
621 echo "<input type='checkbox' name='form_cb_categories' value='1' />\n";
622 echo " " . xlt('Document Categories') . "<br />\n";
623 echo "<input type='checkbox' name='form_cb_feesheet' value='1' />\n";
624 echo " " . xlt('Fee Sheet Options') . "<br />\n";
625 echo "<input type='checkbox' name='form_cb_lab_config' value='1' />\n";
626 echo " " . xlt('Lab Configuration') . "<br />\n";
627 echo "<input type='checkbox' name='form_cb_lang' value='1' />\n";
628 echo " " . xlt('Translations') . "<br />\n";
630 // Multi-select for lists.
631 echo "</td><td valign='top'>\n";
632 echo "<strong>" . xlt('Lists') . "</strong><br />\n";
633 echo "<select class='form-control' multiple name='form_sel_lists[]' size='15'>";
634 $lres = sqlStatement("SELECT option_id, title FROM list_options WHERE " .
635 "list_id = 'lists' AND activity = 1 ORDER BY title, seq");
636 while ($lrow = sqlFetchArray($lres)) {
637 echo "<option value='" . attr($lrow['option_id']) . "'";
638 echo ">" . text(xl_list_label($lrow['title'])) . "</option>\n";
640 echo "</select>\n";
641 echo "<br /><a href='#' onclick='export_submit(102.1)'>" . xlt('Download CSV') . "</a>";
643 // Multi-select for layouts.
644 echo "</td><td valign='top'>\n";
645 echo "<strong>" . xlt('Layouts') . "</strong><br />\n";
646 echo "<select class='form-control' multiple name='form_sel_layouts[]' size='15'>";
647 $lres = sqlStatement("SELECT grp_form_id, grp_title FROM layout_group_properties WHERE " .
648 "grp_group_id = '' AND grp_activity = 1 ORDER BY grp_form_id");
649 while ($lrow = sqlFetchArray($lres)) {
650 $key = $lrow['grp_form_id'];
651 echo "<option value='" . attr($key) . "'";
652 echo ">" . text($key) . ": " . text(xl_layout_label($lrow['grp_title'])) . "</option>\n";
654 echo "</select>\n";
655 echo "<br /><a href='#' onclick='export_submit(102.2)'>" . xlt('Download CSV') . "</a>";
656 echo "</td>\n</tr>\n</table>\n";
658 // Option to auto-export lists referenced by the chosen layouts.
659 echo "&nbsp;<br /><input type='checkbox' name='form_cb_addlists' value='1' />\n";
660 echo " " . xlt('Include all lists referenced in chosen layouts') . "<br />\n";
662 echo "<br /><input class='btn btn-primary' type='submit' onclick='export_submit(102)' value='" . xla('Continue') . "' />\n";
665 if ($form_step == 102) {
666 $tables = '';
667 if (!empty($_POST['form_cb_services' ])) {
668 $tables .= ' codes';
671 if (!empty($_POST['form_cb_products' ])) {
672 $tables .= ' drugs drug_templates';
675 if (!empty($_POST['form_cb_prices' ])) {
676 $tables .= ' prices';
679 if (!empty($_POST['form_cb_categories'])) {
680 $tables .= ' categories categories_seq';
683 if (!empty($_POST['form_cb_feesheet' ])) {
684 $tables .= ' fee_sheet_options';
687 if (!empty($_POST['form_cb_lab_config'])) {
688 $tables .= ' procedure_type procedure_providers procedure_questions';
691 if (!empty($_POST['form_cb_lang' ])) {
692 $tables .= ' lang_languages lang_constants lang_definitions';
695 if ($tables || is_array($_POST['form_sel_lists'] ?? '') || is_array($_POST['form_sel_layouts'] ?? '')) {
696 $form_status .= xl('Creating export file') . "...||br-placeholder||";
697 echo brCustomPlaceholder(text($form_status));
698 if (file_exists($EXPORT_FILE)) {
699 if (! unlink($EXPORT_FILE)) {
700 die(xlt("Couldn't remove old export file: ") . text($EXPORT_FILE));
704 // The substitutions below use perl because sed's not usually on windows systems.
705 $perl = $PERL_PATH . DIRECTORY_SEPARATOR . 'perl';
707 # This condition was added because the windows operating system uses different syntax for the shell commands.
708 # The test is if it is the windows operating system.
709 if (IS_WINDOWS) {
710 # This section sets the character_set_client to utf8 in the sql file as part or the import property.
711 # windows will place the quotes in the outputted code if they are there. we removed them here.
712 $cmd = "echo SET character_set_client = utf8; > " . escapeshellarg($EXPORT_FILE) . " & ";
713 } else {
714 $cmd = "echo 'SET character_set_client = utf8;' > " . escapeshellarg($EXPORT_FILE) . ";";
717 if ($tables) {
718 if (IS_WINDOWS) {
719 $cmd .= escapeshellcmd('"' . $mysql_dump_cmd . '"') . " -u " . escapeshellarg($sqlconf["login"]) .
720 " -p" . escapeshellarg($sqlconf["pass"]) .
721 " -h " . escapeshellarg($sqlconf["host"]) .
722 " --port=" . escapeshellarg($sqlconf["port"]) .
723 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
724 " --hex-blob --opt --quote-names --skip-comments --no-tablespaces $mysql_ssl " .
725 escapeshellarg($sqlconf["dbase"]) . " $tables";
726 } else {
727 $cmd .= escapeshellcmd($mysql_dump_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
728 " -p" . escapeshellarg($sqlconf["pass"]) .
729 " -h " . escapeshellarg($sqlconf["host"]) .
730 " --port=" . escapeshellarg($sqlconf["port"]) .
731 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
732 " --hex-blob --opt --quote-names --skip-comments --no-tablespaces $mysql_ssl " .
733 escapeshellarg($sqlconf["dbase"]) . " $tables";
735 if (IS_WINDOWS) {
736 # The Perl script differs in windows also.
737 $cmd .= " | " . escapeshellcmd('"' . $perl . '"') . " -pe \"s/ DEFAULT CHARSET=[A-Za-z0-9]*//i; s/ collate[ =][^ ;,]*//i;\"" .
738 " >> " . escapeshellarg($EXPORT_FILE) . " & ";
739 } else {
740 $cmd .= " | " . escapeshellcmd($perl) . " -pe 's/ DEFAULT CHARSET=[A-Za-z0-9]*//i; s/ collate[ =][^ ;,]*//i;'" .
741 " > " . escapeshellarg($EXPORT_FILE) . ";";
745 $dumppfx = escapeshellcmd($mysql_dump_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
746 " -p" . escapeshellarg($sqlconf["pass"]) .
747 " -h " . escapeshellarg($sqlconf["host"]) .
748 " --port=" . escapeshellarg($sqlconf["port"]) .
749 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
750 " --hex-blob --skip-opt --quote-names --no-tablespaces --complete-insert" .
751 " --no-create-info --skip-comments $mysql_ssl";
753 // Individual lists.
754 $form_sel_lists = is_array($_POST['form_sel_lists'] ?? '') ? $_POST['form_sel_lists'] : array();
755 if (!empty($_POST['form_cb_addlists']) && is_array($_POST['form_sel_layouts'] ?? '')) {
756 // Include all lists referenced by the exported layouts.
757 foreach ($_POST['form_sel_layouts'] as $layoutid) {
758 $tmpres = sqlStatement(
759 "SELECT a.list_id FROM layout_options AS a " .
760 "JOIN list_options AS i ON i.list_id = 'lists' AND i.option_id = a.list_id AND " .
761 "i.activity = 1 AND i.option_value = 0 " .
762 "WHERE a.form_id = ? AND a.list_id != '' AND a.uor > 0",
763 array($layoutid)
765 while ($tmprow = sqlFetchArray($tmpres)) {
766 if (!in_array($tmprow['list_id'], $form_sel_lists) && !in_array($tmprow['list_id'], $excluded_lists)) {
767 $form_sel_lists[] = $tmprow['list_id'];
772 if (!empty($form_sel_lists)) {
773 foreach ($form_sel_lists as $listid) {
774 // skip if have backtic(s)
775 if (strpos($listid, '`') !== false) {
776 echo xlt("Skipping illegal list name") . ": " . text($listid) . "<br>";
777 continue;
779 // whitelist the $listid
780 $listid_check = sqlQuery("SELECT `list_id` FROM `list_options` WHERE `list_id` = ? OR `option_id` = ?", [$listid, $listid]);
781 if (empty($listid_check['list_id'])) {
782 echo xlt("Skipping missing list name") . ": " . text($listid) . "<br>";
783 continue;
785 if (IS_WINDOWS) {
786 # windows will place the quotes in the outputted code if they are there. we removed them here.
787 $cmd .= " echo 'DELETE FROM list_options WHERE list_id = \"" . add_escape_custom($listid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . " & ";
788 $cmd .= " echo 'DELETE FROM list_options WHERE list_id = 'lists' AND option_id = \"" . add_escape_custom($listid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . " & ";
789 # windows uses the & to join statements.
790 $cmd .= $dumppfx . " --where=\"list_id = 'lists' AND option_id = '$listid' OR list_id = '$listid' " .
791 "ORDER BY list_id != 'lists', seq, title\" " .
792 escapeshellarg($sqlconf["dbase"]) . " list_options";
793 $cmd .= " >> " . escapeshellarg($EXPORT_FILE) . " & ";
794 } else {
795 $cmdarr[] = "echo 'DELETE FROM list_options WHERE list_id = \"" .
796 add_escape_custom($listid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . ";" .
797 "echo 'DELETE FROM list_options WHERE list_id = \"lists\" AND option_id = \"" .
798 add_escape_custom($listid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . ";" .
799 $dumppfx . " --where='list_id = \"lists\" AND option_id = \"" .
800 add_escape_custom($listid) . "\" OR list_id = \"" .
801 add_escape_custom($listid) . "\" " . "ORDER BY list_id != \"lists\", seq, title' " .
802 escapeshellarg($sqlconf["dbase"]) . " list_options" .
803 " >> " . escapeshellarg($EXPORT_FILE) . ";";
808 // Individual layouts.
809 if (is_array($_POST['form_sel_layouts'] ?? '')) {
810 $do_history_repair = false;
811 $do_demographics_repair = false;
812 foreach ($_POST['form_sel_layouts'] as $layoutid) {
813 // skip if have backtic(s)
814 if (strpos($layoutid, '`') !== false) {
815 echo xlt("Skipping illegal layout name") . ": " . text($layoutid) . "<br>";
816 continue;
818 // whitelist the $layoutid
819 $layoutid_check_one = sqlQuery("SELECT `form_id` FROM `layout_options` WHERE `form_id` = ?", [$layoutid]);
820 $layoutid_check_two = sqlQuery("SELECT `grp_form_id` FROM `layout_group_properties` WHERE `grp_form_id` = ?", [$layoutid]);
821 if (empty($layoutid_check_one['list_id']) && empty($layoutid_check_two['grp_form_id'])) {
822 echo xlt("Skipping missing layout name") . ": " . text($layoutid) . "<br>";
823 continue;
825 // Beware and keep in mind that Windows requires double quotes around arguments.
826 if (IS_WINDOWS) {
827 # windows will place the quotes in the outputted code if they are there. we removed them here.
828 $cmd .= " echo DELETE FROM layout_options WHERE form_id = \"" . add_escape_custom($layoutid) . "\"; >> " . escapeshellarg($EXPORT_FILE) . " & ";
829 } else {
830 $cmd .= "echo 'DELETE FROM layout_options WHERE form_id = \"" . add_escape_custom($layoutid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . ";";
832 if (IS_WINDOWS) {
833 # windows will place the quotes in the outputted code if they are there. we removed them here.
834 $cmd .= "echo DELETE FROM layout_group_properties WHERE grp_form_id = \"" . add_escape_custom($layoutid) . "\"; >> " . escapeshellarg($EXPORT_FILE) . " &;";
835 } else {
836 $cmd .= "echo 'DELETE FROM layout_group_properties WHERE grp_form_id = \"" . add_escape_custom($layoutid) . "\";' >> " . escapeshellarg($EXPORT_FILE) . ";";
838 if (IS_WINDOWS) {
839 # windows uses the & to join statements.
840 $cmd .= $dumppfx . ' --where="grp_form_id = \'' . add_escape_custom($layoutid) . "'\" " .
841 escapeshellarg($sqlconf["dbase"]) . " layout_group_properties";
842 $cmd .= " >> " . escapeshellarg($EXPORT_FILE) . " & ";
843 $cmd .= $dumppfx . ' --where="form_id = \'' . add_escape_custom($layoutid) . '\' ORDER BY group_id, seq, title" ' .
844 escapeshellarg($sqlconf["dbase"]) . " layout_options" ;
845 $cmd .= " >> " . escapeshellarg($EXPORT_FILE) . " & ";
846 } else {
847 $cmd .= $dumppfx . " --where='grp_form_id = \"" . add_escape_custom($layoutid) . "\"' " .
848 escapeshellarg($sqlconf["dbase"]) . " layout_group_properties";
849 $cmd .= " >> " . escapeshellarg($EXPORT_FILE) . ";";
850 $cmd .= $dumppfx . " --where='form_id = \"" . add_escape_custom($layoutid) . "\" ORDER BY group_id, seq, title' " .
851 escapeshellarg($sqlconf["dbase"]) . " layout_options" ;
852 $cmd .= " >> " . escapeshellarg($EXPORT_FILE) . ";";
854 // History and demographics exports will get special treatment.
855 if (substr($layoutid, 0, 3) == 'HIS') {
856 $do_history_repair = true;
858 if (substr($layoutid, 0, 3) == 'DEM') {
859 $do_demographics_repair = true;
862 // If any HIS* layouts were exported then also write SQL to add missing history_data columns.
863 if (!IS_WINDOWS) {
864 if ($do_history_repair) {
865 $cmd .= "echo \"SET sql_mode = '';\" >> " . escapeshellarg($EXPORT_FILE) . ";";
866 $cmd .= "echo \"SET group_concat_max_len = 1000000;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
867 $cmd .= "echo \"SELECT CONCAT(\" >> " . escapeshellarg($EXPORT_FILE) . ";";
868 $cmd .= "echo \"'ALTER TABLE history_data ',\" >> " . escapeshellarg($EXPORT_FILE) . ";";
869 $cmd .= "echo \"COALESCE(GROUP_CONCAT(DISTINCT ' ADD \`', lo.field_id, '\` TEXT NOT NULL' ORDER BY lo.field_id), '')\" >> " . escapeshellarg($EXPORT_FILE) . ";";
870 $cmd .= "echo \")\" >> " . escapeshellarg($EXPORT_FILE) . ";";
871 $cmd .= "echo \"FROM layout_options AS lo WHERE\" >> " . escapeshellarg($EXPORT_FILE) . ";";
872 $cmd .= "echo \"(lo.form_id LIKE 'HIS%' OR lo.source = 'H') AND lo.field_id NOT IN\" >> " . escapeshellarg($EXPORT_FILE) . ";";
873 $cmd .= "echo \"(SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'history_data')\" >> " . escapeshellarg($EXPORT_FILE) . ";";
874 $cmd .= "echo \"INTO @sql;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
875 $cmd .= "echo \"PREPARE stmt FROM @sql;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
876 $cmd .= "echo \"EXECUTE stmt;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
878 // If the DEM layout was exported then also write SQL to add missing patient_data columns.
879 if ($do_demographics_repair) {
880 $cmd .= "echo \"SET sql_mode = '';\" >> " . escapeshellarg($EXPORT_FILE) . ";";
881 $cmd .= "echo \"SET group_concat_max_len = 1000000;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
882 $cmd .= "echo \"SELECT CONCAT(\" >> " . escapeshellarg($EXPORT_FILE) . ";";
883 $cmd .= "echo \"'ALTER TABLE patient_data ',\" >> " . escapeshellarg($EXPORT_FILE) . ";";
884 $cmd .= "echo \"COALESCE(GROUP_CONCAT(DISTINCT ' ADD \`', lo.field_id, '\` TEXT NOT NULL' ORDER BY lo.field_id), '')\" >> " . escapeshellarg($EXPORT_FILE) . ";";
885 $cmd .= "echo \")\" >> " . escapeshellarg($EXPORT_FILE) . ";";
886 $cmd .= "echo \"FROM layout_options AS lo WHERE\" >> " . escapeshellarg($EXPORT_FILE) . ";";
887 $cmd .= "echo \"(lo.form_id LIKE 'DEM%' OR lo.source = 'D') AND lo.field_id NOT IN\" >> " . escapeshellarg($EXPORT_FILE) . ";";
888 $cmd .= "echo \"(SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'patient_data')\" >> " . escapeshellarg($EXPORT_FILE) . ";";
889 $cmd .= "echo \"INTO @sql;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
890 $cmd .= "echo \"PREPARE stmt FROM @sql;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
891 $cmd .= "echo \"EXECUTE stmt;\" >> " . escapeshellarg($EXPORT_FILE) . ";";
893 } else {
894 if ($do_history_repair) {
895 $cmd .= "echo SET sql_mode = ''; >> " . escapeshellarg($EXPORT_FILE) . " & ";
896 $cmd .= "echo SET group_concat_max_len = 1000000; >> " . escapeshellarg($EXPORT_FILE) . " & ";
897 $cmd .= "echo SELECT CONCAT( >> " . escapeshellarg($EXPORT_FILE) . " & ";
898 $cmd .= "echo 'ALTER TABLE history_data ' , >> " . escapeshellarg($EXPORT_FILE) . " & ";
899 $cmd .= "echo COALESCE(GROUP_CONCAT(DISTINCT ' ADD `', lo.field_id, '` TEXT NOT NULL' ORDER BY lo.field_id), '') >> " . escapeshellarg($EXPORT_FILE) . " & ";
900 $cmd .= "echo ) >> " . escapeshellarg($EXPORT_FILE) . " & ";
901 $cmd .= "echo FROM layout_options AS lo WHERE >> " . escapeshellarg($EXPORT_FILE) . " & ";
902 $cmd .= "echo (lo.form_id LIKE 'HIS%' OR lo.source = 'H') AND lo.field_id NOT IN >> " . escapeshellarg($EXPORT_FILE) . " & ";
903 $cmd .= "echo (SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'history_data') >> " . escapeshellarg($EXPORT_FILE) . " & ";
904 $cmd .= "echo INTO @sql; >> " . escapeshellarg($EXPORT_FILE) . " & ";
905 $cmd .= "echo PREPARE stmt FROM @sql; >> " . escapeshellarg($EXPORT_FILE) . " & ";
906 $cmd .= "echo EXECUTE stmt; >> " . escapeshellarg($EXPORT_FILE) . " & ";
908 // If the DEM layout was exported then also write SQL to add missing patient_data columns.
909 if ($do_demographics_repair) {
910 $cmd .= "echo SET sql_mode = ''; >> " . escapeshellarg($EXPORT_FILE) . " & ";
911 $cmd .= "echo SET group_concat_max_len = 1000000; >> " . escapeshellarg($EXPORT_FILE) . " & ";
912 $cmd .= "echo SELECT CONCAT( >> " . escapeshellarg($EXPORT_FILE) . " & ";
913 $cmd .= "echo 'ALTER TABLE patient_data ', >> " . escapeshellarg($EXPORT_FILE) . " & ";
914 $cmd .= "echo COALESCE(GROUP_CONCAT(DISTINCT ' ADD `', lo.field_id, '` TEXT NOT NULL' ORDER BY lo.field_id), '') >> " . escapeshellarg($EXPORT_FILE) . " & ";
915 $cmd .= "echo ) >> " . escapeshellarg($EXPORT_FILE) . " & ";
916 $cmd .= "echo FROM layout_options AS lo WHERE >> " . escapeshellarg($EXPORT_FILE) . " & ";
917 $cmd .= "echo (lo.form_id LIKE 'DEM%' OR lo.source = 'D') AND lo.field_id NOT IN >> " . escapeshellarg($EXPORT_FILE) . " & ";
918 $cmd .= "echo (SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME = 'patient_data') >> " . escapeshellarg($EXPORT_FILE) . " & ";
919 $cmd .= "echo INTO @sql; >> " . escapeshellarg($EXPORT_FILE) . " & ";
920 $cmd .= "echo PREPARE stmt FROM @sql; >> " . escapeshellarg($EXPORT_FILE) . " & ";
921 $cmd .= "echo EXECUTE stmt; >> " . escapeshellarg($EXPORT_FILE) . " & ";
925 } else {
926 echo xlt('No items were selected!');
927 $form_step = -1;
930 $auto_continue = true;
933 if ($form_step == 103) {
934 $form_status .= xl('Done. Will now send download.') . "||br-placeholder||";
935 echo brCustomPlaceholder(text($form_status));
936 $auto_continue = true;
939 if ($form_step == 201) {
940 echo xlt('WARNING: This will overwrite configuration information with data from the uploaded file!') . " \n";
941 echo xlt('Use this feature only with newly installed sites, ');
942 echo xlt('otherwise you will destroy references to/from existing data.') . "\n";
943 echo "<br />&nbsp;<br />\n";
944 echo xlt('File to upload') . ":\n";
945 echo "<input type='hidden' name='MAX_FILE_SIZE' value='32000000' />\n";
946 echo "<input type='file' name='userfile' /><br />&nbsp;<br />\n";
947 echo "<input class='btn btn-primary' type='submit' value='" . xla('Continue') . "' />\n";
950 if ($form_step == 202) {
951 // Process uploaded config file.
952 if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
953 if (move_uploaded_file($_FILES['userfile']['tmp_name'], $EXPORT_FILE)) {
954 $form_status .= xl('Applying') . "...||br-placeholder||";
955 echo brCustomPlaceholder(text($form_status));
956 $cmd = escapeshellcmd($mysql_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
957 " -p" . escapeshellarg($sqlconf["pass"]) .
958 " -h " . escapeshellarg($sqlconf["host"]) .
959 " --port=" . escapeshellarg($sqlconf["port"]) .
960 " $mysql_ssl " .
961 escapeshellarg($sqlconf["dbase"]) .
962 " < " . escapeshellarg($EXPORT_FILE);
963 } else {
964 echo xlt('Internal error accessing uploaded file!');
965 $form_step = -1;
967 } else {
968 echo xlt('Upload failed!');
969 $form_step = -1;
972 $auto_continue = true;
975 if ($form_step == 203) {
976 $form_status .= xl('Done') . ".";
977 echo brCustomPlaceholder(text($form_status));
980 /// ViSolve : EventLog Backup
981 if ($form_step == 301) {
982 # Get the Current Timestamp, to attach with the log backup file
983 $backuptime = date("Ymd_His");
984 # Eventlog backup directory
985 $BACKUP_EVENTLOG_DIR = $GLOBALS['backup_log_dir'];
987 # Check if Eventlog Backup directory exists, if not create it with Write permission
988 if (!file_exists($BACKUP_EVENTLOG_DIR)) {
989 mkdir($BACKUP_EVENTLOG_DIR);
990 chmod($BACKUP_EVENTLOG_DIR, 0777);
993 # Frame the Eventlog Backup File Name
994 $BACKUP_EVENTLOG_FILE = $BACKUP_EVENTLOG_DIR . '/eventlog_' . $backuptime . '.sql';
995 # Create a new table similar to event table, rename the existing table as backup table, and rename the new table to event log table. Then export the contents of the table into a text file and drop the table.
996 $res = sqlStatement("create table if not exists log_comment_encrypt_new like log_comment_encrypt");
997 $res = sqlStatement("rename table log_comment_encrypt to log_comment_encrypt_backup,log_comment_encrypt_new to log_comment_encrypt");
998 $res = sqlStatement("create table if not exists log_new like log");
999 $res = sqlStatement("rename table log to log_backup,log_new to log");
1000 $res = sqlStatement("create table if not exists api_log_new like api_log");
1001 $res = sqlStatement("rename table api_log to api_log_backup, api_log_new to api_log");
1002 echo "<br />";
1003 $cmd = escapeshellcmd($mysql_dump_cmd) . " -u " . escapeshellarg($sqlconf["login"]) .
1004 " -p" . escapeshellarg($sqlconf["pass"]) .
1005 " -h " . escapeshellarg($sqlconf["host"]) .
1006 " --port=" . escapeshellarg($sqlconf["port"]) .
1007 " --ignore-table=" . escapeshellarg($sqlconf["dbase"] . ".onsite_activity_view") .
1008 " --hex-blob --opt --quote-names --no-tablespaces -r " . escapeshellarg($BACKUP_EVENTLOG_FILE) . " $mysql_ssl " .
1009 escapeshellarg($sqlconf["dbase"]) . " --tables log_comment_encrypt_backup log_backup api_log_backup";
1010 # Set Eventlog Flag when it is done
1011 $eventlog = 1;
1012 // 301 If ends here.
1015 if ($form_step == 401) {
1016 echo "<p><b>&nbsp;" . xlt('Download or Delete Old Log Entries') . ":</b></p>";
1017 $tmprow = sqlQuery("SELECT COUNT(*) AS count, MIN(date) AS date FROM log");
1018 echo "<p>&nbsp;" . xlt('The log has') . ' ' . $tmprow['count'] . ' ' .
1019 xlt('entries with the oldest dated') . ' ' . $tmprow['date'] . ".</p>";
1020 // Default end date is end of year 2 years ago, ensuring 1 full year of log remaining.
1021 $end_date = (date('Y') - 2) . '-12-31';
1022 if (!empty($_POST['form_end_date'])) {
1023 $end_date = DateToYYYYMMDD($_POST['form_end_date']);
1025 echo "<p>&nbsp;" . xlt('Select an end date. Entries after this date will not be downloaded or deleted.') . " ";
1026 echo "<input type='text' class='datepicker' name='form_end_date' id='form_end_date' size='10' " .
1027 "value='" . attr(oeFormatShortDate($end_date)) . "' " .
1028 "onkeyup='datekeyup(this,mypcc)' onblur='dateblur(this,mypcc)' title='End date yyyy-mm-dd' />";
1029 echo "</p>\n";
1030 echo "<p><input type='button' onclick='export_submit(402)' value='" . xla('Download Log Entries as Zipped CSV') . "' />&nbsp;\n";
1031 echo "<input type='button' onclick='export_submit(405)' value='" . xla('Delete Log Entries') . "' /></p>\n";
1034 if ($form_step == 405) {
1035 // Process log delete, then optimize to reclaim the file space.
1036 if (!empty($_POST['form_end_date'])) {
1037 $end_date = DateToYYYYMMDD($_POST['form_end_date']);
1038 sqlStatement(
1039 "DELETE log, lce, al FROM log " .
1040 "LEFT JOIN log_comment_encrypt AS lce ON lce.log_id = log.id " .
1041 "LEFT JOIN api_log AS al ON al.log_id = log.id " .
1042 "WHERE log.date <= ?",
1043 array("$end_date 23:59:59")
1045 sqlStatement("OPTIMIZE TABLE log");
1046 } else {
1047 die(xlt("End date is missing!"));
1049 $form_step = -1;
1050 $auto_continue = true;
1053 ++$form_step;
1056 </td>
1057 </tr>
1058 </table>
1060 <input type='hidden' name='form_step' value='<?php echo attr($form_step); ?>' />
1061 <input type='hidden' name='form_status' value='<?php echo attr($form_status); ?>' />
1063 </form>
1065 <?php
1066 ob_flush();
1067 flush();
1068 if ($cmd) {
1069 $tmp0 = exec($cmd, $tmp1, $tmp2);
1071 if ($tmp2) {
1072 if ($eventlog == 1) {
1073 // ViSolve : Restore previous state, if backup fails.
1074 $res = sqlStatement("drop table if exists log_comment_encrypt");
1075 $res = sqlStatement("rename table log_comment_encrypt_backup to log_comment_encrypt");
1076 $res = sqlStatement("drop table if exists log");
1077 $res = sqlStatement("rename table log_backup to log");
1078 $res = sqlStatement("drop table if exists api_log");
1079 $res = sqlStatement("rename table api_log_backup to api_log");
1081 //Removed the connection details as it exposes all the database credentials
1083 die("There was an error on the backup");
1086 // ViSolve: If the Eventlog is set, then clear the temporary table -- Start here
1087 if ($eventlog == 1) {
1088 $res = sqlStatement("drop table if exists log_backup");
1089 $res = sqlStatement("drop table if exists log_comment_encrypt_backup");
1090 $res = sqlStatement("drop table if exists api_log_backup");
1091 echo "<br /><b>";
1092 echo xlt('Backup Successfully taken in') . " ";
1093 echo text($BACKUP_EVENTLOG_DIR);
1094 echo "</b>";
1097 // ViSolve: If the Eventlog is set, then clear the temporary table -- Ends here
1100 // $cmdarr exists because some commands may be too long for a single exec.
1101 // Note eventlog stuff does not apply here.
1102 foreach ($cmdarr as $acmd) {
1103 $tmp0 = exec($acmd, $tmp1, $tmp2);
1104 if ($tmp2) {
1105 die("Error $tmp2 in: " . text($acmd));
1109 // If a file was flagged to be gzip-compressed after this cmd, do it.
1110 if ($file_to_compress) {
1111 if (!gz_compress_file($file_to_compress)) {
1112 die(xlt("Error in gzip compression of file: ") . text($file_to_compress));
1117 </center>
1119 <?php if ($auto_continue) { ?>
1120 <script>
1121 setTimeout("document.forms[0].submit();", 500);
1122 </script>
1123 <?php }
1125 // convert ||br-placeholder|| to <br>
1126 // (this is because the nl2br was not working for a reason I couldn't figure out)
1127 function brCustomPlaceholder(string $str): string
1129 return str_replace("||br-placeholder||", "<br />", $str);
1132 // Recursive directory remove (like an O/S insensitive "rm -rf dirname")
1133 function obliterate_dir($dir)
1135 if (!file_exists($dir)) {
1136 return true;
1139 if (!is_dir($dir) || is_link($dir)) {
1140 return unlink($dir);
1143 foreach (scandir($dir) as $item) {
1144 if ($item == '.' || $item == '..') {
1145 continue;
1148 if (!obliterate_dir($dir . DIRECTORY_SEPARATOR . $item)) {
1149 chmod($dir . DIRECTORY_SEPARATOR . $item, 0777);
1150 if (!obliterate_dir($dir . DIRECTORY_SEPARATOR . $item)) {
1151 return false;
1156 return rmdir($dir);
1159 // Create a tar archive given the archive file name, compression method if any, and the
1160 // array of file/directory names to archive
1161 function create_tar_archive($archiveName, $compressMethod, $itemArray)
1163 // Create a tar object using the pear library
1164 $tar = new Archive_Tar($archiveName, $compressMethod);
1165 if ($tar->create($itemArray)) {
1166 return true;
1169 return false;
1172 // Compress a file using gzip. Source file removed, leaving only the compressed
1173 // *.gz file, just like gzip command line would behave.
1174 function gz_compress_file($source)
1176 $dest = $source . '.gz';
1177 $error = false;
1178 if ($fp_in = fopen($source, 'rb')) {
1179 if ($fp_out = gzopen($dest, 'wb')) {
1180 while (!feof($fp_in)) {
1181 gzwrite($fp_out, fread($fp_in, 1024 * 512));
1184 gzclose($fp_out);
1185 fclose($fp_in);
1186 unlink($source);
1187 } else {
1188 $error = true;
1190 } else {
1191 $error = true;
1194 if ($error) {
1195 return false;
1196 } else {
1197 return $dest;
1202 </body>
1203 </html>