+22.15
Рейтинг
88.90
Сила
  • avatar Chiffa
  • 2
оптимально будет так я думаю

{$layoutName = {cfg 'view.topic_list'}|default:'index'}
{extends "layouts/layout.$layoutName.tpl"}
  • avatar ff00
  • 3
Чтобы получилась такая ReCaptcha:
ReCaptcha

Регистрируешся тут: www.google.com/recaptcha/intro/

В header.tpl добавляешь в блоке head добавляешь
{if !$oUserCurrent}<script src='https://www.google.com/recaptcha/api.js'></script>{/if}


В том поле где у тебя стояла каптча, вместо каптчи пишешь:
<div class="g-recaptcha" data-sitekey="RECAPTCHA_PUBLIC_KEY"></div>


Где RECAPTCHA_PUBLIC_KEY — твой публичный ключ рекаптчи

В \engine\modules\validate\entity\ValidatorCaptcha.entity.class.php дописываешь функцию:
public function validateCaptcha() {
	$validateCaptcha = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=RECAPTCHA_SECRET_KEY&response='.$_POST["g-recaptcha-response"].'&remoteip='.$_SERVER['REMOTE_ADDR']);
	$validateCaptcha = json_decode($validateCaptcha);
	if(!$validateCaptcha->success) return false;
	return $validateCaptcha->success;
}


Где RECAPTCHA_SECRET_KEY — твой секретный ключ рекаптчи

В этом же файле в функцию validate, в проверку условия:
if (!isset($_SESSION['captcha_keystring']) || $_SESSION['captcha_keystring'] != strtolower($sValue))


до return, вписать:
if($this->validateCaptcha()) return true;


P.S. кому нужен плагин ГО ТО ФРИЛАНСЕРС job.livestreetcms.com к примеру Chiffa сделает за 3.5 минуты
Как вариант, можно простым css:

.table {
       counter-reset: schetchik;
}
.table tr {
       counter-increment: schetchik;
}
.table tr:before {
       content: counter(schetchik); 
}


":before" можно оформить как хочется.
  • avatar axmxvx
  • 1
В моем плагине кол-во блогов топика расширено до бесконечности. Заметил, что при 100+ блогах у топика сохранение после редактирования начинает подтормаживать. Разобрался — не оптимально сделан пересчет топиков в блогах. Предлагаю оптимизировать штатную функцию ЛС-а т.к. сам ЛС станет в этом моменте чуточку быстрее (на малом кол-ве блогов не видно, но все же):
if ($aBlogsIdOld != $oTopic->getBlogsId()) {
    $this->Blog_RecalculateCountTopicByBlogId($aBlogsIdOld);
}
$this->Blog_RecalculateCountTopicByBlogId($oTopic->getBlogsId());

Если пользователь из 5 блогов меняет 1, то пересчитываются 10 (5+5).
Если сделать так, то пересчитывать будет только уникальные т.е. 6 (5+1):
$aBlogsForRecalculate = $oTopic->getBlogsId();
if ($aBlogsIdOld != $oTopic->getBlogsId()) {
    $aBlogsForRecalculate = array_merge($aBlogsForRecalculate,$aBlogsIdOld);
    $aBlogsForRecalculate = array_unique($aBlogsForRecalculate);
}
$this->Blog_RecalculateCountTopicByBlogId($aBlogsForRecalculate);
Эээ нет. Вы кажется не поняли.
1. Директива try_files позволяет из директории сервера скачать любой файл. Именно для это вы добавляете вот этот костыль
location ~ \.(tpl|xml|log|sql)$ {
deny all;
}

— это очень плохой подход. Вы не можете знать о том, какие еще файлы могут оказаться в директориях движка и как доступ к ним может повлиять на безопасность. Пример: есть скрипты сканирующие стандартные директории типа config/ на предмет артефактов: config.php запрещен, ок, но у вас например не запрещены такие файлы как .swp .bak .~ и т.д., которые могут создаваться редакторами. А как насчет .gz? .backup? .old? Уверены? А если еще какой-то разработчик будет работать в директории он ничего не оставит? Поэтому такой подход очень плохой. Я запускаю скрипт который будет раз в минуту проверять создание копий config.php со всеми возможными расширениями, и как только он появится у меня будет пароль от БД. (примеров может быть сколько угодно).

