Passed
Push — master ( 95625a...4bf62d )
by Angel Fernando Quiroz
06:51
created

ChamiloApi::getServerMidnightTime()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nop 1
dl 0
loc 9
rs 10
c 0
b 0
f 0
nc 1
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Component\Utils;
8
9
use ChamiloSession as Session;
10
use Database;
11
use DateInterval;
12
use DateTime;
13
use DateTimeZone;
14
use Display;
15
use Exception;
16
use Template;
17
18
use const PHP_SAPI;
19
20
class ChamiloApi
21
{
22
    public const COURSE_MANAGER = 1;
23
    public const SESSION_ADMIN = 3;
24
    public const DRH = 4;
25
    public const STUDENT = 5;
26
    public const ANONYMOUS = 6;
27
28
    private static array $configuration;
29
30
    public function __construct(array $configuration)
31
    {
32
        self::$configuration = $configuration;
33
    }
34
35
    public static function getConfigurationArray(): array
36
    {
37
        return self::$configuration;
38
    }
39
40
    public static function getConfigurationValue(string $variable): mixed
41
    {
42
        $configuration = self::getConfigurationArray();
43
        if (\array_key_exists($variable, $configuration)) {
44
            return $configuration[$variable];
45
        }
46
47
        return false;
48
    }
49
50
    /**
51
     * Returns an array of resolutions that can be used for the conversion of documents to images.
52
     */
53
    public static function getDocumentConversionSizes(): array
54
    {
55
        return [
56
            '540x405' => '540x405 (3/4)',
57
            '640x480' => '640x480 (3/4)',
58
            '720x540' => '720x540 (3/4)',
59
            '800x600' => '800x600 (3/4)',
60
            '1024x576' => '1024x576 (16/9)',
61
            '1024x768' => '1000x750 (3/4)',
62
            '1280x720' => '1280x720 (16/9)',
63
            '1280x860' => '1280x960 (3/4)',
64
            '1400x1050' => '1400x1050 (3/4)',
65
            '1600x900' => '1600x900 (16/9)',
66
        ];
67
    }
68
69
    /**
70
     * Get the platform logo path.
71
     *
72
     * @throws Exception
73
     */
74
    public static function getPlatformLogoPath(
75
        string $theme = '',
76
        bool $getSysPath = false,
77
        bool $forcedGetter = false
78
    ): ?string {
79
        static $logoPath;
80
81
        // If call from CLI it should be reloaded.
82
        if ('cli' === PHP_SAPI) {
83
            $logoPath = null;
84
        }
85
86
        if (!isset($logoPath) || $forcedGetter) {
87
            $theme = empty($theme) ? api_get_visual_theme() : $theme;
88
            $accessUrlId = api_get_current_access_url_id();
89
            if ('cli' === PHP_SAPI) {
90
                $accessUrl = api_get_configuration_value('access_url');
91
                if (!empty($accessUrl)) {
92
                    $accessUrlId = $accessUrl;
93
                }
94
            }
95
            $themeDir = Template::getThemeDir($theme);
96
            $customLogoPath = $themeDir.sprintf('images/header-logo-custom%s.png', $accessUrlId);
97
98
            $svgIcons = api_get_setting('icons_mode_svg');
99
            if ('true' === $svgIcons) {
100
                $customLogoPathSVG = substr($customLogoPath, 0, -3).'svg';
101
                if (file_exists(api_get_path(SYS_PUBLIC_PATH).sprintf('css/%s', $customLogoPathSVG))) {
102
                    if ($getSysPath) {
103
                        return api_get_path(SYS_PUBLIC_PATH).sprintf('css/%s', $customLogoPathSVG);
104
                    }
105
106
                    return api_get_path(WEB_CSS_PATH).$customLogoPathSVG;
107
                }
108
            }
109
            if (file_exists(api_get_path(SYS_PUBLIC_PATH).sprintf('css/%s', $customLogoPath))) {
110
                if ($getSysPath) {
111
                    return api_get_path(SYS_PUBLIC_PATH).sprintf('css/%s', $customLogoPath);
112
                }
113
114
                return api_get_path(WEB_CSS_PATH).$customLogoPath;
115
            }
116
117
            $originalLogoPath = $themeDir.'images/header-logo.png';
118
            if ('true' === $svgIcons) {
119
                $originalLogoPathSVG = $themeDir.'images/header-logo.svg';
120
                if (file_exists(api_get_path(SYS_CSS_PATH).$originalLogoPathSVG)) {
121
                    if ($getSysPath) {
122
                        return api_get_path(SYS_CSS_PATH).$originalLogoPathSVG;
123
                    }
124
125
                    return api_get_path(WEB_CSS_PATH).$originalLogoPathSVG;
126
                }
127
            }
128
129
            if (file_exists(api_get_path(SYS_CSS_PATH).$originalLogoPath)) {
130
                if ($getSysPath) {
131
                    return api_get_path(SYS_CSS_PATH).$originalLogoPath;
132
                }
133
134
                return api_get_path(WEB_CSS_PATH).$originalLogoPath;
135
            }
136
            $logoPath = '';
137
        }
138
139
        return $logoPath;
140
    }
141
142
    /**
143
     * Get the platform logo.
144
     * Return a <img> if the logo image exists.
145
     * Otherwise, return a <h2> with the institution name.
146
     *
147
     * @throws Exception
148
     */
149
    public static function getPlatformLogo(
150
        string $theme = '',
151
        array $imageAttributes = [],
152
        bool $getSysPath = false,
153
        bool $forcedGetter = false
154
    ): string {
155
        $logoPath = self::getPlatformLogoPath($theme, $getSysPath, $forcedGetter);
156
        $institution = api_get_setting('Institution');
157
        $institutionUrl = api_get_setting('InstitutionUrl');
158
        $siteName = api_get_setting('siteName');
159
160
        if (null === $logoPath) {
161
            $headerLogo = Display::url($siteName, api_get_path(WEB_PATH).'index.php');
162
163
            if (!empty($institutionUrl) && !empty($institution)) {
164
                $headerLogo .= ' - '.Display::url($institution, $institutionUrl);
165
            }
166
167
            $courseInfo = api_get_course_info();
168
            if (isset($courseInfo['extLink']) && !empty($courseInfo['extLink']['name'])) {
169
                $headerLogo .= '<span class="extLinkSeparator"> - </span>';
170
171
                if (!empty($courseInfo['extLink']['url'])) {
172
                    $headerLogo .= Display::url(
173
                        $courseInfo['extLink']['name'],
174
                        $courseInfo['extLink']['url'],
175
                        [
176
                            'class' => 'extLink',
177
                        ]
178
                    );
179
                } elseif (!empty($courseInfo['extLink']['url'])) {
180
                    $headerLogo .= $courseInfo['extLink']['url'];
181
                }
182
            }
183
184
            return Display::tag('h2', $headerLogo, [
185
                'class' => 'text-left',
186
            ]);
187
        }
188
189
        $image = Display::img($logoPath, $institution, $imageAttributes);
190
191
        return Display::url($image, api_get_path(WEB_PATH).'index.php');
192
    }
193
194
    /**
195
     * Like strip_tags(), but leaves an additional space and removes only the given tags.
196
     *
197
     * @param array $tags Tags to be removed
198
     *
199
     * @return string The original string without the given tags
200
     */
201
    public static function stripGivenTags(string $string, array $tags): string
202
    {
203
        foreach ($tags as $tag) {
204
            $string2 = preg_replace('#</\b'.$tag.'\b[^>]*>#i', ' ', $string);
205
            if ($string2 !== $string) {
206
                $string = preg_replace('/<\b'.$tag.'\b[^>]*>/i', ' ', $string2);
207
            }
208
        }
209
210
        return $string;
211
    }
212
213
    /**
214
     * Adds or Subtract a time in hh:mm:ss to a datetime.
215
     *
216
     * @param string $time      Time to add or substract in hh:mm:ss format
217
     * @param string $datetime  Datetime to be modified as accepted by the Datetime class constructor
218
     * @param bool   $operation True for Add, False to Subtract
219
     *
220
     * @throws Exception
221
     */
222
    public static function addOrSubTimeToDateTime(
223
        string $time,
224
        string $datetime = 'now',
225
        bool $operation = true
226
    ): string {
227
        $date = new DateTime($datetime);
228
        $hours = 0;
229
        $minutes = 0;
230
        $seconds = 0;
231
        sscanf($time, '%d:%d:%d', $hours, $minutes, $seconds);
232
        $timeSeconds = isset($seconds) ? $hours * 3600 + $minutes * 60 + $seconds : $hours * 60 + $minutes;
233
        if ($operation) {
234
            $date->add(new DateInterval('PT'.$timeSeconds.'S'));
235
        } else {
236
            $date->sub(new DateInterval('PT'.$timeSeconds.'S'));
237
        }
238
239
        return $date->format('Y-m-d H:i:s');
240
    }
241
242
    /**
243
     * Returns the course id (integer) for the given course directory or the current ID if no directory is defined.
244
     *
245
     * @param string|null $directory The course directory/path that appears in the URL
246
     *
247
     * @throws Exception
248
     */
249
    public static function getCourseIdByDirectory(?string $directory = null): int
250
    {
251
        if (!empty($directory)) {
252
            $directory = Database::escape_string($directory);
253
            $row = Database::select(
254
                'id',
255
                Database::get_main_table(TABLE_MAIN_COURSE),
256
                [
257
                    'where' => [
258
                        'directory = ?' => [$directory],
259
                    ],
260
                ],
261
                'first'
262
            );
263
264
            if (\is_array($row) && isset($row['id'])) {
265
                return $row['id'];
266
            }
267
268
            return 0;
269
        }
270
271
        return (int) Session::read('_real_cid', 0);
272
    }
273
274
    /**
275
     * Check if the current HTTP request is by AJAX.
276
     */
277
    public static function isAjaxRequest(): bool
278
    {
279
        $requestedWith = $_SERVER['HTTP_X_REQUESTED_WITH'] ?? null;
280
281
        return 'XMLHttpRequest' === $requestedWith;
282
    }
283
284
    /**
285
     * Get a variable name for language file from a text.
286
     */
287
    public static function getLanguageVar(string $text, string $prefix = ''): string
288
    {
289
        $text = api_replace_dangerous_char($text);
290
        $text = str_replace(['-', ' ', '.'], '_', $text);
291
        $text = preg_replace('/_+/', '_', $text);
292
        // $text = str_replace('_', '', $text);
293
        $text = api_underscore_to_camel_case($text);
294
295
        return $prefix.$text;
296
    }
297
298
    /**
299
     * Get the stylesheet path for HTML blocks created with CKEditor.
300
     */
301
    public static function getEditorBlockStylePath(): string
302
    {
303
        $visualTheme = api_get_visual_theme();
304
305
        $cssFile = api_get_path(SYS_CSS_PATH).sprintf('themes/%s/editor_content.css', $visualTheme);
306
307
        if (is_file($cssFile)) {
308
            return api_get_path(WEB_CSS_PATH).sprintf('themes/%s/editor_content.css', $visualTheme);
309
        }
310
311
        return api_get_path(WEB_CSS_PATH).'editor_content.css';
312
    }
313
314
    /**
315
     * Get a list of colors from the palette at main/palette/pchart/default.color
316
     * and return it as an array of strings.
317
     *
318
     * @param bool     $decimalOpacity Whether to return the opacity as 0..100 or 0..1
319
     * @param bool     $wrapInRGBA     Whether to return it as 1,1,1,100 or rgba(1,1,1,100)
320
     * @param int|null $fillUpTo       If the number of colors is smaller than this number, generate more colors
321
     *
322
     * @return array An array of string colors
323
     */
324
    public static function getColorPalette(
325
        bool $decimalOpacity = false,
326
        bool $wrapInRGBA = false,
327
        ?int $fillUpTo = null
328
    ): array {
329
        // Get the common colors from the palette used for pchart
330
        $paletteFile = api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color';
331
        $palette = file($paletteFile);
332
        if ($decimalOpacity) {
333
            // Because the pchart palette has transparency as integer values
334
            // (0..100) and chartjs uses percentage (0.0..1.0), we need to divide
335
            // the last value by 100, which is a bit overboard for just one chart
336
            foreach ($palette as $index => $color) {
337
                $components = explode(',', trim($color));
338
                $components[3] = round((int) $components[3] / 100, 1);
339
                $palette[$index] = implode(',', $components);
340
            }
341
        }
342
        if ($wrapInRGBA) {
343
            foreach ($palette as $index => $color) {
344
                $color = trim($color);
345
                $palette[$index] = 'rgba('.$color.')';
346
            }
347
        }
348
        // If we want more colors, loop through existing colors
349
        $count = \count($palette);
350
        if (isset($fillUpTo) && $fillUpTo > $count) {
351
            for ($i = $count; $i < $fillUpTo; $i++) {
352
                $palette[$i] = $palette[$i % $count];
353
            }
354
        }
355
356
        return $palette;
357
    }
358
359
    /**
360
     * Get the local time for the midnight.
361
     *
362
     * @param null|string $utcTime Optional. The time to ve converted.
363
     *                             See api_get_local_time.
364
     *
365
     * @throws Exception
366
     */
367
    public static function getServerMidnightTime(?string $utcTime = null): DateTime
368
    {
369
        $localTime = api_get_local_time($utcTime);
370
        $localTimeZone = api_get_timezone();
371
372
        $localMidnight = new DateTime($localTime, new DateTimeZone($localTimeZone));
373
        $localMidnight->modify('midnight');
374
375
        return $localMidnight;
376
    }
377
378
    /**
379
     * Get JavaScript code necessary to load quiz markers-rolls in medialement's Markers Rolls plugin.
380
     */
381
    public static function getQuizMarkersRollsJS(): string
382
    {
383
        $webCodePath = api_get_path(WEB_CODE_PATH);
384
        $cidReq = api_get_cidreq(true, true, 'embeddable');
385
        $colorPalette = self::getColorPalette(false, true);
386
387
        return "
388
            var \$originalNode = $(originalNode),
389
                    qMarkersRolls = \$originalNode.data('q-markersrolls') || [],
390
                    qMarkersColor = \$originalNode.data('q-markersrolls-color') || '$colorPalette[0]';
391
392
                if (0 == qMarkersRolls.length) {
393
                    return;
394
                }
395
396
                instance.options.markersRollsColor = qMarkersColor;
397
                instance.options.markersRollsWidth = 2;
398
                instance.options.markersRolls = {};
399
400
                qMarkersRolls.forEach(function (qMarkerRoll) {
401
                    var url = '{$webCodePath}exercise/exercise_submit.php?$cidReq&'
402
                        + $.param({
403
                            exerciseId: qMarkerRoll[1],
404
                            learnpath_id: 0,
405
                            learnpath_item_id: 0,
406
                            learnpath_item_view_id: 0
407
                        });
408
409
                    instance.options.markersRolls[qMarkerRoll[0]] = url;
410
                });
411
412
                instance.buildmarkersrolls(instance, instance.controls, instance.layers, instance.media);
413
        ";
414
    }
415
416
    /**
417
     * Performs a redirection to the specified URL.
418
     *
419
     * This method sends a direct HTTP Location header to the client,
420
     * causing the browser to navigate to the specified URL. It should be
421
     * used with caution and only in scenarios where Symfony's standard
422
     * response handling is not applicable. The method terminates script
423
     * execution after sending the header.
424
     */
425
    public static function redirectTo(string $url): void
426
    {
427
        if (!empty($url)) {
428
            header("Location: $url");
429
430
            exit;
431
        }
432
    }
433
}
434