Completed
Pull Request — master (#103)
by
unknown
03:07
created

Webhook::setup()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 1
crap 2.0185
1
<?php
2
namespace phpbu\App\Log;
3
4
use phpbu\App\Exception;
5
use phpbu\App\Event;
6
use phpbu\App\Listener;
7
use phpbu\App\Result;
8
9
/**
10
 * Webhook Logger
11
 *
12
 * @package    phpbu
13
 * @subpackage Log
14
 * @author     Cees Vogel <[email protected]>
15
 * @author     Sebastian Feldmann <[email protected]>
16
 * @copyright  Sebastian Feldmann <[email protected]>
17
 * @license    https://opensource.org/licenses/MIT The MIT License (MIT)
18
 * @link       http://phpbu.de/
19
 * @since      Class available since Release ???
20
 */
21
class Webhook implements Listener, Logger
22
{
23
    /**
24
     * @var array: List of all debug messages
25
     */
26
    protected $debug = [];
27
28
    /**
29
     * @var array: options for Webhook
30
     */
31
    protected $options = [];
32
33
    /**
34
     * @var null: timer start
35
     */
36
    protected $start = null;
37
38
    /**
39
     * Constructor will only set the start time to be able to log duration
40
     */
41 7
    public function __construct()
42
    {
43 7
        $this->start = microtime(true);
44 7
    }
45
46
    /**
47
     * Returns an array of event names this subscriber wants to listen to.
48
     *
49
     * The array keys are event names and the value can be:
50
     *
51
     *  * The method name to call (priority defaults to 0)
52
     *  * An array composed of the method name to call and the priority
53
     *  * An array of arrays composed of the method names to call and respective
54
     *    priorities, or 0 if unset
55
     *
56
     * @return array The event names to listen to
57
     */
58 1
    public static function getSubscribedEvents()
59
    {
60
        return [
61 1
            'phpbu.debug' => 'onDebug',
62
            'phpbu.app_end' => 'onPhpbuEnd',
63
        ];
64
    }
65
66
    /**
67
     * Setup the logger.
68
     *
69
     * @see    \phpbu\App\Log\Logger::setup
70
     * @param  array $options
71
     * @throws \phpbu\App\Exception
72
     */
73 6
    public function setup(array $options)
74
    {
75 6
        if (empty($options['uri'])) {
76
            throw new Exception('no uri given');
77
        }
78
        $defaults = [
79 6
            'method' => 'GET',
80
            'xml-root' => 'root',
81
            'content-type' => 'multipart/form-data',
82
            'auth-user' => '',
83
            'auth-pwd' => '',
84
            'jsonOutput' => ''
85
        ];
86 6
        $this->options = array_merge($defaults, $options);
87 6
    }
88
89
    /**
90
     * phpbu end event.
91
     *
92
     * @param \phpbu\App\Event\App\End $event
93
     */
94
    public function onPhpbuEnd(Event\App\End $event)
95
    {
96
        $result = $event->getResult();
97
98
        $output = $this->getOutput($result);
99
100
        $this->execute($output);
101
    }
102
103
    /**
104
     * Debugging.
105
     *
106
     * @param \phpbu\App\Event\Debug $event
107
     */
108
    public function onDebug(Event\Debug $event)
109
    {
110
        $this->debug[] = $event->getMessage();
111
    }
112
113
    /**
114
     * Method will use the input Result to replace the placeholders in $this->jsonOutput or return an array with
115
     * the default values.
116
     *
117
     * @param $result \phpbu\App\Result
118
     * @return array: will return array placeholders are replaced with correct data
0 ignored issues
show
Documentation introduced by
The doc-type array: could not be parsed: Unknown type name "array:" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
119
     */
120 3
    public function getOutput($result) : array
121
    {
122
        $vars = [
123 3
            '__status__' => $result->allOk() ? 0 : 1,
124 3
            '__timestamp__' => time(),
125 3
            '__duration__' => round(microtime(true) - $this->start, 4),
126 3
            '__errors__' => $this->extractErrors($result),
127 3
            '__backups__' => $this->extractBackups($result),
128 3
            '__errorcount__' => count($result->getErrors())
129
        ];
130
131 3
        if (!empty($this->options['jsonOutput']) && is_string($this->options['jsonOutput'])) {
132
            // first convert to array. Simple str_replace won't work because of arrays in backups and errors.
133 2
            $outputArray = json_decode(html_entity_decode($this->options['jsonOutput']), true);
134
            // check if json_decode succeeded, otherwise return default parameters
135 2
            if ($outputArray) {
136
                // only value where valuestring equals vars key is supported.
137 1
                array_walk_recursive($outputArray, function (&$value, &$key) use ($vars) {
138 1
                    if (strpos($value, '__') === 0) {
139 1
                        $value = $vars[$value];
140
                    }
141 1
                });
142 1
                return $outputArray;
143
            }
144
        }
145
        $default = [
146 2
            'status' => $vars['__status__'],
147 2
            'timestamp' => $vars['__timestamp__'],
148 2
            'duration' => $vars['__duration__'],
149 2
            'errorcount' => $vars['__errorcount__']
150
        ];
151
152 2
        return $default;
153
    }
154
155
    public function execute($output)
156
    {
157
        $ch = curl_init();
158
        $uri = $this->options['uri'];
159
        if (strtoupper($this->options['method']) == 'GET') {
160
            $uri .= '?' . http_build_query($output);
161
        }
162
        curl_setopt($ch, CURLOPT_URL, $uri);
163
        if (strtoupper($this->options['method']) == 'POST') {
164
            $output = $this->formatPostOutput($output);
165
            curl_setopt($ch, CURLOPT_POST, 1);
166
            curl_setopt($ch, CURLOPT_POSTFIELDS, $output);
167
        }
168
        if (!empty($this->options['auth-user']) && !empty($this->options['auth-pwd'])) {
169
            curl_setopt($ch, CURLOPT_USERPWD, $this->options['auth-user'] . ":" . $this->options['auth-pwd']);
170
        }
171
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
172
            'Content-Type: ' . $this->options['content-type'],
173
            'Accept: ' . $this->options['content-type']
174
        ]);
175
        curl_exec($ch);
176
        curl_close($ch);
177
    }