2. Вот этот локейшен
location ~ \.php$ {


— разрешает выполнение ЛЮБОГО php файла в серверной директории. То есть представим такую ситуацию — в какой-нибудь поставке какого-нибудь плагина просто тупо лежит уязвимый php скрипт. Да можно хоть специально его туда подложить и раздавать на каких-нибудь левых ресурсах (например раздавать бесплатно платный плагин). Другой пример: предположим каким-то образом разрешена загрузка файлов с расширением php во временные директории внутри серверной директории и мы можем узнать имя файла после загрузки.

И самое главное что все это закрывается элементарно.
  • avatar CPClub
  • 0
Слушайте, ну нет тут никакой магии и фантастики. Просто есть определенные правила, стандарты и рекомендации.

www.youtube.com/playlist?list=PL2CvnqaI3Q1fNuq92sInzoIq-sUF0wNBd

support.google.com/webmasters/answer/35769/?hl=uk

www.google.com/intl/ru/webmasters/learn/

В том то и дело, что с помощью тегов и подсказываем поисковику, что именно важно, на что надо обращать внимание.

Для того, чтобы были поведенческие были надо, чтобы люди на сайт попали. Для того, чтобы люди поняли, что на сайте интересно — надо чтобы они на сайт попали.

Если поставить рядом два новых сайта один оптимизированный с качественным текстом к требования поисковых систем, а второй "… сам вылезет..." с качественным текстом. Вопрос. У какого быстрее пойдет посещаемость?

Все важно. Мелочей не бывает.

Если все так легко и просто в части добавления тегов в код, то почему разработчики шаблонов этого не сделали? Не добавили в описание «оптимизированный под поисковые системы»? И таки образом не создали новую добавленную стоимость к шаблону?

Сделайте эксперимент с Chaos to Block. Сделайте новый шаблон на базе этого, но проведите необходимые действия по сеооптимизации: отдельный отличный от заголовка тайтл и дискрипш не только для главной, но и для Топики, Люди, Категории, Активность, разметку правильную и увеличьте его стоимость пропорционально затраченному времени. И посмотрите результат в… рублях.

И. Я не сеошник. Я менеджер. Есть несколько проектов на разных CMS, которыми управляю, поэтому есть возможность сравнивать и делать выводы.
М.б. надо кому будет. Нужно было переопределить заголовок только на страницах плагина. (с сепоратором аналогично) Сделал так:

1) Главный файл плагина PluginName.class.php

protected $aInherits=array(
        'module'  =>array(
            'ModuleViewer'=>'_ModuleViewer'
        )
);


2) Создаем /plugins/name/classes/modules/viewer/Viewer.class.php

class PluginName_ModuleViewer extends PluginName_Inherit_ModuleViewer {
   
	public function AddHtmlTitleName($sText) {
		$this->sHtmlTitle=$sText;
	}

}


И уже в экшене /plugins/name/classes/actions/ActionName.class.php устанавливаем его

class PluginName_ActionName extends ActionPlugin {

    public function Init() {
        $this->SetDefaultEvent('index');
    }

    protected function RegisterEvent() {
        $this->AddEvent('index','EventName');
    }

    protected function EventName() {

            $this->Viewer_AddHtmlTitleName($this->Lang_Get('plugin.name.title')); // сюда
            $this->SetTemplateAction('index');    

    }

}
Тайм зоны изменились:
1.0.3 -> 2.0.0_dev (тут верные)
Помните «зимнее время» отменили, потом опять вернули?
А после того как вернули релизов LS больше не было… )
  • avatar vdenu
  • 0
Я как раз выкинул SEO, а SeoLib поднастроил. Самое ужасное, что делает Seolib — это в тело страниц добавляет ссылки, которые невидны, но якобы улучшают индексирование Sape… Это грубейшее нарушение, лечится настройках в конфиге. Там есть пункт в котором указанр количество спрятанных ссылок их надо обнулить. В остальном там по мелочи что-то было. Вообще в целом, использую его для заработка, но тоже что-то приходилось менять.
  • avatar oduvan
  • 4
Давайте вкратце объясню, как «устроен» аjax в LS, а вы решите, какой вариант лучше для вашей задачи. У вас замечательные шаблоны, и, возможно, вы решите их дополнить интерактивными фишками )
1. Вы делаете ajax запрос на сервер, передавая данные в get или post.
2. Ваш экшин получает эти данные, вы что-то с ними делаете, и формируете ответ клиенту (браузеру).
3. Ответ клиенту в LS имеет стандартный вид (вне зависимости, каким способом вы сделали запрос), это json-объект:
{
bStateError: false
data: true
sMsg: ""
sMsgTitle: ""
}


4. Разберем поля, и найдем откуда они берутся:
bStateError — признак несистемной ошибки. Т.е., вы просто хотите сказать пользователю, что его запрос ошибочен, но ошибка не критична (т.е., это не системная ошибка сервера, запрос обрабатывается корректно). Можно показать пользователю pop-up с сообщением об ошибке, или использовать в других целях, например, перебросить пользователя на другую страничку.
Что бы сформировать признак ошибки достаточно в Ивенте добавить «формирователь» ошибки, например:
$this->Message_AddErrorSingle('Ошибка! Вы не авторизованы!');

