【问题标题】:PHP array foreach and display all values that match a patternPHP数组foreach并显示所有匹配模式的值
【发布时间】:2016-01-15 05:49:15
【问题描述】:

我正在使用 scandir 获取日志目录中所有访问日志的列表,如果 $access_log = 基于域和月份的某些标准,则可以显示不同月份的访问日志。

我想做的是简化这段代码,这样我就不必写出所有这些 if 语句和月份变量。

例如,如果每个域有 100 个访问日志,我就必须写出所有这些 if 语句 100 次。

访问日志如下所示subdomain.mydomain.com-Jan-2016.gz

所以我试图弄清楚如何重写我的代码,使其只有 1 个 if 语句,该语句在 $access_log 中查找 $domain 的模式,并在 $log_month 变量中列出这些访问日志。到目前为止无法弄清楚,除非我为每个 $log_month 变量编写单独的 if 语句,正如您在下面 foreach 循环中的 3 个 if 语句示例中看到的那样。

$access_logs = scandir($log_list);

$month = date("M-Y");
$prevmonth = date('M-Y', strtotime("first day of last month"));
$minus_2_month = date('M-Y', strtotime("first day of -2 month"));
$minus_3_month = date('M-Y', strtotime("first day of -3 month"));
$minus_4_month = date('M-Y', strtotime("first day of -4 month"));
//etc etc etc

    foreach($access_logs as $access_log) {

            if ($access_log == $domain_dashes . '.mydomain.com-' . $month . '.gz') {
                $log_month = '<li><a href="logs.php?log=' . $access_log . '">' . $access_log . '</a></li>' . "\n            ";
            }

            if ($access_log == $domain_dashes . '.mydomain.com-' . $prevmonth . '.gz') {
                $log_month .= '<li><a href="logs.php?log=' . $access_log . '">' . $access_log . '</a></li>' . "\n            ";
            }

            if ($access_log == $domain_dashes . '.mydomain.com-' . $minus_2_month . '.gz') {
                $log_month .= '<li><a href="logs.php?log=' . $access_log . '">' . $access_log . '</a></li>' . "\n            ";
            }

           // etc etc etc
    }

2016 年 1 月 19 日更新

更具体地说,这就是我需要的。域列表,每个域旁边都有访问日志。

域 1 - domain1.com-jan-2016.gz | domain1.com-dec-2015.gz

域 2 - domain2.com-jan-2016.gz

域 3 - domain3.com-jan-2016.gz | domain3.com-dec-2015.gz |等|等等

在每个域旁边,我需要它来显示访问日志文件。对于域 1,可能有来自不同月份的 2 或 3 个文件。对于域 2,可能只有 1 个文件。对于域 3,可能有十几个。

上面的代码可以满足我的需要。但我想用 || 压缩代码或者一个简单的 if 语句,但是当我这样做时,并不是所有的访问日志都会显示在每个域旁边。只会显示一个文件。

如何获取每个域名旁边的所有访问日志文件以及我上面代码的压缩版本?

【问题讨论】:

  • 在每个 if 块中你都在做同样的事情。那么为什么 if 块呢?
  • 你可以用 OR 连接三个 if
  • 如果我将三个 if 与 OR 连接起来,那么只有第一个 $access_log 得到满足,其余的都被忽略并且不会显示在屏幕上。例如,如果 abc.com 的域有 3 条访问日志,则只会显示其中的 1 条,而其他 2 条则不显示。
  • 我看不到 array_map 将如何工作。我有一个访问日志列表。我有一个域列表。我正在尝试将域与访问日志匹配。但是有些域有过去几个月的 2 或 3 个访问日志。如何输出所有将域作为访问日志字符串的一部分的访问日志?
  • 是的,抱歉,我跳过这个问题太快了。 array_map 将有助于将每个日志文件映射到输出字符串,但您仍然需要回调来进行过滤。如果前缀始终相同,那么if ( 0 === strpos($access_log, $domain_dashes . 'mydomain.com-') ) { 可能会解决问题。

标签: php arrays foreach


【解决方案1】:

您可以使用 PHP glob 函数来代替 scandir。 使用 glob,您可以通过模式获取路径名。

例如:

$access_logs = glob('*.mydomain.com-*.gz');
$log_month = '';
foreach($access_logs as $access_log) {
    $log_month .= '<li><a href="logs.php?log=' . $access_log . '">' . $access_log . '</a></li>' . "\n            ";
}

2016 年 1 月 19 日更新

我建议使用正则表达式从文件名中拆分信息(域、月、年)。要收集每个域的所有日志文件,您可以使用域作为数组键。 收集后你必须遍历所有域,你可以列出所有对应的日志文件。

<?php

# gathering
$access_logs = glob('*.gz');

$domainList = [];
foreach ($access_logs as $access_log) {
    if (preg_match('/((?:[-A-Za-z0-9]+\.)+[A-Za-z]{2,6})-(\w{3})-(\d{4})/i', $access_log, $matches)) {
        $domain = $matches[1];
        # $month = $matches[2];
        # $year = $matches[3];
        if (!isset($domainList[$domain])) {
            $domainList[$domain] = '';
        }
        $domainList[$domain] .= '<li><a href="logs.php?log=' . $access_log . '">' . $access_log . '</a></li>';
    }
}

# output
foreach ($domainList as $domain => $list) {
    echo "<h1>{$domain}</h1>";
    echo "<ul>{$list}</ul>";
}

您可以自行调整输出。但逻辑做你想做的事。

【讨论】:

  • 这并没有像 scandir 为这个特定项目带来任何不同的值。我仍然遇到 foreach 循环的问题,即使列表中有更多访问日志,每个域名也只输出 1 个访问日志。
  • 刚刚更新了我的问题 2016 年 1 月 19 日更新。也许现在您可以更全面地了解正在发生的事情以及如何提供帮助。
猜你喜欢
  • 1970-01-01
  • 2012-02-12
  • 2011-07-10
  • 1970-01-01
  • 1970-01-01
  • 2019-08-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多