在PHP中创建具有任意行数的HTML表

时间:2012-10-30 21:38:15

标签: php html

我对PHP知之甚少,因此决定创建一个基于Web的工具来生成Red Hat kickstart文件将是一个值得学习的好项目。除此之外,该工具将解析CSV文件并生成包含从中获取的数据的表。输入文件采用以下格式:

host1,10.153.196.248,255.255.255.0,10.153.196.1,00:50:56:ac:69:cb
,10.153.157.113,255.255.255.128,10.153.157.1,
,10.153.157.241,255.255.255.128,10.153.157.129,
,/home,10,,,
,swap,10,,,
,/opt,60,,,
,/data,30,,,
,,,,,
host2,10.153.155.124,255.255.255.128,10.153.155.1,00:50:56:ac:69:ce
,10.153.157.114,255.255.255.128,10.153.157.1,
,10.153.157.242,255.255.255.128,10.153.157.129,
,/home,10,,,
,swap,10,,,
,/opt,60,,,
,/data,30,,,
,,,,,

文本的每个部分代表一个服务器的信息。字段如下:

hostname,eth0 IP, eth0 netmask, eth0 gateway, eth4 MAC
null,eth1 IP, eth1 netmask, eth1 gateway, null
blank,eth2 IP, eth2 netmask, eth2 gateway, null
null,partition name, partition size in GB, null, null
null,partition name, partition size in GB, null, null
null,partition name, partition size in GB, null, null
null,partition name, partition size in GB, null, null
null,null,null,null,null

目前,我可以解析它并生成一个表,输入文件中的每一行都是表中的一行。处理此问题的函数:

function processFile($workFile) {

    if (file_exists($workFile)) {
        print '<table>';
        $fh = fopen("$workFile", 'rb');
        if ($fh) {
            for ($line = fgets($fh); !feof($fh); $line = fgets($fh)) {
                $line = trim($line);
                $info = explode(',', $line);
                print '<tr><td>' . $info[0] . '</td><td>' . $info[1] . '</td><td>' . $info[2] . '</td><td>' . $info[3] . '</td></tr>';
            }
        } else {
            print "Failed to open $workFile";
        }
        print '</table>';
    } else {
        print "File $workFile does not exist";
    }

}

生成:

host1     eth0 IP      eth0 netmask      eth0 gateway
          eth1 IP      eth1 netmask      eth1 gateway
          eth2 IP      eth2 netmask      eth2 gateway
          partition 1  partition 1 size
          partition 2  partition 2 size
          partition 3  partition 3 size
          partition 4  partition 4 size
host2     eth0 IP      eth0 netmask      eth0 gateway
          eth1 IP      eth1 netmask      eth1 gateway
          eth2 IP      eth2 netmask      eth2 gateway
          partition 1  partition 1 size
          partition 2  partition 2 size
          partition 3  partition 3 size
          partition 4  partition 4 size

这是一个开始。但是,并非每个服务器都有四个分区。有些会有更多,有些会少一两个。并且不知道提前信息会阻碍我想要做的事情,即在每个服务器的分区信息下面添加一行,并且可能会将每个服务器分成自己的表。有点像这样:

host1     eth0 IP          eth0 netmask      eth0 gateway
          eth1 IP          eth1 netmask      eth1 gateway
          eth2 IP          eth2 netmask      eth2 gateway
          partition 1      partition 1 size
          partition 2      partition 2 size
          partition 3      partition 3 size
          partition 4      partition 4 size
          partition 5      partition 5 size
          partition 6      partition 6 size
          How many disks?  [Text Field}    

host2     eth0 IP          eth0 netmask      eth0 gateway
          eth1 IP          eth1 netmask      eth1 gateway
          eth2 IP          eth2 netmask      eth2 gateway
          partition 1      partition 1 size
          partition 2      partition 2 size
          partition 3      partition 3 size
          partition 4      partition 4 size
          How many disks?  [Text Field}

我的主流思想是,我必须在CSV文件中有一个字段,表明该行包含分区信息。这似乎是最简单的方法。我想知道是否还有其他方法可以使用,但不需要改变输入文件的格式。

我还必须弄清楚如何使用包含所有空字段的行作为节分隔符。

对我如何处理此问题的任何想法都将不胜感激。

2 个答案:

答案 0 :(得分:0)

echo('<table>');
$i = 0;
while($data = fgetcsv($fh)) {
    echo('<tr>');
    $cellTag = 'td';
    if($i == 0) {
        $cellTag = 'th';
    }
    $i++;
    foreach($data as $cell) {
        echo('<'.$cellTag.'>'.$cell.'</'.$cellTag.'>');
    }
    echo('</tr>');
}
echo('</table>');

