Passed
Push — webservicelpcreate ( d8cb35 )
by
unknown
13:48
created

get_lang()   F

Complexity

Conditions 19
Paths 1632

Size

Total Lines 81
Code Lines 41

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 19
eloc 41
nc 1632
nop 3
dl 0
loc 81
rs 0.3499
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
use Patchwork\Utf8;
6
7
/**
8
 * File: internationalization.lib.php
9
 * Internationalization library for Chamilo 1.x LMS
10
 * A library implementing internationalization related functions.
11
 * License: GNU General Public License Version 3 (Free Software Foundation)ww.
12
 *
13
 * @author Ivan Tcholakov, <[email protected]>, 2009, 2010
14
 * @author More authors, mentioned in the correpsonding fragments of this source.
15
 *
16
 * @package chamilo.library
17
 */
18
19
// Special tags for marking untranslated variables.
20
define('SPECIAL_OPENING_TAG', '[=');
21
define('SPECIAL_CLOSING_TAG', '=]');
22
23
// Predefined date formats in Chamilo provided by the language sub-system.
24
// To be used as a parameter for the function api_format_date()
25
26
define('TIME_NO_SEC_FORMAT', 0); // 15:23
27
define('DATE_FORMAT_SHORT', 1); // Aug 25, 09
28
define('DATE_FORMAT_LONG', 2); // Monday August 25, 09
29
define('DATE_FORMAT_LONG_NO_DAY', 10); // August 25, 2009
30
define('DATE_TIME_FORMAT_LONG', 3); // Monday August 25, 2009 at 03:28 PM
31
32
define('DATE_FORMAT_NUMBER', 4); // 25.08.09
33
define('DATE_TIME_FORMAT_LONG_24H', 5); // August 25, 2009 at 15:28
34
define('DATE_TIME_FORMAT_SHORT', 6); // Aug 25, 2009 at 03:28 PM
35
define('DATE_TIME_FORMAT_SHORT_TIME_FIRST', 7); // 03:28 PM, Aug 25 2009
36
define('DATE_FORMAT_NUMBER_NO_YEAR', 8); // 25.08 dd-mm
37
define('DATE_FORMAT_ONLY_DAYNAME', 9); // Monday, Sunday, etc
38
39
// Formatting person's name.
40
// Formatting a person's name using the pattern as it has been
41
// configured in the internationalization database for every language.
42
// This (default) option would be the most used.
43
define('PERSON_NAME_COMMON_CONVENTION', 0);
44
// The following options may be used in limited number of places for overriding the common convention:
45
46
// Formatting a person's name in Western order: first_name last_name
47
define('PERSON_NAME_WESTERN_ORDER', 1);
48
// Formatting a person's name in Eastern order: last_name first_name
49
define('PERSON_NAME_EASTERN_ORDER', 2);
50
// Contextual: formatting person's name in library order: last_name, first_name
51
define('PERSON_NAME_LIBRARY_ORDER', 3);
52
// Contextual: formatting a person's name assotiated with an email-address.
53
// Ivan: I am not sure how seems email servers an clients would interpret name order, so I assign the Western order.
54
define('PERSON_NAME_EMAIL_ADDRESS', PERSON_NAME_WESTERN_ORDER);
55
// Contextual: formatting a person's name for data-exporting operations.
56
// For backward compatibility this format has been set to Eastern order.
57
define('PERSON_NAME_DATA_EXPORT', PERSON_NAME_EASTERN_ORDER);
58
59
/**
60
 * Returns a translated (localized) string, called by its ID.
61
 *
62
 * @param string $variable              this is the ID (name) of the translated string to be retrieved
63
 * @param bool   $returnEmptyIfNotFound If variable is not found, then: if false: returns variable name with or without brackets; true: returns ''
64
 * @param string $language              (optional)    Language ID. If it is omitted, the current interface language is assumed.
65
 *
66
 * @return string returns the requested string in the correspondent language
67
 *
68
 * @author Roan Embrechts
69
 * @author Patrick Cool
70
 * @author Ivan Tcholakov, 2009-2010 (caching functionality, additional parameter $language, other adaptations).
71
 *
72
 * Notes:
73
 * 1. If the name of a given language variable has the prefix "lang" it may be omited, i.e. get_lang('Yes') == get_lang('Yes').
74
 * 2. Untranslated variables might be indicated by special opening and closing tags  -  [=  =]
75
 * The special tags do not show up in these two cases:
76
 * - when the system has been switched to "production server mode";
77
 * - when a special platform setting 'hide_dltt_markup' is set to "true" (the name of this setting comes from history);
78
 * 3. Translations are created many contributors through using a special tool: Chamilo Translation Application.
79
 *
80
 * @see http://translate.chamilo.org/
81
 */
82
function get_lang($variable, $returnEmptyIfNotFound = false, $language = null)
83
{
84
    // For serving some old hacks:
85
    // By manipulating this global variable the translation may
86
    // be done in different languages too (not the elegant way).
87
    global $language_interface;
88
    // Because of possibility for manipulations of the global
89
    // variable $language_interface, we need its initial value.
90
    global $language_interface_initial_value;
91
    global $used_lang_vars, $_configuration;
92
    // add language_measure_frequency to your main/inc/conf/configuration.php in order to generate language
93
    // variables frequency measurements (you can then see them trhough main/cron/lang/langstats.php)
94
    // The $langstats object is instanciated at the end of main/inc/global.inc.php
95
    if (isset($_configuration['language_measure_frequency']) &&
96
        $_configuration['language_measure_frequency'] == 1
97
    ) {
98
        require_once api_get_path(SYS_CODE_PATH).'/cron/lang/langstats.class.php';
99
        global $langstats;
100
        $langstats->add_use($variable, '');
101
    }
102
103
    if (!isset($used_lang_vars)) {
104
        $used_lang_vars = [];
105
    }
106
107
    // Caching results from some API functions, for speed.
108
    static $initialized, $show_special_markup;
109
    if (!isset($initialized)) {
110
        $test_server_mode = api_get_setting('server_type') === 'test';
111
        $show_special_markup = api_get_setting('hide_dltt_markup') != 'true' || $test_server_mode;
112
        $initialized = true;
113
    }
114
115
    // Combining both ways for requesting specific language.
116
    if (empty($language)) {
117
        $language = $language_interface;
118
    }
119
    $lang_postfix = isset($is_interface_language) && $is_interface_language ? '' : '('.$language.')';
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $is_interface_language does not exist. Did you maybe mean $language?
Loading history...
120
121
    $is_interface_language = $language == $language_interface_initial_value;
122
123
    // This is a cache for already translated language variables. By using it, we avoid repetitive translations, gaining speed.
124
    static $cache;
125
126
    // Looking up into the cache for existing translation.
127
    if (isset($cache[$language][$variable])) {
128
        // There is a previously saved translation, returning it.
129
        //return $cache[$language][$variable];
130
        $ret = $cache[$language][$variable];
131
        $used_lang_vars[$variable.$lang_postfix] = $ret;
132
133
        return $ret;
134
    }
135
136
    // There is no cached translation, we have to retrieve it:
137
    // - from a global variable (the faster way) - on production server mode;
138
    // - from a local variable after reloading the language files - on test server mode or when requested language
139
    // is different than the genuine interface language.
140
    $read_global_variables = $is_interface_language;
141
    $langvar = '';
142
143
    if ($read_global_variables) {
144
        if (isset($GLOBALS[$variable])) {
145
            $langvar = $GLOBALS[$variable];
146
        } elseif (isset($GLOBALS["lang$variable"])) {
147
            $langvar = $GLOBALS["lang$variable"];
148
        } else {
149
            if (!$returnEmptyIfNotFound) {
150
                $langvar = $show_special_markup ? SPECIAL_OPENING_TAG.$variable.SPECIAL_CLOSING_TAG : $variable;
151
            } else {
152
                return '';
153
            }
154
        }
155
    }
156
    if (empty($langvar) || !is_string($langvar) && !$returnEmptyIfNotFound) {
157
        $langvar = $show_special_markup ? SPECIAL_OPENING_TAG.$variable.SPECIAL_CLOSING_TAG : $variable;
158
    }
159
    $ret = $cache[$language][$variable] = $langvar;
160
    $used_lang_vars[$variable.$lang_postfix] = $ret;
161
162
    return $ret;
163
}
164
165
/**
166
 * Gets the current interface language.
167
 *
168
 * @param bool $purified              (optional)    When it is true, a purified (refined)
169
 *                                    language value will be returned, for example 'french' instead of 'french_unicode'
170
 * @param bool $setParentLanguageName
171
 *
172
 * @throws Exception
173
 *
174
 * @return string the current language of the interface
175
 */
176
function api_get_interface_language(
177
    $purified = false,
178
    $check_sub_language = false,
179
    $setParentLanguageName = true
180
) {
181
    global $language_interface;
182
183
    if (empty($language_interface)) {
184
        return 'english';
185
    }
186
187
    if ($check_sub_language) {
188
        static $parent_language_name = null;
189
190
        if (!isset($parent_language_name)) {
191
            // 2. The current language is a sub language so we grab the father's
192
            // setting according to the internalization_database/name_order_convetions.php file
193
            $language_id = api_get_language_id($language_interface);
194
            $language_info = api_get_language_info($language_id);
195
196
            if (!empty($language_id) &&
197
                !empty($language_info)
198
            ) {
199
                if (!empty($language_info['parent_id'])) {
200
                    $language_info = api_get_language_info($language_info['parent_id']);
201
                    if ($setParentLanguageName) {
202
                        $parent_language_name = $language_info['english_name'];
203
                    }
204
205
                    if (!empty($parent_language_name)) {
206
                        return $parent_language_name;
207
                    }
208
                }
209
210
                return $language_info['english_name'];
211
            }
212
213
            return 'english';
214
        } else {
215
            return $parent_language_name;
216
        }
217
    } else {
218
        // 2. Normal way
219
        $interface_language = $purified ? api_purify_language_id($language_interface) : $language_interface;
220
    }
221
222
    return $interface_language;
223
}
224
225
/**
226
 * Returns a purified language id, without possible suffixes that will disturb language identification in certain cases.
227
 *
228
 * @param string $language the input language identificator, for example 'french_unicode'
229
 * @param string the same purified or filtered language id, for example 'french'
230
 *
231
 * @return string
232
 */
233
function api_purify_language_id($language)
234
{
235
    static $purified = [];
236
    if (!isset($purified[$language])) {
237
        $purified[$language] = trim(
238
            str_replace(
239
                ['_unicode', '_latin', '_corporate', '_org', '_km'],
240
                '',
241
                strtolower($language)
242
            )
243
        );
244
    }
245
246
    return $purified[$language];
247
}
248
249
/**
250
 * Gets language isocode column from the language table, taking the given language as a query parameter.
251
 *
252
 * @param string $language     This is the name of the folder containing translations for the corresponding language (e.g arabic, english).
253
 * @param string $default_code This is the value to be returned if there was no code found corresponding to the given language.
254
 *                             If $language is omitted, interface language is assumed then.
255
 *
256
 * @return string The found isocode or null on error.
257
 *                Returned codes are according to the following standards (in order of preference):
258
 *                -  ISO 639-1 : Alpha-2 code (two-letters code - en, fr, es, ...)
259
 *                -  RFC 4646  : five-letter code based on the ISO 639 two-letter language codes
260
 *                and the ISO 3166 two-letter territory codes (pt-BR, ...)
261
 *                -  ISO 639-2 : Alpha-3 code (three-letters code - ast, fur, ...)
262
 */
263
function api_get_language_isocode($language = null, $default_code = 'en')
264
{
265
    static $iso_code = [];
266
    if (empty($language)) {
267
        $language = api_get_interface_language(false, true);
268
    }
269
    if (!isset($iso_code[$language])) {
270
        if (!class_exists('Database')) {
271
            // This might happen, in case of calling this function early during the global initialization.
272
            return $default_code; // This might happen, in case of calling this function early during the global initialization.
273
        }
274
        $sql = "SELECT isocode
275
                FROM ".Database::get_main_table(TABLE_MAIN_LANGUAGE)."
276
                WHERE dokeos_folder = '$language'";
277
        $sql_result = Database::query($sql);
278
        if (Database::num_rows($sql_result)) {
279
            $result = Database::fetch_array($sql_result);
280
            $iso_code[$language] = trim($result['isocode']);
281
        } else {
282
            $language_purified_id = api_purify_language_id($language);
283
            $iso_code[$language] = isset($iso_code[$language_purified_id]) ? $iso_code[$language_purified_id] : null;
284
        }
285
        if (empty($iso_code[$language])) {
286
            $iso_code[$language] = $default_code;
287
        }
288
    }
289
290
    return $iso_code[$language];
291
}
292
293
/**
294
 * Gets language iso code column from the language table.
295
 *
296
 * @return array An array with the current isocodes
297
 *
298
 * */
