Q:

Can web robots inflate download counts?

I have a PHP program connected to an MYSQL database on a website.
Upon clicking a link to download a file, the program reads an integer field from the database, increments it, then puts the number back, to count the number of downloads.  That program works.  The download counts, however, over time, seem to be moderately inflated.  
Could the download counts be incremented by web robots following the links to download the files?  If so, would telling the web robots to ignore the download page on the website, using the robots.txt file, solve the inflated count problem?
Here is the PHP code:
function updateDownloadCounter($downloadPath, $tableName, $fileNameField, $downloadCountField, $idField) 
{

require("v_config.php");

if(isset($_REQUEST["file_id"]) && is_numeric($_REQUEST["file_id"])) {   

    try
    {
        $sql = "SELECT * FROM " . $tableName . " WHERE file_id = " . $_REQUEST[$idField];
        $connection = new PDO($dsn, $username, $password, $options);    
        $statement = $connection->prepare($sql);
        $statement->execute();

        $result = $statement->fetchAll();

        if ($result && $statement->rowCount() == 1)
        {       
            foreach ($result as $row)
            {                   
                if(is_file($_SERVER['DOCUMENT_ROOT'].$downloadPath . $row[$fileNameField])) 
                {               
                    $count = $row[$downloadCountField] + 1;                 
                    $sql = "UPDATE " . $tableName . " SET " . $downloadCountField . " = " . $count . " WHERE file_id = " . $_REQUEST[$idField];
                    $statement = $connection->prepare($sql);
                    $statement->execute();
                    $documentLocationAndName = $downloadPath . $row[$fileNameField];
                    header('Location:' . $documentLocationAndName);
                }
            }
        }
    }

    catch(PDOException $error) 
    {
        echo $sql . "<br>" . $error->getMessage();
    }   
}

}

A:

The answer to both of your questions is yes.
When a crawler indexes your website, it also looks for related content, akin to creating a sitemap. The first place it looks for related content on a page are the direct links. If you're linking to your files directly on your download page, the crawler will also attempt to index those links.
Preventing the crawlers from seeing your download page with robots.txt would prevent this problem, but then you'd be losing potential SEO. And what if a third party links to your downloads directly? If they have their downloads page indexed, your links will still be visible to crawlers.
Fortunately, you can disable this behaviour. Simply tell the crawlers that the links on the download page are all canonical ones, by adding the following to the <head> section of the downloads page:
<link rel="canonical" href="http://www.example.com/downloads" />

Considering the parameters are essentially different 'pages', crawlers will think that /downloads?file_id=1 is different to /downloads. Adding the above line will inform them that it is the same page, and that they don't need to bother.
Assuming that you have actual files that are being indexed (such as PDFs), you can prevent crawlers from indexing them in your .htaccess or httpd.conf:
<Files ~ "\.pdf$">
  Header set X-Robots-Tag "noindex, nofollow"
</Files>

As a fallback, you could always check who is attempting to download the file in the PHP itself! It depends how pedantic you want to be (as there are a lot of different crawlers), but this function works pretty well:
function bot_detected() {
  return (
    isset($_SERVER['HTTP_USER_AGENT'])
    && preg_match('/bot|crawl|slurp|spider|mediapartners/i', $_SERVER['HTTP_USER_AGENT'])
  );
}

Then simply call it as a conditional before running your try:
if (!bot_detected()) {
  try { } // Will only get executed for real visitors
}

Also, as an aside, I'd recommend using $_GET["file_id"] over $_REQUEST["file_id"]. $_REQUEST combines $_GET with both $_POST and $_COOKIE, which tend to be used in rather different ways. While this is technically secure if you're only retrieving data, it's far safer to limit the request to a simple $_GET.
Hope this helps! :)

