php - 如何使用 PHP 从 .frm 文件中获取表结构?

标签 php mysql

让我通过 phpMyAdmin 创建一个以 pb00k 命名的表,其 SQL 如下所示:

    CREATE TABLE `pb00k` (
  `k3y` int(255) NOT NULL AUTO_INCREMENT,
  `n4m3` text NOT NULL,
  `numb3r` text NOT NULL,
  PRIMARY KEY (`k3y`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

于是它在mysql/data/中生成了一个pb00k.frm文件,其中包含了这个结构。现在我想使用 PHP 从这个文件中获取这个结构。

这可能吗?

最佳答案

是的,至少可以恢复部分信息。 (为了其他读者的利益,问题的提出者已经意识到有更简单的方法来获取列元数据)。

挑战在于 .frm 文件没有很好的记录,因为一般社区很少需要破译它们。此外,文件格式可能因操作系统而异。

但是,通过使用 hexdump 或类似的实用程序查看文件,您可以部分了解正在发生的事情。然后,您最好了解如何读取 PHP 程序中的文件并解码原始二进制数据。

我以前做过这个练习,我能够恢复列数、列名和列类型。

下面是一个示例,展示了如何提取列名。我的 .frm 用于表名“stops”,但您可以替换为您自己的 .frm。

<?php
$fileName = "stops.frm";

// read file into an array of char
//---------------------------------
$handle = fopen($fileName, "rb");
$contents = fread($handle, filesize($fileName));
fclose($handle);
$fileSize=strlen($contents);  // save the filesize fot later printing

// locate the column data near the end of the file
//-------------------------------------------------
$index = 6;    // location of io_size
$io_size_lo = ord($contents[$index]);  
$io_size_hi = ord($contents[$index+1]);
$io_size = $io_size_hi *0x100 + $io_size_lo; // read IO_SIZE

$index = 10;  // location of record length
$rec_len_lo = ord($contents[$index]);
$rec_len_hi = ord($contents[$index+1]);
$rec_len = $rec_len_hi * 0x100 + $rec_len_lo; // read rec_length

// this formula uses io_size and rec_length to get to column data
$colIndex = ( (  (($io_size + $rec_len)/$io_size)   + 1) * $io_size ) + 258;
$colIndex -= 0x3000;   // this is not documented but seems to work!

// find number of columns in the table
//------------------------------------------------- 
echo PHP_EOL."Col data at 0x".dechex($colIndex).PHP_EOL;
$numCols = ord($contents[$colIndex]);

//Extract the column names
//--------------------------------------
$colNameIndex = $colIndex+0x50;   //0X50 by inspection
echo "Col names at 0x".dechex($colNameIndex).PHP_EOL;
$cols=array();
for ($col = 0; $col < $numCols; $col++){
    $nameLen = ord($contents[$colNameIndex++]);          // name length is at ist posn
    $cols[]['ColumnName']= substr($contents,$colNameIndex,$nameLen-1); // read the name
    $colNameIndex+=$nameLen+2;        // skip ahead to next name (2 byte gap after \0)
}
print_r($cols);

这应该可以帮助您入门。如果您认为正朝着正确的方向前进,我会在未来几天有空时补充这一点。

编辑。 我更新了代码,因此它应该适用于任何 .frm 文件(来自表)。可以肯定的是,https://github.com/twindb/undrop-for-innodb 提供了一个免费工具来恢复 mySQL(基于 innoDB 引擎)。 .通读代码和相关博客后,他们没有使用 .FRM 文件进行恢复。相同的表信息也存储在 innoDB 字典中,他们正在使用它来恢复表格式等。

还有一种方法可以读取.FRM 文件的内容。这在这里描述 https://twindb.com/how-to-recover-table-structure-from-frm-files-online/ .但是,他们正在使用 mySQL 读取 .frm 文件并从那里重新创建表。

这里还有一个实用程序包 https://www.mysql.com/why-mysql/presentations/mysql-utilities/包含一个 .frm 阅读器。这是由 Oracle 制作的,他们是唯一知道 .frm 文件格式的人!该实用程序是免费的,因此您可以下载它。

Oracle 发布了一些关于.frm 文件格式的信息https://dev.mysql.com/doc/internals/en/frm-file-format.html ,但它既不完整也不正确!请参阅之前的 Stack 问题。 https://dba.stackexchange.com/questions/208198/mysql-frm-file-format-how-to-extract-column-info

毕竟,如果您仍想尝试自己解析 .frm 文件以娱乐或学习,那么您需要耐心等待并花时间解开相当复杂的结构。如果你想继续尝试,没关系,但请将你的 .FRM 文件发送给我(发送至 sand_groper80@hotmail.com),以便我检查它,几天后我将向你发送一些 PHP 代码,这些代码将提取一些附加信息,如数据类型和显示尺寸。

关于php - 如何使用 PHP 从 .frm 文件中获取表结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51852099/

相关文章:

php - 获取数据库结果后从数组中删除最后一个逗号

实时网站上的 PHP 错误

Mysql string to date with given format containing a timezone specifier

javascript - 页面更新后获取更改的数据

php - 显示MYSQL计数结果

mysql - 恶意软件清除后数据库中的引号逃逸

php - 无法在 thinkphp 中加载 Controller

php - Laravel 原始子查询同表

PHP。为什么日期对象 diff on month 在 12 个月后重置为 0?

php - PDO 方法可以失败并且不抛出 PDOException 吗?