PageRenderTime 53ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/ReferenceCode/phpmyadmin/libraries/plugins/import/ImportOds.class.php

https://gitlab.com/ctheilman92/Aging-In-Place
PHP | 415 lines | 260 code | 50 blank | 105 comment | 51 complexity | 193d2ffb7766ef8a1ac46200adaddf11 MD5 | raw file
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * OpenDocument Spreadsheet import plugin for phpMyAdmin
  5. *
  6. * @todo Pretty much everything
  7. * @todo Importing of accented characters seems to fail
  8. * @package PhpMyAdmin-Import
  9. * @subpackage ODS
  10. */
  11. if (! defined('PHPMYADMIN')) {
  12. exit;
  13. }
  14. /**
  15. * We need way to disable external XML entities processing.
  16. */
  17. if (!function_exists('libxml_disable_entity_loader')) {
  18. return;
  19. }
  20. /* Get the import interface */
  21. require_once 'libraries/plugins/ImportPlugin.class.php';
  22. /**
  23. * Handles the import for the ODS format
  24. *
  25. * @package PhpMyAdmin-Import
  26. * @subpackage ODS
  27. */
  28. class ImportOds extends ImportPlugin
  29. {
  30. /**
  31. * Constructor
  32. */
  33. public function __construct()
  34. {
  35. $this->setProperties();
  36. }
  37. /**
  38. * Sets the import plugin properties.
  39. * Called in the constructor.
  40. *
  41. * @return void
  42. */
  43. protected function setProperties()
  44. {
  45. $props = 'libraries/properties/';
  46. include_once "$props/plugins/ImportPluginProperties.class.php";
  47. include_once "$props/options/groups/OptionsPropertyRootGroup.class.php";
  48. include_once "$props/options/groups/OptionsPropertyMainGroup.class.php";
  49. include_once "$props/options/items/BoolPropertyItem.class.php";
  50. $importPluginProperties = new ImportPluginProperties();
  51. $importPluginProperties->setText('OpenDocument Spreadsheet');
  52. $importPluginProperties->setExtension('ods');
  53. $importPluginProperties->setOptionsText(__('Options'));
  54. // create the root group that will be the options field for
  55. // $importPluginProperties
  56. // this will be shown as "Format specific options"
  57. $importSpecificOptions = new OptionsPropertyRootGroup();
  58. $importSpecificOptions->setName("Format Specific Options");
  59. // general options main group
  60. $generalOptions = new OptionsPropertyMainGroup();
  61. $generalOptions->setName("general_opts");
  62. // create primary items and add them to the group
  63. $leaf = new BoolPropertyItem();
  64. $leaf->setName("col_names");
  65. $leaf->setText(
  66. __(
  67. 'The first line of the file contains the table column names'
  68. . ' <i>(if this is unchecked, the first line will become part'
  69. . ' of the data)</i>'
  70. )
  71. );
  72. $generalOptions->addProperty($leaf);
  73. $leaf = new BoolPropertyItem();
  74. $leaf->setName("empty_rows");
  75. $leaf->setText(__('Do not import empty rows'));
  76. $generalOptions->addProperty($leaf);
  77. $leaf = new BoolPropertyItem();
  78. $leaf->setName("recognize_percentages");
  79. $leaf->setText(
  80. __(
  81. 'Import percentages as proper decimals <i>(ex. 12.00% to .12)</i>'
  82. )
  83. );
  84. $generalOptions->addProperty($leaf);
  85. $leaf = new BoolPropertyItem();
  86. $leaf->setName("recognize_currency");
  87. $leaf->setText(__('Import currencies <i>(ex. $5.00 to 5.00)</i>'));
  88. $generalOptions->addProperty($leaf);
  89. // add the main group to the root group
  90. $importSpecificOptions->addProperty($generalOptions);
  91. // set the options for the import plugin property item
  92. $importPluginProperties->setOptions($importSpecificOptions);
  93. $this->properties = $importPluginProperties;
  94. }
  95. /**
  96. * This method is called when any PluginManager to which the observer
  97. * is attached calls PluginManager::notify()
  98. *
  99. * @param SplSubject $subject The PluginManager notifying the observer
  100. * of an update.
  101. *
  102. * @return void
  103. */
  104. public function update (SplSubject $subject)
  105. {
  106. }
  107. /**
  108. * Handles the whole import logic
  109. *
  110. * @return void
  111. */
  112. public function doImport()
  113. {
  114. global $db, $error, $timeout_passed, $finished;
  115. $i = 0;
  116. $len = 0;
  117. $buffer = "";
  118. /**
  119. * Read in the file via PMA_importGetNextChunk so that
  120. * it can process compressed files
  121. */
  122. while (! ($finished && $i >= $len) && ! $error && ! $timeout_passed) {
  123. $data = PMA_importGetNextChunk();
  124. if ($data === false) {
  125. /* subtract data we didn't handle yet and stop processing */
  126. $offset -= strlen($buffer);
  127. break;
  128. } elseif ($data === true) {
  129. /* Handle rest of buffer */
  130. } else {
  131. /* Append new data to buffer */
  132. $buffer .= $data;
  133. unset($data);
  134. }
  135. }
  136. unset($data);
  137. /**
  138. * Disable loading of external XML entities.
  139. */
  140. libxml_disable_entity_loader();
  141. /**
  142. * Load the XML string
  143. *
  144. * The option LIBXML_COMPACT is specified because it can
  145. * result in increased performance without the need to
  146. * alter the code in any way. It's basically a freebee.
  147. */
  148. $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT);
  149. unset($buffer);
  150. if ($xml === false) {
  151. $sheets = array();
  152. $message = PMA_Message::error(
  153. __(
  154. 'The XML file specified was either malformed or incomplete.'
  155. . ' Please correct the issue and try again.'
  156. )
  157. );
  158. $error = true;
  159. } else {
  160. $root = $xml->children('office', true)->{'body'}->{'spreadsheet'};
  161. if (empty($root)) {
  162. $sheets = array();
  163. $message = PMA_Message::error(
  164. __('Could not parse OpenDocument Spreadsheet!')
  165. );
  166. $error = true;
  167. } else {
  168. $sheets = $root->children('table', true);
  169. }
  170. }
  171. $tables = array();
  172. $max_cols = 0;
  173. $row_count = 0;
  174. $col_count = 0;
  175. $col_names = array();
  176. $tempRow = array();
  177. $tempRows = array();
  178. $rows = array();
  179. /* Iterate over tables */
  180. foreach ($sheets as $sheet) {
  181. $col_names_in_first_row = isset($_REQUEST['ods_col_names']);
  182. /* Iterate over rows */
  183. foreach ($sheet as $row) {
  184. $type = $row->getName();
  185. if (! strcmp('table-row', $type)) {
  186. /* Iterate over columns */
  187. foreach ($row as $cell) {
  188. $text = $cell->children('text', true);
  189. $cell_attrs = $cell->attributes('office', true);
  190. if (count($text) != 0) {
  191. $attr = $cell->attributes('table', true);
  192. $num_repeat = (int) $attr['number-columns-repeated'];
  193. $num_iterations = $num_repeat ? $num_repeat : 1;
  194. for ($k = 0; $k < $num_iterations; $k++) {
  195. if ($_REQUEST['ods_recognize_percentages']
  196. && ! strcmp(
  197. 'percentage',
  198. $cell_attrs['value-type']
  199. )
  200. ) {
  201. $value = (double)$cell_attrs['value'];
  202. } elseif ($_REQUEST['ods_recognize_currency']
  203. && !strcmp('currency', $cell_attrs['value-type'])
  204. ) {
  205. $value = (double)$cell_attrs['value'];
  206. } else {
  207. /* We need to concatenate all paragraphs */
  208. $values = array();
  209. foreach ($text as $paragraph) {
  210. $values[] = (string)$paragraph;
  211. }
  212. $value = implode("\n", $values);
  213. }
  214. if (! $col_names_in_first_row) {
  215. $tempRow[] = $value;
  216. } else {
  217. $col_names[] = $value;
  218. }
  219. ++$col_count;
  220. }
  221. } else {
  222. /* Number of blank columns repeated */
  223. if ($col_count < count($row->children('table', true)) - 1
  224. ) {
  225. $attr = $cell->attributes('table', true);
  226. $num_null = (int)$attr['number-columns-repeated'];
  227. if ($num_null) {
  228. if (! $col_names_in_first_row) {
  229. for ($i = 0; $i < $num_null; ++$i) {
  230. $tempRow[] = 'NULL';
  231. ++$col_count;
  232. }
  233. } else {
  234. for ($i = 0; $i < $num_null; ++$i) {
  235. $col_names[] = PMA_getColumnAlphaName(
  236. $col_count + 1
  237. );
  238. ++$col_count;
  239. }
  240. }
  241. } else {
  242. if (! $col_names_in_first_row) {
  243. $tempRow[] = 'NULL';
  244. } else {
  245. $col_names[] = PMA_getColumnAlphaName(
  246. $col_count + 1
  247. );
  248. }
  249. ++$col_count;
  250. }
  251. }
  252. }
  253. }
  254. /* Find the widest row */
  255. if ($col_count > $max_cols) {
  256. $max_cols = $col_count;
  257. }
  258. /* Don't include a row that is full of NULL values */
  259. if (! $col_names_in_first_row) {
  260. if ($_REQUEST['ods_empty_rows']) {
  261. foreach ($tempRow as $cell) {
  262. if (strcmp('NULL', $cell)) {
  263. $tempRows[] = $tempRow;
  264. break;
  265. }
  266. }
  267. } else {
  268. $tempRows[] = $tempRow;
  269. }
  270. }
  271. $col_count = 0;
  272. $col_names_in_first_row = false;
  273. $tempRow = array();
  274. }
  275. }
  276. /* Skip over empty sheets */
  277. if (count($tempRows) == 0 || count($tempRows[0]) == 0) {
  278. $col_names = array();
  279. $tempRow = array();
  280. $tempRows = array();
  281. continue;
  282. }
  283. /**
  284. * Fill out each row as necessary to make
  285. * every one exactly as wide as the widest
  286. * row. This included column names.
  287. */
  288. /* Fill out column names */
  289. for ($i = count($col_names); $i < $max_cols; ++$i) {
  290. $col_names[] = PMA_getColumnAlphaName($i + 1);
  291. }
  292. /* Fill out all rows */
  293. $num_rows = count($tempRows);
  294. for ($i = 0; $i < $num_rows; ++$i) {
  295. for ($j = count($tempRows[$i]); $j < $max_cols; ++$j) {
  296. $tempRows[$i][] = 'NULL';
  297. }
  298. }
  299. /* Store the table name so we know where to place the row set */
  300. $tbl_attr = $sheet->attributes('table', true);
  301. $tables[] = array((string)$tbl_attr['name']);
  302. /* Store the current sheet in the accumulator */
  303. $rows[] = array((string)$tbl_attr['name'], $col_names, $tempRows);
  304. $tempRows = array();
  305. $col_names = array();
  306. $max_cols = 0;
  307. }
  308. unset($tempRow);
  309. unset($tempRows);
  310. unset($col_names);
  311. unset($sheets);
  312. unset($xml);
  313. /**
  314. * Bring accumulated rows into the corresponding table
  315. */
  316. $num_tbls = count($tables);
  317. for ($i = 0; $i < $num_tbls; ++$i) {
  318. for ($j = 0; $j < count($rows); ++$j) {
  319. if (! strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) {
  320. if (! isset($tables[$i][COL_NAMES])) {
  321. $tables[$i][] = $rows[$j][COL_NAMES];
  322. }
  323. $tables[$i][ROWS] = $rows[$j][ROWS];
  324. }
  325. }
  326. }
  327. /* No longer needed */
  328. unset($rows);
  329. /* Obtain the best-fit MySQL types for each column */
  330. $analyses = array();
  331. $len = count($tables);
  332. for ($i = 0; $i < $len; ++$i) {
  333. $analyses[] = PMA_analyzeTable($tables[$i]);
  334. }
  335. /**
  336. * string $db_name (no backquotes)
  337. *
  338. * array $table = array(table_name, array() column_names, array()() rows)
  339. * array $tables = array of "$table"s
  340. *
  341. * array $analysis = array(array() column_types, array() column_sizes)
  342. * array $analyses = array of "$analysis"s
  343. *
  344. * array $create = array of SQL strings
  345. *
  346. * array $options = an associative array of options
  347. */
  348. /* Set database name to the currently selected one, if applicable */
  349. if (strlen($db)) {
  350. $db_name = $db;
  351. $options = array('create_db' => false);
  352. } else {
  353. $db_name = 'ODS_DB';
  354. $options = null;
  355. }
  356. /* Non-applicable parameters */
  357. $create = null;
  358. /* Created and execute necessary SQL statements from data */
  359. PMA_buildSQL($db_name, $tables, $analyses, $create, $options);
  360. unset($tables);
  361. unset($analyses);
  362. /* Commit any possible data in buffers */
  363. PMA_importRunQuery();
  364. }
  365. }