1

I have a client that uses a website builder that does not offer the ability to edit the code or access the database but hey want to track the downloads of a file.

I setup a system in which I host the file elsewhere, and their website has an <a> link to a page on the host site with a very simple script to insert a record to track the download, as well as download the file.

This is the php script in the page on my site, download-agreement.php:

<?php
$db = new mysqli('localhost', 'username', 'password', 'database');

if ($db->connect_error) {
    die("Connection failed: " . $db->connect_error);
  }

$file_path = 'agreement.pdf';

$stmt = $db->prepare("INSERT INTO `download_log` (`date`) VALUES (CURRENT_TIMESTAMP())");

if ($stmt===false) {
    error_log($db->error);
}

$result = $stmt->execute();

if ($result===false) {
    error_log($stmt->error);
}

$stmt->close();
$db->close();

error_log("Downloaded: " . date("Y-m-d H:i:s"));

header('Content-type: application/pdf');
header('Content-Disposition: attachment; filename=agreement.pdf'); 
readfile($file_path);
?>

And the link I have placed on their site:

https://www.host.com/theirdirectory/download-agreement.php

If link is visited directly, it works properly - the error_log() executes and the record is inserted.

If the link is visited after being clicked on their website, only the file downloads. The error_log() is not executed and the record is not inserted.

I am at a bit of a loss as I cannot even get an error. And thoughts or ideas would be appreciated.

EDIT

This seems to be an issue with Chrome for Desktop (which doesn't really make any sense). This works properly on all browsers except for Chrome for Desktop (it works on chrome for mobile), tested on all with caching disabled on multiple computers.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Andrew
  • 1,745
  • 1
  • 21
  • 29
  • 1
    Well, it's not valid SQL, so you should be getting an error. If you're not, that's a problem. Hint: It's `CURRENT_TIMESTAMP()`. – tadman Apr 30 '21 at 14:37
  • 1
    Tip: A lot of problems can be detected and resolved by [enabling exceptions in `mysqli`](https://stackoverflow.com/questions/14578243/turning-query-errors-to-exceptions-in-mysqli) so errors resulting from simple mistakes made aren’t easily ignored. Without exceptions you must pay close attention to return values, many of these indicate problems you must resolve or report to the user. Exceptions allow for more sophisticated flow control as they can “bubble up” to other parts of your code where it’s more convenient to handle them. – tadman Apr 30 '21 at 14:38
  • 1
    If you're just getting started with PHP and want to build applications, I'd strongly recommend looking at various [development frameworks](https://www.cloudways.com/blog/best-php-frameworks/) to see if you can find one that fits your style and needs. They come in various flavors from lightweight like [Fat-Free Framework](https://fatfreeframework.com/) to far more comprehensive like [Laravel](https://laravel.com/). These give you concrete examples to work from and guidance on how to write your code and organize your project's files. – tadman Apr 30 '21 at 14:38
  • 1
    Note: The [object-oriented interface to `mysqli`](https://www.php.net/manual/en/mysqli.quickstart.connections.php) is significantly less verbose, making code easier to read and audit, and is not easily confused with the obsolete `mysql_query` interface where missing a single `i` can cause trouble. Use this style: `$db = new mysqli(…)` and `$db->prepare("…")` The procedural interface is an artifact from the PHP 4 era and looks clunky and out of place when used in new code. – tadman Apr 30 '21 at 14:38
  • 1
    @tadman thanks for the feedback. I have updated the code to use the object oriented interface (which is what I normally do, shouldn't have used the old way here). I normally do, and I would love to use a framework such as Laravel but in this case it's not feasible. After updating the code nothing has changed, this works when executed directly, but only the file downloads when the link is visited from a different site. – Andrew Apr 30 '21 at 15:18
  • Why are you using short open tags? Those haven't been acceptable in well over a decade. The file is likely cached on the client side; based on the code provided, it's impossible for PHP to generate the file and not create the log entry. – miken32 Apr 30 '21 at 16:15
  • @miken32 I missed those tags, thanks for pointing that out. – Andrew Apr 30 '21 at 16:18
  • Looking better, but keep in mind it's usually better to write `if (!$x)` than `if ($x === false)` as sometimes an API will emit a logically false, but not *literally* false value as a failure result. If you use exceptions you don't need to fuss over catching every single error, you can just `catch` at a higher level. – tadman Apr 30 '21 at 16:21
  • 1
    You might try to enable `error_reporting(E_ALL)` and check the error log file on the server if there is any other error. – Asenar Apr 30 '21 at 16:27
  • @Asenar Thanks for the idea, I enabled it and still no error messages. I did further testing and this seems to work on all browsers except for Desktop Chrome, seems to be a browser issue. – Andrew Apr 30 '21 at 17:12
  • 1
    Is it possible it’s not browser caching, but some weird intermediary cache at play? That’s all I can think of that would create this scenario. – esqew Apr 30 '21 at 17:17
  • Check the Network tab in DevTools panel of Google Chrome. Maybe the PDF is already cached and Chrome does not ask for it again. Try checking the "Disable cache" in the same tab. – Zoli Szabó Apr 30 '21 at 17:40
  • Thanks @esqew, I don't beleive there's any kind of intermediary cache at play - I'll contect the host to see if they have anything funny going on. – Andrew Apr 30 '21 at 17:44
  • Thanks @Zoli Szabó I'll check for the cached pdf. With all of my tests I have checked "Disable Cache". – Andrew Apr 30 '21 at 17:44
  • One other difference between the two requests is the lack/presence of the referrer request header. Try disabling it with `rel="noreferrer"` (e.g. `Example`). – Zoli Szabó Apr 30 '21 at 17:49

1 Answers1

0

Thanks to everyone for all of the help, the issue turned out to be the elements in the "GoDaddy Website Builder" on the client's website where the link was stored.

I am still not sure what exactly the issue was but my solution was to make this work I had to use an HTML Section that allowed me to write in the link manually as an html code block - which happens to render as an iframe in their builder, differently from other pre-built elements such as buttons with links etc. It seems that there may be some caching happening on their end (as esqew mentioned there may be) or something going on behind the scenes with those elements that is behaving differently in different browsers.

Andrew
  • 1,745
  • 1
  • 21
  • 29