Skip to content

Commit 391891c

Browse files
committed
first version
0 parents  commit 391891c

21 files changed

+1857
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea
2+
/vendor/
3+
config.php

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Jocelyn Flament
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# ibd2mysql
2+
3+
[![Latest Packagist release](https://img.shields.io/packagist/v/j0celyn/ibd2mysql.svg)](https://packagist.org/packages/j0celyn/ibd2mysql)
4+
[![Latest Packagist release](https://img.shields.io/packagist/dependency-v/j0celyn/ibd2mysql/php)](https://packagist.org/packages/j0celyn/ibd2mysql)
5+
[![Latest Packagist release](https://img.shields.io/github/license/j0celyn/ibd2mysql)](https://packagist.org/packages/j0celyn/ibd2mysql)
6+
7+
## Description
8+
9+
MySQL provides the configuration flag [innodb_force_recovery](https://dev.mysql.com/doc/refman/8.0/en/forcing-innodb-recovery.html) to help you fix several kinds of errors.
10+
You should first check if it can help you fix your problems.
11+
12+
**ibd2mysql** is a tool to try to recover InnoDB tables under the following conditions:
13+
- MySQL Server v8.0.0 or newer
14+
- your tables are using the InnoDB engine
15+
- [innodb_file_per_table](https://dev.mysql.com/doc/refman/8.0/en/innodb-parameters.html#sysvar_innodb_file_per_table) was enabled in the MySQL Server configuration **before** you ran into problems
16+
(in the MySQL data directory, you should see at least one IBD file for each of your tables)
17+
- the MySQL data dictionary is corrupted or missing (the server no longer knows what tables each database contains, despite the IBD files still being there)
18+
19+
20+
## Requirements
21+
22+
- PHP 8
23+
- MySQL 8
24+
25+
## Installation
26+
27+
#### Install via composer:
28+
composer require j0celyn/ibd2mysql
29+
30+
## Setup
31+
32+
⚠️ The IBD file format evolving with each MySQL version, it is highly recommended to run this script using the version of the MySQL Server that created the IBD files you are trying to recover.
33+
If using a different MySQL version, you will probably still be able to extract the SDI information and create the SQL files. However the **--repair** option is likely to fail with fatal errors when importing your IBD files into the MySQL Server.
34+
35+
Rename `config-empty.php` to `config.php`, then edit its values:
36+
- **DB_HOST**: your MySQL server host
37+
- **DB_PORT**: your MySQL server port
38+
- **DB_USER**: your MySQL server user
39+
- **DB_PASSWORD**: your MySQL server password
40+
- **MYSQL_DATA_DIR**: full path to the MySQL data directory of your server
41+
- **IBD2SDI_PATH**: full path to the directory that holds the [ibd2sdi](https://dev.mysql.com/doc/refman/8.0/en/ibd2sdi.html) program. It was probably installed together with your MySQL server
42+
- **BACKUP_DIR**: full path to the directory of backup IBD files (the IBD files that contain your MySQL data)
43+
- **OUTPUT_DIR**: full path to the directory where this script will create SDI and SQL files
44+
45+
### Usage
46+
Here are the available options:
47+
- **--sdi**: extracts SDI information from IBD files. **Note: Existing SDI files will be overwritten.**
48+
- **--sql**: creates MySQL files from SDI files. **Note: Existing SQL files will be overwritten.**
49+
- **--repair**: for each table:
50+
- runs the MySQL files to create the table
51+
- moves IBD file(s) to replace the empty tablespace with your saved tablespace
52+
- if needed, optimizes the table to fix some issues
53+
54+
**Note: Existing MySQL tables will not be altered.**
55+
56+
When the script is called with more than one option, they will always run in the same order: **sdi sql repair**
57+
58+
To run the script, use one or more options.
59+
60+
#### Examples:
61+
62+
php vendor/j0celyn/ibd2mysql/convert.php --sdi
63+
php vendor/j0celyn/ibd2mysql/convert.php --sdi --sql

composer.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "j0celyn/ibd2mysql",
3+
"description": "Tool to recover InnoDB tables in a corrupted MySQL database or MySQL server",
4+
"keywords": ["MySQL","InnoDB"],
5+
"type": "library",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Jocelyn Flament",
10+
"role": "Developer"
11+
}
12+
],
13+
"autoload": {
14+
"psr-4": {
15+
"j0celyn\\ibd2mysql\\": "src/"
16+
}
17+
},
18+
"require": {
19+
"php": ">=8.0.0",
20+
"ext-pdo": "*"
21+
}
22+
}

config-empty.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* @author Jocelyn Flament
4+
* @since 12/07/2023
5+
*/
6+
7+
/*
8+
* Fill in the necessary values below, then rename this file to config.php
9+
* A valid MySQL connection is necessary to generate the SQL files or create the MySQL tables
10+
*/
11+
12+
const DB_HOST = 'localhost'; // your MySQL server host - change it if necessary
13+
const DB_PORT = 3306; // your MySQL server port - change it if necessary
14+
const DB_USER = ''; // your MySQL server user - it must have database creation and table creation permissions
15+
const DB_PASSWORD = ''; // your MySQL server password
16+
const MYSQL_DATA_DIR = ''; // full path to the MySQL data directory of your server
17+
const IBD2SDI_PATH = ''; // full path to the directory that holds the ibd2sdi program. It was probably installed together with your MySQL server
18+
const BACKUP_DIR = ''; // full path to the directory of backup IBD files (the IBD files that contain your MySQL data)
19+
const OUTPUT_DIR = ''; // full path to the directory where this script will create SDI and SQL files
20+
21+
/*
22+
* if DB_NAMES is empty, it will process all subdirectories (databases) found in BACKUP_DIR
23+
* otherwise, il will only process the subdirectories (databases) listed below
24+
*
25+
* example: ['my_database', 'another_database', 'third_db']
26+
*/
27+
const DB_NAMES = [];

convert.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
/**
3+
* @package ibd2mysql
4+
* @author Jocelyn Flament
5+
*
6+
* This is the file that must be called in the console
7+
*/
8+
9+
require __DIR__ . '/../../autoload.php';
10+
11+
use j0celyn\ibd2mysql\ibd2mysql;
12+
13+
if (!file_exists(__DIR__ . '/config.php')) {
14+
die('ERROR: you must set up the config file first. Open config-empty.php and read the comments, then run this script again when the config is ready.');
15+
}
16+
17+
require __DIR__ . '/config.php';
18+
require __DIR__ . '/src/utils.php';
19+
20+
const OPTIONS = [
21+
'sdi' => [
22+
'cmd' => '--sdi',
23+
'text' => 'generate SDI files from IBD data',
24+
],
25+
'sql' => [
26+
'cmd' => '--sql',
27+
'text' => 'generate SQL files from SDI files',
28+
],
29+
'repair' => [
30+
'cmd' => '--repair',
31+
'text' => 'recreate the tables from SQL files, with their data (using your IBD files)',
32+
],
33+
];
34+
35+
$ibd2mysql = new ibd2mysql(DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, IBD2SDI_PATH, BACKUP_DIR, OUTPUT_DIR,
36+
MYSQL_DATA_DIR, DB_NAMES);
37+
38+
$options = getopt('', array_keys(OPTIONS));
39+
if (empty($options)) {
40+
echo "Use one or more options to run this script:\n";
41+
foreach (OPTIONS as $option) {
42+
printf("%s : %s\n", $option['cmd'], $option['text']);
43+
}
44+
exit;
45+
}
46+
if (array_key_exists('sdi', $options)) {
47+
$ibd2mysql->getSDI()->dumpFiles();
48+
}
49+
if (array_key_exists('sql', $options)) {
50+
$ibd2mysql->getSQL()->dumpFiles();
51+
}
52+
if (array_key_exists('repair', $options)) {
53+
$ibd2mysql->getRepair()->repairTables();
54+
}

src/Paths.php

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
/**
3+
* @package ibd2mysql
4+
* @author Jocelyn Flament
5+
*/
6+
7+
namespace j0celyn\ibd2mysql;
8+
9+
/**
10+
* Helper class to easily retrieve paths to the various directories used by the script
11+
*/
12+
class Paths
13+
{
14+
public function __construct(protected string $ibd2sdi_path, protected string $backup_dir, protected string $output_dir,
15+
protected string $mysql_data_dir)
16+
{
17+
if (!is_executable($this->ibd2sdi_path)) {
18+
die(sprintf('ERROR: ibd2sdi program "%s" could not be located or the file is not executable, check config.', $this->ibd2sdi_path));
19+
}
20+
21+
if (!is_dir($this->backup_dir)) {
22+
die(sprintf('ERROR: backup directory "%s" does not exist, check config.', $this->backup_dir));
23+
}
24+
25+
if (!@mkdir($this->output_dir, 0777, true) && !is_dir($this->output_dir)) {
26+
die(sprintf('ERROR: Output directory "%s" could not be created, check config.', $this->output_dir));
27+
}
28+
}
29+
30+
public function getIbd2sdiPath(): string
31+
{
32+
return $this->ibd2sdi_path;
33+
}
34+
35+
public function getBackupDir(): string
36+
{
37+
return $this->backup_dir;
38+
}
39+
40+
public function getOutputDir(): string
41+
{
42+
return $this->output_dir;
43+
}
44+
45+
public function getOutputPath(string $database, string $table, string $ext = 'sdi'): string
46+
{
47+
return $this->getPath($this->output_dir, $database, $table, $ext);
48+
}
49+
50+
protected function getPath(string $base_dir, string $database, string $table, string $ext): string
51+
{
52+
return $base_dir . DIRECTORY_SEPARATOR . $database . DIRECTORY_SEPARATOR . $table . ($ext !== '' ? '.' . $ext : '');
53+
}
54+
55+
public function getBackupPath(string $database, string $table, string $ext = 'ibd'): string
56+
{
57+
return $this->getPath($this->backup_dir, $database, $table, $ext);
58+
}
59+
60+
public function getMysqlDataDirPath(string $database, string $table, string $ext = 'ibd'): string
61+
{
62+
return $this->getPath($this->mysql_data_dir, $database, $table, $ext);
63+
}
64+
}

0 commit comments

Comments
 (0)