299
function api_get_platform_isocodes()
300
{
301
    $iso_code = [];
302
    $sql = "SELECT isocode
303
            FROM ".Database::get_main_table(TABLE_MAIN_LANGUAGE)."
304
            ORDER BY isocode ";
305
    $sql_result = Database::query($sql);
306
    if (Database::num_rows($sql_result)) {
307
        while ($row = Database::fetch_array($sql_result)) {
308
            $iso_code[] = trim($row['isocode']);
309
        }
310
    }
311
312
    return $iso_code;
313
}
314
315
/**
316
 * Gets text direction according to the given language.
317
 *
318
 * @param string $language This is the name of the
319
 *                         folder containing translations for the corresponding language (e.g 'arabic', 'english', ...).
320
 *                         ISO-codes are acceptable too ('ar', 'en', ...).
321
 *                         If $language is omitted, interface language is assumed then.
322
 *
323
 * @return string the correspondent to the language text direction ('ltr' or 'rtl')
324
 */
325
function api_get_text_direction($language = null)
326
{
327
    static $text_direction = [];
328
329
    if (empty($language)) {
330
        $language = api_get_interface_language();
331
    }
332
    if (!isset($text_direction[$language])) {
333
        $text_direction[$language] = in_array(
334
            api_purify_language_id($language),
335
            [
336
                'arabic',
337
                'ar',
338
                'dari',
339
                'prs',
340
                'hebrew',
341
                'he',
342
                'iw',
343
                'pashto',
344
                'ps',
345
                'persian',
346
                'fa',
347
                'ur',
348
                'yiddish',
349
                'yid',
350
            ]
351
        ) ? 'rtl' : 'ltr';
352
    }
353
354
    return $text_direction[$language];
355
}
356
357
/**
358
 * Returns an alphabetized list of timezones in an associative array
359
 * that can be used to populate a select.
360
 *
361
 * @return array List of timezone identifiers
362
 *
363
 * @author Guillaume Viguier <[email protected]>
364
 */
365
function api_get_timezones()
366
{
367
    $timezone_identifiers = DateTimeZone::listIdentifiers();
368
    sort($timezone_identifiers);
369
    $out = [];
370
    foreach ($timezone_identifiers as $tz) {
371
        $out[$tz] = $tz;
372
    }
373
    $null_option = ['' => ''];
374
    $result = array_merge($null_option, $out);
375
376
    return $result;
377
}
378
379
/**
380
 * Returns the timezone to be converted to/from, based on user or admin preferences.
381
 *
382
 * @return string The timezone chosen
383
 */
384
function api_get_timezone()
385
{
386
    $timezone = Session::read('system_timezone');
387
    if (empty($timezone)) {
388
        // First, get the default timezone of the server
389
        $timezone = date_default_timezone_get();
390
        // Second, see if a timezone has been chosen for the platform
391
        $timezoneFromSettings = api_get_setting('timezone_value', 'timezones');
392
393
        if ($timezoneFromSettings != null) {
394
            $timezone = $timezoneFromSettings;
395
        }
396
397
        // If allowed by the administrator
398
        $allowUserTimezones = api_get_setting('use_users_timezone', 'timezones');
399
400
        if ($allowUserTimezones === 'true') {
401
            $userId = api_get_user_id();
402
            // Get the timezone based on user preference, if it exists
403
            $newExtraField = new ExtraFieldValue('user');
404
            $data = $newExtraField->get_values_by_handler_and_field_variable($userId, 'timezone');
405
            if (!empty($data) && isset($data['timezone']) && !empty($data['timezone'])) {
406
                $timezone = $data['timezone'];
407
            }
408
        }
409
        Session::write('system_timezone', $timezone);
410
    }
411
412
    return $timezone;
413
}
414
415
/**
416
 * Returns the given date as a DATETIME in UTC timezone.
417
 * This function should be used before entering any date in the DB.
418
 *
419
 * @param mixed $time                    Date to be converted (can be a string supported by date() or a timestamp)
420
 * @param bool  $returnNullIfInvalidDate If the date is not correct return null instead of the current date
421
 * @param bool  $returnObj               Returns a DateTime object
422
 *
423
 * @return string|DateTime The DATETIME in UTC to be inserted in the DB,
424
 *                         or null if the format of the argument is not supported
425
 *
426
 * @author Julio Montoya - Adding the 2nd parameter
427
 * @author Guillaume Viguier <[email protected]>
428
 */
429
function api_get_utc_datetime(
430
    $time = null,
431
    $returnNullIfInvalidDate = false,
432
    $returnObj = false
433
) {
434
    if (is_null($time) || empty($time) || $time === '0000-00-00 00:00:00') {
435
        if ($returnNullIfInvalidDate) {
436
            return null;
437
        }
438
        if ($returnObj) {
439
            return new DateTime(gmdate('Y-m-d H:i:s'), new DateTimeZone('UTC'));
440
        }
441
442
        return gmdate('Y-m-d H:i:s');
443
    }
444
445
    // If time is a timestamp, return directly in utc
446
    if (is_numeric($time)) {
447
        $time = (int) $time;
448
449
        return gmdate('Y-m-d H:i:s', $time);
450
    }
451
    try {
452
        $fromTimezone = api_get_timezone();
453
        $date = new DateTime($time, new DateTimezone($fromTimezone));
454
        $date->setTimezone(new DateTimeZone('UTC'));
455
        if ($returnObj) {
456
            return $date;
457
        } else {
458
            return $date->format('Y-m-d H:i:s');
459
        }
460
    } catch (Exception $e) {
461
        return null;
462
    }
463
}
464
465
/**
466
 * Returns a DATETIME string converted to the right timezone.
467
 *
468
 * @param mixed  $time                    The time to be converted
469
 * @param string $to_timezone             If null, the timezone will be determined based on user preference,
470
 *                                        or timezone chosen by the admin for the platform.
471
 * @param string $from_timezone           The timezone to be converted from. If null, UTC will be assumed.
472
 * @param bool   $returnNullIfInvalidDate Return null if date is not correct.
473
 * @param bool   $showTime                Show time.
474
 * @param bool   $humanForm               Return a readable date time.
475
 * @param string $format                  Specify format.
476
 *
477
 * @return string The converted time formatted as Y-m-d H:i:s
478
 *
479
 * @author Guillaume Viguier <[email protected]>
480
 */
481
function api_get_local_time(
482
    $time = null,
483
    $to_timezone = null,
484
    $from_timezone = null,
485
    $returnNullIfInvalidDate = false,
486
    $showTime = true,
487
    $humanForm = false,
488
    $format = ''
489
) {
490
    // Determining the timezone to be converted from
491
    if (is_null($from_timezone)) {
492
        $from_timezone = 'UTC';
493
    }
494
495
    // If time is a timestamp, convert it to a string
496
    if (is_null($time) || empty($time) || $time == '0000-00-00 00:00:00') {
497
        if ($returnNullIfInvalidDate) {
498
            return null;
499
        }
500
        $from_timezone = 'UTC';
501
        $time = gmdate('Y-m-d H:i:s');
502
    }
503
504
    if (is_numeric($time)) {
505
        $time = (int) $time;
506
        if ($returnNullIfInvalidDate) {
507
            if (strtotime(date('d-m-Y H:i:s', $time)) !== (int) $time) {
508
                return null;
509
            }
510
        }
511
512
        $from_timezone = 'UTC';
513
        $time = gmdate('Y-m-d H:i:s', $time);
514
    }
515
516
    if ($time instanceof DateTime) {
517
        $time = $time->format('Y-m-d H:i:s');
518
        $from_timezone = 'UTC';
519
    }
520
521
    try {
522
        // Determining the timezone to be converted to
523
        if (is_null($to_timezone)) {
524
            $to_timezone = api_get_timezone();
525
        }
526
527
        $date = new DateTime($time, new DateTimezone($from_timezone));
528
        $date->setTimezone(new DateTimeZone($to_timezone));
529
530
        if (!empty($format)) {
531
            return $date->format($format);
532
        }
533
534
        return api_get_human_date_time($date, $showTime, $humanForm);
535
    } catch (Exception $e) {
536
        return '';
537
    }
538
}
539
540
/**
541
 * Converts a string into a timestamp safely (handling timezones), using strtotime.
542
 *
543
 * @param string $time     to be converted
544
 * @param string $timezone (if null, the timezone will be determined based
545
 *                         on user preference, or timezone chosen by the admin for the platform)
546
 *
547
 * @return int Timestamp
548
 *
549
 * @author Guillaume Viguier <[email protected]>
550
 */
551
function api_strtotime($time, $timezone = null)
552
{
553
    $system_timezone = date_default_timezone_get();
554
    if (!empty($timezone)) {
555
        date_default_timezone_set($timezone);
556
    }
557
    $timestamp = strtotime($time);
558
    if (!empty($timezone)) {
559
        // only reset timezone if it was changed
560
        date_default_timezone_set($system_timezone);
561
    }
562
563
    return $timestamp;
564
}
565
566
/**
567
 * Returns formatted date/time, correspondent to a given language.
568
 * The given date should be in the timezone chosen by the administrator
569
 * and/or user. Use api_get_local_time to get it.
570
 *
571
 * @author Patrick Cool <[email protected]>, Ghent University
572
 * @author Christophe Gesche<[email protected]>
573
 *         originally inspired from from PhpMyAdmin
574
 * @author Ivan Tcholakov, 2009, code refactoring, adding support for predefined date/time formats.
575
 * @author Guillaume Viguier <[email protected]>
576
 *
577
 * @param mixed $time Timestamp or datetime string
578
 * @param string|int Date format (see date formats in the Chamilo system:
579
 * TIME_NO_SEC_FORMAT,
580
 * DATE_FORMAT_SHORT,
581
 * DATE_FORMAT_LONG,
582
 * DATE_TIME_FORMAT_LONG
583
 * @param string $language (optional) Language id
584
 *                         If it is omitted, the current interface language is assumed
585
 *
586
 * @return string returns the formatted date
587
 *
588
 * @see http://php.net/manual/en/function.strftime.php
589
 */
