Preventing unwanted access I have some code that is helping to protect some online surveys. The surveys have an incentive in the form of an Amazon voucher or cash (which is manually/semi-automatically distributed post-survey) so as you can imagine, we get a lot of people attempting to get multiple vouchers, or undesirable respondents mainly from China.

Of course the main way to prevent this, is to send out unique links to a set of pre-recruited people, however this isn't always an option and hence the need for some kind of protection.

Here is the code, I've removed 2 SQL insert queries to reduce the size of this post:

$countryCode = sanitise($_SERVER["HTTP_CF_IPCOUNTRY"]);
$allowedCountries = getAllowedCountries($projectID); // array('GB', 'US', 'SE');

if(in_array($countryCode, $allowedCountries)) {

    // Count records with matching ip for this project, &gt;=1 TRUE, 0 FALSE
    $isBlocked = checkForBlockedIP($projectID, $ip);

    if($isBlocked == TRUE) {

        header("Location: error.php?blocked");

    } else {

        // Count records with matching ip for this project, &gt;=1 TRUE, 0 FALSE
        $isDuplicate = checkForDuplicateResponse($projectID, $ip);

        if ($isDuplicate == TRUE) {

            //&lt;Removed&gt;
            // Store identifying data into dup_attempts table
            // and block ip from further attempts

            header("Location: error.php?duplicate");

        } else {

            // Create redirect link and send user to it

            $redirectLink = $projectLink . $userID;
            header("refresh:3; url=" . $redirectLink . "");

        }

    }

}


I'm posting this here, because I'm not a professional developer and I don't know if I'm taking the right approach here. Perhaps my approach as a whole is wrong.

I'm allowing only certain countries to participate, checking for a duplicate IP (per project) and if one is found, then I'm storing it in a table for duplicate attempts and adding the IP to a blacklist for that project.
I agree with the comment above about IP-based restriction perhaps not being the best approach here, or at least not using it as the only means to detect duplicates.

I think GeoIP is reasonable for blocking at a country level (though certainly not foolproof).

I think IP address might be a reasonable component to duplicate detection.  You could also add other duplicate detection mechanisms including:


User ID (which is something you seem to have but are not using - I would think this would be most authoritative piece of information if there is authentication/login attached to this user ID)
setting a cookie
inspecting user agent
setting value in browser localStorage and then have browser add to request (localStorage is a little harder for a typical user to clear out than cookies)


With regards to the code itself, you should get in the practice of inverting conditions when you have large blocks of code nested in a conditional (or really just in general to provide clear, early exit paths from a section of code).

For example:

if(!in_array($countryCode, $allowedCountries)) {
    // set location header and exit
}
if (checkForBlockedIP($projectID, $ip)) {
    // set location header and exit
}
if (checkForDuplicateResponse($projectID, $ip)) {
    // set location header and exit
}
// happy path code follows


There is no reason for your else blocks at all here from what I can tell.  As a general rule of thumb, the less nested code and code branches you have, the less prone your code is to bugs, so you should actively look to design away such constructs where possible.