ifsnop / mysqldump-php

PHP version of mysqldump cli that comes with MySQL
https://github.com/ifsnop/mysqldump-php
GNU General Public License v3.0
1.25k stars 300 forks source link

Add support for ZIP compression #205

Closed smalos closed 4 years ago

smalos commented 4 years ago

ZIP is one of the most widely used compressed file formats. Could you add support for it?

Here's my take on it. I'm not quite sure what's the best way to implement addFromString() as it expects a file name. I introduced a $filenameOnly variable that is passed to it. Is there an easier/better way to do it?

Add ZIP to the list of List of available compression methods:

    // List of available compression methods as constants.
    const ZIP   = 'Zip';

Add Mysqldump::ZIP to $enums:

    public static $enums = array(
        Mysqldump::NONE,
    Mysqldump::ZIP,
        Mysqldump::GZIP,
        Mysqldump::BZIP2,
        Mysqldump::GZIPSTREAM,
    );

Add new class CompressZip:

class CompressZip extends CompressManagerFactory
{
    private $fileHandler = null;
    private $filenameOnly = null;

    public function __construct()
    {
        if (!extension_loaded('zip')) {
            throw new Exception("Compression is enabled, but zip lib is not installed or configured properly");
        }
    }

    /**
     * @param string $filename
     */
    public function open($filename)
    {

        $this->fileHandler = new \ZipArchive;
        $this->fileHandler->open($filename, \ZipArchive::CREATE | \ZipArchive::OVERWRITE);
        $this->$filenameOnly = pathinfo($filename)['filename'];

        if (false === $this->fileHandler) {
            throw new Exception("Output file is not writable");
        }

        return true;
    }

    public function write($str)
    {

    $bytesWritten = $this->fileHandler->addFromString($this->$filenameOnly, $str);

        if (false === $bytesWritten) {
            throw new Exception("Writting to file failed! Probably, there is no more free space left?");
        }
        return $bytesWritten;
    }

    public function close()
    {
        return $this->fileHandler->close(); 
    }
}
ifsnop commented 4 years ago

Actually compressors are implemented as stream compressors. Every line is fed to the class that extends CompressManagerFactory, and it is writen to the compressed stream, so there is no need to store it on memory.

If we don't use a stream compressor, a very big dump has to be stored in memory and then compressed, so an out of memory could happen. Using stream compressors, data is compressed on the fly.

I am not aware of any stream compressor for zip in PHP.

smalos commented 4 years ago

Let's close this. My ZIP implementation doesn't seem to work well for larger dumps, just small ones.