590
function api_format_date($time, $format = null, $language = null)
591
{
592
    if (empty($time)) {
593
        return '';
594
    }
595
596
    $system_timezone = date_default_timezone_get();
597
    date_default_timezone_set(api_get_timezone());
598
599
    if (is_string($time)) {
600
        $time = strtotime($time);
601
    }
602
603
    if (is_null($format)) {
604
        $format = DATE_TIME_FORMAT_LONG;
605
    }
606
607
    $datetype = null;
608
    $timetype = null;
609
610
    if (is_int($format)) {
611
        switch ($format) {
612
            case DATE_FORMAT_ONLY_DAYNAME:
613
                $date_format = get_lang('dateFormatOnlyDayName', '', $language);
614
                if (INTL_INSTALLED) {
615
                    $datetype = IntlDateFormatter::SHORT;
616
                    $timetype = IntlDateFormatter::NONE;
617
                }
618
                break;
619
            case DATE_FORMAT_NUMBER_NO_YEAR:
620
                $date_format = get_lang('dateFormatShortNumberNoYear', '', $language);
621
                if (INTL_INSTALLED) {
622
                    $datetype = IntlDateFormatter::SHORT;
623
                    $timetype = IntlDateFormatter::NONE;
624
                }
625
                break;
626
            case DATE_FORMAT_NUMBER:
627
                $date_format = get_lang('dateFormatShortNumber', '', $language);
628
                if (INTL_INSTALLED) {
629
                    $datetype = IntlDateFormatter::SHORT;
630
                    $timetype = IntlDateFormatter::NONE;
631
                }
632
                break;
633
            case TIME_NO_SEC_FORMAT:
634
                $date_format = get_lang('timeNoSecFormat', '', $language);
635
                if (INTL_INSTALLED) {
636
                    $datetype = IntlDateFormatter::NONE;
637
                    $timetype = IntlDateFormatter::SHORT;
638
                }
639
                break;
640
            case DATE_FORMAT_SHORT:
641
                $date_format = get_lang('dateFormatShort', '', $language);
642
                if (INTL_INSTALLED) {
643
                    $datetype = IntlDateFormatter::LONG;
644
                    $timetype = IntlDateFormatter::NONE;
645
                }
646
                break;
647
            case DATE_FORMAT_LONG:
648
                $date_format = get_lang('dateFormatLong', '', $language);
649
                if (INTL_INSTALLED) {
650
                    $datetype = IntlDateFormatter::FULL;
651
                    $timetype = IntlDateFormatter::NONE;
652
                }
653
                break;
654
            case DATE_TIME_FORMAT_LONG:
655
                $date_format = get_lang('dateTimeFormatLong', '', $language);
656
                if (INTL_INSTALLED) {
657
                    $datetype = IntlDateFormatter::FULL;
658
                    $timetype = IntlDateFormatter::SHORT;
659
                }
660
                break;
661
            case DATE_FORMAT_LONG_NO_DAY:
662
                $date_format = get_lang('dateFormatLongNoDay', '', $language);
663
                if (INTL_INSTALLED) {
664
                    $datetype = IntlDateFormatter::FULL;
665
                    $timetype = IntlDateFormatter::SHORT;
666
                }
667
                break;
668
            case DATE_TIME_FORMAT_SHORT:
669
                $date_format = get_lang('dateTimeFormatShort', '', $language);
670
                if (INTL_INSTALLED) {
671
                    $datetype = IntlDateFormatter::FULL;
672
                    $timetype = IntlDateFormatter::SHORT;
673
                }
674
                break;
675
            case DATE_TIME_FORMAT_SHORT_TIME_FIRST:
676
                $date_format = get_lang('dateTimeFormatShortTimeFirst', '', $language);
677
                if (INTL_INSTALLED) {
678
                    $datetype = IntlDateFormatter::FULL;
679
                    $timetype = IntlDateFormatter::SHORT;
680
                }
681
                break;
682
            case DATE_TIME_FORMAT_LONG_24H:
683
                $date_format = get_lang('dateTimeFormatLong24H', '', $language);
684
                if (INTL_INSTALLED) {
685
                    $datetype = IntlDateFormatter::FULL;
686
                    $timetype = IntlDateFormatter::SHORT;
687
                }
688
                break;
689
            default:
690
                $date_format = get_lang('dateTimeFormatLong', '', $language);
691
                if (INTL_INSTALLED) {
692
                    $datetype = IntlDateFormatter::FULL;
693
                    $timetype = IntlDateFormatter::SHORT;
694
                }
695
        }
696
    } else {
697
        $date_format = $format;
698
    }
699
700
    if (0) {
701
        //if using PHP 5.3 format dates like: $dateFormatShortNumber, can't be used
702
        //
703
        // Use ICU
704
        if (is_null($language)) {
705
            $language = api_get_language_isocode();
706
        }
707
        $date_formatter = new IntlDateFormatter($language, $datetype, $timetype, date_default_timezone_get());
708
        //$date_formatter->setPattern($date_format);
709
        $formatted_date = api_to_system_encoding($date_formatter->format($time), 'UTF-8');
710
    } else {
711
        // We replace %a %A %b %B masks of date format with translated strings
712
        $translated = &_api_get_day_month_names($language);
713
        $date_format = str_replace(
714
            ['%A', '%a', '%B', '%b'],
715
            [
716
                $translated['days_long'][(int) strftime('%w', $time)],
717
                $translated['days_short'][(int) strftime('%w', $time)],
718
                $translated['months_long'][(int) strftime('%m', $time) - 1],
719
                $translated['months_short'][(int) strftime('%m', $time) - 1],
720
            ],
721
            $date_format
722
        );
723
        $formatted_date = api_to_system_encoding(strftime($date_format, $time), 'UTF-8');
724
    }
725
    date_default_timezone_set($system_timezone);
726
727
    return $formatted_date;
728
}
729
730
/**
731
 * Returns the difference between the current date (date(now)) with the parameter
732
 * $date in a string format like "2 days ago, 1 hour ago".
733
 * You can use it like this:
734
 * Display::dateToStringAgoAndLongDate($dateInUtc);.
735
 *
736
 * @param string $date                 Result of a date function in this format -> date('Y-m-d H:i:s', time());
737
 * @param string $timeZone
738
 * @param bool   $returnDateDifference
739
 *
740
 * @return string
741
 *
742
 * @author Julio Montoya
743
 */
744
function date_to_str_ago($date, $timeZone = 'UTC', $returnDateDifference = false)
745
{
746
    if ($date === '0000-00-00 00:00:00') {
747
        return '';
748
    }
749
750
    $getOldTimezone = api_get_timezone();
751
    $isoCode = api_get_language_isocode();
752
    if ($isoCode == 'pt') {
753
        $isoCode = 'pt-BR';
754
    }
755
    $checkFile = api_get_path(SYS_PATH).'vendor/jimmiw/php-time-ago/translations/'.$isoCode.'.php';
756
    if (!file_exists($checkFile)) {
757
        $isoCode = 'en';
758
    }
759
    $timeAgo = new TimeAgo($timeZone, $isoCode);
760
    $value = $timeAgo->inWords($date);
761
762
    date_default_timezone_set($getOldTimezone);
763
764
    if ($returnDateDifference) {
765
        $value = $timeAgo->dateDifference($date);
766
    }
767
768
    return $value;
769
}
770
771
/**
772
 * Converts a date to the right timezone and localizes it in the format given as an argument.
773
 *
774
 * @param mixed The time to be converted
775
 * @param mixed Format to be used (TIME_NO_SEC_FORMAT, DATE_FORMAT_SHORT, DATE_FORMAT_LONG, DATE_TIME_FORMAT_LONG)
776
 * @param string Timezone to be converted from. If null, UTC will be assumed.
777
 *
778
 * @return string Converted and localized date
779
 *
780
 * @author Guillaume Viguier <[email protected]>
781
 */
782
function api_convert_and_format_date($time = null, $format = null, $from_timezone = null)
783
{
784
    // First, convert the datetime to the right timezone
785
    $time = api_get_local_time($time, null, $from_timezone, true);
786
    // Second, localize the date
787
    return api_format_date($time, $format);
788
}
789
790
/**
791
 * Returns an array of translated week days in short names.
792
 *
793
 * @param string $language (optional) Language id. If it is omitted, the current interface language is assumed.
794
 *
795
 * @return string Returns an array of week days (short names).
796
 *                Example: api_get_week_days_short('english') means array('Sun', 'Mon', ... 'Sat').
797
 *                Note: For all languges returned days are in the English order.
798
 */
799
function api_get_week_days_short($language = null)
800
{
801
    $days = &_api_get_day_month_names($language);
802
803
    return $days['days_short'];
804
}
805
806
/**
807
 * Returns an array of translated week days.
808
 *
809
 * @param string $language (optional) Language id. If it is omitted,
810
 *                         the current interface language is assumed.
811
 *
812
 * @return string Returns an array of week days.
813
 *                Example: api_get_week_days_long('english') means array('Sunday, 'Monday', ... 'Saturday').
814
 *                Note: For all languges returned days are in the English order.
815
 */
816
function api_get_week_days_long($language = null)
817
{
818
    $days = &_api_get_day_month_names($language);
819
820
    return $days['days_long'];
821
}
822
823
/**
824
 * Returns an array of translated months in short names.
825
 *
826
 * @param string $language (optional)    Language id.
827
 *                         If it is omitted, the current interface language is assumed.
828
 *
829
 * @return string Returns an array of months (short names).
830
 *                Example: api_get_months_short('english') means array('Jan', 'Feb', ... 'Dec').
831
 */
832
function api_get_months_short($language = null)
833
{
834
    $months = &_api_get_day_month_names($language);
835
836
    return $months['months_short'];
837
}
838
839
/**
840
 * Returns an array of translated months.
841
 *
842
 * @param string $language (optional)    Language id.
843
 *                         If it is omitted, the current interface language is assumed.
844
 *
845
 * @return string Returns an array of months.
846
 *                Example: api_get_months_long('english') means array('January, 'February' ... 'December').
847
 */
848
function api_get_months_long($language = null)
849
{
850
    $months = &_api_get_day_month_names($language);
851
852
    return $months['months_long'];
853
}
854
855
/**
856
 * Name order conventions.
857
 */
858
859
/**
860
 * Builds a person (full) name depending on the convention for a given language.
861
 *
862
 * @param string     $first_name the first name of the person
863
 * @param string     $last_name  the last name of the person
864
 * @param string     $title      the title of the person
865
 * @param int|string $format     (optional) The person name format.
866
 *                               It may be a pattern-string (for example '%t %l, %f' or '%T %F %L', ...) or
867
 *                               some of the constants
868
 *                               PERSON_NAME_COMMON_CONVENTION (default),
869
 *                               PERSON_NAME_WESTERN_ORDER,
870
 *                               PERSON_NAME_EASTERN_ORDER,
871
 *                               PERSON_NAME_LIBRARY_ORDER.
872
 * @param string     $language   (optional)
873
 *                               The language id. If it is omitted, the current interface language is assumed.
874
 *                               This parameter has meaning with the format PERSON_NAME_COMMON_CONVENTION only.
875
 * @param string     $username
876
 *
877
 * @return string The result is sort of full name of the person.
878
 *                Sample results:
879
 *                Peter Ustinoff or Dr. Peter Ustinoff     - the Western order
880
 *                Ustinoff Peter or Dr. Ustinoff Peter     - the Eastern order
881
 *                Ustinoff, Peter or - Dr. Ustinoff, Peter - the library order
882
 *                Note: See the file main/inc/lib/internationalization_database/name_order_conventions.php
883
 *                where you can check the convention for your language.
884
 *
885
 * @author Carlos Vargas <[email protected]> - initial implementation.
886
 * @author Ivan Tcholakov
887
 */
888
function api_get_person_name(
889
    $first_name,
890
    $last_name,
891
    $title = null,
892
    $format = null,
893
    $language = null,
894
    $username = null
895
) {
896
    static $valid = [];
897
    if (empty($format)) {
898
        $format = PERSON_NAME_COMMON_CONVENTION;
899
    }
900
    // We check if the language is supported, otherwise we check the
901
    // interface language of the parent language of sublanguage
902
    if (empty($language)) {
903
        // Do not set $setParentLanguageName because this function is called before
904
        // the main language is loaded in global.inc.php
905
        $language = api_get_interface_language(false, true, false);
906
    }
907
908
    if (!isset($valid[$format][$language])) {
909
        if (is_int($format)) {
910
            switch ($format) {
911
                case PERSON_NAME_COMMON_CONVENTION:
912
                    $valid[$format][$language] = _api_get_person_name_convention($language, 'format');
913
                    $usernameOrderFromDatabase = api_get_setting('user_name_order');
914
                    if (isset($usernameOrderFromDatabase) && !empty($usernameOrderFromDatabase)) {
915
                        $valid[$format][$language] = $usernameOrderFromDatabase;
916
                    }
917
                    break;
918
                case PERSON_NAME_WESTERN_ORDER:
919
                    $valid[$format][$language] = '%t %f %l';
920
                    break;
921
                case PERSON_NAME_EASTERN_ORDER:
922
                    $valid[$format][$language] = '%t %l %f';
923
                    break;
924
                case PERSON_NAME_LIBRARY_ORDER:
925
                    $valid[$format][$language] = '%t %l, %f';
926
                    break;
927
                default:
928
                    $valid[$format][$language] = '%t %f %l';
929
                    break;
930
            }
931
        } else {
932
            $valid[$format][$language] = _api_validate_person_name_format($format);
933
        }
934
    }
935
936
    $format = $valid[$format][$language];
937
938
    $keywords = [
939
        '%firstname',
940
        '%f',
941
        '%F',
942
        '%lastname',
943
        '%l',
944
        '%L',
945
        '%title',
946
        '%t',
947
        '%T',
948
        '%username',
949
        '%u',
950
        '%U',
951
    ];
952
953
    $values = [
954
        $first_name,
955
        $first_name,
956
        api_strtoupper($first_name),
957
        $last_name,
958
        $last_name,
959
        api_strtoupper($last_name),
960
        $title,
961
        $title,
962
        api_strtoupper($title),
963
        $username,
964
        $username,
965
        api_strtoupper($username),
966
    ];
967
    $person_name = str_replace($keywords, $values, $format);
968
969
    return _api_clean_person_name($person_name);
970
}
971
972
/**
973
 * Checks whether a given format represents person name in Western order (for which first name is first).
974
 *
975
 * @param int|string $format   (optional)    The person name format.
976
 *                             It may be a pattern-string (for example '%t. %l, %f') or some of the constants
977
 *                             PERSON_NAME_COMMON_CONVENTION (default),
978
 *                             PERSON_NAME_WESTERN_ORDER,
979
 *                             PERSON_NAME_EASTERN_ORDER,
980
 *                             PERSON_NAME_LIBRARY_ORDER.
981
 * @param string     $language (optional) The language id. If it is omitted,
982
 *                             the current interface language is assumed. This parameter has meaning with the
983
 *                             format PERSON_NAME_COMMON_CONVENTION only.
984
 *
985
 * @return bool The result TRUE means that the order is first_name last_name,
986
 *              FALSE means last_name first_name.
987
 *              Note: You may use this function for determining the order of the fields or
988
 *              columns "First name" and "Last name" in forms, tables and reports.
989
 *
990
 * @author Ivan Tcholakov
991
 */
