3 * This library contains functions that implement the database load processing
4 * of external database files into openEMR
6 * Copyright (C) 2011 Phyaura, LLC <info@phyaura.com>
8 * LICENSE: This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://opensource.org/licenses/gpl-license.php>;.
20 * @author Rohit Kumar <pandit.rohit@netsity.com>
21 * @author (Mac) Kevin McAloon <mcaloon@patienthealthcareanalytics.com>
22 * @author Brady Miller <brady@sparmy.com>
23 * @link http://www.open-emr.org
27 // Function to copy a package to temp
28 // $type (RXNORM, SNOMED etc.)
29 function temp_copy($filename,$type) {
31 if(!file_exists($filename)) {
35 if(!file_exists($GLOBALS['temporary_files_dir']."/".$type)) {
36 if(!mkdir($GLOBALS['temporary_files_dir']."/".$type, 0777, true)) {
41 if(copy($filename,$GLOBALS['temporary_files_dir']."/".$type."/".basename($filename))) {
49 // Function to unarchive a package
50 // $type (RXNORM, SNOMED etc.)
51 function temp_unarchive($filename,$type) {
52 $filename = $GLOBALS['temporary_files_dir']."/".$type."/".basename($filename);
53 if(!file_exists($filename)) {
58 // let's uzip the file
59 // use checksums to determine the "version"
61 $zip = new ZipArchive;
62 if ($zip->open($filename) === TRUE) {
63 if (!($zip->extractTo($GLOBALS['temporary_files_dir']."/".$type))) {
75 // Function to import the RXNORM tables
76 // $is_windows_flag - pass the IS_WINDOWS constant
77 function rxnorm_import($is_windows_flag) {
80 $dirScripts = $GLOBALS['temporary_files_dir']."/RXNORM/scripts/mysql";
81 $dir = $GLOBALS['temporary_files_dir']."/RXNORM/rrf";
82 $dir=str_replace('\\','/',$dir);
85 $rx_info['rxnatomarchive'] = array('title' => "Archive Data", 'dir' => "$dir", 'origin' => "RXNATOMARCHIVE.RRF", 'filename' => "RXNATOMARCHIVE.RRF", 'table' => "rxnatomarchive", 'required' => 0);
86 $rx_info['rxnconso'] = array('title' => "Concept Names and Sources", 'dir' => "$dir", 'origin' => "RXNCONSO.RRF", 'filename' => "RXNCONSO.RRF", 'table' => "rxnconso", 'required' => 1);
87 $rx_info['rxncui'] = array('title' => "Retired RXCUI Data", 'dir' => "$dir", 'origin' => "RXNCUI.RRF", 'filename' => "RXNCUI.RRF", 'table' => "rxncui", 'required' => 1);
88 $rx_info['rxncuichanges'] = array('title' => "Concept Changes", 'dir' => "$dir", 'origin' => "RXNCUICHANGES.RRF", 'filename' => "RXNCUICHANGES.RRF", 'table' => "rxncuichanges", 'required' => 1);
89 $rx_info['rxndoc'] = array('title' => "Documentation for Abbreviated Values", 'dir' => "$dir", 'origin' => "RXNDOC.RRF", 'filename' => "RXNDOC.RRF", 'table' => "rxndoc", 'required' => 1);
90 $rx_info['rxnrel'] = array('title' => "Relationships", 'dir' => "$dir", 'origin' => "RXNREL.RRF", 'filename' => "RXNREL.RRF", 'table' => "rxnrel", 'required' => 1);
91 $rx_info['rxnsab'] = array('title' => "Source Information", 'dir' => "$dir", 'origin' => "RXNSAB.RRF", 'filename' => "RXNSAB.RRF", 'table' => "rxnsab", 'required' => 0);
92 $rx_info['rxnsat'] = array('title' => "Simple Concept and Atom Attributes", 'dir' => "$dir", 'origin' => "RXNSAT.RRF", 'filename' => "RXNSAT.RRF", 'table' => "rxnsat", 'required' => 0);
93 $rx_info['rxnsty'] = array('title' => "Semantic Types ", 'dir' => "$dir", 'origin' => "RXNSTY.RRF", 'filename' => "RXNSTY.RRF", 'table' => "rxnsty", 'required' => 1);
96 $file_load = file_get_contents($dirScripts.'/Table_scripts_mysql_rxn.sql', true);
97 if ($is_windows_flag) {
98 $data_load = file_get_contents($dirScripts.'/Load_scripts_mysql_rxn_win.sql', true);
101 $data_load = file_get_contents($dirScripts.'/Load_scripts_mysql_rxn_unix.sql', true);
103 $indexes_load = file_get_contents($dirScripts.'/Indexes_mysql_rxn.sql', true);
106 // Creating the structure for table and applying indexes
109 $file_array=explode(";",$file_load);
110 foreach($file_array as $val){
113 sqlStatementNoLog($val);
117 $indexes_array=explode(";",$indexes_load);
119 foreach($indexes_array as $val1){
122 sqlStatementNoLog($val1);
127 // Settings to drastically speed up import with InnoDB
128 sqlStatementNoLog("SET autocommit=0");
129 sqlStatementNoLog("START TRANSACTION");
130 $data=explode(";",$data_load);
131 foreach($data as $val)
133 foreach($rx_info as $key => $value)
135 $file_name= $value['origin'];
136 $replacement=$dir."/".$file_name;
138 $pattern='/'.$file_name.'/';
139 if(strpos($val,$file_name) !== false) {
140 $val1 = str_replace($file_name,$replacement,$val);
141 if(trim($val1)!='') {
142 sqlStatementNoLog($val1);
147 // Settings to drastically speed up import with InnoDB
148 sqlStatementNoLog("COMMIT");
149 sqlStatementNoLog("SET autocommit=1");
154 // Function to import SNOMED tables
155 function snomed_import($us_extension=FALSE) {
158 $table_array_for_snomed=array(
159 "sct_concepts_drop"=>"DROP TABLE IF EXISTS `sct_concepts`",
160 "sct_concepts_structure"=>"CREATE TABLE IF NOT EXISTS `sct_concepts` (
161 `ConceptId` bigint(20) NOT NULL,
162 `ConceptStatus` int(11) NOT NULL,
163 `FullySpecifiedName` varchar(255) NOT NULL,
164 `CTV3ID` varchar(5) NOT NULL,
165 `SNOMEDID` varchar(8) NOT NULL,
166 `IsPrimitive` tinyint(1) NOT NULL,
167 PRIMARY KEY (`ConceptId`)
169 "sct_descriptions_drop"=>"DROP TABLE IF EXISTS `sct_descriptions`",
170 "sct_descriptions_structure"=>"CREATE TABLE IF NOT EXISTS `sct_descriptions` (
171 `DescriptionId` bigint(20) NOT NULL,
172 `DescriptionStatus` int(11) NOT NULL,
173 `ConceptId` bigint(20) NOT NULL,
174 `Term` varchar(255) NOT NULL,
175 `InitialCapitalStatus` tinyint(1) NOT NULL,
176 `DescriptionType` int(11) NOT NULL,
177 `LanguageCode` varchar(8) NOT NULL,
178 PRIMARY KEY (`DescriptionId`)
180 "sct_relationships_drop"=>"DROP TABLE IF EXISTS `sct_relationships`",
181 "sct_relationships_structure"=>"CREATE TABLE IF NOT EXISTS `sct_relationships` (
182 `RelationshipId` bigint(20) NOT NULL,
183 `ConceptId1` bigint(20) NOT NULL,
184 `RelationshipType` bigint(20) NOT NULL,
185 `ConceptId2` bigint(20) NOT NULL,
186 `CharacteristicType` int(11) NOT NULL,
187 `Refinability` int(11) NOT NULL,
188 `RelationshipGroup` int(11) NOT NULL,
189 PRIMARY KEY (`RelationshipId`)
194 $dir_snomed = $GLOBALS['temporary_files_dir']."/SNOMED/";
195 $sub_path="Terminology/Content/";
197 $dir=str_replace('\\','/',$dir);
199 // executing the create statement for tables, these are defined in snomed_capture.inc file
200 // this is skipped if the US extension is being added
201 if (!$us_extension) {
202 foreach($table_array_for_snomed as $val){
209 // reading the SNOMED directory and identifying the files to import and replacing the variables by originals values.
210 if( is_dir($dir) && $handle = opendir($dir)) {
211 while (false !== ($filename = readdir($handle))) {
212 if ($filename != "." && $filename != ".." && !strpos($filename,"zip")) {
213 $path=$dir."".$filename."/".$sub_path;
214 if (!(is_dir($path))) {
215 $path=$dir."".$filename."/RF1Release/".$sub_path;
217 if( is_dir($path) && $handle1 = opendir($path)) {
218 while (false !== ($filename1 = readdir($handle1))) {
219 $load_script="Load data local infile '#FILENAME#' into table #TABLE# fields terminated by '\\t' ESCAPED BY '' lines terminated by '\\n' ignore 1 lines ";
220 $array_replace=array("#FILENAME#","#TABLE#");
221 if ($filename1 != "." && $filename1 != "..") {
222 $file_replace=$path.$filename1;
223 if(strpos($filename1,"Concepts") !== false){
224 $new_str=str_replace($array_replace,array($file_replace,"sct_concepts"),$load_script);
226 if(strpos($filename1,"Descriptions") !== false){
227 $new_str=str_replace($array_replace,array($file_replace,"sct_descriptions"),$load_script);
229 if(strpos($filename1,"Relationships") !== false){
230 $new_str=str_replace($array_replace,array($file_replace,"sct_relationships"),$load_script);
233 sqlStatement($new_str);
246 // Function to import ICD tables $type differentiates ICD 9, 10 and eventually 11 (circa 2018 :-) etc.
248 function icd_import($type) {
251 $dir_icd = $GLOBALS['temporary_files_dir']."/".$type."/";
252 $dir=str_replace('\\','/',$dir_icd);
256 // the incoming array is a metadata array containing keys that substr match to the incoming filename
257 // followed by the field name, position and length of each fixed length text record in the incoming
258 // flat files. There are separate definitions for ICD 9 and 10 based on the type passed in
260 if ($type == 'ICD9') {
261 $incoming['SHORT_DX'] = array('#TABLENAME#' => "icd9_dx_code",
262 '#FLD1#' => "dx_code", '#POS1#' => 1, '#LEN1#' => 5,
263 '#FLD2#' => "short_desc", '#POS2#' => 7, '#LEN2#' => 60);
264 $incoming['SHORT_SG'] = array('#TABLENAME#' => "icd9_sg_code",
265 '#FLD1#' => "sg_code", '#POS1#' => 1, '#LEN1#' => 4,
266 '#FLD2#' => "short_desc", '#POS2#' => 6, '#LEN2#' => 60);
267 $incoming['LONG_SG'] = array('#TABLENAME#' => "icd9_sg_long_code",
268 '#FLD1#' => "sg_code", '#POS1#' => 1, '#LEN1#' => 4,
269 '#FLD2#' => "long_desc", '#POS2#' => 6, '#LEN2#' => 300);
270 $incoming['LONG_DX'] = array('#TABLENAME#' => "icd9_dx_long_code",
271 '#FLD1#' => "dx_code", '#POS1#' => 1, '#LEN1#' => 5,
272 '#FLD2#' => "long_desc", '#POS2#' => 7, '#LEN2#' => 300);
275 $incoming['icd10pcs_order_'] = array('#TABLENAME#' => "icd10_pcs_order_code",
276 '#FLD1#' => "pcs_code", '#POS1#' => 7, '#LEN1#' => 7,
277 '#FLD2#' => "valid_for_coding", '#POS2#' => 15, '#LEN2#' => 1,
278 '#FLD3#' => "short_desc", '#POS3#' => 17, '#LEN3#' => 60,
279 '#FLD4#' => "long_desc", '#POS4#' => 78, '#LEN4#' => 300);
280 $incoming['icd10cm_order_'] = array('#TABLENAME#' => "icd10_dx_order_code",
281 '#FLD1#' => "dx_code", '#POS1#' =>7, '#LEN1#' => 7,
282 '#FLD2#' => "valid_for_coding", '#POS2#' => 15, '#LEN2#' => 1,
283 '#FLD3#' => "short_desc", '#POS3#' => 17, '#LEN3#' => 60,
284 '#FLD4#' => "long_desc", '#POS4#' => 78, '#LEN4#' => 300);
285 $incoming['reimb_map_pr_'] = array('#TABLENAME#' => "icd10_reimbr_pcs_9_10",
286 '#FLD1#' => "code", '#POS1#' => 1, '#LEN1#' => 7,
287 '#FLD2#' => "code_cnt", '#POS2#' => 9, '#LEN2#' => 1,
288 '#FLD3#' => "ICD9_01", '#POS3#' => 11, '#LEN3#' => 5,
289 '#FLD4#' => "ICD9_02", '#POS4#' => 17, '#LEN4#' => 5,
290 '#FLD5#' => "ICD9_03", '#POS5#' => 23, '#LEN5#' => 5,
291 '#FLD6#' => "ICD9_04", '#POS6#' => 29, '#LEN6#' => 5,
292 '#FLD7#' => "ICD9_05", '#POS7#' => 35, '#LEN7#' => 5,
293 '#FLD8#' => "ICD9_06", '#POS8#' => 41, '#LEN8#' => 5);
294 $incoming['reimb_map_dx_'] = array('#TABLENAME#' => "icd10_reimbr_dx_9_10",
295 '#FLD1#' => "code", '#POS1#' => 1, '#LEN1#' => 7,
296 '#FLD2#' => "code_cnt", '#POS2#' => 9, '#LEN2#' => 1,
297 '#FLD3#' => "ICD9_01", '#POS3#' => 11, '#LEN3#' => 5,
298 '#FLD4#' => "ICD9_02", '#POS4#' => 17, '#LEN4#' => 5,
299 '#FLD5#' => "ICD9_03", '#POS5#' => 23, '#LEN5#' => 5,
300 '#FLD6#' => "ICD9_04", '#POS6#' => 29, '#LEN6#' => 5,
301 '#FLD7#' => "ICD9_05", '#POS7#' => 35, '#LEN7#' => 5,
302 '#FLD8#' => "ICD9_06", '#POS8#' => 41, '#LEN8#' => 5);
303 $incoming['I10gem'] = array('#TABLENAME#' => "icd10_gem_dx_10_9",
304 '#FLD1#' => "dx_icd10_source", '#POS1#' => 1, '#LEN1#' => 7,
305 '#FLD2#' => "dx_icd9_target", '#POS2#' => 9, '#LEN2#' => 5,
306 '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5);
307 $incoming['I9gem'] = array('#TABLENAME#' => "icd10_gem_dx_9_10",
308 '#FLD1#' => "dx_icd9_source", '#POS1#' => 1, '#LEN1#' => 5,
309 '#FLD2#' => "dx_icd10_target", '#POS2#' => 7, '#LEN2#' => 7,
310 '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5);
311 $incoming['gem_pcsi9'] = array('#TABLENAME#' => "icd10_gem_pcs_10_9",
312 '#FLD1#' => "pcs_icd10_source", '#POS1#' => 1, '#LEN1#' => 7,
313 '#FLD2#' => "pcs_icd9_target", '#POS2#' => 9, '#LEN2#' => 5,
314 '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5);
315 $incoming['gem_i9pcs'] = array('#TABLENAME#' => "icd10_gem_pcs_9_10",
316 '#FLD1#' => "pcs_icd9_source", '#POS1#' => 1, '#LEN1#' => 5,
317 '#FLD2#' => "pcs_icd10_target", '#POS2#' => 7, '#LEN2#' => 7,
318 '#FLD3#' => "flags", '#POS3#' => 15, '#LEN3#' => 5);
321 // set up the start of the load script to be appended from the incoming array defined above where incoming
323 $db_load = "LOAD DATA LOCAL INFILE '#INFILE#' INTO TABLE #TABLENAME# FIELDS TERMINATED BY '\0' (@var) SET revision = 0, ";
324 $col_template = "#FLD# = trim(Substring(@var, #POS#, #LEN#))";
326 // load all data and set active revision
327 if( is_dir($dir) && $handle = opendir($dir)) {
328 while (false !== ($filename = readdir($handle))) {
329 // bypass unwanted entries
330 if (!stripos($filename, ".txt") || stripos($filename,"diff") || stripos($filename, "addenda")) {
334 // reset the sql load command and susbtitute the filename
336 $run_sql = str_replace("#INFILE#", $dir . $filename, $run_sql);
337 $keys = array_keys($incoming);
338 while ($this_key = array_pop($keys)) {
339 if (stripos($filename, $this_key) !== false) {
341 // now substitute the tablename
342 $run_sql = str_replace("#TABLENAME#", $incoming[$this_key]['#TABLENAME#'], $run_sql);
344 // the range defines the maximum number of fields contained
345 // in any of the incoming files
346 foreach(range(1, 8) as $field) {
347 $fld = "#FLD" . $field . "#";
348 $nxtfld = "#FLD" . ($field+1) . "#";
349 $pos = "#POS" . $field . "#";
350 $len = "#LEN" . $field . "#";
352 // concat this fields template in the sql string
353 $run_sql .= $col_template;
354 $run_sql = str_replace("#FLD#", $incoming[$this_key][$fld], $run_sql);
355 $run_sql = str_replace("#POS#", $incoming[$this_key][$pos], $run_sql);
356 $run_sql = str_replace("#LEN#", $incoming[$this_key][$len], $run_sql);
357 // at the end of this table's field list
358 if (!array_key_exists($nxtfld, $incoming[$this_key])) {
363 sqlStatement($run_sql);
365 // now update the revision for this load
366 $res = sqlStatement("SELECT max(revision) rev FROM " . $incoming[$this_key]['#TABLENAME#']);
367 $row = sqlFetchArray($res);
368 $next_rev = $row['rev'] + 1;
369 $run_sql = "UPDATE " . $incoming[$this_key]['#TABLENAME#'] . " SET active = 0";
371 $run_sql = "UPDATE " . $incoming[$this_key]['#TABLENAME#'] . " SET active = 1, revision = ? WHERE revision = 0";
372 sqlQuery($run_sql, array($next_rev) );
380 echo htmlspecialchars( xl('ERROR: No ICD import directory.'), ENT_NOQUOTES)."<br>";
384 // now update the tables where necessary
385 if ($type == 'ICD9') {
386 sqlStatement("update `icd9_dx_code` SET formatted_dx_code = dx_code");
387 sqlStatement("update `icd9_dx_code` SET formatted_dx_code = concat(concat(left(dx_code, 3), '.'), substr(dx_code, 4)) WHERE dx_code RLIKE '^[V0-9]{1}.*' AND LENGTH(dx_code) > 3");
388 sqlStatement("update `icd9_dx_code` SET formatted_dx_code = concat(concat(left(dx_code, 4), '.'), substr(dx_code, 5)) WHERE dx_code RLIKE '^[E]{1}.*' AND LENGTH(dx_code) > 4");
389 sqlStatement("update `icd9_sg_code` SET formatted_sg_code = concat(concat(left(sg_code, 2), '.'), substr(sg_code, 3))");
390 sqlStatement("update `icd9_dx_code` A, `icd9_dx_long_code` B set A.long_desc = B.long_desc where A.dx_code = B.dx_code and A.active = 1 and A.long_desc is NULL");
391 sqlStatement("update `icd9_sg_code` A, `icd9_sg_long_code` B set A.long_desc = B.long_desc where A.sg_code = B.sg_code and A.active = 1 and A.long_desc is NULL");
394 sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = dx_code");
395 sqlStatement("update `icd10_dx_order_code` SET formatted_dx_code = concat(concat(left(dx_code, 3), '.'), substr(dx_code, 4)) WHERE LENGTH(dx_code) > 3");
401 function valueset_import($type){
402 $dir_valueset = $GLOBALS['temporary_files_dir']."/".$type."/";
403 $dir = str_replace('\\','/',$dir_valueset);
405 // Settings to drastically speed up import with InnoDB
406 sqlStatementNoLog("SET autocommit=0");
407 sqlStatementNoLog("START TRANSACTION");
408 if( is_dir($dir) && $handle = opendir($dir)) {
409 while (false !== ($filename = readdir($handle))) {
410 if(stripos($filename, ".xml")){
411 $abs_path = $dir.$filename;
412 $xml = simplexml_load_file($abs_path,null,null,'ns0',true);
413 foreach($xml->DescribedValueSet as $vset){
414 $vset_attr = $vset->attributes();
415 $nqf = $vset->xpath('ns0:Group[@displayName="NQF Number"]/ns0:Keyword');
416 foreach($vset->ConceptList as $cp){
417 foreach($nqf as $nqf_code){
418 foreach($cp->Concept as $con){
419 $con_attr = $con->attributes();
420 sqlStatementNoLog("INSERT INTO valueset values(?,?,?,?,?,?,?) on DUPLICATE KEY UPDATE code_system = values(code_system),description = values(description),valueset_name = values(valueset_name)",array($nqf_code,$con_attr->code,$con_attr->codeSystem,$con_attr->codeSystemName,$vset_attr->ID,$con_attr->displayName,$vset_attr->displayName));
426 sqlStatementNoLog("UPDATE valueset set code_type='SNOMED CT' where code_type='SNOMEDCT'");
427 sqlStatementNoLog("UPDATE valueset set code_type='ICD9' where code_type='ICD9CM'");
428 sqlStatementNoLog("UPDATE valueset set code_type='ICD10' where code_type='ICD10CM'");
433 // Settings to drastically speed up import with InnoDB
434 sqlStatementNoLog("COMMIT");
435 sqlStatementNoLog("SET autocommit=1");
439 // Function to clean up temp files
440 // $type (RXNORM etc.)
441 function temp_dir_cleanup($type) {
442 if(is_dir($GLOBALS['temporary_files_dir']."/".$type)) {
443 rmdir_recursive($GLOBALS['temporary_files_dir']."/".$type);
447 // Function to update version tracker table if successful
448 // $type (RXNORM etc.)
449 function update_tracker_table($type,$revision,$version,$file_checksum) {
450 if ($type == 'RXNORM') {
451 sqlStatement("INSERT INTO `standardized_tables_track` (`imported_date`,`name`,`revision_date`, `revision_version`, `file_checksum`) VALUES (NOW(),'RXNORM',?,?,?)", array($revision, $version, $file_checksum) );
454 else if ($type == 'SNOMED') {
455 sqlStatement("INSERT INTO `standardized_tables_track` (`imported_date`,`name`,`revision_date`, `revision_version`, `file_checksum`) VALUES (NOW(),'SNOMED',?,?,?)", array($revision, $version, $file_checksum) );
458 else if ($type == 'ICD9') {
459 sqlStatement("INSERT INTO `standardized_tables_track` (`imported_date`,`name`,`revision_date`, `revision_version`, `file_checksum`) VALUES (NOW(),'ICD9',?,?,?)", array($revision, $version, $file_checksum) );
462 else if($type == 'CQM_VALUESET'){
463 sqlStatement("INSERT INTO `standardized_tables_track` (`imported_date`,`name`,`revision_date`, `revision_version`, `file_checksum`) VALUES (NOW(),'CQM_VALUESET',?,?,?)", array($revision, $version, $file_checksum) );
466 else { // $type == 'ICD10')
467 sqlStatement("INSERT INTO `standardized_tables_track` (`imported_date`,`name`,`revision_date`, `revision_version`, `file_checksum`) VALUES (NOW(),'ICD10',?,?,?)", array($revision, $version, $file_checksum) );
473 // Function to delete an entire directory
474 function rmdir_recursive($dir) {
475 $files = scandir($dir);
476 array_shift($files); // remove '.' from array
477 array_shift($files); // remove '..' from array
479 foreach ($files as $file) {
480 $file = $dir . '/' . $file;
482 rmdir_recursive($file);
490 // function to cleanup temp, copy and unarchive the zip file
491 function handle_zip_file($mode, $file) {
492 // 1. copy the file to temp directory
493 if (!temp_copy($file,$mode)) {
494 echo htmlspecialchars( xl('ERROR: Unable to copy the file.'), ENT_NOQUOTES)."<br>";
495 temp_dir_cleanup($mode);
499 // 2. unarchive the file
500 if (!temp_unarchive($file,$mode)) {
501 echo htmlspecialchars( xl('ERROR: Unable to extract the file.'), ENT_NOQUOTES)."<br>";
502 temp_dir_cleanup($mode);