Я работаю над системой голосования с Laravel, я хочу, чтобы гость голосовал только один раз в день. Это нормально работает, если они находятся в сети Wifi, как вы можете себе представить, поскольку они всегда имеют один и тот же IP-адрес. Но я попробовал с моей 4G Network, и, поскольку мы меняем IP каждый раз, когда мы повторно используем 4G, это не работает. Я почти уверен, что нет никакого способа сделать это вообще, лучше всего иметь учетные записи для голосования, и только учетные записи будут допущены к голосованию. Но это не совсем то, что я хочу.
Вот то, что у меня есть сейчас, если вам нужна идея:
Миграция:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateGuestsVotesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('guests_votes', function (Blueprint $table) {
$table->bigIncrements('id');
$table->ipAddress('ip');
$table->bigInteger('candidate_id')->unsigned();
$table->timestamp('updated_at');
$table
->foreign('candidate_id')
->references('id')
->on('candidates')
->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('guests_votes');
}
}
И во всем мире я сделал Guest Singleton для управления голосами:
<?php
namespace App\Library;
use App\GuestVote;
/**
* Singleton class to manage Guest vote
*
* @package App\Library
*/
class Guest {
/**
* @var Guest
*/
private static $instance;
/**
* IP of the guest
*
* @var string
*/
private static $ip;
protected function __construct()
{
Guest::$ip = \Request::ip();
}
/**
* Singleton, retrieve only one instance
*
* @return Guest
*/
public static function getInstance(): Guest
{
if (empty(Guest::$instance)) {
Guest::$instance = new Guest();
}
return Guest::$instance;
}
/**
* Guest can vote for this candidate ?
*
* @param \App\Candidate $candidate
* @return bool
*/
public function canVote($candidate)
{
if (!($candidate instanceof \App\Candidate)) return false;
$guestVote = GuestVote::where([
'ip' => Guest::$ip,
'candidate_id' => $candidate->id
])
->select([
'ip',
'candidate_id',
'updated_at'
])
->first();
if (!$guestVote || now()->greaterThan($guestVote->updated_at->addDay(1))) return true;
return false;
}
/**
* Vote for a candidate
*
* @param Illuminate\Database\Eloquent\Builder|Illuminate\Database\Eloquent\Model|object|\App\Candidate|\App\Candidate[]|Illuminate\Database\Eloquent\Collection $candidateVote
* @throws \Exception
*/
public function vote($candidateVote)
{
if (!$candidateVote) return;
$candidates = [];
if ($candidateVote instanceof \App\Candidate) {
$candidates[] = $candidateVote;
} else {
$candidates = $candidateVote;
}
foreach ($candidates as $candidate) {
if (!Guest::canVote($candidate)) continue;
$guestVote = GuestVote::firstOrNew([
'ip' => Guest::$ip,
'candidate_id' => $candidate->id
]);
try {
\DB::beginTransaction();
$candidate->increment('votes');
$guestVote->touch();
$guestVote->save();
$candidate->save();
\DB::commit();
} catch (\Exception $e) {
\Log::error('Error while Guest was voting : ' . $e);
\DB::rollBack();
}
}
}
}
Все работает нормально, пока я не использую свою сеть 4G. Если у вас есть идеи, как мы можем ограничить даже сети 4G? Я пытался выяснить, не можем ли мы получить MA C адрес устройства, но, к сожалению, нет: (
Спасибо