function readFromBuffer($length) { global $buffer, $eof; if (strlen($buffer) < $length) { if ($GLOBALS['finished']) { $eof = true; } else { $buffer .= PMA_importGetNextChunk(); } } $result = substr($buffer, 0, $length); $buffer = substr($buffer, $length); return $result; }
/** * Handles the whole import logic * * @param array &$sql_data 2-element array with sql data * * @return void */ public function doImport(&$sql_data = array()) { global $error, $timeout_passed; $buffer = ''; // Defaults for parser $sql = ''; $start_pos = 0; $i = 0; $len = 0; $big_value = 2147483647; // include the space because it's mandatory $delimiter_keyword = 'DELIMITER '; $length_of_delimiter_keyword = strlen($delimiter_keyword); if (isset($_POST['sql_delimiter'])) { $sql_delimiter = $_POST['sql_delimiter']; } else { $sql_delimiter = ';'; } // Handle compatibility options $sql_modes = array(); if (isset($_REQUEST['sql_compatibility']) && 'NONE' != $_REQUEST['sql_compatibility']) { $sql_modes[] = $_REQUEST['sql_compatibility']; } if (isset($_REQUEST['sql_no_auto_value_on_zero'])) { $sql_modes[] = 'NO_AUTO_VALUE_ON_ZERO'; } if (count($sql_modes) > 0) { $GLOBALS['dbi']->tryQuery('SET SQL_MODE="' . implode(',', $sql_modes) . '"'); } unset($sql_modes); /** * will be set in PMA_importGetNextChunk() * * @global boolean $GLOBALS['finished'] */ $GLOBALS['finished'] = false; while (!($GLOBALS['finished'] && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { // subtract data we didn't handle yet and stop processing $GLOBALS['offset'] -= strlen($buffer); break; } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; // free memory unset($data); // Do not parse string when we're not at the end // and don't have ; inside if (strpos($buffer, $sql_delimiter, $i) === false && !$GLOBALS['finished']) { continue; } } // Convert CR (but not CRLF) to LF otherwise all queries // may not get executed on some platforms $buffer = preg_replace("/\r(\$|[^\n])/", "\n\$1", $buffer); // Current length of our buffer $len = strlen($buffer); // Grab some SQL queries out of it while ($i < $len) { $found_delimiter = false; // Find first interesting character $old_i = $i; // this is about 7 times faster that looking for each sequence i // one by one with strpos() $match = preg_match('/(\'|"|#|-- |\\/\\*|`|(?i)(?<![A-Z0-9_])' . $delimiter_keyword . ')/', $buffer, $matches, PREG_OFFSET_CAPTURE, $i); if ($match) { // in $matches, index 0 contains the match for the complete // expression but we don't use it $first_position = $matches[1][1]; } else { $first_position = $big_value; } /** * @todo we should not look for a delimiter that might be * inside quotes (or even double-quotes) */ // the cost of doing this one with preg_match() would be too high $first_sql_delimiter = strpos($buffer, $sql_delimiter, $i); if ($first_sql_delimiter === false) { $first_sql_delimiter = $big_value; } else { $found_delimiter = true; } // set $i to the position of the first quote, // comment.start or delimiter found $i = min($first_position, $first_sql_delimiter); if ($i == $big_value) { // none of the above was found in the string $i = $old_i; if (!$GLOBALS['finished']) { break; } // at the end there might be some whitespace... if (trim($buffer) == '') { $buffer = ''; $len = 0; break; } // We hit end of query, go there! $i = strlen($buffer) - 1; } // Grab current character $ch = $buffer[$i]; // Quotes if (strpos('\'"`', $ch) !== false) { $quote = $ch; $endq = false; while (!$endq) { // Find next quote $pos = strpos($buffer, $quote, $i + 1); /* * Behave same as MySQL and accept end of query as end * of backtick. * I know this is sick, but MySQL behaves like this: * * SELECT * FROM `table * * is treated like * * SELECT * FROM `table` */ if ($pos === false && $quote == '`' && $found_delimiter) { $pos = $first_sql_delimiter - 1; } elseif ($pos === false) { // No quote? Too short string // We hit end of string => unclosed quote, // but we handle it as end of query if ($GLOBALS['finished']) { $endq = true; $i = $len - 1; } $found_delimiter = false; break; } // Was not the quote escaped? $j = $pos - 1; while ($buffer[$j] == '\\') { $j--; } // Even count means it was not escaped $endq = ($pos - 1 - $j) % 2 == 0; // Skip the string $i = $pos; if ($first_sql_delimiter < $pos) { $found_delimiter = false; } } if (!$endq) { break; } $i++; // Aren't we at the end? if ($GLOBALS['finished'] && $i == $len) { $i--; } else { continue; } } // Not enough data to decide if (($i == $len - 1 && ($ch == '-' || $ch == '/') || $i == $len - 2 && ($ch == '-' && $buffer[$i + 1] == '-' || $ch == '/' && $buffer[$i + 1] == '*')) && !$GLOBALS['finished']) { break; } // Comments if ($ch == '#' || $i < $len - 1 && $ch == '-' && $buffer[$i + 1] == '-' && ($i < $len - 2 && $buffer[$i + 2] <= ' ' || $i == $len - 1 && $GLOBALS['finished']) || $i < $len - 1 && $ch == '/' && $buffer[$i + 1] == '*') { // Copy current string to SQL if ($start_pos != $i) { $sql .= substr($buffer, $start_pos, $i - $start_pos); } // Skip the rest $start_of_comment = $i; // do not use PHP_EOL here instead of "\n", because the export // file might have been produced on a different system $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); // didn't we hit end of string? if ($i === false) { if ($GLOBALS['finished']) { $i = $len - 1; } else { break; } } // Skip * if ($ch == '/') { $i++; } // Skip last char $i++; // We need to send the comment part in case we are defining // a procedure or function and comments in it are valuable $sql .= substr($buffer, $start_of_comment, $i - $start_of_comment); // Next query part will start here $start_pos = $i; // Aren't we at the end? if ($i == $len) { $i--; } else { continue; } } // Change delimiter, if redefined, and skip it // (don't send to server!) if ($i + $length_of_delimiter_keyword < $len && strtoupper(substr($buffer, $i, $length_of_delimiter_keyword)) == $delimiter_keyword) { // look for EOL on the character immediately after 'DELIMITER ' // (see previous comment about PHP_EOL) $new_line_pos = strpos($buffer, "\n", $i + $length_of_delimiter_keyword); // it might happen that there is no EOL if (false === $new_line_pos) { $new_line_pos = $len; } $sql_delimiter = substr($buffer, $i + $length_of_delimiter_keyword, $new_line_pos - $i - $length_of_delimiter_keyword); $i = $new_line_pos + 1; // Next query part will start here $start_pos = $i; continue; } // End of SQL if ($found_delimiter || $GLOBALS['finished'] && $i == $len - 1) { $tmp_sql = $sql; if ($start_pos < $len) { $length_to_grab = $i - $start_pos; if (!$found_delimiter) { $length_to_grab++; } $tmp_sql .= substr($buffer, $start_pos, $length_to_grab); unset($length_to_grab); } // Do not try to execute empty SQL if (!preg_match('/^([\\s]*;)*$/', trim($tmp_sql))) { $sql = $tmp_sql; PMA_importRunQuery($sql, substr($buffer, 0, $i + strlen($sql_delimiter)), false, $sql_data); $buffer = substr($buffer, $i + strlen($sql_delimiter)); // Reset parser: $len = strlen($buffer); $sql = ''; $i = 0; $start_pos = 0; // Any chance we will get a complete query? //if ((strpos($buffer, ';') === false) //&& ! $GLOBALS['finished']) { if (strpos($buffer, $sql_delimiter) === false && !$GLOBALS['finished']) { break; } } else { $i++; $start_pos = $i; } } } // End of parser loop } // End of import loop // Commit any possible data in buffers PMA_importRunQuery('', substr($buffer, 0, $len), false, $sql_data); PMA_importRunQuery('', '', false, $sql_data); }
/** * Handles the whole import logic * * @param array &$sql_data 2-element array with sql data * * @return void */ public function doImport(&$sql_data = array()) { global $error, $timeout_passed; // Handle compatibility options. $this->_setSQLMode($GLOBALS['dbi'], $_REQUEST); $bq = new SqlParser\Utils\BufferedQuery(); if (isset($_POST['sql_delimiter'])) { $bq->setDelimiter($_POST['sql_delimiter']); } /** * Will be set in PMA_importGetNextChunk(). * * @global bool $GLOBALS ['finished'] */ $GLOBALS['finished'] = false; while (!$error && !$timeout_passed) { // Getting the first statement, the remaining data and the last // delimiter. $statement = $bq->extract(); // If there is no full statement, we are looking for more data. if (empty($statement)) { // Importing new data. $newData = PMA_importGetNextChunk(); // Subtract data we didn't handle yet and stop processing. if ($newData === false) { $GLOBALS['offset'] -= mb_strlen($bq->query); break; } // Checking if the input buffer has finished. if ($newData === true) { $GLOBALS['finished'] = true; break; } // Convert CR (but not CRLF) to LF otherwise all queries may // not get executed on some platforms. $bq->query .= preg_replace("/\r(\$|[^\n])/", "\n\$1", $newData); continue; } // Executing the query. PMA_importRunQuery($statement, $statement, false, $sql_data); } // Extracting remaining statements. while (!$error && !$timeout_passed && !empty($bq->query)) { $statement = $bq->extract(true); if (!empty($statement)) { PMA_importRunQuery($statement, $statement, false, $sql_data); } } // Finishing. PMA_importRunQuery('', '', false, $sql_data); }
// Convert the file's charset if necessary if ($GLOBALS['PMA_recoding_engine'] != PMA_CHARSET_NONE && isset($charset_of_file)) { if ($charset_of_file != $charset) { $charset_conversion = TRUE; } } elseif (isset($charset_of_file) && $charset_of_file != 'utf8') { PMA_DBI_query('SET NAMES \'' . $charset_of_file . '\''); // We can not show query in this case, it is in different charset $sql_query_disabled = TRUE; $reset_charset = TRUE; } // Something to skip? if (!$error && isset($skip)) { $original_skip = $skip; while ($skip > 0) { PMA_importGetNextChunk($skip < $read_limit ? $skip : $read_limit); $read_multiply = 1; // Disable read progresivity, otherwise we eat all memory! $skip -= $read_limit; } unset($skip); } if (!$error) { // Check for file existance if (!file_exists('./libraries/import/' . $format . '.php')) { $error = TRUE; $message = PMA_Message::error(__('Could not load import plugins, please check your installation!')); } else { // Do the real import $plugin_param = $import_type; require './libraries/import/' . $format . '.php';
/** * Handles the whole import logic * * @return void */ public function doImport() { global $error, $timeout_passed, $finished; // Defaults for parser // The buffer that will be used to store chunks read from the imported file $buffer = ''; // Used as storage for the last part of the current chunk data // Will be appended to the first line of the next chunk, if there is one $last_chunk_line = ''; // Remembers whether the current buffer line is part of a comment $inside_comment = false; // Remembers whether the current buffer line is part of a data comment $inside_data_comment = false; // Remembers whether the current buffer line is part of a structure comment $inside_structure_comment = false; // MediaWiki only accepts "\n" as row terminator $mediawiki_new_line = "\n"; // Initialize the name of the current table $cur_table_name = ""; while (!$finished && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { // Subtract data we didn't handle yet and stop processing $GLOBALS['offset'] -= mb_strlen($buffer); break; } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer $buffer = $data; unset($data); // Don't parse string if we're not at the end // and don't have a new line inside if (mb_strpos($buffer, $mediawiki_new_line) === false) { continue; } } // Because of reading chunk by chunk, the first line from the buffer // contains only a portion of an actual line from the imported file. // Therefore, we have to append it to the last line from the previous // chunk. If we are at the first chunk, $last_chunk_line should be empty. $buffer = $last_chunk_line . $buffer; // Process the buffer line by line $buffer_lines = explode($mediawiki_new_line, $buffer); $full_buffer_lines_count = count($buffer_lines); // If the reading is not finalised, the final line of the current chunk // will not be complete if (!$finished) { $last_chunk_line = $buffer_lines[--$full_buffer_lines_count]; } for ($line_nr = 0; $line_nr < $full_buffer_lines_count; ++$line_nr) { $cur_buffer_line = trim($buffer_lines[$line_nr]); // If the line is empty, go to the next one if ($cur_buffer_line === '') { continue; } $first_character = $cur_buffer_line[0]; $matches = array(); // Check beginning of comment if (!strcmp(mb_substr($cur_buffer_line, 0, 4), "<!--")) { $inside_comment = true; continue; } elseif ($inside_comment) { // Check end of comment if (!strcmp(mb_substr($cur_buffer_line, 0, 4), "-->")) { // Only data comments are closed. The structure comments // will be closed when a data comment begins (in order to // skip structure tables) if ($inside_data_comment) { $inside_data_comment = false; } // End comments that are not related to table structure if (!$inside_structure_comment) { $inside_comment = false; } } else { // Check table name $match_table_name = array(); if (preg_match("/^Table data for `(.*)`\$/", $cur_buffer_line, $match_table_name)) { $cur_table_name = $match_table_name[1]; $inside_data_comment = true; $inside_structure_comment = $this->_mngInsideStructComm($inside_structure_comment); } elseif (preg_match("/^Table structure for `(.*)`\$/", $cur_buffer_line, $match_table_name)) { // The structure comments will be ignored $inside_structure_comment = true; } } continue; } elseif (preg_match('/^\\{\\|(.*)$/', $cur_buffer_line, $matches)) { // Check start of table // This will store all the column info on all rows from // the current table read from the buffer $cur_temp_table = array(); // Will be used as storage for the current row in the buffer // Once all its columns are read, it will be added to // $cur_temp_table and then it will be emptied $cur_temp_line = array(); // Helps us differentiate the header columns // from the normal columns $in_table_header = false; // End processing because the current line does not // contain any column information } elseif (mb_substr($cur_buffer_line, 0, 2) === '|-' || mb_substr($cur_buffer_line, 0, 2) === '|+' || mb_substr($cur_buffer_line, 0, 2) === '|}') { // Check begin row or end table // Add current line to the values storage if (!empty($cur_temp_line)) { // If the current line contains header cells // ( marked with '!' ), // it will be marked as table header if ($in_table_header) { // Set the header columns $cur_temp_table_headers = $cur_temp_line; } else { // Normal line, add it to the table $cur_temp_table[] = $cur_temp_line; } } // Empty the temporary buffer $cur_temp_line = array(); // No more processing required at the end of the table if (mb_substr($cur_buffer_line, 0, 2) === '|}') { $current_table = array($cur_table_name, $cur_temp_table_headers, $cur_temp_table); // Import the current table data into the database $this->_importDataOneTable($current_table); // Reset table name $cur_table_name = ""; } // What's after the row tag is now only attributes } elseif ($first_character === '|' || $first_character === '!') { // Check cell elements // Header cells if ($first_character === '!') { // Mark as table header, but treat as normal row $cur_buffer_line = str_replace('!!', '||', $cur_buffer_line); // Will be used to set $cur_temp_line as table header $in_table_header = true; } else { $in_table_header = false; } // Loop through each table cell $cells = $this->_explodeMarkup($cur_buffer_line); foreach ($cells as $cell) { $cell = $this->_getCellData($cell); // Delete the beginning of the column, if there is one $cell = trim($cell); $col_start_chars = array("|", "!"); foreach ($col_start_chars as $col_start_char) { $cell = $this->_getCellContent($cell, $col_start_char); } // Add the cell to the row $cur_temp_line[] = $cell; } // foreach $cells } else { // If it's none of the above, then the current line has a bad // format $message = PMA\libraries\Message::error(__('Invalid format of mediawiki input on line: <br />%s.')); $message->addParam($cur_buffer_line); $error = true; } } // End treating full buffer lines } // while - finished parsing buffer }
if (isset($plugin_list)) { $plugin_list['ods'] = array('text' => __('Open Document Spreadsheet'), 'extension' => 'ods', 'options' => array(array('type' => 'begin_group', 'name' => 'general_opts'), array('type' => 'bool', 'name' => 'col_names', 'text' => __('The first line of the file contains the table column names <i>(if this is unchecked, the first line will become part of the data)</i>')), array('type' => 'bool', 'name' => 'empty_rows', 'text' => __('Do not import empty rows')), array('type' => 'bool', 'name' => 'recognize_percentages', 'text' => __('Import percentages as proper decimals <i>(ex. 12.00% to .12)</i>')), array('type' => 'bool', 'name' => 'recognize_currency', 'text' => __('Import currencies <i>(ex. $5.00 to 5.00)</i>')), array('type' => 'end_group')), 'options_text' => __('Options')); /* We do not define function when plugin is just queried for information above */ return; } ini_set('memory_limit', '128M'); set_time_limit(120); $i = 0; $len = 0; $buffer = ""; /** * Read in the file via PMA_importGetNextChunk so that * it can process compressed files */ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === FALSE) { /* subtract data we didn't handle yet and stop processing */ $offset -= strlen($buffer); break; } elseif ($data === TRUE) { /* Handle rest of buffer */ } else { /* Append new data to buffer */ $buffer .= $data; unset($data); } } unset($data); /** * Disable loading of external XML entities.
/** * Handles the whole import logic * * @param array &$sql_data 2-element array with sql data * * @return void */ public function doImport(&$sql_data = array()) { global $db, $table, $csv_terminated, $csv_enclosed, $csv_escaped, $csv_new_line, $csv_columns, $err_url; // $csv_replace and $csv_ignore should have been here, // but we use directly from $_POST global $error, $timeout_passed, $finished, $message; $replacements = array('\\n' => "\n", '\\t' => "\t", '\\r' => "\r"); $csv_terminated = strtr($csv_terminated, $replacements); $csv_enclosed = strtr($csv_enclosed, $replacements); $csv_escaped = strtr($csv_escaped, $replacements); $csv_new_line = strtr($csv_new_line, $replacements); $param_error = false; if (mb_strlen($csv_terminated) < 1) { $message = PMA\libraries\Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns terminated with'), false); $error = true; $param_error = true; // The default dialog of MS Excel when generating a CSV produces a // semi-colon-separated file with no chance of specifying the // enclosing character. Thus, users who want to import this file // tend to remove the enclosing character on the Import dialog. // I could not find a test case where having no enclosing characters // confuses this script. // But the parser won't work correctly with strings so we allow just // one character. } elseif (mb_strlen($csv_enclosed) > 1) { $message = PMA\libraries\Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns enclosed with'), false); $error = true; $param_error = true; // I could not find a test case where having no escaping characters // confuses this script. // But the parser won't work correctly with strings so we allow just // one character. } elseif (mb_strlen($csv_escaped) > 1) { $message = PMA\libraries\Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Columns escaped with'), false); $error = true; $param_error = true; } elseif (mb_strlen($csv_new_line) != 1 && $csv_new_line != 'auto') { $message = PMA\libraries\Message::error(__('Invalid parameter for CSV import: %s')); $message->addParam(__('Lines terminated with'), false); $error = true; $param_error = true; } // If there is an error in the parameters entered, // indicate that immediately. if ($param_error) { PMA\libraries\Util::mysqlDie($message->getMessage(), '', false, $err_url); } $buffer = ''; $required_fields = 0; if (!$this->_getAnalyze()) { $sql_template = 'INSERT'; if (isset($_POST['csv_ignore'])) { $sql_template .= ' IGNORE'; } $sql_template .= ' INTO ' . PMA\libraries\Util::backquote($table); $tmp_fields = $GLOBALS['dbi']->getColumns($db, $table); if (empty($csv_columns)) { $fields = $tmp_fields; } else { $sql_template .= ' ('; $fields = array(); $tmp = preg_split('/,( ?)/', $csv_columns); foreach ($tmp as $key => $val) { if (count($fields) > 0) { $sql_template .= ', '; } /* Trim also `, if user already included backquoted fields */ $val = trim($val, " \t\r\n\v`"); $found = false; foreach ($tmp_fields as $field) { if ($field['Field'] == $val) { $found = true; break; } } if (!$found) { $message = PMA\libraries\Message::error(__('Invalid column (%s) specified! Ensure that columns' . ' names are spelled correctly, separated by commas' . ', and not enclosed in quotes.')); $message->addParam($val); $error = true; break; } $fields[] = $field; $sql_template .= PMA\libraries\Util::backquote($val); } $sql_template .= ') '; } $required_fields = count($fields); $sql_template .= ' VALUES ('; } // Defaults for parser $i = 0; $len = 0; $lastlen = null; $line = 1; $lasti = -1; $values = array(); $csv_finish = false; $tempRow = array(); $rows = array(); $col_names = array(); $tables = array(); $col_count = 0; $max_cols = 0; $csv_terminated_len = mb_strlen($csv_terminated); while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { // subtract data we didn't handle yet and stop processing $GLOBALS['offset'] -= strlen($buffer); break; } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; unset($data); // Force a trailing new line at EOF to prevent parsing problems if ($finished && $buffer) { $finalch = mb_substr($buffer, -1); if ($csv_new_line == 'auto' && $finalch != "\r" && $finalch != "\n") { $buffer .= "\n"; } elseif ($csv_new_line != 'auto' && $finalch != $csv_new_line) { $buffer .= $csv_new_line; } } // Do not parse string when we're not at the end // and don't have new line inside if ($csv_new_line == 'auto' && mb_strpos($buffer, "\r") === false && mb_strpos($buffer, "\n") === false || $csv_new_line != 'auto' && mb_strpos($buffer, $csv_new_line) === false) { continue; } } // Current length of our buffer $len = mb_strlen($buffer); // Currently parsed char $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } while ($i < $len) { // Deadlock protection if ($lasti == $i && $lastlen == $len) { $message = PMA\libraries\Message::error(__('Invalid format of CSV input on line %d.')); $message->addParam($line); $error = true; break; } $lasti = $i; $lastlen = $len; // This can happen with auto EOL and \r at the end of buffer if (!$csv_finish) { // Grab empty field if ($ch == $csv_terminated) { if ($i == $len - 1) { break; } $values[] = ''; $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } continue; } // Grab one field $fallbacki = $i; if ($ch == $csv_enclosed) { if ($i == $len - 1) { break; } $need_end = true; $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } } else { $need_end = false; } $fail = false; $value = ''; while ($need_end && ($ch != $csv_enclosed || $csv_enclosed == $csv_escaped) || !$need_end && !($ch == $csv_terminated || $ch == $csv_new_line || $csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))) { if ($ch == $csv_escaped) { if ($i == $len - 1) { $fail = true; break; } $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } if ($csv_enclosed == $csv_escaped && ($ch == $csv_terminated || $ch == $csv_new_line || $csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n"))) { break; } } $value .= $ch; if ($i == $len - 1) { if (!$finished) { $fail = true; } break; } $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } } // unquoted NULL string if (false === $need_end && $value === 'NULL') { $value = null; } if ($fail) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $i += $csv_terminated_len - 1; } break; } // Need to strip trailing enclosing char? if ($need_end && $ch == $csv_enclosed) { if ($finished && $i == $len - 1) { $ch = null; } elseif ($i == $len - 1) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $i += $csv_terminated_len - 1; } break; } else { $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } } } // Are we at the end? if ($ch == $csv_new_line || $csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n") || $finished && $i == $len - 1) { $csv_finish = true; } // Go to next char if ($ch == $csv_terminated) { if ($i == $len - 1) { $i = $fallbacki; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $i += $csv_terminated_len - 1; } break; } $i++; $ch = mb_substr($buffer, $i, 1); if ($csv_terminated_len > 1 && $ch == $csv_terminated[0]) { $ch = $this->readCsvTerminatedString($buffer, $ch, $i, $csv_terminated_len); $i += $csv_terminated_len - 1; } } // If everything went okay, store value $values[] = $value; } // End of line if ($csv_finish || $ch == $csv_new_line || $csv_new_line == 'auto' && ($ch == "\r" || $ch == "\n")) { if ($csv_new_line == 'auto' && $ch == "\r") { // Handle "\r\n" if ($i >= $len - 2 && !$finished) { break; // We need more data to decide new line } if (mb_substr($buffer, $i + 1, 1) == "\n") { $i++; } } // We didn't parse value till the end of line, so there was // empty one if (!$csv_finish) { $values[] = ''; } if ($this->_getAnalyze()) { foreach ($values as $val) { $tempRow[] = $val; ++$col_count; } if ($col_count > $max_cols) { $max_cols = $col_count; } $col_count = 0; $rows[] = $tempRow; $tempRow = array(); } else { // Do we have correct count of values? if (count($values) != $required_fields) { // Hack for excel if ($values[count($values) - 1] == ';') { unset($values[count($values) - 1]); } else { $message = PMA\libraries\Message::error(__('Invalid column count in CSV input' . ' on line %d.')); $message->addParam($line); $error = true; break; } } $first = true; $sql = $sql_template; foreach ($values as $key => $val) { if (!$first) { $sql .= ', '; } if ($val === null) { $sql .= 'NULL'; } else { $sql .= '\'' . PMA\libraries\Util::sqlAddSlashes($val) . '\''; } $first = false; } $sql .= ')'; if (isset($_POST['csv_replace'])) { $sql .= " ON DUPLICATE KEY UPDATE "; foreach ($fields as $field) { $fieldName = PMA\libraries\Util::backquote($field['Field']); $sql .= $fieldName . " = VALUES(" . $fieldName . "), "; } $sql = rtrim($sql, ', '); } /** * @todo maybe we could add original line to verbose * SQL in comment */ PMA_importRunQuery($sql, $sql, $sql_data); } $line++; $csv_finish = false; $values = array(); $buffer = mb_substr($buffer, $i + 1); $len = mb_strlen($buffer); $i = 0; $lasti = -1; $ch = mb_substr($buffer, 0, 1); } } // End of parser loop } // End of import loop if ($this->_getAnalyze()) { /* Fill out all rows */ $num_rows = count($rows); for ($i = 0; $i < $num_rows; ++$i) { for ($j = count($rows[$i]); $j < $max_cols; ++$j) { $rows[$i][] = 'NULL'; } } if (isset($_REQUEST['csv_col_names'])) { $col_names = array_splice($rows, 0, 1); $col_names = $col_names[0]; // MySQL column names can't end with a space character. foreach ($col_names as $key => $col_name) { $col_names[$key] = rtrim($col_name); } } if (isset($col_names) && count($col_names) != $max_cols || !isset($col_names)) { // Fill out column names for ($i = 0; $i < $max_cols; ++$i) { $col_names[] = 'COL ' . ($i + 1); } } if (mb_strlen($db)) { $result = $GLOBALS['dbi']->fetchResult('SHOW TABLES'); $tbl_name = 'TABLE ' . (count($result) + 1); } else { $tbl_name = 'TBL_NAME'; } $tables[] = array($tbl_name, $col_names, $rows); /* Obtain the best-fit MySQL types for each column */ $analyses = array(); $analyses[] = PMA_analyzeTable($tables[0]); /** * string $db_name (no backquotes) * * array $table = array(table_name, array() column_names, array()() rows) * array $tables = array of "$table"s * * array $analysis = array(array() column_types, array() column_sizes) * array $analyses = array of "$analysis"s * * array $create = array of SQL strings * * array $options = an associative array of options */ /* Set database name to the currently selected one, if applicable */ list($db_name, $options) = $this->getDbnameAndOptions($db, 'CSV_DB'); /* Non-applicable parameters */ $create = null; /* Created and execute necessary SQL statements from data */ PMA_buildSQL($db_name, $tables, $analyses, $create, $options, $sql_data); unset($tables); unset($analyses); } // Commit any possible data in buffers PMA_importRunQuery('', '', $sql_data); if (count($values) != 0 && !$error) { $message = PMA\libraries\Message::error(__('Invalid format of CSV input on line %d.')); $message->addParam($line); $error = true; } }
/** * Handles the whole import logic * * @return void */ public function doImport() { global $db, $error, $timeout_passed, $finished; $i = 0; $len = 0; $buffer = ""; /** * Read in the file via PMA_importGetNextChunk so that * it can process compressed files */ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { /* subtract data we didn't handle yet and stop processing */ $GLOBALS['offset'] -= strlen($buffer); break; } elseif ($data === true) { /* Handle rest of buffer */ } else { /* Append new data to buffer */ $buffer .= $data; unset($data); } } unset($data); /** * Disable loading of external XML entities. */ libxml_disable_entity_loader(); /** * Load the XML string * * The option LIBXML_COMPACT is specified because it can * result in increased performance without the need to * alter the code in any way. It's basically a freebee. */ $xml = simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); unset($buffer); if ($xml === false) { $sheets = array(); $GLOBALS['message'] = PMA_Message::error(__('The XML file specified was either malformed or incomplete.' . ' Please correct the issue and try again.')); $GLOBALS['error'] = true; } else { $root = $xml->children('office', true)->{'body'}->{'spreadsheet'}; if (empty($root)) { $sheets = array(); $GLOBALS['message'] = PMA_Message::error(__('Could not parse OpenDocument Spreadsheet!')); $GLOBALS['error'] = true; } else { $sheets = $root->children('table', true); } } $tables = array(); $max_cols = 0; $col_count = 0; $col_names = array(); $tempRow = array(); $tempRows = array(); $rows = array(); /* Iterate over tables */ foreach ($sheets as $sheet) { $col_names_in_first_row = isset($_REQUEST['ods_col_names']); /* Iterate over rows */ foreach ($sheet as $row) { $type = $row->getName(); if (strcmp('table-row', $type)) { continue; } /* Iterate over columns */ foreach ($row as $cell) { $text = $cell->children('text', true); $cell_attrs = $cell->attributes('office', true); if (count($text) != 0) { $attr = $cell->attributes('table', true); $num_repeat = (int) $attr['number-columns-repeated']; $num_iterations = $num_repeat ? $num_repeat : 1; for ($k = 0; $k < $num_iterations; $k++) { $value = $this->getValue($cell_attrs, $text); if (!$col_names_in_first_row) { $tempRow[] = $value; } else { // MySQL column names can't end with a space // character. $col_names[] = rtrim($value); } ++$col_count; } continue; } $attr = $cell->attributes('table', true); $num_null = (int) $attr['number-columns-repeated']; if ($num_null) { if (!$col_names_in_first_row) { for ($i = 0; $i < $num_null; ++$i) { $tempRow[] = 'NULL'; ++$col_count; } } else { for ($i = 0; $i < $num_null; ++$i) { $col_names[] = PMA_getColumnAlphaName($col_count + 1); ++$col_count; } } } else { if (!$col_names_in_first_row) { $tempRow[] = 'NULL'; } else { $col_names[] = PMA_getColumnAlphaName($col_count + 1); } ++$col_count; } } //Endforeach /* Find the widest row */ if ($col_count > $max_cols) { $max_cols = $col_count; } /* Don't include a row that is full of NULL values */ if (!$col_names_in_first_row) { if ($_REQUEST['ods_empty_rows']) { foreach ($tempRow as $cell) { if (strcmp('NULL', $cell)) { $tempRows[] = $tempRow; break; } } } else { $tempRows[] = $tempRow; } } $col_count = 0; $col_names_in_first_row = false; $tempRow = array(); } /* Skip over empty sheets */ if (count($tempRows) == 0 || count($tempRows[0]) == 0) { $col_names = array(); $tempRow = array(); $tempRows = array(); continue; } /** * Fill out each row as necessary to make * every one exactly as wide as the widest * row. This included column names. */ /* Fill out column names */ for ($i = count($col_names); $i < $max_cols; ++$i) { $col_names[] = PMA_getColumnAlphaName($i + 1); } /* Fill out all rows */ $num_rows = count($tempRows); for ($i = 0; $i < $num_rows; ++$i) { for ($j = count($tempRows[$i]); $j < $max_cols; ++$j) { $tempRows[$i][] = 'NULL'; } } /* Store the table name so we know where to place the row set */ $tbl_attr = $sheet->attributes('table', true); $tables[] = array((string) $tbl_attr['name']); /* Store the current sheet in the accumulator */ $rows[] = array((string) $tbl_attr['name'], $col_names, $tempRows); $tempRows = array(); $col_names = array(); $max_cols = 0; } unset($tempRow); unset($tempRows); unset($col_names); unset($sheets); unset($xml); /** * Bring accumulated rows into the corresponding table */ $num_tbls = count($tables); for ($i = 0; $i < $num_tbls; ++$i) { for ($j = 0; $j < count($rows); ++$j) { if (strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { continue; } if (!isset($tables[$i][COL_NAMES])) { $tables[$i][] = $rows[$j][COL_NAMES]; } $tables[$i][ROWS] = $rows[$j][ROWS]; } } /* No longer needed */ unset($rows); /* Obtain the best-fit MySQL types for each column */ $analyses = array(); $len = count($tables); for ($i = 0; $i < $len; ++$i) { $analyses[] = PMA_analyzeTable($tables[$i]); } /** * string $db_name (no backquotes) * * array $table = array(table_name, array() column_names, array()() rows) * array $tables = array of "$table"s * * array $analysis = array(array() column_types, array() column_sizes) * array $analyses = array of "$analysis"s * * array $create = array of SQL strings * * array $options = an associative array of options */ /* Set database name to the currently selected one, if applicable */ list($db_name, $options) = $this->getDbnameAndOptions($db, 'ODS_DB'); /* Non-applicable parameters */ $create = null; /* Created and execute necessary SQL statements from data */ PMA_buildSQL($db_name, $tables, $analyses, $create, $options); unset($tables); unset($analyses); /* Commit any possible data in buffers */ PMA_importRunQuery(); }
function running($import_handle) { global $finished; $buffer = $ret = ''; // Defaults for parser $offset = 0; if (isset($_POST['sql_delimiter'])) { $sql_delimiter = $_POST['sql_delimiter']; } else { $sql_delimiter = '/*DELIMITER*/'; //$sql_delimiter = ';/*DELIMITER*/'; // Ruslan - should be without leading ; //$sql_delimiter = ';'; } // Handle compatibility option if (isset($_REQUEST['sql_compatibility'])) { PMA_DBI_try_query('SET SQL_MODE="' . $_REQUEST['sql_compatibility'] . '"'); } while (!$finished) { $data = PMA_importGetNextChunk(); if ($data === FALSE) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; } elseif ($data === TRUE) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; // Do not parse string when we're not at the end and don't have ; inside if (strpos($buffer, $sql_delimiter) === FALSE && !$finished) { continue; } $sql_queries = explode($sql_delimiter, $buffer); $c_queries = count($sql_queries); if (!$finished) { $buffer = $sql_queries[$c_queries - 1]; $sql_queries = array_splice($sql_queries, 0, $c_queries - 1); } foreach ($sql_queries as $query) { if (strlen($query) != 0) { $ret .= PMA_importRunQuery($query, ''); } } } } return $ret; }
/** * Handles the whole import logic * * @return void */ public function doImport() { global $error, $timeout_passed, $finished, $db; $i = 0; $len = 0; $buffer = ""; /** * Read in the file via PMA_importGetNextChunk so that * it can process compressed files */ while (!($finished && $i >= $len) && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { /* subtract data we didn't handle yet and stop processing */ $GLOBALS['offset'] -= strlen($buffer); break; } elseif ($data === true) { /* Handle rest of buffer */ } else { /* Append new data to buffer */ $buffer .= $data; unset($data); } } unset($data); /** * Disable loading of external XML entities. */ libxml_disable_entity_loader(); /** * Load the XML string * * The option LIBXML_COMPACT is specified because it can * result in increased performance without the need to * alter the code in any way. It's basically a freebee. */ $xml = @simplexml_load_string($buffer, "SimpleXMLElement", LIBXML_COMPACT); unset($buffer); /** * The XML was malformed */ if ($xml === false) { PMA\libraries\Message::error(__('The XML file specified was either malformed or incomplete.' . ' Please correct the issue and try again.'))->display(); unset($xml); $GLOBALS['finished'] = false; return; } /** * Table accumulator */ $tables = array(); /** * Row accumulator */ $rows = array(); /** * Temp arrays */ $tempRow = array(); $tempCells = array(); /** * CREATE code included (by default: no) */ $struct_present = false; /** * Analyze the data in each table */ $namespaces = $xml->getNameSpaces(true); /** * Get the database name, collation and charset */ $db_attr = $xml->children($namespaces['pma'])->{'structure_schemas'}->{'database'}; if ($db_attr instanceof SimpleXMLElement) { $db_attr = $db_attr->attributes(); $db_name = (string) $db_attr['name']; $collation = (string) $db_attr['collation']; $charset = (string) $db_attr['charset']; } else { /** * If the structure section is not present * get the database name from the data section */ $db_attr = $xml->children()->attributes(); $db_name = (string) $db_attr['name']; $collation = null; $charset = null; } /** * The XML was malformed */ if ($db_name === null) { PMA\libraries\Message::error(__('The XML file specified was either malformed or incomplete.' . ' Please correct the issue and try again.'))->display(); unset($xml); $GLOBALS['finished'] = false; return; } /** * Retrieve the structure information */ if (isset($namespaces['pma'])) { /** * Get structures for all tables * * @var SimpleXMLElement $struct */ $struct = $xml->children($namespaces['pma']); $create = array(); /** @var SimpleXMLElement $val1 */ foreach ($struct as $val1) { /** @var SimpleXMLElement $val2 */ foreach ($val1 as $val2) { // Need to select the correct database for the creation of // tables, views, triggers, etc. /** * @todo Generating a USE here blocks importing of a table * into another database. */ $attrs = $val2->attributes(); $create[] = "USE " . PMA\libraries\Util::backquote($attrs["name"]); foreach ($val2 as $val3) { /** * Remove the extra cosmetic spacing */ $val3 = str_replace(" ", "", (string) $val3); $create[] = $val3; } } } $struct_present = true; } /** * Move down the XML tree to the actual data */ $xml = $xml->children()->children(); $data_present = false; /** * Only attempt to analyze/collect data if there is data present */ if ($xml && @count($xml->children())) { $data_present = true; /** * Process all database content */ foreach ($xml as $v1) { $tbl_attr = $v1->attributes(); $isInTables = false; $num_tables = count($tables); for ($i = 0; $i < $num_tables; ++$i) { if (!strcmp($tables[$i][TBL_NAME], (string) $tbl_attr['name'])) { $isInTables = true; break; } } if (!$isInTables) { $tables[] = array((string) $tbl_attr['name']); } foreach ($v1 as $v2) { $row_attr = $v2->attributes(); if (!array_search((string) $row_attr['name'], $tempRow)) { $tempRow[] = (string) $row_attr['name']; } $tempCells[] = (string) $v2; } $rows[] = array((string) $tbl_attr['name'], $tempRow, $tempCells); $tempRow = array(); $tempCells = array(); } unset($tempRow); unset($tempCells); unset($xml); /** * Bring accumulated rows into the corresponding table */ $num_tables = count($tables); for ($i = 0; $i < $num_tables; ++$i) { $num_rows = count($rows); for ($j = 0; $j < $num_rows; ++$j) { if (!strcmp($tables[$i][TBL_NAME], $rows[$j][TBL_NAME])) { if (!isset($tables[$i][COL_NAMES])) { $tables[$i][] = $rows[$j][COL_NAMES]; } $tables[$i][ROWS][] = $rows[$j][ROWS]; } } } unset($rows); if (!$struct_present) { $analyses = array(); $len = count($tables); for ($i = 0; $i < $len; ++$i) { $analyses[] = PMA_analyzeTable($tables[$i]); } } } unset($xml); unset($tempCells); unset($rows); /** * Only build SQL from data if there is data present */ if ($data_present) { /** * Set values to NULL if they were not present * to maintain PMA_buildSQL() call integrity */ if (!isset($analyses)) { $analyses = null; if (!$struct_present) { $create = null; } } } /** * string $db_name (no backquotes) * * array $table = array(table_name, array() column_names, array()() rows) * array $tables = array of "$table"s * * array $analysis = array(array() column_types, array() column_sizes) * array $analyses = array of "$analysis"s * * array $create = array of SQL strings * * array $options = an associative array of options */ /* Set database name to the currently selected one, if applicable */ if (strlen($db)) { /* Override the database name in the XML file, if one is selected */ $db_name = $db; $options = array('create_db' => false); } else { if ($db_name === null) { $db_name = 'XML_DB'; } /* Set database collation/charset */ $options = array('db_collation' => $collation, 'db_charset' => $charset); } /* Created and execute necessary SQL statements from data */ PMA_buildSQL($db_name, $tables, $analyses, $create, $options); unset($analyses); unset($tables); unset($create); /* Commit any possible data in buffers */ PMA_importRunQuery(); }
/** * Handles the whole import logic * * @param array &$sql_data 2-element array with sql data * * @return void */ public function doImport(&$sql_data = array()) { global $error, $timeout_passed; //Manage multibytes or not if (isset($_REQUEST['sql_read_as_multibytes'])) { $this->_readMb = self::READ_MB_TRUE; } $this->_stringFctToUse = $this->_stringFunctions[$this->_readMb]; if (isset($_POST['sql_delimiter'])) { $this->_setDelimiter($_POST['sql_delimiter']); } else { $this->_setDelimiter(';'); } // Handle compatibility options $this->_setSQLMode($GLOBALS['dbi'], $_REQUEST); //Initialise data. $this->_setData(null); /** * will be set in PMA_importGetNextChunk() * * @global boolean $GLOBALS['finished'] */ $GLOBALS['finished'] = false; $delimiterFound = false; while (!$error && !$timeout_passed) { if (false === $delimiterFound) { $newData = PMA_importGetNextChunk(200); if ($newData === false) { // subtract data we didn't handle yet and stop processing $GLOBALS['offset'] -= $this->_dataLength; break; } if ($newData === true) { $GLOBALS['finished'] = true; break; } //Convert CR (but not CRLF) to LF otherwise all queries //may not get executed on some platforms $this->_addData(preg_replace("/\r(\$|[^\n])/", "\n\$1", $newData)); unset($newData); } //Find quotes, comments, delimiter definition or delimiter itself. $delimiterFound = $this->_findDelimiterPosition(); //If no delimiter found, restart and get more data. if (false === $delimiterFound) { continue; } PMA_importRunQuery($this->_stringFctToUse['substr']($this->_data, $this->_queryBeginPosition, $this->_delimiterPosition - $this->_queryBeginPosition), $this->_stringFctToUse['substr']($this->_data, 0, $this->_delimiterPosition + $this->_delimiterLength), false, $sql_data); $this->_setData($this->_stringFctToUse['substr']($this->_data, $this->_delimiterPosition + $this->_delimiterLength)); } //Commit any possible data in buffers PMA_importRunQuery($this->_stringFctToUse['substr']($this->_data, $this->_queryBeginPosition), $this->_data, false, $sql_data); PMA_importRunQuery('', '', false, $sql_data); }
/** * This function will import the huge database files (.sql) into database. * * @package restore * @author Chirag Nagda * @param string $import_file Name of the file with full path * @param resource $conn It is resouceID of the database connection * @return bool true/false On success TRUE otherwise FALSE * @since 4.1.5 */ function soft_import($import_file, $conn) { global $import_handle, $read_limit, $error, $offset, $finished; $buffer = ''; // Defaults for parser $offset = 0; $sql = ''; $start_pos = 0; $i = 0; $len = 0; $big_value = 2147483647; $delimiter_keyword = 'DELIMITER '; // include the space because it's mandatory $sql_delimiter = ';'; $import_handle = @fopen($import_file, 'r'); // We can not read all at once, otherwise we can run out of memory $memory_limit = trim(@ini_get('memory_limit')); // 2 MB as default if (empty($memory_limit)) { $memory_limit = 2 * 1024 * 1024; } // In case no memory limit we work on 10MB chunks if ($memory_limit == -1) { $memory_limit = 10 * 1024 * 1024; } // Calculate value of the limit if (strtolower(substr($memory_limit, -1)) == 'm') { $memory_limit = (int) substr($memory_limit, 0, -1) * 1024 * 1024; } elseif (strtolower(substr($memory_limit, -1)) == 'k') { $memory_limit = (int) substr($memory_limit, 0, -1) * 1024; } elseif (strtolower(substr($memory_limit, -1)) == 'g') { $memory_limit = (int) substr($memory_limit, 0, -1) * 1024 * 1024 * 1024; } else { $memory_limit = (int) $memory_limit; } $read_limit = $memory_limit / 8; // Just to be sure, there might be lot of memory needed for uncompression $finished = false; //will be set in PMA_importGetNextChunk() while (!($finished && $i >= $len)) { $data = PMA_importGetNextChunk(); if ($data === false) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; } elseif ($data === true) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; // free memory unset($data); // Do not parse string when we're not at the end and don't have ; inside if (strpos($buffer, $sql_delimiter, $i) === false && !$finished) { continue; } } // Current length of our buffer $len = strlen($buffer); // Grab some SQL queries out of it while ($i < $len) { $found_delimiter = false; // Find first interesting character $old_i = $i; // this is about 7 times faster that looking for each sequence i // one by one with strpos() if (preg_match('/(\'|"|#|-- |\\/\\*|`|(?i)(?<![A-Z0-9_])' . $delimiter_keyword . ')/', $buffer, $matches, PREG_OFFSET_CAPTURE, $i)) { // in $matches, index 0 contains the match for the complete // expression but we don't use it $first_position = $matches[1][1]; } else { $first_position = $big_value; } /** * @todo we should not look for a delimiter that might be * inside quotes (or even double-quotes) */ // the cost of doing this one with preg_match() would be too high $first_sql_delimiter = strpos($buffer, $sql_delimiter, $i); if ($first_sql_delimiter === false) { $first_sql_delimiter = $big_value; } else { $found_delimiter = true; } // set $i to the position of the first quote, comment.start or delimiter found $i = min($first_position, $first_sql_delimiter); if ($i == $big_value) { // none of the above was found in the string $i = $old_i; if (!$finished) { break; } // at the end there might be some whitespace... if (trim($buffer) == '') { $buffer = ''; $len = 0; break; } // We hit end of query, go there! $i = strlen($buffer) - 1; } // Grab current character $ch = $buffer[$i]; // Quotes if (strpos('\'"`', $ch) !== false) { $quote = $ch; $endq = false; while (!$endq) { // Find next quote $pos = strpos($buffer, $quote, $i + 1); /* * Behave same as MySQL and accept end of query as end of backtick. * I know this is sick, but MySQL behaves like this: * * SELECT * FROM `table * * is treated like * * SELECT * FROM `table` */ if ($pos === false && $quote == '`' && $found_delimiter) { $pos = $first_sql_delimiter - 1; // No quote? Too short string } elseif ($pos === false) { // We hit end of string => unclosed quote, but we handle it as end of query if ($finished) { $endq = true; $i = $len - 1; } $found_delimiter = false; break; } // Was not the quote escaped? $j = $pos - 1; while ($buffer[$j] == '\\') { $j--; } // Even count means it was not escaped $endq = ($pos - 1 - $j) % 2 == 0; // Skip the string $i = $pos; if ($first_sql_delimiter < $pos) { $found_delimiter = false; } } if (!$endq) { break; } $i++; // Aren't we at the end? if ($finished && $i == $len) { $i--; } else { continue; } } // Not enough data to decide if (($i == $len - 1 && ($ch == '-' || $ch == '/') || $i == $len - 2 && ($ch == '-' && $buffer[$i + 1] == '-' || $ch == '/' && $buffer[$i + 1] == '*')) && !$finished) { break; } // Comments if ($ch == '#' || $i < $len - 1 && $ch == '-' && $buffer[$i + 1] == '-' && ($i < $len - 2 && $buffer[$i + 2] <= ' ' || $i == $len - 1 && $finished) || $i < $len - 1 && $ch == '/' && $buffer[$i + 1] == '*') { // Copy current string to SQL if ($start_pos != $i) { $sql .= substr($buffer, $start_pos, $i - $start_pos); } // Skip the rest $start_of_comment = $i; // do not use PHP_EOL here instead of "\n", because the export // file might have been produced on a different system $i = strpos($buffer, $ch == '/' ? '*/' : "\n", $i); // didn't we hit end of string? if ($i === false) { if ($finished) { $i = $len - 1; } else { break; } } // Skip * if ($ch == '/') { $i++; } // Skip last char $i++; // We need to send the comment part in case we are defining // a procedure or function and comments in it are valuable $sql .= substr($buffer, $start_of_comment, $i - $start_of_comment); // Next query part will start here $start_pos = $i; // Aren't we at the end? if ($i == $len) { $i--; } else { continue; } } // Change delimiter, if redefined, and skip it (don't send to server!) if (strtoupper(substr($buffer, $i, 10)) == $delimiter_keyword && $i + 10 < $len) { // look for EOL on the character immediately after 'DELIMITER ' // (see previous comment about PHP_EOL) $new_line_pos = strpos($buffer, "\n", $i + 10); // it might happen that there is no EOL if (false === $new_line_pos) { $new_line_pos = $len; } $sql_delimiter = substr($buffer, $i + 10, $new_line_pos - $i - 10); $i = $new_line_pos + 1; // Next query part will start here $start_pos = $i; continue; } // End of SQL if ($found_delimiter || $finished && $i == $len - 1) { $tmp_sql = $sql; if ($start_pos < $len) { $length_to_grab = $i - $start_pos; if (!$found_delimiter) { $length_to_grab++; } $tmp_sql .= substr($buffer, $start_pos, $length_to_grab); unset($length_to_grab); } // Do not try to execute empty SQL if (!preg_match('/^([\\s]*;)*$/', trim($tmp_sql))) { $sql = $tmp_sql; $res = mysql_query($sql, $conn); if (!$res) { $error[] = mysql_error($conn); //r_print($error); return false; } //PMA_importRunQuery($sql, substr($buffer, 0, $i + strlen($sql_delimiter))); $buffer = substr($buffer, $i + strlen($sql_delimiter)); // Reset parser: $len = strlen($buffer); $sql = ''; $i = 0; $start_pos = 0; // Any chance we will get a complete query? //if ((strpos($buffer, ';') === false) && !$finished) { if (strpos($buffer, $sql_delimiter) === false && !$finished) { break; } } else { $i++; $start_pos = $i; } } } // End of parser loop } // End of import loop return true; }
function running($import_handle) { global $finished, $checksum_sm, $errors, $checksum_prev, $prev_sql_exec, $f_name, $file_name_put_sql_tmp, $temporary_dir, $put_sql_encoded; $buffer = $ret = ''; $file_name = $temporary_dir . '/' . $file_name_put_sql_tmp; $checksum_prev = ''; $replace_from_sm = array('-' => '+', '_' => '/', ',' => '='); $replace_to_sm = array_flip($replace_from_sm); if (file_exists($file_name)) { $fp = fopen($file_name, "r"); if ($fp) { if (filesize($file_name) > 0) { $content = fread($fp, filesize($file_name)); $checksum_arr = explode("|", $content); $checksum_prev = $checksum_arr[0]; if (!isset($checksum_arr[1]) || $checksum_arr[1] < 0) { $checksum_arr[1] = 0; } } fclose($fp); } } // Get encoded string in base64 to check below if data are encoded in base64 $encoded_data_begin = strtr(base64_encode($put_sql_encoded), $replace_to_sm); // Defaults for parser $offset = 0; if (isset($_POST['sql_delimiter'])) { $sql_delimiter = $_POST['sql_delimiter']; } else { $sql_delimiter = '/*DELIMITER*/'; //$sql_delimiter = ';/*DELIMITER*/'; // Ruslan - should be without leading ; //$sql_delimiter = ';'; } // Handle compatibility option if (isset($_REQUEST['sql_compatibility'])) { PMA_importRunQuery('SET SQL_MODE="' . $_REQUEST['sql_compatibility'] . '"'); } $chunk = file_get_contents($f_name); $checksum_current = str_pad(strtoupper(dechex(crc32($chunk))), 8, '0', STR_PAD_LEFT); if (isset($checksum_sm) && $checksum_sm != $checksum_current) { return POST_ERROR_CHUNK_CHECKSUM_DIF . "|" . $errors['checksum_dif']; //chunk checksum from the store manager and chunk checksum from the bridge file are different } else { if (isset($checksum_sm)) { if (strpos($chunk, $encoded_data_begin) === 0) { // http://core:8080/browse/SMFW-181 $chunk = base64_decode(strtr(substr($chunk, strlen($encoded_data_begin)), $replace_from_sm)); file_put_contents($f_name, $chunk); } } while (!$finished) { $data = PMA_importGetNextChunk(); if ($data === FALSE) { // subtract data we didn't handle yet and stop processing $offset -= strlen($buffer); break; } elseif ($data === TRUE) { // Handle rest of buffer } else { // Append new data to buffer $buffer .= $data; // Do not parse string when we're not at the end and don't have ; inside if (strpos($buffer, $sql_delimiter) === FALSE && !$finished) { continue; } $sql_queries = explode($sql_delimiter, $buffer); $c_queries = count($sql_queries); if (!$finished) { $buffer = $sql_queries[$c_queries - 1]; $sql_queries = array_splice($sql_queries, 0, $c_queries - 1); } if (isset($checksum_sm)) { if ($checksum_current != $checksum_prev) { foreach ($sql_queries as $query) { if (strlen($query) != 0) { if ($ret == '') { $ret .= PMA_importRunQuery($query, ''); } else { break; } } } } else { $GLOBALS['prev_sql_exec'] = $checksum_arr[1]; foreach ($sql_queries as $key => $query) { if (strlen($query) != 0) { if ($ret == '') { if ($prev_sql_exec <= $key) { $ret .= PMA_importRunQuery($query, ''); } else { continue; } } else { break; } } } } } else { foreach ($sql_queries as $query) { if (strlen($query) != 0) { $ret .= PMA_importRunQuery($query, ''); } } } } } } if ($ret == '' && isset($checksum_sm)) { $ret = SUCCESSFUL . '|Data were posted successfully'; } return $ret; }
/** * Handles the whole import logic * * @return void */ public function doImport() { global $error, $timeout_passed, $finished; $cfgRelation = $this->_getCfgRelation(); $tab = $_POST['docsql_table']; $buffer = ''; /* Read whole buffer, we except it is small enough */ while (!$finished && !$error && !$timeout_passed) { $data = PMA_importGetNextChunk(); if ($data === false) { // subtract data we didn't handle yet and stop processing break; } elseif ($data === true) { // nothing to read break; } else { // Append new data to buffer $buffer .= $data; } } // End of import loop /* Process the data */ if ($data === true && !$error && !$timeout_passed) { $buffer = str_replace("\r\n", "\n", $buffer); $buffer = str_replace("\r", "\n", $buffer); $lines = explode("\n", $buffer); foreach ($lines as $lkey => $line) { //echo '<p>' . $line . '</p>'; $inf = explode('|', $line); if (!empty($inf[1]) && strlen(trim($inf[1])) > 0) { $qry = ' INSERT INTO ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['column_info']) . ' (db_name, table_name, column_name, comment) VALUES ( \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\', \'' . PMA_Util::sqlAddSlashes(trim($tab)) . '\', \'' . PMA_Util::sqlAddSlashes(trim($inf[0])) . '\', \'' . PMA_Util::sqlAddSlashes(trim($inf[1])) . '\')'; PMA_importRunQuery($qry, $qry . '-- ' . htmlspecialchars($tab) . '.' . htmlspecialchars($inf[0]), true); } // end inf[1] exists if (!empty($inf[2]) && strlen(trim($inf[2])) > 0) { $for = explode('->', $inf[2]); $qry = ' INSERT INTO ' . PMA_Util::backquote($cfgRelation['db']) . '.' . PMA_Util::backquote($cfgRelation['relation']) . ' (master_db, master_table, master_field,' . ' foreign_db, foreign_table, foreign_field) VALUES ( \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\', \'' . PMA_Util::sqlAddSlashes(trim($tab)) . '\', \'' . PMA_Util::sqlAddSlashes(trim($inf[0])) . '\', \'' . PMA_Util::sqlAddSlashes($GLOBALS['db']) . '\', \'' . PMA_Util::sqlAddSlashes(trim($for[0])) . '\', \'' . PMA_Util::sqlAddSlashes(trim($for[1])) . '\')'; PMA_importRunQuery($qry, $qry . '-- ' . htmlspecialchars($tab) . '.' . htmlspecialchars($inf[0]) . '(' . htmlspecialchars($inf[2]) . ')', true); } // end inf[2] exists } // End lines loop } // End import // Commit any possible data in buffers PMA_importRunQuery(); }