992
function api_is_western_name_order($format = null, $language = null)
993
{
994
    static $order = [];
995
    if (empty($format)) {
996
        $format = PERSON_NAME_COMMON_CONVENTION;
997
    }
998
999
    if (empty($language)) {
1000
        $language = api_get_interface_language(false, true);
1001
    }
1002
    if (!isset($order[$format][$language])) {
1003
        $test_name = api_get_person_name('%f', '%l', '%t', $format, $language);
1004
        $order[$format][$language] = stripos($test_name, '%f') <= stripos($test_name, '%l');
1005
    }
1006
1007
    return $order[$format][$language];
1008
}
1009
1010
/**
1011
 * Returns a directive for sorting person names depending on a given language
1012
 * and based on the options in the internationalization "database".
1013
 *
1014
 * @param string $language (optional) The input language.
1015
 *                         If it is omitted, the current interface language is assumed.
1016
 *
1017
 * @return bool Returns boolean value. TRUE means ORDER BY first_name, last_name
1018
 *              FALSE means ORDER BY last_name, first_name.
1019
 *              Note: You may use this function:
1020
 *              2. for constructing the ORDER clause of SQL queries, related to first_name and last_name;
1021
 *              3. for adjusting php-implemented sorting in tables and reports.
1022
 *
1023
 * @author Ivan Tcholakov
1024
 */
1025
function api_sort_by_first_name($language = null)
1026
{
1027
    static $sort_by_first_name = [];
1028
1029
    if (empty($language)) {
1030
        $language = api_get_interface_language(false, true);
1031
    }
1032
    if (!isset($sort_by_first_name[$language])) {
1033
        $sort_by_first_name[$language] = _api_get_person_name_convention($language, 'sort_by');
1034
    }
1035
1036
    return $sort_by_first_name[$language];
1037
}
1038
1039
/**
1040
 * Multibyte string conversion functions.
1041
 */
1042
1043
/**
1044
 * Converts character encoding of a given string.
1045
 *
1046
 * @param string $string        the string being converted
1047
 * @param string $to_encoding   the encoding that $string is being converted to
1048
 * @param string $from_encoding (optional)    The encoding that $string is being converted from.
1049
 *                              If it is omitted, the platform character set is assumed.
1050
 *
1051
 * @return string Returns the converted string.
1052
 *                This function is aimed at replacing the function mb_convert_encoding() for human-language strings.
1053
 *
1054
 * @see http://php.net/manual/en/function.mb-convert-encoding
1055
 */
1056
function api_convert_encoding($string, $to_encoding, $from_encoding = 'UTF-8')
1057
{
1058
    if (strtoupper($to_encoding) === strtoupper($from_encoding)) {
1059
        return $string;
1060
    }
1061
1062
    return mb_convert_encoding($string, $to_encoding, $from_encoding);
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi...coding, $from_encoding) also could return the type array which is incompatible with the documented return type string.
Loading history...
1063
}
1064
1065
/**
1066
 * Converts a given string into UTF-8 encoded string.
1067
 *
1068
 * @param string $string        the string being converted
1069
 * @param string $from_encoding (optional) The encoding that $string is being converted from.
1070
 *                              If it is omitted, the platform character set is assumed.
1071
 *
1072
 * @return string Returns the converted string.
1073
 *                This function is aimed at replacing the function utf8_encode() for human-language strings.
1074
 *
1075
 * @see http://php.net/manual/en/function.utf8-encode
1076
 */
1077
function api_utf8_encode($string, $from_encoding = 'UTF-8')
1078
{
1079
    return mb_convert_encoding($string, 'UTF-8', $from_encoding);
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi...UTF-8', $from_encoding) also could return the type array which is incompatible with the documented return type string.
Loading history...
1080
}
1081
1082
/**
1083
 * Converts a given string from UTF-8 encoding to a specified encoding.
1084
 *
1085
 * @param string $string      the string being converted
1086
 * @param string $to_encoding (optional)    The encoding that $string is being converted to.
1087
 *                            If it is omitted, the platform character set is assumed.
1088
 *
1089
 * @return string Returns the converted string.
1090
 *                This function is aimed at replacing the function utf8_decode() for human-language strings.
1091
 *
1092
 * @see http://php.net/manual/en/function.utf8-decode
1093
 */
1094
function api_utf8_decode($string, $to_encoding = null)
1095
{
1096
    return mb_convert_encoding($string, $to_encoding, 'UTF-8');
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi... $to_encoding, 'UTF-8') also could return the type array which is incompatible with the documented return type string.
Loading history...
1097
}
1098
1099
/**
1100
 * Converts a given string into the system encoding (or platform character set).
1101
 * When $from encoding is omitted on UTF-8 platforms then language dependent encoding
1102
 * is guessed/assumed. On non-UTF-8 platforms omitted $from encoding is assumed as UTF-8.
1103
 * When the parameter $check_utf8_validity is true the function checks string's
1104
 * UTF-8 validity and decides whether to try to convert it or not.
1105
 * This function is useful for problem detection or making workarounds.
1106
 *
1107
 * @param string $string              the string being converted
1108
 * @param string $from_encoding       (optional) The encoding that $string is being converted from.
1109
 *                                    It is guessed when it is omitted.
1110
 * @param bool   $check_utf8_validity (optional)    A flag for UTF-8 validity check as condition for making conversion
1111
 *
1112
 * @return string returns the converted string
1113
 */
1114
function api_to_system_encoding($string, $from_encoding = null, $check_utf8_validity = false)
1115
{
1116
    $system_encoding = api_get_system_encoding();
1117
1118
    return api_convert_encoding($string, $system_encoding, $from_encoding);
1119
}
1120
1121
/**
1122
 * Converts all applicable characters to HTML entities.
1123
 *
1124
 * @param string $string      the input string
1125
 * @param int    $quote_style (optional)    The quote style - ENT_COMPAT (default), ENT_QUOTES, ENT_NOQUOTES
1126
 * @param string $encoding    (optional)    The encoding (of the input string) used in conversion.
1127
 *                            If it is omitted, the platform character set is assumed.
1128
 *
1129
 * @return string Returns the converted string.
1130
 *                This function is aimed at replacing the function htmlentities() for human-language strings.
1131
 *
1132
 * @see http://php.net/manual/en/function.htmlentities
1133
 */
1134
function api_htmlentities($string, $quote_style = ENT_COMPAT, $encoding = 'UTF-8')
1135
{
1136
    switch ($quote_style) {
1137
        case ENT_COMPAT:
1138
            $string = str_replace(['&', '"', '<', '>'], ['&amp;', '&quot;', '&lt;', '&gt;'], $string);
1139
            break;
1140
        case ENT_QUOTES:
1141
            $string = str_replace(['&', '\'', '"', '<', '>'], ['&amp;', '&#039;', '&quot;', '&lt;', '&gt;'], $string);
1142
            break;
1143
    }
1144
1145
    return mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi...TML-ENTITIES', 'UTF-8') also could return the type array which is incompatible with the documented return type string.
Loading history...
1146
}
1147
1148
/**
1149
 * Converts HTML entities into normal characters.
1150
 *
1151
 * @param string $string      the input string
1152
 * @param int    $quote_style (optional)    The quote style - ENT_COMPAT (default), ENT_QUOTES, ENT_NOQUOTES
1153
 * @param string $encoding    (optional)    The encoding (of the result) used in conversion.
1154
 *                            If it is omitted, the platform character set is assumed.
1155
 *
1156
 * @return string Returns the converted string.
1157
 *                This function is aimed at replacing the function html_entity_decode() for human-language strings.
1158
 *
1159
 * @see http://php.net/html_entity_decode
1160
 */
1161
function api_html_entity_decode($string, $quote_style = ENT_COMPAT, $encoding = 'UTF-8')
1162
{
1163
    if (empty($encoding)) {
1164
        $encoding = _api_mb_internal_encoding();
1165
    }
1166
    if (api_is_encoding_supported($encoding)) {
1167
        if (!api_is_utf8($encoding)) {
1168
            $string = api_utf8_encode($string, $encoding);
1169
        }
1170
        $string = html_entity_decode($string, $quote_style, 'UTF-8');
1171
        if (!api_is_utf8($encoding)) {
1172
            return api_utf8_decode($string, $encoding);
1173
        }
1174
1175
        return $string;
1176
    }
1177
1178
    return $string; // Here the function gives up.
1179
}
1180
1181
/**
1182
 * This function encodes (conditionally) a given string to UTF-8 if XmlHttp-request has been detected.
1183
 *
1184
 * @param string $string        the string being converted
1185
 * @param string $from_encoding (optional)    The encoding that $string is being converted from.
1186
 *                              If it is omitted, the platform character set is assumed.
1187
 *
1188
 * @return string returns the converted string
1189
 */
1190
function api_xml_http_response_encode($string, $from_encoding = 'UTF8')
1191
{
1192
    if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
1193
        if (empty($from_encoding)) {
1194
            $from_encoding = _api_mb_internal_encoding();
1195
        }
1196
        if (!api_is_utf8($from_encoding)) {
1197
            return api_utf8_encode($string, $from_encoding);
1198
        }
1199
    }
1200
1201
    return $string;
1202
}
1203
1204
/**
1205
 * Transliterates a string with arbitrary encoding into a plain ASCII string.
1206
 *
1207
 * Example:
1208
 * echo api_transliterate(api_html_entity_decode(
1209
 *    '&#1060;&#1105;&#1076;&#1086;&#1088; '.
1210
 *    '&#1052;&#1080;&#1093;&#1072;&#1081;&#1083;&#1086;&#1074;&#1080;&#1095; '.
1211
 *    '&#1044;&#1086;&#1089;&#1090;&#1086;&#1077;&#1074;&#1082;&#1080;&#1081;',
1212
 *    ENT_QUOTES, 'UTF-8'), 'X', 'UTF-8');
1213
 * The output should be: Fyodor Mihaylovich Dostoevkiy
1214
 *
1215
 * @param string $string        the input string
1216
 * @param string $unknown       (optional) Replacement character for unknown characters and illegal UTF-8 sequences
1217
 * @param string $from_encoding (optional) The encoding of the input string.
1218
 *                              If it is omitted, the platform character set is assumed.
1219
 *
1220
 * @return string plain ASCII output
1221
 */
1222
function api_transliterate($string, $unknown = '?', $from_encoding = null)
1223
{
1224
    return URLify::transliterate($string);
1225
}
1226
1227
/**
1228
 * Takes the first character in a string and returns its Unicode codepoint.
1229
 *
1230
 * @param string $character the input string
1231
 * @param string $encoding  (optional) The encoding of the input string.
1232
 *                          If it is omitted, the platform character set will be used by default.
1233
 *
1234
 * @return int Returns: the codepoint of the first character; or 0xFFFD (unknown character) when the input string is empty.
1235
 *             This is a multibyte aware version of the function ord().
1236
 *
1237
 * @see http://php.net/manual/en/function.ord.php
1238
 * Note the difference with the original funtion ord(): ord('') returns 0, api_ord('') returns 0xFFFD (unknown character).
1239
 */
