PageRenderTime 52ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/phpMyAdmin-2.11.10-english/libraries/import/csv.php

https://github.com/2bj/Skolkovo--i-gorod.com-
PHP | 323 lines | 257 code | 23 blank | 43 comment | 122 complexity | 23cf83f5744080aa8a31d6c54cd195bb MD5 | raw file
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * CSV import plugin for phpMyAdmin
  5. *
  6. * @todo add an option for handling NULL values
  7. * @version $Id: csv.php 11335 2008-06-21 14:01:54Z lem9 $
  8. */
  9. if (! defined('PHPMYADMIN')) {
  10. exit;
  11. }
  12. /**
  13. *
  14. */
  15. if ($plugin_param !== 'table') {
  16. return;
  17. }
  18. if (isset($plugin_list)) {
  19. $plugin_list['csv'] = array(
  20. 'text' => 'strCSV',
  21. 'extension' => 'csv',
  22. 'options' => array(
  23. array('type' => 'bool', 'name' => 'replace', 'text' => 'strReplaceTable'),
  24. array('type' => 'bool', 'name' => 'ignore', 'text' => 'strIgnoreDuplicates'),
  25. array('type' => 'text', 'name' => 'terminated', 'text' => 'strFieldsTerminatedBy', 'size' => 2, 'len' => 2),
  26. array('type' => 'text', 'name' => 'enclosed', 'text' => 'strFieldsEnclosedBy', 'size' => 2, 'len' => 2),
  27. array('type' => 'text', 'name' => 'escaped', 'text' => 'strFieldsEscapedBy', 'size' => 2, 'len' => 2),
  28. array('type' => 'text', 'name' => 'new_line', 'text' => 'strLinesTerminatedBy', 'size' => 2),
  29. array('type' => 'text', 'name' => 'columns', 'text' => 'strColumnNames'),
  30. ),
  31. 'options_text' => 'strOptions',
  32. );
  33. /* We do not define function when plugin is just queried for information above */
  34. return;
  35. }
  36. $replacements = array(
  37. '\\n' => "\n",
  38. '\\t' => "\t",
  39. '\\r' => "\r",
  40. );
  41. $csv_terminated = strtr($csv_terminated, $replacements);
  42. $csv_enclosed = strtr($csv_enclosed, $replacements);
  43. $csv_escaped = strtr($csv_escaped, $replacements);
  44. $csv_new_line = strtr($csv_new_line, $replacements);
  45. if (strlen($csv_terminated) != 1) {
  46. $message = sprintf($strInvalidCSVParameter, $strFieldsTerminatedBy);
  47. $show_error_header = TRUE;
  48. $error = TRUE;
  49. // The default dialog of MS Excel when generating a CSV produces a
  50. // semi-colon-separated file with no chance of specifying the
  51. // enclosing character. Thus, users who want to import this file
  52. // tend to remove the enclosing character on the Import dialog.
  53. // I could not find a test case where having no enclosing characters
  54. // confuses this script.
  55. // But the parser won't work correctly with strings so we allow just
  56. // one character.
  57. } elseif (strlen($csv_enclosed) > 1) {
  58. $message = sprintf($strInvalidCSVParameter, $strFieldsEnclosedBy);
  59. $show_error_header = TRUE;
  60. $error = TRUE;
  61. } elseif (strlen($csv_escaped) != 1) {
  62. $message = sprintf($strInvalidCSVParameter, $strFieldsEscapedBy);
  63. $show_error_header = TRUE;
  64. $error = TRUE;
  65. } elseif (strlen($csv_new_line) != 1 && $csv_new_line != 'auto') {
  66. $message = sprintf($strInvalidCSVParameter, $strLinesTerminatedBy);
  67. $show_error_header = TRUE;
  68. $error = TRUE;
  69. }
  70. $buffer = '';
  71. if (isset($csv_replace)) {
  72. $sql_template = 'REPLACE';
  73. } else {
  74. $sql_template = 'INSERT';
  75. if (isset($csv_ignore)) {
  76. $sql_template .= ' IGNORE';
  77. }
  78. }
  79. $sql_template .= ' INTO ' . PMA_backquote($table);
  80. $tmp_fields = PMA_DBI_get_fields($db, $table);
  81. if (empty($csv_columns)) {
  82. $fields = $tmp_fields;
  83. } else {
  84. $sql_template .= ' (';
  85. $fields = array();
  86. $tmp = split(',( ?)', $csv_columns);
  87. foreach ($tmp as $key => $val) {
  88. if (count($fields) > 0) {
  89. $sql_template .= ', ';
  90. }
  91. $val = trim($val);
  92. $found = FALSE;
  93. foreach ($tmp_fields as $id => $field) {
  94. if ($field['Field'] == $val) {
  95. $found = TRUE;
  96. break;
  97. }
  98. }
  99. if (!$found) {
  100. $message = sprintf($strInvalidColumn, $val);
  101. $show_error_header = TRUE;
  102. $error = TRUE;
  103. break;
  104. }
  105. $fields[] = $field;
  106. $sql_template .= PMA_backquote($val);
  107. }
  108. $sql_template .= ') ';
  109. }
  110. $required_fields = count($fields);
  111. $sql_template .= ' VALUES (';
  112. // Defaults for parser
  113. $i = 0;
  114. $len = 0;
  115. $line = 1;
  116. $lasti = -1;
  117. $values = array();
  118. $csv_finish = FALSE;
  119. while (!($finished && $i >= $len) && !$error && !$timeout_passed) {
  120. $data = PMA_importGetNextChunk();
  121. if ($data === FALSE) {
  122. // subtract data we didn't handle yet and stop processing
  123. $offset -= strlen($buffer);
  124. break;
  125. } elseif ($data === TRUE) {
  126. // Handle rest of buffer
  127. } else {
  128. // Append new data to buffer
  129. $buffer .= $data;
  130. unset($data);
  131. // Do not parse string when we're not at the end and don't have new line inside
  132. if (($csv_new_line == 'auto' && strpos($buffer, "\r") === FALSE && strpos($buffer, "\n") === FALSE)
  133. || ($csv_new_line != 'auto' && strpos($buffer, $csv_new_line) === FALSE)) {
  134. continue;
  135. }
  136. }
  137. // Current length of our buffer
  138. $len = strlen($buffer);
  139. // Currently parsed char
  140. $ch = $buffer[$i];
  141. while ($i < $len) {
  142. // Deadlock protection
  143. if ($lasti == $i && $lastlen == $len) {
  144. $message = sprintf($strInvalidCSVFormat, $line);
  145. $show_error_header = TRUE;
  146. $error = TRUE;
  147. break;
  148. }
  149. $lasti = $i;
  150. $lastlen = $len;
  151. // This can happen with auto EOL and \r at the end of buffer
  152. if (!$csv_finish) {
  153. // Grab empty field
  154. if ($ch == $csv_terminated) {
  155. if ($i == $len - 1) {
  156. break;
  157. }
  158. $values[] = '';
  159. $i++;
  160. $ch = $buffer[$i];
  161. continue;
  162. }
  163. // Grab one field
  164. $fallbacki = $i;
  165. if ($ch == $csv_enclosed) {
  166. if ($i == $len - 1) {
  167. break;
  168. }
  169. $need_end = TRUE;
  170. $i++;
  171. $ch = $buffer[$i];
  172. } else {
  173. $need_end = FALSE;
  174. }
  175. $fail = FALSE;
  176. $value = '';
  177. while (($need_end && $ch != $csv_enclosed)
  178. || (!$need_end && !($ch == $csv_terminated
  179. || $ch == $csv_new_line || ($csv_new_line == 'auto'
  180. && ($ch == "\r" || $ch == "\n"))))) {
  181. if ($ch == $csv_escaped) {
  182. if ($i == $len - 1) {
  183. $fail = TRUE;
  184. break;
  185. }
  186. $i++;
  187. $ch = $buffer[$i];
  188. }
  189. $value .= $ch;
  190. if ($i == $len - 1) {
  191. if (!$finished) {
  192. $fail = TRUE;
  193. }
  194. break;
  195. }
  196. $i++;
  197. $ch = $buffer[$i];
  198. }
  199. // unquoted NULL string
  200. if (false === $need_end && $value === 'NULL') {
  201. $value = null;
  202. }
  203. if ($fail) {
  204. $i = $fallbacki;
  205. $ch = $buffer[$i];
  206. break;
  207. }
  208. // Need to strip trailing enclosing char?
  209. if ($need_end && $ch == $csv_enclosed) {
  210. if ($finished && $i == $len - 1) {
  211. $ch = NULL;
  212. } elseif ($i == $len - 1) {
  213. $i = $fallbacki;
  214. $ch = $buffer[$i];
  215. break;
  216. } else {
  217. $i++;
  218. $ch = $buffer[$i];
  219. }
  220. }
  221. // Are we at the end?
  222. if ($ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) || ($finished && $i == $len - 1)) {
  223. $csv_finish = TRUE;
  224. }
  225. // Go to next char
  226. if ($ch == $csv_terminated) {
  227. if ($i == $len - 1) {
  228. $i = $fallbacki;
  229. $ch = $buffer[$i];
  230. break;
  231. }
  232. $i++;
  233. $ch = $buffer[$i];
  234. }
  235. // If everything went okay, store value
  236. $values[] = $value;
  237. }
  238. // End of line
  239. if ($csv_finish || $ch == $csv_new_line || ($csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))) {
  240. if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n"
  241. if ($i >= ($len - 2) && !$finished) {
  242. break; // We need more data to decide new line
  243. }
  244. if ($buffer[$i + 1] == "\n") {
  245. $i++;
  246. }
  247. }
  248. // We didn't parse value till the end of line, so there was empty one
  249. if (!$csv_finish) {
  250. $values[] = '';
  251. }
  252. // Do we have correct count of values?
  253. if (count($values) != $required_fields) {
  254. // Hack for excel
  255. if ($values[count($values) - 1] == ';') {
  256. unset($values[count($values) - 1]);
  257. } else {
  258. $message = sprintf($strInvalidCSVFieldCount, $line);
  259. $show_error_header = TRUE;
  260. $error = TRUE;
  261. break;
  262. }
  263. }
  264. $first = TRUE;
  265. $sql = $sql_template;
  266. foreach ($values as $key => $val) {
  267. if (!$first) {
  268. $sql .= ', ';
  269. }
  270. if ($val === null) {
  271. $sql .= 'NULL';
  272. } else {
  273. $sql .= '\'' . addslashes($val) . '\'';
  274. }
  275. $first = FALSE;
  276. }
  277. $sql .= ')';
  278. /**
  279. * @todo maybe we could add original line to verbose SQL in comment
  280. */
  281. PMA_importRunQuery($sql, $sql);
  282. $line++;
  283. $csv_finish = FALSE;
  284. $values = array();
  285. $buffer = substr($buffer, $i + 1);
  286. $len = strlen($buffer);
  287. $i = 0;
  288. $lasti = -1;
  289. $ch = $buffer[0];
  290. }
  291. } // End of parser loop
  292. } // End of import loop
  293. // Commit any possible data in buffers
  294. PMA_importRunQuery();
  295. if (count($values) != 0 && !$error) {
  296. $message = sprintf($strInvalidCSVFormat, $line);
  297. $show_error_header = TRUE;
  298. $error = TRUE;
  299. }
  300. ?>