Issues (1519)

system/Inji/Tools.php (12 issues)

1
<?php
2
namespace Inji;
3
/**
4
 * Tools object
5
 *
6
 * Toolkit with most needed functions
7
 *
8
 * @author Alexey Krupskiy <[email protected]>
9
 * @link http://inji.ru/
10
 * @copyright 2015 Alexey Krupskiy
11
 * @license https://github.com/injitools/cms-Inji/blob/master/LICENSE
12
 */
13
class Tools extends Model {
14
15
    /**
16
     * Return random string
17
     *
18
     * @param int $length
19
     * @param string $characters
20
     * @return string
21
     */
22
    public static function randomString($length = 20, $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') {
23
        $charactersLength = strlen($characters);
24
        $randomString = '';
25
        for ($i = 0; $i < $length; $i++) {
26
            $randomString .= $characters[rand(0, $charactersLength - 1)];
27
        }
28
        return $randomString;
29
    }
30
31
    /**
32
     * Clean and return user query params
33
     *
34
     * @param string $uri
35
     * @return array
36
     */
37
    public static function uriParse($uri) {
38
        $answerPos = strpos($uri, '?');
39
        $params = array_slice(explode('/', substr($uri, 0, $answerPos ? $answerPos : strlen($uri))), 1);
40
41
        foreach ($params as $key => $param) {
42
            if ($param != '') {
43
                $params[$key] = urldecode($param);
44
            } else {
45
                unset($params[$key]);
46
            }
47
        }
48
        return $params;
49
    }
50
51
    /**
52
     * Recursive create dir
53
     *
54
     * @param string $path
55
     * @return boolean
56
     */
57 9
    public static function createDir($path) {
58 9
        if (file_exists($path)) {
59 5
            return true;
60
        }
61 4
        $path = explode('/', $path);
62 4
        $cur = '';
63 4
        foreach ($path as $item) {
64 4
            $cur .= $item . '/';
65 4
            if (!file_exists($cur)) {
66 4
                mkdir($cur);
67
            }
68
        }
69 4
        return true;
70
    }
71
72
    public static function delDir($dir) {
73
        if (!file_exists($dir)) {
74
            return true;
75
        }
76
        $files = array_diff(scandir($dir), array('.', '..'));
77
        foreach ($files as $file) {
78
            is_dir("$dir/$file") ? self::delDir("$dir/$file") : unlink("$dir/$file");
79
        }
80
        return rmdir($dir);
81
    }
82
83
    /**
84
     * Resize image in path
85
     *
86
     * @param string $img_path
87
     * @param int $max_width
88
     * @param int $max_height
89
     * @param string|false $crop
90
     * @param string $pos
91
     * @return string
92
     */
93
    public static function resizeImage($img_path, $max_width = 1000, $max_height = 1000, $crop = false, $pos = 'center') {
94
        ini_set("gd.jpeg_ignore_warning", 1);
95
        if (!getimagesize($img_path)) {
96
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
97
        }
98
        list($img_width, $img_height, $img_type, $img_tag) = getimagesize($img_path);
99
        switch ($img_type) {
100
            case 1:
101
                $img_type = 'gif';
102
                break;
103
            case 3:
104
                $img_type = 'png';
105
                break;
106
            case 2:
107
            default:
108
                $img_type = 'jpeg';
109
                break;
110
        }
111
        $imagecreatefromX = "imagecreatefrom{$img_type}";
112
        $src_res = @$imagecreatefromX($img_path);
113
        if (!$src_res) {
114
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
115
        }
116
117
        if ($img_width / $max_width > $img_height / $max_height) {
118
            $separator = $img_width / $max_width;
119
        } else {
120
            $separator = $img_height / $max_height;
121
        }
122
123
        if ($crop === true || $crop == 'q') {
124
            if ($img_width > $img_height) {
125
                $imgX = floor(($img_width - $img_height) / 2);
126
                $imgY = 0;
127
                $img_width = $img_height;
128
                $new_width = $max_width;
129
                $new_height = $max_height;
130
            } else {
131
                $imgX = 0;
132
                $imgY = floor(($img_height - $img_width) / 2);
133
                $img_height = $img_width;
134
                $new_width = $max_width;
135
                $new_height = $max_height;
136
            }
137
            if ($pos == 'top') {
138
                $imgY = 0;
139
            }
140
        } elseif ($crop == 'c') {
141
//Вычисляем некий коэффициент масштабирования
142
            $k1 = $img_width / $max_width;
143
            $k2 = $img_height / $max_height;
144
            $k = $k1 > $k2 ? $k2 : $k1;
145
            $ow = $img_width;
146
            $oh = $img_height;
147
//Вычисляем размеры области для нового изображения
148
            $img_width = intval($max_width * $k);
149
            $img_height = intval($max_height * $k);
150
            $new_width = $max_width;
151
            $new_height = $max_height;
152
//Находим начальные координаты (центрируем новое изображение)
153
            $imgX = (int) (($ow / 2) - ($img_width / 2));
154
            if ($pos == 'center') {
155
                $imgY = (int) (($oh / 2) - ($img_height / 2));
156
            } else {
157
                $imgY = 0;
158
            }
159
        } else {
160
            $imgX = 0;
161
            $imgY = 0;
162
            $new_width = floor($img_width / $separator);
163
            $new_height = floor($img_height / $separator);
164
        }
165
166
        $new_res = imagecreatetruecolor($new_width, $new_height);
0 ignored issues
show
It seems like $new_width can also be of type double; however, parameter $width of imagecreatetruecolor() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

166
        $new_res = imagecreatetruecolor(/** @scrutinizer ignore-type */ $new_width, $new_height);
Loading history...
It seems like $new_height can also be of type double; however, parameter $height of imagecreatetruecolor() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

166
        $new_res = imagecreatetruecolor($new_width, /** @scrutinizer ignore-type */ $new_height);
Loading history...
167
        imageAlphaBlending($new_res, false);
168
        imagesavealpha($new_res, true);
169
        imagecopyresampled($new_res, $src_res, 0, 0, $imgX, $imgY, $new_width, $new_height, $img_width, $img_height);
0 ignored issues
show
It seems like $new_height can also be of type double; however, parameter $dst_h of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        imagecopyresampled($new_res, $src_res, 0, 0, $imgX, $imgY, $new_width, /** @scrutinizer ignore-type */ $new_height, $img_width, $img_height);
Loading history...
It seems like $imgY can also be of type double; however, parameter $src_y of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        imagecopyresampled($new_res, $src_res, 0, 0, $imgX, /** @scrutinizer ignore-type */ $imgY, $new_width, $new_height, $img_width, $img_height);
Loading history...
It seems like $imgX can also be of type double; however, parameter $src_x of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        imagecopyresampled($new_res, $src_res, 0, 0, /** @scrutinizer ignore-type */ $imgX, $imgY, $new_width, $new_height, $img_width, $img_height);
Loading history...
It seems like $new_width can also be of type double; however, parameter $dst_w of imagecopyresampled() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        imagecopyresampled($new_res, $src_res, 0, 0, $imgX, $imgY, /** @scrutinizer ignore-type */ $new_width, $new_height, $img_width, $img_height);
Loading history...
170
171
        if ($img_type == 'jpeg') {
172
            imageinterlace($new_res, 1); // чересстрочное формирование изображение
173
            imagejpeg($new_res, $img_path, 85);
174
        } else {
175
            $imageX = "image{$img_type}";
176
            $imageX($new_res, $img_path);
177
        }
178
179
        imagedestroy($new_res);
180
        imagedestroy($src_res);
181
        return $img_type;
182
    }
183
184
    public static function imgToResource($path) {
185
        ini_set("gd.jpeg_ignore_warning", 1);
186
        if (!getimagesize($path)) {
187
            return false;
188
        }
189
        list($img_width, $img_height, $imgType, $img_tag) = getimagesize($path);
190
        switch ($imgType) {
191
            case 1:
192
                $imgType = 'gif';
193
                break;
194
            case 3:
195
                $imgType = 'png';
196
                break;
197
            case 2:
198
            default:
199
                $imgType = 'jpeg';
200
                break;
201
        }
202
203
        $imagecreatefromX = "imagecreatefrom{$imgType}";
204
        $src_res = @$imagecreatefromX($path);
205
        return [
206
            'res' => $src_res,
207
            'type' => $imgType
208
        ];
209
    }
210
211
    public static function addWatermark($imagePath, $watermarkPath) {
212
213
        $image = self::imgToResource($imagePath);
214
        $watermark = self::imgToResource($watermarkPath);
215
        if (!$image || !$watermark || !$image['res'] || !$watermark['res']) {
216
            return false;
217
        }
218
219
        $marge_right = 10;
220
        $marge_bottom = 10;
221
        $sx = imagesx($watermark['res']);
222
        $sy = imagesy($watermark['res']);
223
224
        imagecopy($image['res'], $watermark['res'], imagesx($image['res']) - $sx - $marge_right, imagesy($image['res']) - $sy - $marge_bottom, 0, 0, imagesx($watermark['res']), imagesy($watermark['res']));
225
226
        if ($image['type'] == 'jpeg') {
227
            imageinterlace($image['res'], 1); // чересстрочное формирование изображение
228
            imagejpeg($image['res'], $imagePath, 85);
229
        } else {
230
            $imageX = "image{$image['type']}";
231
            $imageX($image['res'], $imagePath);
232
        }
233
234
        imagedestroy($watermark['res']);
235
        imagedestroy($image['res']);
236
237
        return true;
238
    }
239
240
    /**
241
     * Send mail
242
     *
243
     * @param string $from
244
     * @param string $to
245
     * @param string $subject
246
     * @param string $text
247
     * @param string $charset
248
     * @param string $ctype
249
     * @return boolean
250
     */
251
    public static function sendMail($from, $to, $subject, $text, $charset = 'utf-8', $ctype = 'text/html') {
252
        $msg = compact('from', 'to', 'subject', 'text', 'charset', 'ctype');
253
        $msg = Inji::$inst->event('sendMail', $msg);
254
        if (is_array($msg)) {
255
            $headers = "From: {$msg['from']}\r\n";
256
            $headers .= "Content-type: {$msg['ctype']}; charset={$msg['charset']}\r\n";
257
            $headers .= "Mime-Version: 1.0\r\n";
258
            return mail($msg['to'], $msg['subject'], $msg['text'], $headers);
259
        }
260
        return $msg;
261
    }
262
263
    /**
264
     * Redirect user from any place of code
265
     *
266
     * Also add message to message query for view
267
     *
268
     * @param string $href
269
     * @param string $text
270
     * @param string $status
271
     */
272
    public static function redirect($href = null, $text = false, $status = 'info') {
273
        if ($href === null) {
274
            $href = $_SERVER['REQUEST_URI'];
275
        }
276
        if ($text !== false) {
277
            \Inji\Msg::add($text, $status);
278
        }
279
        if (!headers_sent()) {
280
            header("Location: {$href}");
281
        } else {
282
            echo '\'"><script>window.location="' . $href . '";</script>';
283
        }
284
        exit("Перенаправление на: <a href = '{$href}'>{$href}</a>");
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
285
    }
286
287
    /**
288
     * Функция возвращает окончание для множественного числа слова на основании числа и массива окончаний
289
     * @param  Integer $number Число на основе которого нужно сформировать окончание
290
     * @param  String[] $endingArray Массив слов или окончаний для чисел (1, 4, 5),
291
     *         например ['яблоко', 'яблока', 'яблок']
292
     * @return String
293
     */
294
    public static function getNumEnding($number, $endingArray) {
295
        $number = $number % 100;
296
        if ($number >= 11 && $number <= 19) {
297
            $ending = $endingArray[2];
298
        } else {
299
            $i = $number % 10;
300
            switch ($i) {
301
                case (1):
302
                    $ending = $endingArray[0];
303
                    break;
304
                case (2):
305
                case (3):
306
                case (4):
307
                    $ending = $endingArray[1];
308
                    break;
309
                default:
310
                    $ending = $endingArray[2];
311
            }
312
        }
313
        return $ending;
314
    }
315
316
    /**
317
     * Clean request path
318
     *
319
     * @param string $path
320
     * @return string
321
     */
322
    public static function parsePath($path) {
323
        $path = str_replace('\\', '/', $path);
324
        $pathArray = explode('/', $path);
325
        $cleanPathArray = [];
326
        do {
327
            $changes = 0;
328
            foreach ($pathArray as $pathItem) {
329
                if (trim($pathItem) === '' || $pathItem == '.') {
330
                    $changes++;
331
                    continue;
332
                }
333
                if ($pathItem == '..') {
334
                    array_pop($cleanPathArray);
335
                    $changes++;
336
                    continue;
337
                }
338
                $cleanPathArray[] = $pathItem;
339
            }
340
            $pathArray = $cleanPathArray;
341
            $cleanPathArray = [];
342
        } while ($changes);
343
        return (strpos($path, '/') === 0 ? '/' : '') . implode('/', $pathArray);
344
    }
345
346
    /**
347
     * Show date in rus
348
     *
349
     * @param string $date
350
     * @return string
351
     */
352
    public static function toRusDate($date) {
353
        $yy = (int) substr($date, 0, 4);
354
        $mm = (int) substr($date, 5, 2);
355
        $dd = (int) substr($date, 8, 2);
356
357
        $hours = substr($date, 11, 5);
358
359
        $month = array('января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря');
360
        if (empty($month[$mm - 1])) {
361
            return 'Не указано';
362
        }
363
        return ($dd > 0 ? $dd . " " : '') . $month[$mm - 1] . " " . $yy . " " . $hours;
364
    }
365
366
    /**
367
     * Set header
368
     *
369
     * @param string $code
370
     * @param boolean $exit
371
     */
372
    public static function header($code, $exit = false) {
373
        if (!headers_sent()) {
374
            switch ($code) {
375
                case '404':
376
                    header('HTTP/1.1 404 Not Found');
377
                    break;
378
                default:
379
                    header($code);
380
            }
381
        }
382
        if ($exit) {
383
            exit;
0 ignored issues
show
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
384
        }
385
    }
386
387
    /**
388
     * Return exist path from array
389
     *
390
     * If no exist path in array - return default
391
     *
392
     * @param array $paths
393
     * @param string|boolean $default
394
     * @return string|boolean
395
     */
396
    public static function pathsResolve($paths = [], $default = false) {
397
        foreach ($paths as $path) {
398
            if (file_exists($path)) {
399
                return $path;
400
            }
401
        }
402
        return $default;
403
    }
404
405
    /**
406
     * Convert acronyms to bites
407
     *
408
     * @param string $val
409
     * @return int
410
     */
411
    public static function toBytes($val) {
412
        $val = trim($val);
413
        $last = strtolower($val[strlen($val) - 1]);
414
        switch ($last) {
415
            case 'g':
416
                $val *= 1024;
417
            // no break
418
            case 'm':
419
                $val *= 1024;
420
            // no break
421
            case 'k':
422
                $val *= 1024;
423
        }
424
425
        return $val;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $val returns the type string which is incompatible with the documented return type integer.
Loading history...
426
    }
427
428
    /**
429
     * Recursive copy directories and files
430
     *
431
     * @param string $from
432
     * @param string $to
433
     */
434
    public static function copyFiles($from, $to) {
435
        $from = rtrim($from, '/');
436
        $to = rtrim($to, '/');
437
        self::createDir($to);
438
        $files = scandir($from);
439
        foreach ($files as $file) {
440
            if (in_array($file, ['.', '..'])) {
441
                continue;
442
            }
443
            if (is_dir($from . '/' . $file)) {
444
                self::copyFiles($from . '/' . $file, $to . '/' . $file);
445
            } else {
446
                copy($from . '/' . $file, $to . '/' . $file);
447
            }
448
        }
449
    }
450
451
    public static function getDirContents($dir, &$results = array(), $curPath = '') {
452
        $files = scandir($dir);
453
        foreach ($files as $key => $value) {
454
            $path = realpath($dir . '/' . $value);
455
            if (!is_dir($path)) {
456
                $results[$path] = $curPath . '/' . $value;
457
            } else if ($value != "." && $value != "..") {
458
                self::getDirContents($path, $results, $curPath . '/' . $value);
459
            }
460
        }
461
462
        return $results;
463
    }
464
465
    /**
466
     * Translit function
467
     *
468
     * @param string $str
469
     * @return string
470
     */
471
    public static function translit($str) {
472
        $rus = array('А', 'Б', 'В', 'Г', 'Д', 'Е', 'Ё', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'Н', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Х', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я', 'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ъ', 'ы', 'ь', 'э', 'ю', 'я');
473
        $lat = array('A', 'B', 'V', 'G', 'D', 'E', 'E', 'Gh', 'Z', 'I', 'Y', 'K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'H', 'C', 'Ch', 'Sh', 'Sch', 'Y', 'Y', 'Y', 'E', 'Yu', 'Ya', 'a', 'b', 'v', 'g', 'd', 'e', 'e', 'gh', 'z', 'i', 'y', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'h', 'c', 'ch', 'sh', 'sch', 'y', 'y', 'y', 'e', 'yu', 'ya');
474
        return str_replace($rus, $lat, $str);
475
    }
476
477
    /**
478
     * get youtube video ID from URL
479
     *
480
     * @author http://stackoverflow.com/a/6556662
481
     * @param string $url
482
     * @return string Youtube video id or FALSE if none found.
483
     */
484
    public static function youtubeIdFromUrl($url) {
485
        $pattern = '%^# Match any youtube URL
486
        (?:https?://)?  # Optional scheme. Either http or https
487
        (?:www\.)?      # Optional www subdomain
488
        (?:             # Group host alternatives
489
          youtu\.be/    # Either youtu.be,
490
        | youtube\.com  # or youtube.com
491
          (?:           # Group path alternatives
492
            /embed/     # Either /embed/
493
          | /v/         # or /v/
494
          | /watch\?v=  # or /watch\?v=
495
          )             # End path alternatives.
496
        )               # End host alternatives.
497
        ([\w-]{10,12})  # Allow 10-12 for 11 char youtube id.
498
        $%x';
499
        $result = preg_match($pattern, $url, $matches);
500
        if (false !== $result) {
501
            return $matches[1];
502
        }
503
        return false;
504
    }
505
506
    /**
507
     * check array is associative
508
     *
509
     * @author http://stackoverflow.com/a/173479
510
     * @param array $arr
511
     * @return boolean
512
     */
513 4
    public static function isAssoc(&$arr) {
514 4
        return array_keys($arr) !== range(0, count($arr) - 1);
515
    }
516
517
    public static function defValue(&$link, $defValue = '') {
518
        return isset($link) ? $link : $defValue;
519
    }
520
521
    public static function rusPrice($price, $zeroEnding = false) {
0 ignored issues
show
The parameter $zeroEnding is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

521
    public static function rusPrice($price, /** @scrutinizer ignore-unused */ $zeroEnding = false) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
522
        $afterDot = $price == (int) $price ? 0 : 2;
523
        return number_format($price, $afterDot, '.', ' ');
524
    }
525
}