Ограничение голосования по 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
440
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.

          Явно есть над чем поработать.