Merge pull request #13834 from mauriciofauth/display-import
Refactor PhpMyAdmin\Display\Import class
This commit is contained in:
commit
ed396da220
@ -38,7 +38,7 @@ list(
|
||||
|
||||
$response = Response::getInstance();
|
||||
$response->addHTML(
|
||||
Import::getImportDisplay(
|
||||
Import::get(
|
||||
'database', $db, $table, $max_upload_size
|
||||
)
|
||||
);
|
||||
|
||||
@ -7,17 +7,12 @@
|
||||
*/
|
||||
namespace PhpMyAdmin\Display;
|
||||
|
||||
use PhpMyAdmin\Charsets;
|
||||
use PhpMyAdmin\Core;
|
||||
use PhpMyAdmin\Display\ImportAjax;
|
||||
use PhpMyAdmin\Encoding;
|
||||
use PhpMyAdmin\Message;
|
||||
use PhpMyAdmin\Plugins;
|
||||
use PhpMyAdmin\Plugins\ImportPlugin;
|
||||
use PhpMyAdmin\Sanitize;
|
||||
use PhpMyAdmin\Template;
|
||||
use PhpMyAdmin\Url;
|
||||
use PhpMyAdmin\Util;
|
||||
|
||||
/**
|
||||
* PhpMyAdmin\Display\Import class
|
||||
@ -26,573 +21,36 @@ use PhpMyAdmin\Util;
|
||||
*/
|
||||
class Import
|
||||
{
|
||||
/**
|
||||
* Prints Html For Display Import Hidden Input
|
||||
*
|
||||
* @param String $import_type Import type: server, database, table
|
||||
* @param String $db Selected DB
|
||||
* @param String $table Selected Table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForHiddenInputs($import_type, $db, $table)
|
||||
{
|
||||
$html = '';
|
||||
if ($import_type == 'server') {
|
||||
$html .= Url::getHiddenInputs('', '', 1);
|
||||
} elseif ($import_type == 'database') {
|
||||
$html .= Url::getHiddenInputs($db, '', 1);
|
||||
} else {
|
||||
$html .= Url::getHiddenInputs($db, $table, 1);
|
||||
}
|
||||
$html .= ' <input type="hidden" name="import_type" value="'
|
||||
. $import_type . '" />' . "\n";
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Import Javascript
|
||||
*
|
||||
* @param int $upload_id The selected upload id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportJs($upload_id)
|
||||
{
|
||||
global $SESSION_KEY;
|
||||
$html = '';
|
||||
$html .= '<script type="text/javascript">';
|
||||
$html .= ' //<![CDATA[';
|
||||
//with "\n", so that the following lines won't be commented out by //<![CDATA[
|
||||
$html .= "\n";
|
||||
$html .= ' $( function() {';
|
||||
// add event when user click on "Go" button
|
||||
$html .= ' $("#buttonGo").bind("click", function() {';
|
||||
// hide form
|
||||
$html .= ' $("#upload_form_form").css("display", "none");';
|
||||
|
||||
if ($_SESSION[$SESSION_KEY]["handler"] != 'PhpMyAdmin\Plugins\Import\Upload\UploadNoplugin') {
|
||||
|
||||
$html .= self::getHtmlForImportWithPlugin($upload_id);
|
||||
|
||||
} else { // no plugin available
|
||||
$image_tag = '<img src="' . $GLOBALS['pmaThemeImage']
|
||||
. 'ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> '
|
||||
. Sanitize::jsFormat(
|
||||
__(
|
||||
'Please be patient, the file is being uploaded. '
|
||||
. 'Details about the upload are not available.'
|
||||
),
|
||||
false
|
||||
) . Util::showDocu('faq', 'faq2-9');
|
||||
$html .= " $('#upload_form_status_info').html('" . $image_tag . "');";
|
||||
$html .= ' $("#upload_form_status").css("display", "none");';
|
||||
} // else
|
||||
|
||||
// onclick
|
||||
$html .= ' });';
|
||||
// domready
|
||||
$html .= ' });';
|
||||
$html .= ' //]]>';
|
||||
//with "\n", so that the following lines won't be commented out by //]]>
|
||||
$html .= "\n";
|
||||
$html .= '</script>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Export options
|
||||
*
|
||||
* @param String $import_type Import type: server, database, table
|
||||
* @param String $db Selected DB
|
||||
* @param String $table Selected Table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptions($import_type, $db, $table)
|
||||
{
|
||||
$html = ' <div class="exportoptions" id="header">';
|
||||
$html .= ' <h2>';
|
||||
$html .= Util::getImage('b_import.png', __('Import'));
|
||||
|
||||
if ($import_type == 'server') {
|
||||
$html .= __('Importing into the current server');
|
||||
} elseif ($import_type == 'database') {
|
||||
$import_str = sprintf(
|
||||
__('Importing into the database "%s"'),
|
||||
htmlspecialchars($db)
|
||||
);
|
||||
$html .= $import_str;
|
||||
} else {
|
||||
$import_str = sprintf(
|
||||
__('Importing into the table "%s"'),
|
||||
htmlspecialchars($table)
|
||||
);
|
||||
$html .= $import_str;
|
||||
}
|
||||
$html .= ' </h2>';
|
||||
$html .= ' </div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : Compressions
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportCompressions()
|
||||
{
|
||||
global $cfg;
|
||||
$html = '';
|
||||
// zip, gzip and bzip2 encode features
|
||||
$compressions = array();
|
||||
|
||||
if ($cfg['GZipDump'] && @function_exists('gzopen')) {
|
||||
$compressions[] = 'gzip';
|
||||
}
|
||||
if ($cfg['BZipDump'] && @function_exists('bzopen')) {
|
||||
$compressions[] = 'bzip2';
|
||||
}
|
||||
if ($cfg['ZipDump'] && @function_exists('zip_open')) {
|
||||
$compressions[] = 'zip';
|
||||
}
|
||||
// We don't have show anything about compression, when no supported
|
||||
if ($compressions != array()) {
|
||||
$html .= '<div class="formelementrow" id="compression_info">';
|
||||
$compress_str = sprintf(
|
||||
__('File may be compressed (%s) or uncompressed.'),
|
||||
implode(", ", $compressions)
|
||||
);
|
||||
$html .= $compress_str;
|
||||
$html .= '<br />';
|
||||
$html .= __(
|
||||
'A compressed file\'s name must end in <b>.[format].[compression]</b>. '
|
||||
. 'Example: <b>.sql.zip</b>'
|
||||
);
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import charset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportCharset()
|
||||
{
|
||||
global $cfg;
|
||||
$html = ' <div class="formelementrow" id="charaset_of_file">';
|
||||
// charset of file
|
||||
if (Encoding::isSupported()) {
|
||||
$html .= '<label for="charset_of_file">' . __('Character set of the file:')
|
||||
. '</label>';
|
||||
$html .= '<select id="charset_of_file" name="charset_of_file" size="1">';
|
||||
foreach (Encoding::listEncodings() as $temp_charset) {
|
||||
$html .= '<option value="' . htmlentities($temp_charset) . '"';
|
||||
if ((empty($cfg['Import']['charset']) && $temp_charset == 'utf-8')
|
||||
|| $temp_charset == $cfg['Import']['charset']
|
||||
) {
|
||||
$html .= ' selected="selected"';
|
||||
}
|
||||
$html .= '>' . htmlentities($temp_charset) . '</option>';
|
||||
}
|
||||
$html .= ' </select><br />';
|
||||
} else {
|
||||
$html .= '<label for="charset_of_file">' . __('Character set of the file:')
|
||||
. '</label>' . "\n";
|
||||
$html .= Charsets::getCharsetDropdownBox(
|
||||
$GLOBALS['dbi'],
|
||||
$GLOBALS['cfg']['Server']['DisableIS'],
|
||||
'charset_of_file',
|
||||
'charset_of_file',
|
||||
'utf8',
|
||||
false
|
||||
);
|
||||
} // end if (recoding)
|
||||
|
||||
$html .= ' </div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : file property
|
||||
*
|
||||
* @param int $max_upload_size Max upload size
|
||||
* @param ImportPlugin[] $import_list import list
|
||||
* @param String $local_import_file from upload directory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptionsFile(
|
||||
$max_upload_size, $import_list, $local_import_file
|
||||
) {
|
||||
global $cfg;
|
||||
$html = ' <div class="importoptions">';
|
||||
$html .= ' <h3>' . __('File to import:') . '</h3>';
|
||||
$html .= self::getHtmlForImportCompressions();
|
||||
$html .= ' <div class="formelementrow" id="upload_form">';
|
||||
|
||||
if ($GLOBALS['is_upload'] && !empty($cfg['UploadDir'])) {
|
||||
$html .= ' <ul>';
|
||||
$html .= ' <li>';
|
||||
$html .= ' <input type="radio" name="file_location" '
|
||||
. 'id="radio_import_file" required="required" />';
|
||||
$html .= Util::getBrowseUploadFileBlock($max_upload_size);
|
||||
$html .= '<br />' . __('You may also drag and drop a file on any page.');
|
||||
$html .= ' </li>';
|
||||
$html .= ' <li>';
|
||||
$html .= ' <input type="radio" name="file_location" '
|
||||
. 'id="radio_local_import_file"';
|
||||
if (! empty($GLOBALS['timeout_passed'])
|
||||
&& ! empty($local_import_file)
|
||||
) {
|
||||
$html .= ' checked="checked"';
|
||||
}
|
||||
$html .= ' />';
|
||||
$html .= Util::getSelectUploadFileBlock(
|
||||
$import_list,
|
||||
$cfg['UploadDir']
|
||||
);
|
||||
$html .= ' </li>';
|
||||
$html .= ' </ul>';
|
||||
|
||||
} elseif ($GLOBALS['is_upload']) {
|
||||
$html .= Util::getBrowseUploadFileBlock($max_upload_size);
|
||||
$html .= '<br />' . __('You may also drag and drop a file on any page.');
|
||||
} elseif (!$GLOBALS['is_upload']) {
|
||||
$html .= Message::notice(
|
||||
__('File uploads are not allowed on this server.')
|
||||
)->getDisplay();
|
||||
} elseif (!empty($cfg['UploadDir'])) {
|
||||
$html .= Util::getSelectUploadFileBlock(
|
||||
$import_list,
|
||||
$cfg['UploadDir']
|
||||
);
|
||||
} // end if (web-server upload directory)
|
||||
|
||||
$html .= ' </div>';
|
||||
$html .= self::getHtmlForImportCharset();
|
||||
$html .= ' </div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : Partial Import
|
||||
*
|
||||
* @param String $timeout_passed timeout passed
|
||||
* @param String $offset timeout offset
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptionsPartialImport($timeout_passed, $offset)
|
||||
{
|
||||
return Template::get('display/import/partial_import_option')->render([
|
||||
'timeout_passed' => isset($timeout_passed) ? $timeout_passed : null,
|
||||
'offset' => $offset,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : Other
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptionsOther()
|
||||
{
|
||||
return Template::get('display/import/other_option')->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : Format
|
||||
*
|
||||
* @param ImportPlugin[] $importList import list
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptionsFormat($importList)
|
||||
{
|
||||
return Template::get('display/import/format_option')->render([
|
||||
'import_list' => $importList,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import options : submit
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportOptionsSubmit()
|
||||
{
|
||||
$html = ' <div class="importoptions" id="submit">';
|
||||
$html .= ' <input type="submit" value="' . __('Go') . '" id="buttonGo" />';
|
||||
$html .= ' </div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints Html For Display Import
|
||||
*
|
||||
* @param int $upload_id The selected upload id
|
||||
* @param String $import_type Import type: server, database, table
|
||||
* @param String $db Selected DB
|
||||
* @param String $table Selected Table
|
||||
* @param int $max_upload_size Max upload size
|
||||
* @param ImportPlugin[] $import_list Import list
|
||||
* @param String $timeout_passed Timeout passed
|
||||
* @param String $offset Timeout offset
|
||||
* @param String $local_import_file from upload directory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImport(
|
||||
$upload_id, $import_type, $db, $table,
|
||||
$max_upload_size, $import_list, $timeout_passed, $offset, $local_import_file
|
||||
) {
|
||||
global $SESSION_KEY;
|
||||
$html = '';
|
||||
$html .= '<iframe id="import_upload_iframe" name="import_upload_iframe" '
|
||||
. 'width="1" height="1" class="hide"></iframe>';
|
||||
$html .= '<div id="import_form_status" class="hide"></div>';
|
||||
$html .= '<div id="importmain">';
|
||||
$html .= ' <img src="' . $GLOBALS['pmaThemeImage'] . 'ajax_clock_small.gif" '
|
||||
. 'width="16" height="16" alt="ajax clock" class="hide" />';
|
||||
|
||||
$html .= self::getHtmlForImportJs($upload_id);
|
||||
|
||||
$html .= ' <form id="import_file_form" action="import.php" method="post" '
|
||||
. 'enctype="multipart/form-data"';
|
||||
$html .= ' name="import"';
|
||||
if ($_SESSION[$SESSION_KEY]["handler"] != 'PhpMyAdmin\Plugins\Import\Upload\UploadNoplugin') {
|
||||
$html .= ' target="import_upload_iframe"';
|
||||
}
|
||||
$html .= ' class="ajax"';
|
||||
$html .= '>';
|
||||
$html .= ' <input type="hidden" name="';
|
||||
$html .= $_SESSION[$SESSION_KEY]['handler']::getIdKey();
|
||||
$html .= '" value="' . $upload_id . '" />';
|
||||
|
||||
$html .= self::getHtmlForHiddenInputs($import_type, $db, $table);
|
||||
|
||||
$html .= self::getHtmlForImportOptions($import_type, $db, $table);
|
||||
|
||||
$html .= self::getHtmlForImportOptionsFile(
|
||||
$max_upload_size, $import_list, $local_import_file
|
||||
);
|
||||
|
||||
$html .= self::getHtmlForImportOptionsPartialImport($timeout_passed, $offset);
|
||||
|
||||
$html .= self::getHtmlForImportOptionsOther();
|
||||
|
||||
$html .= self::getHtmlForImportOptionsFormat($import_list);
|
||||
|
||||
$html .= self::getHtmlForImportOptionsSubmit();
|
||||
|
||||
$html .= '</form>';
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints javascript for upload with plugin, upload process bar
|
||||
*
|
||||
* @param int $upload_id The selected upload id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getHtmlForImportWithPlugin($upload_id)
|
||||
{
|
||||
//some variable for javascript
|
||||
$ajax_url = "import_status.php?id=" . $upload_id . "&"
|
||||
. Url::getCommonRaw(array('import_status'=>1));
|
||||
$promot_str = Sanitize::jsFormat(
|
||||
__(
|
||||
'The file being uploaded is probably larger than '
|
||||
. 'the maximum allowed size or this is a known bug in webkit '
|
||||
. 'based (Safari, Google Chrome, Arora etc.) browsers.'
|
||||
),
|
||||
false
|
||||
);
|
||||
$statustext_str = Sanitize::escapeJsString(__('%s of %s'));
|
||||
$upload_str = Sanitize::jsFormat(__('Uploading your import file…'), false);
|
||||
$second_str = Sanitize::jsFormat(__('%s/sec.'), false);
|
||||
$remaining_min = Sanitize::jsFormat(__('About %MIN min. %SEC sec. remaining.'), false);
|
||||
$remaining_second = Sanitize::jsFormat(__('About %SEC sec. remaining.'), false);
|
||||
$processed_str = Sanitize::jsFormat(
|
||||
__('The file is being processed, please be patient.'),
|
||||
false
|
||||
);
|
||||
$import_url = Url::getCommonRaw(array('import_status'=>1));
|
||||
|
||||
//start output
|
||||
$html = 'var finished = false; ';
|
||||
$html .= 'var percent = 0.0; ';
|
||||
$html .= 'var total = 0; ';
|
||||
$html .= 'var complete = 0; ';
|
||||
$html .= 'var original_title = '
|
||||
. 'parent && parent.document ? parent.document.title : false; ';
|
||||
$html .= 'var import_start; ';
|
||||
|
||||
$html .= 'var perform_upload = function () { ';
|
||||
$html .= 'new $.getJSON( ';
|
||||
$html .= ' "' . $ajax_url . '", ';
|
||||
$html .= ' {}, ';
|
||||
$html .= ' function(response) { ';
|
||||
$html .= ' finished = response.finished; ';
|
||||
$html .= ' percent = response.percent; ';
|
||||
$html .= ' total = response.total; ';
|
||||
$html .= ' complete = response.complete; ';
|
||||
|
||||
$html .= ' if (total==0 && complete==0 && percent==0) { ';
|
||||
$img_tag = '<img src="' . $GLOBALS['pmaThemeImage'] . 'ajax_clock_small.gif"';
|
||||
$html .= ' $("#upload_form_status_info").html(\''
|
||||
. $img_tag . ' width="16" height="16" alt="ajax clock" /> '
|
||||
. $promot_str . '\'); ';
|
||||
$html .= ' $("#upload_form_status").css("display", "none"); ';
|
||||
$html .= ' } else { ';
|
||||
$html .= ' var now = new Date(); ';
|
||||
$html .= ' now = Date.UTC( ';
|
||||
$html .= ' now.getFullYear(), ';
|
||||
$html .= ' now.getMonth(), ';
|
||||
$html .= ' now.getDate(), ';
|
||||
$html .= ' now.getHours(), ';
|
||||
$html .= ' now.getMinutes(), ';
|
||||
$html .= ' now.getSeconds()) ';
|
||||
$html .= ' + now.getMilliseconds() - 1000; ';
|
||||
$html .= ' var statustext = PMA_sprintf(';
|
||||
$html .= ' "' . $statustext_str . '", ';
|
||||
$html .= ' formatBytes( ';
|
||||
$html .= ' complete, 1, PMA_messages.strDecimalSeparator';
|
||||
$html .= ' ), ';
|
||||
$html .= ' formatBytes(';
|
||||
$html .= ' total, 1, PMA_messages.strDecimalSeparator';
|
||||
$html .= ' ) ';
|
||||
$html .= ' ); ';
|
||||
|
||||
$html .= ' if ($("#importmain").is(":visible")) { ';
|
||||
// show progress UI
|
||||
$html .= ' $("#importmain").hide(); ';
|
||||
$html .= ' $("#import_form_status") ';
|
||||
$html .= ' .html(\'<div class="upload_progress">'
|
||||
. '<div class="upload_progress_bar_outer"><div class="percentage">'
|
||||
. '</div><div id="status" class="upload_progress_bar_inner">'
|
||||
. '<div class="percentage"></div></div></div><div>'
|
||||
. '<img src="' . $GLOBALS['pmaThemeImage']
|
||||
. 'ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> '
|
||||
. $upload_str . '</div><div id="statustext"></div></div>\') ';
|
||||
$html .= ' .show(); ';
|
||||
$html .= ' import_start = now; ';
|
||||
$html .= ' } ';
|
||||
$html .= ' else if (percent > 9 || complete > 2000000) { ';
|
||||
// calculate estimated time
|
||||
$html .= ' var used_time = now - import_start; ';
|
||||
$html .= ' var seconds = '
|
||||
. 'parseInt(((total - complete) / complete) * used_time / 1000); ';
|
||||
$html .= ' var speed = PMA_sprintf("' . $second_str . '"';
|
||||
$html .= ' , formatBytes(complete / used_time * 1000, 1,'
|
||||
. ' PMA_messages.strDecimalSeparator)); ';
|
||||
|
||||
$html .= ' var minutes = parseInt(seconds / 60); ';
|
||||
$html .= ' seconds %= 60; ';
|
||||
$html .= ' var estimated_time; ';
|
||||
$html .= ' if (minutes > 0) { ';
|
||||
$html .= ' estimated_time = "' . $remaining_min . '"';
|
||||
$html .= ' .replace("%MIN", minutes)';
|
||||
$html .= ' .replace("%SEC", seconds); ';
|
||||
$html .= ' } ';
|
||||
$html .= ' else { ';
|
||||
$html .= ' estimated_time = "' . $remaining_second . '"';
|
||||
$html .= ' .replace("%SEC", seconds); ';
|
||||
$html .= ' } ';
|
||||
|
||||
$html .= ' statustext += "<br />" + speed + "<br /><br />" '
|
||||
. '+ estimated_time; ';
|
||||
$html .= ' } ';
|
||||
|
||||
$html .= ' var percent_str = Math.round(percent) + "%"; ';
|
||||
$html .= ' $("#status").animate({width: percent_str}, 150); ';
|
||||
$html .= ' $(".percentage").text(percent_str); ';
|
||||
|
||||
// show percent in window title
|
||||
$html .= ' if (original_title !== false) { ';
|
||||
$html .= ' parent.document.title ';
|
||||
$html .= ' = percent_str + " - " + original_title; ';
|
||||
$html .= ' } ';
|
||||
$html .= ' else { ';
|
||||
$html .= ' document.title ';
|
||||
$html .= ' = percent_str + " - " + original_title; ';
|
||||
$html .= ' } ';
|
||||
$html .= ' $("#statustext").html(statustext); ';
|
||||
$html .= ' } ';
|
||||
|
||||
$html .= ' if (finished == true) { ';
|
||||
$html .= ' if (original_title !== false) { ';
|
||||
$html .= ' parent.document.title = original_title; ';
|
||||
$html .= ' } ';
|
||||
$html .= ' else { ';
|
||||
$html .= ' document.title = original_title; ';
|
||||
$html .= ' } ';
|
||||
$html .= ' $("#importmain").hide(); ';
|
||||
// loads the message, either success or mysql error
|
||||
$html .= ' $("#import_form_status") ';
|
||||
$html .= ' .html(\'<img src="' . $GLOBALS['pmaThemeImage']
|
||||
. 'ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> '
|
||||
. $processed_str . '\')';
|
||||
$html .= ' .show(); ';
|
||||
$html .= ' $("#import_form_status").load("import_status.php?'
|
||||
. 'message=true&' . $import_url . '"); ';
|
||||
$html .= ' PMA_reloadNavigation(); ';
|
||||
|
||||
// if finished
|
||||
$html .= ' } ';
|
||||
$html .= ' else { ';
|
||||
$html .= ' setTimeout(perform_upload, 1000); ';
|
||||
$html .= ' } ';
|
||||
$html .= '}); ';
|
||||
$html .= '}; ';
|
||||
$html .= 'setTimeout(perform_upload, 1000); ';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets HTML to display import dialogs
|
||||
*
|
||||
* @param String $import_type Import type: server|database|table
|
||||
* @param String $db Selected DB
|
||||
* @param String $table Selected Table
|
||||
* @param int $max_upload_size Max upload size
|
||||
* @param string $importType Import type: server|database|table
|
||||
* @param string $db Selected DB
|
||||
* @param string $table Selected Table
|
||||
* @param int $maxUploadSize Max upload size
|
||||
*
|
||||
* @return string $html
|
||||
* @return string HTML
|
||||
*/
|
||||
public static function getImportDisplay($import_type, $db, $table, $max_upload_size)
|
||||
public static function get($importType, $db, $table, $maxUploadSize)
|
||||
{
|
||||
global $cfg;
|
||||
global $SESSION_KEY;
|
||||
|
||||
list(
|
||||
$SESSION_KEY,
|
||||
$upload_id,
|
||||
$uploadId,
|
||||
) = ImportAjax::uploadProgressSetup();
|
||||
|
||||
/* Scan for plugins */
|
||||
/* @var $import_list ImportPlugin[] */
|
||||
$import_list = Plugins::getPlugins(
|
||||
/* @var $importList \PhpMyAdmin\Plugins\ImportPlugin[] */
|
||||
$importList = Plugins::getPlugins(
|
||||
"import",
|
||||
'libraries/classes/Plugins/Import/',
|
||||
$import_type
|
||||
$importType
|
||||
);
|
||||
|
||||
/* Fail if we didn't find any plugin */
|
||||
if (empty($import_list)) {
|
||||
if (empty($importList)) {
|
||||
Message::error(
|
||||
__(
|
||||
'Could not load import plugins, please check your installation!'
|
||||
@ -605,26 +63,49 @@ class Import
|
||||
$offset = intval($_REQUEST['offset']);
|
||||
}
|
||||
if (isset($_REQUEST['timeout_passed'])) {
|
||||
$timeout_passed = $_REQUEST['timeout_passed'];
|
||||
$timeoutPassed = $_REQUEST['timeout_passed'];
|
||||
}
|
||||
|
||||
$local_import_file = '';
|
||||
$localImportFile = '';
|
||||
if (isset($_REQUEST['local_import_file'])) {
|
||||
$local_import_file = $_REQUEST['local_import_file'];
|
||||
$localImportFile = $_REQUEST['local_import_file'];
|
||||
}
|
||||
|
||||
$timeout_passed_str = isset($timeout_passed)? $timeout_passed : null;
|
||||
$offset_str = isset($offset)? $offset : null;
|
||||
return self::getHtmlForImport(
|
||||
$upload_id,
|
||||
$import_type,
|
||||
$db,
|
||||
$table,
|
||||
$max_upload_size,
|
||||
$import_list,
|
||||
$timeout_passed_str,
|
||||
$offset_str,
|
||||
$local_import_file
|
||||
);
|
||||
// zip, gzip and bzip2 encode features
|
||||
$compressions = array();
|
||||
if ($cfg['GZipDump'] && @function_exists('gzopen')) {
|
||||
$compressions[] = 'gzip';
|
||||
}
|
||||
if ($cfg['BZipDump'] && @function_exists('bzopen')) {
|
||||
$compressions[] = 'bzip2';
|
||||
}
|
||||
if ($cfg['ZipDump'] && @function_exists('zip_open')) {
|
||||
$compressions[] = 'zip';
|
||||
}
|
||||
|
||||
return Template::get('display/import/import')->render([
|
||||
'upload_id' => $uploadId,
|
||||
'handler' => $_SESSION[$SESSION_KEY]["handler"],
|
||||
'id_key' => $_SESSION[$SESSION_KEY]['handler']::getIdKey(),
|
||||
'pma_theme_image' => $GLOBALS['pmaThemeImage'],
|
||||
'import_type' => $importType,
|
||||
'db' => $db,
|
||||
'table' => $table,
|
||||
'max_upload_size' => $maxUploadSize,
|
||||
'import_list' => $importList,
|
||||
'local_import_file' => $localImportFile,
|
||||
'is_upload' => $GLOBALS['is_upload'],
|
||||
'upload_dir' => isset($cfg['UploadDir']) ? $cfg['UploadDir'] : null,
|
||||
'timeout_passed_global' => isset($GLOBALS['timeout_passed']) ? $GLOBALS['timeout_passed'] : null,
|
||||
'compressions' => $compressions,
|
||||
'is_encoding_supported' => Encoding::isSupported(),
|
||||
'encodings' => Encoding::listEncodings(),
|
||||
'import_charset' => isset($cfg['Import']['charset']) ? $cfg['Import']['charset'] : null,
|
||||
'dbi' => $GLOBALS['dbi'],
|
||||
'disable_is' => $cfg['Server']['DisableIS'],
|
||||
'timeout_passed' => isset($timeoutPassed) ? $timeoutPassed : null,
|
||||
'offset' => isset($offset) ? $offset : null,
|
||||
'can_convert_kanji' => Encoding::canConvertKanji(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,11 @@ class CharsetsExtension extends Twig_Extension
|
||||
'Charsets_getCollationDescr',
|
||||
'PhpMyAdmin\Charsets::getCollationDescr'
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Charsets_getCharsetDropdownBox',
|
||||
'PhpMyAdmin\Charsets::getCharsetDropdownBox',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Charsets_getCollationDropdownBox',
|
||||
'PhpMyAdmin\Charsets::getCollationDropdownBox',
|
||||
|
||||
@ -40,6 +40,11 @@ class UrlExtension extends Twig_Extension
|
||||
'PhpMyAdmin\Url::getCommon',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Url_getCommonRaw',
|
||||
'PhpMyAdmin\Url::getCommonRaw',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Url_link',
|
||||
'PhpMyAdmin\Core::linkURL'
|
||||
|
||||
@ -29,6 +29,11 @@ class UtilExtension extends Twig_Extension
|
||||
'Util_backquote',
|
||||
'PhpMyAdmin\Util::backquote'
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Util_getBrowseUploadFileBlock',
|
||||
'PhpMyAdmin\Util::getBrowseUploadFileBlock',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Util_convertBitDefaultValue',
|
||||
'PhpMyAdmin\Util::convertBitDefaultValue'
|
||||
@ -122,6 +127,11 @@ class UtilExtension extends Twig_Extension
|
||||
'PhpMyAdmin\Util::getRadioFields',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Util_getSelectUploadFileBlock',
|
||||
'PhpMyAdmin\Util::getSelectUploadFileBlock',
|
||||
array('is_safe' => array('html'))
|
||||
),
|
||||
new Twig_SimpleFunction(
|
||||
'Util_getScriptNameForOption',
|
||||
'PhpMyAdmin\Util::getScriptNameForOption',
|
||||
|
||||
@ -28,7 +28,7 @@ require 'libraries/server_common.inc.php';
|
||||
|
||||
$response = Response::getInstance();
|
||||
$response->addHTML(
|
||||
Import::getImportDisplay(
|
||||
Import::get(
|
||||
'server', $db, $table, $max_upload_size
|
||||
)
|
||||
);
|
||||
|
||||
@ -28,7 +28,7 @@ require_once 'libraries/tbl_common.inc.php';
|
||||
$url_query .= '&goto=tbl_import.php&back=tbl_import.php';
|
||||
|
||||
$response->addHTML(
|
||||
Import::getImportDisplay(
|
||||
Import::get(
|
||||
'table', $db, $table, $max_upload_size
|
||||
)
|
||||
);
|
||||
|
||||
26
templates/display/import/charset.twig
Normal file
26
templates/display/import/charset.twig
Normal file
@ -0,0 +1,26 @@
|
||||
<div class="formelementrow" id="charaset_of_file">
|
||||
{# Charset of file #}
|
||||
<label for="charset_of_file">{% trans 'Character set of the file:' %}</label>
|
||||
{% if is_encoding_supported %}
|
||||
<select id="charset_of_file" name="charset_of_file" size="1">
|
||||
{% for charset in encodings %}
|
||||
<option value="{{ charset }}"
|
||||
{% if (import_charset is empty and charset == 'utf-8')
|
||||
or charset == import_charset %}
|
||||
selected="selected"
|
||||
{% endif %}>
|
||||
{{ charset }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
{% else %}
|
||||
{{ Charsets_getCharsetDropdownBox(
|
||||
dbi,
|
||||
disable_is,
|
||||
'charset_of_file',
|
||||
'charset_of_file',
|
||||
'utf8',
|
||||
false
|
||||
) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
10
templates/display/import/compressions.twig
Normal file
10
templates/display/import/compressions.twig
Normal file
@ -0,0 +1,10 @@
|
||||
{# We don't have show anything about compression, when no supported #}
|
||||
{% if compressions is not empty %}
|
||||
<div class="formelementrow" id="compression_info">
|
||||
<p>
|
||||
{{ 'File may be compressed (%s) or uncompressed.'|trans|format(compressions|join(', ')) }}
|
||||
<br>
|
||||
{% trans 'A compressed file\'s name must end in <strong>.[format].[compression]</strong>. Example: <strong>.sql.zip</strong>' %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
44
templates/display/import/file_option.twig
Normal file
44
templates/display/import/file_option.twig
Normal file
@ -0,0 +1,44 @@
|
||||
<div class="importoptions">
|
||||
<h3>{% trans 'File to import:' %}</h3>
|
||||
{% include 'display/import/compressions.twig' with {
|
||||
'compressions': compressions
|
||||
} only %}
|
||||
<div class="formelementrow" id="upload_form">
|
||||
{% if is_upload and upload_dir is not empty %}
|
||||
<ul>
|
||||
<li>
|
||||
<input type="radio" name="file_location" id="radio_import_file" required="required" />
|
||||
{{ Util_getBrowseUploadFileBlock(max_upload_size) }}
|
||||
{% trans 'You may also drag and drop a file on any page.' %}
|
||||
</li>
|
||||
<li>
|
||||
<input type="radio" name="file_location" id="radio_local_import_file"
|
||||
{%- if timeout_passed_global is not empty and local_import_file is not empty %}
|
||||
checked="checked"
|
||||
{%- endif %} />
|
||||
{{ Util_getSelectUploadFileBlock(
|
||||
import_list,
|
||||
upload_dir
|
||||
) }}
|
||||
</li>
|
||||
</ul>
|
||||
{% elseif is_upload %}
|
||||
{{ Util_getBrowseUploadFileBlock(max_upload_size) }}
|
||||
<p>{% trans 'You may also drag and drop a file on any page.' %}</p>
|
||||
{% elseif not is_upload %}
|
||||
{{ Message_notice('File uploads are not allowed on this server.'|trans) }}
|
||||
{% elseif upload_dir is not empty %}
|
||||
{{ Util_getSelectUploadFileBlock(
|
||||
import_list,
|
||||
upload_dir
|
||||
) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% include 'display/import/charset.twig' with {
|
||||
'is_encoding_supported': is_encoding_supported,
|
||||
'encodings': encodings,
|
||||
'import_charset': import_charset,
|
||||
'dbi': dbi,
|
||||
'disable_is': disable_is
|
||||
} only %}
|
||||
</div>
|
||||
8
templates/display/import/hidden_inputs.twig
Normal file
8
templates/display/import/hidden_inputs.twig
Normal file
@ -0,0 +1,8 @@
|
||||
{% if import_type == 'server' %}
|
||||
{{ Url_getHiddenInputs('', '', 1) }}
|
||||
{% elseif import_type == 'database' %}
|
||||
{{ Url_getHiddenInputs(db, '', 1) }}
|
||||
{% else %}
|
||||
{{ Url_getHiddenInputs(db, table, 1) }}
|
||||
{% endif %}
|
||||
<input type="hidden" name="import_type" value="{{ import_type }}" />
|
||||
64
templates/display/import/import.twig
Normal file
64
templates/display/import/import.twig
Normal file
@ -0,0 +1,64 @@
|
||||
<iframe id="import_upload_iframe" name="import_upload_iframe" width="1" height="1" class="hide"></iframe>
|
||||
<div id="import_form_status" class="hide"></div>
|
||||
<div id="importmain">
|
||||
<img src="{{ pma_theme_image }}ajax_clock_small.gif" width="16" height="16" alt="ajax clock" class="hide" />
|
||||
|
||||
{% include 'display/import/javascript.twig' with {
|
||||
'upload_id': upload_id,
|
||||
'handler': handler,
|
||||
'pma_theme_image': pma_theme_image
|
||||
} only %}
|
||||
|
||||
<form id="import_file_form"
|
||||
action="import.php"
|
||||
method="post"
|
||||
enctype="multipart/form-data"
|
||||
name="import"
|
||||
class="ajax"
|
||||
{%- if handler != 'PhpMyAdmin\\Plugins\\Import\\Upload\\UploadNoplugin' %}
|
||||
target="import_upload_iframe"
|
||||
{%- endif %}>
|
||||
<input type="hidden" name="{{ id_key }}" value="{{ upload_id }}" />
|
||||
|
||||
{% include 'display/import/hidden_inputs.twig' with {
|
||||
'import_type': import_type,
|
||||
'db': db,
|
||||
'table': table
|
||||
} only %}
|
||||
|
||||
{% include 'display/import/options.twig' with {
|
||||
'import_type': import_type,
|
||||
'db': db,
|
||||
'table': table
|
||||
} only %}
|
||||
|
||||
{% include 'display/import/file_option.twig' with {
|
||||
'max_upload_size': max_upload_size,
|
||||
'import_list': import_list,
|
||||
'local_import_file': local_import_file,
|
||||
'is_upload': is_upload,
|
||||
'upload_dir': upload_dir,
|
||||
'timeout_passed_global': timeout_passed_global,
|
||||
'compressions': compressions,
|
||||
'is_encoding_supported': is_encoding_supported,
|
||||
'encodings': encodings,
|
||||
'import_charset': import_charset,
|
||||
'dbi': dbi,
|
||||
'disable_is': disable_is
|
||||
} only %}
|
||||
|
||||
{% include 'display/import/partial_import_option.twig' with {
|
||||
'timeout_passed': timeout_passed,
|
||||
'offset': offset
|
||||
} only %}
|
||||
|
||||
{% include 'display/import/other_option.twig' only %}
|
||||
|
||||
{% include 'display/import/format_option.twig' with {
|
||||
'import_list': import_list,
|
||||
'can_convert_kanji': can_convert_kanji
|
||||
} only %}
|
||||
|
||||
{% include 'display/import/submit_option.twig' only %}
|
||||
</form>
|
||||
</div>
|
||||
31
templates/display/import/javascript.twig
Normal file
31
templates/display/import/javascript.twig
Normal file
@ -0,0 +1,31 @@
|
||||
<script type="text/javascript">
|
||||
//<![CDATA[
|
||||
$( function() {
|
||||
{# Add event when user click on "Go" button #}
|
||||
$("#buttonGo").bind("click", function() {
|
||||
{# Hide form #}
|
||||
$("#upload_form_form").css("display", "none");
|
||||
|
||||
{% if handler != 'PhpMyAdmin\\Plugins\\Import\\Upload\\UploadNoplugin' %}
|
||||
{% include 'display/import/with_plugin.twig' with {
|
||||
'upload_id': upload_id,
|
||||
'pma_theme_image': pma_theme_image
|
||||
} only %}
|
||||
{% else %}
|
||||
{# No plugin available #}
|
||||
{% set image_tag -%}
|
||||
<img src="{{ pma_theme_image -}}
|
||||
ajax_clock_small.gif" width="16" height="16" alt="ajax clock" />
|
||||
{{- Sanitize_jsFormat(
|
||||
'Please be patient, the file is being uploaded. Details about the upload are not available.'|trans,
|
||||
false
|
||||
) -}}
|
||||
{{- Util_showDocu('faq', 'faq2-9') -}}
|
||||
{%- endset %}
|
||||
$('#upload_form_status_info').html('{{ image_tag }}');
|
||||
$("#upload_form_status").css("display", "none");
|
||||
{% endif %}
|
||||
});
|
||||
});
|
||||
//]]>
|
||||
</script>
|
||||
12
templates/display/import/options.twig
Normal file
12
templates/display/import/options.twig
Normal file
@ -0,0 +1,12 @@
|
||||
<div class="exportoptions" id="header">
|
||||
<h2>
|
||||
{{ Util_getImage('b_import.png', 'Import'|trans) }}
|
||||
{% if import_type == 'server' %}
|
||||
{% trans 'Importing into the current server' %}
|
||||
{% elseif import_type == 'database' %}
|
||||
{{ 'Importing into the database "%s"'|trans|format(db) }}
|
||||
{% else %}
|
||||
{{ 'Importing into the table "%s"'|trans|format(table) }}
|
||||
{% endif %}
|
||||
</h2>
|
||||
</div>
|
||||
3
templates/display/import/submit_option.twig
Normal file
3
templates/display/import/submit_option.twig
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="importoptions" id="submit">
|
||||
<input type="submit" value="{% trans 'Go' %}" id="buttonGo" />
|
||||
</div>
|
||||
148
templates/display/import/with_plugin.twig
Normal file
148
templates/display/import/with_plugin.twig
Normal file
@ -0,0 +1,148 @@
|
||||
{# Some variable for javascript #}
|
||||
{% set ajax_url = 'import_status.php?id=' ~ upload_id ~ '&' ~ Url_getCommonRaw({
|
||||
'import_status': 1
|
||||
}) %}
|
||||
{% set promot_str = Sanitize_jsFormat(
|
||||
'The file being uploaded is probably larger than the maximum allowed size or this is a known bug in webkit based (Safari, Google Chrome, Arora etc.) browsers.'|trans,
|
||||
false
|
||||
) %}
|
||||
{% set statustext_str = Sanitize_escapeJsString('%s of %s'|trans) %}
|
||||
{% set second_str = Sanitize_jsFormat('%s/sec.'|trans, false) %}
|
||||
{% set remaining_min = Sanitize_jsFormat('About %MIN min. %SEC sec. remaining.'|trans, false) %}
|
||||
{% set remaining_second = Sanitize_jsFormat('About %SEC sec. remaining.'|trans, false) %}
|
||||
{% set processed_str = Sanitize_jsFormat(
|
||||
'The file is being processed, please be patient.'|trans,
|
||||
false
|
||||
) %}
|
||||
{% set import_url = Url_getCommonRaw({'import_status': 1}) %}
|
||||
|
||||
{% set upload_html %}
|
||||
{% spaceless %}
|
||||
<div class="upload_progress">
|
||||
<div class="upload_progress_bar_outer">
|
||||
<div class="percentage"></div>
|
||||
<div id="status" class="upload_progress_bar_inner">
|
||||
<div class="percentage"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<img src="{{ pma_theme_image }}ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> {{ Sanitize_jsFormat('Uploading your import file…'|trans, false) -}}
|
||||
</div>
|
||||
<div id="statustext"></div>
|
||||
</div>
|
||||
{% endspaceless %}
|
||||
{% endset %}
|
||||
|
||||
{# Start output #}
|
||||
var finished = false;
|
||||
var percent = 0.0;
|
||||
var total = 0;
|
||||
var complete = 0;
|
||||
var original_title = parent && parent.document ? parent.document.title : false;
|
||||
var import_start;
|
||||
|
||||
var perform_upload = function () {
|
||||
new $.getJSON(
|
||||
"{{ ajax_url|raw }}",
|
||||
{},
|
||||
function(response) {
|
||||
finished = response.finished;
|
||||
percent = response.percent;
|
||||
total = response.total;
|
||||
complete = response.complete;
|
||||
|
||||
if (total==0 && complete==0 && percent==0) {
|
||||
$("#upload_form_status_info").html('<img src="{{ pma_theme_image }}ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> {{ promot_str|raw }}');
|
||||
$("#upload_form_status").css("display", "none");
|
||||
} else {
|
||||
var now = new Date();
|
||||
now = Date.UTC(
|
||||
now.getFullYear(),
|
||||
now.getMonth(),
|
||||
now.getDate(),
|
||||
now.getHours(),
|
||||
now.getMinutes(),
|
||||
now.getSeconds())
|
||||
+ now.getMilliseconds() - 1000;
|
||||
var statustext = PMA_sprintf(
|
||||
"{{ statustext_str|raw }}",
|
||||
formatBytes(
|
||||
complete, 1, PMA_messages.strDecimalSeparator
|
||||
),
|
||||
formatBytes(
|
||||
total, 1, PMA_messages.strDecimalSeparator
|
||||
)
|
||||
);
|
||||
|
||||
if ($("#importmain").is(":visible")) {
|
||||
{# Show progress UI #}
|
||||
$("#importmain").hide();
|
||||
$("#import_form_status")
|
||||
.html('{{ upload_html|raw }}')
|
||||
.show();
|
||||
import_start = now;
|
||||
}
|
||||
else if (percent > 9 || complete > 2000000) {
|
||||
{# Calculate estimated time #}
|
||||
var used_time = now - import_start;
|
||||
var seconds = parseInt(((total - complete) / complete) * used_time / 1000);
|
||||
var speed = PMA_sprintf(
|
||||
"{{ second_str|raw }}",
|
||||
formatBytes(complete / used_time * 1000, 1, PMA_messages.strDecimalSeparator)
|
||||
);
|
||||
|
||||
var minutes = parseInt(seconds / 60);
|
||||
seconds %= 60;
|
||||
var estimated_time;
|
||||
if (minutes > 0) {
|
||||
estimated_time = "{{ remaining_min|raw }}"
|
||||
.replace("%MIN", minutes)
|
||||
.replace("%SEC", seconds);
|
||||
}
|
||||
else {
|
||||
estimated_time = "{{ remaining_second|raw }}"
|
||||
.replace("%SEC", seconds);
|
||||
}
|
||||
|
||||
statustext += "<br />" + speed + "<br /><br />" + estimated_time;
|
||||
}
|
||||
|
||||
var percent_str = Math.round(percent) + "%";
|
||||
$("#status").animate({width: percent_str}, 150);
|
||||
$(".percentage").text(percent_str);
|
||||
|
||||
{# Show percent in window title #}
|
||||
if (original_title !== false) {
|
||||
parent.document.title
|
||||
= percent_str + " - " + original_title;
|
||||
}
|
||||
else {
|
||||
document.title
|
||||
= percent_str + " - " + original_title;
|
||||
}
|
||||
$("#statustext").html(statustext);
|
||||
}
|
||||
|
||||
if (finished == true) {
|
||||
if (original_title !== false) {
|
||||
parent.document.title = original_title;
|
||||
}
|
||||
else {
|
||||
document.title = original_title;
|
||||
}
|
||||
$("#importmain").hide();
|
||||
{# Loads the message, either success or mysql error #}
|
||||
$("#import_form_status")
|
||||
.html('<img src="{{ pma_theme_image }}ajax_clock_small.gif" width="16" height="16" alt="ajax clock" /> {{ processed_str|raw }}')
|
||||
.show();
|
||||
$("#import_form_status").load("import_status.php?message=true&{{ import_url|raw }}");
|
||||
PMA_reloadNavigation();
|
||||
|
||||
{# If finished #}
|
||||
}
|
||||
else {
|
||||
setTimeout(perform_upload, 1000);
|
||||
}
|
||||
});
|
||||
};
|
||||
setTimeout(perform_upload, 1000);
|
||||
Loading…
Reference in New Issue
Block a user