1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Filter\Compress;
11
12use Zend\Filter\Exception;
13
14/**
15 * Compression adapter for Bz2
16 */
17class Bz2 extends AbstractCompressionAlgorithm
18{
19    /**
20     * Compression Options
21     * array(
22     *     'blocksize' => Blocksize to use from 0-9
23     *     'archive'   => Archive to use
24     * )
25     *
26     * @var array
27     */
28    protected $options = array(
29        'blocksize' => 4,
30        'archive'   => null,
31    );
32
33    /**
34     * Class constructor
35     *
36     * @param null|array|\Traversable $options (Optional) Options to set
37     * @throws Exception\ExtensionNotLoadedException if bz2 extension not loaded
38     */
39    public function __construct($options = null)
40    {
41        if (!extension_loaded('bz2')) {
42            throw new Exception\ExtensionNotLoadedException('This filter needs the bz2 extension');
43        }
44        parent::__construct($options);
45    }
46
47    /**
48     * Returns the set blocksize
49     *
50     * @return int
51     */
52    public function getBlocksize()
53    {
54        return $this->options['blocksize'];
55    }
56
57    /**
58     * Sets a new blocksize
59     *
60     * @param  int $blocksize
61     * @throws Exception\InvalidArgumentException
62     * @return self
63     */
64    public function setBlocksize($blocksize)
65    {
66        if (($blocksize < 0) || ($blocksize > 9)) {
67            throw new Exception\InvalidArgumentException('Blocksize must be between 0 and 9');
68        }
69
70        $this->options['blocksize'] = (int) $blocksize;
71        return $this;
72    }
73
74    /**
75     * Returns the set archive
76     *
77     * @return string
78     */
79    public function getArchive()
80    {
81        return $this->options['archive'];
82    }
83
84    /**
85     * Sets the archive to use for de-/compression
86     *
87     * @param  string $archive Archive to use
88     * @return self
89     */
90    public function setArchive($archive)
91    {
92        $this->options['archive'] = (string) $archive;
93        return $this;
94    }
95
96    /**
97     * Compresses the given content
98     *
99     * @param  string $content
100     * @return string
101     * @throws Exception\RuntimeException
102     */
103    public function compress($content)
104    {
105        $archive = $this->getArchive();
106        if (!empty($archive)) {
107            $file = bzopen($archive, 'w');
108            if (!$file) {
109                throw new Exception\RuntimeException("Error opening the archive '" . $archive . "'");
110            }
111
112            bzwrite($file, $content);
113            bzclose($file);
114            $compressed = true;
115        } else {
116            $compressed = bzcompress($content, $this->getBlocksize());
117        }
118
119        if (is_int($compressed)) {
120            throw new Exception\RuntimeException('Error during compression');
121        }
122
123        return $compressed;
124    }
125
126    /**
127     * Decompresses the given content
128     *
129     * @param  string $content
130     * @return string
131     * @throws Exception\RuntimeException
132     */
133    public function decompress($content)
134    {
135        $archive = $this->getArchive();
136
137        //check if there are null byte characters before doing a file_exists check
138        if (!strstr($content, "\0") && file_exists($content)) {
139            $archive = $content;
140        }
141
142        if (file_exists($archive)) {
143            $file = bzopen($archive, 'r');
144            if (!$file) {
145                throw new Exception\RuntimeException("Error opening the archive '" . $content . "'");
146            }
147
148            $compressed = bzread($file);
149            bzclose($file);
150        } else {
151            $compressed = bzdecompress($content);
152        }
153
154        if (is_int($compressed)) {
155            throw new Exception\RuntimeException('Error during decompression');
156        }
157
158        return $compressed;
159    }
160
161    /**
162     * Returns the adapter name
163     *
164     * @return string
165     */
166    public function toString()
167    {
168        return 'Bz2';
169    }
170}
171