Вы не зашли.
А вот, собственно обновленный код, который заменяет старую функцию ipcheck():
global $ip, $mysql, $userROW, $rating_array; /* в $list_id массив со всеми News ID на странице */ global $list_id; $list_id =array(7,5,2,1,6);
if(is_array($list_id) && count($list_id)){ // проверяем что $list_id - это массив, в нем что-то есть =)
for ($a = 1; $a <= count($list_id); $a++) {
$out_db=$out_db."news_id='".$list_id[$a-1]."' or "; // создаем кусок запроса к БД: "news_id=xx or news_id=xx ...."
}
$rating_out_db=$mysql->select("select news_id from ".prefix."_rating WHERE (user_id='".intval($userROW['id'])."' or ip=".db_squote($ip).") and (".substr($out_db, 0, strlen($out_db)-3).")"); // ищем все новости из списка ID`шников, за которые голосовал этот IP
for ($a = 1; $a <= count($rating_out_db); $a++) {
$rating_array[$a]=$rating_out_db[$a-1]['news_id']; // создаем массив (глобальный) с ID`шниками новостей за которые голосовал этот IP
}
}
/* А эта функция, теперь тупо ищет ID запрашиваемой новости в глобальном массиве и возвращает true или false,
в зависимости от того, найдет ли в массиве ID запрашиваемой новости. Параметр $upd - как обычно, позволяет записать
голос в БД + удалить старые записи из БД(если прошло 24 часа после прошлого удаления)
*/
function ipcheck ($news_id, $upd) {
global $rating_array, $ip, $mysql, $userROW;
if(is_array($rating_array)){
$temp=intval(array_search($news_id, $rating_array));
}
if (is_array($rating_array) && isset($temp) && $temp) {
return true; // возвращаем скрипту истину - этот IP уже голосовал за новость
} else {
// не найдено - можно голосовать
if($upd) {
/* Сохраняем голос в базу данных : START */
$mysql->query("INSERT INTO ".prefix."_rating set user_id='".intval($userROW['id'])."', vote_date=".time().", ip=".db_squote($ip).", news_id=".db_squote($news_id));
/* Сохраняем голос в базу данных : END */
/* Удаляем старые записи : START */
if(intval(pluginGetVariable('rating', 'last_clear')) <= time()) { // проверяем промежуток времени очистки таблицы
$mysql->query('DELETE FROM `'.prefix.'_rating` WHERE `vote_date` < '.(time()-5184000).';'); // удаляем старые записи
pluginSetVariable('rating', 'last_clear', (time()+86400));
pluginsSaveConfig();
}
/* Удаляем старые записи : END */
}
return false; // возвращаем скрипту ложь - этот IP еще не голосовал за новость
}
}и оно как-то работает ![]()
с условием того что $list_id - это глобальный массив со всеми идентификаторами новостей на текущей странице, и скрипт должен получить его в самом начале...
Доступна для скачивания версия 0.9.3 Release Candidate 1 [SVN 856]
Ооо, это хорошо ![]()
vitaly, а список ID'шников всех новостей на странице в RC 1, до загрузки плагинов никак не получить?
Не реализовал ты эту фичу?
А то у меня уже функция почти готова, ей нужен только глобальный массив со всеми ID'шниками новостей на текущей странице, она делает один запрос и записывает в глобальный массив ID всех новостей за которые юзер голосовал, а при последующем обращении к функции запрашиваемый ID новости, не ищется в БД делая лишний запрос и создавая нагрузку, а ищется в глобальном массиве. Ну как-то так ![]()
ikv777vlg пишет:И за 6 обращений к функции, вывод в браузер получается такой:
1;
1;
1;2;
1;2;
1;2;5;
1;2;5;по 2 обращения на каждую новость
Вот именно, поэтому у тебя и запросы с дубликатами. Зачем у тебя два раза отрабатывает логика на каждую новость?
Долгая история...
Давно еще делал разные блоки голосования для короткой и полной новости, нужно было вывести в шаблон еще одно значение... и функция rating_show($newsID, $rating, $votes) вызывалась 2 раза..
Уже пофиксил, обошелся одним вызовом функции на одну новость, немного в ущерб дизайну(которого нет
), но суть дела не меняет:
1;
1;2;
1;2;5;
или
SQL queries:
[ 0.0003 ] select * from `ng_category` order by posorder asc
[ 0.0002 ] select * from ng_users where authcookie = '599386dbeb6845f459b6e226045a07c3' limit 1
[ 0.0005 ] SELECT * FROM ng_news WHERE (`approve` = '1') AND (`mainpage` = '1') order by ratesort desc, postdate desc limit 0,3
[ 0.0003 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='1'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='2'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='5'
[ 0.0002 ] SELECT count(*) as count FROM ng_news WHERE (`approve` = '1') AND (`mainpage` = '1')
Теперь по одному запросу на новость. Например - если 20 новостей на странице - плюс 20 запросов в БД ![]()
Wolverine пишет:Надо vitaly спрашивать о внедрении такой возможности в news_showone, которая отображает все новости. Данные нужные там есть, осталось из записать в какую-нить глобальную переменную, типа $SYSTEM_FLAGS
Ты хотел сказать news_showlist()?
Не прокатит, т.к. новости рендерятся по мере получения данных... хотя.. $mysql->select() ведь сразу всё в память выгружает.
В принципе можно сделать сканирование массива перед отрисовкой данных и всем плагинам сразу же давать список ID новостей, которые будут показаны в этом цикле.
Подумаю над идеей.
Точно. Ради интереса попробовал... Я в news.php в функции news_showlist() объявил глобальную переменную $list_id,
и после
foreach ($mysql->select($query['result']) as $row) {
$i++;
$nCount++;вставил
$list_id=$list_id.$row['id'].";";а в начало функции ipcheck() в rating.php вставил
global $list_id;
echo $list_id."<br />";И за 6 обращений к функции, вывод в браузер получается такой:
1;
1;
1;2;
1;2;
1;2;5;
1;2;5;
по 2 обращения на каждую новость
Vitaly, ты уж придумай что-нибудь ![]()
Надо vitaly спрашивать о внедрении такой возможности в news_showone, которая отображает все новости. Данные нужные там есть, осталось из записать в какую-нить глобальную переменную, типа $SYSTEM_FLAGS
А это ключ к успеху ![]()
Функция news_showone находится в news.php, нашел я ее, а как она работает, интересно...
Но она большая конечно ![]()
Вопрос в том, как получить список ID этих новостей, отображаемых на данной странице, чтобы засунуть их в глобальную переменную для последующего решения давать голосовать или нет.
Вот это я и хотел сказать ![]()
ikv777vlg, Делай лучше через join как vitaly написал. Запрос тогда получится как:
select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='1' and news_id='2' and news_id='5'Пример реализации есть в плагине lastnews...
А как понять and news_id='1' and news_id='2' and news_id='5', а если у меня 100 новостей, 500?
А за один раз как по всем новостям пройти, как запрос должен выглядеть? Чувствую такая реализация мне не по силам ![]()
Посмотрю что там в lastnews...
Уговорил ![]()
OK, но все равно попробую, так, ради интереса ![]()
ikv777vlg, Я своё сообщение дополнил.
Да я вижу
Но непонятно что-то, массив, цикл... Конструкция незнакомая, знаний PHP не хватает ..
Покурю мануал, попробую, отпишусь...
ikv777vlg, На счет скобок всё правильно.
$userROW['id'] так же как и $ip лучше обернуть, intval($userROW['id']) и db_squote($ip) они являются глобальными и их можно подменить другими значениями с другого плагина и лучше обезопасится.
Понятно ![]()
is_array($userROW) выдает ID пользователя, а что?
не, is_array определяет, является ли переданный параметр массивом
Вот это да
А я забыл, и машинально принял ее за обычную функцию, которая объявлена где-то в глубине CMS
Бывает же )))))))
А ты прикинь, я незалогинен - is_array($userROW) возвращает - 0, если залогинен под учетной записью администратора, у меня User ID = 1, и is_array($userROW) тоже возвращала 1, регистрация пользователей запрещена - никакого подвоха, так-бы всё и работало )))))))) ![]()
Не очень понятна:
(user_id='".intval(is_array($userROW))."'тут походу intval выручает))
Скорее:user_id='".intval($userROW['id'])."'и скобки не обязательны...
is_array($userROW) выдает ID пользователя, а что? Как было в плагине, так я и скопировал, я же не знаю до конца что там в массиве )))
Понял, значит будет $userROW['id'] а в intval() его обязательно оборачивать?
А насчет скобок, а разве без скобок получится? select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='1' - этот запрос должен найти в таблице все строки с полями user_id или ip с новостью news_id='1' а как-же без скобок? Или синтаксис неправильный?
Тогда делай один запрос пройдясь по всей таблице и запиши всё в одну переменную и по ней уже сравнивай все новости.
P.S. всего кода не вижу и подробнее написать не могу...
А что его смотреть, функция вызывается всего 3 раза:
1) При голосовании, когда проверяется - вдруг в браузере уже есть печенька, и за эту новость уже голосовали
2) При голосовании, после того как в браузер ставится печенька
3) И при выборе - что показать юзеру, звёзды или просто рейтинг, и это тот самый вариант вызываемый 6 раз:
if ((isset($_COOKIE['rating'.$newsID]) && $_COOKIE['rating'.$newsID]) || (extra_get_param('rating','regonly') && !is_array($userROW)) || ipcheck($newsID, 0)) { // ipcheck 3
// Show
$tpl -> template('rating', $tpath['rating']);
$tpl -> vars('rating', $tvars);
return $tpl -> show('rating');
} else {
// Edit
$tpl -> template('rating.form', $tpath['rating.form']);
$tpl -> vars('rating.form', $tvars);
return $tpl -> show('rating.form');
}Ну по-хорошему надо проверять и при заходе, чтобы пользователю показывать как именно он проголосовал.. но тут правильнее уже делать JOIN к основному select'у по новостям, не уверен что штатно это получится сделать.
JOIN к основному select'у
- непонятно ![]()
Надо, но походу и правда не получится, у меня есть вариант - показывать звезды только при просмотре полной новости, это как вариант... Т.е только при просмотре полной новости будет добавляться 2 запроса. И почему кстати их два??... Надо разбираться...
Так проверять нужно при нажатии, а не как только зайдет на сайт
Логично
Но, я проверяю для того, чтобы выдать или не выдать к новости "5 больших звезд" для голосования, а зачем пользователю опять показывать звёзды, если он уже проголосовал? Рейтинг-то отображается в процентах от 1 до 100...
Апдейт. Только так и больше никак, и IP, и ID пользователя надо учитывать, если он зарегистрирован.
function ipcheck ($news_id, $upd) {
global $ip, $mysql, $userROW;
/* Ищем в базе строку с текущими IP или User ID и News ID */
if($mysql->record("select * from ".prefix."_rating where (user_id='".intval(is_array($userROW))."' or ip='".$ip."') and news_id='".$news_id."'")) {
return true; /* Юзер уже голосовал за эту новость, возвращаем истину */
}
else {
/* Юзер еще не голосовал за эту новость */
if($upd){
if(intval(pluginGetVariable('rating', 'last_clear')) <= time()) { // проверяем промежуток времени очистки таблицы
$mysql->query('DELETE FROM `'.prefix.'_rating` WHERE `vote_date` < '.(time()-5184000).';'); // удаляем старые записи
pluginSetVariable('rating', 'last_clear', (time()+86400));
pluginsSaveConfig();
}
// далее голосуем
$mysql->query("INSERT INTO ".prefix."_rating set user_id='".intval(is_array($userROW))."', vote_date=".time().", ip='".$ip."', news_id='".$news_id."'");
}
return false;
}
}Вот только опять косяк у меня - 10 SQL запросов (time: 0.04 сек.) при загрузке главной страницы, и превью 3-х новостей, каждая новость добавляет два запроса! ![]()
SQL queries:
[ 0.0003 ] select * from `ng_category` order by posorder asc
[ 0.0002 ] select * from ng_users where authcookie = 'e20d1756ef6c888e3bd2a6ea99968536' limit 1
[ 0.0006 ] SELECT * FROM ng_news WHERE (`approve` = '1') AND (`mainpage` = '1') order by ratesort desc, postdate desc limit 0,3
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='1'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='1'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='2'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='2'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='5'
[ 0.0002 ] select * from ng_rating where (user_id='1' or ip='127.0.0.1') and news_id='5'
[ 0.0002 ] SELECT count(*) as count FROM ng_news WHERE (`approve` = '1') AND (`mainpage` = '1')
Вот такая колбаса! ![]()
Буду исправлять...
или давать возможность разным пользователям голосовать с одного IP
Получается, логичнее это делать только при включенной опции "Рейтинг только для зарегистрированных" в настройках плагина?
Стоп, а разве даже если включено - "Рейтинг только для зарегистрированных", в БД не пишется UserID того кто проголосовал за новости, а тоже только печенька в браузер ставится?
Тогда конечно надо сделать, мне это не нужно, но кому-нибудь обязательно пригодится!..
Опять-же, если зарегистрированному юзеру удалить куки, и войти на сайт, с одного ip, потом с другого(если у него динамический IP), и возможность проголосовать может то появляться, то пропадать, если IP найдется.
Отсюда вывод - поле UserID я оставлю, просто нужно искать и сравнивать результаты в БД как я и сказал раньше - и IP+NewsID, и UserID+NewsID вот и логика, хоть включай "Рейтинг только для зарегистрированных", хоть выключай, результат одинаковый - один IP несколько раз проголосовать за одну новость не сможет, и один UserID тоже ![]()
С другой стороны - если включено "Рейтинг только для зарегистрированных" то на IP можно вообще не обращать внимания, а делить голосующих по UserID... Надо выбрать какой-нибудь вариант.
Ой я пойду покурю... ![]()
В твоем случае UserID не нужен, один хрен разрешать голосовать или нет ты разрешаешь только по IP
Вот и я о том-же..
Да, но могут-же и несколько юзеров с одного IP на сайт заходить, желательно бы их всех различать, но это невозможно, если только дополнительные заголовки вместе с IP не считывать, или еще как-то ![]()
Значит я UserID убираю, хотя я подумаю еще над этим...
vitaly, спасибо, один я бы ничего не сделал, спасибо всем вам!
Wolverine, я всё слышал! ![]()
Понятное дело, надо как-то зарабатывать деньги, что-то делать.. Мне нужно сайт запустить, нужен был плагин, были трудности, я к вам обратился, вы мне помогли, с меня - как минимум, индексируемая ссылка с главной страницы моего сайта, или даже со статьи, разберемся. Если, конечно, я этот сайт когда-нибудь доделаю ![]()
В сапе я и сам буду ссылки продавать, хочу попробовать аккуратно всё это реализовать, и чтобы это был СДЛ, но на ngcms.ru ссылку поставлю в любом случае, дай Бог и мне ТИЦа высокого ![]()
Вообще у меня сейчас достаточно свободного времени, пока я просто не работаю, а работа у меня не легкая, и график даалеко не 8-ми часовой, так что незнаю что будет дальше, как минимум еще неделю я свободен, а потом у меня времени и сил будет в разы меньше..
Тут знаете сколько проблем, помимо тех что в виртуальной реальности? Много! И учиться надо, и работать... Я даже не считаю то что у меня сейчас на правой руке или сильный ушиб, или трещина в кости, рука болит, собственно по этому я и не работаю сейчас, зато мышку могу перемещать по коврику ![]()
Ой от души выговорился, мужики, извиняйте за оффтоп ![]()
Проекту помогу еще не раз, чем смогу, надеюсь не один сайт на NG CMS буду делать, будет дебаг, предложения и доработки всякие, замутим что-нибудь, это обязательно ![]()
А теперь по теме...
vitaly, как раз у меня к тебе вопрос. Вот ты писал недавно:
Imho, правильней хранить данные о каждом голосе.
newsID, userID, IP, voteDate
для незарегенного юзера userID будет нулевым.
тогда и проблема очистки будет решаться намного проще и конфликтов вида "двое нажали одновременно на <голосовать>, но только один из голосов появился в таблице" (если несколько человек сидят на одном сайте за NAT'ом) не будет
и поставил меня на путь истинный
, я немного переделал скрипт, добавил пару полей в БД всё работает, но...
Изначально в моей функции есть косяк. Я не пойму, причем тут User ID ? ![]()
Теперь получается что незалогиненный 127.0.0.1+UserID=0 проголосовал один раз за новость, потом вошел на сайт, и опять у него появляется возможность проголосовать за ту же новость, т.к. это уже 127.0.0.1+UserID=1
Что-то я не пойму логику, UserID надо или убрать, или делать как-то по другому ![]()
Запутался я короче говоря, или я неправильно тебя понял... ![]()
Хотя... Может писать в базу надо IP+UserID+NewsID а читать (IP+NewsID or UserID+NewsID) ?
А смысл? Опять я что-то не догоняю...
И еще... В rating.php перед "class RatingNewsFilter extends NewsFilter {" есть непонятный комментарий:
//
// ”Ё«мва ®ў®б⥩ (¤«п Ї®Є § ३⨣ )
//Из-за этого все комментарии в скриптах CMS на английском пишите? ![]()
Кстати, в при создании плагина, нельзя комментарии на кириллице писать? Или мне всё на английский переводить? ![]()
Имхо, надо-же определяться, если Win-1251 - значит Win-1251...
Юзеры чаще будут просто просматривать новость, чем голосовать, тем-более голосование вызывается аяксом, пока будет очищаться таблица, юзер будет видеть картинку "Loading..." в центре страницы, и в итоге получается такой принцип: "Проголосовал? Оставил свой IP в базе? По братски - удали старые записи из БД!"
И в итоге при загрузке страницы очистка никак не выполнится, и страница будет грузиться быстрее.
Так что, ИМХО, всё логично и оптимально ![]()
Напиши какие именно функции из extras.inc.php ты хочешь знать и на http://wiki.ngcms.ru/ я их распишу...
P.S. Только не надо говорить просто ВСЕ
Все и в extras.inc.php и в functions.inc.php, и везде где они есть ![]()
ROZARD, а если серьезно, спасибо конечно тебе, но я же не знаю где какая функция, и в какой момент она мне может пригодиться. Вдруг я решусь создать какой-нибудь полезный плагин и что-то смогу реализовать на чистом PHP, а окажется что это уже реализовано в функциях CMS. Так-что всё постепенно. А при изменении плагина, и так можно разобраться где находится вызываемая функция, и что она делает, хотя бывает трудно, даже с комментариями на английском. В этом случае буду спрашивать тут ![]()
Там вроде комментарии есть хорошие.
Например по теме:
// // Save configuration parameters of plugins (should be called after pluginSetVariable) // function pluginsSaveConfig($suppressNotify = false)
Согласен. Но попробуй встать на мое место, если я первый раз вижу строчку комментария "Save configuration parameters of plugins" я же не могу понять какие параметры сохраняются, что это за параметры такие, при знании PHP "со словарем"
В далеком будущем при детальном изучении работы CMS, что да как, эти вопросы может и отпадут, но пока мало что понятно. NG CMS вообще заинтересовала меня, и отсутствие красивого дефолтного шаблона меня не испугало, буду делать сайт на NG CMS, вроде всё что нужно в ней есть ![]()
А пока я попробую сделать еще что-нибудь хорошее в плагине rating, раз взялся, надо же попытаться его до ума довести! ![]()
ikv777vlg пишет:А вообще, не хватает документации по всем подобным функциям, которые можно вызывать в плагинах.
Или такая документация есть? Я просто не в курсе, уж извиняйтеЕсть http://wiki.ngcms.ru но она пока не полная...
Но ведь никто лучше создателей CMS не знает что там за функции в том-же, например extras.inc.php
, я заглянул туда, а там темный лес, черт ногу сломит с моими знаниями PHP, хотя некоторую информацию можно почерпнуть из комментариев на английском, это очень хорошо, но неудобно конечно ![]()
А теперь по сабжу. Я сделал вот так, вроде работает:
if(intval(pluginGetVariable('rating', 'last_clear')) <= time()) { // проверяем промежуток времени очистки таблицы
$mysql->query('DELETE FROM `'.prefix.'_rating` WHERE `vote_date` < '.(time()-5184000).';'); // удаляем старые записи
pluginSetVariable('rating', 'last_clear', (time()+86400));
pluginsSaveConfig();
}как всё просто ![]()
Вот только куда этот IF лучше вставить? Я считаю, что лучше обрабатывать его когда пользователь голосует($upd=1), а не после каждой проверки голосовал ли юзер ($upd=0). Тем-более при обычной загрузки новости, плагин всегда обращается к функции, делается выбор - просто показать рейтинг, или показать рейтинг+ссылки для голосования (если IP или печенька не найдена).
Пишите что еще не так, может где-то еще я был не прав ![]()
А как работать c pluginSetVariable() и pluginGetVariable()?
Вот так правильно?
pluginSetVariable('rating', 'last_clear', time()); // сначала создаем переменную и задаем ей значение
pluginsSaveConfig(); // где-то сохраняем :)
echo intval(pluginGetVariable('rating', 'last_clear')); // и в любой момент, из любого скрипта, считываем значениеПеременная last_clear будет храниться постоянно? А если она вдруг больше не нужна, как ее удалить, задать пустое значение, или еще как?
А вообще, не хватает документации по всем подобным функциям, которые можно вызывать в плагинах.
Или такая документация есть? Я просто не в курсе, уж извиняйте ![]()
Ах точно!... я тут чуть-чуть не выспался
, добавлю еще одно условие, очистку раз в сутки, как ты говоришь.
Действительно, с каждым голосом запускать очистку нет смысла, можно и раз в сутки, я же не корабль в космос запускаю, 1 день роли не сыграет.
Спасибо! ![]()
Ну вот
Я не стал искать проблем на причинное место, и решил не выходить за пределы моей функции ipcheck(), и всё реализовать в ней, и вот что получилось:
function ipcheck ($news_id, $upd) {
global $ip, $mysql, $userROW;
/* Ищем в базе строку с текущими IP, User ID и News ID */
if($mysql->record("select * from ".prefix."_rating where user_id='".intval(is_array($userROW))."' and news_id='".$news_id."' and ip='".$ip."'")) {
return true; /* Юзер уже голосовал за эту новость, возвращаем истину */
}
else {
/* Юзер еще не голосовал за эту новость, если параметр $upd = 1 голосуем и возвращаем ложь(на всякий случай),
а если $upd = 0 не голосуем, просто возвращаем ложь и в БД ничего не изменяем */
if($upd){
$mysql->query('DELETE FROM `'.prefix.'_rating` WHERE `vote_date` < '.(time()-5184000).';'); // удаляем старые записи
// далее голосуем
$mysql->query("INSERT INTO ".prefix."_rating set user_id='".intval(is_array($userROW))."', vote_date=".time().", ip='".$ip."', news_id='".$news_id."'");
}
return false;
}
}Она удаляет за собой старые записи в БД(более 2-х месяцев)!!! ![]()
Структуру таблицы ng_rating, которую использует эта функция, можно посмотреть в прикрепленном скриншоте.
Везде кроме IP я решил использовать INT(11), я думаю что этого хватит за глаза ![]()
Если я где-то ошибся - поправьте меня!
А вот мне интересно, (по совету Wolverine) при каждом успешном голосовании выполняется
$mysql->query('DELETE FROM `'.prefix.'_rating` WHERE `vote_date` < '.(time()-5184000).';');Правильно ли это? Не создаст лишнюю нагрузку?
ikv777vlg, now() пишется в самом запросе...
Не знал...
Можно и time(), только придется писать ".time()." а now() нужно без кавычек, и использоваться он может только при запросе к БД mysql... Надеюсь что я правильно понял ![]()
А now() и time() выдают один и тот-же результат - timestamp? Не "дд-мм-гггг"? (я просто еще не дошел до этого участка кода, не могу проверить)