L'implémentation de cette nouvelle fonctionnalité repose sur l'utilisation de la bibliothèque libzip version 1.2.0 récemment publiée.

Actuellement seule la compilation avec la bibliothèque système offre ce support, mais une mise à jour de la version embarquée est prévue.

Lorsque tout sera validé, la version sera publiée et intégrée aux sources de php (ext/zip), sans doute pour PHP 7.2.

il s'agit d'un développement en cours, rien n'est définitif, et les méthodes proposées peuvent encore changer.

Installation en RPM

Le paquet php-pecl-zip-1.4.0.0-0.2.20170301dev est disponible dans le dépôt remi-test (et remi-php70-test, remi-php71-test).

Installation depuis les sources

Depuis un clone des sources disponibles dans github :

$ phpize
$ ./configure --with-libzip
...
checking for libzip... from pkgconfig: version 1.2.0 found in /usr/lib64
checking for zip_open in -lzip... yes
checking for zip_file_set_encryption in -lzip... yes
...
$ make
...
Build complete.
Don't forget to run 'make test'.
$ make test
...
PASS ZipArchive::setEncryption*() functions [tests/oo_encryption.phpt]

Création d'un archive chiffrée

Trois méthodes permettent de gérer le cryptage

ZipArchive::setEncryptionName($name, $method [, $password]);
ZipArchive::setEncryptionIndex($index, $method [, $password]);
ZipArchive::setPassword($password);

Le choix de la méthode de chiffrement devant être une des constantes ZipArchive::EM_NONE, ZipArchive::EM_AES_128, ZipArchive::EM_AES_192 ou ZipArchive::EM_AES_256.

Exemple 1 :

Mot de passe par fichier

$zip = new ZipArchive;
$zip->open(__DIR__ . '/encrypted.zip',   ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE);
$zip->addFile(__FILE__, 'foo.php');
$zip->setEncryptionName('foo.php', ZipArchive::EM_AES_256, 'secret');
$zip->close();

Exemple 2 :

Mot de passe par defaut (global)

$zip = new ZipArchive;
$zip->open(__DIR__ . '/encrypted.zip',   ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE);
$zip->setPassword('secret'); 
$zip->addFile(__FILE__, 'foo.php');
$zip->setEncryptionName('foo.php', ZipArchive::EM_AES_256);
$zip->close();

Lecture d'une archive chiffrée

Exemple :

$zip = new ZipArchive;
$zip->open(__DIR__ . '/encrypted.zip');
print_r($zip->statName($file));
$zip->setPassword('secret');
$text = $zip->getFromName('foo.php');
$zip->close();

A noter :

  • utilisation de la méthode setPassword qui positionne le mot de passe utilisé par défaut.
  • la sortie de la méthode statName retourne une nouvelle information : encryption_method (259 pour ZipArchive::EM_AES_256)

Lecture d'un archive chiffrée via les flux

Il est nécessaire de passer le mot de passe en utilisant un context.

Exemple :

$ctx = stream_context_create(array(
    'zip' => array(
        'password' => 'secret'
    )
));
$text = file_get_contents('zip://' . __DIR__ . '/encrypted.zip#foo.php', false, $ctx);

Conclusion

Le script utilisé dans les exemples ci-dessus est disponible dans les sources de l'extension : encryption.php

Cette nouvelle fonctionnalité me semble très utile, et devrait offrir une meilleure compatibilité avec les outils existants, comme WinZip sous Windows ou 7za sous Linux.

Pour Fedora, cette évolution devrait être disponible dans Fedora 26 qui dispose déjà de libzip 1.2.0.