Авто анонс

Задумался о добавлении возможности создания анонса. Полез в код… Оказывается, в ливстрит есть все, что нужно для создания анонса! Максу респект!

Но просто добавить новое поле в форму добавления топика мне показалось мало. Точнее я передумал. =)))

Вместо ручного добавления анонса решил сделать авто обрезание текста топика. Варианта три:

1) Отрезать определенное количество символов и тупо ставить троеточие.
2) То же самое, но до первого пробела. В этом случае целостность слов сохраняется.
3) То же самое, но до первого знака окончания строки. :)

Первый тупой и простой никому давно не интересен, поэтому расскажу, как сделать второй и третий.
Заходим в файл \classes\actions\ActionTopic.class.php

Находим строки 386 и 536 с текстом:

$sTextShort=$sText;

Вариант 2. Меняем их на:

// Ищем первый пробел в строке, начиная с 200 по направлению к началу
$sTextShort = substr ($sText, 0, 200 - strlen (strrchr (substr ($sText, 0, 200), ' ')));


Вариант 3. Меняем строки 386 и 536 на:

// Обрезаем все, что больше 200 символов, но только после точки (или других знаков окончания предложения)
preg_match("/.{200}[^.!;?]*[.!;?]/si", $sText.". ", $matches);
$sTextShort = $matches[0];


* * * * UPDATE * * * *

Чтобы была возможность использовать настройку этого хака — либо «да», либо стандартный cut, делаем нижеследующее.

Добавляем в config.php строчку:

define('BLOG_TOPIC_CUT',200); // 0 - используем стандартный cut, больше 0 - обрезаем анонс после этого символа.

Соответственно исправляем в \classes\actions\ActionTopic.class.php:

if (BLOG_TOPIC_CUT > 0 and strlen($sText) > BLOG_TOPIC_CUT) {
	// Обрезаем все, что больше BLOG_TOPIC_CUT символов, но только после точки (или других знаков окончания предложения)
	preg_match("/.{".BLOG_TOPIC_CUT."}[^.!;?]*[.!;?]/si", $sText.". ", $matches);
	$sTextShort = $matches[0];
} else {
	$sTextShort = $sText;
}


* * * * UPDATE 2 * * * *

Если не хотим «портить» конфиг и нас устраивает условие «есть кат — ничего не трогаем, нет ката — обрезаем» — тогда этот вариант для вас. Редактируем только "\classes\actions\ActionTopic.class.php", заменив "$sTextShort=$sText;" из строк 386 и 536 на:

if (strstr ($sText, '<cut>') or strlen ($sText) <= 200) {
	$sTextShort = $sText;
} else {
	// Обрезаем все, что больше 200 символов, но только после точки (или других знаков окончания предложения)
	preg_match("/.200[^.!;?]*[.!;?]/si", $sText.". ", $matches);
	$sTextShort = $matches[0];
}

71 комментарий

avatar
это автокат что ли?
avatar
Ну можно и так сказать. Смысл в том, чтобы анонсы были примерно одного размера. :)
avatar
отлично! спасибо. в избранное.
avatar
Чет не добавляются новости с этим хаком. Пишет:
Notice: Undefined variable: sTextNew in /var/www/tpLVTg/tp.ks.ua/classes/actions/ActionTopic.class.php on line 404
SQL Error: Column 'topic_text' cannot be null at /var/www/tpLVTg/tp.ks.ua/classes/modules/topic/mapper/Topic.mapper.class.php line 64
Array ( [code] => 1048 [message] => Column 'topic_text' cannot be null [query] => INSERT INTO prefix_topic_content (topic_id, topic_text, topic_text_short, topic_text_source, topic_extra ) VALUES
avatar
Что такое sTextNew?
avatar
Судя по ошибке, у вас в поле topic_text пишется пустое значение. А такого быть не должно! И мы трогаем не его, а topic_text_short. Переменная sTextShort.
avatar
наткнулся на еще один подводный кол, при редактировании админом топика, который уже был создан (при первом создании автоматом создается кат), кат убирается, и топик висит во весь рост без ката. Это решаемо?
avatar
отлично вообще
avatar
Отлично, давно ломал голову как єто сделать, спасибо!
avatar
Респект автору!!!
avatar
Ага, спасибо! :)
avatar
Хорошо бы еще оставить альтернативную возможность самому кат сделать ;-)
avatar
поддерживаю, необходимо
avatar
Добавил. UPDATE. :)
avatar
сложным путем пошли :)