试一试。如果它第一次不起作用,请告诉我。我已经测试了它,但我手头没有CSV文件。

答案 1 :(得分:0)

在解析与特定格式匹配的数据时,它本质上应该是常规的,允许您使用正则表达式来严格匹配您想要的输入(并抛弃您不需要的输入):

$rows = explode("\n", $input);

// @link http://stackoverflow.com/questions/106179/regular-expression-to-match-hostname-or-ip-address
$regIp = "(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])";
$regHost = "(([a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])";

$hosts = array();
foreach ($rows as $row) {
  $matches = null;
  if (preg_match("/(?<host>$regHost),(?<ip>$regIp),(?<netmask>$regIp),(?<gateway>$regIp),(?<mac>.*)/", $row, $matches)) {
    $host = $matches['host'];
    $hosts[$host]['name'] = $matches['host'];
    $hosts[$host]['mac'] = $matches['mac'];
    $hosts[$host]['eth'][] = array(
      'ip'      => $matches['ip'],
      'netmask' => $matches['netmask'],
      'gateway' => $matches['gateway'],
    );
  } else if (preg_match("/,(?<ip>$regIp),(?<netmask>$regIp),(?<gateway>$regIp),/", $row, $matches)) {
    $hosts[$host]['eth'][] = array(
      'ip'      => $matches['ip'],
      'netmask' => $matches['netmask'],
      'gateway' => $matches['gateway'],
    );
  } else if (preg_match("/,(?<name>.+),(?<size>\d+),,,/", $row, $matches)) {
    $hosts[$host]['partition'][] = array(
      'name' => $matches['name'],
      'size' => $matches['size'],
    );
  } else if (preg_match("/,,,,,/", $row)) {
    // we already partition output array with value of `$host` variable.
    echo "Found terminating row\n"; 
  } else {
    echo "Unrecognised data on row: $row\n";
  }
}

var_export($hosts);

由于我们正在处理CSV文件,因此可以在循环内使用$fields = str_getcsv($row)来获取包含每个字段的数组。然后,人们需要计算数组有多少个字段,有多少字段为空,并验证每个字段包含的内容。

直接在每个CSV行的字符串表示上使用正则表达式允许我们在单个表达式中严格匹配上述所有内容。每个正则表达式的(?<var>...)部分都是命名匹配。使用OP提供的输入,上面的脚本输出:

Found terminating row
Found terminating row
array (
  'host1' => 
  array (
    'name' => 'host1',
    'mac' => '00:50:56:ac:69:cb',
    'eth' => 
    array (
      0 => 
      array (
        'ip' => '10.153.196.248',
        'netmask' => '255.255.255.0',
        'gateway' => '10.153.196.1',
      ),
      1 => 
      array (
        'ip' => '10.153.157.113',
        'netmask' => '255.255.255.128',
        'gateway' => '10.153.157.1',
      ),
      2 => 
      array (
        'ip' => '10.153.157.241',
        'netmask' => '255.255.255.128',
        'gateway' => '10.153.157.129',
      ),
    ),
    'partition' => 
    array (
      0 => 
      array (
        'name' => '/home',
        'size' => '10',
      ),
      1 => 
      array (
        'name' => 'swap',
        'size' => '10',
      ),
      2 => 
      array (
        'name' => '/opt',
        'size' => '60',
      ),
      3 => 
      array (
        'name' => '/data',
        'size' => '30',
      ),
    ),
  ),
  'host2' => 
  array (
    'name' => 'host2',
    'mac' => '00:50:56:ac:69:ce',
    'eth' => 
    array (
      0 => 
      array (
        'ip' => '10.153.155.124',
        'netmask' => '255.255.255.128',
        'gateway' => '10.153.155.1',
      ),
      1 => 
      array (
        'ip' => '10.153.157.114',
        'netmask' => '255.255.255.128',
        'gateway' => '10.153.157.1',
      ),
      2 => 
      array (
        'ip' => '10.153.157.242',
        'netmask' => '255.255.255.128',
        'gateway' => '10.153.157.129',
      ),
    ),
    'partition' => 
    array (
      0 => 
      array (
        'name' => '/home',
        'size' => '10',
      ),
      1 => 
      array (
        'name' => 'swap',
        'size' => '10',
      ),
      2 => 
      array (
        'name' => '/opt',
        'size' => '60',
      ),
      3 => 
      array (
        'name' => '/data',
        'size' => '30',
      ),
    ),
  ),
)

由于我们现在拥有一系列结构合理的数据,因此以任何所需格式(即HTML表格)输出数据应该是微不足道的。