Dołącz do zespołu ekspertów! Backend lub Frontend Developer?

Sprawdź najnowsze oferty pracy naszego partnera - 8lines.io!

Punktowanie postów

PHP/MYSQL  Założony przez  qwertyx.

Chce stworzyć system punktowania postów, niestety mam problem z zsumowaniem punktów od użytkowników, wystarczy, że jeden z użytkowników kliknie na dodaj pkt i już nikt więcej nie może dodać, w bazie zapisuje się liczba 2 i nie da się jej zwiększyć, ponowne kliknięcia nic nie dają, poniżej wrzucam część kodu, będę wdzięczny za wszelkie wskazówki...

if($mybb->input['action'] == "add")  {
        
         verify_post_check($mybb->input['my_post_key']);
        
           $field = $db->write_query("SELECT `vote` FROM `mybb_posts` WHERE `pid`='" . $mybb->input['pid'] . "'");
           $field = $field + 1;  
           $sql = $db->write_query("UPDATE `mybb_posts` SET `vote`='" . $field . "' WHERE `pid`='" . $mybb->input['pid'] . "'");
          
     $count = $db->write_query("SELECT `vote` FROM `mybb_posts` WHERE `pid`='" . $mybb->input['pid'] . "'");    

while ($row = $db->fetch_array($count)) {
    echo "punktow = ".$row['vote'];
    echo " dla pid = ".$mybb->input['pid'];
}                
    }
Spróbuj zamienić:
$field $db->write_query("SELECT `vote` FROM `mybb_posts` WHERE `pid`='" $mybb->input['pid'] . "'"); 
           
$field $field 1;  
           
$sql $db->write_query("UPDATE `mybb_posts` SET `vote`='" $field "' WHERE `pid`='" $mybb->input['pid'] . "'"); 
na:
$query $db->write_query("SELECT `vote` FROM `mybb_posts` WHERE `pid`='" $mybb->input['pid'] . "'"); 
           while (
$wiersz $db->fetch_array($query)) {
                      
$field intval($wiersz['vote']);
           }   
           
$field $field 1;  
           
$sql $db->write_query("UPDATE `mybb_posts` SET `vote`='" $field "' WHERE `pid`='" $mybb->input['pid'] . "'"); 
No i filtruj dane wejściowe, chyba że chcesz aby ktoś Ci zrobił potem "kuku".
Destroy666 - Wielkie dzięki działa
lukasamd - na razie od strony bezpieczeństwa nie zagłębiałem się za bardzo, ale z tego co wyczytałem w zapytaniach wystarczy użyć $db->escape_string?

Mam kolejny problem, a raczej brak pomysłu, na stworzenie blokady, gdzie każdy użytkownik, może jedynie raz głosować w jednym poście. Za bardzo nie wiem jak się za to zabrać :/
Byłbym wdzięczny za jakiekolwiek wskazówki, jak to zrobić. Mam nadzieję, że nie łamie regulaminu pisząc to nadal w tym temacie.
Tak, $db->escape_string powinno wystarczyć.

Mógłbyś np. utworzyć nową kolumnę 'whovoted', w której byłyby oddzielone przecinkami nicki jako stringi, do SELECT z 'vote' dodać też 'whovoted' i w pętli while eksplodować string $wiersz['whovoted'] w array. Następnie sprawdzić funkcją in_array czy $mybb->user['username'] w nim występuje - jeśli tak, zakończyć funkcję, jeśli nie dodać nick do arrayu funkcją array_push. Później funkcja implode na arrayu, no i przy zapytaniu UPDATE dodać string po implode do kolumny 'whovoted'.
Coś mi to nie działa, próbowałem różnych kombinacji, ale albo mi nie dodaje nicka do bazy albo dodaje cyfry zamiast username

