View File Name : Export.php
'
. ' '
. '
'
// bottom back button
. $backButton
. $refreshButton
. '
'
. '' . "\n";
}
/**
* Computes the memory limit for export
*
* @return int the memory limit
*/
public function getMemoryLimit(): int
{
$memoryLimit = trim((string) ini_get('memory_limit'));
$memoryLimitNumber = (int) substr($memoryLimit, 0, -1);
$lowerLastChar = strtolower(substr($memoryLimit, -1));
// 2 MB as default
if (empty($memoryLimit) || $memoryLimit == '-1') {
$memoryLimit = 2 * 1024 * 1024;
} elseif ($lowerLastChar === 'm') {
$memoryLimit = $memoryLimitNumber * 1024 * 1024;
} elseif ($lowerLastChar === 'k') {
$memoryLimit = $memoryLimitNumber * 1024;
} elseif ($lowerLastChar === 'g') {
$memoryLimit = $memoryLimitNumber * 1024 * 1024 * 1024;
} else {
$memoryLimit = (int) $memoryLimit;
}
// Some of memory is needed for other things and as threshold.
// During export I had allocated (see memory_get_usage function)
// approx 1.2MB so this comes from that.
if ($memoryLimit > 1500000) {
$memoryLimit -= 1500000;
}
// Some memory is needed for compression, assume 1/3
$memoryLimit /= 8;
return $memoryLimit;
}
/**
* Returns the filename and MIME type for a compression and an export plugin
*
* @param ExportPlugin $exportPlugin the export plugin
* @param string $compression compression asked
* @param string $filename the filename
*
* @return string[] the filename and mime type
*/
public function getFinalFilenameAndMimetypeForFilename(
ExportPlugin $exportPlugin,
string $compression,
string $filename
): array {
// Grab basic dump extension and mime type
// Check if the user already added extension;
// get the substring where the extension would be if it was included
$requiredExtension = '.' . $exportPlugin->getProperties()->getExtension();
$extensionLength = mb_strlen($requiredExtension);
$userExtension = mb_substr($filename, -$extensionLength);
if (mb_strtolower($userExtension) != $requiredExtension) {
$filename .= $requiredExtension;
}
$mediaType = $exportPlugin->getProperties()->getMimeType();
// If dump is going to be compressed, set correct mime_type and add
// compression to extension
if ($compression === 'gzip') {
$filename .= '.gz';
$mediaType = 'application/x-gzip';
} elseif ($compression === 'zip') {
$filename .= '.zip';
$mediaType = 'application/zip';
}
return [
$filename,
$mediaType,
];
}
/**
* Return the filename and MIME type for export file
*
* @param string $exportType type of export
* @param string $rememberTemplate whether to remember template
* @param ExportPlugin $exportPlugin the export plugin
* @param string $compression compression asked
* @param string $filenameTemplate the filename template
*
* @return string[] the filename template and mime type
*/
public function getFilenameAndMimetype(
string $exportType,
string $rememberTemplate,
ExportPlugin $exportPlugin,
string $compression,
string $filenameTemplate
): array {
if ($exportType === 'server') {
if (! empty($rememberTemplate)) {
$GLOBALS['config']->setUserValue(
'pma_server_filename_template',
'Export/file_template_server',
$filenameTemplate
);
}
} elseif ($exportType === 'database') {
if (! empty($rememberTemplate)) {
$GLOBALS['config']->setUserValue(
'pma_db_filename_template',
'Export/file_template_database',
$filenameTemplate
);
}
} elseif ($exportType === 'raw') {
if (! empty($rememberTemplate)) {
$GLOBALS['config']->setUserValue(
'pma_raw_filename_template',
'Export/file_template_raw',
$filenameTemplate
);
}
} else {
if (! empty($rememberTemplate)) {
$GLOBALS['config']->setUserValue(
'pma_table_filename_template',
'Export/file_template_table',
$filenameTemplate
);
}
}
$filename = Util::expandUserString($filenameTemplate);
// remove dots in filename (coming from either the template or already
// part of the filename) to avoid a remote code execution vulnerability
$filename = Sanitize::sanitizeFilename($filename, true);
return $this->getFinalFilenameAndMimetypeForFilename($exportPlugin, $compression, $filename);
}
/**
* Open the export file
*
* @param string $filename the export filename
* @param bool $quickExport whether it's a quick export or not
*
* @return array the full save filename, possible message and the file handle
*/
public function openFile(string $filename, bool $quickExport): array
{
$fileHandle = null;
$message = '';
$doNotSaveItOver = true;
if (isset($_POST['quick_export_onserver_overwrite'])) {
$doNotSaveItOver = $_POST['quick_export_onserver_overwrite'] !== 'saveitover';
}
$saveFilename = Util::userDir((string) ($GLOBALS['cfg']['SaveDir'] ?? ''))
. preg_replace('@[/\\\\]@', '_', $filename);
if (
@file_exists($saveFilename)
&& ((! $quickExport && empty($_POST['onserver_overwrite']))
|| ($quickExport
&& $doNotSaveItOver))
) {
$message = Message::error(
__(
'File %s already exists on server, change filename or check overwrite option.'
)
);
$message->addParam($saveFilename);
} elseif (@is_file($saveFilename) && ! @is_writable($saveFilename)) {
$message = Message::error(
__(
'The web server does not have permission to save the file %s.'
)
);
$message->addParam($saveFilename);
} else {
$fileHandle = @fopen($saveFilename, 'w');
if ($fileHandle === false) {
$message = Message::error(
__(
'The web server does not have permission to save the file %s.'
)
);
$message->addParam($saveFilename);
}
}
return [
$saveFilename,
$message,
$fileHandle,
];
}
/**
* Close the export file
*
* @param resource $fileHandle the export file handle
* @param string $dumpBuffer the current dump buffer
* @param string $saveFilename the export filename
*
* @return Message a message object (or empty string)
*/
public function closeFile(
$fileHandle,
string $dumpBuffer,
string $saveFilename
): Message {
$writeResult = @fwrite($fileHandle, $dumpBuffer);
fclose($fileHandle);
// Here, use strlen rather than mb_strlen to get the length
// in bytes to compare against the number of bytes written.
if (strlen($dumpBuffer) > 0 && (! $writeResult || $writeResult != strlen($dumpBuffer))) {
$message = new Message(
__('Insufficient space to save the file %s.'),
Message::ERROR,
[$saveFilename]
);
} else {
$message = new Message(
__('Dump has been saved to file %s.'),
Message::SUCCESS,
[$saveFilename]
);
}
return $message;
}
/**
* Compress the export buffer
*
* @param array|string $dumpBuffer the current dump buffer
* @param string $compression the compression mode
* @param string $filename the filename
*
* @return array|string|bool
*/
public function compress($dumpBuffer, string $compression, string $filename)
{
if ($compression === 'zip' && function_exists('gzcompress')) {
$zipExtension = new ZipExtension();
$filename = substr($filename, 0, -4); // remove extension (.zip)
$dumpBuffer = $zipExtension->createFile($dumpBuffer, $filename);
} elseif ($compression === 'gzip' && $this->gzencodeNeeded() && is_string($dumpBuffer)) {
// without the optional parameter level because it bugs
$dumpBuffer = gzencode($dumpBuffer);
}
return $dumpBuffer;
}
/**
* Saves the dump buffer for a particular table in an array
* Used in separate files export
*
* @param string $objectName the name of current object to be stored
* @param bool $append optional boolean to append to an existing index or not
*/
public function saveObjectInBuffer(string $objectName, bool $append = false): void
{
if (! empty($this->dumpBuffer)) {
if ($append && isset($this->dumpBufferObjects[$objectName])) {
$this->dumpBufferObjects[$objectName] .= $this->dumpBuffer;
} else {
$this->dumpBufferObjects[$objectName] = $this->dumpBuffer;
}
}
// Re - initialize
$this->dumpBuffer = '';
$this->dumpBufferLength = 0;
}
/**
* Returns HTML containing the header for a displayed export
*
* @param string $exportType the export type
* @param string $db the database name
* @param string $table the table name
*
* @return string[] the generated HTML and back button
*/
public function getHtmlForDisplayedExportHeader(
string $exportType,
string $db,
string $table
): array {
$html = '
';
/**
* Displays a back button with all the $_POST data in the URL
* (store in a variable to also display after the textarea)
*/
$backButton = '
[ ' . __('Back') . ' ]
';
$html .= '
';
$html .= $backButton;
$refreshButton = '
';
$html .= $refreshButton
. '
'
. '