Obfuscate your PHP code
Protect your PHP code with obfuscation. Discover how the php_obfuscator script works and if AI tools like Copilot can still de-obfuscate your proprietary source code.
Changelog

This article tests whether PHP code obfuscation (using the author's php_obfuscator script, which strips whitespace and renames identifiers to random strings) still protects proprietary code in the AI era. A hangman game generated by Gemini is obfuscated and still runs correctly, but Copilot is then able to fully de-obfuscate it back into readable, commented code — questioning whether obfuscation is still worthwhile.
A few years ago, I sold a software called aeSecure, which was a Web Application Firewall. In order to prevent my proprietary code from being picked up by someone who could then sell it, for example, I had developed an obfuscation script.
Since then, I've released a reusable version of that script: https://github.com/cavo789/php_obfuscator.
And what if, today, with artificial intelligence, this type of code was no longer of any interest? The aim of this article is to see if it's always a good idea to make your code unreadable.
Obtaining a previously non-existent code, ask Gemini
Just to give you some PHP code to use as an example for this article, let's create a hangman game using artificial intelligence.

Here is the code proposed by Gemini. Save it to your disk as hangman.php:
<?php
function generateWordList() { // Replace these with your own word list return [ "apple", "banana", "orange", "computer", "programming", ];}
function getRandomWord($wordList) { $randomIndex = array_rand($wordList); return $wordList[$randomIndex];}
function displayHangman($guessesLeft) { $stages = [ "[ O ]", "[ | ]", "[ /| ]", "[ /|\\ ]", "[ | ]", "[ / ]", "Wrong guess: ", ]; echo $stages[$guessesLeft] . PHP_EOL;}
function displayWord($word, $guessedLetters) { $displayedWord = ""; for ($i = 0; $i < strlen($word); $i++) { $letter = $word[$i]; if (in_array($letter, $guessedLetters)) { $displayedWord .= $letter . " "; } else { $displayedWord .= "_ "; } } echo trim($displayedWord) . PHP_EOL;}
function playHangman() { $wordList = generateWordList(); $word = getRandomWord($wordList); $guessedLetters = []; $guessesLeft = 6;
while ($guessesLeft > 0) { displayHangman($guessesLeft); displayWord($word, $guessedLetters);
echo "Guess a letter: "; $guess = trim(fgets(STDIN));
if (strlen($guess) !== 1 || !ctype_alpha($guess)) { echo "Please enter a single letter." . PHP_EOL; continue; }
$guess = strtolower($guess);
if (in_array($guess, $guessedLetters)) { echo "You already guessed that letter." . PHP_EOL; continue; }
$guessedLetters[] = $guess;
if (strpos($word, $guess) === false) { $guessesLeft--; }
if (str_replace(" ", "", displayWord($word, $guessedLetters)) === $word) { echo "Congratulations! You guessed the word." . PHP_EOL; break; } }
if ($guessesLeft === 0) { displayHangman($guessesLeft); echo "You ran out of guesses. The word was: " . $word . PHP_EOL; }}
playHangman();This is a complete Hangman game implementation. It picks a random word from a list, then repeatedly prompts the player to guess letters, tracking which letters have been guessed and how many wrong guesses remain. The game ends when the player either guesses the word correctly or runs out of guesses.
To play with this game, just run docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php hangman.php (see The easiest way to run a PHP script / website if that command looks cryptic).
As you'll see the script works fine without any change!

Obfuscate
Now, we'll make this code unreadable by removing unneeded spaces and carriage returns, and replacing names with some random letters. For instance, replace the playHangman function name with a random string like ppny. And to make the code more unreadable, I'll choose only strings like ppmx, ppnx, ppny and so on.
To do such obfuscation, just download my https://github.com/cavo789/php_obfuscator/blob/main/src/minify.php script and save it on your disk as minify.php. Also create a file called settings.json with this content:
{ "replace": { "getRandomWord":"ppmx", "displayHangman":"ppnx", "playHangman":"ppny", "displayWord":"ppnz", "guessesLeft":"ppnc", "guessedLetters":"ppnt", "randomIndex":"ppmw", "wordList":"ppmu", "generateWordList":"ppms", "displayedWord":"ppmb", "stages":"ppmc" }}This is a configuration object that maps human-readable variable and function names from a hangman game to shortened placeholder names. It's likely used as a search-and-replace lookup table to obfuscate or minify the original code by substituting meaningful names with cryptic abbreviated ones.
Right now, in your folder, you've three files:
Time to make the hangman.php file unreadable by running docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php minify.php input=hangman.php output=hangman_minify.php.

Now, you've a new file called hangman_minify.php:
<?php// cspell:disablefunction ppms(){return ["apple","banana","orange","computer","programming",];}function ppmx($ppmu){$ppmw=array_rand($ppmu);return $ppmu[$ppmw];}function ppnx($ppnc){$ppmc=["[ O ]","[ | ]","[ /| ]","[ /|\\ ]","[ | ]","[ / ]","Wrong guess: ",];echo $ppmc[$ppnc].PHP_EOL;}function ppnz($word,$ppnt){$ppmb="";for ($i=0; $i < strlen($word); $i++){$letter=$word[$i];if(in_array($letter,$ppnt)){$ppmb .=$letter." ";}else{$ppmb .="_ ";}}echo trim($ppmb).PHP_EOL;}function ppny(){$ppmu=ppms();$word=ppmx($ppmu);$ppnt=[];$ppnc=6;while ($ppnc > 0){ppnx($ppnc);ppnz($word,$ppnt);echo "Guess a letter: ";$guess=trim(fgets(STDIN));if(strlen($guess) !==1||!ctype_alpha($guess)){echo "Please enter a single letter.".PHP_EOL;continue;}$guess=strtolower($guess);if(in_array($guess,$ppnt)){echo "You already guessed that letter.".PHP_EOL;continue;}$ppnt[]=$guess;if(strpos($word,$guess)===false){$ppnc--;}if(str_replace(" ", "", ppnz($word,$ppnt))===$word){echo "Congratulations! You guessed the word.".PHP_EOL;break;}}if($ppnc===0){ppnx($ppnc);echo "You ran out of guesses. The word was: ".$word.PHP_EOL;}}ppny();This is a hangman game implementation. It picks a random word from a list, then lets the player guess letters one at a time until they either guess the word correctly or run out of guesses. As the player makes wrong guesses, it displays a stick figure drawing progressively, and it shows the word with blanks for unguessed letters.
What you see here above is the newer version of the hangman.php file and it's still running. You can check by running docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php hangman_minify.php.
Make the code readable again, ask Copilot

The first time, Copilot has kept my minified function name. By asking him Can you suggest another version?, Copilot suggests this code:

<?php// Define an array of wordsfunction getRandomWord(){ $words = [ "apple", "banana", "orange", "computer", "programming", ]; return $words[array_rand($words)];}
// Display hangman art based on the number of incorrect guessesfunction displayHangman($incorrectGuesses){ $hangmanArt = [ "[ O ]", "[ | ]", "[ /| ]", "[ /|\\ ]", "[ | ]", "[ / ]", ]; echo $hangmanArt[$incorrectGuesses] . PHP_EOL;}
// Display the word with guessed letters revealedfunction displayWord($word, $guessedLetters){ $displayedWord = ""; foreach (str_split($word) as $letter) { if (in_array($letter, $guessedLetters)) { $displayedWord .= $letter . " "; } else { $displayedWord .= "_ "; } } echo trim($displayedWord) . PHP_EOL;}
// Main game loopfunction playHangman(){ $wordToGuess = getRandomWord(); $guessedLetters = []; $incorrectGuesses = 6;
while ($incorrectGuesses > 0) { displayHangman($incorrectGuesses); displayWord($wordToGuess, $guessedLetters); echo "Guess a letter: "; $guess = trim(fgets(STDIN));
if (strlen($guess) !== 1 || !ctype_alpha($guess)) { echo "Please enter a single letter." . PHP_EOL; continue; }
$guess = strtolower($guess);
if (in_array($guess, $guessedLetters)) { echo "You already guessed that letter." . PHP_EOL; continue; }
$guessedLetters[] = $guess;
if (strpos($wordToGuess, $guess) === false) { $incorrectGuesses--; }
if (str_replace(" ", "", displayWord($wordToGuess, $guessedLetters)) === $wordToGuess) { echo "Congratulations! You guessed the word." . PHP_EOL; break; } }
if ($incorrectGuesses === 0) { displayHangman($incorrectGuesses); echo "You ran out of guesses. The word was: " . $wordToGuess . PHP_EOL; }}
// Start the gameplayHangman();This is a hangman game implementation in PHP. It picks a random word, then loops asking the player to guess letters one at a time, revealing correct guesses and drawing hangman stages for wrong ones. The game ends when either the player guesses the full word or runs out of incorrect guesses.
The artificial intelligence managed to understand the purpose of the script (a hangman game) and rewrote the code to make it readable. Not only is the code readable, the function names are too, but it has also written comments. Just incredible!
Obfuscation aside, if you're after more conventional PHP code-quality tooling, check out the Docker image bundling static analysis tools.