1240
function api_ord($character, $encoding = 'UTF-8')
1241
{
1242
    return Utf8::ord(api_utf8_encode($character, $encoding));
1243
}
1244
1245
/**
1246
 * This function returns a string or an array with all occurrences of search
1247
 * in subject (ignoring case) replaced with the given replace value.
1248
 *
1249
 * @param mixed  $search   string or array of strings to be found
1250
 * @param mixed  $replace  string or array of strings used for replacement
1251
 * @param mixed  $subject  string or array of strings being searched
1252
 * @param int    $count    (optional) The number of matched and replaced needles
1253
 *                         will be returned in count, which is passed by reference
1254
 * @param string $encoding (optional) The used internally by this function character encoding.
1255
 *                         If it is omitted, the platform character set will be used by default.
1256
 *
1257
 * @return mixed String or array as a result.
1258
 *               Notes:
1259
 *               If $subject is an array, then the search and replace is performed with
1260
 *               every entry of subject, the return value is an array.
1261
 *               If $search and $replace are arrays, then the function takes a value from
1262
 *               each array and uses it to do search and replace on subject.
1263
 *               If $replace has fewer values than search, then an empty string is used for the rest of replacement values.
1264
 *               If $search is an array and $replace is a string, then this replacement string is used for every value of search.
1265
 *               This function is aimed at replacing the function str_ireplace() for human-language strings.
1266
 *
1267
 * @see http://php.net/manual/en/function.str-ireplace
1268
 *
1269
 * @author Henri Sivonen, mailto:[email protected]
1270
 *
1271
 * @see http://hsivonen.iki.fi/php-utf8/
1272
 * Adaptation for Chamilo 1.8.7, 2010
1273
 * Initial implementation Dokeos LMS, August 2009
1274
 *
1275
 * @author Ivan Tcholakov
1276
 */
1277
function api_str_ireplace($search, $replace, $subject, &$count = null, $encoding = null)
1278
{
1279
    return Utf8::str_ireplace($search, $replace, $subject, $count);
1280
}
1281
1282
/**
1283
 * Converts a string to an array.
1284
 *
1285
 * @param string $string       the input string
1286
 * @param int    $split_length maximum character-length of the chunk, one character by default
1287
 * @param string $encoding     (optional) The used internally by this function
1288
 *                             character encoding. If it is omitted, the platform character set will be used by default.
1289
 *
1290
 * @return array The result array of chunks with the spcified length.
1291
 *               Notes:
1292
 *               If the optional split_length parameter is specified, the returned array will be broken down into chunks
1293
 *               with each being split_length in length, otherwise each chunk will be one character in length.
1294
 *               FALSE is returned if split_length is less than 1.
1295
 *               If the split_length length exceeds the length of string, the entire string is returned as the first (and only) array element.
1296
 *               This function is aimed at replacing the function str_split() for human-language strings.
1297
 *
1298
 * @see http://php.net/str_split
1299
 */
1300
function api_str_split($string, $split_length = 1, $encoding = null)
1301
{
1302
    return Utf8::str_split($string, $split_length);
1303
}
1304
1305
/**
1306
 * Finds position of first occurrence of a string within another, case insensitive.
1307
 *
1308
 * @param string $haystack the string from which to get the position of the first occurrence
1309
 * @param string $needle   the string to be found
1310
 * @param int    $offset   The position in $haystack to start searching from.
1311
 *                         If it is omitted, searching starts from the beginning.
1312
 * @param string $encoding (optional) The used internally by this function
1313
 *                         character encoding. If it is omitted, the platform character set will be used by default.
1314
 *
1315
 * @return mixed Returns the numeric position of the first occurrence of
1316
 *               $needle in the $haystack, or FALSE if $needle is not found.
1317
 *               Note: The first character's position is 0, the second character position is 1, and so on.
1318
 *               This function is aimed at replacing the functions stripos() and mb_stripos() for human-language strings.
1319
 *
1320
 * @see http://php.net/manual/en/function.stripos
1321
 * @see http://php.net/manual/en/function.mb-stripos
1322
 */
1323
function api_stripos($haystack, $needle, $offset = 0, $encoding = null)
1324
{
1325
    return Utf8::stripos($haystack, $needle, $offset);
1326
}
1327
1328
/**
1329
 * Finds first occurrence of a string within another, case insensitive.
1330
 *
1331
 * @param string $haystack      the string from which to get the first occurrence
1332
 * @param mixed  $needle        the string to be found
1333
 * @param bool   $before_needle (optional) Determines which portion of $haystack
1334
 *                              this function returns. The default value is FALSE.
1335
 * @param string $encoding      (optional) The used internally by this function
1336
 *                              character encoding. If it is omitted, the platform character set will be used by default.
1337
 *
1338
 * @return mixed Returns the portion of $haystack, or FALSE if $needle is not found.
1339
 *               Notes:
1340
 *               If $needle is not a string, it is converted to an integer and applied as the
1341
 *               ordinal value (codepoint if the encoding is UTF-8) of a character.
1342
 *               If $before_needle is set to TRUE, the function returns all of $haystack
1343
 *               from the beginning to the first occurrence of $needle.
1344
 *               If $before_needle is set to FALSE, the function returns all of $haystack f
1345
 *               rom the first occurrence of $needle to the end.
1346
 *               This function is aimed at replacing the functions stristr() and mb_stristr() for human-language strings.
1347
 *
1348
 * @see http://php.net/manual/en/function.stristr
1349
 * @see http://php.net/manual/en/function.mb-stristr
1350
 */
1351
function api_stristr($haystack, $needle, $before_needle = false, $encoding = null)
1352
{
1353
    return Utf8::stristr($haystack, $needle, $before_needle);
1354
}
1355
1356
/**
1357
 * Returns length of the input string.
1358
 *
1359
 * @param string $string   the string which length is to be calculated
1360
 * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1361
 *
1362
 * @return int Returns the number of characters within the string. A multi-byte character is counted as 1.
1363
 *             This function is aimed at replacing the functions strlen() and mb_strlen() for human-language strings.
1364
 *
1365
 * @see http://php.net/manual/en/function.strlen
1366
 * @see http://php.net/manual/en/function.mb-strlen
1367
 * Note: When you use strlen() to test for an empty string, you needn't change it to api_strlen().
1368
 * For example, in lines like the following:
1369
 * if (strlen($string) > 0)
1370
 * if (strlen($string) != 0)
1371
 * there is no need the original function strlen() to be changed, it works correctly and faster for these cases.
1372
 */
1373
function api_strlen($string, $encoding = null)
1374
{
1375
    return Utf8::strlen($string);
1376
}
1377
1378
/**
1379
 * Finds position of first occurrence of a string within another.
1380
 *
1381
 * @param string $haystack the string from which to get the position of the first occurrence
1382
 * @param string $needle   the string to be found
1383
 * @param int    $offset   (optional) The position in $haystack to start searching from. If it is omitted, searching starts from the beginning.
1384
 * @param string $encoding (optional)    The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1385
 *
1386
 * @return mixed Returns the numeric position of the first occurrence of $needle in the $haystack, or FALSE if $needle is not found.
1387
 *               Note: The first character's position is 0, the second character position is 1, and so on.
1388
 *               This function is aimed at replacing the functions strpos() and mb_strpos() for human-language strings.
1389
 *
1390
 * @see http://php.net/manual/en/function.strpos
1391
 * @see http://php.net/manual/en/function.mb-strpos
1392
 */
1393
function api_strpos($haystack, $needle, $offset = 0, $encoding = null)
1394
{
1395
    return Utf8::strpos($haystack, $needle, $offset);
1396
}
1397
1398
/**
1399
 * Finds the last occurrence of a character in a string.
1400
 *
1401
 * @param string $haystack      the string from which to get the last occurrence
1402
 * @param mixed  $needle        the string which first character is to be found
1403
 * @param bool   $before_needle (optional) Determines which portion of $haystack this function returns. The default value is FALSE.
1404
 * @param string $encoding      (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1405
 *
1406
 * @return mixed Returns the portion of $haystack, or FALSE if the first character from $needle is not found.
1407
 *               Notes:
1408
 *               If $needle is not a string, it is converted to an integer and applied as the ordinal value (codepoint if the encoding is UTF-8) of a character.
1409
 *               If $before_needle is set to TRUE, the function returns all of $haystack from the beginning to the first occurrence.
1410
 *               If $before_needle is set to FALSE, the function returns all of $haystack from the first occurrence to the end.
1411
 *               This function is aimed at replacing the functions strrchr() and mb_strrchr() for human-language strings.
1412
 *
1413
 * @see http://php.net/manual/en/function.strrchr
1414
 * @see http://php.net/manual/en/function.mb-strrchr
1415
 */
1416
function api_strrchr($haystack, $needle, $before_needle = false, $encoding = null)
1417
{
1418
    return Utf8::strrchr($haystack, $needle);
1419
}
1420
1421
/**
1422
 * Reverses a string.
1423
 *
1424
 * @param string $string   the string to be reversed
1425
 * @param string $encoding (optional)    The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1426
 *
1427
 * @return string Returns the reversed string.
1428
 *                This function is aimed at replacing the function strrev() for human-language strings.
1429
 *
1430
 * @see http://php.net/manual/en/function.strrev
1431
 */
1432
function api_strrev($string, $encoding = null)
1433
{
1434
    return Utf8::strrev($string);
1435
}
1436
1437
/**
1438
 * Finds the position of last occurrence (case insensitive) of a string in a string.
1439
 *
1440
 * @param string $haystack the string from which to get the position of the last occurrence
1441
 * @param string $needle   the string to be found
1442
 * @param int    $offset   (optional) $offset may be specified to begin searching an arbitrary position. Negative values will stop searching at an arbitrary point prior to the end of the string.
1443
 * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1444
 *
1445
 * @return mixed Returns the numeric position of the first occurrence (case insensitive) of $needle in the $haystack, or FALSE if $needle is not found.
1446
 *               Note: The first character's position is 0, the second character position is 1, and so on.
1447
 *               This function is aimed at replacing the functions strripos() and mb_strripos() for human-language strings.
1448
 *
1449
 * @see http://php.net/manual/en/function.strripos
1450
 * @see http://php.net/manual/en/function.mb-strripos
1451
 */
1452
function api_strripos($haystack, $needle, $offset = 0, $encoding = null)
1453
{
1454
    return Utf8::strripos($haystack, $needle, $offset);
1455
}
1456
1457
/**
1458
 * Finds the position of last occurrence of a string in a string.
1459
 *
1460
 * @param string $haystack the string from which to get the position of the last occurrence
1461
 * @param string $needle   the string to be found
1462
 * @param int    $offset   (optional) $offset may be specified to begin searching an arbitrary position. Negative values will stop searching at an arbitrary point prior to the end of the string.
1463
 * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1464
 *
1465
 * @return mixed Returns the numeric position of the first occurrence of $needle in the $haystack, or FALSE if $needle is not found.
1466
 *               Note: The first character's position is 0, the second character position is 1, and so on.
1467
 *               This function is aimed at replacing the functions strrpos() and mb_strrpos() for human-language strings.
1468
 *
1469
 * @see http://php.net/manual/en/function.strrpos
1470
 * @see http://php.net/manual/en/function.mb-strrpos
1471
 */
1472
function api_strrpos($haystack, $needle, $offset = 0, $encoding = null)
1473
{
1474
    return Utf8::strrpos($haystack, $needle, $offset);
1475
}
1476
1477
/**
1478
 * Finds first occurrence of a string within another.
1479
 *
1480
 * @param string $haystack      the string from which to get the first occurrence
1481
 * @param mixed  $needle        the string to be found
1482
 * @param bool   $before_needle (optional) Determines which portion of $haystack this function returns. The default value is FALSE.
1483
 * @param string $encoding      (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1484
 *
1485
 * @return mixed Returns the portion of $haystack, or FALSE if $needle is not found.
1486
 *               Notes:
1487
 *               If $needle is not a string, it is converted to an integer and applied as the ordinal value (codepoint if the encoding is UTF-8) of a character.
1488
 *               If $before_needle is set to TRUE, the function returns all of $haystack from the beginning to the first occurrence of $needle.
1489
 *               If $before_needle is set to FALSE, the function returns all of $haystack from the first occurrence of $needle to the end.
1490
 *               This function is aimed at replacing the functions strstr() and mb_strstr() for human-language strings.
1491
 *
1492
 * @see http://php.net/manual/en/function.strstr
1493
 * @see http://php.net/manual/en/function.mb-strstr
1494
 */