я скорее предполагал вариант когда кат работает автоматически постоянно, но если вставляешь его вручную, то используется ручной :)
avatar
Можно и так, но в конфиг все равно выносить кол-во символов. :)
avatar
Так было бы более оптимально.
avatar
Основная идея — примерно одинаковые по длине анонсы. Кат же могут поставить как угодно и где угодно.
avatar
Кстати, да. Все так и есть — если нету ката, обрезается константой, если есть кат — работает он. Я именно так и хотел. Спасибо :)
avatar
Тогда вставляем проверку типа:
if (strstr ($sText, '<cut>')) {
avatar
Чего-то нехватает: если создать и сохранить материал, то обрезается все отлично. Но стоит отредактировать топик, как эффект автоанонса улетучивается. Или это только у меня так?
avatar
Упс. ))
Ща исправим…
avatar
Нужно аналогично отредактировать функцию SubmitEdit этого же класса.
avatar
Да.
avatar
В том же файле в функции SubmitEdit нужно также заменить $sTextShort=$sText; на то, что описано выше. )
avatar
Спасибо все равно :)
avatar
Не за что. :)
avatar
Спасибо за хак. Возможно в определенных проектах будет полезен.

P.S. Считаю, что пользователь сам должен определять когда необходимо ставить «cut».
avatar
Зависит от проекта, конечно. И от дизайна. Если хочется все ровно и красиво, неблогоподобно, тогда кату нет. :)
avatar
Нашел косячок в 3-м варианте. Если длина текста меньше длины анонса, вылетает ошибка и в базу пишется пустое значение. Расширяем проверку:

if (BLOG_TOPIC_CUT > 0 and strlen($sText) > BLOG_TOPIC_CUT) {
avatar
strlen на мультибайтовых строках показывает значение длины в 2 раза меньше реального
avatar
От жеж редиска! Ё!
Просто у мну нет мультибайтовых строк, т.к. хостер не дает, и я от них вообще избавился и всё работает. :)
avatar
function WinToUtf8($s) {
  $t = '';
  for ($i = 0, $m = strlen($s); $i < $m; $i++) {
    $c = ord($s[$i]);
    if ($c <= 127) { $t .= chr($c); continue; }
    if ($c >= 192 && $c <= 207) { $t .= chr(208) . chr($c - 48); continue; }
    if ($c >= 208 && $c <= 239) { $t .= chr(208) . chr($c - 48); continue; }
    if ($c >= 240 && $c <= 255) { $t .= chr(209) . chr($c - 112); continue; }
    if ($c == 184) { $t .= chr(209) . chr(209); continue; };
    if ($c == 168) { $t .= chr(208) . chr(129); continue; };
  }
  return $t;
}

function Utf8ToWin($fcontents) {
    $out = $c1 = '';
    $byte2 = false;
    for ($c = 0;$c < strlen($fcontents);$c++) {
        $i = ord($fcontents[$c]);
        if ($i <= 127) {
            $out .= $fcontents[$c];
        }
        if ($byte2) {
            $new_c2 = ($c1 & 3) * 64 + ($i & 63);
            $new_c1 = ($c1 >> 2) & 5;
            $new_i = $new_c1 * 256 + $new_c2;
            if ($new_i == 1025) {
                $out_i = 168;
            } else {
                if ($new_i == 1105) {
                    $out_i = 184;
                } else {
                    $out_i = $new_i - 848;
                }
            }
            $out .= chr($out_i);
            $byte2 = false;
        }
        if (($i >> 5) == 6) {
            $c1 = $i;
            $byte2 = true;
        }
    }
    return $out;
}


И прощай mb_string! :)
avatar
Но кроме того, что нет mb_string, нет и iconv, которой обходится отсутствие mb в ЛС. Вот и изголяюсь. (((
avatar
кодировка у тебя UTF? значит и текст мультибайтовый
avatar
utf. наверное, есть. я всё дальше отхожу от кодинга (что радует), многое забывается…
avatar
вроде как кроме цифр и латиницы
avatar
ну исходим из того, что сайт на русском языке и в тексте топика количество латиницы пренебрежимо мало :)
avatar
Есть «костыль», как посчитать кол-во символов в мультибайтовой строке?
avatar
// choice 1
function utf8_strlen($str) {
  $count = 0;
  for ($i = 0; $i < strlen($str); ++$i) {
    if ((ord($str[$i]) & 0xC0) != 0x80) {
      ++$count;
    }
  }
  return $count;
}

// choice 2
function utf8_strlen($str) {
  return preg_match_all('/[\x00-\x7F\xC0-\xFD]/', $str, $dummy);
}


Вроде работает…
avatar
А точно mb_string не работает? Если написать mb_strlen($str), то ругается?
avatar
У меня — да. Если у вас mb стоит — возрадуйтесь! :)
avatar
Удивительно, 21 век на дворе…
avatar
Не в Норвегии. =)
avatar
Хостинг проще сменить чем страну :-)
avatar
странно, способ «UPDATE 2» — вызвал ошибку при добавлении поста.
а способ из «update» — сразу заработал, им и пользуюсь :)
Автору огромное спасибо!
avatar
Для устранения ошибки в UPDATE 2 следует писать такой код:
if (strstr ($sText, '<cut>') or strlen ($sText) <= 200) {
        $sTextShort = $sText;
} else {
        // Обрезаем все, что больше 200 символов, но только после точки (или других знаков окончания предложения)
        preg_match("/.{200}[^.!;?]*[.!;?]/si", $sText.". ", $matches);
        $sTextShort = $matches[0];
}

