Ограничение голосования по IP для easyComm

Хотел разместить в Готовые решения — но не хватает рейтинга. ЛожуОставлю тут — если покажется нужным — прошу перенести куда следует.


У клиента система оценки товаров/услуг построена на компоненте — easyComm.
Из-за частых «неположительных» оценках было поручено мне создать нечто, что ограничит голосование на N-ое количество дней. Предмодерация не подошла (как заявили — «предмодерация — говорит о ложных отзывах».

Я создал «это» на основе нескольких подсмотренных в сети кусков. Самое главное что работает)

Не судите строго — первый опыт написания сниппетов.

Создал сниппет — voting_ban:
<?php
// очищаем кеш 
$id = $modx->resource->get('id');
$docObj = $modx->getObject('modResource',$id);// $docObj - объект ресурса, кеш которого надо почистить
$key = $docObj->getCacheKey(); 
$cache = $modx->cacheManager->getCacheProvider($modx->getOption('cache_resource_key', null, 'resource'));
$cache->delete($key, array('deleteTop' => true));
$cache->delete($key);

//Получаем IP посетителя
$ip = $_SERVER['REMOTE_ADDR'];
//Получаем ID текущего ресурса
$id = $modx->resource->get('id');

//текущая дата
$today =  date('Y-m-d');

// сколько дней нельзя голосовать
$day = (isset($day)) ? $day : '7';

//действие при разрешённом голосовании
$unlock = (isset($unlock)) ? $unlock : '';


//вычисляем ПЕРВУЮ дату в периоде в котором нельзя голосовать повторно (вторая дата - текущая дата)
$date = date('Y-m-d',strtotime("-$day day", strtotime(preg_replace('~^(\d+)\.(\d+)\.(\d+)$~', '$3-$2-$1', $today))));

// отбираем записи  IP всех голосовавших с датой публикации больше ПЕРВОЙ для текущего ресурса
$sql = "SELECT C.ip AS ip FROM modx_ec_messages C LEFT JOIN modx_ec_threads D ON C.thread=D.id AND C.date>'$date'
WHERE D.resource =".$id ;
$q = $modx->prepare($sql);
$q->execute(array(0));
$arr = $q->fetchAll(PDO::FETCH_ASSOC);
foreach ($arr as $arr_one) {
    $tmpip = $arr_one["ip"];
    $allip[] = $tmpip;
}
//сравниваем IP посетителя с полученными 
 if (in_array("$ip", $allip)) {
    //Действие если запрещено
}
else{
    //Действие если разрешено
    print $unlock;
}
Параметры:
&unlock — действие при разрешённом голосовании (я поставил вызов формы для голосования)
&day — Количество дней в течении которого нельзя повторно голосовать

Я использую так:
[[!voting_ban? &unlock=`[[!ecForm?]]` &day=`7`]]

Надеюсь кому нибудь пригодится)

ps. Если профессионалы найдут ошибки, либо просто подскажу как улучшить/сократить код — буду рад)

UPD:
Всё что делает сниппет можно было прочесть по комментариям в коде, но продублирую (по просьбе трудящихся)
1) Определяем IP посетителя,
2) На основании параметра &day (по умолчанию 7 дней) вычисляем период в течении которого запрещено голосовать
3) Получаем список IP которые участвовали в голосовании в данный период времени для данного ресурса
4) Сравниваем текущий IP с выборкой — если не находим — показываем форму для голосования &unlock
Сергей
03 сентября 2016, 06:24
modx.pro
1 166
0

Комментарии: 8

Сергей Шлоков
03 сентября 2016, 08:46
0
Зачем это нужно понятно из названия. А что делает данный сниппет? Потенциальный пользователь данного решения должен копаться в коде, чтобы понять?
И ещё вопрос.
Ложу тут — если покажется нужным — прошу перенести куда следует.
В данном предложении как правильно читать — лОжу или ложУ?

П.С. Данное решение никак не тянет на готовое.
    Сергей
    03 сентября 2016, 09:25
    0
    Ок, пусть лежит тут — думаю всё же кому нибудь пригодится
    Сергей
    03 сентября 2016, 09:28
    0
    оффтоп
    В данном предложении как правильно читать — лОжу или ложУ?
    Как удобно так и читайте.
      Сергей Шлоков
      03 сентября 2016, 09:32
      0
      Если вам интересно, могу объяснить почему данное решение вряд ли кто будет использовать.
        Сергей
        03 сентября 2016, 09:39
        0
        Если Вас не затруднит
          Сергей Шлоков
          03 сентября 2016, 10:44
          1
          0
          Смотрите, Сергей, если задача — разрешить добавлять комментарий 1 раз в n дней, то решается она несколькими строчками.
          Вариант 1. Через сниппет как у вас.
          $sql = "SELECT 1 FROM modx_ec_messages C LEFT JOIN modx_ec_threads D ON C.thread=D.id
          WHERE D.resource = {$modx->resource->id} AND C.date>DATE_SUB(NOW(),INTERVAL {$day} DAY) AND ip = ?" ;
          $stmt = $modx->prepare($sql);
          $stmt ->execute($_SERVER['REMOTE_ADDR']);
          if ($stmt->rowCount() ) {
          	// Запрещено
          	return '';
          }
          // Выполняем указанные сниппет
          return $modx->runSnippet($snippet, $scriptProperties);
          Ну и вызывать так
          // Вместо unlock указываем snippet и любые другие параметры указанного сниппета
          [[!voting_ban? &snippet=`ecForm` &day=`7`]]
          Вариант 2. Через плагин.
          Если у этого компонента есть событие добавления комментария по аналогии с Tickets, то форма показывается, но при добавлении комментария плагин проверяет возможность добавления.

          Вот как минимум 2 варианта.
          П.С. Ещё было бы логично проверять почту. У пользователя ip может быть динамическим. А лучше разрешать оставлять отзыв только авторизованным пользователям. Тогда ещё проще.
            Сергей
            03 сентября 2016, 10:55
            0
            Спасибо за объяснение. Повторюсь — писал впервые из нескольких кусков.
              Сергей Шлоков
              03 сентября 2016, 11:31
              +1
              писал впервые из нескольких кусков
              Это очень заметно. Чисто для понимания давайте пробежимся по коду.
              // очищаем кеш
              Зачем?
              П.С. Вообще это можно сделать непрограммно — просто создавать некэшированные страницы. Но в данном случае не понятно, зачем это нужно.

              //Получаем ID текущего ресурса
              $id = $modx->resource->get('id');
              Зачем? В первой строчке уже получали.

              //текущая дата
              $today = date('Y-m-d');
              Зачем? В strtotime и так по умолчанию берется текущая дата.

              $date = date('Y-m-d',strtotime("-$day day", strtotime(preg_replace('~^(\d+)\.(\d+)\.(\d+)$~', '$3-$2-$1', $today))));
              Это вообще что за конструкция? Явно откуда-то скопирована без понимания. Хватило бы
              $date = date('Y-m-d',strtotime("-$day day"));
              Но и это лишнее, так как в mySql есть готовые функции для работы с датами.

              $tmpip = $arr_one[«ip»];
              $allip[] = $tmpip;
              А почему нельзя было написать так $allip[] = $arr_one[«ip»]?

              if (in_array("$ip", $allip)) {
              $ip нужно указывать без кавычек.

              print $unlock;
              Возврат значений из сниппета должен быть через return.

              Явно есть над чем поработать.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        8