Completed
Push — master ( 281cc9...fac822 )
by Sebastian
13:32 queued 10:28
created

AzureBlob::createClient()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 2
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
namespace phpbu\App\Backup\Sync;
3
4
use MicrosoftAzure\Storage\Blob\BlobRestProxy;
5
use phpbu\App\Backup\Collector;
6
use phpbu\App\Backup\Path;
7
use phpbu\App\Backup\Target;
8
use phpbu\App\Result;
9
use phpbu\App\Util;
10
11
/**
12
 * Azure Blob Sync
13
 *
14
 * @package    phpbu
15
 * @subpackage Backup
16
 * @author     Jonathan Bouzekri <[email protected]>
17
 * @author     Sebastian Feldmann <[email protected]>
18
 * @copyright  Sebastian Feldmann <[email protected]>
19
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
20
 * @link       http://phpbu.de/
21
 * @since      Class available since Release 5.2.7
22
 */
23
class AzureBlob implements Simulator
24
{
25
    use Cleanable;
26
27
    /**
28
     * Azure Blob client.
29
     *
30
     * @var BlobRestProxy;
31
     */
32
    private $client;
33
34
35
    /**
36
     * Azure Blob Connection String
37
     *
38
     * @var string
39
     */
40
    private $connectionString;
41
42
    /**
43
     * Azure Blob Container Name
44
     *
45
     * @var string
46
     */
47
    private $containerName;
48
49
    /**
50
     * Azure Blob remote path
51
     *
52
     * @var string
53
     */
54
    protected $path;
55
56
    /**
57
     * Azure Blob remote raw path
58
     *
59
     * @var string
60
     */
61
    protected $pathRaw;
62
63
    /**
64
     * Unix timestamp of generating path from placeholder.
65
     *
66
     * @var int
67
     */
68
    protected $time;
69
70
    /**
71
     * Configure the sync.
72
     *
73
     * @see    \phpbu\App\Backup\Sync::setup()
74
     * @param  array $config
75
     * @throws \phpbu\App\Backup\Sync\Exception
76
     * @throws \phpbu\App\Exception
77
     */
78 10
    public function setup(array $config)
79
    {
80 10
        if (!class_exists('\\MicrosoftAzure\\Storage\\Blob\\BlobRestProxy')) {
81
            throw new Exception('Azure Bob Storage SDK not loaded: use composer to install ' .
82
                                         '"microsoft/azure-storage-blob"');
83
        }
84
85
        // check for mandatory options
86 10
        $this->validateConfig($config, ['connection_string', 'container_name', 'path']);
87
88 7
        $cleanedPath            = Util\Path::withoutTrailingSlash(Util\Path::withoutLeadingSlash($config['path']));
89 7
        $this->time             = time();
90 7
        $this->connectionString = $config['connection_string'];
91 7
        $this->containerName    = $config['container_name'];
92 7
        $this->path             = Util\Path::replaceDatePlaceholders($cleanedPath, $this->time);
93 7
        $this->pathRaw          = $cleanedPath;
94 7
        $this->setUpCleanable($config);
95 7
    }
96
97
    /**
98
     * Make sure all mandatory keys are present in given config.
99
     *
100
     * @param  array $config
101
     * @param  array $keys
102
     * @throws Exception
103
     */
104 10
    protected function validateConfig(array $config, array $keys)
105
    {
106 10
        foreach ($keys as $option) {
107 10
            if (!Util\Arr::isSetAndNotEmptyString($config, $option)) {
108 3
                throw new Exception($option . ' is mandatory');
109
            }
110
        }
111 7
    }
112
113
    /**
114
     * Execute the sync.
115
     *
116
     * @see    \phpbu\App\Backup\Sync::sync()
117
     * @param  \phpbu\App\Backup\Target $target
118
     * @param  \phpbu\App\Result        $result
119
     * @throws \phpbu\App\Backup\Sync\Exception
120
     */
121 3 View Code Duplication
    public function sync(Target $target, Result $result)
122
    {
123 3
        $this->client = $this->createClient();
124
125 3
        if (!$this->doesContainerExist($this->client, $this->containerName)) {
126 3
            $result->debug('create blob container');
127 3
            $this->createContainer($this->client);
128
        }
129
130
        try {
131 3
            $this->upload($target, $this->client);
132 2
            $result->debug('upload: done');
133
134
            // run remote cleanup
135 2
            $this->cleanup($target, $result);
136 1
        } catch (\Exception $e) {
137 1
            throw new Exception($e->getMessage(), null, $e);
138
        }
139 2
    }
140
141
    /**
142
     * Create the Azure Blob client.
143
     *
144
     * @return \MicrosoftAzure\Storage\Blob\BlobRestProxy
145
     */
146
    protected function createClient() : BlobRestProxy
147
    {
148
        return BlobRestProxy::createBlobService($this->connectionString);
149
    }
150
151
    /**
152
     * Creates collector for Azure Blob Storage
153
     *
154
     * @param  \phpbu\App\Backup\Target $target
155
     * @return \phpbu\App\Backup\Collector
156
     */
157 1
    protected function createCollector(Target $target) : Collector
158
    {
159 1
        $path = new Path($this->pathRaw, $this->time);
160 1
        return new Collector\AzureBlob($target, $path, $this->client, $this->containerName);
161
    }
162
163
    /**
164
     * Simulate the sync execution.
165
     *
166
     * @param \phpbu\App\Backup\Target $target
167
     * @param \phpbu\App\Result        $result
168
     */
169 1 View Code Duplication
    public function simulate(Target $target, Result $result)
170
    {
171 1
        $result->debug(
172 1
            'sync backup to Azure Blob' . PHP_EOL
173 1
            . '  connectionString: ********' . PHP_EOL
174 1
            . '  containerName:    ' . $this->containerName . PHP_EOL
175
        );
176
177 1
        $this->simulateRemoteCleanup($target, $result);
178 1
    }
179
180
    /**
181
     * Check if an Azure Blob Storage Container exists
182
     *
183
     * @param \MicrosoftAzure\Storage\Blob\BlobRestProxy $blobRestProxy
184
     * @param string                                     $containerName
185
     * @return bool
186
     */
187 3
    private function doesContainerExist(BlobRestProxy $blobRestProxy, string $containerName): bool
188
    {
189 3
        $containers = $blobRestProxy->listContainers()->getContainers();
190 3
        foreach ($containers as $container) {
191
            if ($container->getName() === $containerName) {
192
                return true;
193
            }
194
        }
195 3
        return false;
196
    }
197
198
    /**
199
     * Create an Azure Storage Container
200
     *
201
     * @param \MicrosoftAzure\Storage\Blob\BlobRestProxy $blobRestProxy
202
     */
203 3
    private function createContainer(BlobRestProxy $blobRestProxy)
204
    {
205 3
        $blobRestProxy->createContainer($this->containerName);
206 3
    }
207
208
    /**
209
     * Upload backup to Azure Blob Storage
210
     *
211
     * @param  \phpbu\App\Backup\Target                    $target
212
     * @param  \MicrosoftAzure\Storage\Blob\BlobRestProxy $blobRestProxy
213
     * @throws \phpbu\App\Backup\Sync\Exception
214
     * @throws \phpbu\App\Exception
215
     */
216 3
    private function upload(Target $target, BlobRestProxy $blobRestProxy)
217
    {
218 3
        $source = $this->getFileHandle($target->getPathname(), 'r');
219 3
        $blobRestProxy->createBlockBlob(
220 3
            $this->containerName,
221 3
            $this->getUploadPath($target),
222
            $source
223
        );
224 2
    }
225
226
    /**
227
     * Open stream and validate it.
228
     *
229
     * @param  string $path
230
     * @param  string $mode
231
     * @return resource
232
     * @throws \phpbu\App\Backup\Sync\Exception
233
     */
234 View Code Duplication
    protected function getFileHandle($path, $mode)
235
    {
236
        $handle = fopen($path, $mode);
237
        if (!is_resource($handle)) {
238
            throw new Exception('fopen failed: could not open stream ' . $path);
239
        }
240
        return $handle;
241
    }
242
243
    /**
244
     * Get the azure blob upload path
245
     *
246
     * @param  \phpbu\App\Backup\Target $target
247
     * @return string
248
     */
249 5
    public function getUploadPath(Target $target)
250
    {
251 5
        return (!empty($this->path) ? $this->path . '/' : '') . $target->getFilename();
252
    }
253
}
254