Confused about why it appears fopen(..,'w') in PHP from CLI causes issue when file already exists?

Using Kernel 6.12 and KDE. (I’m likely doing something very stupid but haven’t been able to figure it out.)

I’ve been experimenting with using PHP from the CLI with the -f flag to run scripts from a file and working with the AES encryption of openssl. The script encrypts a 3 GB SQlite file and then decrypts it.

The first time it runs it works fine. If I run it again, Konsole, Dolphin, and Kate freeze but my web browser and navigation within KDE seem fine.

I thought it was some error in my code but it appears to be that using fopen with the ‘w’ option (which, if I’m understanding, is to overwrite the file from the beginning or attempt to create it if it doesn’t exist) causes the issue when the file exists.

If I delete the file and run the script again, it works fine; but, if I run it without deletiing the file, it freezes. For example, when the files (encrypted and decrypted) do not yet exist, I can start the script and watch the files sizes increase in Dolphin. It takes about 30 seconds to complete. If the files exist, Dolphin shows no changes, the script either does not complete or takes a long time, extra Konsole entries appear in System Monitor and do not close when the script completes, and Kate won’t even scroll.

Does any of this sound familiar, plausible, or make sense? Is it wrong to use a ‘wb’ in fopen?

There is this warning, whether the file exists or not.

PHP Warning:  [snuffleupagus][0.0.0.0][config][log] No configuration specified via sp.configuration_file in Unknown on line 0

The script is mostly a combination of two examples in the PHP docs for openssl.

Any idea what I may be doing wrong and/or why deleting the files before running the script another time does not cause the issue?

Thank you.

<?php
//$key should have been previously generated in a cryptographically safe way, like openssl_random_pseudo_bytes
$key = "abcd1234dcba4321";
$cipher = "aes-256-cbc";
$feBlocks = 10000;
$fpPlain = fopen("../filename.db",'rb');
$fpEncrypt = fopen("encrypted.enc", 'wb');
if (in_array($cipher, openssl_get_cipher_methods()))
{
    $ivlen = openssl_cipher_iv_length($cipher);
    $iv = openssl_random_pseudo_bytes($ivlen);
    // Put the initialzation vector to the beginning of the file
    fwrite($fpEncrypt, $iv);
    while (!feof($fpPlain)) {
        $plaintext = fread($fpPlain, $ivlen * $feBlocks);
        $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
        // $ciphertext = openssl_encrypt($plaintext, $cipher, $key, $options=0, $iv, $tag);
        // Use the first 16 bytes of the ciphertext as the next initialization vector
        $iv = substr($ciphertext, 0, $ivlen);
        fwrite($fpEncrypt, $ciphertext);
    }
    fclose($fpPlain);
    fclose($fpEncrypt);
}

  $fpEncrypt = fopen("encrypted.enc", 'rb');
  $fpPlain = fopen("decrypted.db",'wb');
  $ivlen = openssl_cipher_iv_length($cipher);
  // Get the initialzation vector from the beginning of the file
  $iv = fread($fpEncrypt, $ivlen);
  while (!feof($fpEncrypt)) {
     // we have to read one block more for decrypting than for encrypting
     $ciphertext = fread($fpEncrypt, $ivlen * ($feBlocks+1));
     $plaintext = openssl_decrypt($ciphertext, $cipher, $key, $options=OPENSSL_RAW_DATA, $iv);
     // Use the first 16 bytes of the ciphertext as the next initialization vector
     $iv = substr($ciphertext, 0, $ivlen);
     fwrite($fpPlain, $plaintext);
  }
  fclose($fpEncrypt);
  fclose($fpPlain);
?>

My guess is that php does not allow writing to an existing filename - which is a valid stance - preventing the user from a possible dataloss.

Much like certain utilities e.g. makepkg --printsrcinfo > .SRCINFO will refuse to run when the output file exist.

The obvious solution is to check if the file exist - if yes - remove or rename as precaution - then write the new file.

1 Like

I doubt this. See PHP: fopen - Manual

‘w’ Open for writing only; place the file pointer at the beginning of the file and truncate the file to zero length. If the file does not exist, attempt to create it.
[…]
‘a’ Open for writing only; place the file pointer at the end of the file. If the file does not exist, attempt to create it. In this mode, fseek() has no effect, writes are always appended.
[…]

I’d say check and double-check permissions.

Thank you. I’ll give that a try. It’ll take me awhile to know because permissions always confuse me.

1 Like

Myself. a Tip about that, though:

Use the symbolic notation instead of the numeric notation.

Mod edit:- Uncrapified the markdown url notation.

Thank you for the links and tip. I still don’t know what the issue is but I can perform the same steps on files of smaller size without any issues. The file being opened as ‘wb’ is over 2GB but I thought that limit does not apply to linux. Thus, it appears it is not related to permissions.

The steps are the same except they don’t involve writing in blocks because the files are under the decryption function’s limit and can be processed in a single call. But the output files are still being overwritten.

If/when I figure it out, I will share the reason. My history is that it is likely user error.

1 Like