c = $user_id;
}
public function class($class)
{
$this->class = $class;
}
public function content($table)
{
$content = json_decode($this->c['content'], true);
return $content[$table];
}
private function processContent($rawText)
{
// 1. Обработка упоминаний и смайлов
$withTags = Emoji::parseSmileys(Word::processMentions($rawText));
// 2. Селективное экранирование
$safeContent = $this->selectiveHtmlEscape($withTags);
// 3. Обрезка контента
return $this->truncateContent($safeContent, 200);
}
private function selectiveHtmlEscape(string $html): string
{
// 0. Если текст не UTF‑8, конвертируем из CP1251
if (!mb_check_encoding($html, 'UTF-8')) {
$html = mb_convert_encoding($html, 'UTF-8', 'CP1251');
}
// 1. Разбиваем на «теги» и «текст», сохраняя теги
$parts = preg_split('/(<[^>]+>)/u', $html, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($parts as &$part) {
// 2. Тег — пропускаем
if (preg_match('/^<[^>]+>$/u', $part)) {
continue;
}
// 3. Текст — сначала декодируем все сущности, потом экранируем спецсимволы
// ENT_QUOTES|ENT_HTML5 и false у double_encode гарантируют корректную работу с etc.
$decoded = html_entity_decode($part, ENT_QUOTES | ENT_HTML5, 'UTF-8');
$part = htmlspecialchars($decoded, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
}
unset($part);
// 4. Собираем обратно
return implode('', $parts);
}
private function truncateContent(string $html, int $maxLength): string
{
$dom = new \DOMDocument('1.0', 'UTF-8');
libxml_use_internal_errors(true);
$wrapped = '
' . $html . '
';
$dom->loadHTML($wrapped, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$xpath = new \DOMXPath($dom);
$node = $xpath->query('//div')->item(0);
$this->truncateNode($node, $maxLength);
return $dom->saveHTML($node);
}
private function truncateNode(\DOMNode $node, &$remaining)
{
if ($remaining <= 0) return;
foreach ($node->childNodes as $child) {
if ($child instanceof \DOMText) {
$text = $child->nodeValue;
$visible = mb_substr($text, 0, $remaining);
$hidden = mb_substr($text, $remaining);
if ($remaining < mb_strlen($text)) {
$child->nodeValue = $visible;
$remaining = 0;
// Создаём элемент для скрытой части
$hiddenNode = $child->ownerDocument->createElement('span');
$hiddenNode->setAttribute('class', 'hidden-text');
$hiddenTextNode = $child->ownerDocument->createTextNode($hidden);
$hiddenNode->appendChild($hiddenTextNode);
// Вставляем hiddenNode после текущего текстового узла
$parent = $child->parentNode;
if ($parent) {
if ($child->nextSibling) {
$parent->insertBefore($hiddenNode, $child->nextSibling);
} else {
$parent->appendChild($hiddenNode);
}
}
// Создаём кнопку "показать больше"
$button = $child->ownerDocument->createElement('a');
$buttonText = $child->ownerDocument->createTextNode('показать больше');
$button->appendChild($buttonText);
$button->setAttribute('class', 'toggle-message');
if ($parent) {
$parent->appendChild($button);
}
break;
}
$remaining -= mb_strlen($text);
} else {
$this->truncateNode($child, $remaining);
}
}
}
public function i()
{
$user = new User($this->c['user_id']);
$content = json_decode($this->c['content'], true);
$photo = new \App\Models\Photo($this->c['photo_id']);
$pinc = 'Закрепить';
echo '';
}
if ($content['filetype'] === 'video') {
echo '';
}
echo '
';
}
}
c['user_id'] === Auth::userid()) { ?> Редактировать
Удалить