-3

I have a simple PHP script that queries MySQL DB and deletes(unlinks) file(s) from an uploads folder when a condition (expiry timestamp) is met. Then it redirects to another PHP script. I have set up a cron job to run the first script automatically, this works fine and deletes the files where needed from the uploads folder, but it does not redirect when my if-else statement gets triggered. If I manually paste the file path to the browser, the script runs, deletes and redirects as I would expect. (Also will not redirect if I run the PHP file from the CLI). Any help would be much appreciated.

include_once 'db.php';

date_default_timezone_set("Asia/Bangkok");
$date = date('Y-m-d H:i:s');
$sql = "SELECT name FROM files WHERE expiry <= '$date'";
$result = mysqli_query($conn, $sql);

if (!$result) {
    echo('Could not get data: '.mysqli_error());
}
while ($row = mysqli_fetch_array($result)) {
    $delete = ("assets/uploads/{$row['name']}");
    if (file_exists($delete)) {
        unlink($delete);
    } else {
        header("Location: expire.php", 
            true, 301);
        exit();
    }
}

mysqli_close($conn);
Karl Hill
  • 12,937
  • 5
  • 58
  • 95
  • Slightly o/t, but why do you continue to try to retrieve data if you get `false` back from the query? An `exit()` would be useful there, I think. – droopsnoot May 06 '22 at 09:19
  • 1
    Isn't a header redirect a browser instruction? I haven't tried it myself, but this seems to agree: https://stackoverflow.com/questions/15633829/cron-job-with-header-location-redirect-in-php – droopsnoot May 06 '22 at 09:21
  • 1
    Trying to use a location header in this scenario could only make sense, if you called the script not via CLI in the first place - but with a cron setup that utilizes `wget` to request the script _via HTTP(S)_, or something similar. But on CLI no HTTP is involved, so it makes no sense to try and do an _HTTP redirect_ in that environment. – CBroe May 06 '22 at 09:26
  • As an aside: `mysqli_error()` won't tell you any errors because you forgot to include the connection object as a parameter to it (as per the [documentation](https://www.php.net/manual/en/mysqli.error.php)). But there's a far better way to get errors from mysqli than clunkily having boilerplate testing code after every command - see [How to get the actual mysqli error](https://stackoverflow.com/a/22662582/5947043) for details. – ADyson May 06 '22 at 09:37
  • You have an error. [`mysqli_error()`](https://www.php.net/manual/en/mysqli.error.php) needs one argument. Please consider switching error mode on instead. [How to get the error message in MySQLi?](https://stackoverflow.com/a/22662582/1839439) – Dharman May 06 '22 at 09:55
  • Thanks for all the help everyone, script now working perfectly with @ADyson advice. I will try to do better next time ;0) – Markie Mark May 07 '22 at 06:37

1 Answers1

1

The header function just issues a HTTP response header to be sent back to a client when the script ends. Clearly, that only makes sense in the context of a HTTP request.

And again hopefully it's self-evident that running the script via CLI or cron is not a HTTP context. Therefore, issuing any kind of response header, such as Location, won't have any effect. Remember that the kind of redirect you commonly see on websites is actually done by the browser - the server merely tells the browser (via the Location header) where it wants the browser to go next.

In your CLI/cron situation, if you want to run another script, one option is simply to require it, e.g.

else {
   require "expire.php";
   exit();
}

This will mean it executes as a continuation of the current script.

ADyson
  • 57,178
  • 14
  • 51
  • 63
  • Thanks very much for the explanation and help, I understood that the redirect would only work in the browser environment. I had a not seeing the wood for the trees moment. I also appreciate the mysqli_error() tips, would upvote but I have only just started with stackoverflow (need a few more reputation points) Thanks again ;-) – Markie Mark May 07 '22 at 06:29
  • No worries, you can still mark the answer as "accepted", by clicking the tick mark next to it so it goes green :-) – ADyson May 07 '22 at 09:37
  • 1
    Thanks, clicked and now green – Markie Mark May 08 '22 at 09:15