178
179
    /**
180
     * Method will format the output data in the format requested by the content-type
181
     * @param $output: different formats
182
     */
183 4
    public function formatPostOutput($output)
184
    {
185 4
        switch ($this->options['content-type']) {
186 4
            case 'application/json':
187 1
                return json_encode($output);
188 3
            case 'text/xml':
189 3
            case 'application/xml':
190 1
                $xml = new \SimpleXMLElement(sprintf('<%s/>', $this->options['xml-root']));
191 1
                $this->toXml($xml, $output);
192 1
                return $xml->asXML();
193 2
            case 'application/x-www-form-urlencoded':
194 1
            case 'multipart/form-data':
195
            default:
196 2
                return http_build_query($output);
197
        }
198
    }
199
200
    /**
201
     * Simple toXml function
202
     *
203
     * @author Francis Lewis: https://stackoverflow.com/a/19987539
204
     * @param SimpleXMLElement $object
205
     * @param array $data
206
     */
207 1
    private function toXml(\SimpleXMLElement $object, array $data)
208
    {
209 1
        foreach ($data as $key => $value) {
210 1
            if (is_array($value)) {
211 1
                $new_object = $object->addChild($key);
212 1
                $this->toXml($new_object, $value);
213
            } else {
214
                // if the key is an integer, it needs text with it to actually work.
215 1
                if ($key == (int)$key) {
216 1
                    $key = "key_$key";
217
                }
218
219 1
                $object->addChild($key, $value);
220
            }
221
        }
222 1
    }
223
224
225
    /**
226
     * Get error information.
227
     *
228
     * @param \phpbu\App\Result $result
229
     * @return array
230
     */
231 3 View Code Duplication
    protected function extractErrors(Result $result) : array
232
    {
233 3
        $errors = [];
234
        /** @var \Exception $e */
235 3
        foreach ($result->getErrors() as $e) {
236 3
            $errors[] = [
237 3
                'class' => get_class($e),
238 3
                'msg' => $e->getMessage(),
239 3
                'file' => $e->getFile(),
240 3
                'line' => $e->getLine()
241
            ];
242
        }
243 3
        return $errors;
244
    }
245
246
    /**
247
     * Return backup information.
248
     *
249
     * @param  \phpbu\App\Result $result
250
     * @return array
251
     */
252 3 View Code Duplication
    protected function extractBackups(Result $result) : array
253
    {
254 3
        $output = [];
255 3
        $backups = $result->getBackups();
256 3
        if (count($backups) > 0) {
257
            /** @var \phpbu\App\Result\Backup $backup */
258 3
            foreach ($backups as $backup) {
259 3
                $output[] = [
260 3
                    'name' => $backup->getName(),
261 3
                    'status' => $backup->wasSuccessful() ? 0 : 1,
262
                    'checks' => [
263 3
                        'executed' => $backup->checkCount(),
264 3
                        'failed' => $backup->checkCountFailed()
265
                    ],
266
                    'crypt' => [
267 3
                        'executed' => $backup->cryptCount(),
268 3
                        'skipped' => $backup->cryptCountSkipped(),
269 3
                        'failed' => $backup->cryptCountFailed()
270
                    ],
271
                    'syncs' => [
272 3
                        'executed' => $backup->syncCount(),
273 3
                        'skipped' => $backup->syncCountSkipped(),
274 3
                        'failed' => $backup->syncCountFailed()
275
                    ],
276
                    'cleanups' => [
277 3
                        'executed' => $backup->cleanupCount(),
278 3
                        'skipped' => $backup->cleanupCountSkipped(),
279 3
                        'failed' => $backup->cleanupCountFailed()
280
                    ]
281
                ];
282
            }
283
        }
284 3
        return $output;
285
    }
286
}
287