1495
function api_strstr($haystack, $needle, $before_needle = false, $encoding = null)
1496
{
1497
    return Utf8::strstr($haystack, $needle, $before_needle);
1498
}
1499
1500
/**
1501
 * Makes a string lowercase.
1502
 *
1503
 * @param string $string   the string being lowercased
1504
 * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1505
 *
1506
 * @return string Returns the string with all alphabetic characters converted to lowercase.
1507
 *                This function is aimed at replacing the functions strtolower() and mb_strtolower() for human-language strings.
1508
 *
1509
 * @see http://php.net/manual/en/function.strtolower
1510
 * @see http://php.net/manual/en/function.mb-strtolower
1511
 */
1512
function api_strtolower($string, $encoding = null)
1513
{
1514
    return Utf8::strtolower($string);
1515
}
1516
1517
/**
1518
 * Makes a string uppercase.
1519
 *
1520
 * @param string $string   the string being uppercased
1521
 * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1522
 *
1523
 * @return string Returns the string with all alphabetic characters converted to uppercase.
1524
 *                This function is aimed at replacing the functions strtoupper() and mb_strtoupper() for human-language strings.
1525
 *
1526
 * @see http://php.net/manual/en/function.strtoupper
1527
 * @see http://php.net/manual/en/function.mb-strtoupper
1528
 */
1529
function api_strtoupper($string, $encoding = null)
1530
{
1531
    return Utf8::strtoupper($string);
1532
}
1533
1534
/**
1535
 * // Gets part of a string.
1536
 *
1537
 * @param string $string   the input string
1538
 * @param int    $start    the first position from which the extracted part begins
1539
 * @param int    $length   the length in character of the extracted part
1540
 * @param string $encoding (optional) The used internally by this function
1541
 *                         character encoding. If it is omitted, the platform character set will be used by default.
1542
 *
1543
 * @return string Returns the part of the string specified by the start and length parameters.
1544
 *                Note: First character's position is 0. Second character position is 1, and so on.
1545
 *                This function is aimed at replacing the functions substr() and mb_substr() for human-language strings.
1546
 *
1547
 * @see http://php.net/manual/en/function.substr
1548
 * @see http://php.net/manual/en/function.mb-substr
1549
 */
1550
function api_substr($string, $start, $length = null, $encoding = null)
1551
{
1552
    if (is_null($length)) {
1553
        $length = api_strlen($string, $encoding);
1554
    }
1555
1556
    return Utf8::substr($string, $start, $length);
1557
}
1558
1559
/**
1560
 * Counts the number of substring occurrences.
1561
 *
1562
 * @param string $haystack the string being checked
1563
 * @param string $needle   the string being found
1564
 * @param string $encoding (optional) The used internally by this function character encoding.
1565
 *                         If it is omitted, the platform character set will be used by default.
1566
 *
1567
 * @return int the number of times the needle substring occurs in the haystack string
1568
 *
1569
 * @see http://php.net/manual/en/function.mb-substr-count.php
1570
 */
1571
function api_substr_count($haystack, $needle, $encoding = null)
1572
{
1573
    return Utf8::substr_count($haystack, $needle);
1574
}
1575
1576
/**
1577
 * Replaces text within a portion of a string.
1578
 *
1579
 * @param string $string      the input string
1580
 * @param string $replacement the replacement string
1581
 * @param int    $start       The position from which replacing will begin.
1582
 *                            Notes:
1583
 *                            If $start is positive, the replacing will begin at the $start'th offset into the string.
1584
 *                            If $start is negative, the replacing will begin at the $start'th character from the end of the string.
1585
 * @param int    $length      (optional) The position where replacing will end.
1586
 *                            Notes:
1587
 *                            If given and is positive, it represents the length of the portion of the string which is to be replaced.
1588
 *                            If it is negative, it represents the number of characters from the end of string at which to stop replacing.
1589
 *                            If it is not given, then it will default to api_strlen($string); i.e. end the replacing at the end of string.
1590
 *                            If $length is zero, then this function will have the effect of inserting replacement into the string at the given start offset.
1591
 * @param string $encoding    (optional)    The used internally by this function character encoding.
1592
 *                            If it is omitted, the platform character set will be used by default.
1593
 *
1594
 * @return string The result string is returned.
1595
 *                This function is aimed at replacing the function substr_replace() for human-language strings.
1596
 *
1597
 * @see http://php.net/manual/function.substr-replace
1598
 */
1599
function api_substr_replace($string, $replacement, $start, $length = null, $encoding = null)
1600
{
1601
    if (is_null($length)) {
1602
        $length = api_strlen($string);
1603
    }
1604
1605
    return UTf8::substr_replace($string, $replacement, $start, $length);
1606
}
1607
1608
/**
1609
 * Makes a string's first character uppercase.
1610
 *
1611
 * @param string $string   the input string
1612
 * @param string $encoding (optional)    The used internally by this function character encoding.
1613
 *                         If it is omitted, the platform character set will be used by default.
1614
 *
1615
 * @return string Returns a string with the first character capitalized, if that character is alphabetic.
1616
 *                This function is aimed at replacing the function ucfirst() for human-language strings.
1617
 *
1618
 * @see http://php.net/manual/en/function.ucfirst
1619
 */
1620
function api_ucfirst($string, $encoding = null)
1621
{
1622
    return Utf8::ucfirst($string);
1623
}
1624
1625
/**
1626
 * Uppercases the first character of each word in a string.
1627
 *
1628
 * @param string $string   the input string
1629
 * @param string $encoding (optional) The used internally by this function character encoding.
1630
 *                         If it is omitted, the platform character set will be used by default.
1631
 *
1632
 * @return string Returns the modified string.
1633
 *                This function is aimed at replacing the function ucwords() for human-language strings.
1634
 *
1635
 * @see http://php.net/manual/en/function.ucwords
1636
 */
1637
function api_ucwords($string, $encoding = null)
1638
{
1639
    return Utf8::ucwords($string);
1640
}
1641
1642
/**
1643
 * Performs a regular expression match, UTF-8 aware when it is applicable.
1644
 *
1645
 * @param string $pattern  the pattern to search for, as a string
1646
 * @param string $subject  the input string
1647
 * @param array  &$matches (optional) If matches is provided,
1648
 *                         then it is filled with the results of search (as an array).
1649
 *                         $matches[0] will contain the text that matched the full pattern, $matches[1] will have the text that matched the first captured parenthesized subpattern, and so on.
1650
 * @param int    $flags    (optional) Could be PREG_OFFSET_CAPTURE. If this flag is passed, for every occurring match the appendant string offset will also be returned.
1651
 *                         Note that this changes the return value in an array where every element is an array consisting of the matched string at index 0 and its string offset into subject at index 1.
1652
 * @param int    $offset   (optional)        Normally, the search starts from the beginning of the subject string. The optional parameter offset can be used to specify the alternate place from which to start the search.
1653
 * @param string $encoding (optional)    The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1654
 *
1655
 * @return int|bool returns the number of times pattern matches or FALSE if an error occurred
1656
 *
1657
 * @see http://php.net/preg_match
1658
 */
1659
function api_preg_match(
1660
    $pattern,
1661
    $subject,
1662
    &$matches = null,
1663
    $flags = 0,
1664
    $offset = 0,
1665
    $encoding = null
1666
) {
1667
    if (empty($encoding)) {
1668
        $encoding = _api_mb_internal_encoding();
1669
    }
1670
1671
    return preg_match(api_is_utf8($encoding) ? $pattern.'u' : $pattern, $subject, $matches, $flags, $offset);
1672
}
1673
1674
/**
1675
 * Performs a global regular expression match, UTF-8 aware when it is applicable.
1676
 *
1677
 * @param string $pattern  the pattern to search for, as a string
1678
 * @param string $subject  the input string
1679
 * @param array  &$matches (optional)    Array of all matches in multi-dimensional array ordered according to $flags
1680
 * @param int    $flags    (optional)            Can be a combination of the following flags (note that it doesn't make sense to use PREG_PATTERN_ORDER together with PREG_SET_ORDER):
1681
 *                         PREG_PATTERN_ORDER - orders results so that $matches[0] is an array of full pattern matches, $matches[1] is an array of strings matched by the first parenthesized subpattern, and so on;
1682
 *                         PREG_SET_ORDER - orders results so that $matches[0] is an array of first set of matches, $matches[1] is an array of second set of matches, and so on;
1683
 *                         PREG_OFFSET_CAPTURE - If this flag is passed, for every occurring match the appendant string offset will also be returned. Note that this changes the value of matches
1684
 *                         in an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.
1685
 *                         If no order flag is given, PREG_PATTERN_ORDER is assumed.
1686
 * @param int    $offset   (optional)		Normally, the search starts from the beginning of the subject string. The optional parameter offset can be used to specify the alternate place from which to start the search.
1687
 * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1688
 *
1689
 * @return int|bool returns the number of full pattern matches (which might be zero), or FALSE if an error occurred
1690
 *
1691
 * @see http://php.net/preg_match_all
1692
 */
1693
function api_preg_match_all($pattern, $subject, &$matches, $flags = PREG_PATTERN_ORDER, $offset = 0, $encoding = null)
1694
{
1695
    if (empty($encoding)) {
1696
        $encoding = _api_mb_internal_encoding();
1697
    }
1698
    if (is_null($flags)) {
1699
        $flags = PREG_PATTERN_ORDER;
1700
    }
1701
1702
    return preg_match_all(api_is_utf8($encoding) ? $pattern.'u' : $pattern, $subject, $matches, $flags, $offset);
0 ignored issues
show
Bug Best Practice introduced by
The expression return preg_match_all(ap...tches, $flags, $offset) also could return the type null which is incompatible with the documented return type boolean|integer.
Loading history...
1703
}
1704
1705
/**
1706
 * Performs a regular expression search and replace, UTF-8 aware when it is applicable.
1707
 *
1708
 * @param string|array $pattern     The pattern to search for. It can be either a string or an array with strings.
1709
 * @param string|array $replacement the string or an array with strings to replace
1710
 * @param string|array $subject     the string or an array with strings to search and replace
1711
 * @param int          $limit       The maximum possible replacements for each pattern in each subject string. Defaults to -1 (no limit).
1712
 * @param int          &$count      If specified, this variable will be filled with the number of replacements done
1713
 * @param string       $encoding    (optional)	The used internally by this function character encoding.
1714
 *                                  If it is omitted, the platform character set will be used by default.
1715
 *
1716
 * @return array|string|null returns an array if the subject parameter is an array, or a string otherwise.
1717
 *                           If matches are found, the new subject will be returned, otherwise subject will be returned unchanged or NULL if an error occurred.
1718
 *
1719
 * @see http://php.net/preg_replace
1720
 */
1721
function api_preg_replace($pattern, $replacement, $subject, $limit = -1, &$count = 0, $encoding = null)
1722
{
1723
    if (empty($encoding)) {
1724
        $encoding = _api_mb_internal_encoding();
1725
    }
1726
    $is_utf8 = api_is_utf8($encoding);
1727
    if (is_array($pattern)) {
1728
        foreach ($pattern as &$p) {
1729
            $p = $is_utf8 ? $p.'u' : $p;
1730
        }
1731
    } else {
1732
        $pattern = $is_utf8 ? $pattern.'u' : $pattern;
1733
    }
1734
1735
    return preg_replace($pattern, $replacement, $subject, $limit, $count);
1736
}
1737
1738
/**
1739
 * Splits a string by a regular expression, UTF-8 aware when it is applicable.
1740
 *
1741
 * @param string $pattern  the pattern to search for, as a string
1742
 * @param string $subject  the input string
1743
 * @param int    $limit    (optional)			If specified, then only substrings up to $limit are returned with the rest of the string being placed in the last substring. A limit of -1, 0 or null means "no limit" and, as is standard across PHP.
1744
 * @param int    $flags    (optional)			$flags can be any combination of the following flags (combined with bitwise | operator):
1745
 *                         PREG_SPLIT_NO_EMPTY - if this flag is set, only non-empty pieces will be returned;
1746
 *                         PREG_SPLIT_DELIM_CAPTURE - if this flag is set, parenthesized expression in the delimiter pattern will be captured and returned as well;
1747
 *                         PREG_SPLIT_OFFSET_CAPTURE - If this flag is set, for every occurring match the appendant string offset will also be returned.
1748
 *                         Note that this changes the return value in an array where every element is an array consisting of the matched string at offset 0 and its string offset into subject at offset 1.
1749
 * @param string $encoding (optional)	The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1750
 *
1751
 * @return array returns an array containing substrings of $subject split along boundaries matched by $pattern
1752
 *
1753
 * @see http://php.net/preg_split
1754
 */