$query = $db->write_query("SELECT `vote`,`voted` FROM `mybb_posts` WHERE `pid`='" . $db->escape_string($mybb->input['pid']) . "'");
           while ($wiersz = $db->fetch_array($query)) {
                      $field = intval($wiersz['vote']);
                      $check = explode(" ", $wiersz['voted']);
                      if (in_array($mybb->user['username'], $check)) {
                          error("Juz oddales glos. " . mysql_error());
                      }
                      else {
                       $uzy = array($mybb->user['username']);
                       $gnick = array_push($uzy, $check);
                       $nicki= explode(" ", $gnick);
                      }
           }  
           $field = $field + 1;  
           $sql = $db->write_query("UPDATE `mybb_posts` SET `vote`='" . $db->escape_string($field) . "',`voted`='" . $db->escape_string($nicki) . "' WHERE `pid`='" . $db->escape_string($mybb->input['pid']) . "'");
@qwertyx:
Jeżeli wiesz, że przewidywana wartość to liczba, to lepiej rzutować na int niż robić escape.


@Destroy666:
Nie przekombinowane to czasem? Lepiej już zebrać ID użytkowników i wrzucić to osobnej tabeli z najprostszą możliwą strukturą:
- pid (index, ale nie primary/unique, bo mogą się powtarzać)
- uid

I tyle... to jedno zapytanie więcej do pobierania wyników niewiele zmieni, a znacznie uprości inne operacje - sprawdzanie czy już głosował, usuwanie, dodawanie głosu. Zobacz ile jest roboty więcej przy napisie. Poza tym, tam dla bezpieczeństwa trzeba by dać minimum TEXT, tutaj będą kolejne rekordy.

A jak wyświetlać kto głosował? W postbit zbierać id postów. Potem na koniec, już nawet w innym hooku pobrać i podmienić jakiś kod - np. komentarz w HTMLu. To jest dobry sposób na obchodzenie problemów z hookami typu "pętla zapytań".
Racja, o wiele wiele lepiej byłoby zbierać i sprawdzać uid niż nicki (nie wziąłem też innej rzeczy pod uwagę - kod byłby błędny gdyby ktoś miał przecinek lub w przypadku kodu qwertyx spację w nicku, o ile się nie mylę w przypadku nicków trzeba by było użyć unserialize/serialize lub czegoś podobnego). Tu rzeczywiście przekombinowałem.

Ale co do utworzenia nowej tabeli już nie byłbym taki pewien czy to coś polepszy/przyspieszy, nie za bardzo widzę różnicę pomiędzy dwoma dodatkowymi kolumnami w domyślnej tabeli MyBB oraz trzema w nowej, może dlatego że nie wiem czy do końca rozumiem Twoje rozwiązanie.

@qwertyx, spróbuj:
$query $db->write_query("SELECT `vote`,`voted` FROM `mybb_posts` WHERE `pid`='" $db->escape_string($mybb->input['pid']) . "'"); 
           while (
$wiersz $db->fetch_array($query)) {
                      
$field intval($wiersz['vote']);
                      
$check = array();
                      if (
$wiersz['voted']) $check explode(","$wiersz['voted']);
                      
$uzy $mybb->user['uid'];
                      if (
in_array($uzy$check)) {
                           
$uidstring $wiersz['voted'];
                           
error("Juz oddales glos. " mysql_error());
                      }
                      else {
                           
$uidarray array_push($check$uzy);
                           
$uidstring implode(","$uidarray);
                      }
           }   
           
$field $field 1;  
           
$sql $db->write_query("UPDATE `mybb_posts` SET `vote`='" $db->escape_string($field) . "',`voted`='" $db->escape_string($uidstring) . "' WHERE `pid`='" $db->escape_string($mybb->input['pid']) . "'"); 
Głównym problemem w kodzie było użycie explode zamiast implode i do bazy nie wstawiał się string. Przed testowaniem wyczyść całkowicie kolumnę 'voted' i powinno zadziałać.
Przekombinowaniem jest w ogóle stosowanie nicków do identyfikacji, bo do tego powinno się używać tylko i wyłącznie ID (ktoś zmieni nick i wszystko się posypie) :P

