【问题标题】:Create HTML table with arbitrary number of rows in PHP在 PHP 中创建具有任意行数的 HTML 表
【发布时间】:2012-10-30 21:38:14
【问题描述】:

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

主机1,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, ,/家,10,,, ,交换,10,,, ,/opt,60,,, ,/数据,30,,, ,,,,, 主机2,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, ,/家,10,,, ,交换,10,,, ,/opt,60,,, ,/数据,30,,, ,,,,,

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

主机名、eth0 IP、eth0 网络掩码、eth0 网关、eth4 MAC 空,eth1 IP,eth1 网络掩码,eth1 网关,空 空白,eth2 IP,eth2 网络掩码,eth2 网关,空 null,分区名称,分区大小(GB),null,null null,分区名称,分区大小(GB),null,null null,分区名称,分区大小(GB),null,null null,分区名称,分区大小(GB),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 网络掩码 eth0 网关 eth1 IP eth1 网络掩码 eth1 网关 eth2 IP eth2 网络掩码 eth2 网关 分区 1 分区 1 大小 分区 2 分区 2 大小 分区 3 分区 3 大小 分区 4 分区 4 大小 host2 eth0 IP eth0 网络掩码 eth0 网关 eth1 IP eth1 网络掩码 eth1 网关 eth2 IP eth2 网络掩码 eth2 网关 分区 1 分区 1 大小 分区 2 分区 2 大小 分区 3 分区 3 大小 分区 4 分区 4 大小

这是一个开始。然而,并不是每台服务器都会有四个分区。有些人会有更多,有些人会少一两个。并且不提前知道这些信息会阻碍我想要做的事情,即在每个服务器的分区信息下方添加一行,并可能将每个服务器分解成自己的表。类似这样的东西:

host1 eth0 IP eth0 网络掩码 eth0 网关 eth1 IP eth1 网络掩码 eth1 网关 eth2 IP eth2 网络掩码 eth2 网关 分区 1 分区 1 大小 分区 2 分区 2 大小 分区 3 分区 3 大小 分区 4 分区 4 大小 分区 5 分区 5 大小 分区 6 分区 6 大小 多少个磁盘? [文本域} host2 eth0 IP eth0 网络掩码 eth0 网关 eth1 IP eth1 网络掩码 eth1 网关 eth2 IP eth2 网络掩码 eth2 网关 分区 1 分区 1 大小 分区 2 分区 2 大小 分区 3 分区 3 大小 分区 4 分区 4 大小 多少个磁盘? [文本域}

我的普遍想法是,我必须在 CSV 文件中有一个字段来指示该行包含分区信息。这似乎是最简单的方法。不过,我想知道是否还有其他方法可以使用,不需要更改输入文件的格式。

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

任何关于我如何解决此问题的想法将不胜感激。

【问题讨论】:

  • 为什么不使用 mysql 数据库呢?
  • 可能是从其他来源导入数据
  • 该工具的目的是获取一个从现有电子表格创建的 CSV 文件,并使用它来生成 kickstart 文件。生成文件后,不需要 CSV。它可能会出于考古目的而保留,但除此之外,以数据库形式存在的持久性是多余的。如果 CSV 丢失,如果再次需要它,可以从电子表格中重新创建它,这种可能性很小。

标签: php html


【解决方案1】:
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 文件。

【讨论】:

  • 那行得通。虽然,我确实注释掉了创建表头的部分。我目前对此并不担心。不过,我还需要能够跳过 MAC 地址的显示。否则,这似乎允许任意行的分区数据。谢谢。
  • 现在我只需要弄清楚如何在每个允许输入磁盘号的主机数据部分下方添加一行:print "&lt;tr&gt;&lt;td&gt;Number of disks:&lt;/td&gt;&lt;td&gt;&lt;input type="text" size="4"&gt;&lt;/td&gt;&lt;/tr&gt;";
  • 在 StackOverflow (stackoverflow.com/a/5040899/1602022) 使用另一个帖子,我想出了如何查找没有条目的行并使用这些行来确定何时插入包含输入字段的行磁盘数量。
【解决方案2】:

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

$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 行的字符串表示上使用正则表达式允许我们在单个表达式中严格匹配上述所有内容。每个正则表达式的(?&lt;var&gt;...) 部分被命名为匹配项。使用 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 表格)输出数据应该是微不足道的。

【讨论】:

  • 正则表达式路径似乎比必要的复杂得多。我已经能够以我想要的格式输出数据。我只需要知道如何为每组分区使用任意数量的行。我会研究你关于 str_getcsv() 的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 2017-10-06
  • 2020-10-22
  • 2017-10-05
  • 2019-01-26
  • 1970-01-01
相关资源
最近更新 更多