1755
function api_preg_split($pattern, $subject, $limit = -1, $flags = 0, $encoding = null)
1756
{
1757
    if (empty($encoding)) {
1758
        $encoding = _api_mb_internal_encoding();
1759
    }
1760
1761
    return preg_split(api_is_utf8($encoding) ? $pattern.'u' : $pattern, $subject, $limit, $flags);
1762
}
1763
1764
/**
1765
 * String comparison.
1766
 */
1767
1768
/**
1769
 * Performs string comparison, case insensitive, language sensitive, with extended multibyte support.
1770
 *
1771
 * @param string $string1  the first string
1772
 * @param string $string2  the second string
1773
 * @param string $language (optional) The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1774
 * @param string $encoding (optional) The used internally by this function character encoding. If it is omitted, the platform character set will be used by default.
1775
 *
1776
 * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
1777
 *             This function is aimed at replacing the function strcasecmp() for human-language strings.
1778
 *
1779
 * @see http://php.net/manual/en/function.strcasecmp
1780
 */
1781
function api_strcasecmp($string1, $string2, $language = null, $encoding = null)
1782
{
1783
    return api_strcmp(api_strtolower($string1, $encoding), api_strtolower($string2, $encoding), $language, $encoding);
1784
}
1785
1786
/**
1787
 * Performs string comparison, case sensitive, language sensitive, with extended multibyte support.
1788
 *
1789
 * @param string $string1  the first string
1790
 * @param string $string2  the second string
1791
 * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1792
 * @param string $encoding (optional)	The used internally by this function character encoding.
1793
 *                         If it is omitted, the platform character set will be used by default.
1794
 *
1795
 * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
1796
 *             This function is aimed at replacing the function strcmp() for human-language strings.
1797
 *
1798
 * @see http://php.net/manual/en/function.strcmp.php
1799
 * @see http://php.net/manual/en/collator.compare.php
1800
 */
1801
function api_strcmp($string1, $string2, $language = null, $encoding = null)
1802
{
1803
    return strcmp($string1, $string2);
1804
}
1805
1806
/**
1807
 * Performs string comparison in so called "natural order", case sensitive, language sensitive, with extended multibyte support.
1808
 *
1809
 * @param string $string1  the first string
1810
 * @param string $string2  the second string
1811
 * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1812
 * @param string $encoding (optional)	The used internally by this function character encoding.
1813
 *                         If it is omitted, the platform character set will be used by default.
1814
 *
1815
 * @return int Returns < 0 if $string1 is less than $string2; > 0 if $string1 is greater than $string2; and 0 if the strings are equal.
1816
 *             This function is aimed at replacing the function strnatcmp() for human-language strings.
1817
 *
1818
 * @see http://php.net/manual/en/function.strnatcmp.php
1819
 * @see http://php.net/manual/en/collator.compare.php
1820
 */
1821
function api_strnatcmp($string1, $string2, $language = null, $encoding = null)
1822
{
1823
    return strnatcmp($string1, $string2);
1824
}
1825
1826
/**
1827
 * Sorting arrays.
1828
 */
1829
1830
/**
1831
 * Sorts an array using natural order algorithm.
1832
 *
1833
 * @param array  $array    the input array
1834
 * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1835
 * @param string $encoding (optional)	The used internally by this function character encoding.
1836
 *                         If it is omitted, the platform character set will be used by default.
1837
 *
1838
 * @return bool Returns TRUE on success, FALSE on error.
1839
 *              This function is aimed at replacing the function natsort() for sorting human-language strings.
1840
 *
1841
 * @see http://php.net/manual/en/function.natsort.php
1842
 */
1843
function api_natsort(&$array, $language = null, $encoding = null)
1844
{
1845
    return natsort($array);
1846
}
1847
1848
/**
1849
 * Sorts an array using natural order algorithm in reverse order.
1850
 *
1851
 * @param array  $array    the input array
1852
 * @param string $language (optional)	The language in which comparison is to be made. If language is omitted, interface language is assumed then.
1853
 * @param string $encoding (optional)	The used internally by this function character encoding.
1854
 *                         If it is omitted, the platform character set will be used by default.
1855
 *
1856
 * @return bool returns TRUE on success, FALSE on error
1857
 */
1858
function api_natrsort(&$array, $language = null, $encoding = null)
1859
{
1860
    return uasort($array, '_api_strnatrcmp');
1861
}
1862
1863
/**
1864
 * Encoding management functions.
1865
 */
1866
1867
/**
1868
 * This function unifies the encoding identificators, so they could be compared.
1869
 *
1870
 * @param string|array $encoding the specified encoding
1871
 *
1872
 * @return string returns the encoding identificator modified in suitable for comparison way
1873
 */
1874
function api_refine_encoding_id($encoding)
1875
{
1876
    if (is_array($encoding)) {
1877
        return array_map('api_refine_encoding_id', $encoding);
1878
    }
1879
1880
    return strtoupper(str_replace('_', '-', $encoding));
1881
}
1882
1883
/**
1884
 * This function checks whether two $encoding are equal (same, equvalent).
1885
 *
1886
 * @param string|array $encoding1 The first encoding
1887
 * @param string|array $encoding2 The second encoding
1888
 * @param bool         $strict    When this parameter is TRUE the comparison ignores aliases of encodings.
1889
 *                                When the parameter is FALSE, aliases are taken into account.
1890
 *
1891
 * @return bool returns TRUE if the encodings are equal, FALSE otherwise
1892
 */
1893
function api_equal_encodings($encoding1, $encoding2, $strict = false)
1894
{
1895
    static $equal_encodings = [];
1896
    if (is_array($encoding1)) {
1897
        foreach ($encoding1 as $encoding) {
1898
            if (api_equal_encodings($encoding, $encoding2, $strict)) {
1899
                return true;
1900
            }
1901
        }
1902
1903
        return false;
1904
    } elseif (is_array($encoding2)) {
1905
        foreach ($encoding2 as $encoding) {
1906
            if (api_equal_encodings($encoding1, $encoding, $strict)) {
1907
                return true;
1908
            }
1909
        }
1910
1911
        return false;
1912
    }
1913
    if (!isset($equal_encodings[$encoding1][$encoding2][$strict])) {
1914
        $encoding_1 = api_refine_encoding_id($encoding1);
1915
        $encoding_2 = api_refine_encoding_id($encoding2);
1916
        if ($encoding_1 == $encoding_2) {
1917
            $result = true;
1918
        } else {
1919
            if ($strict) {
1920
                $result = false;
1921
            } else {
1922
                $alias1 = _api_get_character_map_name($encoding_1);
1923
                $alias2 = _api_get_character_map_name($encoding_2);
1924
                $result = !empty($alias1) && !empty($alias2) && $alias1 == $alias2;
1925
            }
1926
        }
1927
        $equal_encodings[$encoding1][$encoding2][$strict] = $result;
1928
    }
1929
1930
    return $equal_encodings[$encoding1][$encoding2][$strict];
1931
}
1932
1933
/**
1934
 * This function checks whether a given encoding is UTF-8.
1935
 *
1936
 * @param string $encoding the tested encoding
1937
 *
1938
 * @return bool returns TRUE if the given encoding id means UTF-8, otherwise returns false
1939
 */
1940
function api_is_utf8($encoding)
1941
{
1942
    static $result = [];
1943
    if (!isset($result[$encoding])) {
1944
        $result[$encoding] = api_equal_encodings($encoding, 'UTF-8');
1945
    }
1946
1947
    return $result[$encoding];
1948
}
1949
1950
/**
1951
 * This function returns the encoding, currently used by the system.
1952
 *
1953
 * @return string The system's encoding.
1954
 *                Note: The value of api_get_setting('platform_charset') is tried to be returned first,
1955
 *                on the second place the global variable $charset is tried to be returned. If for some
1956
 *                reason both attempts fail, then the libraly's internal value will be returned.
1957
 */
1958
function api_get_system_encoding()
1959
{
1960
    return 'UTF-8';
1961
}
1962
1963
/**
1964
 * Checks whether a specified encoding is supported by this API.
1965
 *
1966
 * @param string $encoding the specified encoding
1967
 *
1968
 * @return bool returns TRUE when the specified encoding is supported, FALSE othewise
1969
 */
1970
function api_is_encoding_supported($encoding)
1971
{
1972
    static $supported = [];
1973
    if (!isset($supported[$encoding])) {
1974
        $supported[$encoding] = _api_mb_supports($encoding) || _api_iconv_supports($encoding) || _api_convert_encoding_supports($encoding);
1975
    }
1976
1977
    return $supported[$encoding];
1978
}
1979
1980
/**
1981
 * Detects encoding of plain text.
1982
 *
1983
 * @param string $string   the input text
1984
 * @param string $language (optional) The language of the input text, provided if it is known
1985
 *
1986
 * @return string returns the detected encoding
1987
 */
1988
function api_detect_encoding($string, $language = null)
1989
{
1990
    // Testing against valid UTF-8 first.
1991
    if (api_is_valid_utf8($string)) {
1992
        return 'UTF-8';
1993
    }
1994
1995
    return mb_detect_encoding($string);
1996
}
1997
1998
/**
1999
 * String validation functions concerning certain encodings.
2000
 */
2001
2002
/**
2003
 * Checks a string for UTF-8 validity.
2004
 *
2005
 * @param string $string
2006
 *
2007
 * @return string
2008
 */
2009
function api_is_valid_utf8($string)
2010
{
2011
    return Utf8::isUtf8($string);
2012
}
2013
2014
/**
2015
 * Checks whether a string contains 7-bit ASCII characters only.
2016
 *
2017
 * @param string $string the string to be tested/validated
2018
 *
2019
 * @return bool returns TRUE when the tested string contains 7-bit
2020
 *              ASCII characters only, FALSE othewise
2021
 */
2022
function api_is_valid_ascii(&$string)
2023
{
2024
    return mb_detect_encoding($string, 'ASCII', true) == 'ASCII' ? true : false;
2025
}
2026
2027
/**
2028
 * Return true a date is valid.
2029
 *
2030
 * @param string $date   example: 2014-06-30 13:05:05
2031
 * @param string $format example: "Y-m-d H:i:s"
2032
 *
2033
 * @return bool
2034
 */
2035
function api_is_valid_date($date, $format = 'Y-m-d H:i:s')
2036
{
2037
    $d = DateTime::createFromFormat($format, $date);
2038
2039
    return $d && $d->format($format) == $date;
2040
}
2041
2042
/**
2043
 * Returns the variable translated.
2044
 *
2045
 * @param string $variable   the string to translate
2046
 * @param string $pluginName the Plugin name
2047
 *
2048
 * @return string the variable translated
2049
 */
2050
function get_plugin_lang($variable, $pluginName)
2051
{
2052
    $plugin = $pluginName::create();
2053
2054
    return $plugin->get_lang($variable);
2055
}
2056
2057
/**
2058
 * Returns an array of translated week days and months, short and normal names.
2059
 *
2060
 * @param string $language (optional Language id. If it is omitted,
2061
 *                         the current interface language is assumed.
2062
 *
2063
 * @return array returns a multidimensional array with translated week days and months
2064
 */