(02.08.2013, 13:17)Destroy666 napisał(a): Ale co do utworzenia nowej tabeli już nie byłbym taki pewien czy to coś polepszy/przyspieszy, nie za bardzo widzę różnicę pomiędzy dwoma dodatkowymi kolumnami w domyślnej tabeli MyBB oraz trzema w nowej, może dlatego że nie wiem czy do końca rozumiem Twoje rozwiązanie.
Z pewnością bardziej przejrzyście - do zliczania, usuwania konkretnego głosu czy innych operacji wystarczy proste zapytanie, bez potrzeby rozbijania tego dodatkowo w PHP. W rozwiązaniu @lukasamd jeśli będziesz chciał za jednym zamachem pobrać głosy i nicki użytkowników (+linki do profilów, avatary, hulaj dusza), wszystko załatwisz jednym zapytaniem ;)
Destroy666
Coś mi to działać, nie chce. Nic nie dodaje do kolumny voted. Trochę dziwnie dla mnie wygląda ta część kodu
if ($wiersz['voted']) $check = explode(",", $wiersz['voted']);
Czy na pewno ona jest dobrze?


Jeżeli ręcznie dodam w bazie danych uid uzytkownika, to nie mogę już więcej głosować, więc błąd jest po stronie dodawanie uid do kolumny voted :/

//edit
Zadziałało, gdy zmieniłem jedną linijkę na
$uidarray = array_merge($check, array($mybb->user['uid']));
(02.08.2013, 13:35)Devilshakerz napisał(a): Przekombinowaniem jest w ogóle stosowanie nicków do identyfikacji, bo do tego powinno się używać tylko i wyłącznie ID (ktoś zmieni nick i wszystko się posypie) :P

No tak, przyznałem rację, tamto rozwiązanie pisałem na szybko i raczej niezbyt przemyślanie. Nie ma sensu wstawiać nazw,

(02.08.2013, 13:35)Devilshakerz napisał(a): Z pewnością bardziej przejrzyście - do zliczania, usuwania konkretnego głosu czy innych operacji wystarczy proste zapytanie, bez potrzeby rozbijania tego dodatkowo w PHP. W rozwiązaniu @lukasamd jeśli będziesz chciał za jednym zamachem pobrać głosy i nicki użytkowników (+linki do profilów, avatary, hulaj dusza), wszystko załatwisz jednym zapytaniem ;)

Bez nowej tabeli też da się to zrobić jednym zapytaniem, a dodatkowy PHP nie jest jakiś bardzo wymagający. Jeśli chodzi o przejrzystość - zgadzam się, ale to tylko na razie dwie kolumny (jedna zresztą chyba niepotrzebna, bo można policzyć głosy przeliczając uid w arrayu).

(02.08.2013, 14:00)qwertyx napisał(a): Zadziałało, gdy zmieniłem jedną linijkę na
$uidarray = array_merge($check, array($mybb->user['uid']));

Hmmm, ciekawe, ktoś wyjaśni dlaczego array_push w moim poprzednim poście nie zadziałał poprawnie?
(02.08.2013, 20:53)Destroy666 napisał(a): Hmmm, ciekawe, ktoś wyjaśni dlaczego array_push w moim poprzednim poście nie zadziałał poprawnie?

array_merge() zwraca połączoną tablicę, array_push() - końcową liczbę elementów (modyfikuje tablicę podaną jako pierwszy argument, więc nie trzeba do niczego przypisać). Jest trochę takich kwiatków w funkcjach PHP, trzeba dokładnie czytać notki w manualu przed użyciem jakiejś.
Niestety mam kolejny problem
Chce utworzyć kolory głosów: zielony dla dodatnich, czerwony dla ujemnych

Po obliczeniu $field dodaje takie kod
if($field  > 0)  {
           $bgvote = "voteplus";
            }    
           if($field < 0)  {
           $bgvote = "voteminus";
           }
           eval("\$votes .= \"".$templates->get("postbit_vote")."\";");

Następnie tworzę szablon postbit_vote, umieszczam oto taki kod
Cytat:<style>
.voteplus {
background: green;
padding:5px;
color: #fff;
}
.voteminus {
background: red;
padding:5px;
color: #fff;
}
</style>
Liczba głosów: <div class="{$bgvote}">{$post['vote']}</div>

Następnie w szablonie postbit_classic dodaje {$votes}

Niestety nie działa mi to, a w podobny sposób tworzyłem szablon do statystyk pliku stats.php

Rozumiem, że podczas wczytywania tematu, nie jest wczytywany plik increment.php? Czy błąd jest w kodzie?



Użytkownicy przeglądający ten wątek:

2 gości