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

时间:2018-08-15 02:22:10

标签: 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;

因此,它将在pb00k.frm中生成一个包含此结构的mysql/data/文件。现在,我想使用PHP从此文件中获取此结构。

有可能吗?

1 个答案:

答案 0 :(得分:1)

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

面临的挑战是.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文件(来自Table)。当然,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制作的,Oracle是唯一知道.frm文件格式的人!该实用程序是免费的,因此您可以下载它。

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

现在,毕竟,如果您仍然想尝试自己分析.frm文件是为了娱乐还是为了学习,那么您需要耐心并花一些时间来整理一个非常复杂的结构。如果您想继续尝试就可以了,但是请将您的.FRM文件发送给我(至sand_groper80@hotmail.com),以便我可以检查出来,我将在几天内向您发送一些PHP代码,以提取一些其他信息,例如数据类型和显示尺寸。