How to encrypt files in PHP?
If you handle sensitive data, encrypting files before storing them on a server or cloud storage may be necessary. Let’s see how to encrypt and decrypt files in PHP with the openssl_encrypt
function.
🚫 Don’t pass the entire content to openssl_encrypt
openssl_encrypt
function is simple to use: you pass a string and a key (as well as the algorithm to use and the initialisation vector), and it returns the encrypted version of your string.
You might think that all you have to do is to pass the whole file content into openssl_encrypt
to get the encrypted content. This is however a bad idea because it will load the entire file into memory, as well as the encrypted version.
If you want to encrypt a 30M file, your PHP request will use at least 60M of memory. With larger files, you risk to exceed the PHP memory limit.
Let’s try the following code with a 30M file. It loads the entire file content with file_get_contents()
and passes it to openssl_encrypt()
.
➜ php encrypt_file.phpFile encrypted!
Memory usage: 64.98M
64.98M is allocated to PHP. It means this code won’t work with large files since we’ll exceed the PHP memory limit.
✅ Encrypt smaller chunks of a large file
To avoid loading a large file into memory, the best practice is to encrypt smaller chunks of the file, one after the other, and write them into another file.
1. Create a random Initialisation Vector (IV)
As you may know, when we use openssl_encrypt()
or openssl_decrypt()
we need to pass a non-null initialisation vector. Let’s generate a random one using openssl_random_pseudo_bytes()
.
2. Store this IV at the beginning of the encrypted file
We can’t decrypt anything without the IV, so we have to store this IV somewhere so we can decrypt the content later. It’s not a secret information as the encryption key, so we can store it at the beginning of the encrypted file.
3. Take a first chunk, encrypt it with the IV, and store it
Now that we have a random IV, we can take a first chunk of the plaintext file, and encrypt it, then store it at the end of the encrypted file.
4. Use the first characters of the encrypted chunk for the next IV
The idea is to change the IV for each chunk encryption. The next IV will always be the first characters of the last encrypted chunk.
5. Take the next chunk and repeat step 3
➜ php encrypt_file.phpFile encrypted!
Memory usage: 0.38M
For the same file, it tooks this time 0.38M of memory to encrypt it. This is much better than the 64.98M of our first approach!
To decrypt the file, we just have to do the reverse operation.
➡️ Full code
👋 I offer tech consulting services for companies that need help with their Laravel applications. I can assist with upgrades, refactoring, testing, new features, or building new apps. Feel free to contact me through LinkedIn, or you can find my email on my GitHub profile.