Этот формирователь ошибок сформирует корректный json ответ клиенту.
В поле sMsgTitle будет текст ошибки, а в поле bStateError — признак ошибки. Поле data будет пустым.
sMsg — поле тела сообщения об ошибке, формируется вторым параметром метода Message_AddErrorSingle. При желании.

data — поле с вашими json-данными для правильного, «безошибочного» ответа клиенту. Формируется методом Viewer_AssignAjax, например:
$this->Viewer_AssignAjax('data', $data);


Первый параметр метода отвечает за название поля, в котором будет находится json-ответ с данными, второй параметр — значение передаваемой переменной, объекта массива или чего-то, подлежащего преобразованию в json-объект.

Т.е., в data вы помещаете то, с чем хотите работать на клиенте.

5. Обработка данных на сервере.
К примеру, ваш Ивент имеет следующий вид:
    /**
     * Fetch all public Blogs
     */
    protected function EventFetchBlogs(){
        // Устанавливаем ответ типа JSON
        $this->Viewer_SetResponseAjax('json');
        // Берем текущего пользователя и проверяем,
        // залогинен ли он, и ялвяется ли администратором 
        $currentUser = $this->User_GetUserCurrent();
        if(!$currentUser or !$currentUser->isAdministrator()) {
            // Если нет, отправляем клиенту ошибку
            $this->Message_AddErrorSingle('Ошибка! Вы не залогинены или не являетесь админом!');
            return;
        }
        // Берем из базы все блоги, используя метод модуля SomeModule 
        // (предполагаем, что ответ — ассоциативный массив списка блогов)
        if(!$data = $this->PluginSomeplugin_SomeModule_getBlogs()) {
            // Если нет блогов, возвращаем пользователю ошибку
            $this->Message_AddErrorSingle('Ошибка! Блоги не найдены!');
            return;
        }
        // Вормируем сообщение о успешной находке блогов
        $this->Message_AddNoticeSingle('Блоги найдены!');
        // Помещаем в поле ajax ответа "data" наши найденные блоги (ассоциативный массив)
        $this->Viewer_AssignAjax('data', $data);
    }


6. Обработка данных на клиенте
Формируем «наш ajax».

// Параметры запроса. Будут преобразованы либо в строку для GET либо в тело для POST
var params = {
    //Какие-то пары ключ-значение для обработки на сервере
    width:1680,
    height:1050,
    //Обязательный параметр для корректной обработки запроса в LS.
    security_ls_key: _ВАШ_SEQURITY_LS_KEY_ОБЯЗАТЕЛЬНЫЙ_ПАРАМЕТР_
};
$.ajax({
    // Устанавливаем тип запроса
    type : 'GET',
    // Путь для Ивента
    url: 'http://site.tld/someplugin/someevent',
    // Данные запроса. Автоматически преобразуются либо в строку, либо в тело
    data: $.param(params),
    // При успешном запросе
    success : function(xhr){
        // Проверяем, есть ли от сервера какие-либо сообщения
        if(!!xhr.sMsg) {
            // Если установлен флаг ошибки, обрабатываем, как сообщение об ошибке
            // Если флага нет — значит это сообщение об успехе
            if(xhr.bStateError){
                 // Выводим сообщение об ошибке xhr.sMsg;
                console.debug('Сообщение об ошибке', xhr.sMsg);
            } else {
                // Выводим сообщение об успешном запросе xhr.sMsg;
                console.debug('Сообщение об успехе', xhr.sMsg);
            }
        }
        // Если есть какие-либо данные в поле дата
        if(xhr.data) {
            // Выводим содержимое поля data
            console.debug('Принятые данные', xhr.data);
        }
    },
    // При неуспешном запросе. LS умеет обрабатывать только ошибки 404
    error :  function () {
        if(xhr.status === 404){
            //Что-то делаем при системной ошибке 404
            console.debug('Системная ошибка!', xhr.status);
        }
    }
});
  • avatar vdenu
  • 1
Есть пара способов. Один такой. В ту часть шаблона куда надо вывести блок впишите примерно такой код:
{get_blocks assign='aBlocksLoad'}
				{if isset($aBlocksLoad.ВАШЕНАЗВАНИЕ)}
					{foreach from=$aBlocksLoad.ВАШЕНАЗВАНИЕ item=aBlock}
						{if $aBlock.type=='block'}
							{insert name="block" block=$aBlock.name params=$aBlock.params}
						{/if}
						{if $aBlock.type=='template'}
							{include file=$aBlock.name params=$aBlock.params}
						{/if}
					{/foreach}
				{/if}

