Completed
Push — master ( f82444...6e866c )
by Daniel
02:55
created

CommonCode   C

Complexity

Total Complexity 69

Size/Duplication

Total Lines 488
Duplicated Lines 4.1 %

Coupling/Cohesion

Components 2
Dependencies 7

Importance

Changes 54
Bugs 6 Features 4
Metric Value
wmc 69
c 54
b 6
f 4
lcom 2
cbo 7
dl 20
loc 488
rs 5.6447

17 Methods

Rating   Name   Duplication   Size   Complexity  
B arrayDiffAssocRecursive() 0 19 8
C getContentFromUrlThroughCurl() 10 48 8
B getContentFromUrlThroughCurlAsArrayIfJson() 10 15 5
A getFeedbackMySQLAffectedRecords() 0 10 2
B getFileDetails() 0 40 3
A getListOfFiles() 0 18 4
B getTimestamp() 0 32 4
A isJsonByDanielGP() 0 9 2
A moveFilesIntoTargetFolder() 0 19 3
C removeFilesOlderThanGivenRule() 0 38 8
C sendBackgroundEncodedFormElementsByPost() 0 36 7
A setArrayToJson() 0 13 3
A setArrayToArrayKbr() 0 8 2
A setArrayValuesAsKey() 0 6 1
A setDividedResult() 0 17 4
A setJsonErrorInPlainEnglish() 0 17 2
A setJsonToArray() 0 17 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like CommonCode often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CommonCode, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 *
5
 * The MIT License (MIT)
6
 *
7
 * Copyright (c) 2015 Daniel Popiniuc
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 *
16
 * The above copyright notice and this permission notice shall be included in all
17
 * copies or substantial portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25
 * SOFTWARE.
26
 *
27
 */
28
29
namespace danielgp\common_lib;
30
31
/**
32
 * usefull functions to get quick results
33
 *
34
 * @author Daniel Popiniuc
35
 */
