3 // Copyright (C) 2008-2014 Rod Roark <rod@sunsetsystems.com>
4 // Adapted for cross-platform operation by Bill Cernansky (www.mi-squared.com)
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This script creates a backup tarball and sends it to the users's
12 // browser for download. The tarball includes:
14 // * an OpenEMR database dump (gzipped)
15 // * a phpGACL database dump (gzipped), if phpGACL is used and has
17 // * the OpenEMR web directory (.tar.gz)
18 // * the phpGACL web directory (.tar.gz), if phpGACL is used
20 // The OpenEMR web directory is important because it includes config-
21 // uration files, patient documents, and possible customizations, and
22 // also because the database structure is dependent on the installed
25 // This script depends on execution of some external programs:
26 // mysqldump & pg_dump. It has been tested with Debian and Ubuntu
27 // Linux and with Windows XP.
28 // Do not assume that it works for you until you have successfully
31 require_once("../globals.php");
32 require_once("$srcdir/acl.inc");
33 require_once("$srcdir/log.inc");
35 if (!extension_loaded('zlib'))
37 die('Abort '.basename(__FILE__
).' : Missing zlib extensions');
39 if (!function_exists('gzopen') && function_exists('gzopen64'))
41 function gzopen($filename, $mode, $use_include_path = 0)
43 return gzopen64($filename, $mode, $use_include_path);
48 if (!acl_check('admin', 'super')) die(xl('Not authorized','','','!'));
50 include_once("Archive/Tar.php");
52 // Set up method, which will depend on OS and if pear tar.php is installed
53 if (class_exists('Archive_Tar')) {
54 # pear tar.php is installed so can use os independent method
55 $newBackupMethod = true;
58 # without the tar.php module, can't run backup in windows
59 die(xl("Error. You need to install the Archive/Tar.php php module."));
62 # without the tar.php module, can run via system commands in non-windows
63 $newBackupMethod = false;
66 $BTN_TEXT_CREATE = xl('Create Backup');
67 $BTN_TEXT_EXPORT = xl('Export Configuration');
68 $BTN_TEXT_IMPORT = xl('Import Configuration');
69 // ViSolve: Create Log Backup button
70 $BTN_TEXT_CREATE_EVENTLOG = xl('Create Eventlog Backup');
72 $form_step = isset($_POST['form_step']) ?
trim($_POST['form_step']) : '0';
73 $form_status = isset($_POST['form_status' ]) ?
trim($_POST['form_status' ]) : '';
75 if (!empty($_POST['form_export'])) $form_step = 101;
76 if (!empty($_POST['form_import'])) $form_step = 201;
77 //ViSolve: Assign Unique Number for the Log Creation
78 if (!empty($_POST['form_backup'])) $form_step = 301;
79 // When true the current form will submit itself after a brief pause.
80 $auto_continue = false;
83 $backup_file_prefix = "emr_backup";
84 $backup_file_suffix = ".tar";
85 $TMP_BASE = $GLOBALS['temporary_files_dir'] . "/openemr_web_backup";
86 $BACKUP_DIR = $TMP_BASE . "/emr_backup";
87 $TAR_FILE_PATH = $TMP_BASE . DIRECTORY_SEPARATOR
. $backup_file_prefix . $backup_file_suffix;
88 $EXPORT_FILE = $GLOBALS['temporary_files_dir'] . "/openemr_config.sql";
89 $MYSQL_PATH = $GLOBALS['mysql_bin_dir'];
90 $PERL_PATH = $GLOBALS['perl_bin_dir'];
92 if ($form_step == 6) {
93 header("Pragma: public");
95 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
96 header("Content-Type: application/force-download");
97 header("Content-Length: " . filesize($TAR_FILE_PATH));
98 header("Content-Disposition: attachment; filename=" . basename($TAR_FILE_PATH));
99 header("Content-Description: File Transfer");
100 readfile($TAR_FILE_PATH);
101 unlink($TAR_FILE_PATH);
102 obliterate_dir($BACKUP_DIR);
106 if ($form_step == 104) {
107 header("Pragma: public");
108 header("Expires: 0");
109 header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
110 header("Content-Type: application/force-download");
111 header("Content-Length: " . filesize($EXPORT_FILE));
112 header("Content-Disposition: attachment; filename=" . basename($EXPORT_FILE));
113 header("Content-Description: File Transfer");
114 readfile($EXPORT_FILE);
115 unlink($EXPORT_FILE);
122 <link rel
="stylesheet" href
='<?php echo $css_header ?>' type
='text/css'>
123 <title
><?php
xl('Backup','e'); ?
></title
>
126 <body
class="body_top">
129 <form method
='post' action
='backup.php' enctype
='multipart/form-data'>
131 <table
<?php
if ($form_step != 101) echo " style='width:50em'"; ?
>>
137 $mysql_cmd = $MYSQL_PATH . DIRECTORY_SEPARATOR
. 'mysql';
138 $mysql_dump_cmd = $mysql_cmd . 'dump';
139 $file_to_compress = ''; // if named, this iteration's file will be gzipped after it is created
140 $eventlog=0; // Eventlog Flag
142 if ($form_step == 0) {
145 echo " <td><input type='submit' name='form_create' value='$BTN_TEXT_CREATE' /></td>\n";
146 echo " <td>" . xl('Create and download a full backup') . "</td>\n";
148 // The config import/export feature is optional.
149 if (!empty($GLOBALS['configuration_import_export'])) {
151 echo " <td><input type='submit' name='form_export' value='$BTN_TEXT_EXPORT' /></td>\n";
152 echo " <td>" . xl('Download configuration data') . "</td>\n";
155 echo " <td><input type='submit' name='form_import' value='$BTN_TEXT_IMPORT' /></td>\n";
156 echo " <td>" . xl('Upload configuration data') . "</td>\n";
159 // ViSolve : Add ' Create Log table backup Button'
161 echo " <td><input type='submit' name='form_backup' value='$BTN_TEXT_CREATE_EVENTLOG' /></td>\n";
162 echo " <td>" . xl('Create Eventlog Backup') . "</td>\n";
165 echo " <td></td><td class='text'><b>" . xl('Note')."</b> " . xl('Please refer to').' README-Log-Backup.txt '.xl('file in the Documentation directory to learn how to automate the process of creating log backups') . "</td>\n";
170 if ($form_step == 1) {
171 $form_status .= xl('Dumping OpenEMR database') . "...<br />";
172 echo nl2br($form_status);
173 if (file_exists($TAR_FILE_PATH))
174 if (! unlink($TAR_FILE_PATH)) die(xl("Couldn't remove old backup file:") . " " . $TAR_FILE_PATH);
175 if (! obliterate_dir($TMP_BASE)) die(xl("Couldn't remove dir:"). " " . $TMP_BASE);
176 if (! mkdir($BACKUP_DIR, 0777, true)) die(xl("Couldn't create backup dir:") . " " . $BACKUP_DIR);
177 $file_to_compress = "$BACKUP_DIR/openemr.sql"; // gzip this file after creation
179 if($GLOBALS['include_de_identification']==1)
181 //include routines during backup when de-identification is enabled
182 $cmd = "$mysql_dump_cmd -u " . escapeshellarg($sqlconf["login"]) .
183 " -p" . escapeshellarg($sqlconf["pass"]) .
184 " -h" . escapeshellarg($sqlconf["host"]) .
185 " --port=".escapeshellarg($sqlconf["port"]) .
187 " --opt --quote-names -r $file_to_compress " .
188 escapeshellarg($sqlconf["dbase"]);
192 $cmd = "$mysql_dump_cmd -u " . escapeshellarg($sqlconf["login"]) .
193 " -p" . escapeshellarg($sqlconf["pass"]) .
194 " -h" . escapeshellarg($sqlconf["host"]) .
195 " --port=".escapeshellarg($sqlconf["port"]) .
196 " --opt --quote-names -r $file_to_compress " .
197 escapeshellarg($sqlconf["dbase"]);
199 $auto_continue = true;
202 if ($form_step == 2) {
203 if (!empty($phpgacl_location) && $gacl_object->_db_name
!= $sqlconf["dbase"]) {
204 $form_status .= xl('Dumping phpGACL database') . "...<br />";
205 echo nl2br($form_status);
206 $file_to_compress = "$BACKUP_DIR/phpgacl.sql"; // gzip this file after creation
207 $cmd = "$mysql_dump_cmd -u " . escapeshellarg($gacl_object->_db_user
) .
208 " -p" . escapeshellarg($gacl_object->_db_password
) .
209 " --opt --quote-names -r $file_to_compress " .
210 escapeshellarg($gacl_object->_db_name
);
211 $auto_continue = true;
218 if ($form_step == 3) {
219 $form_status .= xl('Dumping OpenEMR web directory tree') . "...<br />";
220 echo nl2br($form_status);
222 chdir($webserver_root);
224 // Select the files and directories to archive. Basically everything
225 // except site-specific data for other sites.
226 $file_list = array();
227 $dh = opendir($webserver_root);
228 if (!$dh) die("Cannot read directory '$webserver_root'.");
229 while (false !== ($filename = readdir($dh))) {
230 if ($filename == '.' ||
$filename == '..') continue;
231 if ($filename == 'sites') {
233 $file_list[] = "$filename/" . $_SESSION['site_id'];
236 $file_list[] = $filename;
241 $arch_file = $BACKUP_DIR . DIRECTORY_SEPARATOR
. "openemr.tar.gz";
242 if (!create_tar_archive($arch_file, "gz", $file_list))
243 die(xl("An error occurred while dumping OpenEMR web directory tree"));
245 $auto_continue = true;
248 if ($form_step == 4) {
249 if ((!empty($phpgacl_location)) && ($phpgacl_location != $srcdir."/../gacl") ) {
250 $form_status .= xl('Dumping phpGACL web directory tree') . "...<br />";
251 echo nl2br($form_status);
253 chdir($phpgacl_location);
254 $file_list = array('.'); // archive entire directory
255 $arch_file = $BACKUP_DIR . DIRECTORY_SEPARATOR
. "phpgacl.tar.gz";
256 if (!create_tar_archive($arch_file, "gz", $file_list))
257 die (xl("An error occurred while dumping phpGACL web directory tree"));
259 $auto_continue = true;
266 if ($form_step == 5) { // create the final compressed tar containing all files
267 $form_status .= xl('Backup file has been created. Will now send download.') . "<br />";
268 echo nl2br($form_status);
271 $file_list = array('.');
272 if (!create_tar_archive($TAR_FILE_PATH, '', $file_list))
273 die(xl("Error: Unable to create downloadable archive"));
275 /* To log the backup event */
276 if ($GLOBALS['audit_events_backup']){
277 newEvent("backup", $_SESSION['authUser'], $_SESSION['authProvider'], 0,"Backup is completed");
279 $auto_continue = true;
282 if ($form_step == 101) {
283 echo "<p><b> " . xl('Select the configuration items to export') . ":</b></p>";
285 echo "<table cellspacing='10' cellpadding='0'>\n<tr>\n<td valign='top'>\n";
287 echo "<b>" . xlt('Tables') . "</b><br />\n";
288 echo "<input type='checkbox' name='form_cb_services' value='1' />\n";
289 echo " " . xl('Services') . "<br />\n";
290 echo "<input type='checkbox' name='form_cb_products' value='1' />\n";
291 echo " " . xl('Products') . "<br />\n";
292 echo "<input type='checkbox' name='form_cb_prices' value='1' />\n";
293 echo " " . xl('Prices') . "<br />\n";
294 echo "<input type='checkbox' name='form_cb_categories' value='1' />\n";
295 echo " " . xl('Document Categories') . "<br />\n";
296 echo "<input type='checkbox' name='form_cb_feesheet' value='1' />\n";
297 echo " " . xl('Fee Sheet Options') . "<br />\n";
298 echo "<input type='checkbox' name='form_cb_lang' value='1' />\n";
299 echo " " . xl('Translations') . "<br />\n";
301 // Multi-select for lists.
302 echo "</td><td valign='top'>\n";
303 echo "<b>" . xlt('Lists') . "</b><br />\n";
304 echo "<select multiple name='form_sel_lists[]' size='15'>";
305 $lres = sqlStatement("SELECT option_id, title FROM list_options WHERE " .
306 "list_id = 'lists' ORDER BY title, seq");
307 while ($lrow = sqlFetchArray($lres)) {
308 echo "<option value='" . attr($lrow['option_id']) . "'";
309 echo ">" . text(xl_list_label($lrow['title'])) . "</option>\n";
313 // Multi-select for layouts.
314 echo "</td><td valign='top'>\n";
315 echo "<b>" . xlt('Layouts') . "</b><br />\n";
316 echo "<select multiple name='form_sel_layouts[]' size='15'>";
317 $lres = sqlStatement("SELECT option_id, title FROM list_options WHERE " .
318 "list_id = 'lbfnames' ORDER BY title, seq");
319 while ($lrow = sqlFetchArray($lres)) {
320 echo "<option value='" . attr($lrow['option_id']) . "'";
321 echo ">" . text(xl_layout_label($lrow['title'])) . "</option>\n";
325 echo "</td>\n</tr>\n</table>\n";
326 echo " <br /><input type='submit' value='" . xl('Continue') . "' />\n";
329 if ($form_step == 102)
332 if ($_POST['form_cb_services' ]) $tables .= ' codes';
333 if ($_POST['form_cb_products' ]) $tables .= ' drugs drug_templates';
334 if ($_POST['form_cb_prices' ]) $tables .= ' prices';
335 if ($_POST['form_cb_categories']) $tables .= ' categories categories_seq';
336 if ($_POST['form_cb_feesheet' ]) $tables .= ' fee_sheet_options';
337 if ($_POST['form_cb_lang' ]) $tables .= ' lang_languages lang_constants lang_definitions';
338 if ($tables ||
is_array($_POST['form_sel_lists']) ||
is_array($_POST['form_sel_layouts']))
340 $form_status .= xl('Creating export file') . "...<br />";
341 echo nl2br($form_status);
342 if (file_exists($EXPORT_FILE))
344 if (! unlink($EXPORT_FILE)) die(xl("Couldn't remove old export file: ") . $EXPORT_FILE);
346 // The substitutions below use perl because sed's not usually on windows systems.
347 $perl = $PERL_PATH . DIRECTORY_SEPARATOR
. 'perl';
350 # This condition was added because the windows operating system uses different syntax for the shell commands.
351 # The test is if it is the windows operating system.
354 # This section sets the character_set_client to utf8 in the sql file as part or the import property.
355 # windows will place the quotes in the outputted code if they are there. we removed them here.
356 $cmd = "echo SET character_set_client = utf8; > $EXPORT_FILE & ";
360 $cmd = "echo 'SET character_set_client = utf8;' > $EXPORT_FILE;";
364 $cmd .= "$mysql_dump_cmd -u " . escapeshellarg($sqlconf["login"]) .
365 " -p" . escapeshellarg($sqlconf["pass"]) .
366 " --opt --quote-names " .
367 escapeshellarg($sqlconf["dbase"]) . " $tables";
370 # The Perl script differs in windows also.
371 $cmd .= " | $perl -pe \"s/ DEFAULT CHARSET=utf8//i; s/ collate[ =][^ ;,]*//i;\"" .
372 " >> $EXPORT_FILE & ";
376 $cmd .= " | $perl -pe 's/ DEFAULT CHARSET=utf8//i; s/ collate[ =][^ ;,]*//i;'" .
380 $dumppfx = "$mysql_dump_cmd -u " . escapeshellarg($sqlconf["login"]) .
381 " -p" . escapeshellarg($sqlconf["pass"]) .
382 " --skip-opt --quote-names --complete-insert --no-create-info";
384 if (is_array($_POST['form_sel_lists']))
386 foreach ($_POST['form_sel_lists'] as $listid)
390 # windows will place the quotes in the outputted code if they are there. we removed them here.
391 $cmd .= " echo DELETE FROM list_options WHERE list_id = '$listid'; >> $EXPORT_FILE & ";
392 $cmd .= " echo DELETE FROM list_options WHERE list_id = 'lists' AND option_id = '$listid'; >> $EXPORT_FILE & ";
396 $cmd .= "echo \"DELETE FROM list_options WHERE list_id = '$listid';\" >> $EXPORT_FILE;";
397 $cmd .= "echo \"DELETE FROM list_options WHERE list_id = 'lists' AND option_id = '$listid';\" >> $EXPORT_FILE;";
400 " --where=\"list_id = 'lists' AND option_id = '$listid' OR list_id = '$listid'\" " .
401 escapeshellarg($sqlconf["dbase"]) . " list_options";
404 # windows uses the & to join statements.
405 $cmd .= " >> $EXPORT_FILE & ";
409 $cmd .= " >> $EXPORT_FILE;";
413 // Individual layouts.
414 if (is_array($_POST['form_sel_layouts']))
416 foreach ($_POST['form_sel_layouts'] as $layoutid)
420 # windows will place the quotes in the outputted code if they are there. we removed them here.
421 $cmd .= " echo DELETE FROM layout_options WHERE form_id = '$layoutid'; >> $EXPORT_FILE & ";
425 $cmd .= "echo \"DELETE FROM layout_options WHERE form_id = '$layoutid';\" >> $EXPORT_FILE;";
427 if (strpos($layoutid, 'LBF') === 0)
431 # windows will place the quotes in the outputted code if they are there. we removed them here.
432 $cmd .= " echo DELETE FROM list_options WHERE list_id = 'lbfnames' AND option_id = '$layoutid'; >> $EXPORT_FILE & ";
436 $cmd .= "echo \"DELETE FROM list_options WHERE list_id = 'lbfnames' AND option_id = '$layoutid';\" >> $EXPORT_FILE;";
439 " --where=\"list_id = 'lbfnames' AND option_id = '$layoutid'\" " .
440 escapeshellarg($sqlconf["dbase"]) . " list_options" ;
443 # windows uses the & to join statements.
444 $cmd .= " >> $EXPORT_FILE & ";
448 $cmd .= " >> $EXPORT_FILE;";
452 " --where=\"form_id = '$layoutid'\" " .
453 escapeshellarg($sqlconf["dbase"]) . " layout_options" ;
456 # windows uses the & to join statements.
457 $cmd .= " >> $EXPORT_FILE & ";
461 $cmd .= " >> $EXPORT_FILE;";
468 echo xl('No items were selected!');
471 $auto_continue = true;
474 if ($form_step == 103) {
475 $form_status .= xl('Done. Will now send download.') . "<br />";
476 echo nl2br($form_status);
477 $auto_continue = true;
480 if ($form_step == 201) {
481 echo xl('WARNING: This will overwrite configuration information with data from the uploaded file!') . " \n";
482 echo xl('Use this feature only with newly installed sites, ');
483 echo xl('otherwise you will destroy references to/from existing data.') . "\n";
484 echo "<br /> <br />\n";
485 echo xl('File to upload') . ":\n";
486 echo "<input type='hidden' name='MAX_FILE_SIZE' value='4000000' />\n";
487 echo "<input type='file' name='userfile' /><br /> <br />\n";
488 echo "<input type='submit' value='" . xl('Continue') . "' />\n";
491 if ($form_step == 202) {
492 // Process uploaded config file.
493 if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
494 if (move_uploaded_file($_FILES['userfile']['tmp_name'], $EXPORT_FILE)) {
495 $form_status .= xl('Applying') . "...<br />";
496 echo nl2br($form_status);
497 $cmd = "$mysql_cmd -u" . escapeshellarg($sqlconf["login"]) .
498 " -p" . escapeshellarg($sqlconf["pass"]) . " " .
499 escapeshellarg($sqlconf["dbase"]) .
503 echo xl('Internal error accessing uploaded file!');
508 echo xl('Upload failed!');
511 $auto_continue = true;
514 if ($form_step == 203) {
515 $form_status .= xl('Done') . ".";
516 echo nl2br($form_status);
519 /// ViSolve : EventLog Backup
520 if ($form_step == 301) {
521 # Get the Current Timestamp, to attach with the log backup file
522 $backuptime=date("Ymd_His");
523 # Eventlog backup directory
524 $BACKUP_EVENTLOG_DIR = $GLOBALS['backup_log_dir'] . "/emr_eventlog_backup";
526 # Check if Eventlog Backup directory exists, if not create it with Write permission
527 if (!file_exists($BACKUP_EVENTLOG_DIR))
529 mkdir($BACKUP_EVENTLOG_DIR);
530 chmod($BACKUP_EVENTLOG_DIR,0777);
532 # Frame the Eventlog Backup File Name
533 $BACKUP_EVENTLOG_FILE=$BACKUP_EVENTLOG_DIR.'/eventlog_'.$backuptime.'.sql';
534 # 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.
535 $res=sqlStatement("create table if not exists log_comment_encrypt_new like log_comment_encrypt");
536 $res=sqlStatement("rename table log_comment_encrypt to log_comment_encrypt_backup,log_comment_encrypt_new to log_comment_encrypt");
537 $res=sqlStatement("create table if not exists log_new like log");
538 $res=sqlStatement("rename table log to log_backup,log_new to log");
540 $cmd = "$mysql_dump_cmd -u " . escapeshellarg($sqlconf["login"]) .
541 " -p" . escapeshellarg($sqlconf["pass"]) .
542 " --opt --quote-names -r $BACKUP_EVENTLOG_FILE " .
543 escapeshellarg($sqlconf["dbase"]) ." --tables log_comment_encrypt_backup log_backup";
544 # Set Eventlog Flag when it is done
556 <input type
='hidden' name
='form_step' value
='<?php echo $form_step; ?>' />
557 <input type
='hidden' name
='form_status' value
='<?php echo $form_status; ?>' />
565 $tmp0 = exec($cmd, $tmp1, $tmp2);
571 // ViSolve : Restore previous state, if backup fails.
572 $res=sqlStatement("drop table if exists log_comment_encrypt");
573 $res=sqlStatement("rename table log_comment_encrypt_backup to log_comment_encrypt");
574 $res=sqlStatement("drop table if exists log");
575 $res=sqlStatement("rename table log_backup to log");
577 die("\"$cmd\" returned $tmp2: $tmp0");
579 // ViSolve: If the Eventlog is set, then clear the temporary table -- Start here
581 $res=sqlStatement("drop table if exists log_backup");
582 $res=sqlStatement("drop table if exists log_comment_encrypt_backup");
584 echo xl('Backup Successfully taken in')." ";
585 echo $BACKUP_EVENTLOG_DIR;
588 // ViSolve: If the Eventlog is set, then clear the temporary table -- Ends here
590 // If a file was flagged to be gzip-compressed after this cmd, do it.
591 if ($file_to_compress) {
592 if (!gz_compress_file($file_to_compress))
593 die (xl("Error in gzip compression of file: ") . $file_to_compress);
599 <?php
if ($auto_continue) { ?
>
600 <script language
="JavaScript">
601 setTimeout("document.forms[0].submit();", 500);
605 // Recursive directory remove (like an O/S insensitive "rm -rf dirname")
606 function obliterate_dir($dir) {
607 if (!file_exists($dir)) return true;
608 if (!is_dir($dir) ||
is_link($dir)) return unlink($dir);
609 foreach (scandir($dir) as $item) {
610 if ($item == '.' ||
$item == '..') continue;
611 if (!obliterate_dir($dir . DIRECTORY_SEPARATOR
. $item)) {
612 chmod($dir . DIRECTORY_SEPARATOR
. $item, 0777);
613 if (!obliterate_dir($dir . DIRECTORY_SEPARATOR
. $item)) return false;
619 // Create a tar archive given the archive file name, compression method if any, and the
620 // array of file/directory names to archive
621 function create_tar_archive($archiveName, $compressMethod, $itemArray) {
622 global $newBackupMethod;
624 if ($newBackupMethod) {
625 // Create a tar object using the pear library
626 // (this is the preferred method)
627 $tar = new Archive_Tar($archiveName, $compressMethod);
628 if ($tar->create($itemArray)) return true;
631 // Create the tar files via command line tools
632 // (this method used when the tar pear library is not available)
633 $files = '"' . implode('" "', $itemArray) . '"';
634 if ($compressMethod == "gz") {
635 $command = "tar --same-owner --ignore-failed-read -zcphf $archiveName $files";
638 $command = "tar -cpf $archiveName $files";
640 $temp0 = exec($command, $temp1, $temp2);
641 if ($temp2) die("\"$command\" returned $temp2: $temp0");
647 // Compress a file using gzip. Source file removed, leaving only the compressed
648 // *.gz file, just like gzip command line would behave.
649 function gz_compress_file($source) {
652 if ($fp_in=fopen($source,'rb')) {
653 if ($fp_out=gzopen($dest,'wb')) {
655 gzwrite($fp_out,fread($fp_in,1024*512));