dev ldap fixes (#3914)
[openemr.git] / library / edihistory / edih_archive.php
blob0b4fcef6c2e167e8fd62690cdb6ef778b2acbd2c
1 <?php
3 /**
4 * edih_archive.php
5 * Purpose: to archive old entries in the csv files and old files
7 * @package OpenEMR
8 * @subpackage ediHistory
9 * @link https://www.open-emr.org
10 * @author Kevin McCormick
11 * @copyright Copyright (c) 2016 Kevin McCormick Longview, Texas
12 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
15 // a security measure to prevent direct web access to this file
16 // must be accessed through the main calling script ibr_history.php
17 // from admin at rune-city dot com; found in php manual
18 //if (!defined('SITE_IN')) die('Direct access not allowed!');
21 // required functions
22 //require_once("$srcdir/edihistory/test_edih_csv_inc.php");
24 // constant DS = DIRECTORY_SEPARATOR
26 /**
27 * Report on edi_history
29 * @uses csv_parameters()
30 * @uses csv_assoc_array()
32 * @param string archive date in CCYYMMDD format
34 * @return array array[i] = filename
36 function edih_archive_report($period = '')
39 $str_html = '';
40 $chkdt = '';
41 $strdt = '';
42 // edih_archive_date returns empty string if no period
43 $tper = edih_archive_date($period);
44 $chkdt = ($tper) ? $tper : 'None';
45 $strdt = ($tper) ? substr($chkdt, 0, 4) . '-' . substr($chkdt, 4, 2) . '-' . substr($chkdt, 6, 2) : 'None';
47 csv_edihist_log("edih_archive_report: creating archive report with date $chkdt");
49 $bdir = csv_edih_basedir();
50 $params = csv_parameters('ALL');
51 if (!is_array($params) && count($params)) {
52 csv_edihist_log("edih_archive_report: invalid csv_parameters");
53 return "<p>There was an error creating the report.</p>";
57 $str_html .= "<h3>Report on edi files using archive date " . text($strdt) . "</h3>" . PHP_EOL;
58 foreach ($params as $key => $param) {
59 $old_ct = 0;
60 $clm_ct = 0;
61 $dir_ct = 0;
62 $dir_sz = 0;
63 $row_ct = 0;
64 $dir_kb = '';
65 $subdir_ct = 0;
66 $fntp = '';
67 $fntp_ct = 0;
69 $tp = $param['type'];
70 $fdir = $param['directory'];
72 if (is_dir($fdir)) {
73 $dir_ar = scandir($fdir);
74 if (is_array($dir_ar) && ((count($dir_ar) - 2) > 0)) {
75 $str_html .= "<H3><em>Type</em> " . text($tp) . "</H3>" . PHP_EOL;
76 $str_html .= "<ul>" . PHP_EOL;
77 $dir_ct = count($dir_ar);
78 foreach ($dir_ar as $fn) {
79 if ($fn == 'README.txt') {
80 $dir_ct--;
81 continue;
84 if (substr($fn, 0, 1) == '.') {
85 $dir_ct--;
86 continue;
89 if (is_dir($fdir . DS . $fn)) {
90 $subdir_ct++;
91 $dir_ct--;
92 continue;
95 $dir_sz += filesize($fdir . DS . $fn);
99 $csv_ar = csv_assoc_array($tp, 'file');
100 $row_ct = (is_array($csv_ar)) ? count($csv_ar) : 0;
101 if ($row_ct) {
102 foreach ($csv_ar as $row) {
103 // tally amount of claim transactions in the files
104 if ($tp == 'f837') {
105 $clm_ct += $row['Claim_ct'];
108 if ($tp == 'f277') {
109 $clm_ct += ($row['Accept'] + $row['Reject']);
112 if ($tp == 'f835') {
113 $clm_ct += $row['Claim_ct'];
116 // check for duplicates
117 // here assume that files with multiple rows are consecutive
118 if ($fntp !== $row['FileName']) {
119 $fntp = $row['FileName'];
120 // count files that would be archived
121 if (($chkdt != 'None') && strcmp($row['Date'], $chkdt) < 0) {
122 $old_ct++;
125 $fntp_ct++;
130 $dir_kb = csv_convert_bytes($dir_sz);
131 } else {
132 csv_edihist_log("edih_archive_report: error $tp file count $dir_ct with csv rows $row_ct");
136 $mis = ($fntp_ct == $dir_ct ) ? "(check/eft count or ISA--IEA count)" : "(mismatch csv $fntp_ct dir $dir_ct)";
138 if ($tp == 'f837') {
139 $str_html .= "<li><em>Note:</em> 837 Claims files are not archived </li>" . PHP_EOL;
143 $str_html .= "<li>files directory has " . text($dir_ct) . " files, using " . text($dir_kb) . " </li>" . PHP_EOL;
144 $str_html .= ($subdir_ct && ($tp != 'f837')) ? "<li> <em>warning</em> found " . text($subdir_ct) . " sub-directories</li>" . PHP_EOL : "";
145 $str_html .= "<li>files csv table has " . text($row_ct) . " rows " . text($mis) . "</li>" . PHP_EOL;
146 $str_html .= ($clm_ct) ? "<li>there are " . text($clm_ct) . " claim transactions counted</li>" . PHP_EOL : "";
147 $str_html .= ($old_ct) ? "<li>Archive date " . text($strdt) . " would archive " . text($old_ct) . " files </li>" . PHP_EOL : "";
148 $str_html .= "</ul>" . PHP_EOL;
149 } else {
150 $str_html .= "<p><em>Type</em> <b>" . text($tp) . "</b> <br /> -- empty " . text($tp) . " file directory</p>" . PHP_EOL;
152 } else {
153 $str_html .= "<p><em>warning</em> <b>" . text($tp) . "</b> file directory does not exist</p>" . PHP_EOL;
157 $str_html .= "<p>Report end</p>" . PHP_EOL;
159 return $str_html;
164 * Format the date used in comparisons
166 * @param string period from select list e.g. 6m, 12m
168 * @return string archive date in CCYYMMDD format
170 function edih_archive_date($period)
173 $dtpd2 = '';
174 if (!$period) {
175 return $dtpd2;
178 $is_period = preg_match('/\d{1,2}(?=m)/', $period, $matches);
180 if (count($matches)) {
181 $gtdt = getdate();
183 if (strpos($period, 'm')) {
184 // take the number part of 'period'
185 // so modstr will be '-N month'
186 $modstr = '-' . $matches[0] . ' month';
187 $dtstr1 = $gtdt['mon'] . '/01/' . $gtdt['year'];
188 } elseif (strpos($period, 'y')) {
189 $modstr = '-' . $matches[0] . ' year';
190 $dtstr1 = $gtdt['mon'] . '/01/' . $gtdt['year'];
191 } else {
192 csv_edihist_log("edih_archive_date: incorrect date period $period");
193 return false;
197 if ($modstr) {
198 $dtpd1 = date_create($dtstr1);
199 $dtm = date_modify($dtpd1, $modstr);
200 $dtpd2 = $dtm->format('Ymd');
201 } else {
202 csv_edihist_log("edih_archive_date: failed to parse $period");
203 return false;
205 } else {
206 csv_edihist_log("edih_archive_date: invalid argment $period");
207 return false;
210 // the testing date in CCYYMMDD format
211 return $dtpd2;
216 * Create an array of file names to be archived
217 * The 'Date' column in the files_[type].csv file
218 * is compared to the archive date. If the date is less
219 * than the archive date, the "FileName' value is copied
221 * @param array csv file rows array
222 * @param string archive date in CCYYMMDD format
224 * @return array array[i] = filename
226 function edih_archive_filenames($csv_ar, $archive_date)
229 if ($archive_date && strlen($archive_date) == 8 && is_numeric($archive_date)) {
230 $testdate = (string)$archive_date;
231 } else {
232 csv_edihist_log("edih_archive_filenames: invalid archive date $archive_date");
233 return false;
237 if (!is_array($csv_ar) || !count($csv_ar)) {
238 csv_edihist_log("edih_archive_filenames: failed to get csv file array $file_type");
239 return false;
243 $fn_ar = array();
244 foreach ($csv_ar as $row) {
245 if (strcmp($row['Date'], $archive_date) < 0) {
246 $fn_ar[] = $row['FileName'];
250 $ret_ar = (count($fn_ar)) ? array_values(array_unique($fn_ar)) : $fn_ar;
252 return $ret_ar;
256 * Create a new csv array by omitting rows which reference
257 * a file name that is to be archived
259 * @uses csv_file_type()
260 * @uses csv_assoc_array()
262 * @param string the file type
263 * @param string the csv type file or claim
264 * @param array the array of archived file names and retained file names
266 * @return array
268 function edih_archive_csv_split($csv_ar, $filename_array)
271 if (!is_array($filename_array) || !count($filename_array)) {
272 csv_edihist_log('csv_archive_table; invalid filename array');
273 return false;
277 if (is_array($csv_ar) && count($csv_ar)) {
278 csv_edihist_log("edih_archive_csv_split: csv rows " . count($csv_ar) . " old files " . count($filename_array));
279 } else {
280 csv_edihist_log("edih_archive_csv_split: failed to get csv file array");
281 return false;
285 // if the to be archived file name is in the row,
286 // do not copy it to the new csv array
287 $arch_ar = array();
288 $arch_ar['arch'] = array();
289 $arch_ar['keep'] = array();
291 foreach ($csv_ar as $row) {
292 if (in_array($row['FileName'], $filename_array)) {
293 $arch_ar['arch'][] = $row;
294 } else {
295 $arch_ar['keep'][] = $row;
300 csv_edihist_log("edih_archive_csv_split: 'arch' array rows " . count($arch_ar['arch']));
301 csv_edihist_log("edih_archive_csv_split: 'keep' array rows " . count($arch_ar['keep']));
303 return $arch_ar;
308 * Creates a zip archive of the files in the $filename_ar array and
309 * returns the path/name of the archive or FALSE on error
311 * @param array $parameters array for file type from csv_parameters
312 * @param array $filename_ar array of filenames to be archived
313 * @param string $archive_date date of archive to be incorporated in archive file name
315 * @return bool result of zipArchive functions
317 function edih_archive_create_zip($parameters, $filename_ar, $archive_date, $archive_filename)
319 // we deal with possible maximum files issues by chunking the $fn_ar array
321 $ft = $parameters['type'];
322 $fdir = $parameters['directory'];
323 $tmp_dir = csv_edih_tmpdir();
324 // archive csv rows -- same name as from edih_archive_main
325 // $fn_files_arch = $tmp_dir.DS.'arch_'.basename($files_csv);
326 $files_csv_arch = 'arch_' . basename($parameters['files_csv']);
327 // $fn_claims_arch = $tmp_dir.DS.'arch_'.basename($claim_csv);
328 $claims_csv_arch = 'arch_' . basename($parameters['claims_csv']);
330 $f_max = 200;
331 $fn_ar2 = array();
332 // to handle possibility of more than 200 files in the archive
333 // use the 'chunk' method
334 if (count($filename_ar) > $f_max) {
335 $fn_ar2 = array_chunk($filename_ar, $f_max);
336 } else {
337 $fn_ar2[] = $filename_ar;
341 $zip_name = $tmp_dir . DS . $archive_filename;
342 csv_edihist_log("edih_archive_create_zip: using $zip_name");
344 $zip_obj = new ZipArchive();
345 csv_edihist_log("edih_archive_create_zip: now opening archive $archive_filename");
346 if (is_file($zip_name)) {
347 $isOK = $zip_obj->open($zip_name, ZipArchive::CHECKCONS);
348 if ($isOK) {
349 if ($zip_obj->locateName($ft) === false) {
350 $isOK = $zip_obj->addEmptyDir($ft);
351 if (!$isOK) {
352 csv_edihist_log("edih_archive_create_zip: adding $ft ZipArchive error $msg");
353 return $isOK;
356 } else {
357 $msg = $zip_obj->getStatusString();
358 csv_edihist_log("edih_archive_create_zip: $ft ZipArchive error $msg");
359 return $isOK;
361 } else {
362 $isOK = $zip_obj->open($zip_name, ZipArchive::CREATE);
363 $isOK = $zip_obj->addEmptyDir('csv');
364 $isOK = $zip_obj->addEmptyDir($ft);
365 $zip_obj->setArchiveComment("edi_history archive prior to $archive_date");
368 // we are working with the open archive
369 // now add the old csv files to the archive
370 if (is_file($tmp_dir . DS . $files_csv_arch)) {
371 csv_edihist_log("edih_archive_create_zip: now adding $files_csv_arch to archive");
372 $isOK = $zip_obj->addFile($tmp_dir . DS . $files_csv_arch, 'csv' . DS . $files_csv_arch);
375 if (is_file($tmp_dir . DS . $claims_csv_arch)) {
376 csv_edihist_log("edih_archive_create_zip: now adding $claims_csv_arch to archive");
377 $isOK = $zip_obj->addFile($tmp_dir . DS . $claims_csv_arch, 'csv' . DS . $claims_csv_arch);
380 // close zip archive
381 csv_edihist_log("edih_archive_create_zip: now closing archive");
382 $isOK = $zip_obj->close();
383 if ($isOK !== true) {
384 $msg = $zip_obj->getStatusString();
385 csv_edihist_log("edih_archive_create_zip: $ft ZipArchive error $msg");
386 return $isOK;
389 // $fn_ar2[i][j]
390 csv_edihist_log("edih_archive_create_zip: with file name groups " . count($fn_ar2));
391 foreach ($fn_ar2 as $fnz) {
392 // reopen the zip archive on each loop so the open file count is controlled
393 if (is_file($zip_name)) {
394 csv_edihist_log("edih_archive_create_zip: now opening archive");
395 $isOK = $zip_obj->open($zip_name, ZipArchive::CHECKCONS);
399 if ($isOK === true) {
400 // we are working with the open archive
401 // now add the old x12 files to the archive
402 csv_edihist_log("edih_archive_create_zip: now adding $ft files to archive");
403 foreach ($fnz as $fz) {
404 if ($fz == '.' || $fz == '..') {
405 continue;
408 if (is_file($fdir . DS . $fz) && is_readable($fdir . DS . $fz)) {
409 $isOK = $zip_obj->addFile($fdir . DS . $fz, $ft . DS . $fz);
410 } else {
411 // possible that file is in csv table, but not in directory?
412 $msg = $zip_obj->getStatusString();
413 csv_edihist_log("edih_archive_create_zip: error adding file $fz zipArchive: $msg");
415 } // end foreach($fnz as $fz)
416 // close zip object for next iteration of chunked array
417 csv_edihist_log("edih_archive_create_zip: now closing archive");
418 $isOK = $zip_obj->close();
419 // errors on close would be non-existing file added or something else
420 if ($isOK !== true) {
421 $msg = $zip_obj->getStatusString();
422 csv_edihist_log("edih_archive_create_zip: $ft ZipArchive error $msg");
424 return $isOK;
426 } else {
427 // ZipArchive open() failed -- try to get the error message and return false
428 $msg = $zip_obj->getStatusString();
429 csv_edihist_log("edih_archive_create_zip: $ft ZipArchive failed $msg");
430 return $isOK;
431 }// end if ($isOK)
433 } // end foreach($fn_ar2 as $fnz)
435 return $isOK;
439 * Archived files have been included in archive file
440 * so we move the files to the archive tmp directory, for later deletion
442 * @param array parameters array for type
443 * @param array filename array
445 * @return int count of moved files
447 function edih_archive_move_old($parameters, $filename_ar)
450 if (!is_array($filename_ar) || !count($filename_ar)) {
451 return false;
454 if (!is_array($parameters) || !count($parameters)) {
455 return false;
459 clearstatcache(true);
461 $fnct = 0;
462 $fn_ar_ct = count($filename_ar);
463 $ft = $parameters['type'];
464 $fdir = $parameters['directory'];
465 $fdir = realpath($fdir);
466 $rndir = csv_edih_tmpdir() . DS . $ft;
468 if (is_dir($fdir)) {
469 csv_edihist_log("edih_archive_delete_old: $ft dir OK");
470 if (is_dir($rndir) || mkdir($rndir)) {
471 $rndir = realpath($rndir);
472 csv_edihist_log("edih_archive_delete_old: $ft move dir OK");
473 $isOK = true;
474 } else {
475 csv_edihist_log("edih_archive_delete_old: $ft move dir error");
476 $isOK = false;
478 } else {
479 csv_edihist_log("edih_archive_delete_old: $ft dir error");
480 $isOK = false;
484 if ($isOK) {
485 csv_edihist_log("edih_archive_delete_old: $ft old file count $fn_ar_ct");
486 foreach ($filename_ar as $fn) {
487 // if we have added the file to the archive, remove it from the storage directory
488 // but keep the /history/tmp file copy for now
489 if (is_file($fdir . DS . $fn)) {
490 $isrn = rename($fdir . DS . $fn, $rndir . DS . $fn);
494 if ($isrn) {
495 $fnct++;
496 } else {
497 csv_edihist_log("edih_archive_delete_old: $ft failed to move $fn");
500 } else {
501 csv_edihist_log("edih_archive_delete_old: $ft directory error for files or tmp");
505 return $fnct;
510 * create associative array from archive csv file
512 * @uses edih_archive_csv_array()
514 * @param string
515 * @param string
516 * @param string optional filepath
518 * @return array
520 function edih_archive_csv_array($filetype, $csv_type, $filepath = '')
523 $str_out = '';
524 $csv_ar = array();
525 $tmpdir = csv_edih_tmpdir();
526 $tmpcsv = $tmpdir . DS . 'csv';
528 $csvtp = (strpos($csv_type, 'aim')) ? 'claims' : 'files';
530 if (is_file($filepath)) {
531 $csv_arch_path = $filepath;
532 } else {
533 $csv_arch_path = $tmpcsv . DS . 'arch_' . $csvtp . '_' . $filetype . '.csv';
537 $ct = 0;
538 $row = 0;
539 $ky = -1;
540 // relies on first row being header or column names
541 if (($fh = fopen($csv_arch_path, "rb")) !== false) {
542 while (($data = fgetcsv($fh, 2048, ",")) !== false) {
543 if (is_null($data)) {
544 continue;
547 if ($row) {
548 for ($i = 0; $i < $ct; $i++) {
549 $csv_ar[$ky][$h[$i]] = $data[$i];
551 } else {
552 $ct = count($data);
553 $h = $data;
556 $row++;
557 $ky++;
560 fclose($fh);
561 } else {
562 // invalid file path
563 csv_edihist_log('edih_archive_csv_array; invalid file path ' . $csv_arch_path);
564 return false;
568 return $csv_ar;
572 * combine the csv file in the archive with the current csv file
574 * @uses edih_archive_csv_array()
576 * @param string
577 * @param string
579 * @return string
581 function edih_archive_csv_combine($filetype, $csvtype)
584 $str_out = '';
585 $hdr_ar = array();
586 $bdir = csv_edih_basedir();
587 $tmpdir = csv_edih_tmpdir();
588 $tmpcsv = $tmpdir . DS . 'csv';
590 $csvtp = (strpos($csvtype, 'aim')) ? 'claims' : 'files';
591 $csv_arch_file = $tmpcsv . DS . 'arch_' . $csvtp . '_' . $filetype . '.csv';
592 $csv_new_file = $tmpdir . DS . 'cmb_' . $csvtp . '_' . $filetype . '.csv';
594 // arrays used to eliminate duplicate rows
595 $dup_ar = $dup_unique = $dup_keys = array();
596 // combine files by combining arrays and writing a tmp file
597 // get the present csv file contents
598 $car1 = csv_assoc_array($filetype, $csvtp);
599 // get the archived csv contents
600 if (is_file($csv_arch_file)) {
601 $car2 = edih_archive_csv_array($filetype, $csvtp, $csv_arch_file);
604 // possibility of empty arrays if no data rows in a csv file
605 $hdrc1 = (is_array($car1) && count($car1)) ? array_keys($car1[0]) : array();
606 $hdrc2 = (is_array($car2) && count($car2)) ? array_keys($car2[0]) : array();
607 if (count($hdrc1) && ($hdrc1 === $hdrc2)) {
608 $hdr_ar = $hdrc1;
609 } elseif (empty($hdrc1) && count($hdrc2)) {
610 $hdr_ar = $hdrc2;
611 } elseif (empty($hdrc2) && count($hdrc1)) {
612 $hdr_ar = $hdrc1;
613 } else {
614 // array mismatch error (impossible?)
615 csv_edihist_log("edih_archive_csv_combine: $filetype $csvtp array header mismatch");
616 // just use the current csv file
617 $hdr_ar = csv_table_header($filetype, $csvtp);
618 $car_cmb_unique = $car1;
619 // debug
620 if (count($hdrc1)) {
621 $dbg_str = '';
622 foreach ($hdrc1 as $h) {
623 $dbg_str .= $h . ' ';
626 csv_edihist_log("edih_archive_csv_combine: $csvtp car1 header $dbg_str");
627 } else {
628 csv_edihist_log("edih_archive_csv_combine: $csvtp car1 header empty");
631 if (count($hdrc2)) {
632 $dbg_str = '';
633 foreach ($hdrc2 as $h) {
634 $dbg_str .= $h . ' ';
637 csv_edihist_log("edih_archive_csv_combine: $csvtp car2 header $dbg_str");
638 } else {
639 csv_edihist_log("edih_archive_csv_combine: $csvtp car2 header empty");
645 // if the arrays checked out
646 if (!isset($car_cmb_unique)) {
647 // if we have archive csv rows
648 if (is_array($car1) && is_array($car2)) {
649 // put the archive rows first
650 $car_cmb = array_merge($car2, $car1);
651 // now eliminate duplicates
652 if ($csvtp == 'files') {
653 if ($filetype == 'f835') {
654 $ky = 'Trace';
655 } else {
656 $ky = 'Control';
659 // array_column() php v5.5
660 foreach ($car_cmb as $idx => $row) {
661 $dup_ar[$idx] = $row[$ky];
664 csv_edihist_log("edih_archive_csv_combine: $csvtp array row count " . count($dup_ar));
665 $dup_unique = array_unique($dup_ar);
666 $dup_keys = array_keys($dup_unique);
667 csv_edihist_log("edih_archive_csv_combine: $csvtp index row count " . count($dup_keys));
668 foreach ($dup_keys as $k) {
669 $car_cmb_unique[] = $car_cmb[$k];
672 csv_edihist_log("edih_archive_csv_combine: $csvtp combined row count " . count($car_cmb_unique));
673 } elseif ($csvtp == 'claims') {
674 $ct = count($hdr_ar);
675 $ftxt = $csvtp . ' array' . PHP_EOL;
676 foreach ($car_cmb as $idx => $row) {
677 $r_str = '';
678 for ($i = 0; $i < $ct; $i++) {
679 $r_str .= $row[$hdr_ar[$i]];
682 $dup_ar[$idx] = $r_str;
683 $ftxt .= $r_str . PHP_EOL;
686 csv_edihist_log("edih_archive_csv_combine: $csvtp array row count " . count($dup_ar));
687 file_put_contents($tmpdir . DS . 'archive' . DS . 'claimstr.txt', $ftxt);
689 $dup_unique = array_unique($dup_ar);
690 $dup_keys = array_keys($dup_unique);
691 csv_edihist_log("edih_archive_csv_combine: $csvtp index row count " . count($dup_keys));
692 foreach ($dup_keys as $k) {
693 $car_cmb_unique[] = $car_cmb[$k];
696 csv_edihist_log("edih_archive_csv_combine: $csvtp combined row count " . count($car_cmb_unique));
697 } else {
698 $car_cmb_unique = $car_cmb;
700 } else {
701 csv_edihist_log("edih_archive_csv_combine: array keys mismatch $filetype");
703 } else {
704 csv_edihist_log("edih_archive_csv_combine: error reading archived csv " . $csvtp . "_" . $filetype . ".csv");
707 $rwct = 0;
708 $fh = fopen($csv_new_file, 'wb');
709 if ($fh) {
710 fputcsv($fh, $hdr_ar);
711 $rwct++;
713 foreach ($car_cmb_unique as $row) {
714 fputcsv($fh, $row);
715 $rwct++;
718 // close new csv file
719 fclose($fh);
720 } else {
721 csv_edihist_log("edih_archive_csv_combine: failed to open $filetype new csv file");
724 return $rwct;
728 * Unpack an existing archive and restore it to current csv records
729 * and replace the files in the respective directories
731 * @uses edih_archive_csv_combine
732 * @param string
734 * @return string
736 function edih_archive_restore($archive_name)
739 $str_out = '';
740 $bdir = csv_edih_basedir();
741 $tmpdir = csv_edih_tmpdir();
742 $archdir = $bdir . DS . 'archive';
744 if (is_file($archdir . DS . $archive_name)) {
745 $arch = realpath($archdir . DS . $archive_name);
746 $str_out .= "Archive: restoring " . text($archive_name) . "<br />";
747 csv_edihist_log("edih_archive_restore: restoring $archive_name");
748 } else {
749 $str_out = "Archive: restore archive bad file name " . text($archive_name) . " <br />";
750 csv_edihist_log("edih_archive_restore: restore archive bad file name $archive_name");
751 return $str_out;
755 $zip_obj = new ZipArchive();
756 // open archive (ZipArchive::CHECKCONS the ZipArchive::CREATE is supposedly necessary for microsoft)
757 //$res = $zip_obj->open($arch, ZipArchive::CHECKCONS);
758 if ($zip_obj->open($arch, ZipArchive::CHECKCONS) === true) {
759 $f_ct = $zip_obj->numFiles;
760 $str_out .= "Extracting " . text($f_ct) . " items from " . text($archive_name) . " <br />";
761 csv_edihist_log("edih_archive_restore: Extracting $f_ct items from $archive_name");
762 $isOK = $zip_obj->extractTo($tmpdir);
763 if (!$isOK) {
764 $msg = $zip_obj->getStatusString();
765 csv_edihist_log("edih_archive_restore: error extracting archive");
766 $str_out .= "Archive: error extracting archive " . text($archive_name) . " <br />";
767 $str_out .= "zipArchive: " . text($msg) . " <br />";
768 return $str_out;
770 } else {
771 $msg = $zip_obj->getStatusString();
772 csv_edihist_log("edih_archive_restore: error opening archive");
773 $str_out .= "Archive: error opening archive <br />" . PHP_EOL;
774 $str_out .= "zipArchive: " . text($msg) . " <br />";
775 return $str_out;
778 // now traverse the tmpdir and replace things
779 // we should have tmp/csv/files_[ftype].csv claims_[ftype].csv
780 // tmp/[ftype]/x12_filenames
781 $arch_ar = scandir($tmpdir);
782 $tpstr = '';
783 foreach ($arch_ar as $fa) {
784 if ($fa == '.' || $fa == '..') {
785 continue;
788 if (is_dir($tmpdir . DS . $fa)) {
789 if ($fa == 'csv') {
790 continue;
793 // if a /history/ftype dir exists
794 if (is_dir($bdir . DS . $fa)) {
795 $type_ar[] = $fa;
796 $tpstr .= "$fa ";
798 } else {
799 continue;
804 csv_edihist_log("edih_archive_restore: types in archive $tpstr");
805 $str_out .= "Archive: types in archive " . text($tpstr) . " <br />" . PHP_EOL;
807 foreach ($type_ar as $ft) {
808 $str_out .= "Archive: now restoring " . text($ft) . "<br />" . PHP_EOL;
809 csv_edihist_log("edih_archive_restore: now restoring $ft");
811 $frows = edih_archive_csv_combine($ft, 'file');
812 csv_edihist_log("edih_archive_restore: files_$ft csv combined rows $frow");
813 $crows = edih_archive_csv_combine($ft, 'claim');
814 csv_edihist_log("edih_archive_restore: claims_$ft csv combined rows $frow");
816 $file_ar = scandir($tmpdir . DS . $ft);
817 foreach ($file_ar as $fn) {
818 if ($fn == '.' || $fn == '..') {
819 continue;
822 if (is_file($tmpdir . DS . $ft . DS . $fn)) {
823 $rn = rename($tmpdir . DS . $ft . DS . $fn, $bdir . DS . $ft . DS . $fn);
824 if (!$rn) {
825 $str_out .= " -- error restoring " . text($ft) . DS . text($fn) . "<br />" . PHP_EOL;
826 csv_edihist_log("edih_archive_restore: error restoring " . $ft . DS . $fn);
831 // this will catch the csv files for the particulat type
832 $str_out .= "Archive: now replacing csv tables for " . text($ft) . "<br />" . PHP_EOL;
833 csv_edihist_log("edih_archive_restore: now replacing csv tables for $ft");
835 $rnf = rename($tmpdir . DS . 'cmb_files_' . $ft . '.csv', $bdir . DS . 'csv' . DS . 'files_' . $ft . '.csv');
836 $rnc = rename($tmpdir . DS . 'cmb_claims_' . $ft . '.csv', $bdir . DS . 'csv' . DS . 'claims_' . $ft . '.csv');
837 $str_out .= ($rnf) ? "" : " -- error restoring files_" . text($ft) . ".csv <br />" . PHP_EOL;
838 $str_out .= ($rnc) ? "" : " -- error restoring claims_" . text($ft) . ".csv <br />" . PHP_EOL;
842 csv_edihist_log("edih_archive_restore: now removing archive file");
843 $str_out .= "Archive: now removing archive file <br />" . PHP_EOL;
844 $rm = unlink($arch);
845 if (!$rm) {
846 csv_edihist_log("edih_archive_restore: error removing $archdir.DS.$archive_name");
847 $str_out .= ($rnf) ? "" : " -- error removing " . text($archdir) . "." . DS . "." . text($archive_name) . PHP_EOL;
851 //edih_archive_cleanup($arch_fn, $tp_ar);
852 csv_edihist_log("edih_archive_restore: now removing temporary files");
853 $str_out .= "Archive: now removing temporary files <br />" . PHP_EOL;
856 $is_clear = csv_clear_tmpdir();
857 if ($is_clear) {
858 $str_out .= "Archive: temporary files removed. Process complete.<br />" . PHP_EOL;
859 } else {
860 $str_out .= "Archive: still some files in /history/tmp/. Process complete.<br />" . PHP_EOL;
864 return $str_out;
869 * restores files from the tmp dir if the archive process needs to be aborted
871 * @uses csv_edih_basedir()
872 * @uses csv_edih_tmpdir()
873 * @uses csv_parameters()
875 * @return string
877 function edih_archive_undo()
880 // archive process creates files in /history/tmp
881 // /tmp/old_files_[type].csv copy of pre-archive csv record
882 // /tmp/old_claims_[type].csv copy of pre-archive csv record
883 // /tmp/new_files_[type].csv csv record of non-archived files
884 // /tmp/new_claims_[type].csv csv record of non-archived files
885 // /tmp/arch_files_[type].csv csv record of archived files (to be put in zip file)
886 // /tmp/arch_claims_[type].csv csv record of archived files (to be put in zip file)
887 // /tmp/[type]/filename_to_be_archived all the archived files for [type]
889 $str_out = '';
890 $bdir = csv_edih_basedir();
891 $tmpdir = csv_edih_tmpdir();
892 $archdir = $bdir . DS . 'archive';
894 $params = csv_parameters("ALL");
895 $types_ar = array_keys($params);
897 csv_edihist_log("edih_archive_undo: restoring prior csv files files");
898 foreach ($types_ar as $ft) {
899 if (is_file($tmpdir . DS . 'old_files_' . $ft . '.csv')) {
900 $rn = rename($tmpdir . DS . 'old_files_' . $ft . '.csv', $bdir . DS . 'csv' . DS . 'files_' . $ft . '.csv');
901 if ($rn) {
902 csv_edihist_log("edih_archive_undo: restored prior files_$ft ");
903 } else {
904 csv_edihist_log("edih_archive_undo: restore failed for prior files_$ft ");
908 if (is_file($tmpdir . DS . 'old_claims_' . $ft . '.csv')) {
909 $rn = rename($tmpdir . DS . 'old_claims_' . $ft . '.csv', $bdir . DS . 'csv' . DS . 'claims_' . $ft . '.csv');
910 if ($rn) {
911 csv_edihist_log("edih_archive_undo: restored prior claimss_$ft ");
912 } else {
913 csv_edihist_log("edih_archive_undo: restore failed for prior claims_$ft ");
918 $arch_ar = scandir($tmpdir);
919 foreach ($arch_ar as $fa) {
920 if ($fa == "." && $fa == "..") {
921 continue;
924 if (is_dir($tmpdir . DS . $fa)) {
925 if (in_array($fa, $types_ar)) {
926 $fpath = $params[$fa]['directory'];
927 if ($dh = opendir($tmpdir . DS . $fa)) {
928 $str_out .= "Archive: undo restoring " . text($fa) . " files<br />" . PHP_EOL;
929 csv_edihist_log("edih_archive_undo: restoring $fa files");
930 while (false !== ($entry = readdir($dh))) {
931 if ($entry != "." && $entry != "..") {
932 if (is_file($fpath . DS . $entry)) {
933 // file was not moved
934 } else {
935 rename($tmpdir . DS . $fa . DS . $entry, $fpath . DS . $entry);
940 closedir($dh);
946 return $str_out;
951 * After the archive is created, the csv record needs to be re-written so the archived
952 * files are not in the csv file and hence, not searched for.
954 * @uses csv_table_header()
956 * @param string $csv_path the tmp csv file path is expected
957 * @param array $row_array the data rows to be written (an associative array)
959 * @return integer count the rows written
961 function edih_archive_rewrite_csv($csv_path, $csv_keys, $row_array)
963 // @param string $csv_path -- the tmp csv file path is expected
964 // @param array $heading_ar -- the column heading for the csv file
965 // @param array $row_array -- the data rows to be written
967 // count characters written -- returned by fputcsv
968 $ocwct = 0;
969 $rwct = 0;
971 if (is_array($row_array)) {
972 csv_edihist_log("edih_archive_rewrite_csv: row array count " . count($row_array));
973 } else {
974 csv_edihist_log("edih_archive_rewrite_csv: row array not array");
978 if (is_array($row_array) && is_array($csv_keys)) {
979 if (count($csv_keys)) {
980 $h_ar = $csv_keys;
982 } else {
983 csv_edihist_log("edih_archive_rewrite_csv: invalid row array");
984 return $rwct;
987 //$csv_path should end with /history/tmp/[arch|keep]_[files|claims]_[type].csv
988 // with 'w' flag, place the file pointer at the beginning of the file
989 // and truncate the file to zero length.
990 // If the file does not exist, attempt to create it.
991 $fh3 = fopen($csv_path, 'wb');
992 if ($fh3) {
993 // write the heading row first
994 $ocwct += fputcsv($fh3, $h_ar);
995 // wrote heading, now add rows
996 foreach ($row_array as $row) {
997 $ocwct += fputcsv($fh3, $row);
998 $rwct++;
1001 fclose($fh3);
1002 csv_edihist_log("edih_archive_rewrite_csv: wrote " . count($row_array) . " rows to " . basename($csv_path));
1003 } else {
1004 csv_edihist_log("edih_archive_rewrite_csv: failed to open $csv_path");
1007 return $rwct;
1012 * cleanup archived files after archive created
1014 * @param string name of archive file
1015 * @param array array of types included in archive
1017 * @return string
1019 function edih_archive_cleanup($archivename, $types_ar)
1022 $str_out = '';
1024 if (is_array($types_ar) && count($types_ar)) {
1025 $tdirs = $types_ar;
1026 } else {
1027 csv_edihist_log("edih_archive_cleanup: no types in file types list");
1028 $str_out = "no types in file types list" . PHP_EOL;
1029 return $str_out;
1032 $bdir = csv_edih_basedir();
1033 $tmpdir = csv_edih_tmpdir();
1034 $archivedir = $bdir . DS . 'archive';
1035 $fct = 0;
1036 // move archive file to archive directory
1037 csv_edihist_log("edih_archive_cleanup: now clearing temporary files");
1038 $str_out .= "Archive: now clearing temporary files<br />" . PHP_EOL;
1039 // delete archived files from edih tmp dir
1040 foreach ($tdirs as $td) {
1041 csv_edihist_log("edih_archive_cleanup: cleaning up for $td");
1042 if (is_dir($tmpdir . DS . $td)) {
1043 $fn_ar = scandir($tmpdir . DS . $td);
1044 foreach ($fn_ar as $fn) {
1045 if ($fn == '.' || $fn == '..') {
1046 continue;
1049 if (is_file($tmpdir . DS . $td . DS . $fn)) {
1050 $ul = unlink($tmpdir . DS . $td . DS . $fn);
1051 if (!$ul) {
1052 csv_edihist_log("edih_archive_cleanup: error removing file $fn");
1053 $str_out .= "<p>edih_archive_cleanup: error removing file " . text($td) . DS . text($fn) . "</p>";
1054 } else {
1055 $fct++;
1060 // try to remove the now empty directory
1061 csv_edihist_log("edih_archive_cleanup: removing tmp $td");
1062 rmdir($tmpdir . DS . $td);
1065 csv_edihist_log("edih_archive_cleanup: removed $fct files from $td");
1068 return $str_out;
1073 * The main function in this edih_archive.php script. This function gets the parameters array
1074 * from csv_parameters() and calls the archiving functions on each type of file
1075 * in the parameters array.
1077 * @uses edih_archive_date()
1078 * @uses csv_edih_basedir()
1079 * @uses csv_parameters()
1080 * @uses csv_edih_tmpdir()
1081 * @uses csv_table_header()
1082 * @uses edih_archive_filenames()
1083 * @uses edih_archive_rewrite_csv()
1084 * @uses edih_archive_csv_split()
1085 * @uses edih_archive_create_zip()
1087 * @param string from select drop-down 6m, 12m, 18m, etc
1089 * @return string descriptive message in html format
1091 function edih_archive_main($period)
1094 $out_html = '';
1095 if ($period) {
1096 $archive_date = edih_archive_date($period);
1097 if ($archive_date) {
1098 $archive_dir = csv_edih_basedir() . DS . 'archive';
1099 $tmp_dir = csv_edih_tmpdir();
1100 $arch_fn = $archive_date . '_archive.zip';
1101 $params = csv_parameters();
1102 } else {
1103 csv_edihist_log("edih_archive_main: error creating archive date from $period");
1104 $out_html = "Error creating archive date from " . text($period) . "<br />" . PHP_EOL;
1106 } else {
1107 $out_html = "Archive period invalid.<br />" . PHP_EOL;
1108 return $out_html;
1112 if (is_dir($archive_dir)) {
1113 if (is_file($archive_dir . DS . $arch_fn)) {
1114 csv_edihist_log("edih_archive_main: archive file $arch_fn already exists");
1115 $out_html = "Archive: archive file " . text($arch_fn) . " already exists<br />" . PHP_EOL;
1116 return $out_html;
1118 } else {
1119 // should have been created at setup
1120 if (!mkdir($archive_dir, 0755)) {
1121 csv_edihist_log("edih_archive_main: archive directory does not exist");
1122 $out_html = "Archive: archive directory does not exist<br />" . PHP_EOL;
1123 return $out_html;
1128 foreach ($params as $k => $p) {
1130 $ft = $p['type']; // could be $k
1132 if ($ft == 'f837') {
1133 csv_edihist_log("edih_archive_main: 837 Claims files are not archived");
1134 continue;
1137 $fdir = $p['directory'];
1138 $scan = scandir($fdir);
1139 if (!$scan || count($scan) < 3) {
1140 continue;
1144 $files_csv = $p['files_csv'];
1145 $claims_csv = $p['claims_csv'];
1146 $date_col = $p['filedate'];
1147 $fncol = 'FileName';
1149 // create three csv file paths 'old_', 'arch_', and 'keep_'
1150 // files csv temporary names
1151 $fn_files_old = $tmp_dir . DS . 'old_' . basename($files_csv);
1152 $fn_files_arch = $tmp_dir . DS . 'arch_' . basename($files_csv);
1153 $fn_files_keep = $tmp_dir . DS . 'keep_' . basename($files_csv);
1154 // claims csv temporary names
1155 $fn_claims_old = $tmp_dir . DS . 'old_' . basename($claims_csv);
1156 $fn_claims_arch = $tmp_dir . DS . 'arch_' . basename($claims_csv);
1157 $fn_claims_keep = $tmp_dir . DS . 'keep_' . basename($claims_csv);
1158 // table headings
1159 $fh_ar = csv_table_header($ft, 'file');
1160 $ch_ar = csv_table_header($ft, 'claim');
1161 // copy existing csv files -- continue to next type if no files_csv
1162 $iscpc = $iscpf = false;
1163 if (is_file($files_csv)) {
1164 $iscpf = copy($files_csv, $fn_files_old);
1165 csv_edihist_log("edih_archive_main: copy $ft files csv to tmp dir");
1166 } else {
1167 csv_edihist_log("edih_archive_main: $ft files csv does not exist");
1168 continue;
1171 if (is_file($claims_csv)) {
1172 $iscpc = copy($claims_csv, $fn_claims_old);
1173 csv_edihist_log("edih_archive_main: copy $ft claims csv to tmp dir");
1174 } else {
1175 if ($ft == 'f997') {
1176 // there may be no 997 type claims records, so create a dummy file
1177 $fh = fopen($fn_claims_old, 'wb');
1178 if ($fh) {
1179 fputcsv($fh, $ch_ar);
1180 fclose($fh);
1182 } else {
1183 csv_edihist_log("edih_archive_main: $ft claims csv does not exist");
1184 continue;
1189 if (!$iscpf || !$iscpc) {
1190 csv_edihist_log("edih_archive_csv_old: copy to tmp dir failed for csv file $ft");
1191 $out_html = "Archive temporary files operation failed ... aborting <br />" . PHP_EOL;
1192 // need to call archive_undo()
1193 $out_html .= edih_archive_undo();
1194 return $out_html;
1197 // get the csv data
1198 $csv_files_ar = csv_assoc_array($ft, 'file');
1199 $csv_claims_ar = csv_assoc_array($ft, 'claim');
1200 // get filenames to be archived
1201 $fn_ar = array();
1202 $tp_ar = array();
1203 $fn_ar = edih_archive_filenames($csv_files_ar, $archive_date);
1204 if (count($fn_ar)) {
1205 // add type to list
1206 $tp_ar[] = $ft;
1207 // get the old and new csv row arrays for files_csv
1208 $arch_new = edih_archive_csv_split($csv_files_ar, $fn_ar);
1209 if ($arch_new) {
1210 if (isset($arch_new['keep'])) {
1211 // write the new
1212 $frws = edih_archive_rewrite_csv($fn_files_keep, $fh_ar, $arch_new['keep']);
1213 $out_html .= "type " . text($ft) . " keep files_csv file with " . text($frws) . " rows<br />";
1216 if (isset($arch_new['arch'])) {
1217 // write the old
1218 $frws2 = edih_archive_rewrite_csv($fn_files_arch, $fh_ar, $arch_new['arch']);
1219 $out_html .= "type " . text($ft) . " archive files_csv file with " . text($frws2) . " rows<br />";
1221 } else {
1222 $out_html .= "type $ft error creating new files_csv tables";
1225 // repeat for claims_csv
1226 $arch_new = edih_archive_csv_split($csv_claims_ar, $fn_ar);
1227 if ($arch_new) {
1228 if (isset($arch_new['keep'])) {
1229 // write the new
1230 $crws = edih_archive_rewrite_csv($fn_claims_keep, $ch_ar, $arch_new['keep']);
1231 $out_html .= "type " . text($ft) . " keep claims_csv file with " . text($crws) . " rows<br />";
1234 if (isset($arch_new['arch'])) {
1235 // write the old
1236 $crws = edih_archive_rewrite_csv($fn_claims_arch, $ch_ar, $arch_new['arch']);
1237 $out_html .= "type " . text($ft) . " archive claims_csv file with " . text($crws) . " rows<br />";
1239 } else {
1240 $out_html .= "type " . text($ft) . " error creating new claims csv tables<br />";
1243 // now the csv_records are in files
1244 // file records in $fn_files_arch $fn_files_keep
1245 // claim records in $fn_claims_arch $fn_claims_new
1247 // create a zip archive
1248 // zf is result of zipArchive functions true or false
1249 $zf = edih_archive_create_zip($p, $fn_ar, $archive_date, $arch_fn);
1251 // delete archived files
1252 if ($zf) {
1253 // replace the csv files
1254 $rn = rename($fn_files_keep, $files_csv);
1255 if ($rn) {
1256 csv_edihist_log("edih_archive_main: replaced $files_csv");
1257 } else {
1258 csv_edihist_log("edih_archive_main: error trying to replace $files_csv");
1261 $rn = rename($fn_claims_keep, $claims_csv);
1262 if ($rn) {
1263 csv_edihist_log("edih_archive_main: replaced $claims_csv");
1264 } else {
1265 csv_edihist_log("edih_archive_main: error trying to replace $claims_csv");
1268 // move archive files to tmpdir/ftype
1269 // $rndir = mkdir($tmpdir.DS.$fdir);
1270 csv_edihist_log("edih_archive_main: $ft now moving old files ");
1271 $del = edih_archive_move_old($p, $fn_ar);
1272 $out_html .= "Archive moved " . text($del . " " . $ft) . " type files<br />" . PHP_EOL;
1274 } else {
1275 csv_edihist_log("edih_archive_main: type $ft error in creating archive");
1276 $out_html .= "type " . text($ft) . " error in creating archive<br />" . PHP_EOL;
1278 } else {
1279 csv_edihist_log("edih_archive_main: search found no type $ft files older than $period");
1280 $out_html .= "Archive: type " . text($ft) . " archive found no files older than " . text($period) . "<br />" . PHP_EOL;
1282 } // end foreach($params as $k=>$p)
1284 if (is_file($tmp_dir . DS . $arch_fn)) {
1285 $rn = rename($tmp_dir . DS . $arch_fn, $archive_dir . DS . $arch_fn);
1286 $cm = chmod($archive_dir . DS . $arch_fn, 0400);
1287 if ($rn) {
1288 csv_edihist_log("edih_archive_main: moved $arch_fn to archive directory");
1289 } else {
1290 csv_edihist_log("edih_archive_main: error moving archive file $arch_fn");
1291 $out_html .= "<p>edih_archive_main: error moving archive file " . text($arch_fn) . "</p>";
1293 } else {
1294 csv_edihist_log("edih_archive_main: is_file false $tmp_dir.DS.$arch_fn");
1297 //edih_archive_cleanup($arch_fn, $tp_ar);
1298 $is_clear = csv_clear_tmpdir();
1299 if ($is_clear) {
1300 $out_html .= "Archive: temporary files removed. Process complete.<br />" . PHP_EOL;
1301 } else {
1302 $out_html .= "Archive: still some files in /history/tmp/. Process complete.<br />" . PHP_EOL;
1306 return $out_html;