36
trait CommonCode
37
{
38
39
    use CommonLibLocale,
40
        CommonPermissions,
41
        DomComponentsByDanielGP,
42
        MySQLiByDanielGPqueries,
43
        MySQLiByDanielGP;
44
45
    protected function arrayDiffAssocRecursive($array1, $array2)
46
    {
47
        $difference = [];
48
        foreach ($array1 as $key => $value) {
49
            if (is_array($value)) {
50
                if (!isset($array2[$key]) || !is_array($array2[$key])) {
51
                    $difference[$key] = $value;
52
                } else {
53
                    $workingDiff = $this->arrayDiffAssocRecursive($value, $array2[$key]);
54
                    if (!empty($workingDiff)) {
55
                        $difference[$key] = $workingDiff;
56
                    }
57
                }
58
            } elseif (!array_key_exists($key, $array2) || $array2[$key] !== $value) {
59
                $difference[$key] = $value;
60
            }
61
        }
62
        return $difference;
63
    }
64
65
    /**
66
     * Reads the content of a remote file through CURL extension
67
     *
68
     * @param string $fullURL
69
     * @param array $features
70
     * @return blob
71
     */
72
    protected function getContentFromUrlThroughCurl($fullURL, $features = null)
73
    {
74
        $aReturn = [];
75
        if (!function_exists('curl_init')) {
76
            $aReturn['info']     = $this->lclMsgCmn('i18n_Error_ExtensionNotLoaded');
77
            $aReturn['response'] = '';
78
        }
79
        if (!filter_var($fullURL, FILTER_VALIDATE_URL)) {
80
            $aReturn['info']     = $this->lclMsgCmn('i18n_Error_GivenUrlIsNotValid');
81
            $aReturn['response'] = '';
82
        }
83
        $chanel = curl_init();
84
        curl_setopt($chanel, CURLOPT_USERAGENT, $this->getUserAgentByCommonLib());
85
        if ((strpos($fullURL, 'https') !== false) || (isset($features['forceSSLverification']))) {
86
            curl_setopt($chanel, CURLOPT_SSL_VERIFYHOST, false);
87
            curl_setopt($chanel, CURLOPT_SSL_VERIFYPEER, false);
88
        }
89
        curl_setopt($chanel, CURLOPT_URL, $fullURL);
90
        curl_setopt($chanel, CURLOPT_HEADER, false);
91
        curl_setopt($chanel, CURLOPT_RETURNTRANSFER, true);
92
        curl_setopt($chanel, CURLOPT_FRESH_CONNECT, true); //avoid a cached response
93
        curl_setopt($chanel, CURLOPT_FAILONERROR, true);
94
        $rspJsonFromClient = curl_exec($chanel);
95
        if (curl_errno($chanel)) {
96
            $aReturn['info']     = $this->setArrayToJson([
97
                '#'           => curl_errno($chanel),
98
                'description' => curl_error($chanel)
99
            ]);
100
            $aReturn['response'] = '';
101
        } else {
102
            $aReturn['info']     = $this->setArrayToJson(curl_getinfo($chanel));
103
            $aReturn['response'] = $rspJsonFromClient;
104
        }
105
        curl_close($chanel);
106
        $sReturn = '';
0 ignored issues
show
Unused Code introduced by
$sReturn is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
107 View Code Duplication
        if ($this->isJsonByDanielGP($aReturn['info'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
108
            $sReturn = '"info": ' . $aReturn['info'];
109
        } else {
110
            $sReturn = '"info": {' . $aReturn['info'] . ' }';
111
        }
112
        $sReturn .= ', ';
113 View Code Duplication
        if ($this->isJsonByDanielGP($aReturn['response'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
114
            $sReturn .= '"response": ' . $aReturn['response'];
115
        } else {
116
            $sReturn .= '"response": { ' . $aReturn['response'] . ' }';
117
        }
118
        return '{ ' . $sReturn . ' }';
119
    }
120
121
    /**
122
     * Reads the content of a remote file through CURL extension
123
     *
124
     * @param string $fullURL
125
     * @param array $features
126
     * @return blob
127
     */
128
    protected function getContentFromUrlThroughCurlAsArrayIfJson($fullURL, $features = null)
129
    {
130
        $result = $this->setJsonToArray($this->getContentFromUrlThroughCurl($fullURL, $features));
131 View Code Duplication
        if (isset($result['info'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
132
            if (is_array($result['info'])) {
133
                ksort($result['info']);
134
            }
135
        }
136 View Code Duplication
        if (isset($result['response'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
137
            if (is_array($result['response'])) {
138
                ksort($result['response']);
139
            }
140
        }
141
        return $result;
142
    }
143
144
    protected function getFeedbackMySQLAffectedRecords()
145
    {
146
        if (is_null($this->mySQLconnection)) {
147
            $message = 'No MySQL';
148
        } else {
149
            $afRows  = $this->mySQLconnection->affected_rows;
150
            $message = sprintf($this->lclMsgCmnNumber('i18n_Record', 'i18n_Records', $afRows), $afRows);
151
        }
152
        return '<div>' . $message . '</div>';
153
    }
154
155
    /**
156
     * returns the details about Communicator (current) file
157
     *
158
     * @param string $fileGiven
159
     * @return array
160
     */
161
    protected function getFileDetails($fileGiven)
162
    {
163
        if (!file_exists($fileGiven)) {
164
            return ['error' => sprintf($this->lclMsgCmn('i18n_Error_GivenFileDoesNotExist'), $fileGiven)];
165
        }
166
        $info = new \SplFileInfo($fileGiven);
167
        return [
168
            'File Extension'         => $info->getExtension(),
169
            'File Group'             => $info->getGroup(),
170
            'File Inode'             => $info->getInode(),
171
            'File Link Target'       => ($info->isLink() ? $info->getLinkTarget() : '-'),
172
            'File is Dir'            => $info->isDir(),
173
            'File is Executable'     => $info->isExecutable(),
174
            'File is File'           => $info->isFile(),
175
            'File is Link'           => $info->isLink(),
176
            'File is Readable'       => $info->isReadable(),
177
            'File is Writable'       => $info->isWritable(),
178
            'File Name'              => $info->getBasename('.' . $info->getExtension()),
179
            'File Name w. Extension' => $info->getFilename(),
180
            'File Owner'             => $info->getOwner(),
181
            'File Path'              => $info->getPath(),
182
            'File Permissions'       => $this->explainPerms($info->getPerms()),
183
            'Name'                   => $info->getRealPath(),
184
            'Size'                   => $info->getSize(),
185
            'Sha1'                   => sha1_file($fileGiven),
186
            'Timestamp Accessed'     => [
187
                'PHP number' => $info->getATime(),
188
                'SQL format' => date('Y-m-d H:i:s', $info->getATime()),
189
            ],
190
            'Timestamp Changed'      => [
191
                'PHP number' => $info->getCTime(),
192
                'SQL format' => date('Y-m-d H:i:s', $info->getCTime()),
193
            ],
194
            'Timestamp Modified'     => [
195
                'PHP number' => $info->getMTime(),
196
                'SQL format' => date('Y-m-d H:i:s', $info->getMTime()),
197
            ],
198
            'Type'                   => $info->getType(),
199
        ];
200
    }
201
202
    /**
203
     * returns a multi-dimensional array with list of file details within a given path
204
     * (by using Symfony/Finder package)
205
     *
206
     * @param  string $pathAnalised
207
     * @return array
208
     */
209
    protected function getListOfFiles($pathAnalised)
210
    {
211
        if (realpath($pathAnalised) === false) {
212
            return ['error' => sprintf($this->lclMsgCmn('i18n_Error_GivenPathIsNotValid'), $pathAnalised)];
213
        } elseif (!is_dir($pathAnalised)) {
214
            return ['error' => $this->lclMsgCmn('i18n_Error_GivenPathIsNotFolder')];
215
        }
216
        $aFiles   = null;
217
        $finder   = new \Symfony\Component\Finder\Finder();
218
        $iterator = $finder
219
                ->files()
220
                ->sortByName()
221
                ->in($pathAnalised);
222
        foreach ($iterator as $file) {
223
            $aFiles[$file->getRealPath()] = $this->getFileDetails($file);
224
        }
225
        return $aFiles;
226
    }
227
228
    /**
229
     * Returns server Timestamp into various formats
230
     *
231
     * @param string $returnType
232
     * @return string
233
     */
234
    protected function getTimestamp($returnType = 'string')
235
    {
236
        $crtTime = gettimeofday();
237
        switch ($returnType) {
238
            case 'array':
239
                $sReturn = [
240
                    'float'  => ($crtTime['sec'] + $crtTime['usec'] / pow(10, 6)),
241
                    'string' => implode('', [
242
                        '<span style="color:black!important;font-weight:bold;">[',
243
                        date('Y-m-d H:i:s.', $crtTime['sec']),
244
                        substr(round($crtTime['usec'], -3), 0, 3),
245
                        ']</span> '
246
                    ]),
247
                ];
248
                break;
249
            case 'float':
250
                $sReturn = ($crtTime['sec'] + $crtTime['usec'] / pow(10, 6));
251
                break;
252
            case 'string':
253
                $sReturn = implode('', [
254
                    '<span style="color:black!important;font-weight:bold;">[',
255
                    date('Y-m-d H:i:s.', $crtTime['sec']),
256
                    substr(round($crtTime['usec'], -3), 0, 3),
257
                    ']</span> '
258
                ]);
259
                break;
260
            default:
261
                $sReturn = sprintf($this->lclMsgCmn('i18n_Error_UnknownReturnType'), $returnType);
262
                break;
263
        }
264
        return $sReturn;
265
    }
266
267
    /**
268
     * Tests if given string has a valid Json format
269
     *
270
     * @param string $inputJson
271
     * @return boolean|string
272
     */
273
    protected function isJsonByDanielGP($inputJson)
274
    {
275
        if (is_string($inputJson)) {
276
            json_decode($inputJson);
277
            return (json_last_error() == JSON_ERROR_NONE);
278
        } else {
279
            return $this->lclMsgCmn('i18n_Error_GivenInputIsNotJson');
280
        }
281
    }
282
283
    /**
284
     * Moves files into another folder
285
     *
286
     * @param type $sourcePath
287
     * @param type $targetPath
288
     * @param type $overwrite
0 ignored issues
show
Bug introduced by
There is no parameter named $overwrite. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
289
     * @return type
290
     */
291
    protected function moveFilesIntoTargetFolder($sourcePath, $targetPath)
292
    {
293
        $filesystem = new \Symfony\Component\Filesystem\Filesystem();
294
        $filesystem->mirror($sourcePath, $targetPath);
295
        $finder     = new \Symfony\Component\Finder\Finder();
296
        $iterator   = $finder
297
                ->files()
298
                ->ignoreUnreadableDirs(true)
299
                ->followLinks()
300
                ->in($sourcePath);
301
        $sFiles     = [];
302
        foreach ($iterator as $file) {
303
            $relativePathFile = str_replace($sourcePath, '', $file->getRealPath());
304
            if (!file_exists($targetPath . $relativePathFile)) {
305
                $sFiles[$relativePathFile] = $targetPath . $relativePathFile;
306
            }
307
        }
308
        return $this->setArrayToJson($sFiles);
309
    }
310
311
    /**
312
     * Remove files older than given rule
313
     * (both Access time and Modified time will be checked
314
     * and only if both matches removal will take place)
315
     *
316
     * @param array $inputArray
317
     * @return string
318
     */
319
    protected function removeFilesOlderThanGivenRule($inputArray)
320
    {
321
        if (is_array($inputArray)) {
322
            if (!isset($inputArray['path'])) {
323
                $proceedWithDeletion = false;
324
                $error               = '`path` has not been provided';
325
            } elseif (!isset($inputArray['dateRule'])) {
326
                $proceedWithDeletion = false;
327
                $error               = '`dateRule` has not been provided';
328
            } else {
329
                $proceedWithDeletion = true;
330
            }
331
        } else {
332
            $proceedWithDeletion = false;
333
        }
334
        if ($proceedWithDeletion) {
335
            $finder   = new \Symfony\Component\Finder\Finder();
336
            $iterator = $finder
337
                    ->files()
338
                    ->ignoreUnreadableDirs(true)
339
                    ->followLinks()
340
                    ->in($inputArray['path']);
341
            $aFiles   = null;
342
            foreach ($iterator as $file) {
343
                if ($file->getATime() < strtotime($inputArray['dateRule'])) {
344
                    $aFiles[] = $file->getRealPath();
345
                }
346
            }
347
            if (is_null($aFiles)) {
348
                return null;
349
            } else {
350
                $filesystem = new \Symfony\Component\Filesystem\Filesystem();
351
                $filesystem->remove($aFiles);
352
                return $this->setArrayToJson($aFiles);
353
            }
354
        }
355
        return $error;
0 ignored issues
show
Bug introduced by
The variable $error does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
356
    }
357
358
    /**
359
     * Send an array of parameters like a form through a POST action
360
     *
361
     * @param string $urlToSendTo
362
     * @param array $params
363
     * @throws \Exception
364
     * @throws \UnexpectedValueException
365
     */
366
    protected function sendBackgroundEncodedFormElementsByPost($urlToSendTo, $params = [])
0 ignored issues
show
Coding Style introduced by
sendBackgroundEncodedFormElementsByPost uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
367
    {
368
        try {
369
            $postingUrl = filter_var($urlToSendTo, FILTER_VALIDATE_URL);
370
            if ($postingUrl === false) {
371
                throw new \Exception($exc);
372
            } else {
373
                if (is_array($params)) {
374
                    $postingString   = $this->setArrayToStringForUrl('&', $params);
375
                    $postingUrlParts = parse_url($postingUrl);
376
                    $postingPort     = (isset($postingUrlParts['port']) ? $postingUrlParts['port'] : 80);
377
                    $flPointer       = fsockopen($postingUrlParts['host'], $postingPort, $errNo, $errorMessage, 30);
378
                    if ($flPointer === false) {
379
                        throw new \UnexpectedValueException($this->lclMsgCmn('i18n_Error_FailedToConnect') . ': '
380
                        . $errNo . ' (' . $errorMessage . ')');
381
                    } else {
382
                        $out[] = 'POST ' . $postingUrlParts['path'] . ' ' . $_SERVER['SERVER_PROTOCOL'];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$out was never initialized. Although not strictly required by PHP, it is generally a good practice to add $out = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
383
                        $out[] = 'Host: ' . $postingUrlParts['host'];
384
                        if (isset($_SERVER['HTTP_USER_AGENT'])) {
385
                            $out[] = 'User-Agent: ' . filter_var($_SERVER['HTTP_USER_AGENT'], FILTER_SANITIZE_STRING);
386
                        }
387
                        $out[] = 'Content-Type: application/x-www-form-urlencoded';
388
                        $out[] = 'Content-Length: ' . strlen($postingString);
389
                        $out[] = 'Connection: Close' . "\r\n";
390
                        $out[] = $postingString;
391
                        fwrite($flPointer, implode("\r\n", $out));
392
                        fclose($flPointer);
393
                    }
394
                } else {
395
                    throw new \UnexpectedValueException($this->lclMsgCmn('i18n_Error_GivenParameterIsNotAnArray'));
396
                }
397
            }
398
        } catch (\Exception $exc) {
399
            echo '<pre style="color:#f00">' . $exc->getTraceAsString() . '</pre>';
400
        }
401
    }
402
403
    /**
404
     * Converts an array into JSON string
405
     *
406
     * @param array $inArray
407
     * @return string
408
     */
409
    protected function setArrayToJson(array $inArray)
410
    {
411
        if (!is_array($inArray)) {
412
            return $this->lclMsgCmn('i18n_Error_GivenInputIsNotArray');
413
        }
414
        $rtrn      = utf8_encode(json_encode($inArray, JSON_FORCE_OBJECT | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT));
415
        $jsonError = $this->setJsonErrorInPlainEnglish();
416
        if (is_null($jsonError)) {
417
            return $rtrn;
418
        } else {
419
            return $jsonError;
420
        }
421
    }
422
423
    /**
424
     * Replace space with break line for each key element
425
     *
426
     * @param array $aElements
427
     * @return array
428
     */
429
    protected function setArrayToArrayKbr(array $aElements)
430
    {
431
        $aReturn = [];
432
        foreach ($aElements as $key => $value) {
433
            $aReturn[str_replace(' ', '<br/>', $key)] = $value;
434
        }
435
        return $aReturn;
436
    }
437
438
    /**
439
     * Converts a single-child array into an parent-child one
440
     *
441
     * @param type $inArray
442
     * @return type
443
     */
444
    protected function setArrayValuesAsKey(array $inArray)
445
    {
446
        $outArray = array_combine($inArray, $inArray);
447
        ksort($outArray);
448
        return $outArray;
449
    }
450
451
    /**
452
     * Returns proper result from a mathematical division in order to avoid Zero division erorr or Infinite results
453
     *
454
     * @param float $fAbove
455
     * @param float $fBelow
456
     * @param mixed $mArguments
457
     * @return decimal
458
     */
459
    protected function setDividedResult($fAbove, $fBelow, $mArguments = 0)
460
    {
461
        // prevent infinite result AND division by 0
462
        if (($fAbove == 0) || ($fBelow == 0)) {
463
            $nReturn = 0;
464
        } else {
465
            if (is_array($mArguments)) {
466
                $nReturn = $this->setNumberFormat(($fAbove / $fBelow), [
467
                    'MinFractionDigits' => $mArguments[1],
468
                    'MaxFractionDigits' => $mArguments[1],
469
                ]);
470
            } else {
471
                $nReturn = $this->setNumberFormat(round(($fAbove / $fBelow), $mArguments));
472
            }
473
        }
474
        return $nReturn;
475
    }
476
477
    /**
478
     * Provides a list of all known JSON errors and their description
479
     *
480
     * @return type
481
     */
482
    private function setJsonErrorInPlainEnglish()
483
    {
484
        $knownErrors  = [
485
            JSON_ERROR_NONE           => null,
486
            JSON_ERROR_DEPTH          => 'Maximum stack depth exceeded',
487
            JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch',
488
            JSON_ERROR_CTRL_CHAR      => 'Unexpected control character found',
489
            JSON_ERROR_SYNTAX         => 'Syntax error, malformed JSON',
490
            JSON_ERROR_UTF8           => 'Malformed UTF-8 characters, possibly incorrectly encoded',
491
        ];
492
        $currentError = json_last_error();
493
        $sReturn      = null;
494
        if (in_array($currentError, $knownErrors)) {
495
            $sReturn = $knownErrors[$currentError];
496
        }
497
        return $sReturn;
498
    }
499
500
    /**
501
     * Converts a JSON string into an Array
502
     *
503
     * @param string $inputJson
504
     * @return array
505
     */
506
    protected function setJsonToArray($inputJson)
507
    {
508
        if (!$this->isJsonByDanielGP($inputJson)) {
509
            return [
510
                'error' => $this->lclMsgCmn('i18n_Error_GivenInputIsNotJson')
511
            ];
512
        }
513
        $sReturn   = (json_decode($inputJson, true));
514
        $jsonError = $this->setJsonErrorInPlainEnglish();
515
        if (is_null($jsonError)) {
516
            return $sReturn;
517
        } else {
518
            return [
519
                'error' => $jsonError
520
            ];
521
        }
522
    }
523
}
524