1<?php 2 3 /** 4 * Does an import to a particular table from a text file 5 * 6 * $Id: dataimport.php,v 1.11 2007/01/22 16:33:01 soranzo Exp $ 7 */ 8 9 // Prevent timeouts on large exports (non-safe mode only) 10 if (!ini_get('safe_mode')) set_time_limit(0); 11 12 // Include application functions 13 include_once('./libraries/lib.inc.php'); 14 15 // Default state for XML parser 16 $state = 'XML'; 17 $curr_col_name = null; 18 $curr_col_val = null; 19 $curr_col_null = false; 20 $curr_row = array(); 21 22 /** 23 * Open tag handler for XML import feature 24 */ 25 function _startElement($parser, $name, $attrs) { 26 global $data, $misc, $lang; 27 global $state, $curr_row, $curr_col_name, $curr_col_val, $curr_col_null; 28 29 switch ($name) { 30 case 'DATA': 31 if ($state != 'XML') { 32 $data->rollbackTransaction(); 33 $misc->printMsg($lang['strimporterror']); 34 exit; 35 } 36 $state = 'DATA'; 37 break; 38 case 'HEADER': 39 if ($state != 'DATA') { 40 $data->rollbackTransaction(); 41 $misc->printMsg($lang['strimporterror']); 42 exit; 43 } 44 $state = 'HEADER'; 45 break; 46 case 'RECORDS': 47 if ($state != 'READ_HEADER') { 48 $data->rollbackTransaction(); 49 $misc->printMsg($lang['strimporterror']); 50 exit; 51 } 52 $state = 'RECORDS'; 53 break; 54 case 'ROW': 55 if ($state != 'RECORDS') { 56 $data->rollbackTransaction(); 57 $misc->printMsg($lang['strimporterror']); 58 exit; 59 } 60 $state = 'ROW'; 61 $curr_row = array(); 62 break; 63 case 'COLUMN': 64 // We handle columns in rows 65 if ($state == 'ROW') { 66 $state = 'COLUMN'; 67 $curr_col_name = $attrs['NAME']; 68 $curr_col_null = isset($attrs['NULL']); 69 } 70 // And we ignore columns in headers and fail in any other context 71 elseif ($state != 'HEADER') { 72 $data->rollbackTransaction(); 73 $misc->printMsg($lang['strimporterror']); 74 exit; 75 } 76 break; 77 default: 78 // An unrecognised tag means failure 79 $data->rollbackTransaction(); 80 $misc->printMsg($lang['strimporterror']); 81 exit; 82 } 83 } 84 85 /** 86 * Close tag handler for XML import feature 87 */ 88 function _endElement($parser, $name) { 89 global $data, $misc, $lang; 90 global $state, $curr_row, $curr_col_name, $curr_col_val, $curr_col_null; 91 92 switch ($name) { 93 case 'DATA': 94 $state = 'READ_DATA'; 95 break; 96 case 'HEADER': 97 $state = 'READ_HEADER'; 98 break; 99 case 'RECORDS': 100 $state = 'READ_RECORDS'; 101 break; 102 case 'ROW': 103 // Build value map in order to insert row into table 104 $fields = array(); 105 $vars = array(); 106 $nulls = array(); 107 $format = array(); 108 $types = array(); 109 $i = 0; 110 foreach ($curr_row as $k => $v) { 111 $fields[$i] = $k; 112 // Check for nulls 113 if ($v === null) $nulls[$i] = 'on'; 114 // Add to value array 115 $vars[$i] = $v; 116 // Format is always VALUE 117 $format[$i] = 'VALUE'; 118 // Type is always text 119 $types[$i] = 'text'; 120 $i++; 121 } 122 $status = $data->insertRow($_REQUEST['table'], $fields, $vars, $nulls, $format, $types); 123 if ($status != 0) { 124 $data->rollbackTransaction(); 125 $misc->printMsg($lang['strimporterror']); 126 exit; 127 } 128 $curr_row = array(); 129 $state = 'RECORDS'; 130 break; 131 case 'COLUMN': 132 $curr_row[$curr_col_name] = ($curr_col_null ? null : $curr_col_val); 133 $curr_col_name = null; 134 $curr_col_val = null; 135 $curr_col_null = false; 136 $state = 'ROW'; 137 break; 138 default: 139 // An unrecognised tag means failure 140 $data->rollbackTransaction(); 141 $misc->printMsg($lang['strimporterror']); 142 exit; 143 } 144 } 145 146 /** 147 * Character data handler for XML import feature 148 */ 149 function _charHandler($parser, $cdata) { 150 global $data, $misc, $lang; 151 global $state, $curr_col_val; 152 153 if ($state == 'COLUMN') { 154 $curr_col_val .= $cdata; 155 } 156 } 157 158 function loadNULLArray() { 159 $array = array(); 160 if (isset($_POST['allowednulls'])) { 161 foreach ($_POST['allowednulls'] as $null_char) 162 $array[] = $null_char; 163 } 164 return $array; 165 } 166 167 function determineNull($field, $null_array) { 168 return in_array($field, $null_array); 169 } 170 171 $misc->printHeader($lang['strimport']); 172 $misc->printTrail('table'); 173 $misc->printTabs('table','import'); 174 175 // Check that file is specified and is an uploaded file 176 if (isset($_FILES['source']) && is_uploaded_file($_FILES['source']['tmp_name']) && is_readable($_FILES['source']['tmp_name'])) { 177 178 $fd = fopen($_FILES['source']['tmp_name'], 'r'); 179 // Check that file was opened successfully 180 if ($fd !== false) { 181 $null_array = loadNULLArray(); 182 $status = $data->beginTransaction(); 183 if ($status != 0) { 184 $misc->printMsg($lang['strimporterror']); 185 exit; 186 } 187 188 // If format is set to 'auto', then determine format automatically from file name 189 if ($_REQUEST['format'] == 'auto') { 190 $extension = substr(strrchr($_FILES['source']['name'], '.'), 1); 191 switch ($extension) { 192 case 'csv': 193 $_REQUEST['format'] = 'csv'; 194 break; 195 case 'txt': 196 $_REQUEST['format'] = 'tab'; 197 break; 198 case 'xml': 199 $_REQUEST['format'] = 'xml'; 200 break; 201 default: 202 $data->rollbackTransaction(); 203 $misc->printMsg($lang['strimporterror-fileformat']); 204 exit; 205 } 206 } 207 208 // Do different import technique depending on file format 209 switch ($_REQUEST['format']) { 210 case 'csv': 211 case 'tab': 212 // XXX: Length of CSV lines limited to 100k 213 $csv_max_line = 100000; 214 // Set delimiter to tabs or commas 215 if ($_REQUEST['format'] == 'csv') $csv_delimiter = ','; 216 else $csv_delimiter = "\t"; 217 // Get first line of field names 218 $fields = fgetcsv($fd, $csv_max_line, $csv_delimiter); 219 $row = 2; //We start on the line AFTER the field names 220 while ($line = fgetcsv($fd, $csv_max_line, $csv_delimiter)) { 221 // Build value map 222 $t_fields = array(); 223 $vars = array(); 224 $nulls = array(); 225 $format = array(); 226 $types = array(); 227 $i = 0; 228 foreach ($fields as $f) { 229 // Check that there is a column 230 if (!isset($line[$i])) { 231 $misc->printMsg(sprintf($lang['strimporterrorline-badcolumnnum'], $row)); 232 exit; 233 } 234 $t_fields[$i] = $f; 235 236 // Check for nulls 237 if (determineNull($line[$i], $null_array)) { 238 $nulls[$i] = 'on'; 239 } 240 // Add to value array 241 $vars[$i] = $line[$i]; 242 // Format is always VALUE 243 $format[$i] = 'VALUE'; 244 // Type is always text 245 $types[$i] = 'text'; 246 $i++; 247 } 248 249 $status = $data->insertRow($_REQUEST['table'], $t_fields, $vars, $nulls, $format, $types); 250 if ($status != 0) { 251 $data->rollbackTransaction(); 252 $misc->printMsg(sprintf($lang['strimporterrorline'], $row)); 253 exit; 254 } 255 $row++; 256 } 257 break; 258 case 'xml': 259 $parser = xml_parser_create(); 260 xml_set_element_handler($parser, '_startElement', '_endElement'); 261 xml_set_character_data_handler($parser, '_charHandler'); 262 263 while (!feof($fd)) { 264 $line = fgets($fd, 4096); 265 xml_parse($parser, $line); 266 } 267 268 xml_parser_free($parser); 269 break; 270 default: 271 // Unknown type 272 $data->rollbackTransaction(); 273 $misc->printMsg($lang['strinvalidparam']); 274 exit; 275 } 276 277 $status = $data->endTransaction(); 278 if ($status != 0) { 279 $misc->printMsg($lang['strimporterror']); 280 exit; 281 } 282 fclose($fd); 283 284 $misc->printMsg($lang['strfileimported']); 285 } 286 else { 287 // File could not be opened 288 $misc->printMsg($lang['strimporterror']); 289 } 290 } 291 else { 292 // Upload went wrong 293 $misc->printMsg($lang['strimporterror-uploadedfile']); 294 } 295 296 $misc->printFooter(); 297 298?> 299