<!--
  canonical-url: https://www.avonture.be/fr/blog/php-obfuscator
  published:     2024-04-09
  This is a static plain-Markdown mirror generated at build time.
  Visit the canonical URL above for the fully rendered page, with images and interactive components.
-->

# Obfusquez votre code PHP

> Protégez votre code PHP grâce à l'obfuscation. Découvrez comment fonctionne le script php_obfuscator et si des outils d'IA comme Copilot arrivent encore à désobfusquer votre code source propriétaire.

---
![Obfusquez votre code PHP](/img/v2/obfuscated_code.webp)

**TL;DR**

Cet article teste si l'obfuscation de code PHP (avec le script `php_obfuscator` de l'auteur, qui supprime les espaces et renomme les identifiants en chaînes aléatoires) protège encore le code propriétaire à l'ère de l'IA. Un jeu du pendu généré par Gemini est obfusqué et continue de fonctionner correctement, mais Copilot arrive ensuite à le désobfusquer entièrement, en code lisible et commenté — de quoi se demander si l'obfuscation vaut encore la peine.

Il y a quelques années, je vendais un logiciel appelé aeSecure, un Web Application Firewall. Pour éviter que mon code propriétaire soit récupéré par quelqu'un qui pourrait ensuite le revendre, par exemple, j'avais développé un script d'obfuscation.

Depuis, j'ai publié une version réutilisable de ce script : <https://github.com/cavo789/php_obfuscator>.

Et si, aujourd'hui, avec l'intelligence artificielle, ce type de code n'avait plus aucun intérêt ? L'objectif de cet article est de voir s'il est toujours pertinent de rendre son code illisible.

## Obtenir un code qui n'existait pas encore : demandez à Gemini {#obtaining-a-previously-non-existent-code-ask-gemini}

Juste pour disposer d'un peu de code PHP en exemple pour cet article, créons un jeu du pendu avec l'intelligence artificielle.

![Demander à Gemini](./images/gemini.webp)

Voici le code proposé par [Gemini](https://gemini.google.com/). Enregistrez-le sur votre disque sous le nom `hangman.php` :

**hangman.php**

```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();
```

Pour jouer, il suffit de lancer `docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php hangman.php` (voyez [The easiest way to run a PHP script / website](/blog/docker-php-run-script-or-website) si cette commande vous semble cryptique).

Comme vous allez le voir, le script fonctionne très bien sans aucune modification !

![En train de jouer](./images/playing.webp)

## Obfusquer {#obfuscate}

Maintenant, nous allons rendre ce code illisible en supprimant les espaces et les retours à la ligne inutiles, et en remplaçant les noms par des lettres aléatoires. Par exemple, remplacer le nom de fonction `playHangman` par une chaîne aléatoire comme `ppny`. Et pour rendre le code encore plus illisible, je ne choisirai que des chaînes du type `ppmx`, `ppnx`, `ppny` et ainsi de suite.

Pour réaliser cette obfuscation, téléchargez simplement mon script <https://github.com/cavo789/php_obfuscator/blob/main/src/minify.php> et enregistrez-le sur votre disque sous le nom `minify.php`. Créez aussi un fichier appelé `settings.json` avec ce contenu :

**settings.json**

```json
{
    "replace": {
        "getRandomWord":"ppmx",
        "displayHangman":"ppnx",
        "playHangman":"ppny",
        "displayWord":"ppnz",
        "guessesLeft":"ppnc",
        "guessedLetters":"ppnt",
        "randomIndex":"ppmw",
        "wordList":"ppmu",
        "generateWordList":"ppms",
        "displayedWord":"ppmb",
        "stages":"ppmc"
    }
}
```

À ce stade, vous avez trois fichiers dans votre dossier :

```bash
$ ls -alh
total 28K
drwxr-xr-x  2 root root 4.0K Apr  7 20:11 .
drwxrwxrwt 22 root root 4.0K Apr  7 19:55 ..
-rw-r--r--  1 root root 1.9K Apr  7 20:07 hangman.php
-rw-r--r--  1 root root  12K Apr  7 19:34 minify.php
-rw-r--r--  1 root root  731 Apr  7 19:47 settings.json
```

Il est temps de rendre le fichier `hangman.php` illisible en lançant `docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php minify.php input=hangman.php output=hangman_minify.php`.

![Obfusquer votre code PHP](./images/obfuscate.webp)

Vous avez maintenant un nouveau fichier appelé `hangman_minify.php` :

**hangman\_minify.php**

```php
<?php
// cspell:disable
function 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();
```

Ce que vous voyez ici, c'est la nouvelle version du fichier `hangman.php`, et elle fonctionne toujours. Vous pouvez le vérifier en lançant `docker run -it -v ${PWD}:/src -w /src php:8.3-fpm php hangman_minify.php`.

## Rendre le code lisible à nouveau : demandez à Copilot {#make-the-code-readable-again-ask-copilot}

![Demander à Copilot](./images/copilot.webp)

La première fois, [Copilot](https://copilot.microsoft.com/) a conservé mes noms de fonctions minifiés. En lui demandant *Can you suggest another version?*, Copilot propose ce code :

![Réécriture du code](./images/copilot_rewritting.webp)

**hangman.php**

```php
<?php
// Define an array of words
function getRandomWord()
{
    $words = [
        "apple",
        "banana",
        "orange",
        "computer",
        "programming",
    ];
    return $words[array_rand($words)];
}

// Display hangman art based on the number of incorrect guesses
function displayHangman($incorrectGuesses)
{
    $hangmanArt = [
        "[   O    ]",
        "[   |    ]",
        "[  /|    ]",
        "[  /|\\   ]",
        "[   |    ]",
        "[  /     ]",
    ];
    echo $hangmanArt[$incorrectGuesses] . PHP_EOL;
}

// Display the word with guessed letters revealed
function 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 loop
function 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 game
playHangman();
```

L'intelligence artificielle a réussi à comprendre l'objectif du script (un jeu du pendu) et a réécrit le code pour le rendre lisible. Non seulement le code est lisible, les noms de fonctions aussi, mais elle a également écrit des commentaires. Tout simplement incroyable !

L'obfuscation mise à part, si vous cherchez des outils plus classiques pour la qualité du code PHP, jetez un œil à [l'image Docker qui regroupe les outils d'analyse statique](/blog/php-jakzal-phpqa).
