0

I am creating a website that has users log in and select a pdf document that they want to download. When they open up the document to view and possibly download, I want data to be logged into a database at the same time.

The code to send the data to the database works (Except for: Undefined index: learningMaterial). But when I want to have the pdf document open and at the same time log the user and other data, all that happens is the document opens up.

Any advice would be appreciated, even for overall better methods of going about what I'm trying to achieve here. Still inexperienced with PHP.

See code below.

HTML

<form name="myform" method='post' action="../includes/writeStats.php">  

<input type='hidden' name='learningMaterial' id='learningMaterial' value='learningMaterial'>

<a href='../documents/test.pdf' id='mylink' class='courses' name='Driver Training'> Driver Training </a>

</form>

JS - In header

<script type="text/javascript">

function submitform(){
document.myform.submit(); }


var form = document.getElementById("myform");

document.getElementById("mylink").addEventListener("click", function () {
      submitform();
});

</script>

PHP

<?php
$con=mysqli_connect("localhost","root","password","qmptest");
// Check connection
if (mysqli_connect_errno()) {
echo "Failed to connect to MySQL: " . mysqli_connect_error();
}

//Get latest log nr
$result = mysqli_query($con,"SELECT * FROM logbook ORDER BY log DESC LIMIT 1");

while($row = mysqli_fetch_array($result)) {
$log =  $row['log'] + 1;
//If statement to check if log is 0(first entry) to go here
}


$date = date("Y/m/d");

session_start(); // Start a new session

$person = $_SESSION['currentUser'];

//Not sure if this is correct along with my HTML input
$material = mysqli_real_escape_string($con, $_POST['learningMaterial']);


//Insert into database 

$sql="INSERT INTO logbook (log, date, person, learningMaterial)
VALUES ('$log', '$date', '$person', '$material')";

if (!mysqli_query($con,$sql)) {
die('Error: ' . mysqli_error($con));
}


mysqli_close($con);
?>
Syther
  • 1
  • 1

2 Answers2

1

Your way, clicking the link will override the form being submitted. This leads to the file opening and the form never going through.

Instead, you could try either opening the file in a new window by adding target="_blank" to the tag, or send the files URL through to the PHP, executing the database code then adding to the end:

header("Location: http://yourdomain.com/yourfile.pdf");
James Hunt
  • 2,448
  • 11
  • 23
1

Your file is just a normal file being returned by your web server:

<a href='../documents/test.pdf' ...

So while you may be able to suggest to users or browsers that they should invoke some code before downloading this file, you can't actually require it. Any user can just request the file directly. And since PDF files don't execute PHP code (thankfully), your server-side PHP code has no way of knowing that the file has been requested.

What you can do is obscure the file itself behind a PHP request. You can create something like a download.php page which accepts the name of a file (test.pdf) and returns that file.

Be very careful when doing this. Don't just allow users to request any file and blindly return whatever they request. A user can request something like "../../../../../../../../../../etc/passwd" and if your code just builds a path and returns the file then you've just given users a sensitive file. It's best practice to keep a finite known list of identified files (perhaps in a database table) and let users request by the identifier rather than by the file path itself. That way the actual path is only ever known server-side in data that you control.

The main point here, however, is that by using such a page you inject some PHP code in between the user and the file. In order to get the file, the user needs to make a request to a PHP page. On that page you can record the act of the user having requested the file. (As well as perform authorization checks to validate that the user is allowed to view the file, etc.)

Never assume client-side code is going to do what you expect it to do. If you want to ensure something happens for anything approaching security or auditing purposes, it needs to happen in server-side code.

Community
  • 1
  • 1
David
  • 208,112
  • 36
  • 198
  • 279