// nouvelle archive
$zip = new ZipArchive;

// ouverture
if ($zip->open('test.zip', ZipArchive::CREATE) === TRUE) {
   $folder = 'mon_dossier';
   inputfolder: // "goto" apparu en php >= 5.3.0

   // ouvre le dossier
   if ($handle = opendir($folder)) {

      // parcourt les entrées une par unes.
      while (FALSE !== ($entry = readdir($handle))) {

         // on exclu les dossiers parents (..) et courant (.),
         // ainsi que les fichiers dont on n’a pas les droits en lecture
         if ($entry != "." AND $entry != ".." AND is_readable($folder.'/'.$entry)) {

            // si c’est un dossier, on reboucle avec le GOTO
            if (is_dir($folder.'/'.$entry)) {
               // ne surtout pas oublier ceci :)
               $folder =  $folder.'/'.$entry;
               goto inputfolder;
            }

            // on ajoute le fichier (l’arborescence d’origine est conservée)
            $zip->addFile($folder.'/'.$entry, $folder.'/'.$entry);
         }
      }

      // ferme le dossier
      closedir($handle);
   }

   // ferme l’archive ZIP
   $zip->close();

   echo '<p>ok : <a href="test.zip">test.zip</a></p>';
} else {
   echo '<p>échec lors du open()</p>';
}