Completed
Pull Request — master (#901)
by
unknown
02:35
created

Zip::setPassword()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
nc 2
nop 1
dl 0
loc 12
rs 9.8666
c 0
b 0
f 0
1
<?php
2
3
namespace Spatie\Backup\Tasks\Backup;
4
5
use ZipArchive;
6
use Illuminate\Support\Str;
7
use Spatie\Backup\Helpers\Format;
8
9
class Zip
10
{
11
    /** @var \ZipArchive */
12
    protected $zipFile;
13
14
    /** @var int */
15
    protected $fileCount = 0;
16
17
    /** @var string */
18
    protected $pathToZip;
19
20
    /** @var string */
21
    protected $password;
22
23
    public static function createForManifest(Manifest $manifest, string $pathToZip): self
24
    {
25
        $zip = new static($pathToZip);
26
27
        $zip->open();
28
29
        $zip->setPassword(config('backup.backup.password', null));
30
31
        foreach ($manifest->files() as $file) {
32
            $zip->add($file, self::determineNameOfFileInZip($file, $pathToZip));
33
        }
34
35
        $zip->close();
36
37
        return $zip;
38
    }
39
40
    protected static function determineNameOfFileInZip(string $pathToFile, string $pathToZip)
41
    {
42
        $zipDirectory = pathinfo($pathToZip, PATHINFO_DIRNAME);
43
44
        $fileDirectory = pathinfo($pathToFile, PATHINFO_DIRNAME);
45
46
        if (Str::startsWith($fileDirectory, $zipDirectory)) {
47
            return str_replace($zipDirectory, '', $pathToFile);
48
        }
49
50
        return $pathToFile;
51
    }
52
53
    public static function formatZipFilename(string $filename): string
54
    {
55
        return ltrim($filename, DIRECTORY_SEPARATOR);
56
    }
57
58
    public function __construct(string $pathToZip)
59
    {
60
        $this->zipFile = new ZipArchive();
61
62
        $this->pathToZip = $pathToZip;
63
64
        $this->open();
65
    }
66
67
    public function path(): string
68
    {
69
        return $this->pathToZip;
70
    }
71
72
    public function size(): int
73
    {
74
        if ($this->fileCount === 0) {
75
            return 0;
76
        }
77
78
        return filesize($this->pathToZip);
79
    }
80
81
    public function humanReadableSize(): string
82
    {
83
        return Format::humanReadableSize($this->size());
84
    }
85
86
    public function open()
87
    {
88
        $this->zipFile->open($this->pathToZip, ZipArchive::CREATE);
89
    }
90
91
    public function close()
92
    {
93
        $this->zipFile->close();
94
    }
95
96
    /**
97
     * @param string|null $password
98
     * @return Zip
99
     */
100
    public function setPassword(?string $password): self
101
    {
102
        if (! empty($password) && ! method_exists(ZipArchive::class, 'setEncryptionName')) {
103
            consoleOutput()->info('Password encryption requires PHP 7.2 >= and libzip-dev >= 1.2.0');
0 ignored issues
show
Documentation Bug introduced by
The method info does not exist on object<Spatie\Backup\Helpers\ConsoleOutput>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
104
105
            return $this;
106
        }
107
108
        $this->password = $password;
109
110
        return $this;
111
    }
112
113
    /**
114
     * @param string $nameInZip
115
     *
116
     * @return Zip
117
     */
118
    protected function passwordProtectFile(string $nameInZip): self
119
    {
120
        if (empty($this->password)) {
121
            return $this;
122
        }
123
124
        if (! $this->zipFile->setEncryptionName($nameInZip, ZipArchive::EM_AES_256, $this->password)) {
125
            consoleOutput()->error("Cannot password protect {$nameInZip}");
0 ignored issues
show
Documentation Bug introduced by
The method error does not exist on object<Spatie\Backup\Helpers\ConsoleOutput>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
126
        }
127
128
        return $this;
129
    }
130
131
    /**
132
     * @param string|array $files
133
     * @param string $nameInZip
134
     *
135
     * @return \Spatie\Backup\Tasks\Backup\Zip
136
     */
137
    public function add($files, string $nameInZip = null): self
138
    {
139
        if (is_array($files)) {
140
            $nameInZip = null;
141
        }
142
143
        if (is_string($files)) {
144
            $files = [$files];
145
        }
146
147
        foreach ($files as $file) {
148
            if (file_exists($file)) {
149
                $localName = self::formatZipFilename($nameInZip ?? $file);
150
151
                if ($this->zipFile->addFile($file, $localName).PHP_EOL) {
152
                    $this->passwordProtectFile($localName);
153
                }
154
            }
155
            $this->fileCount++;
156
        }
157
158
        return $this;
159
    }
160
161
    public function count(): int
162
    {
163
        return $this->fileCount;
164
    }
165
}
166