Search code examples
phplinuxcronunlink

unlink not working when php script is ran by cron


I have a php script that is checking the result of a virustotal scan. If the scan returns positive for malicious code it changes the value to 0 in the db. I have another php script which checks the value and if it is 0 it removes the entry from the db and then removes the file from the directory. When I run this through the command line it works perfectly, however when cron runs it, it does remove the db entry as it should however it does not delete the file from the directory.

Any help would be much appreciated.

Here is the end of the php file with the unlink:

else{
        // if not it deletes the image
        $hash = $row['hash'];
        $result2 = mysqli_query($connection, "DELETE FROM userUploads WHERE hash = '$hash' ");

        // need due to dir structure
        $pat = str_replace('../','', $row['fileName']);
        unlink ($pat);

        if (! $result2){
            echo('Database error: ' . mysqli_error($connection));

        }

For reference, here is the full file:

<?php

function VirusTotalCheckHashOfSubmitedFile($hash){
    $debug = false;
    $post = array('apikey' => '','resource'=>$hash);
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://www.virustotal.com/vtapi/v2/file/report');
    curl_setopt($ch, CURLOPT_POST,1);
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate'); // please compress data
    curl_setopt($ch, CURLOPT_USERAGENT, "gzip, My php curl client");
    curl_setopt($ch, CURLOPT_VERBOSE, 1); // remove this if your not debugging
    curl_setopt($ch, CURLOPT_RETURNTRANSFER ,true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

    $result = curl_exec ($ch);
    $status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    if ($status_code == 200) { // OK
      $js = json_decode($result, true);
       if($debug){echo "<pre>";}
       if($debug){print_r($js);}
      if($js["positives"]==0){
          // clean
        return true;
      }else{
          // malware
        return false;
      }
    } else {  // Error occured
      print($result);
    }
    curl_close ($ch);
}


$connection = mysqli_connect("");
if (!$connection) {
    trigger_error("Could not reach database!<br/>");

}

$db_selected = mysqli_select_db($connection, "seclog");
if (!$db_selected) {
    trigger_error("Could not reach database!<br/>");

} 
// Selecs images that have not been marked as clean by virus total
$result = mysqli_query($connection, "Select hash, fileName FROM userUploads WHERE scanResult = 0"); 
if (! $result){
    echo('Database error: ' . mysqli_error($connection));

}
while ($row = mysqli_fetch_assoc($result)) {
    // checks for results on scanned images
    if(VirusTotalCheckHashOfSubmitedFile($row['hash'])){
        // if report returns image is malware free we update its virusFree attribute to true
        $hash = $row['hash'];
        $result2 = mysqli_query($connection, "UPDATE userUploads SET scanResult = 1 WHERE hash = '$hash'"); 
        if (! $result2){
            echo('Database error: ' . mysqli_error($connection));

        }
    }else{
        // if not it deletes the image
        $hash = $row['hash'];
        $result2 = mysqli_query($connection, "DELETE FROM userUploads WHERE hash = '$hash' ");

        // need due to dir structure
        $pat = str_replace('../','', $row['fileName']);
        unlink ($pat);

        if (! $result2){
            echo('Database error: ' . mysqli_error($connection));

        }
    }
}  

?>


Solution

  • The problem almost certainly is the path $pat = str_replace('../','', $row['fileName']);. Crons execute PHP cli, that is not the same PHP that Apache executes, also is another context. Try setting absolute path:

    $pat = "/var/www/myfolder/myscript.some";
    

    If for some reason you need a variable because folder structure depends of the context (e.g. development, production) you could pass the variable as a parameter when the cron executes PHP:

    //this is the cron
    30 17 * * 1 myscript.php myvar
    

    Inside myscript.php $argv[1] is myvar.