55954ba081
Generic: Repo Health / Access control (push) Successful in 1s
Universal: Auto Version Bump / Version Bump (push) Successful in 3s
Generic: Repo Health / Site Health (push) Has been skipped
Joomla: Extension CI / Release Readiness Check (pull_request) Failing after 4s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: Secret Scanning / Gitleaks Secret Scan (pull_request) Successful in 4s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 7s
Generic: Project CI / Lint & Validate (push) Successful in 42s
Generic: Project CI / Lint & Validate (pull_request) Successful in 42s
Universal: PR Check / Validate PR (pull_request) Failing after 38s
Joomla: Extension CI / Lint & Validate (pull_request) Failing after 44s
Generic: Project CI / Tests (push) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.2) (pull_request) Has been cancelled
Joomla: Extension CI / Tests (PHP 8.3) (pull_request) Has been cancelled
Joomla: Extension CI / PHPStan Analysis (pull_request) Has been cancelled
Joomla: Extension CI / Build RC Pre-Release (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (push) Has been cancelled
Generic: Repo Health / Repository health (push) Has been cancelled
Generic: Repo Health / Report Issues (push) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report Issues (pull_request) Has been cancelled
- DatabaseImporter: apply #__ prefix replacement on trailing statement (was missing for SQL not terminated by semicolon) - SteppedBackupEngine: remove unused DatabaseDumper instantiation - SteppedBackupEngine: fix misaligned indentation in stepDatabase()
127 lines
3.1 KiB
PHP
127 lines
3.1 KiB
PHP
<?php
|
|
|
|
/**
|
|
* @package MokoSuiteBackup
|
|
* @subpackage com_mokosuitebackup
|
|
* @author Moko Consulting <hello@mokoconsulting.tech>
|
|
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
|
* @license GNU General Public License version 3 or later; see LICENSE
|
|
*
|
|
* Imports a SQL dump file created by DatabaseDumper.
|
|
* Handles #__ prefix replacement, multi-statement execution,
|
|
* and DROP TABLE before CREATE TABLE for clean restores.
|
|
*/
|
|
|
|
namespace Joomla\Component\MokoSuiteBackup\Administrator\Engine;
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
use Joomla\CMS\Factory;
|
|
|
|
class DatabaseImporter
|
|
{
|
|
/**
|
|
* Import a SQL dump file into the database.
|
|
*
|
|
* @param string $sqlFile Absolute path to the SQL dump file
|
|
*
|
|
* @return int Number of statements executed
|
|
*
|
|
* @throws \RuntimeException On import failure
|
|
*/
|
|
public function import(string $sqlFile): int
|
|
{
|
|
if (!is_file($sqlFile) || !is_readable($sqlFile)) {
|
|
throw new \RuntimeException('SQL file not readable: ' . $sqlFile);
|
|
}
|
|
|
|
$db = Factory::getDbo();
|
|
$prefix = $db->getPrefix();
|
|
|
|
$handle = fopen($sqlFile, 'r');
|
|
|
|
if ($handle === false) {
|
|
throw new \RuntimeException('Cannot open SQL file: ' . $sqlFile);
|
|
}
|
|
|
|
$statementsExecuted = 0;
|
|
$currentStatement = '';
|
|
$inMultiLineComment = false;
|
|
|
|
try {
|
|
while (($line = fgets($handle)) !== false) {
|
|
$trimmed = trim($line);
|
|
|
|
// Skip empty lines
|
|
if ($trimmed === '') {
|
|
continue;
|
|
}
|
|
|
|
// Skip single-line comments
|
|
if (str_starts_with($trimmed, '--') || str_starts_with($trimmed, '#')) {
|
|
continue;
|
|
}
|
|
|
|
// Handle multi-line comments
|
|
if (str_starts_with($trimmed, '/*')) {
|
|
$inMultiLineComment = true;
|
|
}
|
|
|
|
if ($inMultiLineComment) {
|
|
if (str_contains($trimmed, '*/')) {
|
|
$inMultiLineComment = false;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Accumulate the statement
|
|
$currentStatement .= $line;
|
|
|
|
// Check if statement is complete (ends with semicolon)
|
|
if (str_ends_with($trimmed, ';')) {
|
|
$statement = trim($currentStatement);
|
|
$currentStatement = '';
|
|
|
|
if (empty($statement)) {
|
|
continue;
|
|
}
|
|
|
|
// Replace abstract #__ prefix with the current site's prefix
|
|
$statement = str_replace('#__', $prefix, $statement);
|
|
|
|
try {
|
|
$db->setQuery($statement);
|
|
$db->execute();
|
|
$statementsExecuted++;
|
|
} catch (\Exception $e) {
|
|
// Log but don't abort — some statements may fail on
|
|
// different MySQL versions (e.g. charset differences)
|
|
// but the overall restore should continue.
|
|
error_log('MokoSuiteBackup SQL import warning: ' . $e->getMessage());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Execute any remaining statement without trailing semicolon
|
|
$remaining = trim($currentStatement);
|
|
|
|
if (!empty($remaining)) {
|
|
$remaining = str_replace('#__', $prefix, $remaining);
|
|
|
|
try {
|
|
$db->setQuery($remaining);
|
|
$db->execute();
|
|
$statementsExecuted++;
|
|
} catch (\Exception $e) {
|
|
error_log('MokoSuiteBackup SQL import warning (final): ' . $e->getMessage());
|
|
}
|
|
}
|
|
} finally {
|
|
fclose($handle);
|
|
}
|
|
|
|
return $statementsExecuted;
|
|
}
|
|
}
|