Вместо ВАШЕНАЗВАНИЕ — задайте имя позиции латинским шрифтом (не заглавными буквами), обратите внимание, что это два раза надо сделать в коде. После этого в конфиге, в настройках блоков по аналогии со стандартным выводом в позиции right, сделайте вывод в вашей позиции. ))
Или попробуйте сделать вывод блока так:
{include file='blocks/block.ВАШБЛОК.tpl'}
  • avatar ff00
  • 0
Полностью избавился от ботов следующим образом. Расскажу образно:
— Изменил поле name у стандартной капчи
— Добавил капчу на добавление топиков (опционально для всего другого комменты, лс) для пользователей у которых рейтинг меньше 1 или меньше 20 сообщений или топиков, не суть.
— Если бот не вводит или не правильно вводит капчу 20 раз подряд, то перенаправляю все его запросы на страницу проверки на «человечность», там нужно 2 раза подряд ввести капчу после чего, если это человек сбрасываю его блокировку, но счетчик капчи запускаю по новой, чтоб не баловались.
— Некоторые запросы сразу отравляю на проверку человечности (к примеру запрос admin.php и IP сразу проверяется)
Капча простейшая, состоит из 3 цифр (чтоб не напрягать пользователей) и справляется на ура. Вносил изменения прямо в код движка, реализация простейшая, все работает на xcache или memcache. Кому нужно, помогу.
  • avatar gamabu
  • 0
Справиться с этим легко — достаточно подменить названия полей в форме комментариев. Для людей форма не изменится, а боты перестанут ее видеть. Ну а ручной спам отсеиваем, убрав из формы комментариев поле «Сайт». Работы на десять минут.
Давно папа не помогал)

Как вариант, можно сделать так:
{assign var=random value=1|mt_rand:15}
<img src="http://сайтец.ру/имаги/{$random}.png">

В папке имаги у нас будет допустим 15 изображений с именами с 1 до 15, с одинаковым расширением .png (или любое другое).
Если это для фона, то само собой делаете типа:
<div style="background:url(http://сайтец.ру/имаги/{$random}.png) no-repeat fixed center top">...</div>
  • avatar vOFFka
  • 0
В конец файла topic_part_footer.tpl шаблона добавляем:

{include file='blocks.tpl' group='topic-bottom'}


Содержимое файла HookSimilar.class.php плагина меняем на:

class PluginSimilar_HookSimilar extends Hook
{

    /**
     * Регистрируем хук на topic_show
     *
     * @return void
     */
    public function RegisterHook() {
        $this->AddHook("topic_show", "topicShowed", __CLASS__);
    }

    /**
     * Получаем список похожих топиков, передаем их в Viewer и добавляем нужный блок в сайдбар
     *
     * @param array $aVars
     */
    function topicShowed($aVars) {
        if (isset($aVars['oTopic'])) {
            $this->Viewer_AddBlock('topic-bottom', 'similarTopics', array('plugin' => 'similar', 'oTopic' => $aVars['oTopic']
                    ), Config::Get('plugin.similar.topics_block_priority')
            );
        }
    }

}
  • avatar vdenu
  • 1
Коллекцию топиков скорее вот так можно получить, т.т. функции GetTopicsOnlyPersonalByUser нет в природе… Опять же навскидку это всё, не проверял, но вроде правильно.
{assign var="aTopics" value=$LS->Topic_GetTopicsByFilter(['topic_publish'=>1,'user_id'=>$oUserProfile->getId(),'blog_type'=>['personal']],1,10)}}
  • avatar vdenu
  • 1
Хы… На самом деле вполне себе тривиальная задача. Можно и прямо в шаблоне это сделать (просто не очень кошерно будет. В шаблоне профиля, примерно так надо сделать. Пример навскидку.
{assign var="aTopics" value=$LS->Topic_GetTopicsOnlyPersonalByUser($oUserProfile->getId(),1,1,30)}
{if count($aTopics)>0}
<!-->Топики из персонального блога<--!>
{foreach from=$aTopics item=oTopic}
  <!-->А тут вывод топика<--!>
{/foreach }
 {/if}
github.com/livestreet/livestreet/blob/1.0.3-replication/engine/modules/text/Text.class.php#L144
Заменить
$sResult=$this->JevixParser($sResult);
на
if(!$this->User_GetUserCurrent()->isAdministrator()) {          
	$sResult=$this->JevixParser($sResult);
}