Passed
Push — master ( bb15d1...ce9f14 )
by Julito
09:50
created

getLegacyOrderConventions()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 81
Code Lines 79

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 79
c 0
b 0
f 0
nc 1
nop 0
dl 0
loc 81
rs 8.4581

How to fix   Long Method   

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