Автор забыл в строке…
preg_match("/.200[^.!;?]*[.!;?]/si", $sText.". ", $matches);

… число (в данном случае 200) заключить в фигурные скобки.

Я у себя на проекте заключил — все работает.
Автору плюс. Т.к. очень нужная для мну штука. Благодарствую.
avatar
А можно ли сделать кат не по колличеству символов, а по высоте блока. Например, чтобы отрезало когда пост больше 150px?
avatar
Как вы себе это представляете? :)
Тогда для «резиновых» сайтов придётся и ширину, и высоту учитывать. :)
avatar
Я как раз и не представлял как это сделать, потому и спросил.
СПС за ответ
avatar
это можно через цсс сделать, сделать отдельный класс для блока в темплейте вывода всех постов для отдельного поста и в нём что то такое max-height:150px; overflow-y:hidden; и если текста будет больше чем на 150 пикселей в высоту они будут просто не видны. если ограничиться еще кол-вом символов, то те несколько строк лишнего текста не будут мешать
avatar
Вдруг обратил внимание на странную вещь. Я ставлю у себя кол-во символов 3000 до автовставки тега cut. Но почему то вставляется в р-не 1700-го символа. Если ставлю 2000 символов ограничение — обрезается в р-не 1200 символа. В чем подвох? оО
  • g3n0m
  • 0
avatar
Пробелы считаешь?
avatar
Эээ… признаться честно — не знаю. Судя по кол-ву выводимых перед катом символов — не считает. Тогда встречный вопрос — как посчитать и их тоже?
avatar
Ну я имею ввиду как вы определяете что выводит 1200 вместо 2000? Измеряете на выходе функцией strlen? Или как?
avatar
в редакторе (notepad++) смотрю сколько выводит символов перед катом ))
avatar
на сколько я понимаю такая разница происходит из-за того что функция preg_match встроенная в php по разному отрабатывает символы кириллицы и латиницы.
Потому как в том же notepad++
Для латинского текста вывел 1019 chars 1029 bytes
Для кирилицы — 556 chars 1018 bytes
Скорее всего константа BLOG_TOPIC_CUT для preg_match в строке
preg_match("/.{".BLOG_TOPIC_CUT."}[^.!;?]*[.!;?]/si", $sText.". ", $matches);
Указывает кол-во байт а не символов.
Подскажите гуру php как побороть данный вопрос?
avatar
Как вариант:
mb_ereg_match("/.{".BLOG_TOPIC_CUT."}[^.!;?]*[.!;?]/si", $sText.". ", $matches);
$sTextShort = $matches[0];

заменить на
$tmp_str = iconv("UTF-8", "CP1251", $sText);
preg_match("/.{".BLOG_TOPIC_CUT."}[^.!;?]*[.!;?]/si", $tmp_str.". ", $matches);
$sTextShort = iconv("CP1251", "UTF-8", $matches[0]);

Проверил для русского текста результат 1004 char 1816 bytes при настройке BLOG_TOPIC_CUT — 1000.

Для предыдущего комментария BLOG_TOPIC_CUT тоже 1000.
avatar
Корректируем
$tmp_str = iconv(«UTF-8», "CP1251", $sText);
в
$tmp_str = iconv(«UTF-8», "CP1251//IGNORE", $sText);
чтобы не было
iconv() [function.iconv]: Detected an illegal character in input string
avatar
К сожалению публикации меньше заданного чиста символов BLOG_TOPIC_CUT выдают ошибку :(
avatar
Вот кстати с модулем какой глюк вылез livestreet.ru/blog/questions/3068.html
avatar
а для версии 0.4 как подправить?
avatar
Ребята, а как сделать авто анонс для версии 0.4.2? Может кто-то делал, помогите советом или примером. Это актуально для владельцев версии 0.4.2.
avatar
точно-точно) поддерживаю 2 топика выше)
avatar
+1 к вышесказанному
avatar
напишите пожалуйста как работает на текущей версии: LiveStreet 0.4.2?
avatar
Здесь уже встроенная функция cut есть.
Просто заключите нужный текст в тег при создании топика :)
avatar
Вот тег:
<cut> 
:)
avatar
avatar
Пользователи могут пользоваться тего кат не так, как хочется автору проекта, лучше обрезать столько символов, сколько нужно. Млм.
avatar
Автор ты просто красавчиг! Если робит тему надо прикрепить ))) Ой блин сорь рефлекс)
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.