使用PHP PCRE regex从日志字符串获取url扩展名的文件名

时间:2015-03-31 12:13:44

标签: php regex

我正在编写用于从网络设备解析日志文件的脚本。从设备生成的日志文件不是常规的,这些行不遵循逻辑顺序并且具有多个模式。我的脚本需要从日志行中仅提取与特定模式匹配的日志行,并从该行中提取特定信息作为日期时间,条目类型,资源类型和字符串中url的资源名称。我需要匹配它的模式如下:

dd-mm-yyyy hh:mm:ss INFO spx.resource.media - 新资源' URI' [flags](dlc / tcd)

其中' INFO'是条目类型,' spx.resource.media'资源类型和URI中的资源名称。目前,我们需要过滤具有特定扩展名的那些。

我查看了几篇涉及此主题并在线使用tool的帖子:我带来了这个常规表达:

/(\d{2}-\d{2}-\d{4}\s{1}\d{2}:\d{2}:\d{2})\s{1,}(\w{4})\s{1,}(spx.resource.media)(.{1,}(?<=(?:.jpg)|(?:.png)))/g

问题是最后一个正则表达式组匹配整个URI加上资源类型中的字符和空格,并且y只需要带扩展名的文件名。我试过这个&#39; regex-to-get-a-filename-from-a-url&#39; (不能发布链接信誉不足),但没有锻炼,导致调试器将^ /作为未转义的分隔符。如果删除也不起作用。可以找到日志的一部分here。我真的需要这个。

感谢您阅读和/或回答

2 个答案:

答案 0 :(得分:1)

看看这个。首先确定文件的位置,然后您可以相应地循环以获得您想要的内容

<?php
$handle = @fopen("/tmp/inputfile.txt", "r");
if ($handle) {
while (($buffer = fgets($handle, 4096)) !== false) {
    echo $buffer;
}
if (!feof($handle)) {
    echo "Error: unexpected fgets() fail\n";
}
fclose($handle);
}
?>

答案 1 :(得分:0)

一个月前,有一个解决方案。我想要的是用一种模式提取文件名和其余的子组,我不知道这是否可行,但目前的正则表达式技能不是。所以我所做的就是使用三个正则表达式模式,如下面的代码所示:

这段代码是我(显然)称为Parser的类的一部分。首先,我将模式定义为类中的常量。

/**
 * @const string Log line pattern
 */
const LINE_REGEX_PATTERN = '/(\d{2}-\d{2}-\d{4}\s{1}\d{2}:\d{2}:\d{2})\s{1,}(\w{4})\s{1,}(spx.resource.media)(.{1,}(?<=%extensions%))/';

/**
 * @const string Full URL pattern
 */
const FULL_URL_PATTERN = '/\b((?:https?|ftps?|file|spx):\/\/[-A-Z0-9+&@#\/%?=~_|$!:,.;]*[A-Z0-9+&@#\/%=~_|$])/i';

/**
 * @const string Filename pattern
 */
const RESOURCE_REGEX_PATTERN = '/((?:[^\/][\d\w\.-]+)(?<=%extensions%))/';

如您所见,我使用占位符作为文件扩展名,因为在这种情况下,我需要通过配置或数据库查询动态设置它们。接下来,我针对第一个模式验证每个提取的行

/**
 * Line extract
 *
 * @param string $file_line File line string
 *
 * @return array An array if matches
 *               Array (
 *                  [0] => Matched line
 *                  [1] => Date\Time subgroup (format >> d-M-y H:i:s)
 *                  [2] => String flag subgroup
 *                  [3] => Resource type subgroup (not used)
 *                  [4] => Text string containing resource URL
 *               )
 *               , null otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractMatches($file_line)
{
    $extensions = array();

    // build valid extensions subgroup
    foreach ($this->valid_extensions as $extension) {
        $extensions[] = sprintf("(?:\.%s)", $extension);
    }

    $matches = array();
    // replace extensions placeholder
    $pattern  = str_replace('%extensions%', implode('|', $extensions), self::LINE_REGEX_PATTERN);
    $is_valid = preg_match($pattern, $file_line, $matches);

    if ($is_valid === false) {
        throw new RegexException();
    }

    return $matches;
}

从结果数组(如果有的话)中我获取第5个元素(存储带有URL的文本的元素),然后我传递给另外两个函数,第一个是完全URL提取,第二个是最后提取文件名。见下文:

/**
 * Full URL extract
 *
 * @param string $text Text with URL in it
 *
 * @return string The URL, empty string otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractUrl($text)
{
    $match    = array();
    $is_valid = preg_match(self::FULL_URL_PATTERN, $text, $match);

    if ($is_valid === false) {
        throw new RegexException();
    } elseif ($is_valid === 1) {
        return $match[0];
    }

    return ''; // No URL found!
}

/**
 * Filename extract
 *
 * @param string $url Resource URL (expects no GET parameters)
 *
 * @return string Resource filename (includes extension), empty string otherwise
 *
 * @throws RegexException If malformed pattern
 */
private function extractResourceNameFromUrl($url)
{
    $extensions = array();

    // build valid extensions subgroup
    foreach ($this->valid_extensions as $extension) {
        $extensions[] = sprintf("(?:\.%s)", $extension);
    }

    $matches = array();
    // replace extensions placeholder
    $pattern  = str_replace('%extensions%', implode('|', $extensions), self::RESOURCE_REGEX_PATTERN);
    $is_valid = preg_match($pattern, $url, $matches);

    if ($is_valid === false) {
        throw new RegexException();
    } elseif ($is_valid === 1) {
        return $matches[1];
    }

    return '';
}

最后我在我的应用程序中的一些地方:

$parser = new Parser();
// fetch file line loop
$matches = $parser->extractMatches($file_line);
$url = $parser->extractUrl($matches[4]);
$filename = $parser->extractResourceNameFromUrl($matches[4]);

希望帮助某人。谢谢!