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