PHP拆分字符串<img>然后中断输出


PHP split string by <img> and break output

我有一些HTML内容,我需要解析它,得到所有的图像。然后打印出整个内容,但是在每次出现image

时运行一个PHP类实例
This is the content
<?php $content = 'Some text
<p>A paragraph</p>
<img src="image1.jpg" width="200" height="200">
More text
<img src="image2.jpg" width="200" height="200">'; ?>

我需要能够获得图像并运行一个类方法的输出。

那么结果会是类似于

<?php echo 'Some text
<p>A paragraph</p>';
$this->Image('image1.jpg', PDF_MARGIN_LEFT, $y_offset, 116, 85);
echo 'More text';
$this->Image('image2.jpg', PDF_MARGIN_LEFT, $y_offset, 116, 85);

但是显然我认为它必须是一个循环或者其他自动完成的东西

如您在评论中提到的那样,要将整个HTML代码段转换为TcPDF,您需要使用DOMDocument解析代码段,并遍历每个子节点,决定如何适当地处理它们。

上面提供的代码片段的问题是它不是一个完整的HTML文档,因此DOMDocument在解析它时会将其包装在<html><body>标记中,在内部加载以下结构:

<html>
    <body>
        Some text
        <p>A paragraph</p>
        <img src="image1.jpg" width="200" height="200">
        More text
        <img src="image2.jpg" width="200" height="200">
    </body>
</html>

这个警告很容易解决,然而,通过建立@hakre的回答在我链接到下面的线程。我的建议大致如下:

// Load the snipped into a DOMDocument
$doc = new DOMDocument();
$doc->loadHTML($content);
// Use DOMXPath to retrieve the body content of the snippet
$xpath = new DOMXPath($doc);
$data = $xpath->evaluate('//html/body');
// <body> is now $data[0], so for readability we do this
$body = $data[0];
// Now we loop through the elements in your original snippet
foreach ($body->childNodes as $node) {
    switch ($node->nodeName) {
        case 'img':
            // Get the value of the src attribute from the img element
            $src = $node->attributes->getNamedItem('src')->nodeValue;
            $this->Image($src, PDF_MARGIN_LEFT, $y_offset, 116, 85);
            break;
        default:
            // Pass the line to TcPDF as a normal paragraph
            break;
    }
}

这样,您可以轻松地添加额外的case 'blah':块来处理可能出现在$content片段中的其他元素并适当地处理它们,并且内容将以正确的顺序处理,而不会破坏文本的原始流程。:)

——原始答案。将工作,如果你只是想提取图像源和处理他们在其他地方独立的其余内容。

您可以使用正则表达式匹配$content字符串中的所有<img>标记:

/<img(?:['s'w="]+)src="([^"]+)"(?:['s'w="]*)'/?>/i

regex的实时分解,你可以在这里玩,看看它是如何工作的:http://regex101.com/r/tS5xY9

您可以对preg_match_all()使用这个正则表达式从$content变量中检索所有图像标记,如下所示:

$matches = array();
$num = preg_match_all('/<img(?:['s'w="]+)src="([^"]+)"(?:['s'w="]*)'/?>/i', $content, $matches, PREG_SET_ORDER);

PREG_SET_ORDER常量告诉preg_match_all()以一种更容易在产生输出时循环的方式存储其结果,因为数组上的第一个索引(即$matches[0], $matches[1]等)将包含来自正则表达式的完整匹配集。在上述正则表达式的情况下,$matches[0]将包含以下内容:

array(
    0 => '<img src="image1.jpg" width="200" height="200">',
    1 => 'image1.jpg',
)

你现在可以循环通过$matches作为$key => $match,并将$match[1]传递给你的$this->Image()方法。

或者,如果您不想循环,您可以直接从$matches访问每个src属性,如$matches[0][1], $matches[1][1]等。

如果您需要能够访问标签中的其他属性,那么我建议使用@hakre在PHP Get img src上提供的DOMDocument方法。如果您只需要访问src属性,那么使用preg_match_all()会更快更有效,因为它不需要将代码片段的整个DOM作为对象加载到内存中,从而为您提供所需的数据。

您可以构建一个词法分析器或解析器来查找图像的位置。

您正在开始寻找两个令牌:<img和各自的结束>。起始点可以是这样的:

$text = "hello <img src='//first.jpg'> there <img src='//second.jpg'>";
$pos  = 0;
while (($opening = strpos($text, '<img', $pos)) !== FALSE) {
    // Find the next closing bracket's location
    $closing = strpos($text, '>', $opening);
    $length = ($closing - $opening) + 1; // Add one for the closing '>'
    $img_tag = substr($text, $opening, $length);
    var_dump($img_tag);
    // Update the loop position with our closing tag to advance the lexer
    $pos = $closing;
}

您将不得不构建方法来扫描img标签。您还可以在循环中添加PDF方法。

另一种更易于管理的方法是构建一个遍历每个字符的类。它首先查找开头的'<'字符,然后检查接下来的三个字符是否为'img',如果是,则分别扫描src、height、width属性。这是更多的工作,但更灵活的方式-你将能够扫描更多的不仅仅是你的图像标签。