2065
function &_api_get_day_month_names($language = null)
2066
{
2067
    static $date_parts = [];
2068
    if (empty($language)) {
2069
        $language = api_get_interface_language();
2070
    }
2071
    if (!isset($date_parts[$language])) {
2072
        $week_day = [
2073
            'Sunday',
2074
            'Monday',
2075
            'Tuesday',
2076
            'Wednesday',
2077
            'Thursday',
2078
            'Friday',
2079
            'Saturday',
2080
        ];
2081
        $month = [
2082
            'January',
2083
            'February',
2084
            'March',
2085
            'April',
2086
            'May',
2087
            'June',
2088
            'July',
2089
            'August',
2090
            'September',
2091
            'October',
2092
            'November',
2093
            'December',
2094
        ];
2095
        for ($i = 0; $i < 7; $i++) {
2096
            $date_parts[$language]['days_short'][] = get_lang(
2097
                $week_day[$i].'Short',
2098
                '',
2099
                $language
2100
            );
2101
            $date_parts[$language]['days_long'][] = get_lang(
2102
                $week_day[$i].'Long',
2103
                '',
2104
                $language
2105
            );
2106
        }
2107
        for ($i = 0; $i < 12; $i++) {
2108
            $date_parts[$language]['months_short'][] = get_lang(
2109
                $month[$i].'Short',
2110
                '',
2111
                $language
2112
            );
2113
            $date_parts[$language]['months_long'][] = get_lang(
2114
                $month[$i].'Long',
2115
                '',
2116
                $language
2117
            );
2118
        }
2119
    }
2120
2121
    return $date_parts[$language];
2122
}
2123
2124
/**
2125
 * Returns returns person name convention for a given language.
2126
 *
2127
 * @param string $language the input language
2128
 * @param string $type     The type of the requested convention.
2129
 *                         It may be 'format' for name order convention or 'sort_by' for name sorting convention.
2130
 *
2131
 * @return mixed Depending of the requested type,
2132
 *               the returned result may be string or boolean; null is returned on error;
2133
 */
2134
function _api_get_person_name_convention($language, $type)
2135
{
2136
    static $conventions;
2137
    $language = api_purify_language_id($language);
2138
    if (!isset($conventions)) {
2139
        $file = __DIR__.'/internationalization_database/name_order_conventions.php';
2140
        if (file_exists($file)) {
2141
            $conventions = include $file;
2142
        } else {
2143
            $conventions = [
2144
                'english' => [
2145
                    'format' => 'title first_name last_name',
2146
                    'sort_by' => 'first_name',
2147
                ],
2148
            ];
2149
        }
2150
        // Overwrite classic conventions
2151
        $customConventions = api_get_configuration_value('name_order_conventions');
2152
2153
        if (!empty($customConventions)) {
2154
            foreach ($customConventions as $key => $data) {
2155
                $conventions[$key] = $data;
2156
            }
2157
        }
2158
2159
        $search1 = ['FIRST_NAME', 'LAST_NAME', 'TITLE'];
2160
        $replacement1 = ['%F', '%L', '%T'];
2161
        $search2 = ['first_name', 'last_name', 'title'];
2162
        $replacement2 = ['%f', '%l', '%t'];
2163
        foreach (array_keys($conventions) as $key) {
2164
            $conventions[$key]['format'] = str_replace($search1, $replacement1, $conventions[$key]['format']);
2165
            $conventions[$key]['format'] = _api_validate_person_name_format(
2166
                _api_clean_person_name(
2167
                    str_replace(
2168
                        '%',
2169
                        ' %',
2170
                        str_ireplace(
2171
                            $search2,
2172
                            $replacement2,
2173
                            $conventions[$key]['format']
2174
                        )
2175
                    )
2176
                )
2177
            );
2178
            $conventions[$key]['sort_by'] = strtolower($conventions[$key]['sort_by']) != 'last_name' ? true : false;
2179
        }
2180
    }
2181
    switch ($type) {
2182
        case 'format':
2183
            return is_string($conventions[$language]['format']) ? $conventions[$language]['format'] : '%t %f %l';
2184
        case 'sort_by':
2185
            return is_bool($conventions[$language]['sort_by']) ? $conventions[$language]['sort_by'] : true;
2186
    }
2187
2188
    return null;
2189
}
2190
2191
/**
2192
 * Replaces non-valid formats for person names with the default (English) format.
2193
 *
2194
 * @param string $format the input format to be verified
2195
 *
2196
 * @return bool returns the same format if is is valid, otherwise returns a valid English format
2197
 */
2198
function _api_validate_person_name_format($format)
2199
{
2200
    if (empty($format) || stripos($format, '%f') === false || stripos($format, '%l') === false) {
2201
        return '%t %f %l';
2202
    }
2203
2204
    return $format;
2205
}
2206
2207
/**
2208
 * Removes leading, trailing and duplicate whitespace and/or commas in a full person name.
2209
 * Cleaning is needed for the cases when not all parts of the name are available
2210
 * or when the name is constructed using a "dirty" pattern.
2211
 *
2212
 * @param string $person_name the input person name
2213
 *
2214
 * @return string returns cleaned person name
2215
 */
2216
function _api_clean_person_name($person_name)
2217
{
2218
    return preg_replace(['/\s+/', '/, ,/', '/,+/', '/^[ ,]/', '/[ ,]$/'], [' ', ', ', ',', '', ''], $person_name);
2219
}
2220
2221
/**
2222
 * Appendix to "Multibyte string conversion functions".
2223
 */
2224
2225
/**
2226
 * This is a php-implementation of a function that is similar to mb_convert_encoding() from mbstring extension.
2227
 * The function converts a given string from one to another character encoding.
2228
 *
2229
 * @param string $string        the string being converted
2230
 * @param string $to_encoding   the encoding that $string is being converted to
2231
 * @param string $from_encoding the encoding that $string is being converted from
2232
 *
2233
 * @return string returns the converted string
2234
 */
2235
function _api_convert_encoding(&$string, $to_encoding, $from_encoding)
2236
{
2237
    return mb_convert_encoding($string, $to_encoding, $from_encoding);
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_convert_encodi...coding, $from_encoding) also could return the type array which is incompatible with the documented return type string.
Loading history...
2238
}
2239
2240
/**
2241
 * This function determines the name of corresponding to a given encoding conversion table.
2242
 * It is able to deal with some aliases of the encoding.
2243
 *
2244
 * @param string $encoding the given encoding identificator, for example 'WINDOWS-1252'
2245
 *
2246
 * @return string returns the name of the corresponding conversion table, for the same example - 'CP1252'
2247
 */
2248
function _api_get_character_map_name($encoding)
2249
{
2250
    static $character_map_selector;
2251
    if (!isset($character_map_selector)) {
2252
        $file = __DIR__.'/internationalization_database/conversion/character_map_selector.php';
2253
        if (file_exists($file)) {
2254
            $character_map_selector = include $file;
2255
        } else {
2256
            $character_map_selector = [];
2257
        }
2258
    }
2259
2260
    return isset($character_map_selector[$encoding]) ? $character_map_selector[$encoding] : '';
2261
}
2262
2263
/**
2264
 * Appendix to "String comparison".
2265
 */
2266
2267
/**
2268
 * A reverse function from php-core function strnatcmp(),
2269
 * performs string comparison in reverse natural (alpha-numerical) order.
2270
 *
2271
 * @param string $string1 the first string
2272
 * @param string $string2 the second string
2273
 *
2274
 * @return int returns 0 if $string1 = $string2; >0 if $string1 < $string2; <0 if $string1 > $string2
2275
 */
2276
function _api_strnatrcmp($string1, $string2)
2277
{
2278
    return strnatcmp($string2, $string1);
2279
}
2280
2281
/**
2282
 * Sets/Gets internal character encoding of the common string functions within the PHP mbstring extension.
2283
 *
2284
 * @param string $encoding (optional)    When this parameter is given, the function sets the internal encoding
2285
 *
2286
 * @return string When $encoding parameter is not given, the function returns the internal encoding.
2287
 *                Note: This function is used in the global initialization script for setting the
2288
 *                internal encoding to the platform's character set.
2289
 *
2290
 * @see http://php.net/manual/en/function.mb-internal-encoding
2291
 */
2292
function _api_mb_internal_encoding($encoding = 'UTF-8')
2293
{
2294
    return mb_internal_encoding($encoding);
0 ignored issues
show
Bug Best Practice introduced by
The expression return mb_internal_encoding($encoding) also could return the type true which is incompatible with the documented return type string.
Loading history...
2295
}
2296
2297
/**
2298
 * Checks whether the specified encoding is supported by the PHP mbstring extension.
2299
 *
2300
 * @param string $encoding the specified encoding
2301
 *
2302
 * @return bool returns TRUE when the specified encoding is supported, FALSE othewise
2303
 */
2304
function _api_mb_supports($encoding)
2305
{
2306
    static $supported = [];
2307
    if (!isset($supported[$encoding])) {
2308
        if (MBSTRING_INSTALLED) {
2309
            $supported[$encoding] = api_equal_encodings($encoding, mb_list_encodings(), true);
2310
        } else {
2311
            $supported[$encoding] = false;
2312
        }
2313
    }
2314
2315
    return $supported[$encoding];
2316
}
2317
2318
/**
2319
 * Checks whether the specified encoding is supported by the PHP iconv extension.
2320
 *
2321
 * @param string $encoding the specified encoding
2322
 *
2323
 * @return bool returns TRUE when the specified encoding is supported, FALSE othewise
2324
 */
2325
function _api_iconv_supports($encoding)
2326
{
2327
    static $supported = [];
2328
    if (!isset($supported[$encoding])) {
2329
        if (ICONV_INSTALLED) {
2330
            $enc = api_refine_encoding_id($encoding);
2331
            if ($enc != 'HTML-ENTITIES') {
2332
                $test_string = '';
2333
                for ($i = 32; $i < 128; $i++) {
2334
                    $test_string .= chr($i);
2335
                }
2336
                $supported[$encoding] = (@iconv_strlen($test_string, $enc)) ? true : false;
2337
            } else {
2338
                $supported[$encoding] = false;
2339
            }
2340
        } else {
2341
            $supported[$encoding] = false;
2342
        }
2343
    }
2344
2345
    return $supported[$encoding];
2346
}
2347
2348
// This function checks whether the function _api_convert_encoding() (the php-
2349
// implementation) is able to convert from/to a given encoding.
2350
function _api_convert_encoding_supports($encoding)
2351
{
2352
    static $supports = [];
2353
    if (!isset($supports[$encoding])) {
2354
        $supports[$encoding] = _api_get_character_map_name(api_refine_encoding_id($encoding)) != '';
2355
    }
2356
2357
    return $supports[$encoding];
2358
}
2359
2360
/**
2361
 * Given a date object, return a human or ISO format, with or without h:m:s.
2362
 *
2363
 * @param object $date      The Date object
2364
 * @param bool   $showTime  Whether to show the time and date (true) or only the date (false)
2365
 * @param bool   $humanForm Whether to show day-month-year (true) or year-month-day (false)
2366
 *
2367
 * @return string Formatted date
2368
 */
2369
function api_get_human_date_time($date, $showTime = true, $humanForm = false)
2370
{
2371
    if ($showTime) {
2372
        if ($humanForm) {
2373
            return $date->format('j M Y H:i:s');
2374
        } else {
2375
            return $date->format('Y-m-d H:i:s');
2376
        }
2377
    } else {
2378
        if ($humanForm) {
2379
            return $date->format('j M Y');
2380
        } else {
2381
            return $date->format('Y-m-d');
2382
        }
2383
    }
2384
}
2385
2386
/**
2387
 * @param string $language
2388
 *
2389
 * @return array
2390
 */
2391
function api_get_language_files_to_load($language)
2392
{
2393
    $parent_path = SubLanguageManager::get_parent_language_path($language);
2394
    $langPath = api_get_path(SYS_LANG_PATH);
2395
2396
    $languagesToLoad = [
2397
        $langPath.'english/trad4all.inc.php', // include English always
2398
    ];
2399
2400
    if (!empty($parent_path)) { // if the sub-language feature is on
2401
        // prepare string for current language and its parent
2402
        $lang_file = $langPath.$language.'/trad4all.inc.php';
2403
        $parent_lang_file = $langPath.$parent_path.'/trad4all.inc.php';
2404
        // load the parent language file first
2405
        if (file_exists($parent_lang_file)) {
2406
            $languagesToLoad[] = $parent_lang_file;
2407
        }
2408
        // overwrite the parent language translations if there is a child
2409
        if (file_exists($lang_file)) {
2410
            $languagesToLoad[] = $lang_file;
2411
        }
2412
    } else {
2413
        // if the sub-languages feature is not on, then just load the
2414
        // set language interface
2415
        // prepare string for current language
2416
        $langFile = $langPath.$language.'/trad4all.inc.php';
2417
2418
        if (file_exists($langFile)) {
2419
            $languagesToLoad[] = $langFile;
2420
        }
2421
2422
        // Check if language/custom.php exists
2423
        $customLanguage = $langPath.$language.'/custom.php';
2424
2425
        if (file_exists($customLanguage)) {
2426
            $languagesToLoad[] = $customLanguage;
2427
        }
2428
    }
2429
2430
    return $languagesToLoad;
2431
}
2432