有限的内容打破了PHP中的HTML布局

时间:2015-03-25 13:51:20

标签: php html string

当我试图限制description的内容时,我遇到了一些问题,我试过这样的话:

<?php 
$intDescLt = 400;
$content   = $arrContentList[$arr->nid]['description'];
$excerpt   = substr($content, 0, $intDescLt);
?>
<div class="three16 DetailsDiv">
    <?php echo $excerpt; ?>
<div>

在描述字段中,如果我只是将内容放在没有html标签的情况下,它可以正常工作,但如果我将内容与html标签放在一起,并且如果限制到达结束标记之前的末尾,则将该选项卡样式应用于所有内容之后那。

所以我需要知道如何解决这个问题。

实施例 问题:

$string = "<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry.</p>";
echo substr($string, 0, 15);

控制台中的Html输出: <p><b>Lorem Ipsu 现在,它将<b>标记应用于页面中的其他内容。

控制台中的预期输出: <p><b>Lorem Ipsu</b>

2 个答案:

答案 0 :(得分:0)

好的,给出你提供的例子:

$string = "<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry.</p>";
$substring = substr((addslashes($string)),0,15);

如果要关闭所有未关闭的标签,可能的解决方法是使用DOMDocument class

$doc = new DOMDocument();
$doc->loadHTML($substring);
$yourText = $doc->saveHTML($doc->getElementsByTagName('*')->item(2));
//item(0) = html
//item(1) = body
echo htmlspecialchars($yourText);
//<p><b>Lorem Ips</b></p>

答案 1 :(得分:0)

你不能只在HTML字符串上使用PHP的二进制字符串函数,然后期望事情能够发挥作用。

$string = "<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry.</p>";

首先,您需要制定您希望在HTML上下文中创建的摘录。让我们举一个关注字符实际文本长度的例子。那是计算HTML标签的大小。标签也应该保持关闭状态。

首先创建 DOMDocument ,以便您可以对自己的HTML片段进行操作。加载的$string将是<body>标记的子节点,因此代码也会将其作为参考:

$doc    = new DOMDocument();
$result = $doc->loadHTML($string);
if (!$result) {
    throw new InvalidArgumentException('String could not be parsed as HTML fragment');
}
$body = $doc->getElementsByTagName('body')->item(0);

接下来需要按文档顺序对其中的所有节点进行操作。借助xpath查询可以轻松实现迭代这些节点:

$xp    = new DOMXPath($doc);
$nodes = $xp->query('./descendant::node()', $body);

然后需要实现如何创建摘录的逻辑。这就是所有文本节点都被接管,直到它们的长度超过剩余的字符数。如果是,则为split或者如果没有从其父级中删除任何字符:

$length = 0;
foreach ($nodes as $node) {
    if (!$node instanceof DOMText) {
        continue;
    }
    $left = max(0, 15 - $length);
    if ($left) {
        if ($node->length > $left) {
            $node->splitText($left);
            $node->nextSibling->parentNode->removeChild($node->nextSibling);
        }
        $length += $node->length;
    } else {
        $node->parentNode->removeChild($node);
    }
}

最后,您需要将body标签的内部HTML转换为字符串以获取结果:

$buffer = '';
foreach ($body->childNodes as $node) {
    $buffer .= $doc->saveHTML($node);
}

echo $buffer;

这会给你以下结果:

<p><b>Lorem Ipsum</b> is </p>

由于节点元素已被更改但仅包含文本节点,因此元素仍然完好无损。只是文字缩短了。 Document Object Model允许您根据需要进行遍历,字符串操作以及节点删除。

可以想象,像substr()这样更简单的字符串函数在处理HTML方面同样不具备。

实际上可能还有更多工作要做:字符串中的HTML可能无效(查看Tidy扩展名),您可能希望删除HTML属性和标记(图像,脚本,iframe),您可能还想放置考虑到标签的大小。 DOM允许您这样做。

完整示例(online demo):

<?php
/**
 * Limited content break the HTML layout in php
 *
 * @link http://stackoverflow.com/a/29323396/367456
 * @author hakre <http://hakre.wordpress.com>
 */

$string = "<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry.</p>";
echo substr($string, 0, 15), "\n";

$doc    = new DOMDocument();
$result = $doc->loadHTML($string);
if (!$result) {
    throw new InvalidArgumentException('String could not be parsed as HTML fragment');
}
$body = $doc->getElementsByTagName('body')->item(0);

$xp    = new DOMXPath($doc);
$nodes = $xp->query('./descendant::node()', $body);

$length = 0;
foreach ($nodes as $node) {
    if (!$node instanceof DOMText) {
        continue;
    }
    $left = max(0, 15 - $length);
    if ($left) {
        if ($node->length > $left) {
            $node->splitText($left);
            $node->nextSibling->parentNode->removeChild($node->nextSibling);
        }
        $length += $node->length;
    } else {
        $node->parentNode->removeChild($node);
    }
}

$buffer = '';
foreach ($body->childNodes as $node) {
    $buffer .= $doc->saveHTML($node);
}

echo $buffer;