Proyectos de Subversion Moodle

Rev

Rev 1361 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 1361 Rev 1441
Línea 378... Línea 378...
378
/** Get remote addr constant */
378
/** Get remote addr constant */
379
define('GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR', '2');
379
define('GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR', '2');
380
/**
380
/**
381
 * GETREMOTEADDR_SKIP_DEFAULT defines the default behavior remote IP address validation.
381
 * GETREMOTEADDR_SKIP_DEFAULT defines the default behavior remote IP address validation.
382
 */
382
 */
383
define('GETREMOTEADDR_SKIP_DEFAULT', GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR | GETREMOTEADDR_SKIP_HTTP_CLIENT_IP);
383
define('GETREMOTEADDR_SKIP_DEFAULT', GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR|GETREMOTEADDR_SKIP_HTTP_CLIENT_IP);
Línea 384... Línea 384...
384
 
384
 
385
// Blog access level constant declaration.
385
// Blog access level constant declaration.
386
define('BLOG_USER_LEVEL', 1);
386
define ('BLOG_USER_LEVEL', 1);
387
define('BLOG_GROUP_LEVEL', 2);
387
define ('BLOG_GROUP_LEVEL', 2);
388
define('BLOG_COURSE_LEVEL', 3);
388
define ('BLOG_COURSE_LEVEL', 3);
389
define('BLOG_SITE_LEVEL', 4);
389
define ('BLOG_SITE_LEVEL', 4);
Línea 390... Línea -...
390
define('BLOG_GLOBAL_LEVEL', 5);
-
 
391
 
390
define ('BLOG_GLOBAL_LEVEL', 5);
392
 
-
 
393
// Tag constants.
-
 
394
/**
-
 
395
 * To prevent problems with multibytes strings,Flag updating in nav not working on the review page. this should not exceed the
-
 
396
 * length of "varchar(255) / 3 (bytes / utf-8 character) = 85".
-
 
397
 * TODO: this is not correct, varchar(255) are 255 unicode chars ;-)
-
 
398
 *
-
 
399
 * @todo define(TAG_MAX_LENGTH) this is not correct, varchar(255) are 255 unicode chars ;-)
391
 
Línea 400... Línea 392...
400
 */
392
/** The maximum length of a tag */
401
define('TAG_MAX_LENGTH', 50);
393
define('TAG_MAX_LENGTH', 255);
402
 
394
 
403
// Password policy constants.
395
// Password policy constants.
404
define('PASSWORD_LOWER', 'abcdefghijklmnopqrstuvwxyz');
396
define ('PASSWORD_LOWER', 'abcdefghijklmnopqrstuvwxyz');
Línea 405... Línea 397...
405
define('PASSWORD_UPPER', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
397
define ('PASSWORD_UPPER', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
406
define('PASSWORD_DIGITS', '0123456789');
398
define ('PASSWORD_DIGITS', '0123456789');
407
define('PASSWORD_NONALPHANUM', '.,;:!?_-+/*@#&$');
399
define ('PASSWORD_NONALPHANUM', '.,;:!?_-+/*@#&$');
408
 
400
 
Línea 409... Línea 401...
409
/**
401
/**
410
 * Required password pepper entropy.
402
 * Required password pepper entropy.
Línea 411... Línea 403...
411
 */
403
 */
412
define('PEPPER_ENTROPY', 112);
404
define ('PEPPER_ENTROPY', 112);
-
 
405
 
-
 
406
// Feature constants.
413
 
407
// Used for plugin_supports() to report features that are, or are not, supported by a module.
414
// Feature constants.
408
 
415
// Used for plugin_supports() to report features that are, or are not, supported by a module.
409
/** True if module can provide a grade */
416
 
410
define('FEATURE_GRADE_HAS_GRADE', 'grade_has_grade');
417
/** True if module can provide a grade */
411
/** True if module can support grade penalty */
418
define('FEATURE_GRADE_HAS_GRADE', 'grade_has_grade');
412
define('FEATURE_GRADE_HAS_PENALTY', 'grade_has_penalty');
419
/** True if module supports outcomes */
413
/** True if module supports outcomes */
420
define('FEATURE_GRADE_OUTCOMES', 'outcomes');
414
define('FEATURE_GRADE_OUTCOMES', 'outcomes');
Línea -... Línea 415...
-
 
415
/** True if module supports advanced grading methods */
-
 
416
define('FEATURE_ADVANCED_GRADING', 'grade_advanced_grading');
421
/** True if module supports advanced grading methods */
417
/** True if module controls the grade visibility over the gradebook */
422
define('FEATURE_ADVANCED_GRADING', 'grade_advanced_grading');
418
define('FEATURE_CONTROLS_GRADE_VISIBILITY', 'controlsgradevisbility');
423
/** True if module controls the grade visibility over the gradebook */
419
/** True if module supports plagiarism plugins */
424
define('FEATURE_CONTROLS_GRADE_VISIBILITY', 'controlsgradevisbility');
420
define('FEATURE_PLAGIARISM', 'plagiarism');
Línea 455... Línea 451...
455
 
451
 
456
define('FEATURE_RATE', 'rate');
452
define('FEATURE_RATE', 'rate');
457
/** True if module supports backup/restore of moodle2 format */
453
/** True if module supports backup/restore of moodle2 format */
Línea -... Línea 454...
-
 
454
define('FEATURE_BACKUP_MOODLE2', 'backup_moodle2');
-
 
455
 
-
 
456
/** True if module shares questions with other modules. */
-
 
457
define('FEATURE_PUBLISHES_QUESTIONS', 'publishesquestions');
-
 
458
 
-
 
459
/** Used by {@see course_modinfo::is_mod_type_visible_on_course()} to determine if a plugin should render to display */
-
 
460
define('FEATURE_CAN_DISPLAY', 'candisplay');
-
 
461
 
-
 
462
/** Can this module type be uninstalled */
458
define('FEATURE_BACKUP_MOODLE2', 'backup_moodle2');
463
define('FEATURE_CAN_UNINSTALL', 'canuninstall');
459
 
464
 
Línea 460... Línea 465...
460
/** True if module can show description on course main page */
465
/** True if module can show description on course main page */
461
define('FEATURE_SHOW_DESCRIPTION', 'showdescription');
466
define('FEATURE_SHOW_DESCRIPTION', 'showdescription');
Línea 495... Línea 500...
495
define('MOD_PURPOSE_OTHER', 'other');
500
define('MOD_PURPOSE_OTHER', 'other');
496
/**
501
/**
497
 * Module purpose interface
502
 * Module purpose interface
498
 * @deprecated since Moodle 4.4
503
 * @deprecated since Moodle 4.4
499
 * @todo MDL-80701 Remove in Moodle 4.8
504
 * @todo MDL-80701 Remove in Moodle 4.8
500
 */
505
*/
501
define('MOD_PURPOSE_INTERFACE', 'interface');
506
define('MOD_PURPOSE_INTERFACE', 'interface');
Línea -... Línea 507...
-
 
507
 
-
 
508
/** True if module can be quickly created without filling a previous form. */
502
 
509
define('FEATURE_QUICKCREATE', 'quickcreate');
503
/**
510
/**
504
 * Security token used for allowing access
511
 * Security token used for allowing access
505
 * from external application such as web services.
512
 * from external application such as web services.
506
 * Scripts do not use any session, performance is relatively
513
 * Scripts do not use any session, performance is relatively
Línea 531... Línea 538...
531
define('HOMEPAGE_USER', 2);
538
define('HOMEPAGE_USER', 2);
532
/**
539
/**
533
 * The home page should be the users my courses page
540
 * The home page should be the users my courses page
534
 */
541
 */
535
define('HOMEPAGE_MYCOURSES', 3);
542
define('HOMEPAGE_MYCOURSES', 3);
-
 
543
/**
-
 
544
 * The home page is defined as a URL
-
 
545
 */
-
 
546
define('HOMEPAGE_URL', 4);
Línea 536... Línea 547...
536
 
547
 
537
/**
548
/**
538
 * URL of the Moodle sites registration portal.
549
 * URL of the Moodle sites registration portal.
539
 */
550
 */
Línea 640... Línea 651...
640
 * @param string $parname the name of the page parameter we want
651
 * @param string $parname the name of the page parameter we want
641
 * @param string $type expected type of parameter
652
 * @param string $type expected type of parameter
642
 * @return mixed
653
 * @return mixed
643
 * @throws coding_exception
654
 * @throws coding_exception
644
 */
655
 */
645
function required_param($parname, $type)
656
function required_param($parname, $type) {
646
{
-
 
647
    return \core\param::from_type($type)->required_param($parname);
657
    return \core\param::from_type($type)->required_param($parname);
648
}
658
}
Línea 649... Línea 659...
649
 
659
 
650
/**
660
/**
Línea 662... Línea 672...
662
 * @param string $parname the name of the page parameter we want
672
 * @param string $parname the name of the page parameter we want
663
 * @param string $type expected type of parameter
673
 * @param string $type expected type of parameter
664
 * @return array
674
 * @return array
665
 * @throws coding_exception
675
 * @throws coding_exception
666
 */
676
 */
667
function required_param_array($parname, $type)
677
function required_param_array($parname, $type) {
668
{
-
 
669
    return \core\param::from_type($type)->required_param_array($parname);
678
    return \core\param::from_type($type)->required_param_array($parname);
670
}
679
}
Línea 671... Línea 680...
671
 
680
 
672
/**
681
/**
Línea 684... Línea 693...
684
 * @param mixed  $default the default value to return if nothing is found
693
 * @param mixed  $default the default value to return if nothing is found
685
 * @param string $type expected type of parameter
694
 * @param string $type expected type of parameter
686
 * @return mixed
695
 * @return mixed
687
 * @throws coding_exception
696
 * @throws coding_exception
688
 */
697
 */
689
function optional_param($parname, $default, $type)
698
function optional_param($parname, $default, $type) {
690
{
-
 
691
    return \core\param::from_type($type)->optional_param(
699
    return \core\param::from_type($type)->optional_param(
692
        paramname: $parname,
700
        paramname: $parname,
693
        default: $default,
701
        default: $default,
694
    );
702
    );
695
}
703
}
Línea 709... Línea 717...
709
 * @param mixed $default the default value to return if nothing is found
717
 * @param mixed $default the default value to return if nothing is found
710
 * @param string $type expected type of parameter
718
 * @param string $type expected type of parameter
711
 * @return array
719
 * @return array
712
 * @throws coding_exception
720
 * @throws coding_exception
713
 */
721
 */
714
function optional_param_array($parname, $default, $type)
722
function optional_param_array($parname, $default, $type) {
715
{
-
 
716
    return \core\param::from_type($type)->optional_param_array(
723
    return \core\param::from_type($type)->optional_param_array(
717
        paramname: $parname,
724
        paramname: $parname,
718
        default: $default,
725
        default: $default,
719
    );
726
    );
720
}
727
}
Línea 731... Línea 738...
731
 * @param bool $allownull are nulls valid value?
738
 * @param bool $allownull are nulls valid value?
732
 * @param string $debuginfo optional debug information
739
 * @param string $debuginfo optional debug information
733
 * @return mixed the $param value converted to PHP type
740
 * @return mixed the $param value converted to PHP type
734
 * @throws invalid_parameter_exception if $param is not of given type
741
 * @throws invalid_parameter_exception if $param is not of given type
735
 */
742
 */
736
function validate_param($param, $type, $allownull = NULL_NOT_ALLOWED, $debuginfo = '')
743
function validate_param($param, $type, $allownull = NULL_NOT_ALLOWED, $debuginfo = '') {
737
{
-
 
738
    return \core\param::from_type($type)->validate_param(
744
    return \core\param::from_type($type)->validate_param(
739
        param: $param,
745
        param: $param,
740
        allownull: $allownull,
746
        allownull: $allownull,
741
        debuginfo: $debuginfo,
747
        debuginfo: $debuginfo,
742
    );
748
    );
Línea 753... Línea 759...
753
 * @param string $type expected format of param after cleaning.
759
 * @param string $type expected format of param after cleaning.
754
 * @param bool $recursive clean recursive arrays
760
 * @param bool $recursive clean recursive arrays
755
 * @return array
761
 * @return array
756
 * @throws coding_exception
762
 * @throws coding_exception
757
 */
763
 */
758
function clean_param_array(?array $param, $type, $recursive = false)
764
function clean_param_array(?array $param, $type, $recursive = false) {
759
{
-
 
760
    return \core\param::from_type($type)->clean_param_array(
765
    return \core\param::from_type($type)->clean_param_array(
761
        param: $param,
766
        param: $param,
762
        recursive: $recursive,
767
        recursive: $recursive,
763
    );
768
    );
764
}
769
}
Línea 775... Línea 780...
775
 * @param mixed $param the variable we are cleaning
780
 * @param mixed $param the variable we are cleaning
776
 * @param string $type expected format of param after cleaning.
781
 * @param string $type expected format of param after cleaning.
777
 * @return mixed
782
 * @return mixed
778
 * @throws coding_exception
783
 * @throws coding_exception
779
 */
784
 */
780
function clean_param($param, $type)
785
function clean_param($param, $type) {
781
{
-
 
782
    return \core\param::from_type($type)->clean($param);
786
    return \core\param::from_type($type)->clean($param);
783
}
787
}
Línea 784... Línea 788...
784
 
788
 
785
/**
789
/**
Línea 795... Línea 799...
795
 * This function tries to best guess which parameters can contain localised strings.
799
 * This function tries to best guess which parameters can contain localised strings.
796
 *
800
 *
797
 * @param string $paramtype Constant PARAM_*.
801
 * @param string $paramtype Constant PARAM_*.
798
 * @return bool
802
 * @return bool
799
 */
803
 */
800
function is_rtl_compatible($paramtype)
804
function is_rtl_compatible($paramtype) {
801
{
-
 
802
    return $paramtype == PARAM_TEXT || $paramtype == PARAM_NOTAGS;
805
    return $paramtype == PARAM_TEXT || $paramtype == PARAM_NOTAGS;
803
}
806
}
Línea 804... Línea 807...
804
 
807
 
805
/**
808
/**
Línea 808... Línea 811...
808
 * Note: this function is not intended for full objects with methods and private properties.
811
 * Note: this function is not intended for full objects with methods and private properties.
809
 *
812
 *
810
 * @param mixed $value
813
 * @param mixed $value
811
 * @return mixed with proper utf-8 encoding
814
 * @return mixed with proper utf-8 encoding
812
 */
815
 */
813
function fix_utf8($value)
816
function fix_utf8($value) {
814
{
-
 
815
    if (is_null($value) or $value === '') {
817
    if (is_null($value) or $value === '') {
816
        return $value;
818
        return $value;
-
 
819
 
817
    } else if (is_string($value)) {
820
    } else if (is_string($value)) {
818
        if ((string)(int)$value === $value) {
821
        if ((string)(int)$value === $value) {
819
            // Shortcut.
822
            // Shortcut.
820
            return $value;
823
            return $value;
821
        }
824
        }
Línea 824... Línea 827...
824
        $value = str_replace(["\0", "\xef\xbf\xbe", "\xef\xbf\xbf"], '', $value);
827
        $value = str_replace(["\0", "\xef\xbf\xbe", "\xef\xbf\xbf"], '', $value);
Línea 825... Línea 828...
825
 
828
 
826
        // Note: this duplicates min_fix_utf8() intentionally.
829
        // Note: this duplicates min_fix_utf8() intentionally.
827
        static $buggyiconv = null;
830
        static $buggyiconv = null;
828
        if ($buggyiconv === null) {
831
        if ($buggyiconv === null) {
829
            $buggyiconv = (!function_exists('iconv') or @iconv('UTF-8', 'UTF-8//IGNORE', '100' . chr(130) . '€') !== '100€');
832
            $buggyiconv = (!function_exists('iconv') or @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
Línea 830... Línea 833...
830
        }
833
        }
831
 
834
 
832
        if ($buggyiconv) {
835
        if ($buggyiconv) {
833
            if (function_exists('mb_convert_encoding')) {
836
            if (function_exists('mb_convert_encoding')) {
834
                $subst = mb_substitute_character();
837
                $subst = mb_substitute_character();
835
                mb_substitute_character('none');
838
                mb_substitute_character('none');
-
 
839
                $result = mb_convert_encoding($value, 'utf-8', 'utf-8');
836
                $result = mb_convert_encoding($value, 'utf-8', 'utf-8');
840
                mb_substitute_character($subst);
837
                mb_substitute_character($subst);
841
 
838
            } else {
842
            } else {
839
                // Warn admins on admin/index.php page.
843
                // Warn admins on admin/index.php page.
-
 
844
                $result = $value;
840
                $result = $value;
845
            }
841
            }
846
 
842
        } else {
847
        } else {
Línea 843... Línea 848...
843
            $result = @iconv('UTF-8', 'UTF-8//IGNORE', $value);
848
            $result = @iconv('UTF-8', 'UTF-8//IGNORE', $value);
-
 
849
        }
844
        }
850
 
845
 
851
        return $result;
846
        return $result;
852
 
847
    } else if (is_array($value)) {
853
    } else if (is_array($value)) {
848
        foreach ($value as $k => $v) {
854
        foreach ($value as $k => $v) {
-
 
855
            $value[$k] = fix_utf8($v);
849
            $value[$k] = fix_utf8($v);
856
        }
850
        }
857
        return $value;
851
        return $value;
858
 
852
    } else if (is_object($value)) {
859
    } else if (is_object($value)) {
853
        // Do not modify original.
860
        // Do not modify original.
854
        $value = clone ($value);
861
        $value = clone($value);
855
        foreach ($value as $k => $v) {
862
        foreach ($value as $k => $v) {
-
 
863
            $value->$k = fix_utf8($v);
856
            $value->$k = fix_utf8($v);
864
        }
857
        }
865
        return $value;
858
        return $value;
866
 
859
    } else {
867
    } else {
860
        // This is some other type, no utf-8 here.
868
        // This is some other type, no utf-8 here.
Línea 866... Línea 874...
866
 * Return true if given value is integer or string with integer value
874
 * Return true if given value is integer or string with integer value
867
 *
875
 *
868
 * @param mixed $value String or Int
876
 * @param mixed $value String or Int
869
 * @return bool true if number, false if not
877
 * @return bool true if number, false if not
870
 */
878
 */
871
function is_number($value)
879
function is_number($value) {
872
{
-
 
873
    if (is_int($value)) {
880
    if (is_int($value)) {
874
        return true;
881
        return true;
875
    } else if (is_string($value)) {
882
    } else if (is_string($value)) {
876
        return ((string)(int)$value) === $value;
883
        return ((string)(int)$value) === $value;
877
    } else {
884
    } else {
Línea 883... Línea 890...
883
 * Returns host part from url.
890
 * Returns host part from url.
884
 *
891
 *
885
 * @param string $url full url
892
 * @param string $url full url
886
 * @return string host, null if not found
893
 * @return string host, null if not found
887
 */
894
 */
888
function get_host_from_url($url)
895
function get_host_from_url($url) {
889
{
-
 
890
    preg_match('|^[a-z]+://([a-zA-Z0-9-.]+)|i', $url, $matches);
896
    preg_match('|^[a-z]+://([a-zA-Z0-9-.]+)|i', $url, $matches);
891
    if ($matches) {
897
    if ($matches) {
892
        return $matches[1];
898
        return $matches[1];
893
    }
899
    }
894
    return null;
900
    return null;
Línea 903... Línea 909...
903
 *
909
 *
904
 * @param string $string a string containing HTML.
910
 * @param string $string a string containing HTML.
905
 * @return boolean does the string contain any actual content - that is text,
911
 * @return boolean does the string contain any actual content - that is text,
906
 * images, objects, etc.
912
 * images, objects, etc.
907
 */
913
 */
908
function html_is_blank($string)
914
function html_is_blank($string) {
909
{
-
 
910
    return trim(strip_tags((string)$string, '<img><object><applet><input><select><textarea><hr>')) == '';
915
    return trim(strip_tags((string)$string, '<img><object><applet><input><select><textarea><hr>')) == '';
911
}
916
}
Línea 912... Línea 917...
912
 
917
 
913
/**
918
/**
Línea 925... Línea 930...
925
 *
930
 *
926
 * @param string $name the key to set
931
 * @param string $name the key to set
927
 * @param string|int|bool|null $value the value to set (without magic quotes),
932
 * @param string|int|bool|null $value the value to set (without magic quotes),
928
 *               null to unset the value
933
 *               null to unset the value
929
 * @param string $plugin (optional) the plugin scope, default null
934
 * @param string $plugin (optional) the plugin scope, default null
-
 
935
 * @param boolean $log (optional) should this emit to the config log
930
 * @return bool true or exception
936
 * @return bool true or exception
931
 */
937
 */
932
function set_config($name, $value, $plugin = null)
938
function set_config($name, $value, $plugin = null, bool $log = false) {
933
{
-
 
934
    global $CFG, $DB;
939
    global $CFG, $DB;
Línea 935... Línea 940...
935
 
940
 
936
    // Redirect to appropriate handler when value is null.
941
    // Redirect to appropriate handler when value is null.
937
    if ($value === null) {
942
    if ($value === null) {
-
 
943
        return unset_config($name, $plugin, $log);
-
 
944
    }
-
 
945
 
-
 
946
    if ($log) {
-
 
947
        $prev = get_config($plugin, $name);
-
 
948
        if ($prev === false) {
-
 
949
            $prev = null;
-
 
950
        }
938
        return unset_config($name, $plugin);
951
        add_to_config_log($name, $prev, $value, $plugin);
Línea 939... Línea 952...
939
    }
952
    }
940
 
953
 
941
    // Set variables determining conditions and where to store the new config.
954
    // Set variables determining conditions and where to store the new config.
Línea 1011... Línea 1024...
1011
 * @param string $plugin full component name
1024
 * @param string $plugin full component name
1012
 * @param string $name default null
1025
 * @param string $name default null
1013
 * @return mixed hash-like object or single value, return false no config found
1026
 * @return mixed hash-like object or single value, return false no config found
1014
 * @throws dml_exception
1027
 * @throws dml_exception
1015
 */
1028
 */
1016
function get_config($plugin, $name = null)
1029
function get_config($plugin, $name = null) {
1017
{
-
 
1018
    global $CFG, $DB;
1030
    global $CFG, $DB;
Línea 1019... Línea 1031...
1019
 
1031
 
1020
    if ($plugin === 'moodle' || $plugin === 'core' || empty($plugin)) {
1032
    if ($plugin === 'moodle' || $plugin === 'core' || empty($plugin)) {
1021
        $forced = &$CFG->config_php_settings;
1033
        $forced =& $CFG->config_php_settings;
1022
        $iscore = true;
1034
        $iscore = true;
1023
        $plugin = 'core';
1035
        $plugin = 'core';
1024
    } else {
1036
    } else {
1025
        if (array_key_exists($plugin, $CFG->forced_plugin_settings)) {
1037
        if (array_key_exists($plugin, $CFG->forced_plugin_settings)) {
1026
            $forced = &$CFG->forced_plugin_settings[$plugin];
1038
            $forced =& $CFG->forced_plugin_settings[$plugin];
1027
        } else {
1039
        } else {
1028
            $forced = array();
1040
            $forced = array();
1029
        }
1041
        }
1030
        $iscore = false;
1042
        $iscore = false;
Línea 1092... Línea 1104...
1092
 *
1104
 *
1093
 * NOTE: this function is called from lib/db/upgrade.php
1105
 * NOTE: this function is called from lib/db/upgrade.php
1094
 *
1106
 *
1095
 * @param string $name the key to set
1107
 * @param string $name the key to set
1096
 * @param string $plugin (optional) the plugin scope
1108
 * @param string $plugin (optional) the plugin scope
-
 
1109
 * @param boolean $log (optional) should this emit to the config log
1097
 * @return boolean whether the operation succeeded.
1110
 * @return boolean whether the operation succeeded.
1098
 */
1111
 */
1099
function unset_config($name, $plugin = null)
1112
function unset_config($name, $plugin = null, bool $log = false) {
1100
{
-
 
1101
    global $CFG, $DB;
1113
    global $CFG, $DB;
Línea -... Línea 1114...
-
 
1114
 
-
 
1115
    if ($log) {
-
 
1116
        $prev = get_config($plugin, $name);
-
 
1117
        if ($prev === false) {
-
 
1118
            $prev = null;
-
 
1119
        }
-
 
1120
        add_to_config_log($name, $prev, null, $plugin);
-
 
1121
    }
1102
 
1122
 
1103
    if (empty($plugin)) {
1123
    if (empty($plugin)) {
1104
        unset($CFG->$name);
1124
        unset($CFG->$name);
1105
        $DB->delete_records('config', array('name' => $name));
1125
        $DB->delete_records('config', array('name' => $name));
1106
        cache_helper::invalidate_by_definition('core', 'config', array(), 'core');
1126
        cache_helper::invalidate_by_definition('core', 'config', array(), 'core');
Línea 1118... Línea 1138...
1118
 * NOTE: this function is called from lib/db/upgrade.php
1138
 * NOTE: this function is called from lib/db/upgrade.php
1119
 *
1139
 *
1120
 * @param string $plugin a plugin, for example 'quiz' or 'qtype_multichoice';
1140
 * @param string $plugin a plugin, for example 'quiz' or 'qtype_multichoice';
1121
 * @return boolean whether the operation succeeded.
1141
 * @return boolean whether the operation succeeded.
1122
 */
1142
 */
1123
function unset_all_config_for_plugin($plugin)
1143
function unset_all_config_for_plugin($plugin) {
1124
{
-
 
1125
    global $DB;
1144
    global $DB;
1126
    // Delete from the obvious config_plugins first.
1145
    // Delete from the obvious config_plugins first.
1127
    $DB->delete_records('config_plugins', array('plugin' => $plugin));
1146
    $DB->delete_records('config_plugins', array('plugin' => $plugin));
1128
    // Next delete any suspect settings from config.
1147
    // Next delete any suspect settings from config.
1129
    $like = $DB->sql_like('name', '?', true, true, false, '|');
1148
    $like = $DB->sql_like('name', '?', true, true, false, '|');
1130
    $params = array($DB->sql_like_escape($plugin . '_', '|') . '%');
1149
    $params = array($DB->sql_like_escape($plugin.'_', '|') . '%');
1131
    $DB->delete_records_select('config', $like, $params);
1150
    $DB->delete_records_select('config', $like, $params);
1132
    // Finally clear both the plugin cache and the core cache (suspect settings now removed from core).
1151
    // Finally clear both the plugin cache and the core cache (suspect settings now removed from core).
1133
    cache_helper::invalidate_by_definition('core', 'config', array(), array('core', $plugin));
1152
    cache_helper::invalidate_by_definition('core', 'config', array(), array('core', $plugin));
Línea 1134... Línea 1153...
1134
 
1153
 
Línea 1143... Línea 1162...
1143
 * @param string $value the value of the config setting.
1162
 * @param string $value the value of the config setting.
1144
 * @param string $capability the capability - must match the one passed to the admin_setting_users_with_capability constructor.
1163
 * @param string $capability the capability - must match the one passed to the admin_setting_users_with_capability constructor.
1145
 * @param bool $includeadmins include administrators.
1164
 * @param bool $includeadmins include administrators.
1146
 * @return array of user objects.
1165
 * @return array of user objects.
1147
 */
1166
 */
1148
function get_users_from_config($value, $capability, $includeadmins = true)
1167
function get_users_from_config($value, $capability, $includeadmins = true) {
1149
{
-
 
1150
    if (empty($value) or $value === '$@NONE@$') {
1168
    if (empty($value) or $value === '$@NONE@$') {
1151
        return array();
1169
        return array();
1152
    }
1170
    }
Línea 1153... Línea 1171...
1153
 
1171
 
Línea 1182... Línea 1200...
1182
/**
1200
/**
1183
 * Invalidates browser caches and cached data in temp.
1201
 * Invalidates browser caches and cached data in temp.
1184
 *
1202
 *
1185
 * @return void
1203
 * @return void
1186
 */
1204
 */
1187
function purge_all_caches()
1205
function purge_all_caches() {
1188
{
-
 
1189
    purge_caches();
1206
    purge_caches();
1190
}
1207
}
Línea 1191... Línea 1208...
1191
 
1208
 
1192
/**
1209
/**
Línea 1195... Línea 1212...
1195
 * Purges the cache areas specified.  By default, this will purge all caches but can selectively purge specific
1212
 * Purges the cache areas specified.  By default, this will purge all caches but can selectively purge specific
1196
 * areas alone or in combination.
1213
 * areas alone or in combination.
1197
 *
1214
 *
1198
 * @param bool[] $options Specific parts of the cache to purge. Valid options are:
1215
 * @param bool[] $options Specific parts of the cache to purge. Valid options are:
1199
 *        'muc'    Purge MUC caches?
1216
 *        'muc'    Purge MUC caches?
1200
 *        'courses' Purge all course caches, or specific course caches (CLI only)
1217
 *        'courses' Purge all course caches, or specific course caches
1201
 *        'theme'  Purge theme cache?
1218
 *        'theme'  Purge theme cache?
1202
 *        'lang'   Purge language string cache?
1219
 *        'lang'   Purge language string cache?
1203
 *        'js'     Purge javascript cache?
1220
 *        'js'     Purge javascript cache?
-
 
1221
 *        'template' Purge template cache
1204
 *        'filter' Purge text filter cache?
1222
 *        'filter' Purge text filter cache?
1205
 *        'other'  Purge all other caches?
1223
 *        'other'  Purge all other caches?
1206
 */
1224
 */
1207
function purge_caches($options = [])
1225
function purge_caches($options = []) {
1208
{
-
 
1209
    $defaults = array_fill_keys(['muc', 'courses', 'theme', 'lang', 'js', 'template', 'filter', 'other'], false);
1226
    $defaults = array_fill_keys(['muc', 'courses', 'theme', 'lang', 'js', 'template', 'filter', 'other'], false);
1210
    if (empty(array_filter($options))) {
1227
    if (empty(array_filter($options))) {
1211
        $options = array_fill_keys(array_keys($defaults), true); // Set all options to true.
1228
        $options = array_fill_keys(array_keys($defaults), true); // Set all options to true.
1212
    } else {
1229
    } else {
1213
        $options = array_merge($defaults, array_intersect_key($options, $defaults)); // Override defaults with specified options.
1230
        $options = array_merge($defaults, array_intersect_key($options, $defaults)); // Override defaults with specified options.
Línea 1246... Línea 1263...
1246
 * Purge all non-MUC caches not otherwise purged in purge_caches.
1263
 * Purge all non-MUC caches not otherwise purged in purge_caches.
1247
 *
1264
 *
1248
 * IMPORTANT - If you are adding anything here to do with the cache directory you should also have a look at
1265
 * IMPORTANT - If you are adding anything here to do with the cache directory you should also have a look at
1249
 * {@link phpunit_util::reset_dataroot()}
1266
 * {@link phpunit_util::reset_dataroot()}
1250
 */
1267
 */
1251
function purge_other_caches()
1268
function purge_other_caches() {
1252
{
-
 
1253
    global $DB, $CFG;
1269
    global $DB, $CFG;
1254
    if (class_exists('core_plugin_manager')) {
1270
    if (class_exists('core_plugin_manager')) {
1255
        core_plugin_manager::reset_caches();
1271
        core_plugin_manager::reset_caches();
1256
    }
1272
    }
Línea 1264... Línea 1280...
1264
 
1280
 
Línea 1265... Línea 1281...
1265
    $DB->reset_caches();
1281
    $DB->reset_caches();
1266
 
1282
 
1267
    // Purge all other caches: rss, simplepie, etc.
1283
    // Purge all other caches: rss, simplepie, etc.
Línea 1268... Línea 1284...
1268
    clearstatcache();
1284
    clearstatcache();
1269
    remove_dir($CFG->cachedir . '', true);
1285
    remove_dir($CFG->cachedir.'', true);
Línea 1270... Línea 1286...
1270
 
1286
 
Línea 1287... Línea 1303...
1287
 *
1303
 *
1288
 * @param string $type
1304
 * @param string $type
1289
 * @param int $changedsince default null
1305
 * @param int $changedsince default null
1290
 * @return array records array
1306
 * @return array records array
1291
 */
1307
 */
1292
function get_cache_flags($type, $changedsince = null)
1308
function get_cache_flags($type, $changedsince = null) {
1293
{
-
 
1294
    global $DB;
1309
    global $DB;
Línea 1295... Línea 1310...
1295
 
1310
 
1296
    $params = array('type' => $type, 'expiry' => time());
1311
    $params = array('type' => $type, 'expiry' => time());
1297
    $sqlwhere = "flagtype = :type AND expiry >= :expiry";
1312
    $sqlwhere = "flagtype = :type AND expiry >= :expiry";
Línea 1314... Línea 1329...
1314
 * @param string $type
1329
 * @param string $type
1315
 * @param string $name
1330
 * @param string $name
1316
 * @param int $changedsince default null
1331
 * @param int $changedsince default null
1317
 * @return string|false The cache flag value or false
1332
 * @return string|false The cache flag value or false
1318
 */
1333
 */
1319
function get_cache_flag($type, $name, $changedsince = null)
1334
function get_cache_flag($type, $name, $changedsince=null) {
1320
{
-
 
1321
    global $DB;
1335
    global $DB;
Línea 1322... Línea 1336...
1322
 
1336
 
Línea 1323... Línea 1337...
1323
    $params = array('type' => $type, 'name' => $name, 'expiry' => time());
1337
    $params = array('type' => $type, 'name' => $name, 'expiry' => time());
Línea 1338... Línea 1352...
1338
 * @param string $name the key to set
1352
 * @param string $name the key to set
1339
 * @param string $value the value to set (without magic quotes) - null will remove the flag
1353
 * @param string $value the value to set (without magic quotes) - null will remove the flag
1340
 * @param int $expiry (optional) epoch indicating expiry - defaults to now()+ 24hs
1354
 * @param int $expiry (optional) epoch indicating expiry - defaults to now()+ 24hs
1341
 * @return bool Always returns true
1355
 * @return bool Always returns true
1342
 */
1356
 */
1343
function set_cache_flag($type, $name, $value, $expiry = null)
1357
function set_cache_flag($type, $name, $value, $expiry = null) {
1344
{
-
 
1345
    global $DB;
1358
    global $DB;
Línea 1346... Línea 1359...
1346
 
1359
 
1347
    $timemodified = time();
1360
    $timemodified = time();
1348
    if ($expiry === null || $expiry < $timemodified) {
1361
    if ($expiry === null || $expiry < $timemodified) {
Línea 1382... Línea 1395...
1382
 *
1395
 *
1383
 * @param string $type the "type" namespace for the key
1396
 * @param string $type the "type" namespace for the key
1384
 * @param string $name the key to set
1397
 * @param string $name the key to set
1385
 * @return bool
1398
 * @return bool
1386
 */
1399
 */
1387
function unset_cache_flag($type, $name)
1400
function unset_cache_flag($type, $name) {
1388
{
-
 
1389
    global $DB;
1401
    global $DB;
1390
    $DB->delete_records('cache_flags', array('name' => $name, 'flagtype' => $type));
1402
    $DB->delete_records('cache_flags', array('name' => $name, 'flagtype' => $type));
1391
    return true;
1403
    return true;
1392
}
1404
}
Línea 1393... Línea 1405...
1393
 
1405
 
1394
/**
1406
/**
1395
 * Garbage-collect volatile flags
1407
 * Garbage-collect volatile flags
1396
 *
1408
 *
1397
 * @return bool Always returns true
1409
 * @return bool Always returns true
1398
 */
1410
 */
1399
function gc_cache_flags()
-
 
1400
{
1411
function gc_cache_flags() {
1401
    global $DB;
1412
    global $DB;
1402
    $DB->delete_records_select('cache_flags', 'expiry < ?', array(time()));
1413
    $DB->delete_records_select('cache_flags', 'expiry < ?', array(time()));
1403
    return true;
1414
    return true;
Línea 1417... Línea 1428...
1417
 * @param    stdClass         $user          User object. Preferences are preloaded into 'preference' property
1428
 * @param    stdClass         $user          User object. Preferences are preloaded into 'preference' property
1418
 * @param    int              $cachelifetime Cache life time on the current page (in seconds)
1429
 * @param    int              $cachelifetime Cache life time on the current page (in seconds)
1419
 * @throws   coding_exception
1430
 * @throws   coding_exception
1420
 * @return   null
1431
 * @return   null
1421
 */
1432
 */
1422
function check_user_preferences_loaded(stdClass $user, $cachelifetime = 120)
1433
function check_user_preferences_loaded(stdClass $user, $cachelifetime = 120) {
1423
{
-
 
1424
    global $DB;
1434
    global $DB;
1425
    // Static cache, we need to check on each page load, not only every 2 minutes.
1435
    // Static cache, we need to check on each page load, not only every 2 minutes.
1426
    static $loadedusers = array();
1436
    static $loadedusers = array();
Línea 1427... Línea 1437...
1427
 
1437
 
Línea 1442... Línea 1452...
1442
    if (isset($loadedusers[$user->id]) and isset($user->preference) and isset($user->preference['_lastloaded'])) {
1452
    if (isset($loadedusers[$user->id]) and isset($user->preference) and isset($user->preference['_lastloaded'])) {
1443
        // Already loaded at least once on this page. Are we up to date?
1453
        // Already loaded at least once on this page. Are we up to date?
1444
        if ($user->preference['_lastloaded'] + $cachelifetime > $timenow) {
1454
        if ($user->preference['_lastloaded'] + $cachelifetime > $timenow) {
1445
            // No need to reload - we are on the same page and we loaded prefs just a moment ago.
1455
            // No need to reload - we are on the same page and we loaded prefs just a moment ago.
1446
            return;
1456
            return;
-
 
1457
 
1447
        } else if (!get_cache_flag('userpreferenceschanged', $user->id, $user->preference['_lastloaded'])) {
1458
        } else if (!get_cache_flag('userpreferenceschanged', $user->id, $user->preference['_lastloaded'])) {
1448
            // No change since the lastcheck on this page.
1459
            // No change since the lastcheck on this page.
1449
            $user->preference['_lastloaded'] = $timenow;
1460
            $user->preference['_lastloaded'] = $timenow;
1450
            return;
1461
            return;
1451
        }
1462
        }
Línea 1464... Línea 1475...
1464
 *
1475
 *
1465
 * @package core
1476
 * @package core
1466
 * @access private
1477
 * @access private
1467
 * @param integer $userid the user whose prefs were changed.
1478
 * @param integer $userid the user whose prefs were changed.
1468
 */
1479
 */
1469
function mark_user_preferences_changed($userid)
1480
function mark_user_preferences_changed($userid) {
1470
{
-
 
1471
    global $CFG;
1481
    global $CFG;
Línea 1472... Línea 1482...
1472
 
1482
 
1473
    if (empty($userid) or isguestuser($userid)) {
1483
    if (empty($userid) or isguestuser($userid)) {
1474
        // No cache flags for guest and not-logged-in users.
1484
        // No cache flags for guest and not-logged-in users.
Línea 1493... Línea 1503...
1493
 *                                    record, null means delete current value.
1503
 *                                    record, null means delete current value.
1494
 * @param    stdClass|int|null $user  A moodle user object or id, null means current user
1504
 * @param    stdClass|int|null $user  A moodle user object or id, null means current user
1495
 * @throws   coding_exception
1505
 * @throws   coding_exception
1496
 * @return   bool                     Always true or exception
1506
 * @return   bool                     Always true or exception
1497
 */
1507
 */
1498
function set_user_preference($name, $value, $user = null)
1508
function set_user_preference($name, $value, $user = null) {
1499
{
-
 
1500
    global $USER, $DB;
1509
    global $USER, $DB;
Línea 1501... Línea 1510...
1501
 
1510
 
1502
    if (empty($name) or is_numeric($name) or $name === '_lastloaded') {
1511
    if (empty($name) or is_numeric($name) or $name === '_lastloaded') {
1503
        throw new coding_exception('Invalid preference name in set_user_preference() call');
1512
        throw new coding_exception('Invalid preference name in set_user_preference() call');
Línea 1509... Línea 1518...
1509
    } else if (is_object($value)) {
1518
    } else if (is_object($value)) {
1510
        throw new coding_exception('Invalid value in set_user_preference() call, objects are not allowed');
1519
        throw new coding_exception('Invalid value in set_user_preference() call, objects are not allowed');
1511
    } else if (is_array($value)) {
1520
    } else if (is_array($value)) {
1512
        throw new coding_exception('Invalid value in set_user_preference() call, arrays are not allowed');
1521
        throw new coding_exception('Invalid value in set_user_preference() call, arrays are not allowed');
1513
    }
1522
    }
1514
    // Value column maximum length is 1333 characters.
-
 
1515
    $value = (string)$value;
1523
    $value = (string)$value;
1516
    if (core_text::strlen($value) > 1333) {
-
 
1517
        throw new coding_exception('Invalid value in set_user_preference() call, value is is too long for the value column');
-
 
1518
    }
-
 
Línea 1519... Línea 1524...
1519
 
1524
 
1520
    if (is_null($user)) {
1525
    if (is_null($user)) {
1521
        $user = $USER;
1526
        $user = $USER;
1522
    } else if (isset($user->id)) {
1527
    } else if (isset($user->id)) {
Línea 1533... Línea 1538...
1533
        // No permanent storage for not-logged-in users and guest.
1538
        // No permanent storage for not-logged-in users and guest.
1534
        $user->preference[$name] = $value;
1539
        $user->preference[$name] = $value;
1535
        return true;
1540
        return true;
1536
    }
1541
    }
Línea -... Línea 1542...
-
 
1542
 
-
 
1543
    $retry = 0;
-
 
1544
    $saved = false;
-
 
1545
 
1537
 
1546
    while (!$saved && $retry++ < 2) {
1538
    if ($preference = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => $name))) {
1547
        if ($preference = $DB->get_record('user_preferences', ['userid' => $user->id, 'name' => $name])) {
1539
        if ($preference->value === $value and isset($user->preference[$name]) and $user->preference[$name] === $value) {
1548
            if ($preference->value === $value && isset($user->preference[$name]) && $user->preference[$name] === $value) {
1540
            // Preference already set to this value.
1549
                // Preference already set to this value.
-
 
1550
                return true;
-
 
1551
            }
-
 
1552
            $DB->set_field('user_preferences', 'value', $value, ['id' => $preference->id]);
-
 
1553
            $saved = true;
-
 
1554
        } else {
-
 
1555
            $preference = new stdClass();
-
 
1556
            $preference->userid = $user->id;
-
 
1557
            $preference->name   = $name;
-
 
1558
            $preference->value  = $value;
-
 
1559
            try {
-
 
1560
                $DB->insert_record('user_preferences', $preference);
-
 
1561
                $saved = true;
-
 
1562
            } catch (dml_write_exception $e) {
-
 
1563
                // We have an insert race, so just ignore and try again.
-
 
1564
                $saved = false;
1541
            return true;
1565
            }
1542
        }
-
 
1543
        $DB->set_field('user_preferences', 'value', $value, array('id' => $preference->id));
-
 
1544
    } else {
-
 
1545
        $preference = new stdClass();
-
 
1546
        $preference->userid = $user->id;
-
 
1547
        $preference->name   = $name;
-
 
1548
        $preference->value  = $value;
-
 
1549
        $DB->insert_record('user_preferences', $preference);
1566
        }
Línea 1550... Línea 1567...
1550
    }
1567
    }
1551
 
1568
 
1552
    // Update value in cache.
1569
    // Update value in cache.
Línea 1572... Línea 1589...
1572
 * @access   public
1589
 * @access   public
1573
 * @param    array             $prefarray An array of key/value pairs to be set
1590
 * @param    array             $prefarray An array of key/value pairs to be set
1574
 * @param    stdClass|int|null $user      A moodle user object or id, null means current user
1591
 * @param    stdClass|int|null $user      A moodle user object or id, null means current user
1575
 * @return   bool                         Always true or exception
1592
 * @return   bool                         Always true or exception
1576
 */
1593
 */
1577
function set_user_preferences(array $prefarray, $user = null)
1594
function set_user_preferences(array $prefarray, $user = null) {
1578
{
-
 
1579
    foreach ($prefarray as $name => $value) {
1595
    foreach ($prefarray as $name => $value) {
1580
        set_user_preference($name, $value, $user);
1596
        set_user_preference($name, $value, $user);
1581
    }
1597
    }
1582
    return true;
1598
    return true;
1583
}
1599
}
Línea 1593... Línea 1609...
1593
 * @param    string            $name The key to unset as preference for the specified user
1609
 * @param    string            $name The key to unset as preference for the specified user
1594
 * @param    stdClass|int|null $user A moodle user object or id, null means current user
1610
 * @param    stdClass|int|null $user A moodle user object or id, null means current user
1595
 * @throws   coding_exception
1611
 * @throws   coding_exception
1596
 * @return   bool                    Always true or exception
1612
 * @return   bool                    Always true or exception
1597
 */
1613
 */
1598
function unset_user_preference($name, $user = null)
1614
function unset_user_preference($name, $user = null) {
1599
{
-
 
1600
    global $USER, $DB;
1615
    global $USER, $DB;
Línea 1601... Línea 1616...
1601
 
1616
 
1602
    if (empty($name) or is_numeric($name) or $name === '_lastloaded') {
1617
    if (empty($name) or is_numeric($name) or $name === '_lastloaded') {
1603
        throw new coding_exception('Invalid preference name in unset_user_preference() call');
1618
        throw new coding_exception('Invalid preference name in unset_user_preference() call');
Línea 1658... Línea 1673...
1658
 * @param    stdClass|int|null $user    A moodle user object or id, null means current user
1673
 * @param    stdClass|int|null $user    A moodle user object or id, null means current user
1659
 * @throws   coding_exception
1674
 * @throws   coding_exception
1660
 * @return   string|mixed|null          A string containing the value of a single preference. An
1675
 * @return   string|mixed|null          A string containing the value of a single preference. An
1661
 *                                      array with all of the preferences or null
1676
 *                                      array with all of the preferences or null
1662
 */
1677
 */
1663
function get_user_preferences($name = null, $default = null, $user = null)
1678
function get_user_preferences($name = null, $default = null, $user = null) {
1664
{
-
 
1665
    global $USER;
1679
    global $USER;
Línea 1666... Línea 1680...
1666
 
1680
 
1667
    if (is_null($name)) {
1681
    if (is_null($name)) {
1668
        // All prefs.
1682
        // All prefs.
Línea 1715... Línea 1729...
1715
 *             if 99 then default user's timezone is used {@link https://moodledev.io/docs/apis/subsystems/time#timezone}
1729
 *             if 99 then default user's timezone is used {@link https://moodledev.io/docs/apis/subsystems/time#timezone}
1716
 * @param bool $applydst Toggle Daylight Saving Time, default true, will be
1730
 * @param bool $applydst Toggle Daylight Saving Time, default true, will be
1717
 *             applied only if timezone is 99 or string.
1731
 *             applied only if timezone is 99 or string.
1718
 * @return int GMT timestamp
1732
 * @return int GMT timestamp
1719
 */
1733
 */
1720
function make_timestamp($year, $month = 1, $day = 1, $hour = 0, $minute = 0, $second = 0, $timezone = 99, $applydst = true)
1734
function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0, $timezone=99, $applydst=true) {
1721
{
-
 
1722
    $date = new DateTime('now', core_date::get_user_timezone_object($timezone));
1735
    $date = new DateTime('now', core_date::get_user_timezone_object($timezone));
1723
    $date->setDate((int)$year, (int)$month, (int)$day);
1736
    $date->setDate((int)$year, (int)$month, (int)$day);
1724
    $date->setTime((int)$hour, (int)$minute, (int)$second);
1737
    $date->setTime((int)$hour, (int)$minute, (int)$second);
Línea 1725... Línea 1738...
1725
 
1738
 
Línea 1726... Línea 1739...
1726
    $time = $date->getTimestamp();
1739
    $time = $date->getTimestamp();
1727
 
1740
 
1728
    if ($time === false) {
1741
    if ($time === false) {
1729
        throw new coding_exception('getTimestamp() returned false, please ensure you have passed correct values.' .
1742
        throw new coding_exception('getTimestamp() returned false, please ensure you have passed correct values.'.
Línea 1730... Línea 1743...
1730
            ' This can fail if year is more than 2038 and OS is 32 bit windows');
1743
            ' This can fail if year is more than 2038 and OS is 32 bit windows');
1731
    }
1744
    }
1732
 
1745
 
1733
    // Moodle BC DST stuff.
1746
    // Moodle BC DST stuff.
Línea 1734... Línea 1747...
1734
    if (!$applydst) {
1747
    if (!$applydst) {
-
 
1748
        $time += dst_offset_on($time, $timezone);
1735
        $time += dst_offset_on($time, $timezone);
1749
    }
Línea 1736... Línea 1750...
1736
    }
1750
 
1737
 
1751
    return $time;
1738
    return $time;
1752
 
Línea 1752... Línea 1766...
1752
 * @uses YEARSECS
1766
 * @uses YEARSECS
1753
 * @param int $totalsecs Time in seconds
1767
 * @param int $totalsecs Time in seconds
1754
 * @param stdClass $str Should be a time object
1768
 * @param stdClass $str Should be a time object
1755
 * @return string A nicely formatted date/time string
1769
 * @return string A nicely formatted date/time string
1756
 */
1770
 */
1757
function format_time($totalsecs, $str = null)
1771
function format_time($totalsecs, $str = null) {
1758
{
-
 
Línea 1759... Línea 1772...
1759
 
1772
 
Línea 1760... Línea 1773...
1760
    $totalsecs = abs($totalsecs);
1773
    $totalsecs = abs($totalsecs);
1761
 
1774
 
Línea 1772... Línea 1785...
1772
        $str->secs  = get_string('secs');
1785
        $str->secs  = get_string('secs');
1773
        $str->year  = get_string('year');
1786
        $str->year  = get_string('year');
1774
        $str->years = get_string('years');
1787
        $str->years = get_string('years');
1775
    }
1788
    }
Línea 1776... Línea 1789...
1776
 
1789
 
1777
    $years     = floor($totalsecs / YEARSECS);
1790
    $years     = floor($totalsecs/YEARSECS);
1778
    $remainder = $totalsecs - ($years * YEARSECS);
1791
    $remainder = $totalsecs - ($years*YEARSECS);
1779
    $days      = floor($remainder / DAYSECS);
1792
    $days      = floor($remainder/DAYSECS);
1780
    $remainder = $totalsecs - ($days * DAYSECS);
1793
    $remainder = $totalsecs - ($days*DAYSECS);
1781
    $hours     = floor($remainder / HOURSECS);
1794
    $hours     = floor($remainder/HOURSECS);
1782
    $remainder = $remainder - ($hours * HOURSECS);
1795
    $remainder = $remainder - ($hours*HOURSECS);
1783
    $mins      = floor($remainder / MINSECS);
1796
    $mins      = floor($remainder/MINSECS);
Línea 1784... Línea 1797...
1784
    $secs      = $remainder - ($mins * MINSECS);
1797
    $secs      = $remainder - ($mins*MINSECS);
1785
 
1798
 
1786
    $ss = ($secs == 1)  ? $str->sec  : $str->secs;
1799
    $ss = ($secs == 1)  ? $str->sec  : $str->secs;
1787
    $sm = ($mins == 1)  ? $str->min  : $str->mins;
1800
    $sm = ($mins == 1)  ? $str->min  : $str->mins;
Línea 1794... Línea 1807...
1794
    $ohours = '';
1807
    $ohours = '';
1795
    $omins = '';
1808
    $omins = '';
1796
    $osecs = '';
1809
    $osecs = '';
Línea 1797... Línea 1810...
1797
 
1810
 
1798
    if ($years) {
1811
    if ($years) {
1799
        $oyears  = $years . ' ' . $sy;
1812
        $oyears  = $years .' '. $sy;
1800
    }
1813
    }
1801
    if ($days) {
1814
    if ($days) {
1802
        $odays  = $days . ' ' . $sd;
1815
        $odays  = $days .' '. $sd;
1803
    }
1816
    }
1804
    if ($hours) {
1817
    if ($hours) {
1805
        $ohours = $hours . ' ' . $sh;
1818
        $ohours = $hours .' '. $sh;
1806
    }
1819
    }
1807
    if ($mins) {
1820
    if ($mins) {
1808
        $omins  = $mins . ' ' . $sm;
1821
        $omins  = $mins .' '. $sm;
1809
    }
1822
    }
1810
    if ($secs) {
1823
    if ($secs) {
1811
        $osecs  = $secs . ' ' . $ss;
1824
        $osecs  = $secs .' '. $ss;
Línea 1812... Línea 1825...
1812
    }
1825
    }
1813
 
1826
 
1814
    if ($years) {
1827
    if ($years) {
1815
        return trim($oyears . ' ' . $odays);
1828
        return trim($oyears .' '. $odays);
1816
    }
1829
    }
1817
    if ($days) {
1830
    if ($days) {
1818
        return trim($odays . ' ' . $ohours);
1831
        return trim($odays .' '. $ohours);
1819
    }
1832
    }
1820
    if ($hours) {
1833
    if ($hours) {
1821
        return trim($ohours . ' ' . $omins);
1834
        return trim($ohours .' '. $omins);
1822
    }
1835
    }
1823
    if ($mins) {
1836
    if ($mins) {
1824
        return trim($omins . ' ' . $osecs);
1837
        return trim($omins .' '. $osecs);
1825
    }
1838
    }
1826
    if ($secs) {
1839
    if ($secs) {
1827
        return $osecs;
1840
        return $osecs;
Línea 1843... Línea 1856...
1843
 * @param bool $fixday If true (default) then the leading zero from %d is removed.
1856
 * @param bool $fixday If true (default) then the leading zero from %d is removed.
1844
 *        If false then the leading zero is maintained.
1857
 *        If false then the leading zero is maintained.
1845
 * @param bool $fixhour If true (default) then the leading zero from %I is removed.
1858
 * @param bool $fixhour If true (default) then the leading zero from %I is removed.
1846
 * @return string the formatted date/time.
1859
 * @return string the formatted date/time.
1847
 */
1860
 */
1848
function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour = true)
1861
function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour = true) {
1849
{
-
 
1850
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
1862
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
1851
    return $calendartype->timestamp_to_date_string($date, $format, $timezone, $fixday, $fixhour);
1863
    return $calendartype->timestamp_to_date_string($date, $format, $timezone, $fixday, $fixhour);
1852
}
1864
}
Línea 1853... Línea 1865...
1853
 
1865
 
Línea 1866... Línea 1878...
1866
 * @param bool $fixday If true (default) then the leading zero from %d is removed.
1878
 * @param bool $fixday If true (default) then the leading zero from %d is removed.
1867
 *        If false then the leading zero is maintained.
1879
 *        If false then the leading zero is maintained.
1868
 * @param bool $fixhour If true (default) then the leading zero from %I is removed.
1880
 * @param bool $fixhour If true (default) then the leading zero from %I is removed.
1869
 * @return string the formatted date/time.
1881
 * @return string the formatted date/time.
1870
 */
1882
 */
1871
function userdate_htmltime($date, $format = '', $timezone = 99, $fixday = true, $fixhour = true)
1883
function userdate_htmltime($date, $format = '', $timezone = 99, $fixday = true, $fixhour = true) {
1872
{
-
 
1873
    $userdatestr = userdate($date, $format, $timezone, $fixday, $fixhour);
1884
    $userdatestr = userdate($date, $format, $timezone, $fixday, $fixhour);
1874
    if (CLI_SCRIPT && !PHPUNIT_TEST) {
1885
    if (CLI_SCRIPT && !PHPUNIT_TEST) {
1875
        return $userdatestr;
1886
        return $userdatestr;
1876
    }
1887
    }
1877
    $machinedate = new DateTime();
1888
    $machinedate = new DateTime();
Línea 1891... Línea 1902...
1891
 * @param string $format strftime format.
1902
 * @param string $format strftime format.
1892
 * @param int|float|string $tz the user timezone
1903
 * @param int|float|string $tz the user timezone
1893
 * @return string the formatted date/time.
1904
 * @return string the formatted date/time.
1894
 * @since Moodle 2.3.3
1905
 * @since Moodle 2.3.3
1895
 */
1906
 */
1896
function date_format_string($date, $format, $tz = 99)
1907
function date_format_string($date, $format, $tz = 99) {
1897
{
-
 
Línea 1898... Línea 1908...
1898
 
1908
 
Línea 1899... Línea 1909...
1899
    date_default_timezone_set(core_date::get_user_timezone($tz));
1909
    date_default_timezone_set(core_date::get_user_timezone($tz));
1900
 
1910
 
Línea 1923... Línea 1933...
1923
 * @category time
1933
 * @category time
1924
 * @param int $time Timestamp in GMT
1934
 * @param int $time Timestamp in GMT
1925
 * @param float|int|string $timezone user timezone
1935
 * @param float|int|string $timezone user timezone
1926
 * @return array An array that represents the date in user time
1936
 * @return array An array that represents the date in user time
1927
 */
1937
 */
1928
function usergetdate($time, $timezone = 99)
1938
function usergetdate($time, $timezone=99) {
1929
{
-
 
1930
    if ($time === null) {
1939
    if ($time === null) {
1931
        // PHP8 and PHP7 return different results when getdate(null) is called.
1940
        // PHP8 and PHP7 return different results when getdate(null) is called.
1932
        // Display warning and cast to 0 to make sure the usergetdate() behaves consistently on all versions of PHP.
1941
        // Display warning and cast to 0 to make sure the usergetdate() behaves consistently on all versions of PHP.
1933
        // In the future versions of Moodle we may consider adding a strict typehint.
1942
        // In the future versions of Moodle we may consider adding a strict typehint.
1934
        debugging('usergetdate() expects parameter $time to be int, null given', DEBUG_DEVELOPER);
1943
        debugging('usergetdate() expects parameter $time to be int, null given', DEBUG_DEVELOPER);
Línea 1953... Línea 1962...
1953
 * @category time
1962
 * @category time
1954
 * @param int $date Timestamp in GMT
1963
 * @param int $date Timestamp in GMT
1955
 * @param float|int|string $timezone user timezone
1964
 * @param float|int|string $timezone user timezone
1956
 * @return int
1965
 * @return int
1957
 */
1966
 */
1958
function usertime($date, $timezone = 99)
1967
function usertime($date, $timezone=99) {
1959
{
-
 
1960
    $userdate = new DateTime('@' . $date);
1968
    $userdate = new DateTime('@' . $date);
1961
    $userdate->setTimezone(core_date::get_user_timezone_object($timezone));
1969
    $userdate->setTimezone(core_date::get_user_timezone_object($timezone));
1962
    $dst = dst_offset_on($date, $timezone);
1970
    $dst = dst_offset_on($date, $timezone);
Línea 1963... Línea 1971...
1963
 
1971
 
Línea 1979... Línea 1987...
1979
 *                         e.g. a duration of 3 days and 2 hours will be displayed as '3d 2h' instead of '3d 2h 0s'
1987
 *                         e.g. a duration of 3 days and 2 hours will be displayed as '3d 2h' instead of '3d 2h 0s'
1980
 * @param bool $fullformat If format is not provided and this is set to true, display time units in full format.
1988
 * @param bool $fullformat If format is not provided and this is set to true, display time units in full format.
1981
 *                         e.g. instead of showing "3d", "3 days" will be returned.
1989
 *                         e.g. instead of showing "3d", "3 days" will be returned.
1982
 * @return string the formatted string describing the time difference, e.g. '10d 11h 45m'.
1990
 * @return string the formatted string describing the time difference, e.g. '10d 11h 45m'.
1983
 */
1991
 */
1984
function get_time_interval_string(
1992
function get_time_interval_string(int $time1, int $time2, string $format = '',
1985
    int $time1,
-
 
1986
    int $time2,
-
 
1987
    string $format = '',
-
 
1988
    bool $dropzeroes = false,
1993
        bool $dropzeroes = false, bool $fullformat = false): string {
1989
    bool $fullformat = false
-
 
1990
): string {
-
 
1991
    $dtdate = new DateTime();
1994
    $dtdate = new DateTime();
1992
    $dtdate->setTimeStamp($time1);
1995
    $dtdate->setTimeStamp($time1);
1993
    $dtdate2 = new DateTime();
1996
    $dtdate2 = new DateTime();
1994
    $dtdate2->setTimeStamp($time2);
1997
    $dtdate2->setTimeStamp($time2);
1995
    $interval = $dtdate2->diff($dtdate);
1998
    $interval = $dtdate2->diff($dtdate);
Línea 2035... Línea 2038...
2035
 * @category time
2038
 * @category time
2036
 * @param int $date Timestamp in GMT
2039
 * @param int $date Timestamp in GMT
2037
 * @param float|int|string $timezone user timezone
2040
 * @param float|int|string $timezone user timezone
2038
 * @return int Returns a GMT timestamp
2041
 * @return int Returns a GMT timestamp
2039
 */
2042
 */
2040
function usergetmidnight($date, $timezone = 99)
2043
function usergetmidnight($date, $timezone=99) {
2041
{
-
 
Línea 2042... Línea 2044...
2042
 
2044
 
Línea 2043... Línea 2045...
2043
    $userdate = usergetdate($date, $timezone);
2045
    $userdate = usergetdate($date, $timezone);
2044
 
2046
 
-
 
2047
    // Time of midnight of this user's day, in GMT.
2045
    // Time of midnight of this user's day, in GMT.
2048
    return make_timestamp($userdate['year'], $userdate['mon'], $userdate['mday'], 0, 0, 0, $timezone);
Línea 2046... Línea 2049...
2046
    return make_timestamp($userdate['year'], $userdate['mon'], $userdate['mday'], 0, 0, 0, $timezone);
2049
 
2047
}
2050
}
2048
 
2051
 
2049
/**
2052
/**
2050
 * Returns a string that prints the user's timezone
2053
 * Returns a string that prints the user's timezone
2051
 *
2054
 *
2052
 * @package core
2055
 * @package core
2053
 * @category time
2056
 * @category time
2054
 * @param float|int|string $timezone user timezone
2057
 * @param float|int|string $timezone user timezone
2055
 * @return string
-
 
2056
 */
2058
 * @return string
2057
function usertimezone($timezone = 99)
2059
 */
2058
{
2060
function usertimezone($timezone=99) {
Línea 2059... Línea 2061...
2059
    $tz = core_date::get_user_timezone($timezone);
2061
    $tz = core_date::get_user_timezone($timezone);
Línea 2071... Línea 2073...
2071
 * @param float|int|string $tz timezone to calculate GMT time offset before
2073
 * @param float|int|string $tz timezone to calculate GMT time offset before
2072
 *        calculating user timezone, 99 is default user timezone
2074
 *        calculating user timezone, 99 is default user timezone
2073
 *        {@link https://moodledev.io/docs/apis/subsystems/time#timezone}
2075
 *        {@link https://moodledev.io/docs/apis/subsystems/time#timezone}
2074
 * @return float|string
2076
 * @return float|string
2075
 */
2077
 */
2076
function get_user_timezone($tz = 99)
2078
function get_user_timezone($tz = 99) {
2077
{
-
 
2078
    global $USER, $CFG;
2079
    global $USER, $CFG;
Línea 2079... Línea 2080...
2079
 
2080
 
2080
    $timezones = array(
2081
    $timezones = array(
2081
        $tz,
2082
        $tz,
2082
        isset($CFG->forcetimezone) ? $CFG->forcetimezone : 99,
2083
        isset($CFG->forcetimezone) ? $CFG->forcetimezone : 99,
2083
        isset($USER->timezone) ? $USER->timezone : 99,
2084
        isset($USER->timezone) ? $USER->timezone : 99,
2084
        isset($CFG->timezone) ? $CFG->timezone : 99,
2085
        isset($CFG->timezone) ? $CFG->timezone : 99,
Línea 2085... Línea 2086...
2085
    );
2086
        );
Línea 2086... Línea 2087...
2086
 
2087
 
2087
    $tz = 99;
2088
    $tz = 99;
Línea 2103... Línea 2104...
2103
 * @category time
2104
 * @category time
2104
 * @param int $time must NOT be compensated at all, it has to be a pure timestamp
2105
 * @param int $time must NOT be compensated at all, it has to be a pure timestamp
2105
 * @param int|float|string $strtimezone user timezone
2106
 * @param int|float|string $strtimezone user timezone
2106
 * @return int
2107
 * @return int
2107
 */
2108
 */
2108
function dst_offset_on($time, $strtimezone = null)
2109
function dst_offset_on($time, $strtimezone = null) {
2109
{
-
 
2110
    $tz = core_date::get_user_timezone($strtimezone);
2110
    $tz = core_date::get_user_timezone($strtimezone);
2111
    $date = new DateTime('@' . $time);
2111
    $date = new DateTime('@' . $time);
2112
    $date->setTimezone(new DateTimeZone($tz));
2112
    $date->setTimezone(new DateTimeZone($tz));
2113
    if ($date->format('I') == '1') {
2113
    if ($date->format('I') == '1') {
2114
        if ($tz === 'Australia/Lord_Howe') {
2114
        if ($tz === 'Australia/Lord_Howe') {
Línea 2128... Línea 2128...
2128
 * @param int $weekday The day when week starts (normally taken from user preferences)
2128
 * @param int $weekday The day when week starts (normally taken from user preferences)
2129
 * @param int $month The month whose day is sought
2129
 * @param int $month The month whose day is sought
2130
 * @param int $year The year of the month whose day is sought
2130
 * @param int $year The year of the month whose day is sought
2131
 * @return int
2131
 * @return int
2132
 */
2132
 */
2133
function find_day_in_month($startday, $weekday, $month, $year)
2133
function find_day_in_month($startday, $weekday, $month, $year) {
2134
{
-
 
2135
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
2134
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
Línea 2136... Línea 2135...
2136
 
2135
 
2137
    $daysinmonth = days_in_month($month, $year);
2136
    $daysinmonth = days_in_month($month, $year);
Línea 2189... Línea 2188...
2189
 * @category time
2188
 * @category time
2190
 * @param int $month The month whose day count is sought
2189
 * @param int $month The month whose day count is sought
2191
 * @param int $year The year of the month whose day count is sought
2190
 * @param int $year The year of the month whose day count is sought
2192
 * @return int
2191
 * @return int
2193
 */
2192
 */
2194
function days_in_month($month, $year)
2193
function days_in_month($month, $year) {
2195
{
-
 
2196
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
2194
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
2197
    return $calendartype->get_num_days_in_month($year, $month);
2195
    return $calendartype->get_num_days_in_month($year, $month);
2198
}
2196
}
Línea 2199... Línea 2197...
2199
 
2197
 
Línea 2205... Línea 2203...
2205
 * @param int $day The day of the date whose position in the week is sought
2203
 * @param int $day The day of the date whose position in the week is sought
2206
 * @param int $month The month of the date whose position in the week is sought
2204
 * @param int $month The month of the date whose position in the week is sought
2207
 * @param int $year The year of the date whose position in the week is sought
2205
 * @param int $year The year of the date whose position in the week is sought
2208
 * @return int
2206
 * @return int
2209
 */
2207
 */
2210
function dayofweek($day, $month, $year)
2208
function dayofweek($day, $month, $year) {
2211
{
-
 
2212
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
2209
    $calendartype = \core_calendar\type_factory::get_calendar_instance();
2213
    return $calendartype->get_weekday($year, $month, $day);
2210
    return $calendartype->get_weekday($year, $month, $day);
2214
}
2211
}
Línea 2215... Línea 2212...
2215
 
2212
 
Línea 2221... Línea 2218...
2221
 * Any form submissions for authentication to this URL must include username,
2218
 * Any form submissions for authentication to this URL must include username,
2222
 * password as well as a logintoken generated by \core\session\manager::get_login_token().
2219
 * password as well as a logintoken generated by \core\session\manager::get_login_token().
2223
 *
2220
 *
2224
 * @return string login url
2221
 * @return string login url
2225
 */
2222
 */
2226
function get_login_url()
2223
function get_login_url() {
2227
{
-
 
2228
    global $CFG;
2224
    global $CFG;
Línea 2229... Línea 2225...
2229
 
2225
 
2230
    return "$CFG->wwwroot/login/index.php";
2226
    return "$CFG->wwwroot/login/index.php";
Línea 2261... Línea 2257...
2261
 * @return mixed Void, exit, and die depending on path
2257
 * @return mixed Void, exit, and die depending on path
2262
 * @throws coding_exception
2258
 * @throws coding_exception
2263
 * @throws require_login_exception
2259
 * @throws require_login_exception
2264
 * @throws moodle_exception
2260
 * @throws moodle_exception
2265
 */
2261
 */
2266
function require_login($courseorid = null, $autologinguest = true, $cm = null, $setwantsurltome = true, $preventredirect = false)
2262
function require_login($courseorid = null, $autologinguest = true, $cm = null, $setwantsurltome = true, $preventredirect = false) {
2267
{
-
 
2268
    global $CFG, $SESSION, $USER, $PAGE, $SITE, $DB, $OUTPUT;
2263
    global $CFG, $SESSION, $USER, $PAGE, $SITE, $DB, $OUTPUT;
Línea 2269... Línea 2264...
2269
 
2264
 
2270
    // Must not redirect when byteserving already started.
2265
    // Must not redirect when byteserving already started.
2271
    if (!empty($_SERVER['HTTP_RANGE'])) {
2266
    if (!empty($_SERVER['HTTP_RANGE'])) {
Línea 2280... Línea 2275...
2280
    // Setup global $COURSE, themes, language and locale.
2275
    // Setup global $COURSE, themes, language and locale.
2281
    if (!empty($courseorid)) {
2276
    if (!empty($courseorid)) {
2282
        if (is_object($courseorid)) {
2277
        if (is_object($courseorid)) {
2283
            $course = $courseorid;
2278
            $course = $courseorid;
2284
        } else if ($courseorid == SITEID) {
2279
        } else if ($courseorid == SITEID) {
2285
            $course = clone ($SITE);
2280
            $course = clone($SITE);
2286
        } else {
2281
        } else {
2287
            $course = $DB->get_record('course', array('id' => $courseorid), '*', MUST_EXIST);
2282
            $course = $DB->get_record('course', array('id' => $courseorid), '*', MUST_EXIST);
2288
        }
2283
        }
2289
        if ($cm) {
2284
        if ($cm) {
2290
            if ($cm->course != $course->id) {
2285
            if ($cm->course != $course->id) {
Línea 2349... Línea 2344...
2349
                $SESSION->wantsurl = qualified_me();
2344
                $SESSION->wantsurl = qualified_me();
2350
            }
2345
            }
Línea 2351... Línea 2346...
2351
 
2346
 
2352
            // Give auth plugins an opportunity to authenticate or redirect to an external login page
2347
            // Give auth plugins an opportunity to authenticate or redirect to an external login page
2353
            $authsequence = get_enabled_auth_plugins(); // Auths, in sequence.
2348
            $authsequence = get_enabled_auth_plugins(); // Auths, in sequence.
2354
            foreach ($authsequence as $authname) {
2349
            foreach($authsequence as $authname) {
2355
                $authplugin = get_auth_plugin($authname);
2350
                $authplugin = get_auth_plugin($authname);
2356
                $authplugin->pre_loginpage_hook();
2351
                $authplugin->pre_loginpage_hook();
2357
                if (isloggedin()) {
2352
                if (isloggedin()) {
2358
                    if ($cm) {
2353
                    if ($cm) {
Línea 2374... Línea 2369...
2374
 
2369
 
2375
    // Loginas as redirection if needed.
2370
    // Loginas as redirection if needed.
2376
    if ($course->id != SITEID and \core\session\manager::is_loggedinas()) {
2371
    if ($course->id != SITEID and \core\session\manager::is_loggedinas()) {
2377
        if ($USER->loginascontext->contextlevel == CONTEXT_COURSE) {
2372
        if ($USER->loginascontext->contextlevel == CONTEXT_COURSE) {
2378
            if ($USER->loginascontext->instanceid != $course->id) {
2373
            if ($USER->loginascontext->instanceid != $course->id) {
2379
                throw new \moodle_exception(
-
 
2380
                    'loginasonecourse',
-
 
2381
                    '',
2374
                throw new \moodle_exception('loginasonecourse', '',
2382
                    $CFG->wwwroot . '/course/view.php?id=' . $USER->loginascontext->instanceid
-
 
2383
                );
2375
                    $CFG->wwwroot.'/course/view.php?id='.$USER->loginascontext->instanceid);
2384
            }
2376
            }
2385
        }
2377
        }
Línea 2386... Línea 2378...
2386
    }
2378
    }
Línea 2395... Línea 2387...
2395
            if ($changeurl = $userauth->change_password_url()) {
2387
            if ($changeurl = $userauth->change_password_url()) {
2396
                // Use plugin custom url.
2388
                // Use plugin custom url.
2397
                redirect($changeurl);
2389
                redirect($changeurl);
2398
            } else {
2390
            } else {
2399
                // Use moodle internal method.
2391
                // Use moodle internal method.
2400
                redirect($CFG->wwwroot . '/login/change_password.php');
2392
                redirect($CFG->wwwroot .'/login/change_password.php');
2401
            }
2393
            }
2402
        } else if ($userauth->can_change_password()) {
2394
        } else if ($userauth->can_change_password()) {
2403
            throw new moodle_exception('forcepasswordchangenotice');
2395
            throw new moodle_exception('forcepasswordchangenotice');
2404
        } else {
2396
        } else {
2405
            throw new moodle_exception('nopasswordchangeforced', 'auth');
2397
            throw new moodle_exception('nopasswordchangeforced', 'auth');
Línea 2421... Línea 2413...
2421
            throw new moodle_exception('usernotfullysetup');
2413
            throw new moodle_exception('usernotfullysetup');
2422
        }
2414
        }
2423
        if ($setwantsurltome) {
2415
        if ($setwantsurltome) {
2424
            $SESSION->wantsurl = qualified_me();
2416
            $SESSION->wantsurl = qualified_me();
2425
        }
2417
        }
2426
        redirect($CFG->wwwroot . '/user/edit.php?id=' . $USER->id . '&amp;course=' . SITEID);
2418
        redirect($CFG->wwwroot .'/user/edit.php?id='. $USER->id .'&amp;course='. SITEID);
2427
    }
2419
    }
Línea 2428... Línea 2420...
2428
 
2420
 
2429
    // Make sure the USER has a sesskey set up. Used for CSRF protection.
2421
    // Make sure the USER has a sesskey set up. Used for CSRF protection.
Línea 2516... Línea 2508...
2516
                }
2508
                }
2517
                $PAGE->set_context(null);
2509
                $PAGE->set_context(null);
2518
                // We need to override the navigation URL as the course won't have been added to the navigation and thus
2510
                // We need to override the navigation URL as the course won't have been added to the navigation and thus
2519
                // the navigation will mess up when trying to find it.
2511
                // the navigation will mess up when trying to find it.
2520
                navigation_node::override_active_url(new moodle_url('/'));
2512
                navigation_node::override_active_url(new moodle_url('/'));
2521
                notice(get_string('coursehidden'), $CFG->wwwroot . '/');
2513
                notice(get_string('coursehidden'), $CFG->wwwroot .'/');
2522
            }
2514
            }
2523
        }
2515
        }
2524
    }
2516
    }
Línea 2525... Línea 2517...
2525
 
2517
 
Línea 2528... Línea 2520...
2528
        // Everybody is enrolled on the frontpage.
2520
        // Everybody is enrolled on the frontpage.
2529
    } else {
2521
    } else {
2530
        if (\core\session\manager::is_loggedinas()) {
2522
        if (\core\session\manager::is_loggedinas()) {
2531
            // Make sure the REAL person can access this course first.
2523
            // Make sure the REAL person can access this course first.
2532
            $realuser = \core\session\manager::get_realuser();
2524
            $realuser = \core\session\manager::get_realuser();
2533
            if (
-
 
2534
                !is_enrolled($coursecontext, $realuser->id, '', true) and
2525
            if (!is_enrolled($coursecontext, $realuser->id, '', true) and
2535
                !is_viewing($coursecontext, $realuser->id) and !is_siteadmin($realuser->id)
2526
                !is_viewing($coursecontext, $realuser->id) and !is_siteadmin($realuser->id)) {
2536
            ) {
-
 
2537
                if ($preventredirect) {
2527
                if ($preventredirect) {
2538
                    throw new require_login_exception('Invalid course login-as access');
2528
                    throw new require_login_exception('Invalid course login-as access');
2539
                }
2529
                }
2540
                $PAGE->set_context(null);
2530
                $PAGE->set_context(null);
2541
                echo $OUTPUT->header();
2531
                echo $OUTPUT->header();
2542
                notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot . '/');
2532
                notice(get_string('studentnotallowed', '', fullname($USER, true)), $CFG->wwwroot .'/');
2543
            }
2533
            }
2544
        }
2534
        }
Línea 2545... Línea 2535...
2545
 
2535
 
Línea 2546... Línea 2536...
2546
        $access = false;
2536
        $access = false;
2547
 
2537
 
2548
        if (is_role_switched($course->id)) {
2538
        if (is_role_switched($course->id)) {
-
 
2539
            // Ok, user had to be inside this course before the switch.
2549
            // Ok, user had to be inside this course before the switch.
2540
            $access = true;
2550
            $access = true;
2541
 
2551
        } else if (is_viewing($coursecontext, $USER)) {
2542
        } else if (is_viewing($coursecontext, $USER)) {
-
 
2543
            // Ok, no need to mess with enrol.
2552
            // Ok, no need to mess with enrol.
2544
            $access = true;
2553
            $access = true;
2545
 
2554
        } else {
2546
        } else {
2555
            if (isset($USER->enrol['enrolled'][$course->id])) {
2547
            if (isset($USER->enrol['enrolled'][$course->id])) {
2556
                if ($USER->enrol['enrolled'][$course->id] > time()) {
2548
                if ($USER->enrol['enrolled'][$course->id] > time()) {
Línea 2584... Línea 2576...
2584
                    if ($until == 0) {
2576
                    if ($until == 0) {
2585
                        $until = ENROL_MAX_TIMESTAMP;
2577
                        $until = ENROL_MAX_TIMESTAMP;
2586
                    }
2578
                    }
2587
                    $USER->enrol['enrolled'][$course->id] = $until;
2579
                    $USER->enrol['enrolled'][$course->id] = $until;
2588
                    $access = true;
2580
                    $access = true;
-
 
2581
 
2589
                } else if (core_course_category::can_view_course_info($course)) {
2582
                } else if (core_course_category::can_view_course_info($course)) {
2590
                    $params = array('courseid' => $course->id, 'status' => ENROL_INSTANCE_ENABLED);
2583
                    $params = array('courseid' => $course->id, 'status' => ENROL_INSTANCE_ENABLED);
2591
                    $instances = $DB->get_records('enrol', $params, 'sortorder, id ASC');
2584
                    $instances = $DB->get_records('enrol', $params, 'sortorder, id ASC');
2592
                    $enrols = enrol_get_plugins(true);
2585
                    $enrols = enrol_get_plugins(true);
2593
                    // First ask all enabled enrol instances in course if they want to auto enrol user.
2586
                    // First ask all enabled enrol instances in course if they want to auto enrol user.
Línea 2628... Línea 2621...
2628
                    }
2621
                    }
2629
                    $PAGE->set_context(null);
2622
                    $PAGE->set_context(null);
2630
                    // We need to override the navigation URL as the course won't have been added to the navigation and thus
2623
                    // We need to override the navigation URL as the course won't have been added to the navigation and thus
2631
                    // the navigation will mess up when trying to find it.
2624
                    // the navigation will mess up when trying to find it.
2632
                    navigation_node::override_active_url(new moodle_url('/'));
2625
                    navigation_node::override_active_url(new moodle_url('/'));
2633
                    notice(get_string('coursehidden'), $CFG->wwwroot . '/');
2626
                    notice(get_string('coursehidden'), $CFG->wwwroot .'/');
2634
                }
2627
                }
2635
            }
2628
            }
2636
        }
2629
        }
Línea 2637... Línea 2630...
2637
 
2630
 
Línea 2640... Línea 2633...
2640
                throw new require_login_exception('Not enrolled');
2633
                throw new require_login_exception('Not enrolled');
2641
            }
2634
            }
2642
            if ($setwantsurltome) {
2635
            if ($setwantsurltome) {
2643
                $SESSION->wantsurl = qualified_me();
2636
                $SESSION->wantsurl = qualified_me();
2644
            }
2637
            }
2645
            redirect($CFG->wwwroot . '/enrol/index.php?id=' . $course->id);
2638
            redirect($CFG->wwwroot .'/enrol/index.php?id='. $course->id);
2646
        }
2639
        }
2647
    }
2640
    }
Línea 2648... Línea 2641...
2648
 
2641
 
2649
    // Check whether the activity has been scheduled for deletion. If so, then deny access, even for admins.
2642
    // Check whether the activity has been scheduled for deletion. If so, then deny access, even for admins.
Línea 2690... Línea 2683...
2690
 
2683
 
2691
/**
2684
/**
2692
 * A convenience function for where we must be logged in as admin
2685
 * A convenience function for where we must be logged in as admin
2693
 * @return void
2686
 * @return void
2694
 */
2687
 */
2695
function require_admin()
-
 
2696
{
2688
function require_admin() {
2697
    require_login(null, false);
2689
    require_login(null, false);
2698
    require_capability('moodle/site:config', context_system::instance());
2690
    require_capability('moodle/site:config', context_system::instance());
Línea 2699... Línea 2691...
2699
}
2691
}
2700
 
2692
 
2701
/**
2693
/**
2702
 * This function just makes sure a user is logged out.
2694
 * This function just makes sure a user is logged out.
2703
 *
2695
 *
2704
 * @package    core_access
2696
 * @package    core_access
2705
 * @category   access
2697
 * @category   access
2706
 */
-
 
2707
function require_logout()
2698
 */
Línea 2708... Línea 2699...
2708
{
2699
function require_logout() {
2709
    global $USER, $DB;
2700
    global $USER, $DB;
2710
 
2701
 
Línea 2729... Línea 2720...
2729
            'userid' => $USER->id,
2720
            'userid' => $USER->id,
2730
            'objectid' => $USER->id,
2721
            'objectid' => $USER->id,
2731
            'other' => array('sessionid' => $sid),
2722
            'other' => array('sessionid' => $sid),
2732
        )
2723
        )
2733
    );
2724
    );
2734
    if ($session = $DB->get_record('sessions', array('sid' => $sid))) {
2725
    $session = \core\session\manager::get_session_by_sid($sid);
-
 
2726
    if (isset($session->id)) {
2735
        $event->add_record_snapshot('sessions', $session);
2727
        $event->add_record_snapshot('sessions', $session);
2736
    }
2728
    }
Línea 2737... Línea 2729...
2737
 
2729
 
2738
    // Clone of $USER object to be used by auth plugins.
2730
    // Clone of $USER object to be used by auth plugins.
Línea 2769... Línea 2761...
2769
 *             in order to keep redirects working properly. MDL-14495
2761
 *             in order to keep redirects working properly. MDL-14495
2770
 * @param bool $preventredirect set to true in scripts that can not redirect (CLI, rss feeds, etc.), throws exceptions
2762
 * @param bool $preventredirect set to true in scripts that can not redirect (CLI, rss feeds, etc.), throws exceptions
2771
 * @return void
2763
 * @return void
2772
 * @throws coding_exception
2764
 * @throws coding_exception
2773
 */
2765
 */
2774
function require_course_login($courseorid, $autologinguest = true, $cm = null, $setwantsurltome = true, $preventredirect = false)
2766
function require_course_login($courseorid, $autologinguest = true, $cm = null, $setwantsurltome = true, $preventredirect = false) {
2775
{
-
 
2776
    global $CFG, $PAGE, $SITE;
2767
    global $CFG, $PAGE, $SITE;
2777
    $issite = ((is_object($courseorid) and $courseorid->id == SITEID)
2768
    $issite = ((is_object($courseorid) and $courseorid->id == SITEID)
2778
        or (!is_object($courseorid) and $courseorid == SITEID));
2769
          or (!is_object($courseorid) and $courseorid == SITEID));
2779
    if ($issite && !empty($cm) && !($cm instanceof cm_info)) {
2770
    if ($issite && !empty($cm) && !($cm instanceof cm_info)) {
2780
        // Note: nearly all pages call get_fast_modinfo anyway and it does not make any
2771
        // Note: nearly all pages call get_fast_modinfo anyway and it does not make any
2781
        // db queries so this is not really a performance concern, however it is obviously
2772
        // db queries so this is not really a performance concern, however it is obviously
2782
        // better if you use get_fast_modinfo to get the cm before calling this.
2773
        // better if you use get_fast_modinfo to get the cm before calling this.
2783
        if (is_object($courseorid)) {
2774
        if (is_object($courseorid)) {
2784
            $course = $courseorid;
2775
            $course = $courseorid;
2785
        } else {
2776
        } else {
2786
            $course = clone ($SITE);
2777
            $course = clone($SITE);
2787
        }
2778
        }
2788
        $modinfo = get_fast_modinfo($course);
2779
        $modinfo = get_fast_modinfo($course);
2789
        $cm = $modinfo->get_cm($cm->id);
2780
        $cm = $modinfo->get_cm($cm->id);
2790
    }
2781
    }
2791
    if (!empty($CFG->forcelogin)) {
2782
    if (!empty($CFG->forcelogin)) {
2792
        // Login required for both SITE and courses.
2783
        // Login required for both SITE and courses.
2793
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
2784
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
-
 
2785
 
2794
    } else if ($issite && !empty($cm) and !$cm->uservisible) {
2786
    } else if ($issite && !empty($cm) and !$cm->uservisible) {
2795
        // Always login for hidden activities.
2787
        // Always login for hidden activities.
2796
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
2788
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
-
 
2789
 
2797
    } else if (isloggedin() && !isguestuser()) {
2790
    } else if (isloggedin() && !isguestuser()) {
2798
        // User is already logged in. Make sure the login is complete (user is fully setup, policies agreed).
2791
        // User is already logged in. Make sure the login is complete (user is fully setup, policies agreed).
2799
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
2792
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
-
 
2793
 
2800
    } else if ($issite) {
2794
    } else if ($issite) {
2801
        // Login for SITE not required.
2795
        // Login for SITE not required.
2802
        // We still need to instatiate PAGE vars properly so that things that rely on it like navigation function correctly.
2796
        // We still need to instatiate PAGE vars properly so that things that rely on it like navigation function correctly.
2803
        if (!empty($courseorid)) {
2797
        if (!empty($courseorid)) {
2804
            if (is_object($courseorid)) {
2798
            if (is_object($courseorid)) {
Línea 2822... Línea 2816...
2822
        // Do not update access time for webservice or ajax requests.
2816
        // Do not update access time for webservice or ajax requests.
2823
        if (!WS_SERVER && !AJAX_SCRIPT) {
2817
        if (!WS_SERVER && !AJAX_SCRIPT) {
2824
            user_accesstime_log(SITEID);
2818
            user_accesstime_log(SITEID);
2825
        }
2819
        }
2826
        return;
2820
        return;
-
 
2821
 
2827
    } else {
2822
    } else {
2828
        // Course login always required.
2823
        // Course login always required.
2829
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
2824
        require_login($courseorid, $autologinguest, $cm, $setwantsurltome, $preventredirect);
2830
    }
2825
    }
2831
}
2826
}
Línea 2838... Línea 2833...
2838
 * @param  int $instance    instance id
2833
 * @param  int $instance    instance id
2839
 * @return stdClass the key entry in the user_private_key table
2834
 * @return stdClass the key entry in the user_private_key table
2840
 * @since Moodle 3.2
2835
 * @since Moodle 3.2
2841
 * @throws moodle_exception
2836
 * @throws moodle_exception
2842
 */
2837
 */
2843
function validate_user_key($keyvalue, $script, $instance)
2838
function validate_user_key($keyvalue, $script, $instance) {
2844
{
-
 
2845
    global $DB;
2839
    global $DB;
Línea 2846... Línea 2840...
2846
 
2840
 
2847
    if (!$key = $DB->get_record('user_private_key', array('script' => $script, 'value' => $keyvalue, 'instance' => $instance))) {
2841
    if (!$key = $DB->get_record('user_private_key', array('script' => $script, 'value' => $keyvalue, 'instance' => $instance))) {
2848
        throw new \moodle_exception('invalidkey');
2842
        throw new \moodle_exception('invalidkey');
Línea 2869... Línea 2863...
2869
 * @param string $script unique script identifier
2863
 * @param string $script unique script identifier
2870
 * @param int $instance optional instance id
2864
 * @param int $instance optional instance id
2871
 * @param string $keyvalue The key. If not supplied, this will be fetched from the current session.
2865
 * @param string $keyvalue The key. If not supplied, this will be fetched from the current session.
2872
 * @return int Instance ID
2866
 * @return int Instance ID
2873
 */
2867
 */
2874
function require_user_key_login($script, $instance = null, $keyvalue = null)
2868
function require_user_key_login($script, $instance = null, $keyvalue = null) {
2875
{
-
 
2876
    global $DB;
2869
    global $DB;
Línea 2877... Línea 2870...
2877
 
2870
 
2878
    if (!NO_MOODLE_COOKIES) {
2871
    if (!NO_MOODLE_COOKIES) {
2879
        throw new \moodle_exception('sessioncookiesdisable');
2872
        throw new \moodle_exception('sessioncookiesdisable');
Línea 2915... Línea 2908...
2915
 * @param int $instance optional instance id
2908
 * @param int $instance optional instance id
2916
 * @param string $iprestriction optional ip restricted access
2909
 * @param string $iprestriction optional ip restricted access
2917
 * @param int $validuntil key valid only until given data
2910
 * @param int $validuntil key valid only until given data
2918
 * @return string access key value
2911
 * @return string access key value
2919
 */
2912
 */
2920
function create_user_key($script, $userid, $instance = null, $iprestriction = null, $validuntil = null)
2913
function create_user_key($script, $userid, $instance=null, $iprestriction=null, $validuntil=null) {
2921
{
-
 
2922
    global $DB;
2914
    global $DB;
Línea 2923... Línea 2915...
2923
 
2915
 
2924
    $key = new stdClass();
2916
    $key = new stdClass();
2925
    $key->script        = $script;
2917
    $key->script        = $script;
Línea 2928... Línea 2920...
2928
    $key->iprestriction = $iprestriction;
2920
    $key->iprestriction = $iprestriction;
2929
    $key->validuntil    = $validuntil;
2921
    $key->validuntil    = $validuntil;
2930
    $key->timecreated   = time();
2922
    $key->timecreated   = time();
Línea 2931... Línea 2923...
2931
 
2923
 
2932
    // Something long and unique.
2924
    // Something long and unique.
2933
    $key->value         = md5($userid . '_' . time() . random_string(40));
2925
    $key->value         = md5($userid.'_'.time().random_string(40));
2934
    while ($DB->record_exists('user_private_key', array('value' => $key->value))) {
2926
    while ($DB->record_exists('user_private_key', array('value' => $key->value))) {
2935
        // Must be unique.
2927
        // Must be unique.
2936
        $key->value     = md5($userid . '_' . time() . random_string(40));
2928
        $key->value     = md5($userid.'_'.time().random_string(40));
2937
    }
2929
    }
2938
    $DB->insert_record('user_private_key', $key);
2930
    $DB->insert_record('user_private_key', $key);
2939
    return $key->value;
2931
    return $key->value;
Línea 2944... Línea 2936...
2944
 *
2936
 *
2945
 * @param string $script unique target identifier
2937
 * @param string $script unique target identifier
2946
 * @param int $userid
2938
 * @param int $userid
2947
 * @return void
2939
 * @return void
2948
 */
2940
 */
2949
function delete_user_key($script, $userid)
2941
function delete_user_key($script, $userid) {
2950
{
-
 
2951
    global $DB;
2942
    global $DB;
2952
    $DB->delete_records('user_private_key', array('script' => $script, 'userid' => $userid));
2943
    $DB->delete_records('user_private_key', array('script' => $script, 'userid' => $userid));
2953
}
2944
}
Línea 2954... Línea 2945...
2954
 
2945
 
Línea 2960... Línea 2951...
2960
 * @param int $instance optional instance id
2951
 * @param int $instance optional instance id
2961
 * @param string $iprestriction optional ip restricted access
2952
 * @param string $iprestriction optional ip restricted access
2962
 * @param int $validuntil key valid only until given date
2953
 * @param int $validuntil key valid only until given date
2963
 * @return string access key value
2954
 * @return string access key value
2964
 */
2955
 */
2965
function get_user_key($script, $userid, $instance = null, $iprestriction = null, $validuntil = null)
2956
function get_user_key($script, $userid, $instance=null, $iprestriction=null, $validuntil=null) {
2966
{
-
 
2967
    global $DB;
2957
    global $DB;
Línea 2968... Línea 2958...
2968
 
2958
 
2969
    if ($key = $DB->get_record('user_private_key', array(
-
 
2970
        'script' => $script,
-
 
2971
        'userid' => $userid,
-
 
2972
        'instance' => $instance,
2959
    if ($key = $DB->get_record('user_private_key', array('script' => $script, 'userid' => $userid,
2973
        'iprestriction' => $iprestriction,
2960
                                                         'instance' => $instance, 'iprestriction' => $iprestriction,
2974
        'validuntil' => $validuntil
-
 
2975
    ))) {
2961
                                                         'validuntil' => $validuntil))) {
2976
        return $key->value;
2962
        return $key->value;
2977
    } else {
2963
    } else {
2978
        return create_user_key($script, $userid, $instance, $iprestriction, $validuntil);
2964
        return create_user_key($script, $userid, $instance, $iprestriction, $validuntil);
2979
    }
2965
    }
Línea 2983... Línea 2969...
2983
/**
2969
/**
2984
 * Modify the user table by setting the currently logged in user's last login to now.
2970
 * Modify the user table by setting the currently logged in user's last login to now.
2985
 *
2971
 *
2986
 * @return bool Always returns true
2972
 * @return bool Always returns true
2987
 */
2973
 */
2988
function update_user_login_times()
2974
function update_user_login_times() {
2989
{
-
 
2990
    global $USER, $DB, $SESSION;
2975
    global $USER, $DB, $SESSION;
Línea 2991... Línea 2976...
2991
 
2976
 
2992
    if (isguestuser()) {
2977
    if (isguestuser()) {
2993
        // Do not update guest access times/ips for performance.
2978
        // Do not update guest access times/ips for performance.
Línea 3036... Línea 3021...
3036
 *
3021
 *
3037
 * @param stdClass $user A {@link $USER} object to test for the existence of a valid name and email
3022
 * @param stdClass $user A {@link $USER} object to test for the existence of a valid name and email
3038
 * @param bool $strict Be more strict and assert id and custom profile fields set, too
3023
 * @param bool $strict Be more strict and assert id and custom profile fields set, too
3039
 * @return bool
3024
 * @return bool
3040
 */
3025
 */
3041
function user_not_fully_set_up($user, $strict = true)
3026
function user_not_fully_set_up($user, $strict = true) {
3042
{
-
 
3043
    global $CFG, $SESSION, $USER;
3027
    global $CFG, $SESSION, $USER;
3044
    require_once($CFG->dirroot . '/user/profile/lib.php');
3028
    require_once($CFG->dirroot.'/user/profile/lib.php');
Línea 3045... Línea 3029...
3045
 
3029
 
3046
    // If the user is setup then store this in the session to avoid re-checking.
3030
    // If the user is setup then store this in the session to avoid re-checking.
3047
    // Some edge cases are when the users email starts to bounce or the
3031
    // Some edge cases are when the users email starts to bounce or the
3048
    // configuration for custom fields has changed while they are logged in so
3032
    // configuration for custom fields has changed while they are logged in so
3049
    // we re-check this fully every hour for the rare cases it has changed.
-
 
3050
    if (
3033
    // we re-check this fully every hour for the rare cases it has changed.
3051
        isset($USER->id) && isset($user->id) && $USER->id === $user->id &&
3034
    if (isset($USER->id) && isset($user->id) && $USER->id === $user->id &&
3052
        isset($SESSION->fullysetupstrict) && (time() - $SESSION->fullysetupstrict) < HOURSECS
-
 
3053
    ) {
3035
         isset($SESSION->fullysetupstrict) && (time() - $SESSION->fullysetupstrict) < HOURSECS) {
3054
        return false;
3036
        return false;
Línea 3055... Línea 3037...
3055
    }
3037
    }
3056
 
3038
 
Línea 3082... Línea 3064...
3082
 * Check whether the user has exceeded the bounce threshold
3064
 * Check whether the user has exceeded the bounce threshold
3083
 *
3065
 *
3084
 * @param stdClass $user A {@link $USER} object
3066
 * @param stdClass $user A {@link $USER} object
3085
 * @return bool true => User has exceeded bounce threshold
3067
 * @return bool true => User has exceeded bounce threshold
3086
 */
3068
 */
3087
function over_bounce_threshold($user)
3069
function over_bounce_threshold($user) {
3088
{
-
 
3089
    global $CFG, $DB;
3070
    global $CFG, $DB;
Línea 3090... Línea 3071...
3090
 
3071
 
3091
    if (empty($CFG->handlebounces)) {
3072
    if (empty($CFG->handlebounces)) {
3092
        return false;
3073
        return false;
Línea 3104... Línea 3085...
3104
    if (empty($CFG->bounceratio)) {
3085
    if (empty($CFG->bounceratio)) {
3105
        $CFG->bounceratio = .20;
3086
        $CFG->bounceratio = .20;
3106
    }
3087
    }
3107
    $bouncecount = 0;
3088
    $bouncecount = 0;
3108
    $sendcount = 0;
3089
    $sendcount = 0;
3109
    if ($bounce = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_bounce_count'))) {
3090
    if ($bounce = $DB->get_record('user_preferences', array ('userid' => $user->id, 'name' => 'email_bounce_count'))) {
3110
        $bouncecount = $bounce->value;
3091
        $bouncecount = $bounce->value;
3111
    }
3092
    }
3112
    if ($send = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_send_count'))) {
3093
    if ($send = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_send_count'))) {
3113
        $sendcount = $send->value;
3094
        $sendcount = $send->value;
3114
    }
3095
    }
3115
    return ($bouncecount >= $CFG->minbounces && $bouncecount / $sendcount >= $CFG->bounceratio);
3096
    return ($bouncecount >= $CFG->minbounces && $bouncecount/$sendcount >= $CFG->bounceratio);
3116
}
3097
}
Línea 3117... Línea 3098...
3117
 
3098
 
3118
/**
3099
/**
3119
 * Used to increment or reset email sent count
3100
 * Used to increment or reset email sent count
3120
 *
3101
 *
3121
 * @param stdClass $user object containing an id
3102
 * @param stdClass $user object containing an id
3122
 * @param bool $reset will reset the count to 0
3103
 * @param bool $reset will reset the count to 0
3123
 * @return void
3104
 * @return void
3124
 */
3105
 */
3125
function set_send_count($user, $reset = false)
-
 
3126
{
3106
function set_send_count($user, $reset=false) {
Línea 3127... Línea 3107...
3127
    global $DB;
3107
    global $DB;
3128
 
3108
 
3129
    if (empty($user->id)) {
3109
    if (empty($user->id)) {
3130
        // No real (DB) user, nothing to do here.
3110
        // No real (DB) user, nothing to do here.
Línea 3131... Línea 3111...
3131
        return;
3111
        return;
3132
    }
3112
    }
3133
 
3113
 
3134
    if ($pref = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_send_count'))) {
3114
    if ($pref = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_send_count'))) {
3135
        $pref->value = (!empty($reset)) ? 0 : $pref->value + 1;
3115
        $pref->value = (!empty($reset)) ? 0 : $pref->value+1;
3136
        $DB->update_record('user_preferences', $pref);
3116
        $DB->update_record('user_preferences', $pref);
3137
    } else if (!empty($reset)) {
3117
    } else if (!empty($reset)) {
Línea 3148... Línea 3128...
3148
 * Increment or reset user's email bounce count
3128
 * Increment or reset user's email bounce count
3149
 *
3129
 *
3150
 * @param stdClass $user object containing an id
3130
 * @param stdClass $user object containing an id
3151
 * @param bool $reset will reset the count to 0
3131
 * @param bool $reset will reset the count to 0
3152
 */
3132
 */
3153
function set_bounce_count($user, $reset = false)
3133
function set_bounce_count($user, $reset=false) {
3154
{
-
 
3155
    global $DB;
3134
    global $DB;
Línea 3156... Línea 3135...
3156
 
3135
 
3157
    if ($pref = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_bounce_count'))) {
3136
    if ($pref = $DB->get_record('user_preferences', array('userid' => $user->id, 'name' => 'email_bounce_count'))) {
3158
        $pref->value = (!empty($reset)) ? 0 : $pref->value + 1;
3137
        $pref->value = (!empty($reset)) ? 0 : $pref->value+1;
3159
        $DB->update_record('user_preferences', $pref);
3138
        $DB->update_record('user_preferences', $pref);
3160
    } else if (!empty($reset)) {
3139
    } else if (!empty($reset)) {
3161
        // If it's not there and we're resetting, don't bother. Make a new one.
3140
        // If it's not there and we're resetting, don't bother. Make a new one.
3162
        $pref = new stdClass();
3141
        $pref = new stdClass();
Línea 3171... Línea 3150...
3171
 * Determines if the logged in user is currently moving an activity
3150
 * Determines if the logged in user is currently moving an activity
3172
 *
3151
 *
3173
 * @param int $courseid The id of the course being tested
3152
 * @param int $courseid The id of the course being tested
3174
 * @return bool
3153
 * @return bool
3175
 */
3154
 */
3176
function ismoving($courseid)
3155
function ismoving($courseid) {
3177
{
-
 
3178
    global $USER;
3156
    global $USER;
Línea 3179... Línea 3157...
3179
 
3157
 
3180
    if (!empty($USER->activitycopy)) {
3158
    if (!empty($USER->activitycopy)) {
3181
        return ($USER->activitycopycourse == $courseid);
3159
        return ($USER->activitycopycourse == $courseid);
Línea 3193... Línea 3171...
3193
 *
3171
 *
3194
 * @param stdClass $user A {@link $USER} object to get full name of.
3172
 * @param stdClass $user A {@link $USER} object to get full name of.
3195
 * @param bool $override If true then the alternativefullnameformat format rather than fullnamedisplay format will be used.
3173
 * @param bool $override If true then the alternativefullnameformat format rather than fullnamedisplay format will be used.
3196
 * @return string
3174
 * @return string
3197
 */
3175
 */
3198
function fullname($user, $override = false)
3176
function fullname($user, $override=false) {
3199
{
-
 
3200
    // Note: We do not intend to deprecate this function any time soon as it is too widely used at this time.
3177
    // Note: We do not intend to deprecate this function any time soon as it is too widely used at this time.
3201
    // Uses of it should be updated to use the new API and pass updated arguments.
3178
    // Uses of it should be updated to use the new API and pass updated arguments.
Línea 3202... Línea 3179...
3202
 
3179
 
3203
    // Return an empty string if there is no user.
3180
    // Return an empty string if there is no user.
Línea 3219... Línea 3196...
3219
 * @param string $prefix prefix to be added to all fields (including $additionalfields) e.g. authorfirstname.
3196
 * @param string $prefix prefix to be added to all fields (including $additionalfields) e.g. authorfirstname.
3220
 * @param array $additionalfields Additional fields to be matched with data in the second object.
3197
 * @param array $additionalfields Additional fields to be matched with data in the second object.
3221
 * The key can be set to the user table field name.
3198
 * The key can be set to the user table field name.
3222
 * @return object User name fields.
3199
 * @return object User name fields.
3223
 */
3200
 */
3224
function username_load_fields_from_object($addtoobject, $secondobject, $prefix = null, $additionalfields = null)
3201
function username_load_fields_from_object($addtoobject, $secondobject, $prefix = null, $additionalfields = null) {
3225
{
-
 
3226
    $fields = [];
3202
    $fields = [];
3227
    foreach (\core_user\fields::get_name_fields() as $field) {
3203
    foreach (\core_user\fields::get_name_fields() as $field) {
3228
        $fields[$field] = $prefix . $field;
3204
        $fields[$field] = $prefix . $field;
3229
    }
3205
    }
3230
    if ($additionalfields) {
3206
    if ($additionalfields) {
Línea 3256... Línea 3232...
3256
 *
3232
 *
3257
 * @param array $values Values to be found in the string format
3233
 * @param array $values Values to be found in the string format
3258
 * @param string $stringformat The string which may contain values being searched for.
3234
 * @param string $stringformat The string which may contain values being searched for.
3259
 * @return array An array of values in order according to placement in the string format.
3235
 * @return array An array of values in order according to placement in the string format.
3260
 */
3236
 */
3261
function order_in_string($values, $stringformat)
3237
function order_in_string($values, $stringformat) {
3262
{
-
 
3263
    $valuearray = array();
3238
    $valuearray = array();
3264
    foreach ($values as $value) {
3239
    foreach ($values as $value) {
3265
        $pattern = "/$value\b/";
3240
        $pattern = "/$value\b/";
3266
        // Using preg_match as strpos() may match values that are similar e.g. firstname and firstnamephonetic.
3241
        // Using preg_match as strpos() may match values that are similar e.g. firstname and firstnamephonetic.
3267
        if (preg_match($pattern, $stringformat)) {
3242
        if (preg_match($pattern, $stringformat)) {
Línea 3280... Línea 3255...
3280
 * Returns whether a given authentication plugin exists.
3255
 * Returns whether a given authentication plugin exists.
3281
 *
3256
 *
3282
 * @param string $auth Form of authentication to check for. Defaults to the global setting in {@link $CFG}.
3257
 * @param string $auth Form of authentication to check for. Defaults to the global setting in {@link $CFG}.
3283
 * @return boolean Whether the plugin is available.
3258
 * @return boolean Whether the plugin is available.
3284
 */
3259
 */
3285
function exists_auth_plugin($auth)
3260
function exists_auth_plugin($auth) {
3286
{
-
 
3287
    global $CFG;
3261
    global $CFG;
Línea 3288... Línea 3262...
3288
 
3262
 
3289
    if (file_exists("{$CFG->dirroot}/auth/$auth/auth.php")) {
3263
    if (file_exists("{$CFG->dirroot}/auth/$auth/auth.php")) {
3290
        return is_readable("{$CFG->dirroot}/auth/$auth/auth.php");
3264
        return is_readable("{$CFG->dirroot}/auth/$auth/auth.php");
Línea 3296... Línea 3270...
3296
 * Checks if a given plugin is in the list of enabled authentication plugins.
3270
 * Checks if a given plugin is in the list of enabled authentication plugins.
3297
 *
3271
 *
3298
 * @param string $auth Authentication plugin.
3272
 * @param string $auth Authentication plugin.
3299
 * @return boolean Whether the plugin is enabled.
3273
 * @return boolean Whether the plugin is enabled.
3300
 */
3274
 */
3301
function is_enabled_auth($auth)
3275
function is_enabled_auth($auth) {
3302
{
-
 
3303
    if (empty($auth)) {
3276
    if (empty($auth)) {
3304
        return false;
3277
        return false;
3305
    }
3278
    }
Línea 3306... Línea 3279...
3306
 
3279
 
Línea 3313... Línea 3286...
3313
 * Returns an authentication plugin instance.
3286
 * Returns an authentication plugin instance.
3314
 *
3287
 *
3315
 * @param string $auth name of authentication plugin
3288
 * @param string $auth name of authentication plugin
3316
 * @return auth_plugin_base An instance of the required authentication plugin.
3289
 * @return auth_plugin_base An instance of the required authentication plugin.
3317
 */
3290
 */
3318
function get_auth_plugin($auth)
3291
function get_auth_plugin($auth) {
3319
{
-
 
3320
    global $CFG;
3292
    global $CFG;
Línea 3321... Línea 3293...
3321
 
3293
 
3322
    // Check the plugin exists first.
3294
    // Check the plugin exists first.
3323
    if (! exists_auth_plugin($auth)) {
3295
    if (! exists_auth_plugin($auth)) {
Línea 3334... Línea 3306...
3334
 * Returns array of active auth plugins.
3306
 * Returns array of active auth plugins.
3335
 *
3307
 *
3336
 * @param bool $fix fix $CFG->auth if needed. Only set if logged in as admin.
3308
 * @param bool $fix fix $CFG->auth if needed. Only set if logged in as admin.
3337
 * @return array
3309
 * @return array
3338
 */
3310
 */
3339
function get_enabled_auth_plugins($fix = false)
3311
function get_enabled_auth_plugins($fix=false) {
3340
{
-
 
3341
    global $CFG;
3312
    global $CFG;
Línea 3342... Línea 3313...
3342
 
3313
 
Línea 3343... Línea 3314...
3343
    $default = array('manual', 'nologin');
3314
    $default = array('manual', 'nologin');
Línea 3378... Línea 3349...
3378
 * if method not specified then, global default is assumed
3349
 * if method not specified then, global default is assumed
3379
 *
3350
 *
3380
 * @param string $auth Form of authentication required
3351
 * @param string $auth Form of authentication required
3381
 * @return bool
3352
 * @return bool
3382
 */
3353
 */
3383
function is_internal_auth($auth)
3354
function is_internal_auth($auth) {
3384
{
-
 
3385
    // Throws error if bad $auth.
3355
    // Throws error if bad $auth.
3386
    $authplugin = get_auth_plugin($auth);
3356
    $authplugin = get_auth_plugin($auth);
3387
    return $authplugin->is_internal();
3357
    return $authplugin->is_internal();
3388
}
3358
}
Línea 3393... Línea 3363...
3393
 * Used in the login process to inform the user and allow him/her to reset the password
3363
 * Used in the login process to inform the user and allow him/her to reset the password
3394
 *
3364
 *
3395
 * @param string $username username to be checked
3365
 * @param string $username username to be checked
3396
 * @return bool
3366
 * @return bool
3397
 */
3367
 */
3398
function is_restored_user($username)
3368
function is_restored_user($username) {
3399
{
-
 
3400
    global $CFG, $DB;
3369
    global $CFG, $DB;
Línea 3401... Línea 3370...
3401
 
3370
 
3402
    return $DB->record_exists('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id, 'password' => 'restored'));
3371
    return $DB->record_exists('user', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id, 'password' => 'restored'));
Línea 3403... Línea 3372...
3403
}
3372
}
3404
 
3373
 
3405
/**
3374
/**
3406
 * Returns an array of user fields
3375
 * Returns an array of user fields
3407
 *
3376
 *
3408
 * @return array User field/column names
3377
 * @return array User field/column names
3409
 */
-
 
3410
function get_user_fieldnames()
3378
 */
Línea 3411... Línea 3379...
3411
{
3379
function get_user_fieldnames() {
3412
    global $DB;
3380
    global $DB;
3413
 
3381
 
Línea 3421... Línea 3389...
3421
/**
3389
/**
3422
 * Returns the string of the language for the new user.
3390
 * Returns the string of the language for the new user.
3423
 *
3391
 *
3424
 * @return string language for the new user
3392
 * @return string language for the new user
3425
 */
3393
 */
3426
function get_newuser_language()
3394
function get_newuser_language() {
3427
{
-
 
3428
    global $CFG, $SESSION;
3395
    global $CFG, $SESSION;
3429
    return (!empty($CFG->autolangusercreation) && !empty($SESSION->lang)) ? $SESSION->lang : $CFG->lang;
3396
    return (!empty($CFG->autolangusercreation) && !empty($SESSION->lang)) ? $SESSION->lang : $CFG->lang;
3430
}
3397
}
Línea 3431... Línea 3398...
3431
 
3398
 
Línea 3437... Línea 3404...
3437
 * @param string $username New user's username to add to record
3404
 * @param string $username New user's username to add to record
3438
 * @param string $password New user's password to add to record
3405
 * @param string $password New user's password to add to record
3439
 * @param string $auth Form of authentication required
3406
 * @param string $auth Form of authentication required
3440
 * @return stdClass A complete user object
3407
 * @return stdClass A complete user object
3441
 */
3408
 */
3442
function create_user_record($username, $password, $auth = 'manual')
3409
function create_user_record($username, $password, $auth = 'manual') {
3443
{
-
 
3444
    global $CFG, $DB, $SESSION;
3410
    global $CFG, $DB, $SESSION;
3445
    require_once($CFG->dirroot . '/user/profile/lib.php');
3411
    require_once($CFG->dirroot.'/user/profile/lib.php');
3446
    require_once($CFG->dirroot . '/user/lib.php');
3412
    require_once($CFG->dirroot.'/user/lib.php');
Línea 3447... Línea 3413...
3447
 
3413
 
3448
    // Just in case check text case.
3414
    // Just in case check text case.
Línea 3449... Línea 3415...
3449
    $username = trim(core_text::strtolower($username));
3415
    $username = trim(core_text::strtolower($username));
Línea 3485... Línea 3451...
3485
 
3451
 
3486
    // Save user profile data.
3452
    // Save user profile data.
Línea 3487... Línea 3453...
3487
    profile_save_data($newuser);
3453
    profile_save_data($newuser);
3488
 
3454
 
3489
    $user = get_complete_user_data('id', $newuser->id);
3455
    $user = get_complete_user_data('id', $newuser->id);
3490
    if (!empty($CFG->{'auth_' . $newuser->auth . '_forcechangepassword'})) {
3456
    if (!empty($CFG->{'auth_'.$newuser->auth.'_forcechangepassword'})) {
3491
        set_user_preference('auth_forcepasswordchange', 1, $user);
3457
        set_user_preference('auth_forcepasswordchange', 1, $user);
3492
    }
3458
    }
Línea 3503... Línea 3469...
3503
 * Will update a local user record from an external source (MNET users can not be updated using this method!).
3469
 * Will update a local user record from an external source (MNET users can not be updated using this method!).
3504
 *
3470
 *
3505
 * @param string $username user's username to update the record
3471
 * @param string $username user's username to update the record
3506
 * @return stdClass A complete user object
3472
 * @return stdClass A complete user object
3507
 */
3473
 */
3508
function update_user_record($username)
3474
function update_user_record($username) {
3509
{
-
 
3510
    global $DB, $CFG;
3475
    global $DB, $CFG;
3511
    // Just in case check text case.
3476
    // Just in case check text case.
3512
    $username = trim(core_text::strtolower($username));
3477
    $username = trim(core_text::strtolower($username));
Línea 3513... Línea 3478...
3513
 
3478
 
Línea 3519... Línea 3484...
3519
 * Will update a local user record from an external source (MNET users can not be updated using this method!).
3484
 * Will update a local user record from an external source (MNET users can not be updated using this method!).
3520
 *
3485
 *
3521
 * @param int $id user id
3486
 * @param int $id user id
3522
 * @return stdClass A complete user object
3487
 * @return stdClass A complete user object
3523
 */
3488
 */
3524
function update_user_record_by_id($id)
3489
function update_user_record_by_id($id) {
3525
{
-
 
3526
    global $DB, $CFG;
3490
    global $DB, $CFG;
3527
    require_once($CFG->dirroot . "/user/profile/lib.php");
3491
    require_once($CFG->dirroot."/user/profile/lib.php");
3528
    require_once($CFG->dirroot . '/user/lib.php');
3492
    require_once($CFG->dirroot.'/user/lib.php');
Línea 3529... Línea 3493...
3529
 
3493
 
3530
    $params = array('mnethostid' => $CFG->mnet_localhost_id, 'id' => $id, 'deleted' => 0);
3494
    $params = array('mnethostid' => $CFG->mnet_localhost_id, 'id' => $id, 'deleted' => 0);
Línea 3531... Línea 3495...
3531
    $oldinfo = $DB->get_record('user', $params, '*', MUST_EXIST);
3495
    $oldinfo = $DB->get_record('user', $params, '*', MUST_EXIST);
Línea 3541... Línea 3505...
3541
            $iscustom = in_array($key, $customfields);
3505
            $iscustom = in_array($key, $customfields);
3542
            if (!$iscustom) {
3506
            if (!$iscustom) {
3543
                $key = strtolower($key);
3507
                $key = strtolower($key);
3544
            }
3508
            }
3545
            if ((!property_exists($oldinfo, $key) && !$iscustom) or $key === 'username' or $key === 'id'
3509
            if ((!property_exists($oldinfo, $key) && !$iscustom) or $key === 'username' or $key === 'id'
3546
                or $key === 'auth' or $key === 'mnethostid' or $key === 'deleted'
3510
                    or $key === 'auth' or $key === 'mnethostid' or $key === 'deleted') {
3547
            ) {
-
 
3548
                // Unknown or must not be changed.
3511
                // Unknown or must not be changed.
3549
                continue;
3512
                continue;
3550
            }
3513
            }
3551
            if (empty($userauth->config->{'field_updatelocal_' . $key}) || empty($userauth->config->{'field_lock_' . $key})) {
3514
            if (empty($userauth->config->{'field_updatelocal_' . $key}) || empty($userauth->config->{'field_lock_' . $key})) {
3552
                continue;
3515
                continue;
Línea 3560... Línea 3523...
3560
                // in a value for the selected field _if LDAP is giving
3523
                // in a value for the selected field _if LDAP is giving
3561
                // nothing_ for this field. Thus it makes sense to let this value
3524
                // nothing_ for this field. Thus it makes sense to let this value
3562
                // stand in until LDAP is giving a value for this field.
3525
                // stand in until LDAP is giving a value for this field.
3563
                if (!(empty($value) && $lockval === 'unlockedifempty')) {
3526
                if (!(empty($value) && $lockval === 'unlockedifempty')) {
3564
                    if ($iscustom || (in_array($key, $userauth->userfields) &&
3527
                    if ($iscustom || (in_array($key, $userauth->userfields) &&
3565
                        ((string)$oldinfo->$key !== (string)$value))) {
3528
                            ((string)$oldinfo->$key !== (string)$value))) {
3566
                        $newuser[$key] = (string)$value;
3529
                        $newuser[$key] = (string)$value;
3567
                    }
3530
                    }
3568
                }
3531
                }
3569
            }
3532
            }
3570
        }
3533
        }
Línea 3588... Línea 3551...
3588
 * Will truncate userinfo as it comes from auth_get_userinfo (from external auth) which may have large fields.
3551
 * Will truncate userinfo as it comes from auth_get_userinfo (from external auth) which may have large fields.
3589
 *
3552
 *
3590
 * @param array $info Array of user properties to truncate if needed
3553
 * @param array $info Array of user properties to truncate if needed
3591
 * @return array The now truncated information that was passed in
3554
 * @return array The now truncated information that was passed in
3592
 */
3555
 */
3593
function truncate_userinfo(array $info)
3556
function truncate_userinfo(array $info) {
3594
{
-
 
3595
    // Define the limits.
3557
    // Define the limits.
3596
    $limit = array(
3558
    $limit = array(
3597
        'username'    => 100,
3559
        'username'    => 100,
3598
        'idnumber'    => 255,
3560
        'idnumber'    => 255,
3599
        'firstname'   => 100,
3561
        'firstname'   => 100,
Línea 3626... Línea 3588...
3626
 *
3588
 *
3627
 * @param stdClass $user full user object before delete
3589
 * @param stdClass $user full user object before delete
3628
 * @return boolean success
3590
 * @return boolean success
3629
 * @throws coding_exception if invalid $user parameter detected
3591
 * @throws coding_exception if invalid $user parameter detected
3630
 */
3592
 */
3631
function delete_user(stdClass $user)
3593
function delete_user(stdClass $user) {
3632
{
-
 
3633
    global $CFG, $DB, $SESSION;
3594
    global $CFG, $DB, $SESSION;
3634
    require_once($CFG->libdir . '/grouplib.php');
3595
    require_once($CFG->libdir.'/grouplib.php');
3635
    require_once($CFG->libdir . '/gradelib.php');
3596
    require_once($CFG->libdir.'/gradelib.php');
3636
    require_once($CFG->dirroot . '/message/lib.php');
3597
    require_once($CFG->dirroot.'/message/lib.php');
3637
    require_once($CFG->dirroot . '/user/lib.php');
3598
    require_once($CFG->dirroot.'/user/lib.php');
Línea 3638... Línea 3599...
3638
 
3599
 
3639
    // Make sure nobody sends bogus record type as parameter.
3600
    // Make sure nobody sends bogus record type as parameter.
3640
    if (!property_exists($user, 'id') or !property_exists($user, 'username')) {
3601
    if (!property_exists($user, 'id') or !property_exists($user, 'username')) {
3641
        throw new coding_exception('Invalid $user parameter in delete_user() detected');
3602
        throw new coding_exception('Invalid $user parameter in delete_user() detected');
Línea 3746... Línea 3707...
3746
    if (isset($SESSION->bulk_users[$user->id])) {
3707
    if (isset($SESSION->bulk_users[$user->id])) {
3747
        unset($SESSION->bulk_users[$user->id]);
3708
        unset($SESSION->bulk_users[$user->id]);
3748
    }
3709
    }
Línea 3749... Línea 3710...
3749
 
3710
 
3750
    // Force logout - may fail if file based sessions used, sorry.
3711
    // Force logout - may fail if file based sessions used, sorry.
Línea 3751... Línea 3712...
3751
    \core\session\manager::kill_user_sessions($user->id);
3712
    \core\session\manager::destroy_user_sessions($user->id);
3752
 
3713
 
Línea 3753... Línea 3714...
3753
    // Generate username from email address, or a fake email.
3714
    // Generate username from email address, or a fake email.
Línea 3779... Línea 3740...
3779
    // Mark internal user record as "deleted".
3740
    // Mark internal user record as "deleted".
3780
    $updateuser = new stdClass();
3741
    $updateuser = new stdClass();
3781
    $updateuser->id           = $user->id;
3742
    $updateuser->id           = $user->id;
3782
    $updateuser->deleted      = 1;
3743
    $updateuser->deleted      = 1;
3783
    $updateuser->username     = $delname;            // Remember it just in case.
3744
    $updateuser->username     = $delname;            // Remember it just in case.
3784
    $updateuser->email        = md5($user->username); // Store hash of username, useful importing/restoring users.
3745
    $updateuser->email        = md5($user->username);// Store hash of username, useful importing/restoring users.
3785
    $updateuser->idnumber     = '';                  // Clear this field to free it up.
3746
    $updateuser->idnumber     = '';                  // Clear this field to free it up.
3786
    $updateuser->picture      = 0;
3747
    $updateuser->picture      = 0;
3787
    $updateuser->timemodified = $deltime;
3748
    $updateuser->timemodified = $deltime;
Línea 3788... Línea 3749...
3788
 
3749
 
Línea 3796... Línea 3757...
3796
    \core_search\manager::context_deleted($usercontext);
3757
    \core_search\manager::context_deleted($usercontext);
Línea 3797... Línea 3758...
3797
 
3758
 
3798
    // Any plugin that needs to cleanup should register this event.
3759
    // Any plugin that needs to cleanup should register this event.
3799
    // Trigger event.
3760
    // Trigger event.
3800
    $event = \core\event\user_deleted::create(
3761
    $event = \core\event\user_deleted::create(
3801
        array(
3762
            array(
3802
            'objectid' => $user->id,
3763
                'objectid' => $user->id,
3803
            'relateduserid' => $user->id,
3764
                'relateduserid' => $user->id,
3804
            'context' => $usercontext,
3765
                'context' => $usercontext,
3805
            'other' => array(
3766
                'other' => array(
3806
                'username' => $user->username,
3767
                    'username' => $user->username,
3807
                'email' => $user->email,
3768
                    'email' => $user->email,
3808
                'idnumber' => $user->idnumber,
3769
                    'idnumber' => $user->idnumber,
3809
                'picture' => $user->picture,
3770
                    'picture' => $user->picture,
3810
                'mnethostid' => $user->mnethostid
3771
                    'mnethostid' => $user->mnethostid
3811
            )
3772
                    )
3812
        )
3773
                )
3813
    );
3774
            );
3814
    $event->add_record_snapshot('user', $olduser);
3775
    $event->add_record_snapshot('user', $olduser);
Línea 3815... Línea 3776...
3815
    $event->trigger();
3776
    $event->trigger();
3816
 
3777
 
Línea 3828... Línea 3789...
3828
/**
3789
/**
3829
 * Retrieve the guest user object.
3790
 * Retrieve the guest user object.
3830
 *
3791
 *
3831
 * @return stdClass A {@link $USER} object
3792
 * @return stdClass A {@link $USER} object
3832
 */
3793
 */
3833
function guest_user()
3794
function guest_user() {
3834
{
-
 
3835
    global $CFG, $DB;
3795
    global $CFG, $DB;
Línea 3836... Línea 3796...
3836
 
3796
 
3837
    if ($newuser = $DB->get_record('user', array('id' => $CFG->siteguest))) {
3797
    if ($newuser = $DB->get_record('user', array('id' => $CFG->siteguest))) {
3838
        $newuser->confirmed = 1;
3798
        $newuser->confirmed = 1;
Línea 3907... Línea 3867...
3907
                'username' => $username,
3867
                'username' => $username,
3908
                'reason' => $failurereason,
3868
                'reason' => $failurereason,
3909
            ],
3869
            ],
3910
        ])->trigger();
3870
        ])->trigger();
Línea 3911... Línea 3871...
3911
 
3871
 
3912
        error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Invalid Login Token:  $username  " . $_SERVER['HTTP_USER_AGENT']);
3872
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Invalid Login Token:  $username  ".$_SERVER['HTTP_USER_AGENT']);
3913
        return false;
3873
        return false;
Línea 3914... Línea 3874...
3914
    }
3874
    }
3915
 
3875
 
Línea 3940... Línea 3900...
3940
 
3900
 
3941
        if (!empty($user->suspended)) {
3901
        if (!empty($user->suspended)) {
Línea 3942... Línea 3902...
3942
            $failurereason = AUTH_LOGIN_SUSPENDED;
3902
            $failurereason = AUTH_LOGIN_SUSPENDED;
3943
 
3903
 
3944
            // Trigger login failed event.
-
 
3945
            $event = \core\event\user_login_failed::create(array(
3904
            // Trigger login failed event.
3946
                'userid' => $user->id,
-
 
3947
                'other' => array('username' => $username, 'reason' => $failurereason)
3905
            $event = \core\event\user_login_failed::create(array('userid' => $user->id,
3948
            ));
3906
                    'other' => array('username' => $username, 'reason' => $failurereason)));
3949
            $event->trigger();
3907
            $event->trigger();
3950
            error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Suspended Login:  $username  " . $_SERVER['HTTP_USER_AGENT']);
3908
            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Suspended Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
3951
            return false;
3909
            return false;
3952
        }
3910
        }
3953
        if ($auth == 'nologin' or !is_enabled_auth($auth)) {
3911
        if ($auth=='nologin' or !is_enabled_auth($auth)) {
Línea 3954... Línea 3912...
3954
            // Legacy way to suspend user.
3912
            // Legacy way to suspend user.
3955
            $failurereason = AUTH_LOGIN_SUSPENDED;
3913
            $failurereason = AUTH_LOGIN_SUSPENDED;
3956
 
-
 
3957
            // Trigger login failed event.
3914
 
3958
            $event = \core\event\user_login_failed::create(array(
-
 
3959
                'userid' => $user->id,
3915
            // Trigger login failed event.
3960
                'other' => array('username' => $username, 'reason' => $failurereason)
3916
            $event = \core\event\user_login_failed::create(array('userid' => $user->id,
3961
            ));
3917
                    'other' => array('username' => $username, 'reason' => $failurereason)));
3962
            $event->trigger();
3918
            $event->trigger();
3963
            error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Disabled Login:  $username  " . $_SERVER['HTTP_USER_AGENT']);
3919
            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Disabled Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
-
 
3920
            return false;
3964
            return false;
3921
        }
3965
        }
3922
        $auths = array($auth);
3966
        $auths = array($auth);
3923
 
3967
    } else {
3924
    } else {
Línea 3968... Línea 3925...
3968
        // Check if there's a deleted record (cheaply), this should not happen because we mangle usernames in delete_user().
3925
        // Check if there's a deleted record (cheaply), this should not happen because we mangle usernames in delete_user().
3969
        if ($DB->get_field('user', 'id', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id,  'deleted' => 1))) {
3926
        if ($DB->get_field('user', 'id', array('username' => $username, 'mnethostid' => $CFG->mnet_localhost_id,  'deleted' => 1))) {
3970
            $failurereason = AUTH_LOGIN_NOUSER;
-
 
3971
 
3927
            $failurereason = AUTH_LOGIN_NOUSER;
3972
            // Trigger login failed event.
-
 
3973
            $event = \core\event\user_login_failed::create(array('other' => array(
3928
 
3974
                'username' => $username,
3929
            // Trigger login failed event.
3975
                'reason' => $failurereason
3930
            $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
3976
            )));
3931
                    'reason' => $failurereason)));
Línea 3977... Línea 3932...
3977
            $event->trigger();
3932
            $event->trigger();
3978
            error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Deleted Login:  $username  " . $_SERVER['HTTP_USER_AGENT']);
3933
            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Deleted Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
Línea 3992... Línea 3947...
3992
        // Verify login lockout after other ways that may prevent user login.
3947
        // Verify login lockout after other ways that may prevent user login.
3993
        if (login_is_lockedout($user)) {
3948
        if (login_is_lockedout($user)) {
3994
            $failurereason = AUTH_LOGIN_LOCKOUT;
3949
            $failurereason = AUTH_LOGIN_LOCKOUT;
Línea 3995... Línea 3950...
3995
 
3950
 
3996
            // Trigger login failed event.
3951
            // Trigger login failed event.
3997
            $event = \core\event\user_login_failed::create(array(
-
 
3998
                'userid' => $user->id,
3952
            $event = \core\event\user_login_failed::create(array('userid' => $user->id,
3999
                'other' => array('username' => $username, 'reason' => $failurereason)
-
 
4000
            ));
3953
                    'other' => array('username' => $username, 'reason' => $failurereason)));
Línea 4001... Línea 3954...
4001
            $event->trigger();
3954
            $event->trigger();
4002
 
3955
 
Línea 4003... Línea 3956...
4003
            error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Login lockout:  $username  " . $_SERVER['HTTP_USER_AGENT']);
3956
            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Login lockout:  $username  ".$_SERVER['HTTP_USER_AGENT']);
4004
            $SESSION->loginerrormsg = get_string('accountlocked', 'admin');
3957
            $SESSION->loginerrormsg = get_string('accountlocked', 'admin');
4005
 
3958
 
Línea 4074... Línea 4027...
4074
            // The user is authenticated but user creation may be disabled.
4027
            // The user is authenticated but user creation may be disabled.
4075
            if (!empty($CFG->authpreventaccountcreation)) {
4028
            if (!empty($CFG->authpreventaccountcreation)) {
4076
                $failurereason = AUTH_LOGIN_UNAUTHORISED;
4029
                $failurereason = AUTH_LOGIN_UNAUTHORISED;
Línea 4077... Línea 4030...
4077
 
4030
 
4078
                // Trigger login failed event.
4031
                // Trigger login failed event.
4079
                $event = \core\event\user_login_failed::create(array('other' => array(
-
 
4080
                    'username' => $username,
4032
                $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
4081
                    'reason' => $failurereason
-
 
4082
                )));
4033
                        'reason' => $failurereason)));
Línea 4083... Línea 4034...
4083
                $event->trigger();
4034
                $event->trigger();
4084
 
4035
 
4085
                error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Unknown user, can not create new accounts:  $username  " .
4036
                error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Unknown user, can not create new accounts:  $username  ".
4086
                    $_SERVER['HTTP_USER_AGENT']);
4037
                        $_SERVER['HTTP_USER_AGENT']);
4087
                return false;
4038
                return false;
4088
            } else {
4039
            } else {
4089
                $user = create_user_record($username, $password, $auth);
4040
                $user = create_user_record($username, $password, $auth);
Línea 4098... Línea 4049...
4098
        }
4049
        }
Línea 4099... Línea 4050...
4099
 
4050
 
4100
        if (empty($user->id)) {
4051
        if (empty($user->id)) {
4101
            $failurereason = AUTH_LOGIN_NOUSER;
4052
            $failurereason = AUTH_LOGIN_NOUSER;
4102
            // Trigger login failed event.
4053
            // Trigger login failed event.
4103
            $event = \core\event\user_login_failed::create(array('other' => array(
-
 
4104
                'username' => $username,
4054
            $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
4105
                'reason' => $failurereason
-
 
4106
            )));
4055
                    'reason' => $failurereason)));
4107
            $event->trigger();
4056
            $event->trigger();
4108
            return false;
4057
            return false;
Línea 4109... Línea 4058...
4109
        }
4058
        }
4110
 
4059
 
4111
        if (!empty($user->suspended)) {
4060
        if (!empty($user->suspended)) {
4112
            // Just in case some auth plugin suspended account.
4061
            // Just in case some auth plugin suspended account.
4113
            $failurereason = AUTH_LOGIN_SUSPENDED;
4062
            $failurereason = AUTH_LOGIN_SUSPENDED;
4114
            // Trigger login failed event.
-
 
4115
            $event = \core\event\user_login_failed::create(array(
4063
            // Trigger login failed event.
4116
                'userid' => $user->id,
-
 
4117
                'other' => array('username' => $username, 'reason' => $failurereason)
4064
            $event = \core\event\user_login_failed::create(array('userid' => $user->id,
4118
            ));
4065
                    'other' => array('username' => $username, 'reason' => $failurereason)));
4119
            $event->trigger();
4066
            $event->trigger();
4120
            error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Suspended Login:  $username  " . $_SERVER['HTTP_USER_AGENT']);
4067
            error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Suspended Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
Línea 4121... Línea 4068...
4121
            return false;
4068
            return false;
4122
        }
4069
        }
4123
 
4070
 
4124
        login_attempt_valid($user);
4071
        login_attempt_valid($user);
Línea 4125... Línea 4072...
4125
        $failurereason = AUTH_LOGIN_OK;
4072
        $failurereason = AUTH_LOGIN_OK;
4126
        return $user;
4073
        return $user;
4127
    }
4074
    }
4128
 
4075
 
Línea 4129... Línea 4076...
4129
    // Failed if all the plugins have failed.
4076
    // Failed if all the plugins have failed.
4130
    if (debugging('', DEBUG_ALL)) {
4077
    if (debugging('', DEBUG_ALL)) {
4131
        error_log('[client ' . getremoteaddr() . "]  $CFG->wwwroot  Failed Login:  $username  " . $_SERVER['HTTP_USER_AGENT']);
4078
        error_log('[client '.getremoteaddr()."]  $CFG->wwwroot  Failed Login:  $username  ".$_SERVER['HTTP_USER_AGENT']);
4132
    }
4079
    }
4133
 
4080
 
4134
    if ($user->id) {
-
 
4135
        login_attempt_failed($user);
4081
    if ($user->id) {
4136
        $failurereason = AUTH_LOGIN_FAILED;
-
 
4137
        // Trigger login failed event.
4082
        login_attempt_failed($user);
4138
        $event = \core\event\user_login_failed::create(array(
4083
        $failurereason = AUTH_LOGIN_FAILED;
4139
            'userid' => $user->id,
4084
        // Trigger login failed event.
4140
            'other' => array('username' => $username, 'reason' => $failurereason)
4085
        $event = \core\event\user_login_failed::create(array('userid' => $user->id,
4141
        ));
4086
                'other' => array('username' => $username, 'reason' => $failurereason)));
4142
        $event->trigger();
-
 
4143
    } else {
4087
        $event->trigger();
4144
        $failurereason = AUTH_LOGIN_NOUSER;
-
 
4145
        // Trigger login failed event.
4088
    } else {
4146
        $event = \core\event\user_login_failed::create(array('other' => array(
4089
        $failurereason = AUTH_LOGIN_NOUSER;
Línea 4147... Línea 4090...
4147
            'username' => $username,
4090
        // Trigger login failed event.
4148
            'reason' => $failurereason
4091
        $event = \core\event\user_login_failed::create(array('other' => array('username' => $username,
Línea 4164... Línea 4107...
4164
 *
4107
 *
4165
 * @param stdClass $user
4108
 * @param stdClass $user
4166
 * @param array $extrauserinfo
4109
 * @param array $extrauserinfo
4167
 * @return stdClass A {@link $USER} object - BC only, do not use
4110
 * @return stdClass A {@link $USER} object - BC only, do not use
4168
 */
4111
 */
4169
function complete_user_login($user, array $extrauserinfo = [])
4112
function complete_user_login($user, array $extrauserinfo = []) {
4170
{
-
 
4171
    global $CFG, $DB, $USER, $SESSION;
4113
    global $CFG, $DB, $USER, $SESSION;
Línea 4172... Línea 4114...
4172
 
4114
 
Línea 4173... Línea 4115...
4173
    \core\session\manager::login_user($user);
4115
    \core\session\manager::login_user($user);
Línea 4262... Línea 4204...
4262
            if ($changeurl = $userauth->change_password_url()) {
4204
            if ($changeurl = $userauth->change_password_url()) {
4263
                redirect($changeurl);
4205
                redirect($changeurl);
4264
            } else {
4206
            } else {
4265
                require_once($CFG->dirroot . '/login/lib.php');
4207
                require_once($CFG->dirroot . '/login/lib.php');
4266
                $SESSION->wantsurl = core_login_get_return_url();
4208
                $SESSION->wantsurl = core_login_get_return_url();
4267
                redirect($CFG->wwwroot . '/login/change_password.php');
4209
                redirect($CFG->wwwroot.'/login/change_password.php');
4268
            }
4210
            }
4269
        } else {
4211
        } else {
4270
            throw new \moodle_exception('nopasswordchangeforced', 'auth');
4212
            throw new \moodle_exception('nopasswordchangeforced', 'auth');
4271
        }
4213
        }
4272
    }
4214
    }
Línea 4277... Línea 4219...
4277
 * Check a password hash to see if it was hashed using the legacy hash algorithm (bcrypt).
4219
 * Check a password hash to see if it was hashed using the legacy hash algorithm (bcrypt).
4278
 *
4220
 *
4279
 * @param string $password String to check.
4221
 * @param string $password String to check.
4280
 * @return bool True if the $password matches the format of a bcrypt hash.
4222
 * @return bool True if the $password matches the format of a bcrypt hash.
4281
 */
4223
 */
4282
function password_is_legacy_hash(#[\SensitiveParameter] string $password): bool
4224
function password_is_legacy_hash(#[\SensitiveParameter] string $password): bool {
4283
{
-
 
4284
    return (bool) preg_match('/^\$2y\$[\d]{2}\$[A-Za-z0-9\.\/]{53}$/', $password);
4225
    return (bool) preg_match('/^\$2y\$[\d]{2}\$[A-Za-z0-9\.\/]{53}$/', $password);
4285
}
4226
}
Línea 4286... Línea 4227...
4286
 
4227
 
4287
/**
4228
/**
4288
 * Calculate the Shannon entropy of a string.
4229
 * Calculate the Shannon entropy of a string.
4289
 *
4230
 *
4290
 * @param string $pepper The pepper to calculate the entropy of.
4231
 * @param string $pepper The pepper to calculate the entropy of.
4291
 * @return float The Shannon entropy of the string.
4232
 * @return float The Shannon entropy of the string.
4292
 */
4233
 */
4293
function calculate_entropy(#[\SensitiveParameter] string $pepper): float
-
 
4294
{
4234
function calculate_entropy(#[\SensitiveParameter] string $pepper): float {
4295
    // Initialize entropy.
4235
    // Initialize entropy.
Línea 4296... Línea 4236...
4296
    $h = 0;
4236
    $h = 0;
4297
 
4237
 
Línea 4322... Línea 4262...
4322
 * Also, we allow the latest pepper to be empty, to allow admins to migrate off peppers.
4262
 * Also, we allow the latest pepper to be empty, to allow admins to migrate off peppers.
4323
 *
4263
 *
4324
 * @return array The password peppers.
4264
 * @return array The password peppers.
4325
 * @throws coding_exception If the entropy of the password pepper is less than the recommended minimum.
4265
 * @throws coding_exception If the entropy of the password pepper is less than the recommended minimum.
4326
 */
4266
 */
4327
function get_password_peppers(): array
4267
function get_password_peppers(): array {
4328
{
-
 
4329
    global $CFG;
4268
    global $CFG;
Línea 4330... Línea 4269...
4330
 
4269
 
4331
    // Get all available peppers.
4270
    // Get all available peppers.
4332
    if (isset($CFG->passwordpeppers) && is_array($CFG->passwordpeppers)) {
4271
    if (isset($CFG->passwordpeppers) && is_array($CFG->passwordpeppers)) {
Línea 4340... Línea 4279...
4340
    // Check if the entropy of the most recent pepper is less than the minimum.
4279
    // Check if the entropy of the most recent pepper is less than the minimum.
4341
    // Also, we allow the most recent pepper to be empty, to allow admins to migrate off peppers.
4280
    // Also, we allow the most recent pepper to be empty, to allow admins to migrate off peppers.
4342
    $lastpepper = reset($peppers);
4281
    $lastpepper = reset($peppers);
4343
    if (!empty($peppers) && $lastpepper !== '' && calculate_entropy($lastpepper) < PEPPER_ENTROPY) {
4282
    if (!empty($peppers) && $lastpepper !== '' && calculate_entropy($lastpepper) < PEPPER_ENTROPY) {
4344
        throw new coding_exception(
4283
        throw new coding_exception(
4345
            'password pepper below minimum',
4284
                'password pepper below minimum',
4346
            'The entropy of the password pepper is less than the recommended minimum.'
4285
                'The entropy of the password pepper is less than the recommended minimum.');
4347
        );
-
 
4348
    }
4286
    }
4349
    return $peppers;
4287
    return $peppers;
4350
}
4288
}
Línea 4351... Línea 4289...
4351
 
4289
 
Línea 4356... Línea 4294...
4356
 *
4294
 *
4357
 * @param stdClass $user (Password property may be updated).
4295
 * @param stdClass $user (Password property may be updated).
4358
 * @param string $password Plain text password.
4296
 * @param string $password Plain text password.
4359
 * @return bool True if password is valid.
4297
 * @return bool True if password is valid.
4360
 */
4298
 */
4361
function validate_internal_user_password(stdClass $user, #[\SensitiveParameter] string $password): bool
4299
function validate_internal_user_password(stdClass $user, #[\SensitiveParameter] string $password): bool {
4362
{
-
 
Línea 4363... Línea 4300...
4363
 
4300
 
4364
    if (exceeds_password_length($password)) {
4301
    if (exceeds_password_length($password)) {
4365
        // Password cannot be more than MAX_PASSWORD_CHARACTERS characters.
4302
        // Password cannot be more than MAX_PASSWORD_CHARACTERS characters.
4366
        return false;
4303
        return false;
Línea 4411... Línea 4348...
4411
 * @param int $pepperlength Lenght of the peppers
4348
 * @param int $pepperlength Lenght of the peppers
4412
 * @return string The hashed password.
4349
 * @return string The hashed password.
4413
 *
4350
 *
4414
 * @throws moodle_exception If a problem occurs while generating the hash.
4351
 * @throws moodle_exception If a problem occurs while generating the hash.
4415
 */
4352
 */
4416
function hash_internal_user_password(#[\SensitiveParameter] string $password, $fasthash = false, $pepperlength = 0): string
4353
function hash_internal_user_password(#[\SensitiveParameter] string $password, $fasthash = false, $pepperlength = 0): string {
4417
{
-
 
4418
    if (exceeds_password_length($password, $pepperlength)) {
4354
    if (exceeds_password_length($password, $pepperlength)) {
4419
        // Password cannot be more than MAX_PASSWORD_CHARACTERS.
4355
        // Password cannot be more than MAX_PASSWORD_CHARACTERS.
4420
        throw new \moodle_exception(get_string("passwordexceeded", 'error', MAX_PASSWORD_CHARACTERS));
4356
        throw new \moodle_exception(get_string("passwordexceeded", 'error', MAX_PASSWORD_CHARACTERS));
4421
    }
4357
    }
Línea 4467... Línea 4403...
4467
 *                       less secure. It is used when lots of hashes need to
4403
 *                       less secure. It is used when lots of hashes need to
4468
 *                       be generated quickly.
4404
 *                       be generated quickly.
4469
 * @return bool Always returns true.
4405
 * @return bool Always returns true.
4470
 */
4406
 */
4471
function update_internal_user_password(
4407
function update_internal_user_password(
4472
    stdClass $user,
4408
        stdClass $user,
4473
    #[\SensitiveParameter] ?string $password,
4409
        #[\SensitiveParameter] ?string $password,
4474
    bool $fasthash = false
4410
        bool $fasthash = false
4475
): bool {
4411
): bool {
4476
    global $CFG, $DB;
4412
    global $CFG, $DB;
Línea 4477... Línea 4413...
4477
 
4413
 
4478
    // Add the latest password pepper to the password before further processing.
4414
    // Add the latest password pepper to the password before further processing.
Línea 4481... Línea 4417...
4481
        $password = $password . reset($peppers);
4417
        $password = $password . reset($peppers);
4482
    }
4418
    }
Línea 4483... Línea 4419...
4483
 
4419
 
4484
    // Figure out what the hashed password should be.
4420
    // Figure out what the hashed password should be.
4485
    if (!isset($user->auth)) {
-
 
4486
        debugging(
4421
    if (!isset($user->auth)) {
4487
            'User record in update_internal_user_password() must include field auth',
4422
        debugging('User record in update_internal_user_password() must include field auth',
4488
            DEBUG_DEVELOPER
-
 
4489
        );
4423
                DEBUG_DEVELOPER);
4490
        $user->auth = $DB->get_field('user', 'auth', array('id' => $user->id));
4424
        $user->auth = $DB->get_field('user', 'auth', array('id' => $user->id));
4491
    }
4425
    }
4492
    $authplugin = get_auth_plugin($user->auth);
4426
    $authplugin = get_auth_plugin($user->auth);
4493
    if ($authplugin->prevent_local_passwords()) {
4427
    if ($authplugin->prevent_local_passwords()) {
Línea 4499... Línea 4433...
4499
    $algorithmchanged = false;
4433
    $algorithmchanged = false;
Línea 4500... Línea 4434...
4500
 
4434
 
4501
    if ($hashedpassword === AUTH_PASSWORD_NOT_CACHED) {
4435
    if ($hashedpassword === AUTH_PASSWORD_NOT_CACHED) {
4502
        // Password is not cached, update it if not set to AUTH_PASSWORD_NOT_CACHED.
4436
        // Password is not cached, update it if not set to AUTH_PASSWORD_NOT_CACHED.
-
 
4437
        $passwordchanged = ($user->password !== $hashedpassword);
4503
        $passwordchanged = ($user->password !== $hashedpassword);
4438
 
4504
    } else if (isset($user->password)) {
4439
    } else if (isset($user->password)) {
4505
        // If verification fails then it means the password has changed.
4440
        // If verification fails then it means the password has changed.
4506
        $passwordchanged = !password_verify($password, $user->password);
4441
        $passwordchanged = !password_verify($password, $user->password);
4507
        $algorithmchanged = password_is_legacy_hash($user->password);
4442
        $algorithmchanged = password_is_legacy_hash($user->password);
Línea 4519... Línea 4454...
4519
        $user = $DB->get_record('user', array('id' => $user->id));
4454
        $user = $DB->get_record('user', array('id' => $user->id));
4520
        \core\event\user_password_updated::create_from_user($user)->trigger();
4455
        \core\event\user_password_updated::create_from_user($user)->trigger();
Línea 4521... Línea 4456...
4521
 
4456
 
4522
        // Remove WS user tokens.
4457
        // Remove WS user tokens.
4523
        if (!empty($CFG->passwordchangetokendeletion)) {
4458
        if (!empty($CFG->passwordchangetokendeletion)) {
4524
            require_once($CFG->dirroot . '/webservice/lib.php');
4459
            require_once($CFG->dirroot.'/webservice/lib.php');
4525
            webservice::delete_user_ws_tokens($user->id);
4460
            webservice::delete_user_ws_tokens($user->id);
4526
        }
4461
        }
Línea 4527... Línea 4462...
4527
    }
4462
    }
Línea 4539... Línea 4474...
4539
 * @param int $mnethostid
4474
 * @param int $mnethostid
4540
 * @param bool $throwexception If true, it will throw an exception when there's no record found or when there are multiple records
4475
 * @param bool $throwexception If true, it will throw an exception when there's no record found or when there are multiple records
4541
 *                              found. Otherwise, it will just return false.
4476
 *                              found. Otherwise, it will just return false.
4542
 * @return mixed False, or A {@link $USER} object.
4477
 * @return mixed False, or A {@link $USER} object.
4543
 */
4478
 */
4544
function get_complete_user_data($field, $value, $mnethostid = null, $throwexception = false)
4479
function get_complete_user_data($field, $value, $mnethostid = null, $throwexception = false) {
4545
{
-
 
4546
    global $CFG, $DB;
4480
    global $CFG, $DB;
Línea 4547... Línea 4481...
4547
 
4481
 
4548
    if (!$field || !$value) {
4482
    if (!$field || !$value) {
4549
        return false;
4483
        return false;
Línea 4630... Línea 4564...
4630
    }
4564
    }
Línea 4631... Línea 4565...
4631
 
4565
 
4632
    // Add the custom profile fields to the user record.
4566
    // Add the custom profile fields to the user record.
4633
    $user->profile = array();
4567
    $user->profile = array();
4634
    if (!isguestuser($user)) {
4568
    if (!isguestuser($user)) {
4635
        require_once($CFG->dirroot . '/user/profile/lib.php');
4569
        require_once($CFG->dirroot.'/user/profile/lib.php');
4636
        profile_load_custom_fields($user);
4570
        profile_load_custom_fields($user);
Línea 4637... Línea 4571...
4637
    }
4571
    }
4638
 
4572
 
Línea 4659... Línea 4593...
4659
 * @param string|null $errmsg the error message to display when the password doesn't comply with the policy.
4593
 * @param string|null $errmsg the error message to display when the password doesn't comply with the policy.
4660
 * @param stdClass|null $user the user object to perform password validation against. Defaults to null if not provided.
4594
 * @param stdClass|null $user the user object to perform password validation against. Defaults to null if not provided.
4661
 *
4595
 *
4662
 * @return bool true if the password is valid according to the policy. false otherwise.
4596
 * @return bool true if the password is valid according to the policy. false otherwise.
4663
 */
4597
 */
4664
function check_password_policy(string $password, ?string &$errmsg, ?stdClass $user = null)
4598
function check_password_policy(string $password, ?string &$errmsg, ?stdClass $user = null) {
4665
{
-
 
4666
    global $CFG;
4599
    global $CFG;
4667
    if (!empty($CFG->passwordpolicy) && !isguestuser($user)) {
4600
    if (!empty($CFG->passwordpolicy) && !isguestuser($user)) {
4668
        $errors = get_password_policy_errors($password, $user);
4601
        $errors = get_password_policy_errors($password, $user);
Línea 4669... Línea 4602...
4669
 
4602
 
Línea 4682... Línea 4615...
4682
 * @param string $password the password to be checked against the password policy
4615
 * @param string $password the password to be checked against the password policy
4683
 * @param stdClass|null $user the user object to perform password validation against. Defaults to null if not provided.
4616
 * @param stdClass|null $user the user object to perform password validation against. Defaults to null if not provided.
4684
 *
4617
 *
4685
 * @return string[] Array of error messages.
4618
 * @return string[] Array of error messages.
4686
 */
4619
 */
4687
function get_password_policy_errors(string $password, ?stdClass $user = null): array
4620
function get_password_policy_errors(string $password, ?stdClass $user = null) : array {
4688
{
-
 
4689
    global $CFG;
4621
    global $CFG;
Línea 4690... Línea 4622...
4690
 
4622
 
Línea 4691... Línea 4623...
4691
    $errors = [];
4623
    $errors = [];
Línea 4725... Línea 4657...
4725
}
4657
}
Línea 4726... Línea 4658...
4726
 
4658
 
4727
/**
4659
/**
4728
 * When logging in, this function is run to set certain preferences for the current SESSION.
4660
 * When logging in, this function is run to set certain preferences for the current SESSION.
4729
 */
4661
 */
4730
function set_login_session_preferences()
-
 
4731
{
4662
function set_login_session_preferences() {
Línea 4732... Línea 4663...
4732
    global $SESSION;
4663
    global $SESSION;
Línea 4733... Línea 4664...
4733
 
4664
 
Línea 4746... Línea 4677...
4746
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
4677
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
4747
 * @return bool true if all the removals succeeded. false if there were any failures. If this
4678
 * @return bool true if all the removals succeeded. false if there were any failures. If this
4748
 *             method returns false, some of the removals will probably have succeeded, and others
4679
 *             method returns false, some of the removals will probably have succeeded, and others
4749
 *             failed, but you have no way of knowing which.
4680
 *             failed, but you have no way of knowing which.
4750
 */
4681
 */
4751
function delete_course($courseorid, $showfeedback = true)
4682
function delete_course($courseorid, $showfeedback = true) {
4752
{
-
 
4753
    global $DB, $CFG;
4683
    global $DB, $CFG;
Línea 4754... Línea 4684...
4754
 
4684
 
4755
    if (is_object($courseorid)) {
4685
    if (is_object($courseorid)) {
4756
        $courseid = $courseorid->id;
4686
        $courseid = $courseorid->id;
Línea 4811... Línea 4741...
4811
        'context' => $context,
4741
        'context' => $context,
4812
        'other' => array(
4742
        'other' => array(
4813
            'shortname' => $course->shortname,
4743
            'shortname' => $course->shortname,
4814
            'fullname' => $course->fullname,
4744
            'fullname' => $course->fullname,
4815
            'idnumber' => $course->idnumber
4745
            'idnumber' => $course->idnumber
4816
        )
4746
            )
4817
    ));
4747
    ));
4818
    $event->add_record_snapshot('course', $course);
4748
    $event->add_record_snapshot('course', $course);
4819
    $event->trigger();
4749
    $event->trigger();
Línea 4820... Línea 4750...
4820
 
4750
 
Línea 4834... Línea 4764...
4834
 *  - 'keep_groups_and_groupings' - false by default
4764
 *  - 'keep_groups_and_groupings' - false by default
4835
 *
4765
 *
4836
 * @param int $courseid The id of the course that is being deleted
4766
 * @param int $courseid The id of the course that is being deleted
4837
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
4767
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
4838
 * @param array $options extra options
4768
 * @param array $options extra options
-
 
4769
 * @param bool $coursedeletion Are we calling this as part of deleting the course?
4839
 * @return bool true if all the removals succeeded. false if there were any failures. If this
4770
 * @return bool true if all the removals succeeded. false if there were any failures. If this
4840
 *             method returns false, some of the removals will probably have succeeded, and others
4771
 *             method returns false, some of the removals will probably have succeeded, and others
4841
 *             failed, but you have no way of knowing which.
4772
 *             failed, but you have no way of knowing which.
4842
 */
4773
 */
4843
function remove_course_contents($courseid, $showfeedback = true, array $options = null)
4774
function remove_course_contents($courseid, $showfeedback = true, ?array $options = null, bool $coursedeletion = true) {
4844
{
-
 
4845
    global $CFG, $DB, $OUTPUT;
4775
    global $CFG, $DB, $OUTPUT;
Línea 4846... Línea 4776...
4846
 
4776
 
4847
    require_once($CFG->libdir . '/badgeslib.php');
4777
    require_once($CFG->libdir.'/badgeslib.php');
4848
    require_once($CFG->libdir . '/completionlib.php');
4778
    require_once($CFG->libdir.'/completionlib.php');
4849
    require_once($CFG->libdir . '/questionlib.php');
4779
    require_once($CFG->libdir.'/questionlib.php');
4850
    require_once($CFG->libdir . '/gradelib.php');
4780
    require_once($CFG->libdir.'/gradelib.php');
4851
    require_once($CFG->dirroot . '/group/lib.php');
4781
    require_once($CFG->dirroot.'/group/lib.php');
4852
    require_once($CFG->dirroot . '/comment/lib.php');
4782
    require_once($CFG->dirroot.'/comment/lib.php');
4853
    require_once($CFG->dirroot . '/rating/lib.php');
4783
    require_once($CFG->dirroot.'/rating/lib.php');
Línea 4854... Línea 4784...
4854
    require_once($CFG->dirroot . '/notes/lib.php');
4784
    require_once($CFG->dirroot.'/notes/lib.php');
4855
 
4785
 
Línea 4856... Línea 4786...
4856
    // Handle course badges.
4786
    // Handle course badges.
4857
    badges_handle_course_deletion($courseid);
4787
    badges_handle_course_deletion($courseid);
Línea 4858... Línea 4788...
4858
 
4788
 
4859
    // NOTE: these concatenated strings are suboptimal, but it is just extra info...
4789
    // NOTE: these concatenated strings are suboptimal, but it is just extra info...
Línea 4860... Línea 4790...
4860
    $strdeleted = get_string('deleted') . ' - ';
4790
    $strdeleted = get_string('deleted').' - ';
Línea 4868... Línea 4798...
4868
 
4798
 
4869
    // Delete course completion information, this has to be done before grades and enrols.
4799
    // Delete course completion information, this has to be done before grades and enrols.
4870
    $cc = new completion_info($course);
4800
    $cc = new completion_info($course);
4871
    $cc->clear_criteria();
4801
    $cc->clear_criteria();
4872
    if ($showfeedback) {
4802
    if ($showfeedback) {
4873
        echo $OUTPUT->notification($strdeleted . get_string('completion', 'completion'), 'notifysuccess');
4803
        echo $OUTPUT->notification($strdeleted.get_string('completion', 'completion'), 'notifysuccess');
Línea 4874... Línea 4804...
4874
    }
4804
    }
4875
 
4805
 
4876
    // Remove all data from gradebook - this needs to be done before course modules
4806
    // Remove all data from gradebook - this needs to be done before course modules
Línea 4886... Línea 4816...
4886
        blocks_delete_all_for_context($childcontext->id);
4816
        blocks_delete_all_for_context($childcontext->id);
4887
    }
4817
    }
4888
    unset($childcontexts);
4818
    unset($childcontexts);
4889
    blocks_delete_all_for_context($coursecontext->id);
4819
    blocks_delete_all_for_context($coursecontext->id);
4890
    if ($showfeedback) {
4820
    if ($showfeedback) {
4891
        echo $OUTPUT->notification($strdeleted . get_string('type_block_plural', 'plugin'), 'notifysuccess');
4821
        echo $OUTPUT->notification($strdeleted.get_string('type_block_plural', 'plugin'), 'notifysuccess');
4892
    }
4822
    }
Línea 4893... Línea 4823...
4893
 
4823
 
4894
    $DB->set_field('course_modules', 'deletioninprogress', '1', ['course' => $courseid]);
4824
    $DB->set_field('course_modules', 'deletioninprogress', '1', ['course' => $courseid]);
Línea 4898... Línea 4828...
4898
    $allmodules = $DB->get_records_menu('modules', array(), '', 'name, id');
4828
    $allmodules = $DB->get_records_menu('modules', array(), '', 'name, id');
Línea 4899... Línea 4829...
4899
 
4829
 
4900
    // Delete every instance of every module,
4830
    // Delete every instance of every module,
4901
    // this has to be done before deleting of course level stuff.
4831
    // this has to be done before deleting of course level stuff.
-
 
4832
    $locations = core_component::get_plugin_list('mod');
-
 
4833
    // Sort mod instances that publish questions to the end of the list, so that they will be removed last.
-
 
4834
    // This is because they could have questions in use by other activities in this course.
-
 
4835
    uksort($locations, static function ($a, $b) {
-
 
4836
        return plugin_supports('mod', $a, FEATURE_PUBLISHES_QUESTIONS) <=> plugin_supports('mod', $b, FEATURE_PUBLISHES_QUESTIONS);
4902
    $locations = core_component::get_plugin_list('mod');
4837
    });
4903
    foreach ($locations as $modname => $moddir) {
4838
    foreach ($locations as $modname => $moddir) {
4904
        if ($modname === 'NEWMODULE') {
4839
        if ($modname === 'NEWMODULE') {
4905
            continue;
4840
            continue;
4906
        }
4841
        }
4907
        if (array_key_exists($modname, $allmodules)) {
4842
        if (array_key_exists($modname, $allmodules)) {
4908
            $sql = "SELECT cm.*, m.id AS modinstance, m.name, '$modname' AS modname
4843
            $sql = "SELECT cm.*, m.id AS modinstance, m.name, '$modname' AS modname
4909
              FROM {" . $modname . "} m
4844
              FROM {".$modname."} m
4910
                   LEFT JOIN {course_modules} cm ON cm.instance = m.id AND cm.module = :moduleid
4845
                   LEFT JOIN {course_modules} cm ON cm.instance = m.id AND cm.module = :moduleid
4911
             WHERE m.course = :courseid";
4846
             WHERE m.course = :courseid";
4912
            $instances = $DB->get_records_sql($sql, array(
-
 
4913
                'courseid' => $course->id,
-
 
4914
                'modulename' => $modname,
4847
            $instances = $DB->get_records_sql($sql, array('courseid' => $course->id,
4915
                'moduleid' => $allmodules[$modname]
-
 
Línea 4916... Línea 4848...
4916
            ));
4848
                'modulename' => $modname, 'moduleid' => $allmodules[$modname]));
4917
 
4849
 
Línea 4918... Línea 4850...
4918
            include_once("$moddir/lib.php");                 // Shows php warning only if plugin defective.
4850
            include_once("$moddir/lib.php");                 // Shows php warning only if plugin defective.
4919
            $moddelete = $modname . '_delete_instance';       // Delete everything connected to an instance.
4851
            $moddelete = $modname .'_delete_instance';       // Delete everything connected to an instance.
4920
 
-
 
4921
            if ($instances) {
-
 
4922
                foreach ($instances as $cm) {
-
 
4923
                    if ($cm->id) {
-
 
4924
                        // Delete activity context questions and question categories.
4852
 
4925
                        question_delete_activity($cm);
-
 
4926
                        // Notify the competency subsystem.
4853
            if ($instances) {
4927
                        \core_competency\api::hook_course_module_deleted($cm);
-
 
4928
 
-
 
4929
                        // Delete all tag instances associated with the instance of this module.
-
 
4930
                        core_tag_tag::delete_instances("mod_{$modname}", null, context_module::instance($cm->id)->id);
4854
                foreach ($instances as $cm) {
4931
                        core_tag_tag::remove_all_item_tags('core', 'course_modules', $cm->id);
4855
                    // Warning! there is very similar code in course_delete_module.
4932
                    }
4856
                    // If you are changing this code, you probably need to change that too.
4933
                    if (function_exists($moddelete)) {
4857
                    if (function_exists($moddelete)) {
4934
                        // This purges all module data in related tables, extra user prefs, settings, etc.
4858
                        // This purges all module data in related tables, extra user prefs, settings, etc.
4935
                        $moddelete($cm->modinstance);
4859
                        $moddelete($cm->modinstance);
4936
                    } else {
4860
                    } else {
4937
                        // NOTE: we should not allow installation of modules with missing delete support!
4861
                        // NOTE: we should not allow installation of modules with missing delete support!
Línea 4938... Línea 4862...
4938
                        debugging("Defective module '$modname' detected when deleting course contents: missing function $moddelete()!");
4862
                        debugging("Defective module '$modname' detected when deleting course contents: missing function $moddelete()!");
-
 
4863
                        $DB->delete_records($modname, array('id' => $cm->modinstance));
-
 
4864
                    }
-
 
4865
 
-
 
4866
                    if ($cm->id) {
-
 
4867
                        // Delete activity context questions and question categories.
-
 
4868
                        // We delete the questions after the activity database is removed,
-
 
4869
                        // because questions are referenced via question reference tables
-
 
4870
                        // and cannot be deleted while the activities that use them still exist.
-
 
4871
                        question_delete_activity($cm, coursedeletion: $coursedeletion);
-
 
4872
                        // Delete all tag instances associated with the instance of this module.
4939
                        $DB->delete_records($modname, array('id' => $cm->modinstance));
4873
                        core_tag_tag::delete_instances("mod_{$modname}", null, context_module::instance($cm->id)->id);
4940
                    }
4874
                        core_tag_tag::remove_all_item_tags('core', 'course_modules', $cm->id);
4941
 
4875
                        // Notify the competency subsystem.
4942
                    if ($cm->id) {
4876
                        \core_competency\api::hook_course_module_deleted($cm);
4943
                        // Delete cm and its context - orphaned contexts are purged in cron in case of any race condition.
4877
                        // Delete cm and its context - orphaned contexts are purged in cron in case of any race condition.
4944
                        context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
4878
                        context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
4945
                        $DB->delete_records('course_modules_completion', ['coursemoduleid' => $cm->id]);
4879
                        $DB->delete_records('course_modules_completion', ['coursemoduleid' => $cm->id]);
4946
                        $DB->delete_records('course_modules_viewed', ['coursemoduleid' => $cm->id]);
4880
                        $DB->delete_records('course_modules_viewed', ['coursemoduleid' => $cm->id]);
4947
                        $DB->delete_records('course_modules', array('id' => $cm->id));
4881
                        $DB->delete_records('course_modules', array('id' => $cm->id));
4948
                        rebuild_course_cache($cm->course, true);
4882
                        rebuild_course_cache($cm->course, true);
4949
                    }
4883
                    }
4950
                }
4884
                }
4951
            }
4885
            }
4952
            if ($instances and $showfeedback) {
4886
            if ($instances and $showfeedback) {
4953
                echo $OUTPUT->notification($strdeleted . get_string('pluginname', $modname), 'notifysuccess');
4887
                echo $OUTPUT->notification($strdeleted.get_string('pluginname', $modname), 'notifysuccess');
4954
            }
4888
            }
Línea 4963... Línea 4897...
4963
    $DB->delete_records("course_completion_defaults", array("course" => $courseid));
4897
    $DB->delete_records("course_completion_defaults", array("course" => $courseid));
Línea 4964... Línea 4898...
4964
 
4898
 
4965
    // Remove all data from availability and completion tables that is associated
4899
    // Remove all data from availability and completion tables that is associated
4966
    // with course-modules belonging to this course. Note this is done even if the
4900
    // with course-modules belonging to this course. Note this is done even if the
4967
    // features are not enabled now, in case they were enabled previously.
-
 
4968
    $DB->delete_records_subquery(
4901
    // features are not enabled now, in case they were enabled previously.
4969
        'course_modules_completion',
-
 
4970
        'coursemoduleid',
-
 
4971
        'id',
4902
    $DB->delete_records_subquery('course_modules_completion', 'coursemoduleid', 'id',
4972
        'SELECT id from {course_modules} WHERE course = ?',
-
 
4973
        [$courseid]
-
 
4974
    );
4903
            'SELECT id from {course_modules} WHERE course = ?', [$courseid]);
4975
    $DB->delete_records_subquery(
-
 
4976
        'course_modules_viewed',
-
 
4977
        'coursemoduleid',
-
 
4978
        'id',
4904
    $DB->delete_records_subquery('course_modules_viewed', 'coursemoduleid', 'id',
4979
        'SELECT id from {course_modules} WHERE course = ?',
-
 
4980
        [$courseid]
-
 
Línea 4981... Línea 4905...
4981
    );
4905
        'SELECT id from {course_modules} WHERE course = ?', [$courseid]);
4982
 
4906
 
4983
    // Remove course-module data that has not been removed in modules' _delete_instance callbacks.
4907
    // Remove course-module data that has not been removed in modules' _delete_instance callbacks.
4984
    $cms = $DB->get_records('course_modules', array('course' => $course->id));
4908
    $cms = $DB->get_records('course_modules', array('course' => $course->id));
Línea 4995... Línea 4919...
4995
        $DB->delete_records('course_modules', array('id' => $cm->id));
4919
        $DB->delete_records('course_modules', array('id' => $cm->id));
4996
        rebuild_course_cache($cm->course, true);
4920
        rebuild_course_cache($cm->course, true);
4997
    }
4921
    }
Línea 4998... Línea 4922...
4998
 
4922
 
4999
    if ($showfeedback) {
4923
    if ($showfeedback) {
5000
        echo $OUTPUT->notification($strdeleted . get_string('type_mod_plural', 'plugin'), 'notifysuccess');
-
 
5001
    }
-
 
5002
 
-
 
5003
    // Delete questions and question categories.
-
 
5004
    question_delete_course($course);
-
 
5005
    if ($showfeedback) {
-
 
5006
        echo $OUTPUT->notification($strdeleted . get_string('questions', 'question'), 'notifysuccess');
4924
        echo $OUTPUT->notification($strdeleted.get_string('type_mod_plural', 'plugin'), 'notifysuccess');
Línea 5007... Línea 4925...
5007
    }
4925
    }
5008
 
4926
 
5009
    // Delete content bank contents.
4927
    // Delete content bank contents.
5010
    $cb = new \core_contentbank\contentbank();
4928
    $cb = new \core_contentbank\contentbank();
5011
    $cbdeleted = $cb->delete_contents($coursecontext);
4929
    $cbdeleted = $cb->delete_contents($coursecontext);
5012
    if ($showfeedback && $cbdeleted) {
4930
    if ($showfeedback && $cbdeleted) {
Línea 5013... Línea 4931...
5013
        echo $OUTPUT->notification($strdeleted . get_string('contentbank', 'contentbank'), 'notifysuccess');
4931
        echo $OUTPUT->notification($strdeleted.get_string('contentbank', 'contentbank'), 'notifysuccess');
5014
    }
4932
    }
5015
 
4933
 
Línea 5027... Línea 4945...
5027
        // permission to remove.
4945
        // permission to remove.
5028
        $userid = $options['userid'] ?? null;
4946
        $userid = $options['userid'] ?? null;
5029
        enrol_course_delete($course, $userid);
4947
        enrol_course_delete($course, $userid);
5030
        role_unassign_all(array('contextid' => $coursecontext->id, 'component' => ''), true);
4948
        role_unassign_all(array('contextid' => $coursecontext->id, 'component' => ''), true);
5031
        if ($showfeedback) {
4949
        if ($showfeedback) {
5032
            echo $OUTPUT->notification($strdeleted . get_string('type_enrol_plural', 'plugin'), 'notifysuccess');
4950
            echo $OUTPUT->notification($strdeleted.get_string('type_enrol_plural', 'plugin'), 'notifysuccess');
5033
        }
4951
        }
5034
    }
4952
    }
Línea 5035... Línea 4953...
5035
 
4953
 
5036
    // Delete any groups, removing members and grouping/course links first.
4954
    // Delete any groups, removing members and grouping/course links first.
Línea 5110... Línea 5028...
5110
        // there might be also files used by enrol plugins...
5028
        // there might be also files used by enrol plugins...
5111
    }
5029
    }
Línea 5112... Línea 5030...
5112
 
5030
 
5113
    // Delete legacy files - just in case some files are still left there after conversion to new file api,
5031
    // Delete legacy files - just in case some files are still left there after conversion to new file api,
5114
    // also some non-standard unsupported plugins may try to store something there.
5032
    // also some non-standard unsupported plugins may try to store something there.
Línea 5115... Línea 5033...
5115
    fulldelete($CFG->dataroot . '/' . $course->id);
5033
    fulldelete($CFG->dataroot.'/'.$course->id);
5116
 
5034
 
Línea 5117... Línea 5035...
5117
    // Delete from cache to reduce the cache size especially makes sense in case of bulk course deletion.
5035
    // Delete from cache to reduce the cache size especially makes sense in case of bulk course deletion.
5118
    course_modinfo::purge_course_cache($courseid);
5036
    course_modinfo::purge_course_cache($courseid);
5119
 
5037
 
5120
    // Trigger a course content deleted event.
5038
    // Trigger a course content deleted event.
5121
    $event = \core\event\course_content_deleted::create(array(
-
 
5122
        'objectid' => $course->id,
5039
    $event = \core\event\course_content_deleted::create(array(
5123
        'context' => $coursecontext,
5040
        'objectid' => $course->id,
5124
        'other' => array(
-
 
5125
            'shortname' => $course->shortname,
5041
        'context' => $coursecontext,
5126
            'fullname' => $course->fullname,
5042
        'other' => array('shortname' => $course->shortname,
5127
            'options' => $options
5043
                         'fullname' => $course->fullname,
5128
        ) // Passing this for legacy reasons.
5044
                         'options' => $options) // Passing this for legacy reasons.
Línea 5129... Línea 5045...
5129
    ));
5045
    ));
Línea 5141... Línea 5057...
5141
 * @param int $timeshift time difference
5057
 * @param int $timeshift time difference
5142
 * @param int $courseid
5058
 * @param int $courseid
5143
 * @param int $modid (Optional) passed if specific mod instance in course needs to be updated.
5059
 * @param int $modid (Optional) passed if specific mod instance in course needs to be updated.
5144
 * @return bool success
5060
 * @return bool success
5145
 */
5061
 */
5146
function shift_course_mod_dates($modname, $fields, $timeshift, $courseid, $modid = 0)
5062
function shift_course_mod_dates($modname, $fields, $timeshift, $courseid, $modid = 0) {
5147
{
-
 
5148
    global $CFG, $DB;
5063
    global $CFG, $DB;
5149
    include_once($CFG->dirroot . '/mod/' . $modname . '/lib.php');
5064
    include_once($CFG->dirroot.'/mod/'.$modname.'/lib.php');
Línea 5150... Línea 5065...
5150
 
5065
 
5151
    $return = true;
5066
    $return = true;
5152
    $params = array($timeshift, $courseid);
5067
    $params = array($timeshift, $courseid);
5153
    foreach ($fields as $field) {
5068
    foreach ($fields as $field) {
5154
        $updatesql = "UPDATE {" . $modname . "}
5069
        $updatesql = "UPDATE {".$modname."}
5155
                          SET $field = $field + ?
5070
                          SET $field = $field + ?
5156
                        WHERE course=? AND $field<>0";
5071
                        WHERE course=? AND $field<>0";
5157
        if ($modid) {
5072
        if ($modid) {
5158
            $updatesql .= ' AND id=?';
5073
            $updatesql .= ' AND id=?';
Línea 5169... Línea 5084...
5169
 * It will retain the activities and the structure of the course.
5084
 * It will retain the activities and the structure of the course.
5170
 *
5085
 *
5171
 * @param object $data an object containing all the settings including courseid (without magic quotes)
5086
 * @param object $data an object containing all the settings including courseid (without magic quotes)
5172
 * @return array status array of array component, item, error
5087
 * @return array status array of array component, item, error
5173
 */
5088
 */
5174
function reset_course_userdata($data)
5089
function reset_course_userdata($data) {
5175
{
-
 
5176
    global $CFG, $DB;
5090
    global $CFG, $DB;
5177
    require_once($CFG->libdir . '/gradelib.php');
5091
    require_once($CFG->libdir.'/gradelib.php');
5178
    require_once($CFG->libdir . '/completionlib.php');
5092
    require_once($CFG->libdir.'/completionlib.php');
5179
    require_once($CFG->dirroot . '/completion/criteria/completion_criteria_date.php');
5093
    require_once($CFG->dirroot.'/completion/criteria/completion_criteria_date.php');
5180
    require_once($CFG->dirroot . '/group/lib.php');
5094
    require_once($CFG->dirroot.'/group/lib.php');
Línea 5181... Línea 5095...
5181
 
5095
 
5182
    $data->courseid = $data->id;
5096
    $data->courseid = $data->id;
Línea 5183... Línea 5097...
5183
    $context = context_course::instance($data->courseid);
5097
    $context = context_course::instance($data->courseid);
Línea 5192... Línea 5106...
5192
    $event = \core\event\course_reset_started::create($eventparams);
5106
    $event = \core\event\course_reset_started::create($eventparams);
5193
    $event->trigger();
5107
    $event->trigger();
Línea 5194... Línea 5108...
5194
 
5108
 
5195
    // Calculate the time shift of dates.
5109
    // Calculate the time shift of dates.
5196
    if (!empty($data->reset_start_date)) {
-
 
5197
        // Time part of course startdate should be zero.
5110
    if (!empty($data->reset_start_date)) {
5198
        $data->timeshift = $data->reset_start_date - usergetmidnight($data->reset_start_date_old);
5111
        $data->timeshift = $data->reset_start_date - $data->reset_start_date_old;
5199
    } else {
5112
    } else {
5200
        $data->timeshift = 0;
5113
        $data->timeshift = 0;
Línea 5201... Línea 5114...
5201
    }
5114
    }
Línea 5225... Línea 5138...
5225
        if ($CFG->enablecompletion) {
5138
        if ($CFG->enablecompletion) {
5226
            $modinfo = get_fast_modinfo($data->courseid);
5139
            $modinfo = get_fast_modinfo($data->courseid);
5227
            $changed = false;
5140
            $changed = false;
5228
            foreach ($modinfo->get_cms() as $cm) {
5141
            foreach ($modinfo->get_cms() as $cm) {
5229
                if ($cm->completion && !empty($cm->completionexpected)) {
5142
                if ($cm->completion && !empty($cm->completionexpected)) {
5230
                    $DB->set_field(
-
 
5231
                        'course_modules',
-
 
5232
                        'completionexpected',
-
 
5233
                        $cm->completionexpected + $data->timeshift,
5143
                    $DB->set_field('course_modules', 'completionexpected', $cm->completionexpected + $data->timeshift,
5234
                        array('id' => $cm->id)
5144
                        array('id' => $cm->id));
5235
                    );
-
 
5236
                    $changed = true;
5145
                    $changed = true;
5237
                }
5146
                }
5238
            }
5147
            }
Línea 5239... Línea 5148...
5239
 
5148
 
Línea 5244... Línea 5153...
5244
 
5153
 
5245
            // Update course date completion criteria.
5154
            // Update course date completion criteria.
5246
            \completion_criteria_date::update_date($data->courseid, $data->timeshift);
5155
            \completion_criteria_date::update_date($data->courseid, $data->timeshift);
Línea 5247... Línea 5156...
5247
        }
5156
        }
5248
 
5157
 
Línea 5249... Línea 5158...
5249
        $status[] = array('component' => $componentstr, 'item' => get_string('datechanged'), 'error' => false);
5158
        $status[] = ['component' => $componentstr, 'item' => get_string('date'), 'error' => false];
5250
    }
5159
    }
5251
 
5160
 
Línea 5262... Línea 5171...
5262
        $DB->delete_records('event', array('courseid' => $data->courseid));
5171
        $DB->delete_records('event', array('courseid' => $data->courseid));
5263
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false);
5172
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteevents', 'calendar'), 'error' => false);
5264
    }
5173
    }
Línea 5265... Línea 5174...
5265
 
5174
 
5266
    if (!empty($data->reset_notes)) {
5175
    if (!empty($data->reset_notes)) {
5267
        require_once($CFG->dirroot . '/notes/lib.php');
5176
        require_once($CFG->dirroot.'/notes/lib.php');
5268
        note_delete_all($data->courseid);
5177
        note_delete_all($data->courseid);
5269
        $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false);
5178
        $status[] = array('component' => $componentstr, 'item' => get_string('deletenotes', 'notes'), 'error' => false);
Línea 5270... Línea 5179...
5270
    }
5179
    }
5271
 
5180
 
5272
    if (!empty($data->delete_blog_associations)) {
5181
    if (!empty($data->delete_blog_associations)) {
5273
        require_once($CFG->dirroot . '/blog/lib.php');
5182
        require_once($CFG->dirroot.'/blog/lib.php');
5274
        blog_remove_associations_for_course($data->courseid);
5183
        blog_remove_associations_for_course($data->courseid);
Línea 5275... Línea 5184...
5275
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteblogassociations', 'blog'), 'error' => false);
5184
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteblogassociations', 'blog'), 'error' => false);
5276
    }
5185
    }
5277
 
5186
 
5278
    if (!empty($data->reset_completion)) {
5187
    if (!empty($data->reset_completion)) {
5279
        // Delete course and activity completion information.
5188
        // Delete course and activity completion information.
5280
        $course = $DB->get_record('course', array('id' => $data->courseid));
-
 
5281
        $cc = new completion_info($course);
5189
        $course = $DB->get_record('course', array('id' => $data->courseid));
5282
        $cc->delete_all_completion_data();
5190
        $cc = new completion_info($course);
5283
        $status[] = array(
-
 
5284
            'component' => $componentstr,
-
 
5285
            'item' => get_string('deletecompletiondata', 'completion'),
5191
        $cc->delete_all_completion_data();
Línea 5286... Línea 5192...
5286
            'error' => false
5192
        $status[] = array('component' => $componentstr,
5287
        );
5193
                'item' => get_string('deletecompletiondata', 'completion'), 'error' => false);
5288
    }
-
 
5289
 
5194
    }
5290
    if (!empty($data->reset_competency_ratings)) {
5195
 
5291
        \core_competency\api::hook_course_reset_competency_ratings($data->courseid);
-
 
5292
        $status[] = array(
-
 
5293
            'component' => $componentstr,
5196
    if (!empty($data->reset_competency_ratings)) {
Línea 5294... Línea 5197...
5294
            'item' => get_string('deletecompetencyratings', 'core_competency'),
5197
        \core_competency\api::hook_course_reset_competency_ratings($data->courseid);
Línea 5295... Línea 5198...
5295
            'error' => false
5198
        $status[] = array('component' => $componentstr,
Línea 5334... Línea 5237...
5334
                          FROM {user_enrolments} ue
5237
                          FROM {user_enrolments} ue
5335
                          JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
5238
                          JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
5336
                          JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)
5239
                          JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)
5337
                          JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)";
5240
                          JOIN {role_assignments} ra ON (ra.contextid = c.id AND ra.roleid = :roleid AND ra.userid = ue.userid)";
5338
                $params = array('courseid' => $data->courseid, 'roleid' => $withroleid, 'courselevel' => CONTEXT_COURSE);
5241
                $params = array('courseid' => $data->courseid, 'roleid' => $withroleid, 'courselevel' => CONTEXT_COURSE);
-
 
5242
 
5339
            } else {
5243
            } else {
5340
                // Without any role assigned at course context.
5244
                // Without any role assigned at course context.
5341
                $sql = "SELECT ue.*
5245
                $sql = "SELECT ue.*
5342
                          FROM {user_enrolments} ue
5246
                          FROM {user_enrolments} ue
5343
                          JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
5247
                          JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)
Línea 5373... Línea 5277...
5373
        }
5277
        }
5374
    }
5278
    }
5375
    if (!empty($data->unenrolled)) {
5279
    if (!empty($data->unenrolled)) {
5376
        $status[] = array(
5280
        $status[] = array(
5377
            'component' => $componentstr,
5281
            'component' => $componentstr,
5378
            'item' => get_string('unenrol', 'enrol') . ' (' . count($data->unenrolled) . ')',
5282
            'item' => get_string('unenrol', 'enrol').' ('.count($data->unenrolled).')',
5379
            'error' => false
5283
            'error' => false
5380
        );
5284
        );
5381
    }
5285
    }
Línea 5382... Línea 5286...
5382
 
5286
 
Línea 5406... Línea 5310...
5406
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false);
5310
        $status[] = array('component' => $componentstr, 'item' => get_string('deleteallgroupings', 'group'), 'error' => false);
5407
    }
5311
    }
Línea 5408... Línea 5312...
5408
 
5312
 
5409
    // Look in every instance of every module for data to delete.
5313
    // Look in every instance of every module for data to delete.
5410
    $unsupportedmods = array();
5314
    $unsupportedmods = array();
5411
    if ($allmods = $DB->get_records('modules')) {
5315
    if ($allmods = $DB->get_records('modules') ) {
5412
        foreach ($allmods as $mod) {
5316
        foreach ($allmods as $mod) {
5413
            $modname = $mod->name;
5317
            $modname = $mod->name;
5414
            $modfile = $CFG->dirroot . '/mod/' . $modname . '/lib.php';
5318
            $modfile = $CFG->dirroot.'/mod/'. $modname.'/lib.php';
5415
            $moddeleteuserdata = $modname . '_reset_userdata';   // Function to delete user data.
5319
            $moddeleteuserdata = $modname.'_reset_userdata';   // Function to delete user data.
5416
            if (file_exists($modfile)) {
5320
            if (file_exists($modfile)) {
5417
                if (!$DB->count_records($modname, array('course' => $data->courseid))) {
5321
                if (!$DB->count_records($modname, array('course' => $data->courseid))) {
5418
                    continue; // Skip mods with no instances.
5322
                    continue; // Skip mods with no instances.
5419
                }
5323
                }
5420
                include_once($modfile);
5324
                include_once($modfile);
5421
                if (function_exists($moddeleteuserdata)) {
5325
                if (function_exists($moddeleteuserdata)) {
5422
                    $modstatus = $moddeleteuserdata($data);
5326
                    $modstatus = $moddeleteuserdata($data);
5423
                    if (is_array($modstatus)) {
5327
                    if (is_array($modstatus)) {
5424
                        $status = array_merge($status, $modstatus);
5328
                        $status = array_merge($status, $modstatus);
5425
                    } else {
5329
                    } else {
5426
                        debugging('Module ' . $modname . ' returned incorrect staus - must be an array!');
5330
                        debugging('Module '.$modname.' returned incorrect staus - must be an array!');
5427
                    }
5331
                    }
5428
                } else {
5332
                } else {
5429
                    $unsupportedmods[] = $mod;
5333
                    $unsupportedmods[] = $mod;
5430
                }
5334
                }
5431
            } else {
5335
            } else {
5432
                debugging('Missing lib.php in ' . $modname . ' module!');
5336
                debugging('Missing lib.php in '.$modname.' module!');
5433
            }
5337
            }
5434
            // Update calendar events for all modules.
5338
            // Update calendar events for all modules.
5435
            course_module_bulk_update_calendar_events($modname, $data->courseid);
5339
            course_module_bulk_update_calendar_events($modname, $data->courseid);
5436
        }
5340
        }
Línea 5454... Línea 5358...
5454
    $componentstr = get_string('gradebook', 'grades');
5358
    $componentstr = get_string('gradebook', 'grades');
5455
    // Reset gradebook,.
5359
    // Reset gradebook,.
5456
    if (!empty($data->reset_gradebook_items)) {
5360
    if (!empty($data->reset_gradebook_items)) {
5457
        remove_course_grades($data->courseid, false);
5361
        remove_course_grades($data->courseid, false);
5458
        grade_grab_course_grades($data->courseid);
5362
        grade_grab_course_grades($data->courseid);
5459
        grade_regrade_final_grades($data->courseid);
5363
        grade_regrade_final_grades($data->courseid, async: true);
5460
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false);
5364
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcourseitems', 'grades'), 'error' => false);
-
 
5365
 
5461
    } else if (!empty($data->reset_gradebook_grades)) {
5366
    } else if (!empty($data->reset_gradebook_grades)) {
5462
        grade_course_reset($data->courseid);
5367
        grade_course_reset($data->courseid);
5463
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false);
5368
        $status[] = array('component' => $componentstr, 'item' => get_string('removeallcoursegrades', 'grades'), 'error' => false);
5464
    }
5369
    }
5465
    // Reset comments.
5370
    // Reset comments.
5466
    if (!empty($data->reset_comments)) {
5371
    if (!empty($data->reset_comments)) {
5467
        require_once($CFG->dirroot . '/comment/lib.php');
5372
        require_once($CFG->dirroot.'/comment/lib.php');
5468
        comment::reset_course_page_comments($context);
5373
        comment::reset_course_page_comments($context);
5469
    }
5374
    }
Línea 5470... Línea 5375...
5470
 
5375
 
5471
    $event = \core\event\course_reset_ended::create($eventparams);
5376
    $event = \core\event\course_reset_ended::create($eventparams);
Línea 5479... Línea 5384...
5479
 *
5384
 *
5480
 * @param int $modid
5385
 * @param int $modid
5481
 * @param string $modargs
5386
 * @param string $modargs
5482
 * @return string Returns email processing address
5387
 * @return string Returns email processing address
5483
 */
5388
 */
5484
function generate_email_processing_address($modid, $modargs)
5389
function generate_email_processing_address($modid, $modargs) {
5485
{
-
 
5486
    global $CFG;
5390
    global $CFG;
Línea 5487... Línea 5391...
5487
 
5391
 
5488
    $header = $CFG->mailprefix . substr(base64_encode(pack('C', $modid)), 0, 2) . $modargs;
5392
    $header = $CFG->mailprefix . substr(base64_encode(pack('C', $modid)), 0, 2).$modargs;
5489
    return $header . substr(md5($header . get_site_identifier()), 0, 16) . '@' . $CFG->maildomain;
-
 
5490
}
-
 
5491
 
-
 
5492
/**
-
 
5493
 * ?
-
 
5494
 *
-
 
5495
 * @todo Finish documenting this function
-
 
5496
 *
-
 
5497
 * @param string $modargs
-
 
5498
 * @param string $body Currently unused
-
 
5499
 */
-
 
5500
function moodle_process_email($modargs, $body)
-
 
5501
{
-
 
5502
    global $DB;
-
 
5503
 
-
 
5504
    // The first char should be an unencoded letter. We'll take this as an action.
-
 
5505
    switch ($modargs[0]) {
-
 
5506
        case 'B': { // Bounce.
-
 
5507
                list(, $userid) = unpack('V', base64_decode(substr($modargs, 1, 8)));
-
 
5508
                if ($user = $DB->get_record("user", array('id' => $userid), "id,email")) {
-
 
5509
                    // Check the half md5 of their email.
-
 
5510
                    $md5check = substr(md5($user->email), 0, 16);
-
 
5511
                    if ($md5check == substr($modargs, -16)) {
-
 
5512
                        set_bounce_count($user);
-
 
5513
                    }
-
 
5514
                    // Else maybe they've already changed it?
-
 
5515
                }
-
 
5516
            }
-
 
5517
            break;
-
 
5518
            // Maybe more later?
-
 
5519
    }
5393
    return $header . substr(md5($header.get_site_identifier()), 0, 16).'@'.$CFG->maildomain;
Línea 5520... Línea 5394...
5520
}
5394
}
Línea 5521... Línea 5395...
5521
 
5395
 
5522
// CORRESPONDENCE.
5396
// CORRESPONDENCE.
5523
 
5397
 
5524
/**
5398
/**
5525
 * Get mailer instance, enable buffering, flush buffer or disable buffering.
5399
 * Get mailer instance, enable buffering, flush buffer or disable buffering.
5526
 *
5400
 *
5527
 * @param string $action 'get', 'buffer', 'close' or 'flush'
5401
 * @param string $action 'get', 'buffer', 'close' or 'flush'
5528
 * @return moodle_phpmailer|null mailer instance if 'get' used or nothing
-
 
5529
 */
5402
 * @return moodle_phpmailer|null mailer instance if 'get' used or nothing
Línea 5530... Línea 5403...
5530
function get_mailer($action = 'get')
5403
 */
5531
{
5404
function get_mailer($action='get') {
5532
    global $CFG;
5405
    global $CFG;
Línea 5567... Línea 5440...
5567
 
5440
 
5568
            $prevkeepalive = $mailer->SMTPKeepAlive;
5441
            $prevkeepalive = $mailer->SMTPKeepAlive;
5569
            get_mailer('flush');
5442
            get_mailer('flush');
Línea 5570... Línea 5443...
5570
        }
5443
        }
5571
 
5444
 
Línea 5572... Línea 5445...
5572
        require_once($CFG->libdir . '/phpmailer/moodle_phpmailer.php');
5445
        require_once($CFG->libdir.'/phpmailer/moodle_phpmailer.php');
Línea 5573... Línea 5446...
5573
        $mailer = new moodle_phpmailer();
5446
        $mailer = new moodle_phpmailer();
5574
 
5447
 
5575
        $counter = 1;
5448
        $counter = 1;
-
 
5449
 
5576
 
5450
        if ($CFG->smtphosts == 'qmail') {
5577
        if ($CFG->smtphosts == 'qmail') {
5451
            // Use Qmail system.
5578
            // Use Qmail system.
5452
            $mailer->isQmail();
-
 
5453
 
5579
            $mailer->isQmail();
5454
        } else if (empty($CFG->smtphosts)) {
5580
        } else if (empty($CFG->smtphosts)) {
5455
            // Use PHP mail() = sendmail.
5581
            // Use PHP mail() = sendmail.
5456
            $mailer->isMail();
5582
            $mailer->isMail();
5457
 
5583
        } else {
5458
        } else {
Línea 5620... Línea 5495...
5620
 
5495
 
5621
    // Close smtp session, but continue buffering.
5496
    // Close smtp session, but continue buffering.
5622
    if ($action == 'flush') {
5497
    if ($action == 'flush') {
5623
        if (isset($mailer) and $mailer->Mailer == 'smtp') {
5498
        if (isset($mailer) and $mailer->Mailer == 'smtp') {
5624
            if (!empty($mailer->SMTPDebug)) {
5499
            if (!empty($mailer->SMTPDebug)) {
5625
                echo '<pre>' . "\n";
5500
                echo '<pre>'."\n";
5626
            }
5501
            }
5627
            $mailer->SmtpClose();
5502
            $mailer->SmtpClose();
5628
            if (!empty($mailer->SMTPDebug)) {
5503
            if (!empty($mailer->SMTPDebug)) {
5629
                echo '</pre>';
5504
                echo '</pre>';
Línea 5647... Línea 5522...
5647
 * A helper function to test for email diversion
5522
 * A helper function to test for email diversion
5648
 *
5523
 *
5649
 * @param string $email
5524
 * @param string $email
5650
 * @return bool Returns true if the email should be diverted
5525
 * @return bool Returns true if the email should be diverted
5651
 */
5526
 */
5652
function email_should_be_diverted($email)
5527
function email_should_be_diverted($email) {
5653
{
-
 
5654
    global $CFG;
5528
    global $CFG;
Línea 5655... Línea 5529...
5655
 
5529
 
5656
    if (empty($CFG->divertallemailsto)) {
5530
    if (empty($CFG->divertallemailsto)) {
5657
        return false;
5531
        return false;
Línea 5675... Línea 5549...
5675
 * Generate a unique email Message-ID using the moodle domain and install path
5549
 * Generate a unique email Message-ID using the moodle domain and install path
5676
 *
5550
 *
5677
 * @param string $localpart An optional unique message id prefix.
5551
 * @param string $localpart An optional unique message id prefix.
5678
 * @return string The formatted ID ready for appending to the email headers.
5552
 * @return string The formatted ID ready for appending to the email headers.
5679
 */
5553
 */
5680
function generate_email_messageid($localpart = null)
5554
function generate_email_messageid($localpart = null) {
5681
{
-
 
5682
    global $CFG;
5555
    global $CFG;
Línea 5683... Línea 5556...
5683
 
5556
 
5684
    $urlinfo = parse_url($CFG->wwwroot);
5557
    $urlinfo = parse_url($CFG->wwwroot);
Línea 5719... Línea 5592...
5719
 * @param string $replyto Email address to reply to
5592
 * @param string $replyto Email address to reply to
5720
 * @param string $replytoname Name of reply to recipient
5593
 * @param string $replytoname Name of reply to recipient
5721
 * @param int $wordwrapwidth custom word wrap width, default 79
5594
 * @param int $wordwrapwidth custom word wrap width, default 79
5722
 * @return bool Returns true if mail was sent OK and false if there was an error.
5595
 * @return bool Returns true if mail was sent OK and false if there was an error.
5723
 */
5596
 */
5724
function email_to_user(
5597
function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '', $attachment = '', $attachname = '',
5725
    $user,
-
 
5726
    $from,
-
 
5727
    $subject,
-
 
5728
    $messagetext,
-
 
5729
    $messagehtml = '',
-
 
5730
    $attachment = '',
-
 
5731
    $attachname = '',
-
 
5732
    $usetrueaddress = true,
5598
                       $usetrueaddress = true, $replyto = '', $replytoname = '', $wordwrapwidth = 79) {
5733
    $replyto = '',
-
 
5734
    $replytoname = '',
-
 
5735
    $wordwrapwidth = 79
-
 
5736
) {
-
 
Línea 5737... Línea 5599...
5737
 
5599
 
Línea 5738... Línea 5600...
5738
    global $CFG, $PAGE, $SITE;
5600
    global $CFG, $PAGE, $SITE;
5739
 
5601
 
5740
    if (empty($user) or empty($user->id)) {
5602
    if (empty($user) or empty($user->id)) {
5741
        debugging('Can not send email to null user', DEBUG_DEVELOPER);
5603
        debugging('Can not send email to null user', DEBUG_DEVELOPER);
Línea 5742... Línea 5604...
5742
        return false;
5604
        return false;
5743
    }
5605
    }
5744
 
5606
 
5745
    if (empty($user->email)) {
5607
    if (empty($user->email)) {
Línea 5746... Línea 5608...
5746
        debugging('Can not send email to user without email: ' . $user->id, DEBUG_DEVELOPER);
5608
        debugging('Can not send email to user without email: '.$user->id, DEBUG_DEVELOPER);
5747
        return false;
5609
        return false;
5748
    }
5610
    }
5749
 
5611
 
Línea -... Línea 5612...
-
 
5612
    if (!empty($user->deleted)) {
5750
    if (!empty($user->deleted)) {
5613
        debugging('Can not send email to deleted user: '.$user->id, DEBUG_DEVELOPER);
-
 
5614
        return false;
5751
        debugging('Can not send email to deleted user: ' . $user->id, DEBUG_DEVELOPER);
5615
    }
5752
        return false;
5616
 
5753
    }
5617
    if (defined('BEHAT_SITE_RUNNING') && !defined('TEST_EMAILCATCHER_MAIL_SERVER') &&
Línea 5754... Línea 5618...
5754
 
5618
            !defined('TEST_EMAILCATCHER_API_SERVER')) {
5755
    if (defined('BEHAT_SITE_RUNNING')) {
5619
 
5756
        // Fake email sending in behat.
5620
        // Behat tests are running and we are not using email catcher so fake email sending.
5757
        return true;
5621
        return true;
5758
    }
5622
    }
Línea 5759... Línea 5623...
5759
 
5623
 
5760
    if (!empty($CFG->noemailever)) {
5624
    if (!empty($CFG->noemailever)) {
5761
        // Hidden setting for development sites, set in config.php if needed.
5625
        // Hidden setting for development sites, set in config.php if needed.
5762
        debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL);
5626
        debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_DEVELOPER);
5763
        return true;
5627
        return true;
Línea 5764... Línea 5628...
5764
    }
5628
    }
5765
 
5629
 
5766
    if (email_should_be_diverted($user->email)) {
5630
    if (email_should_be_diverted($user->email)) {
5767
        $subject = "[DIVERTED {$user->email}] $subject";
5631
        $subject = "[DIVERTED {$user->email}] $subject";
Línea 5768... Línea 5632...
5768
        $user = clone ($user);
5632
        $user = clone($user);
5769
        $user->email = $CFG->divertallemailsto;
5633
        $user->email = $CFG->divertallemailsto;
5770
    }
5634
    }
5771
 
5635
 
5772
    // Skip mail to suspended users.
5636
    // Skip mail to suspended users.
Línea 5773... Línea 5637...
5773
    if ((isset($user->auth) && $user->auth == 'nologin') or (isset($user->suspended) && $user->suspended)) {
5637
    if ((isset($user->auth) && $user->auth=='nologin') or (isset($user->suspended) && $user->suspended)) {
5774
        return true;
5638
        return true;
5775
    }
5639
    }
5776
 
5640
 
Línea 5777... Línea 5641...
5777
    if (!validate_email($user->email)) {
5641
    if (!validate_email($user->email)) {
5778
        // We can not send emails to invalid addresses - it might create security issue or confuse the mailer.
5642
        // We can not send emails to invalid addresses - it might create security issue or confuse the mailer.
5779
        debugging("email_to_user: User $user->id (" . fullname($user) . ") email ($user->email) is invalid! Not sending.");
5643
        debugging("email_to_user: User $user->id (".fullname($user).") email ($user->email) is invalid! Not sending.");
5780
        return false;
5644
        return false;
5781
    }
5645
    }
5782
 
5646
 
Línea 5783... Línea 5647...
5783
    if (over_bounce_threshold($user)) {
5647
    if (over_bounce_threshold($user)) {
5784
        debugging("email_to_user: User $user->id (" . fullname($user) . ") is over bounce threshold! Not sending.");
5648
        debugging("email_to_user: User $user->id (".fullname($user).") is over bounce threshold! Not sending.");
5785
        return false;
5649
        return false;
5786
    }
5650
    }
5787
 
5651
 
Línea 5788... Línea 5652...
5788
    // TLD .invalid  is specifically reserved for invalid domain names.
5652
    // TLD .invalid  is specifically reserved for invalid domain names.
5789
    // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}.
5653
    // For More information, see {@link http://tools.ietf.org/html/rfc2606#section-2}.
Línea 5790... Línea 5654...
5790
    if (substr($user->email, -8) == '.invalid') {
5654
    if (substr($user->email, -8) == '.invalid') {
5791
        debugging("email_to_user: User $user->id (" . fullname($user) . ") email domain ($user->email) is invalid! Not sending.");
-
 
5792
        return true; // This is not an error.
5655
        debugging("email_to_user: User $user->id (".fullname($user).") email domain ($user->email) is invalid! Not sending.");
5793
    }
5656
        return true; // This is not an error.
5794
 
-
 
5795
    // If the user is a remote mnet user, parse the email text for URL to the
-
 
5796
    // wwwroot and modify the url to direct the user's browser to login at their
5657
    }
5797
    // home site (identity provider - idp) before hitting the link itself.
5658
 
5798
    if (is_mnet_remote_user($user)) {
5659
    // If the user is a remote mnet user, parse the email text for URL to the
5799
        require_once($CFG->dirroot . '/mnet/lib.php');
-
 
5800
 
5660
    // wwwroot and modify the url to direct the user's browser to login at their
5801
        $jumpurl = mnet_get_idp_jump_url($user);
5661
    // home site (identity provider - idp) before hitting the link itself.
Línea 5802... Línea 5662...
5802
        $callback = partial('mnet_sso_apply_indirection', $jumpurl);
5662
    if (is_mnet_remote_user($user)) {
5803
 
5663
        require_once($CFG->dirroot.'/mnet/lib.php');
Línea 5824... Línea 5684...
5824
    // Make sure that we fall back onto some reasonable no-reply address.
5684
    // Make sure that we fall back onto some reasonable no-reply address.
5825
    $noreplyaddressdefault = 'noreply@' . get_host_from_url($CFG->wwwroot);
5685
    $noreplyaddressdefault = 'noreply@' . get_host_from_url($CFG->wwwroot);
5826
    $noreplyaddress = empty($CFG->noreplyaddress) ? $noreplyaddressdefault : $CFG->noreplyaddress;
5686
    $noreplyaddress = empty($CFG->noreplyaddress) ? $noreplyaddressdefault : $CFG->noreplyaddress;
Línea 5827... Línea 5687...
5827
 
5687
 
5828
    if (!validate_email($noreplyaddress)) {
5688
    if (!validate_email($noreplyaddress)) {
5829
        debugging('email_to_user: Invalid noreply-email ' . s($noreplyaddress));
5689
        debugging('email_to_user: Invalid noreply-email '.s($noreplyaddress));
5830
        $noreplyaddress = $noreplyaddressdefault;
5690
        $noreplyaddress = $noreplyaddressdefault;
Línea 5831... Línea 5691...
5831
    }
5691
    }
5832
 
5692
 
5833
    // Make up an email address for handling bounces.
5693
    // Make up an email address for handling bounces.
5834
    if (!empty($CFG->handlebounces)) {
5694
    if (!empty($CFG->handlebounces)) {
5835
        $modargs = 'B' . base64_encode(pack('V', $user->id)) . substr(md5($user->email), 0, 16);
5695
        $modargs = 'B'.base64_encode(pack('V', $user->id)).substr(md5($user->email), 0, 16);
5836
        $mail->Sender = generate_email_processing_address(0, $modargs);
5696
        $mail->Sender = generate_email_processing_address(0, $modargs);
5837
    } else {
5697
    } else {
Línea 5838... Línea 5698...
5838
        $mail->Sender = $noreplyaddress;
5698
        $mail->Sender = $noreplyaddress;
5839
    }
5699
    }
5840
 
5700
 
5841
    // Make sure that the explicit replyto is valid, fall back to the implicit one.
5701
    // Make sure that the explicit replyto is valid, fall back to the implicit one.
5842
    if (!empty($replyto) && !validate_email($replyto)) {
5702
    if (!empty($replyto) && !validate_email($replyto)) {
Línea 5843... Línea 5703...
5843
        debugging('email_to_user: Invalid replyto-email ' . s($replyto));
5703
        debugging('email_to_user: Invalid replyto-email '.s($replyto));
5844
        $replyto = $noreplyaddress;
5704
        $replyto = $noreplyaddress;
5845
    }
5705
    }
5846
 
5706
 
5847
    if (is_string($from)) { // So we can pass whatever we want if there is need.
5707
    if (is_string($from)) { // So we can pass whatever we want if there is need.
5848
        $mail->From     = $noreplyaddress;
5708
        $mail->From     = $noreplyaddress;
5849
        $mail->FromName = $from;
5709
        $mail->FromName = $from;
5850
        // Check if using the true address is true, and the email is in the list of allowed domains for sending email,
5710
    // Check if using the true address is true, and the email is in the list of allowed domains for sending email,
5851
        // and that the senders email setting is either displayed to everyone, or display to only other users that are enrolled
5711
    // and that the senders email setting is either displayed to everyone, or display to only other users that are enrolled
5852
        // in a course with the sender.
5712
    // in a course with the sender.
5853
    } else if ($usetrueaddress && can_send_from_real_email_address($from, $user)) {
5713
    } else if ($usetrueaddress && can_send_from_real_email_address($from, $user)) {
5854
        if (!validate_email($from->email)) {
5714
        if (!validate_email($from->email)) {
5855
            debugging('email_to_user: Invalid from-email ' . s($from->email) . ' - not sending');
5715
            debugging('email_to_user: Invalid from-email '.s($from->email).' - not sending');
5856
            // Better not to use $noreplyaddress in this case.
5716
            // Better not to use $noreplyaddress in this case.
Línea 5918... Línea 5778...
5918
                $origin = $call;
5778
                $origin = $call;
5919
            }
5779
            }
5920
        }
5780
        }
Línea 5921... Línea 5781...
5921
 
5781
 
5922
        $originheader = $CFG->wwwroot . ' => ' . gethostname() . ':'
5782
        $originheader = $CFG->wwwroot . ' => ' . gethostname() . ':'
5923
            . str_replace($CFG->dirroot . '/', '', $origin['file']) . ':' . $origin['line'];
5783
             . str_replace($CFG->dirroot . '/', '', $origin['file']) . ':' . $origin['line'];
5924
        $mail->addCustomHeader('X-Moodle-Originating-Script: ' . $originheader);
5784
        $mail->addCustomHeader('X-Moodle-Originating-Script: ' . $originheader);
Línea 5925... Línea 5785...
5925
    }
5785
    }
5926
 
5786
 
Línea 5979... Línea 5839...
5979
    if (empty($mail->MessageID)) {
5839
    if (empty($mail->MessageID)) {
5980
        $mail->MessageID = generate_email_messageid();
5840
        $mail->MessageID = generate_email_messageid();
5981
    }
5841
    }
Línea 5982... Línea 5842...
5982
 
5842
 
5983
    if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) {
-
 
5984
        global $CFG; // Necesario para usar $CFG->wwwroot
-
 
5985
 
5843
    if ($messagehtml && !empty($user->mailformat) && $user->mailformat == 1) {
5986
        // Construir URLs de imágenes basadas en el dominio del sitio
-
 
5987
        $header_image_url = $CFG->wwwroot . '/theme/universe_child/pix/logo-horizontal-cesa.png';
-
 
5988
        $footer_image_url = $CFG->wwwroot . '/theme/universe_child/pix/email-footer.png';
-
 
5989
 
-
 
5990
        $header_html = "
-
 
5991
            <div style=\"text-align:left; margin-bottom:20px;\">
-
 
5992
                <h1 style=\"margin: 0; font-size: 24px; font-weight: bold;\">ONROOM</h1>
-
 
5993
            </div>";
-
 
5994
 
-
 
5995
        $footer_html = "
-
 
5996
            <div style=\"text-align:center; margin-top:40px;\">
-
 
5997
                <p style=\"margin: 0; font-size: 16px;\">Construyendo Futuro - Desarrollando Líderes y Personas</p>
-
 
5998
            </div>";
-
 
5999
 
-
 
6000
        // Unir todo: Header + Contenido original + Footer
-
 
6001
        $full_html_message = $messagehtml;
-
 
6002
 
5844
        // Don't ever send HTML to users who don't want it.
6003
        $mail->isHTML(true);
5845
        $mail->isHTML(true);
6004
        $mail->Encoding = 'quoted-printable';
5846
        $mail->Encoding = 'quoted-printable';
6005
        $mail->Body = $full_html_message; // Ahora enviamos Header + Contenido + Footer
5847
        $mail->Body    =  $messagehtml;
6006
        $mail->AltBody = $messagetext; // Versión texto plano
5848
        $mail->AltBody =  "\n$messagetext\n";
6007
    } else {
5849
    } else {
6008
        $mail->IsHTML(false);
5850
        $mail->IsHTML(false);
6009
        $mail->Body =  "\n$messagetext\n";
5851
        $mail->Body =  "\n$messagetext\n";
Línea 6010... Línea 5852...
6010
    }
5852
    }
6011
 
5853
 
6012
    if ($attachment && $attachname) {
5854
    if ($attachment && $attachname) {
6013
        if (preg_match("~\\.\\.~", $attachment)) {
5855
        if (preg_match( "~\\.\\.~" , $attachment )) {
6014
            // Security check for ".." in dir path.
5856
            // Security check for ".." in dir path.
6015
            $supportuser = core_user::get_support_user();
5857
            $supportuser = core_user::get_support_user();
6016
            $temprecipients[] = array($supportuser->email, fullname($supportuser, true));
5858
            $temprecipients[] = array($supportuser->email, fullname($supportuser, true));
6017
            $mail->addStringAttachment('Error in attachment.  User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain');
5859
            $mail->addStringAttachment('Error in attachment.  User attempted to attach a filename with a unsafe name.', 'error.txt', '8bit', 'text/plain');
6018
        } else {
5860
        } else {
Línea 6019... Línea 5861...
6019
            require_once($CFG->libdir . '/filelib.php');
5861
            require_once($CFG->libdir.'/filelib.php');
6020
            $mimetype = mimeinfo('type', $attachname);
5862
            $mimetype = mimeinfo('type', $attachname);
6021
 
5863
 
Línea 6022... Línea 5864...
6022
            // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction).
5864
            // Before doing the comparison, make sure that the paths are correct (Windows uses slashes in the other direction).
6023
            // The absolute (real) path is also fetched to ensure that comparisons to allowed paths are compared equally.
5865
            // The absolute (real) path is also fetched to ensure that comparisons to allowed paths are compared equally.
6024
            $attachpath = str_replace('\\', '/', realpath($attachment));
5866
            $attachpath = str_replace('\\', '/', realpath($attachment));
6025
 
5867
 
6026
            // Build an array of all filepaths from which attachments can be added (normalised slashes, absolute/real path).
5868
            // Build an array of all filepaths from which attachments can be added (normalised slashes, absolute/real path).
6027
            $allowedpaths = array_map(function (string $path): string {
5869
            $allowedpaths = array_map(function(string $path): string {
6028
                return str_replace('\\', '/', realpath($path));
5870
                return str_replace('\\', '/', realpath($path));
Línea 6125... Línea 5967...
6125
                'errorinfo' => $mail->ErrorInfo
5967
                'errorinfo' => $mail->ErrorInfo
6126
            )
5968
            )
6127
        ));
5969
        ));
6128
        $event->trigger();
5970
        $event->trigger();
6129
        if (CLI_SCRIPT) {
5971
        if (CLI_SCRIPT) {
6130
            mtrace('Error: lib/moodlelib.php email_to_user(): ' . $mail->ErrorInfo);
5972
            mtrace('Error: lib/moodlelib.php email_to_user(): '.$mail->ErrorInfo);
6131
        }
5973
        }
6132
        if (!empty($mail->SMTPDebug)) {
5974
        if (!empty($mail->SMTPDebug)) {
6133
            echo '</pre>';
5975
            echo '</pre>';
6134
        }
5976
        }
6135
        return false;
5977
        return false;
Línea 6142... Línea 5984...
6142
 * @param  object $from The user object for the user we are sending the email from.
5984
 * @param  object $from The user object for the user we are sending the email from.
6143
 * @param  object $user The user object that we are sending the email to.
5985
 * @param  object $user The user object that we are sending the email to.
6144
 * @param  array $unused No longer used.
5986
 * @param  array $unused No longer used.
6145
 * @return bool Returns true if we can use the from user's email adress in the "From" field.
5987
 * @return bool Returns true if we can use the from user's email adress in the "From" field.
6146
 */
5988
 */
6147
function can_send_from_real_email_address($from, $user, $unused = null)
5989
function can_send_from_real_email_address($from, $user, $unused = null) {
6148
{
-
 
6149
    global $CFG;
5990
    global $CFG;
6150
    if (!isset($CFG->allowedemaildomains) || empty(trim($CFG->allowedemaildomains))) {
5991
    if (!isset($CFG->allowedemaildomains) || empty(trim($CFG->allowedemaildomains))) {
6151
        return false;
5992
        return false;
6152
    }
5993
    }
6153
    $alloweddomains = array_map('trim', explode("\n", $CFG->allowedemaildomains));
5994
    $alloweddomains = array_map('trim', explode("\n", $CFG->allowedemaildomains));
6154
    // Email is in the list of allowed domains for sending email,
5995
    // Email is in the list of allowed domains for sending email,
6155
    // and the senders email setting is either displayed to everyone, or display to only other users that are enrolled
5996
    // and the senders email setting is either displayed to everyone, or display to only other users that are enrolled
6156
    // in a course with the sender.
5997
    // in a course with the sender.
6157
    if (
-
 
6158
        \core\ip_utils::is_domain_in_allowed_list(substr($from->email, strpos($from->email, '@') + 1), $alloweddomains)
5998
    if (\core\ip_utils::is_domain_in_allowed_list(substr($from->email, strpos($from->email, '@') + 1), $alloweddomains)
6159
        && ($from->maildisplay == core_user::MAILDISPLAY_EVERYONE
5999
                && ($from->maildisplay == core_user::MAILDISPLAY_EVERYONE
6160
            || ($from->maildisplay == core_user::MAILDISPLAY_COURSE_MEMBERS_ONLY
6000
                || ($from->maildisplay == core_user::MAILDISPLAY_COURSE_MEMBERS_ONLY
6161
                && enrol_get_shared_courses($user, $from, false, true)))
6001
                && enrol_get_shared_courses($user, $from, false, true)))) {
6162
    ) {
-
 
6163
        return true;
6002
        return true;
6164
    }
6003
    }
6165
    return false;
6004
    return false;
6166
}
6005
}
Línea 6167... Línea 6006...
6167
 
6006
 
6168
/**
6007
/**
6169
 * Generate a signoff for emails based on support settings
6008
 * Generate a signoff for emails based on support settings
6170
 *
6009
 *
6171
 * @return string
6010
 * @return string
6172
 */
6011
 */
6173
function generate_email_signoff()
-
 
6174
{
6012
function generate_email_signoff() {
Línea 6175... Línea 6013...
6175
    global $CFG, $OUTPUT;
6013
    global $CFG, $OUTPUT;
6176
 
6014
 
6177
    $signoff = "\n";
6015
    $signoff = "\n";
6178
    if (!empty($CFG->supportname)) {
6016
    if (!empty($CFG->supportname)) {
Línea 6179... Línea 6017...
6179
        $signoff .= $CFG->supportname . "\n";
6017
        $signoff .= $CFG->supportname."\n";
Línea 6180... Línea 6018...
6180
    }
6018
    }
6181
 
6019
 
6182
    $supportemail = $OUTPUT->supportemail(['class' => 'font-weight-bold']);
6020
    $supportemail = $OUTPUT->supportemail(['class' => 'fw-bold']);
Línea 6193... Línea 6031...
6193
 *
6031
 *
6194
 * @param stdClass $user A {@link $USER} object
6032
 * @param stdClass $user A {@link $USER} object
6195
 * @param bool $fasthash If true, use a low cost factor when generating the hash for speed.
6033
 * @param bool $fasthash If true, use a low cost factor when generating the hash for speed.
6196
 * @return bool|string Returns "true" if mail was sent OK and "false" if there was an error
6034
 * @return bool|string Returns "true" if mail was sent OK and "false" if there was an error
6197
 */
6035
 */
6198
function setnew_password_and_mail($user, $fasthash = false)
6036
function setnew_password_and_mail($user, $fasthash = false) {
6199
{
-
 
6200
    global $CFG, $DB;
6037
    global $CFG, $DB;
Línea 6201... Línea 6038...
6201
 
6038
 
6202
    // We try to send the mail in language the user understands,
6039
    // We try to send the mail in language the user understands,
6203
    // unfortunately the filter_string() does not support alternative langs yet
6040
    // unfortunately the filter_string() does not support alternative langs yet
Línea 6211... Línea 6048...
6211
    $newpassword = generate_password();
6048
    $newpassword = generate_password();
Línea 6212... Línea 6049...
6212
 
6049
 
Línea 6213... Línea 6050...
6213
    update_internal_user_password($user, $newpassword, $fasthash);
6050
    update_internal_user_password($user, $newpassword, $fasthash);
6214
 
6051
 
-
 
6052
    $a = new stdClass();
-
 
6053
    $placeholders = \core_user::get_name_placeholders($user);
-
 
6054
    foreach ($placeholders as $field => $value) {
6215
    $a = new stdClass();
6055
        $a->{$field} = $value;
6216
    $a->firstname   = fullname($user, true);
6056
    }
6217
    $a->sitename    = format_string($site->fullname);
6057
    $a->sitename    = format_string($site->fullname);
6218
    $a->username    = $user->username;
6058
    $a->username    = $user->username;
6219
    $a->newpassword = $newpassword;
6059
    $a->newpassword = $newpassword;
Línea 6220... Línea 6060...
6220
    $a->link        = $CFG->wwwroot . '/login/?lang=' . $lang;
6060
    $a->link        = $CFG->wwwroot .'/login/?lang='.$lang;
Línea 6221... Línea 6061...
6221
    $a->signoff     = generate_email_signoff();
6061
    $a->signoff     = generate_email_signoff();
Línea 6222... Línea 6062...
6222
 
6062
 
6223
    $message = (string)new lang_string('newusernewpasswordtext', '', $a, $lang);
6063
    $message = (string)new lang_string('newusernewpasswordtext', '', $a, $lang);
6224
 
-
 
6225
    $subject = format_string($site->fullname) . ': ' . (string)new lang_string('newusernewpasswordsubj', '', $a, $lang);
-
 
6226
 
-
 
6227
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
-
 
6228
    return email_to_user($user, $supportuser, $subject, $message);
-
 
6229
}
-
 
6230
 
-
 
6231
/**
-
 
6232
 * Resets specified user's password and send the new password to the user via email.
-
 
6233
 *
-
 
6234
 * @param stdClass $user A {@link $USER} object
-
 
6235
 * @return bool Returns true if mail was sent OK and false if there was an error.
-
 
6236
 */
-
 
6237
function reset_password_and_mail($user)
-
 
6238
{
-
 
6239
    global $CFG;
-
 
6240
 
-
 
6241
    $site  = get_site();
-
 
6242
    $supportuser = core_user::get_support_user();
-
 
6243
 
-
 
6244
    $userauth = get_auth_plugin($user->auth);
-
 
6245
    if (!$userauth->can_reset_password() or !is_enabled_auth($user->auth)) {
-
 
6246
        trigger_error("Attempt to reset user password for user $user->username with Auth $user->auth.");
-
 
6247
        return false;
-
 
6248
    }
-
 
6249
 
-
 
6250
    $newpassword = generate_password();
-
 
6251
 
-
 
6252
    if (!$userauth->user_update_password($user, $newpassword)) {
-
 
6253
        throw new \moodle_exception("cannotsetpassword");
-
 
6254
    }
-
 
6255
 
-
 
6256
    $a = new stdClass();
-
 
6257
    $a->firstname   = $user->firstname;
-
 
6258
    $a->lastname    = $user->lastname;
-
 
6259
    $a->sitename    = format_string($site->fullname);
-
 
6260
    $a->username    = $user->username;
-
 
6261
    $a->newpassword = $newpassword;
-
 
6262
    $a->link        = $CFG->wwwroot . '/login/change_password.php';
-
 
6263
    $a->signoff     = generate_email_signoff();
-
 
6264
 
-
 
Línea 6265... Línea -...
6265
    $message = get_string('newpasswordtext', '', $a);
-
 
6266
 
-
 
6267
    $subject  = format_string($site->fullname) . ': ' . get_string('changedpassword');
6064
 
Línea 6268... Línea 6065...
6268
 
6065
    $subject = format_string($site->fullname) .': '. (string)new lang_string('newusernewpasswordsubj', '', $a, $lang);
6269
    unset_user_preference('create_password', $user); // Prevent cron from generating the password.
6066
 
6270
 
6067
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
6271
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
6068
    return email_to_user($user, $supportuser, $subject, $message);
6272
    return email_to_user($user, $supportuser, $subject, $message);
6069
 
6273
}
6070
}
6274
 
6071
 
6275
/**
6072
/**
6276
 * Send email to specified user with confirmation text and activation link.
-
 
6277
 *
6073
 * Send email to specified user with confirmation text and activation link.
Línea 6278... Línea 6074...
6278
 * @param stdClass $user A {@link $USER} object
6074
 *
6279
 * @param string $confirmationurl user confirmation URL
6075
 * @param stdClass $user A {@link $USER} object
Línea 6280... Línea 6076...
6280
 * @return bool Returns true if mail was sent OK and false if there was an error.
6076
 * @param string $confirmationurl user confirmation URL
6281
 */
6077
 * @return bool Returns true if mail was sent OK and false if there was an error.
6282
function send_confirmation_email($user, $confirmationurl = null)
6078
 */
-
 
6079
function send_confirmation_email($user, $confirmationurl = null) {
-
 
6080
    global $CFG;
-
 
6081
 
-
 
6082
    $site = get_site();
-
 
6083
    $supportuser = core_user::get_support_user();
Línea 6283... Línea 6084...
6283
{
6084
 
Línea 6284... Línea 6085...
6284
    global $CFG;
6085
    $data = new stdClass();
6285
 
6086
    $data->sitename  = format_string($site->fullname);
Línea 6308... Línea 6109...
6308
    // Perform normal url encoding of the username first.
6109
    // Perform normal url encoding of the username first.
6309
    $username = urlencode($user->username);
6110
    $username = urlencode($user->username);
6310
    // Prevent problems with trailing dots not being included as part of link in some mail clients.
6111
    // Prevent problems with trailing dots not being included as part of link in some mail clients.
6311
    $username = str_replace('.', '%2E', $username);
6112
    $username = str_replace('.', '%2E', $username);
Línea 6312... Línea 6113...
6312
 
6113
 
Línea 6313... Línea 6114...
6313
    $data->link = $confirmationpath . ($hasquerystring ? '&' : '?') . 'data=' . $user->secret . '/' . $username;
6114
    $data->link = $confirmationpath . ( $hasquerystring ? '&' : '?') . 'data='. $user->secret .'/'. $username;
6314
 
6115
 
Línea 6315... Línea 6116...
6315
    $message     = get_string('emailconfirmation', '', $data);
6116
    $message     = get_string('emailconfirmation', '', $data);
Línea 6324... Línea 6125...
6324
 *
6125
 *
6325
 * @param stdClass $user A {@link $USER} object
6126
 * @param stdClass $user A {@link $USER} object
6326
 * @param stdClass $resetrecord An object tracking metadata regarding password reset request
6127
 * @param stdClass $resetrecord An object tracking metadata regarding password reset request
6327
 * @return bool Returns true if mail was sent OK and false if there was an error.
6128
 * @return bool Returns true if mail was sent OK and false if there was an error.
6328
 */
6129
 */
6329
function send_password_change_confirmation_email($user, $resetrecord)
6130
function send_password_change_confirmation_email($user, $resetrecord) {
6330
{
-
 
6331
    global $CFG;
6131
    global $CFG;
Línea 6332... Línea 6132...
6332
 
6132
 
6333
    $site = get_site();
6133
    $site = get_site();
6334
    $supportuser = core_user::get_support_user();
6134
    $supportuser = core_user::get_support_user();
Línea 6335... Línea 6135...
6335
    $pwresetmins = isset($CFG->pwresettime) ? floor($CFG->pwresettime / MINSECS) : 30;
6135
    $pwresetmins = isset($CFG->pwresettime) ? floor($CFG->pwresettime / MINSECS) : 30;
-
 
6136
 
6336
 
6137
    $data = new stdClass();
6337
    $data = new stdClass();
6138
    $placeholders = \core_user::get_name_placeholders($user);
-
 
6139
    foreach ($placeholders as $field => $value) {
6338
    $data->firstname = $user->firstname;
6140
        $data->{$field} = $value;
6339
    $data->lastname  = $user->lastname;
6141
    }
6340
    $data->username  = $user->username;
6142
    $data->username  = $user->username;
6341
    $data->sitename  = format_string($site->fullname);
6143
    $data->sitename  = format_string($site->fullname);
6342
    $data->link      = $CFG->wwwroot . '/login/forgot_password.php?token=' . $resetrecord->token;
6144
    $data->link      = $CFG->wwwroot .'/login/forgot_password.php?token='. $resetrecord->token;
Línea 6343... Línea 6145...
6343
    $data->admin     = generate_email_signoff();
6145
    $data->admin     = generate_email_signoff();
6344
    $data->resetminutes = $pwresetmins;
6146
    $data->resetminutes = $pwresetmins;
Línea 6345... Línea 6147...
6345
 
6147
 
6346
    $message = get_string('emailresetconfirmation', '', $data);
6148
    $message = get_string('emailresetconfirmation', '', $data);
-
 
6149
    $subject = get_string('emailresetconfirmationsubject', '', format_string($site->fullname));
6347
    $subject = get_string('emailresetconfirmationsubject', '', format_string($site->fullname));
6150
 
Línea 6348... Línea 6151...
6348
 
6151
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
6349
    // Directly email rather than using the messaging system to ensure its not routed to a popup or jabber.
6152
    return email_to_user($user, $supportuser, $subject, $message);
6350
    return email_to_user($user, $supportuser, $subject, $message);
6153
 
6351
}
6154
}
6352
 
6155
 
6353
/**
6156
/**
6354
 * Sends an email containing information on how to change your password.
6157
 * Sends an email containing information on how to change your password.
6355
 *
-
 
6356
 * @param stdClass $user A {@link $USER} object
6158
 *
6357
 * @return bool Returns true if mail was sent OK and false if there was an error.
6159
 * @param stdClass $user A {@link $USER} object
Línea 6358... Línea 6160...
6358
 */
6160
 * @return bool Returns true if mail was sent OK and false if there was an error.
-
 
6161
 */
6359
function send_password_change_info($user)
6162
function send_password_change_info($user) {
6360
{
6163
    $site = get_site();
-
 
6164
    $supportuser = core_user::get_support_user();
6361
    $site = get_site();
6165
 
6362
    $supportuser = core_user::get_support_user();
6166
    $data = new stdClass();
6363
 
6167
    $placeholders = \core_user::get_name_placeholders($user);
Línea 6364... Línea 6168...
6364
    $data = new stdClass();
6168
    foreach ($placeholders as $field => $value) {
Línea 6386... Línea 6190...
6386
 * Check that an email is allowed.  It returns an error message if there was a problem.
6190
 * Check that an email is allowed.  It returns an error message if there was a problem.
6387
 *
6191
 *
6388
 * @param string $email Content of email
6192
 * @param string $email Content of email
6389
 * @return string|false
6193
 * @return string|false
6390
 */
6194
 */
6391
function email_is_not_allowed($email)
6195
function email_is_not_allowed($email) {
6392
{
-
 
6393
    global $CFG;
6196
    global $CFG;
Línea 6394... Línea 6197...
6394
 
6197
 
6395
    // Comparing lowercase domains.
6198
    // Comparing lowercase domains.
6396
    $email = strtolower($email);
6199
    $email = strtolower($email);
Línea 6404... Línea 6207...
6404
            if (strpos($allowedpattern, '.') === 0) {
6207
            if (strpos($allowedpattern, '.') === 0) {
6405
                if (strpos(strrev($email), strrev($allowedpattern)) === 0) {
6208
                if (strpos(strrev($email), strrev($allowedpattern)) === 0) {
6406
                    // Subdomains are in a form ".example.com" - matches "xxx@anything.example.com".
6209
                    // Subdomains are in a form ".example.com" - matches "xxx@anything.example.com".
6407
                    return false;
6210
                    return false;
6408
                }
6211
                }
-
 
6212
 
6409
            } else if (strpos(strrev($email), strrev('@' . $allowedpattern)) === 0) {
6213
            } else if (strpos(strrev($email), strrev('@'.$allowedpattern)) === 0) {
6410
                return false;
6214
                return false;
6411
            }
6215
            }
6412
        }
6216
        }
6413
        return get_string('emailonlyallowed', '', $CFG->allowemailaddresses);
6217
        return get_string('emailonlyallowed', '', $CFG->allowemailaddresses);
-
 
6218
 
6414
    } else if (!empty($CFG->denyemailaddresses)) {
6219
    } else if (!empty($CFG->denyemailaddresses)) {
6415
        $denied = explode(' ', strtolower($CFG->denyemailaddresses));
6220
        $denied = explode(' ', strtolower($CFG->denyemailaddresses));
6416
        foreach ($denied as $deniedpattern) {
6221
        foreach ($denied as $deniedpattern) {
6417
            $deniedpattern = trim($deniedpattern);
6222
            $deniedpattern = trim($deniedpattern);
6418
            if (!$deniedpattern) {
6223
            if (!$deniedpattern) {
Línea 6421... Línea 6226...
6421
            if (strpos($deniedpattern, '.') === 0) {
6226
            if (strpos($deniedpattern, '.') === 0) {
6422
                if (strpos(strrev($email), strrev($deniedpattern)) === 0) {
6227
                if (strpos(strrev($email), strrev($deniedpattern)) === 0) {
6423
                    // Subdomains are in a form ".example.com" - matches "xxx@anything.example.com".
6228
                    // Subdomains are in a form ".example.com" - matches "xxx@anything.example.com".
6424
                    return get_string('emailnotallowed', '', $CFG->denyemailaddresses);
6229
                    return get_string('emailnotallowed', '', $CFG->denyemailaddresses);
6425
                }
6230
                }
-
 
6231
 
6426
            } else if (strpos(strrev($email), strrev('@' . $deniedpattern)) === 0) {
6232
            } else if (strpos(strrev($email), strrev('@'.$deniedpattern)) === 0) {
6427
                return get_string('emailnotallowed', '', $CFG->denyemailaddresses);
6233
                return get_string('emailnotallowed', '', $CFG->denyemailaddresses);
6428
            }
6234
            }
6429
        }
6235
        }
6430
    }
6236
    }
Línea 6437... Línea 6243...
6437
/**
6243
/**
6438
 * Returns local file storage instance
6244
 * Returns local file storage instance
6439
 *
6245
 *
6440
 * @return ?file_storage
6246
 * @return ?file_storage
6441
 */
6247
 */
6442
function get_file_storage($reset = false)
6248
function get_file_storage($reset = false) {
6443
{
-
 
6444
    global $CFG;
6249
    global $CFG;
Línea 6445... Línea 6250...
6445
 
6250
 
Línea 6446... Línea 6251...
6446
    static $fs = null;
6251
    static $fs = null;
Línea 6464... Línea 6269...
6464
/**
6269
/**
6465
 * Returns local file storage instance
6270
 * Returns local file storage instance
6466
 *
6271
 *
6467
 * @return file_browser
6272
 * @return file_browser
6468
 */
6273
 */
6469
function get_file_browser()
6274
function get_file_browser() {
6470
{
-
 
6471
    global $CFG;
6275
    global $CFG;
Línea 6472... Línea 6276...
6472
 
6276
 
Línea 6473... Línea 6277...
6473
    static $fb = null;
6277
    static $fb = null;
Línea 6487... Línea 6291...
6487
 * Returns file packer
6291
 * Returns file packer
6488
 *
6292
 *
6489
 * @param string $mimetype default application/zip
6293
 * @param string $mimetype default application/zip
6490
 * @return file_packer|false
6294
 * @return file_packer|false
6491
 */
6295
 */
6492
function get_file_packer($mimetype = 'application/zip')
6296
function get_file_packer($mimetype='application/zip') {
6493
{
-
 
6494
    global $CFG;
6297
    global $CFG;
Línea 6495... Línea 6298...
6495
 
6298
 
Línea 6496... Línea 6299...
6496
    static $fp = array();
6299
    static $fp = array();
Línea 6503... Línea 6306...
6503
        case 'application/zip':
6306
        case 'application/zip':
6504
        case 'application/vnd.moodle.profiling':
6307
        case 'application/vnd.moodle.profiling':
6505
            $classname = 'zip_packer';
6308
            $classname = 'zip_packer';
6506
            break;
6309
            break;
Línea 6507... Línea 6310...
6507
 
6310
 
6508
        case 'application/x-gzip':
6311
        case 'application/x-gzip' :
6509
            $classname = 'tgz_packer';
6312
            $classname = 'tgz_packer';
Línea 6510... Línea 6313...
6510
            break;
6313
            break;
6511
 
6314
 
Línea 6527... Línea 6330...
6527
 * Returns current name of file on disk if it exists.
6330
 * Returns current name of file on disk if it exists.
6528
 *
6331
 *
6529
 * @param string $newfile File to be verified
6332
 * @param string $newfile File to be verified
6530
 * @return string Current name of file on disk if true
6333
 * @return string Current name of file on disk if true
6531
 */
6334
 */
6532
function valid_uploaded_file($newfile)
6335
function valid_uploaded_file($newfile) {
6533
{
-
 
6534
    if (empty($newfile)) {
6336
    if (empty($newfile)) {
6535
        return '';
6337
        return '';
6536
    }
6338
    }
6537
    if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
6339
    if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
6538
        return $newfile['tmp_name'];
6340
        return $newfile['tmp_name'];
Línea 6563... Línea 6365...
6563
 * @param int $coursebytes Current course $course->maxbytes (in bytes)
6365
 * @param int $coursebytes Current course $course->maxbytes (in bytes)
6564
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6366
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6565
 * @param bool $unused This parameter has been deprecated and is not used any more.
6367
 * @param bool $unused This parameter has been deprecated and is not used any more.
6566
 * @return int The maximum size for uploading files.
6368
 * @return int The maximum size for uploading files.
6567
 */
6369
 */
6568
function get_max_upload_file_size($sitebytes = 0, $coursebytes = 0, $modulebytes = 0, $unused = false)
6370
function get_max_upload_file_size($sitebytes=0, $coursebytes=0, $modulebytes=0, $unused = false) {
6569
{
-
 
Línea 6570... Línea 6371...
6570
 
6371
 
6571
    if (! $filesize = ini_get('upload_max_filesize')) {
6372
    if (! $filesize = ini_get('upload_max_filesize')) {
6572
        $filesize = '5M';
6373
        $filesize = '5M';
6573
    }
6374
    }
Línea 6606... Línea 6407...
6606
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6407
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6607
 * @param stdClass|int|null $user The user
6408
 * @param stdClass|int|null $user The user
6608
 * @param bool $unused This parameter has been deprecated and is not used any more.
6409
 * @param bool $unused This parameter has been deprecated and is not used any more.
6609
 * @return int The maximum size for uploading files.
6410
 * @return int The maximum size for uploading files.
6610
 */
6411
 */
6611
function get_user_max_upload_file_size(
6412
function get_user_max_upload_file_size($context, $sitebytes = 0, $coursebytes = 0, $modulebytes = 0, $user = null,
6612
    $context,
-
 
6613
    $sitebytes = 0,
-
 
6614
    $coursebytes = 0,
-
 
6615
    $modulebytes = 0,
-
 
6616
    $user = null,
-
 
6617
    $unused = false
6413
        $unused = false) {
6618
) {
-
 
6619
    global $USER;
6414
    global $USER;
Línea 6620... Línea 6415...
6620
 
6415
 
6621
    if (empty($user)) {
6416
    if (empty($user)) {
6622
        $user = $USER;
6417
        $user = $USER;
Línea 6647... Línea 6442...
6647
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6442
 * @param int $modulebytes Current module ->maxbytes (in bytes)
6648
 * @param int|array $custombytes custom upload size/s which will be added to list,
6443
 * @param int|array $custombytes custom upload size/s which will be added to list,
6649
 *        Only value/s smaller then maxsize will be added to list.
6444
 *        Only value/s smaller then maxsize will be added to list.
6650
 * @return array
6445
 * @return array
6651
 */
6446
 */
6652
function get_max_upload_sizes($sitebytes = 0, $coursebytes = 0, $modulebytes = 0, $custombytes = null)
6447
function get_max_upload_sizes($sitebytes = 0, $coursebytes = 0, $modulebytes = 0, $custombytes = null) {
6653
{
-
 
6654
    global $CFG;
6448
    global $CFG;
Línea 6655... Línea 6449...
6655
 
6449
 
6656
    if (!$maxsize = get_max_upload_file_size($sitebytes, $coursebytes, $modulebytes)) {
6450
    if (!$maxsize = get_max_upload_file_size($sitebytes, $coursebytes, $modulebytes)) {
6657
        return array();
6451
        return array();
Línea 6661... Línea 6455...
6661
        // Will get the minimum of upload_max_filesize or post_max_size.
6455
        // Will get the minimum of upload_max_filesize or post_max_size.
6662
        $sitebytes = get_max_upload_file_size();
6456
        $sitebytes = get_max_upload_file_size();
6663
    }
6457
    }
Línea 6664... Línea 6458...
6664
 
6458
 
6665
    $filesize = array();
6459
    $filesize = array();
6666
    $sizelist = array(
-
 
6667
        10240,
-
 
6668
        51200,
-
 
6669
        102400,
-
 
6670
        512000,
-
 
6671
        1048576,
-
 
6672
        2097152,
-
 
6673
        5242880,
-
 
6674
        10485760,
-
 
6675
        20971520,
-
 
6676
        52428800,
-
 
6677
        104857600,
-
 
6678
        262144000,
6460
    $sizelist = array(10240, 51200, 102400, 512000, 1048576, 2097152,
6679
        524288000,
-
 
6680
        786432000,
6461
                      5242880, 10485760, 20971520, 52428800, 104857600,
6681
        1073741824,
-
 
6682
        2147483648,
6462
                      262144000, 524288000, 786432000, 1073741824,
6683
        4294967296,
-
 
6684
        8589934592
-
 
Línea 6685... Línea 6463...
6685
    );
6463
                      2147483648, 4294967296, 8589934592);
6686
 
6464
 
6687
    // If custombytes is given and is valid then add it to the list.
6465
    // If custombytes is given and is valid then add it to the list.
6688
    if (is_number($custombytes) and $custombytes > 0) {
6466
    if (is_number($custombytes) and $custombytes > 0) {
Línea 6706... Línea 6484...
6706
        }
6484
        }
6707
    }
6485
    }
Línea 6708... Línea 6486...
6708
 
6486
 
6709
    $limitlevel = '';
6487
    $limitlevel = '';
6710
    $displaysize = '';
-
 
6711
    if (
6488
    $displaysize = '';
6712
        $modulebytes &&
6489
    if ($modulebytes &&
6713
        (($modulebytes < $coursebytes || $coursebytes == 0) &&
6490
        (($modulebytes < $coursebytes || $coursebytes == 0) &&
6714
            ($modulebytes < $sitebytes || $sitebytes == 0))
-
 
6715
    ) {
6491
         ($modulebytes < $sitebytes || $sitebytes == 0))) {
6716
        $limitlevel = get_string('activity', 'core');
6492
        $limitlevel = get_string('activity', 'core');
6717
        $displaysize = display_size($modulebytes, 0);
6493
        $displaysize = display_size($modulebytes, 0);
Línea 6718... Línea 6494...
6718
        $filesize[$modulebytes] = $displaysize; // Make sure the limit is also included in the list.
6494
        $filesize[$modulebytes] = $displaysize; // Make sure the limit is also included in the list.
Línea 6752... Línea 6528...
6752
 * @param bool $descend If true then subdirectories are recursed as well
6528
 * @param bool $descend If true then subdirectories are recursed as well
6753
 * @param bool $getdirs If true then (sub)directories are included in the output
6529
 * @param bool $getdirs If true then (sub)directories are included in the output
6754
 * @param bool $getfiles  If true then files are included in the output
6530
 * @param bool $getfiles  If true then files are included in the output
6755
 * @return array An array with all the filenames in all subdirectories, relative to the given rootdir
6531
 * @return array An array with all the filenames in all subdirectories, relative to the given rootdir
6756
 */
6532
 */
6757
function get_directory_list($rootdir, $excludefiles = '', $descend = true, $getdirs = false, $getfiles = true)
6533
function get_directory_list($rootdir, $excludefiles='', $descend=true, $getdirs=false, $getfiles=true) {
6758
{
-
 
Línea 6759... Línea 6534...
6759
 
6534
 
Línea 6760... Línea 6535...
6760
    $dirs = array();
6535
    $dirs = array();
6761
 
6536
 
Línea 6778... Línea 6553...
6778
    while (false !== ($file = readdir($dir))) {
6553
    while (false !== ($file = readdir($dir))) {
6779
        $firstchar = substr($file, 0, 1);
6554
        $firstchar = substr($file, 0, 1);
6780
        if ($firstchar == '.' or $file == 'CVS' or in_array($file, $excludefiles)) {
6555
        if ($firstchar == '.' or $file == 'CVS' or in_array($file, $excludefiles)) {
6781
            continue;
6556
            continue;
6782
        }
6557
        }
6783
        $fullfile = $rootdir . '/' . $file;
6558
        $fullfile = $rootdir .'/'. $file;
6784
        if (filetype($fullfile) == 'dir') {
6559
        if (filetype($fullfile) == 'dir') {
6785
            if ($getdirs) {
6560
            if ($getdirs) {
6786
                $dirs[] = $file;
6561
                $dirs[] = $file;
6787
            }
6562
            }
6788
            if ($descend) {
6563
            if ($descend) {
6789
                $subdirs = get_directory_list($fullfile, $excludefiles, $descend, $getdirs, $getfiles);
6564
                $subdirs = get_directory_list($fullfile, $excludefiles, $descend, $getdirs, $getfiles);
6790
                foreach ($subdirs as $subdir) {
6565
                foreach ($subdirs as $subdir) {
6791
                    $dirs[] = $file . '/' . $subdir;
6566
                    $dirs[] = $file .'/'. $subdir;
6792
                }
6567
                }
6793
            }
6568
            }
6794
        } else if ($getfiles) {
6569
        } else if ($getfiles) {
6795
            $dirs[] = $file;
6570
            $dirs[] = $file;
6796
        }
6571
        }
Línea 6808... Línea 6583...
6808
 *
6583
 *
6809
 * @param string $rootdir  The directory to start from
6584
 * @param string $rootdir  The directory to start from
6810
 * @param string $excludefile A file to exclude when summing directory size
6585
 * @param string $excludefile A file to exclude when summing directory size
6811
 * @return int The summed size of all files and subfiles within the root directory
6586
 * @return int The summed size of all files and subfiles within the root directory
6812
 */
6587
 */
6813
function get_directory_size($rootdir, $excludefile = '')
6588
function get_directory_size($rootdir, $excludefile='') {
6814
{
-
 
6815
    global $CFG;
6589
    global $CFG;
Línea 6816... Línea 6590...
6816
 
6590
 
6817
    // Do it this way if we can, it's much faster.
6591
    // Do it this way if we can, it's much faster.
6818
    if (!empty($CFG->pathtodu) && is_executable(trim($CFG->pathtodu))) {
6592
    if (!empty($CFG->pathtodu) && is_executable(trim($CFG->pathtodu))) {
6819
        $command = trim($CFG->pathtodu) . ' -sk ' . escapeshellarg($rootdir);
6593
        $command = trim($CFG->pathtodu).' -sk '.escapeshellarg($rootdir);
6820
        $output = null;
6594
        $output = null;
6821
        $return = null;
6595
        $return = null;
6822
        exec($command, $output, $return);
6596
        exec($command, $output, $return);
6823
        if (is_array($output)) {
6597
        if (is_array($output)) {
6824
            // We told it to return k.
6598
            // We told it to return k.
6825
            return get_real_size(intval($output[0]) . 'k');
6599
            return get_real_size(intval($output[0]).'k');
6826
        }
6600
        }
Línea 6827... Línea 6601...
6827
    }
6601
    }
6828
 
6602
 
Línea 6841... Línea 6615...
6841
    while (false !== ($file = readdir($dir))) {
6615
    while (false !== ($file = readdir($dir))) {
6842
        $firstchar = substr($file, 0, 1);
6616
        $firstchar = substr($file, 0, 1);
6843
        if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
6617
        if ($firstchar == '.' or $file == 'CVS' or $file == $excludefile) {
6844
            continue;
6618
            continue;
6845
        }
6619
        }
6846
        $fullfile = $rootdir . '/' . $file;
6620
        $fullfile = $rootdir .'/'. $file;
6847
        if (filetype($fullfile) == 'dir') {
6621
        if (filetype($fullfile) == 'dir') {
6848
            $size += get_directory_size($fullfile, $excludefile);
6622
            $size += get_directory_size($fullfile, $excludefile);
6849
        } else {
6623
        } else {
6850
            $size += filesize($fullfile);
6624
            $size += filesize($fullfile);
6851
        }
6625
        }
Línea 6861... Línea 6635...
6861
 * @param int $size  The size to convert to human readable form
6635
 * @param int $size  The size to convert to human readable form
6862
 * @param int $decimalplaces If specified, uses fixed number of decimal places
6636
 * @param int $decimalplaces If specified, uses fixed number of decimal places
6863
 * @param string $fixedunits If specified, uses fixed units (e.g. 'KB')
6637
 * @param string $fixedunits If specified, uses fixed units (e.g. 'KB')
6864
 * @return string Display version of size
6638
 * @return string Display version of size
6865
 */
6639
 */
6866
function display_size($size, int $decimalplaces = 1, string $fixedunits = ''): string
6640
function display_size($size, int $decimalplaces = 1, string $fixedunits = ''): string {
6867
{
-
 
Línea 6868... Línea 6641...
6868
 
6641
 
Línea 6869... Línea 6642...
6869
    static $units;
6642
    static $units;
6870
 
6643
 
Línea 6880... Línea 6653...
6880
        $units[] = get_string('sizetb');
6653
        $units[] = get_string('sizetb');
6881
        $units[] = get_string('sizepb');
6654
        $units[] = get_string('sizepb');
6882
    }
6655
    }
Línea 6883... Línea 6656...
6883
 
6656
 
6884
    switch ($fixedunits) {
6657
    switch ($fixedunits) {
6885
        case 'PB':
6658
        case 'PB' :
6886
            $magnitude = 5;
6659
            $magnitude = 5;
6887
            break;
6660
            break;
6888
        case 'TB':
6661
        case 'TB' :
6889
            $magnitude = 4;
6662
            $magnitude = 4;
6890
            break;
6663
            break;
6891
        case 'GB':
6664
        case 'GB' :
6892
            $magnitude = 3;
6665
            $magnitude = 3;
6893
            break;
6666
            break;
6894
        case 'MB':
6667
        case 'MB' :
6895
            $magnitude = 2;
6668
            $magnitude = 2;
6896
            break;
6669
            break;
6897
        case 'KB':
6670
        case 'KB' :
6898
            $magnitude = 1;
6671
            $magnitude = 1;
6899
            break;
6672
            break;
6900
        case 'B':
6673
        case 'B' :
6901
            $magnitude = 0;
6674
            $magnitude = 0;
6902
            break;
6675
            break;
6903
        case '':
6676
        case '':
6904
            $magnitude = floor(log($size, 1024));
6677
            $magnitude = floor(log($size, 1024));
Línea 6926... Línea 6699...
6926
 *
6699
 *
6927
 * @see clean_param()
6700
 * @see clean_param()
6928
 * @param string $string file name
6701
 * @param string $string file name
6929
 * @return string cleaned file name
6702
 * @return string cleaned file name
6930
 */
6703
 */
6931
function clean_filename($string)
6704
function clean_filename($string) {
6932
{
-
 
6933
    return clean_param($string, PARAM_FILE);
6705
    return clean_param($string, PARAM_FILE);
6934
}
6706
}
Línea 6935... Línea 6707...
6935
 
6707
 
Línea 6939... Línea 6711...
6939
 * Returns the code for the current language
6711
 * Returns the code for the current language
6940
 *
6712
 *
6941
 * @category string
6713
 * @category string
6942
 * @return string
6714
 * @return string
6943
 */
6715
 */
6944
function current_language()
6716
function current_language() {
6945
{
-
 
6946
    global $CFG, $PAGE, $SESSION, $USER;
6717
    global $CFG, $PAGE, $SESSION, $USER;
Línea 6947... Línea 6718...
6947
 
6718
 
6948
    if (!empty($SESSION->forcelang)) {
6719
    if (!empty($SESSION->forcelang)) {
6949
        // Allows overriding course-forced language (useful for admins to check
6720
        // Allows overriding course-forced language (useful for admins to check
6950
        // issues in courses whose language they don't understand).
6721
        // issues in courses whose language they don't understand).
6951
        // Also used by some code to temporarily get language-related information in a
6722
        // Also used by some code to temporarily get language-related information in a
6952
        // specific language (see force_current_language()).
6723
        // specific language (see force_current_language()).
-
 
6724
        $return = $SESSION->forcelang;
6953
        $return = $SESSION->forcelang;
6725
 
6954
    } else if (!empty($PAGE->cm->lang)) {
6726
    } else if (!empty($PAGE->cm->lang)) {
6955
        // Activity language, if set.
6727
        // Activity language, if set.
-
 
6728
        $return = $PAGE->cm->lang;
6956
        $return = $PAGE->cm->lang;
6729
 
6957
    } else if (!empty($PAGE->course->id) && $PAGE->course->id != SITEID && !empty($PAGE->course->lang)) {
6730
    } else if (!empty($PAGE->course->id) && $PAGE->course->id != SITEID && !empty($PAGE->course->lang)) {
6958
        // Course language can override all other settings for this page.
6731
        // Course language can override all other settings for this page.
-
 
6732
        $return = $PAGE->course->lang;
6959
        $return = $PAGE->course->lang;
6733
 
6960
    } else if (!empty($SESSION->lang)) {
6734
    } else if (!empty($SESSION->lang)) {
6961
        // Session language can override other settings.
6735
        // Session language can override other settings.
-
 
6736
        $return = $SESSION->lang;
6962
        $return = $SESSION->lang;
6737
 
6963
    } else if (!empty($USER->lang)) {
6738
    } else if (!empty($USER->lang)) {
-
 
6739
        $return = $USER->lang;
6964
        $return = $USER->lang;
6740
 
6965
    } else if (isset($CFG->lang)) {
6741
    } else if (isset($CFG->lang)) {
-
 
6742
        $return = $CFG->lang;
6966
        $return = $CFG->lang;
6743
 
6967
    } else {
6744
    } else {
6968
        $return = 'en';
6745
        $return = 'en';
Línea 6969... Línea 6746...
6969
    }
6746
    }
Línea 6978... Línea 6755...
6978
 * Fix the current language to the given language code.
6755
 * Fix the current language to the given language code.
6979
 *
6756
 *
6980
 * @param string $lang The language code to use.
6757
 * @param string $lang The language code to use.
6981
 * @return void
6758
 * @return void
6982
 */
6759
 */
6983
function fix_current_language(string $lang): void
6760
function fix_current_language(string $lang): void {
6984
{
-
 
6985
    global $CFG, $COURSE, $SESSION, $USER;
6761
    global $CFG, $COURSE, $SESSION, $USER;
Línea 6986... Línea 6762...
6986
 
6762
 
6987
    if (!get_string_manager()->translation_exists($lang)) {
6763
    if (!get_string_manager()->translation_exists($lang)) {
6988
        throw new coding_exception("The language pack for $lang is not available");
6764
        throw new coding_exception("The language pack for $lang is not available");
Línea 7013... Línea 6789...
7013
 *
6789
 *
7014
 * @category string
6790
 * @category string
7015
 * @param string $lang null means current language
6791
 * @param string $lang null means current language
7016
 * @return string
6792
 * @return string
7017
 */
6793
 */
7018
function get_parent_language($lang = null)
6794
function get_parent_language($lang=null) {
7019
{
-
 
Línea 7020... Línea 6795...
7020
 
6795
 
Línea 7021... Línea 6796...
7021
    $parentlang = get_string_manager()->get_string('parentlanguage', 'langconfig', null, $lang);
6796
    $parentlang = get_string_manager()->get_string('parentlanguage', 'langconfig', null, $lang);
7022
 
6797
 
Línea 7034... Línea 6809...
7034
 * until this function is called again, or equivalent code is run.
6809
 * until this function is called again, or equivalent code is run.
7035
 *
6810
 *
7036
 * @param string $language
6811
 * @param string $language
7037
 * @return string previous $SESSION->forcelang value
6812
 * @return string previous $SESSION->forcelang value
7038
 */
6813
 */
7039
function force_current_language($language)
6814
function force_current_language($language) {
7040
{
-
 
7041
    global $SESSION;
6815
    global $SESSION;
7042
    $sessionforcelang = isset($SESSION->forcelang) ? $SESSION->forcelang : '';
6816
    $sessionforcelang = isset($SESSION->forcelang) ? $SESSION->forcelang : '';
7043
    if ($language !== $sessionforcelang) {
6817
    if ($language !== $sessionforcelang) {
7044
        // Setting forcelang to null or an empty string disables its effect.
6818
        // Setting forcelang to null or an empty string disables its effect.
7045
        if (empty($language) || get_string_manager()->translation_exists($language, false)) {
6819
        if (empty($language) || get_string_manager()->translation_exists($language, false)) {
Línea 7058... Línea 6832...
7058
 *
6832
 *
7059
 * @category string
6833
 * @category string
7060
 * @param bool $forcereload shall the singleton be released and new instance created instead?
6834
 * @param bool $forcereload shall the singleton be released and new instance created instead?
7061
 * @return core_string_manager
6835
 * @return core_string_manager
7062
 */
6836
 */
7063
function get_string_manager($forcereload = false)
6837
function get_string_manager($forcereload=false) {
7064
{
-
 
7065
    global $CFG;
6838
    global $CFG;
Línea 7066... Línea 6839...
7066
 
6839
 
Línea 7067... Línea 6840...
7067
    static $singleton = null;
6840
    static $singleton = null;
Línea 7072... Línea 6845...
7072
    if ($singleton === null) {
6845
    if ($singleton === null) {
7073
        if (empty($CFG->early_install_lang)) {
6846
        if (empty($CFG->early_install_lang)) {
Línea 7074... Línea 6847...
7074
 
6847
 
7075
            $transaliases = array();
6848
            $transaliases = array();
7076
            if (empty($CFG->langlist)) {
6849
            if (empty($CFG->langlist)) {
7077
                $translist = array();
6850
                 $translist = array();
7078
            } else {
6851
            } else {
7079
                $translist = explode(',', $CFG->langlist);
6852
                $translist = explode(',', $CFG->langlist);
7080
                $translist = array_map('trim', $translist);
6853
                $translist = array_map('trim', $translist);
7081
                // Each language in the $CFG->langlist can has an "alias" that would substitute the default language name.
6854
                // Each language in the $CFG->langlist can has an "alias" that would substitute the default language name.
Línea 7095... Línea 6868...
7095
                    $implements = class_implements($classname);
6868
                    $implements = class_implements($classname);
Línea 7096... Línea 6869...
7096
 
6869
 
7097
                    if (isset($implements['core_string_manager'])) {
6870
                    if (isset($implements['core_string_manager'])) {
7098
                        $singleton = new $classname($CFG->langotherroot, $CFG->langlocalroot, $translist, $transaliases);
6871
                        $singleton = new $classname($CFG->langotherroot, $CFG->langlocalroot, $translist, $transaliases);
-
 
6872
                        return $singleton;
7099
                        return $singleton;
6873
 
7100
                    } else {
6874
                    } else {
7101
                        debugging('Unable to instantiate custom string manager: class ' . $classname .
6875
                        debugging('Unable to instantiate custom string manager: class '.$classname.
7102
                            ' does not implement the core_string_manager interface.');
6876
                            ' does not implement the core_string_manager interface.');
-
 
6877
                    }
7103
                    }
6878
 
7104
                } else {
6879
                } else {
7105
                    debugging('Unable to instantiate custom string manager: class ' . $classname . ' can not be found.');
6880
                    debugging('Unable to instantiate custom string manager: class '.$classname.' can not be found.');
7106
                }
6881
                }
Línea 7107... Línea 6882...
7107
            }
6882
            }
-
 
6883
 
7108
 
6884
            $singleton = new core_string_manager_standard($CFG->langotherroot, $CFG->langlocalroot, $translist, $transaliases);
7109
            $singleton = new core_string_manager_standard($CFG->langotherroot, $CFG->langlocalroot, $translist, $transaliases);
6885
 
7110
        } else {
6886
        } else {
7111
            $singleton = new core_string_manager_install();
6887
            $singleton = new core_string_manager_install();
Línea 7185... Línea 6961...
7185
 * @param bool $lazyload If set to true a string object is returned instead of
6961
 * @param bool $lazyload If set to true a string object is returned instead of
7186
 *      the string itself. The string then isn't calculated until it is first used.
6962
 *      the string itself. The string then isn't calculated until it is first used.
7187
 * @return string The localized string.
6963
 * @return string The localized string.
7188
 * @throws coding_exception
6964
 * @throws coding_exception
7189
 */
6965
 */
7190
function get_string($identifier, $component = '', $a = null, $lazyload = false)
6966
function get_string($identifier, $component = '', $a = null, $lazyload = false) {
7191
{
-
 
7192
    global $CFG;
6967
    global $CFG;
Línea 7193... Línea 6968...
7193
 
6968
 
7194
    // If the lazy load argument has been supplied return a lang_string object
6969
    // If the lazy load argument has been supplied return a lang_string object
7195
    // instead.
6970
    // instead.
Línea 7209... Línea 6984...
7209
        debugging('extralocations parameter in get_string() is not supported any more, please use standard lang locations only.');
6984
        debugging('extralocations parameter in get_string() is not supported any more, please use standard lang locations only.');
7210
    }
6985
    }
Línea 7211... Línea 6986...
7211
 
6986
 
7212
    if (strpos((string)$component, '/') !== false) {
6987
    if (strpos((string)$component, '/') !== false) {
7213
        debugging('The module name you passed to get_string is the deprecated format ' .
6988
        debugging('The module name you passed to get_string is the deprecated format ' .
7214
            'like mod/mymod or block/myblock. The correct form looks like mymod, or block_myblock.', DEBUG_DEVELOPER);
6989
                'like mod/mymod or block/myblock. The correct form looks like mymod, or block_myblock.' , DEBUG_DEVELOPER);
Línea 7215... Línea 6990...
7215
        $componentpath = explode('/', $component);
6990
        $componentpath = explode('/', $component);
7216
 
6991
 
7217
        switch ($componentpath[0]) {
6992
        switch ($componentpath[0]) {
7218
            case 'mod':
6993
            case 'mod':
7219
                $component = $componentpath[1];
6994
                $component = $componentpath[1];
7220
                break;
6995
                break;
7221
            case 'blocks':
6996
            case 'blocks':
7222
            case 'block':
6997
            case 'block':
7223
                $component = 'block_' . $componentpath[1];
6998
                $component = 'block_'.$componentpath[1];
7224
                break;
6999
                break;
7225
            case 'enrol':
7000
            case 'enrol':
7226
                $component = 'enrol_' . $componentpath[1];
7001
                $component = 'enrol_'.$componentpath[1];
7227
                break;
7002
                break;
7228
            case 'format':
7003
            case 'format':
7229
                $component = 'format_' . $componentpath[1];
7004
                $component = 'format_'.$componentpath[1];
7230
                break;
7005
                break;
7231
            case 'grade':
7006
            case 'grade':
7232
                $component = 'grade' . $componentpath[1] . '_' . $componentpath[2];
7007
                $component = 'grade'.$componentpath[1].'_'.$componentpath[2];
7233
                break;
7008
                break;
Línea 7234... Línea 7009...
7234
        }
7009
        }
Línea 7248... Línea 7023...
7248
 *
7023
 *
7249
 * @param array $array An array of strings
7024
 * @param array $array An array of strings
7250
 * @param string $component The language module that these strings can be found in.
7025
 * @param string $component The language module that these strings can be found in.
7251
 * @return stdClass translated strings.
7026
 * @return stdClass translated strings.
7252
 */
7027
 */
7253
function get_strings($array, $component = '')
7028
function get_strings($array, $component = '') {
7254
{
-
 
7255
    $string = new stdClass;
7029
    $string = new stdClass;
7256
    foreach ($array as $item) {
7030
    foreach ($array as $item) {
7257
        $string->$item = get_string($item, $component);
7031
        $string->$item = get_string($item, $component);
7258
    }
7032
    }
7259
    return $string;
7033
    return $string;
Línea 7281... Línea 7055...
7281
 * @category string
7055
 * @category string
7282
 * @param string $identifier The key identifier for the localized string
7056
 * @param string $identifier The key identifier for the localized string
7283
 * @param string $component The module where the key identifier is stored. If none is specified then moodle.php is used.
7057
 * @param string $component The module where the key identifier is stored. If none is specified then moodle.php is used.
7284
 * @param string|object|array $a An object, string or number that can be used within translation strings
7058
 * @param string|object|array $a An object, string or number that can be used within translation strings
7285
 */
7059
 */
7286
function print_string($identifier, $component = '', $a = null)
7060
function print_string($identifier, $component = '', $a = null) {
7287
{
-
 
7288
    echo get_string($identifier, $component, $a);
7061
    echo get_string($identifier, $component, $a);
7289
}
7062
}
Línea 7290... Línea 7063...
7290
 
7063
 
7291
/**
7064
/**
Línea 7294... Línea 7067...
7294
 * Returns a list of charset codes. It's hardcoded, so they should be added manually
7067
 * Returns a list of charset codes. It's hardcoded, so they should be added manually
7295
 * (checking that such charset is supported by the texlib library!)
7068
 * (checking that such charset is supported by the texlib library!)
7296
 *
7069
 *
7297
 * @return array And associative array with contents in the form of charset => charset
7070
 * @return array And associative array with contents in the form of charset => charset
7298
 */
7071
 */
7299
function get_list_of_charsets()
7072
function get_list_of_charsets() {
7300
{
-
 
Línea 7301... Línea 7073...
7301
 
7073
 
7302
    $charsets = array(
7074
    $charsets = array(
7303
        'EUC-JP'     => 'EUC-JP',
7075
        'EUC-JP'     => 'EUC-JP',
7304
        'ISO-2022-JP' => 'ISO-2022-JP',
7076
        'ISO-2022-JP'=> 'ISO-2022-JP',
7305
        'ISO-8859-1' => 'ISO-8859-1',
7077
        'ISO-8859-1' => 'ISO-8859-1',
7306
        'SHIFT-JIS'  => 'SHIFT-JIS',
7078
        'SHIFT-JIS'  => 'SHIFT-JIS',
7307
        'GB2312'     => 'GB2312',
7079
        'GB2312'     => 'GB2312',
7308
        'GB18030'    => 'GB18030', // GB18030 not supported by typo and mbstring.
7080
        'GB18030'    => 'GB18030', // GB18030 not supported by typo and mbstring.
7309
        'UTF-8'      => 'UTF-8'
-
 
Línea 7310... Línea 7081...
7310
    );
7081
        'UTF-8'      => 'UTF-8');
Línea 7311... Línea 7082...
7311
 
7082
 
7312
    asort($charsets);
7083
    asort($charsets);
Línea 7317... Línea 7088...
7317
/**
7088
/**
7318
 * Returns a list of valid and compatible themes
7089
 * Returns a list of valid and compatible themes
7319
 *
7090
 *
7320
 * @return array
7091
 * @return array
7321
 */
7092
 */
7322
function get_list_of_themes()
7093
function get_list_of_themes() {
7323
{
-
 
7324
    global $CFG;
7094
    global $CFG;
Línea 7325... Línea 7095...
7325
 
7095
 
Línea 7326... Línea 7096...
7326
    $themes = array();
7096
    $themes = array();
Línea 7340... Línea 7110...
7340
 
7110
 
7341
    return $themes;
7111
    return $themes;
Línea 7342... Línea 7112...
7342
}
7112
}
7343
 
7113
 
7344
/**
7114
/**
7345
 * Factory function for emoticon_manager
7115
 * Factory function for {@see \core\emoticon_manager}
7346
 *
7116
 *
7347
 * @return emoticon_manager singleton
7117
 * @return \core\emoticon_manager singleton
7348
 */
-
 
7349
function get_emoticon_manager()
7118
 */
Línea 7350... Línea 7119...
7350
{
7119
function get_emoticon_manager(): \core\emoticon_manager {
7351
    static $singleton = null;
7120
    static $singleton = null;
7352
 
7121
 
Línea 7353... Línea 7122...
7353
    if (is_null($singleton)) {
7122
    if (is_null($singleton)) {
7354
        $singleton = new emoticon_manager();
7123
        $singleton = new \core\emoticon_manager();
Línea 7355... Línea -...
7355
    }
-
 
7356
 
-
 
7357
    return $singleton;
-
 
7358
}
-
 
7359
 
-
 
7360
/**
-
 
7361
 * Provides core support for plugins that have to deal with emoticons (like HTML editor or emoticon filter).
-
 
7362
 *
-
 
7363
 * Whenever this manager mentiones 'emoticon object', the following data
-
 
7364
 * structure is expected: stdClass with properties text, imagename, imagecomponent,
-
 
7365
 * altidentifier and altcomponent
-
 
7366
 *
-
 
7367
 * @see admin_setting_emoticons
-
 
7368
 *
-
 
7369
 * @copyright 2010 David Mudrak
-
 
7370
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
-
 
7371
 */
-
 
7372
class emoticon_manager
-
 
7373
{
-
 
7374
 
-
 
7375
    /**
-
 
7376
     * Returns the currently enabled emoticons
-
 
7377
     *
-
 
7378
     * @param boolean $selectable - If true, only return emoticons that should be selectable from a list.
-
 
7379
     * @return array of emoticon objects
-
 
7380
     */
-
 
7381
    public function get_emoticons($selectable = false)
-
 
7382
    {
-
 
7383
        global $CFG;
-
 
7384
        $notselectable = ['martin', 'egg'];
-
 
7385
 
-
 
7386
        if (empty($CFG->emoticons)) {
-
 
7387
            return array();
-
 
7388
        }
-
 
7389
 
-
 
7390
        $emoticons = $this->decode_stored_config($CFG->emoticons);
-
 
7391
 
-
 
7392
        if (!is_array($emoticons)) {
-
 
7393
            // Something is wrong with the format of stored setting.
-
 
7394
            debugging('Invalid format of emoticons setting, please resave the emoticons settings form', DEBUG_NORMAL);
-
 
7395
            return array();
-
 
7396
        }
-
 
7397
        if ($selectable) {
-
 
7398
            foreach ($emoticons as $index => $emote) {
-
 
7399
                if (in_array($emote->altidentifier, $notselectable)) {
-
 
7400
                    // Skip this one.
-
 
7401
                    unset($emoticons[$index]);
-
 
7402
                }
-
 
7403
            }
-
 
7404
        }
-
 
7405
 
-
 
7406
        return $emoticons;
-
 
7407
    }
-
 
7408
 
-
 
7409
    /**
-
 
7410
     * Converts emoticon object into renderable pix_emoticon object
-
 
7411
     *
-
 
7412
     * @param stdClass $emoticon emoticon object
-
 
7413
     * @param array $attributes explicit HTML attributes to set
-
 
7414
     * @return pix_emoticon
-
 
7415
     */
-
 
7416
    public function prepare_renderable_emoticon(stdClass $emoticon, array $attributes = array())
-
 
7417
    {
-
 
7418
        $stringmanager = get_string_manager();
-
 
7419
        if ($stringmanager->string_exists($emoticon->altidentifier, $emoticon->altcomponent)) {
-
 
7420
            $alt = get_string($emoticon->altidentifier, $emoticon->altcomponent);
-
 
7421
        } else {
-
 
7422
            $alt = s($emoticon->text);
-
 
7423
        }
-
 
7424
        return new pix_emoticon($emoticon->imagename, $alt, $emoticon->imagecomponent, $attributes);
-
 
7425
    }
-
 
7426
 
-
 
7427
    /**
-
 
7428
     * Encodes the array of emoticon objects into a string storable in config table
-
 
7429
     *
-
 
7430
     * @see self::decode_stored_config()
-
 
7431
     * @param array $emoticons array of emtocion objects
-
 
7432
     * @return string
-
 
7433
     */
-
 
7434
    public function encode_stored_config(array $emoticons)
-
 
7435
    {
-
 
7436
        return json_encode($emoticons);
-
 
7437
    }
-
 
7438
 
-
 
7439
    /**
-
 
7440
     * Decodes the string into an array of emoticon objects
-
 
7441
     *
-
 
7442
     * @see self::encode_stored_config()
-
 
7443
     * @param string $encoded
-
 
7444
     * @return array|null
-
 
7445
     */
-
 
7446
    public function decode_stored_config($encoded)
-
 
7447
    {
-
 
7448
        $decoded = json_decode($encoded);
-
 
7449
        if (!is_array($decoded)) {
-
 
7450
            return null;
-
 
7451
        }
-
 
7452
        return $decoded;
-
 
7453
    }
-
 
7454
 
-
 
7455
    /**
-
 
7456
     * Returns default set of emoticons supported by Moodle
-
 
7457
     *
-
 
7458
     * @return array of sdtClasses
-
 
7459
     */
-
 
7460
    public function default_emoticons()
-
 
7461
    {
-
 
7462
        return array(
-
 
7463
            $this->prepare_emoticon_object(":-)", 's/smiley', 'smiley'),
-
 
7464
            $this->prepare_emoticon_object(":)", 's/smiley', 'smiley'),
-
 
7465
            $this->prepare_emoticon_object(":-D", 's/biggrin', 'biggrin'),
-
 
7466
            $this->prepare_emoticon_object(";-)", 's/wink', 'wink'),
-
 
7467
            $this->prepare_emoticon_object(":-/", 's/mixed', 'mixed'),
-
 
7468
            $this->prepare_emoticon_object("V-.", 's/thoughtful', 'thoughtful'),
-
 
7469
            $this->prepare_emoticon_object(":-P", 's/tongueout', 'tongueout'),
-
 
7470
            $this->prepare_emoticon_object(":-p", 's/tongueout', 'tongueout'),
-
 
7471
            $this->prepare_emoticon_object("B-)", 's/cool', 'cool'),
-
 
7472
            $this->prepare_emoticon_object("^-)", 's/approve', 'approve'),
-
 
7473
            $this->prepare_emoticon_object("8-)", 's/wideeyes', 'wideeyes'),
-
 
7474
            $this->prepare_emoticon_object(":o)", 's/clown', 'clown'),
-
 
7475
            $this->prepare_emoticon_object(":-(", 's/sad', 'sad'),
-
 
7476
            $this->prepare_emoticon_object(":(", 's/sad', 'sad'),
-
 
7477
            $this->prepare_emoticon_object("8-.", 's/shy', 'shy'),
-
 
7478
            $this->prepare_emoticon_object(":-I", 's/blush', 'blush'),
-
 
7479
            $this->prepare_emoticon_object(":-X", 's/kiss', 'kiss'),
-
 
7480
            $this->prepare_emoticon_object("8-o", 's/surprise', 'surprise'),
-
 
7481
            $this->prepare_emoticon_object("P-|", 's/blackeye', 'blackeye'),
-
 
7482
            $this->prepare_emoticon_object("8-[", 's/angry', 'angry'),
-
 
7483
            $this->prepare_emoticon_object("(grr)", 's/angry', 'angry'),
-
 
7484
            $this->prepare_emoticon_object("xx-P", 's/dead', 'dead'),
-
 
7485
            $this->prepare_emoticon_object("|-.", 's/sleepy', 'sleepy'),
-
 
7486
            $this->prepare_emoticon_object("}-]", 's/evil', 'evil'),
-
 
7487
            $this->prepare_emoticon_object("(h)", 's/heart', 'heart'),
-
 
7488
            $this->prepare_emoticon_object("(heart)", 's/heart', 'heart'),
-
 
7489
            $this->prepare_emoticon_object("(y)", 's/yes', 'yes', 'core'),
-
 
7490
            $this->prepare_emoticon_object("(n)", 's/no', 'no', 'core'),
-
 
7491
            $this->prepare_emoticon_object("(martin)", 's/martin', 'martin'),
-
 
7492
            $this->prepare_emoticon_object("( )", 's/egg', 'egg'),
-
 
7493
        );
-
 
7494
    }
-
 
7495
 
-
 
7496
    /**
-
 
7497
     * Helper method preparing the stdClass with the emoticon properties
-
 
7498
     *
-
 
7499
     * @param string|array $text or array of strings
-
 
7500
     * @param string $imagename to be used by {@link pix_emoticon}
-
 
7501
     * @param string $altidentifier alternative string identifier, null for no alt
-
 
7502
     * @param string $altcomponent where the alternative string is defined
-
 
7503
     * @param string $imagecomponent to be used by {@link pix_emoticon}
-
 
7504
     * @return stdClass
-
 
7505
     */
-
 
7506
    protected function prepare_emoticon_object(
-
 
7507
        $text,
-
 
7508
        $imagename,
-
 
7509
        $altidentifier = null,
-
 
7510
        $altcomponent = 'core_pix',
-
 
7511
        $imagecomponent = 'core'
-
 
7512
    ) {
-
 
7513
        return (object)array(
-
 
7514
            'text'           => $text,
-
 
7515
            'imagename'      => $imagename,
-
 
7516
            'imagecomponent' => $imagecomponent,
-
 
7517
            'altidentifier'  => $altidentifier,
-
 
7518
            'altcomponent'   => $altcomponent,
-
 
7519
        );
-
 
7520
    }
-
 
7521
}
-
 
7522
 
-
 
7523
// ENCRYPTION.
-
 
7524
 
-
 
7525
/**
-
 
7526
 * rc4encrypt
-
 
7527
 *
-
 
7528
 * @param string $data        Data to encrypt.
-
 
7529
 * @return string             The now encrypted data.
-
 
7530
 */
-
 
7531
function rc4encrypt($data)
-
 
7532
{
-
 
7533
    return endecrypt(get_site_identifier(), $data, '');
-
 
7534
}
-
 
7535
 
-
 
7536
/**
-
 
7537
 * rc4decrypt
-
 
7538
 *
-
 
7539
 * @param string $data        Data to decrypt.
-
 
7540
 * @return string             The now decrypted data.
-
 
7541
 */
-
 
7542
function rc4decrypt($data)
-
 
7543
{
-
 
7544
    return endecrypt(get_site_identifier(), $data, 'de');
-
 
7545
}
-
 
7546
 
-
 
7547
/**
-
 
7548
 * Based on a class by Mukul Sabharwal [mukulsabharwal @ yahoo.com]
-
 
7549
 *
-
 
7550
 * @todo Finish documenting this function
-
 
7551
 *
-
 
7552
 * @param string $pwd The password to use when encrypting or decrypting
-
 
7553
 * @param string $data The data to be decrypted/encrypted
-
 
7554
 * @param string $case Either 'de' for decrypt or '' for encrypt
-
 
7555
 * @return string
-
 
7556
 */
-
 
7557
function endecrypt($pwd, $data, $case)
-
 
7558
{
-
 
7559
 
-
 
7560
    if ($case == 'de') {
-
 
7561
        $data = urldecode($data);
-
 
7562
    }
-
 
7563
 
-
 
7564
    $key[] = '';
-
 
7565
    $box[] = '';
-
 
7566
    $pwdlength = strlen($pwd);
-
 
7567
 
-
 
7568
    for ($i = 0; $i <= 255; $i++) {
-
 
7569
        $key[$i] = ord(substr($pwd, ($i % $pwdlength), 1));
-
 
7570
        $box[$i] = $i;
-
 
7571
    }
-
 
7572
 
-
 
7573
    $x = 0;
-
 
7574
 
-
 
7575
    for ($i = 0; $i <= 255; $i++) {
-
 
7576
        $x = ($x + $box[$i] + $key[$i]) % 256;
-
 
7577
        $tempswap = $box[$i];
-
 
7578
        $box[$i] = $box[$x];
-
 
7579
        $box[$x] = $tempswap;
-
 
7580
    }
-
 
7581
 
-
 
7582
    $cipher = '';
-
 
7583
 
-
 
7584
    $a = 0;
-
 
7585
    $j = 0;
-
 
7586
 
-
 
7587
    for ($i = 0; $i < strlen($data); $i++) {
-
 
7588
        $a = ($a + 1) % 256;
-
 
7589
        $j = ($j + $box[$a]) % 256;
-
 
7590
        $temp = $box[$a];
-
 
7591
        $box[$a] = $box[$j];
-
 
7592
        $box[$j] = $temp;
-
 
7593
        $k = $box[(($box[$a] + $box[$j]) % 256)];
-
 
7594
        $cipherby = ord(substr($data, $i, 1)) ^ $k;
-
 
7595
        $cipher .= chr($cipherby);
-
 
7596
    }
-
 
7597
 
-
 
7598
    if ($case == 'de') {
-
 
7599
        $cipher = urldecode(urlencode($cipher));
-
 
7600
    } else {
-
 
7601
        $cipher = urlencode($cipher);
-
 
7602
    }
7124
    }
Línea 7603... Línea 7125...
7603
 
7125
 
7604
    return $cipher;
7126
    return $singleton;
7605
}
7127
}
7606
 
7128
 
7607
// ENVIRONMENT CHECKING.
7129
// ENVIRONMENT CHECKING.
7608
 
7130
 
7609
/**
7131
/**
7610
 * This method validates a plug name. It is much faster than calling clean_param.
-
 
7611
 *
7132
 * This method validates a plug name. It is much faster than calling clean_param.
7612
 * @param string $name a string that might be a plugin name.
7133
 *
7613
 * @return bool if this string is a valid plugin name.
7134
 * @param string $name a string that might be a plugin name.
Línea 7614... Línea 7135...
7614
 */
7135
 * @return bool if this string is a valid plugin name.
Línea 7629... Línea 7150...
7629
 * @param string $file the name of file within the plugin that defines the
7150
 * @param string $file the name of file within the plugin that defines the
7630
 *      function. Defaults to lib.php.
7151
 *      function. Defaults to lib.php.
7631
 * @return array with frankenstyle plugin names as keys (e.g. 'report_courselist', 'mod_forum')
7152
 * @return array with frankenstyle plugin names as keys (e.g. 'report_courselist', 'mod_forum')
7632
 *      and the function names as values (e.g. 'report_courselist_hook', 'forum_hook').
7153
 *      and the function names as values (e.g. 'report_courselist_hook', 'forum_hook').
7633
 */
7154
 */
7634
function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php')
7155
function get_plugin_list_with_function($plugintype, $function, $file = 'lib.php') {
7635
{
-
 
7636
    global $CFG;
7156
    global $CFG;
Línea 7637... Línea 7157...
7637
 
7157
 
7638
    // We don't include here as all plugin types files would be included.
7158
    // We don't include here as all plugin types files would be included.
Línea 7679... Línea 7199...
7679
 *      function. Defaults to lib.php.
7199
 *      function. Defaults to lib.php.
7680
 * @param bool $include Whether to include the files that contain the functions or not.
7200
 * @param bool $include Whether to include the files that contain the functions or not.
7681
 * @param bool $migratedtohook if true this is a deprecated lib.php callback, if hook callback is present then do nothing
7201
 * @param bool $migratedtohook if true this is a deprecated lib.php callback, if hook callback is present then do nothing
7682
 * @return array with [plugintype][plugin] = functionname
7202
 * @return array with [plugintype][plugin] = functionname
7683
 */
7203
 */
7684
function get_plugins_with_function($function, $file = 'lib.php', $include = true, bool $migratedtohook = false)
7204
function get_plugins_with_function($function, $file = 'lib.php', $include = true, bool $migratedtohook = false) {
7685
{
-
 
7686
    global $CFG;
7205
    global $CFG;
Línea 7687... Línea 7206...
7687
 
7206
 
7688
    if (during_initial_install() || isset($CFG->upgraderunning)) {
7207
    if (during_initial_install() || isset($CFG->upgraderunning)) {
7689
        // API functions _must not_ be called during an installation or upgrade.
7208
        // API functions _must not_ be called during an installation or upgrade.
7690
        return [];
7209
        return [];
Línea 7691... Línea 7210...
7691
    }
7210
    }
7692
 
7211
 
7693
    $plugincallback = $function;
7212
    $plugincallback = $function;
7694
    $filtermigrated = function ($plugincallback, $pluginfunctions): array {
7213
    $filtermigrated = function($plugincallback, $pluginfunctions): array {
7695
        foreach ($pluginfunctions as $plugintype => $plugins) {
7214
        foreach ($pluginfunctions as $plugintype => $plugins) {
-
 
7215
            foreach ($plugins as $plugin => $unusedfunction) {
7696
            foreach ($plugins as $plugin => $unusedfunction) {
7216
                $component = $plugintype . '_' . $plugin;
7697
                $component = $plugintype . '_' . $plugin;
7217
                $hookmanager = di::get(hook\manager::class);
7698
                if ($hooks = di::get(hook\manager::class)->get_hooks_deprecating_plugin_callback($plugincallback)) {
7218
                if ($hooks = $hookmanager->get_hooks_deprecating_plugin_callback($plugincallback)) {
7699
                    if (di::get(hook\manager::class)->is_deprecating_hook_present($component, $plugincallback)) {
7219
                    if ($hookmanager->is_deprecating_hook_present($component, $plugincallback)) {
7700
                        // Ignore the old callback, it is there only for older Moodle versions.
7220
                        // Ignore the old callback, it is there only for older Moodle versions.
7701
                        unset($pluginfunctions[$plugintype][$plugin]);
7221
                        unset($pluginfunctions[$plugintype][$plugin]);
7702
                    } else {
7222
                    } else if ($hookmanager->warn_on_unmigrated_legacy_hooks()) {
7703
                        $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
7223
                        $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
7704
                        debugging(
7224
                        debugging(
7705
                            "Callback $plugincallback in $component component should be migrated to new " .
7225
                            "Callback $plugincallback in $component component should be migrated to new " .
Línea 7793... Línea 7313...
7793
 
7313
 
7794
            $pluginfunction = false;
7314
            $pluginfunction = false;
7795
            if (function_exists($fullfunction)) {
7315
            if (function_exists($fullfunction)) {
7796
                // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
7316
                // Function exists with standard name. Store, indexed by frankenstyle name of plugin.
-
 
7317
                $pluginfunction = $fullfunction;
7797
                $pluginfunction = $fullfunction;
7318
 
7798
            } else if ($plugintype === 'mod') {
7319
            } else if ($plugintype === 'mod') {
7799
                // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
7320
                // For modules, we also allow plugin without full frankenstyle but just starting with the module name.
7800
                $shortfunction = $plugin . '_' . $function;
7321
                $shortfunction = $plugin . '_' . $function;
7801
                if (function_exists($shortfunction)) {
7322
                if (function_exists($shortfunction)) {
Línea 7807... Línea 7328...
7807
                if (empty($pluginfunctions[$plugintype])) {
7328
                if (empty($pluginfunctions[$plugintype])) {
7808
                    $pluginfunctions[$plugintype] = array();
7329
                    $pluginfunctions[$plugintype] = array();
7809
                }
7330
                }
7810
                $pluginfunctions[$plugintype][$plugin] = $pluginfunction;
7331
                $pluginfunctions[$plugintype][$plugin] = $pluginfunction;
7811
            }
7332
            }
-
 
7333
 
7812
        }
7334
        }
7813
    }
7335
    }
7814
    if (!empty($CFG->allversionshash)) {
7336
    if (!empty($CFG->allversionshash)) {
7815
        $cache->set($key, $pluginfunctions);
7337
        $cache->set($key, $pluginfunctions);
7816
    }
7338
    }
Línea 7818... Línea 7340...
7818
    if ($migratedtohook && $file === 'lib.php') {
7340
    if ($migratedtohook && $file === 'lib.php') {
7819
        $pluginfunctions = $filtermigrated($plugincallback, $pluginfunctions);
7341
        $pluginfunctions = $filtermigrated($plugincallback, $pluginfunctions);
7820
    }
7342
    }
Línea 7821... Línea 7343...
7821
 
7343
 
-
 
7344
    return $pluginfunctions;
7822
    return $pluginfunctions;
7345
 
Línea 7823... Línea 7346...
7823
}
7346
}
7824
 
7347
 
7825
/**
7348
/**
Línea 7833... Línea 7356...
7833
 * @param string $directory relative directory from root
7356
 * @param string $directory relative directory from root
7834
 * @param string $exclude dir name to exclude from the list (defaults to none)
7357
 * @param string $exclude dir name to exclude from the list (defaults to none)
7835
 * @param string $basedir full path to the base dir where $plugin resides (defaults to $CFG->dirroot)
7358
 * @param string $basedir full path to the base dir where $plugin resides (defaults to $CFG->dirroot)
7836
 * @return array Sorted array of directory names found under the requested parameters
7359
 * @return array Sorted array of directory names found under the requested parameters
7837
 */
7360
 */
7838
function get_list_of_plugins($directory = 'mod', $exclude = '', $basedir = '')
7361
function get_list_of_plugins($directory='mod', $exclude='', $basedir='') {
7839
{
-
 
7840
    global $CFG;
7362
    global $CFG;
Línea 7841... Línea 7363...
7841
 
7363
 
Línea 7842... Línea 7364...
7842
    $plugins = array();
7364
    $plugins = array();
7843
 
7365
 
-
 
7366
    if (empty($basedir)) {
7844
    if (empty($basedir)) {
7367
        $basedir = $CFG->dirroot .'/'. $directory;
7845
        $basedir = $CFG->dirroot . '/' . $directory;
7368
 
7846
    } else {
7369
    } else {
Línea 7847... Línea 7370...
7847
        $basedir = $basedir . '/' . $directory;
7370
        $basedir = $basedir .'/'. $directory;
7848
    }
7371
    }
7849
 
7372
 
Línea 7883... Línea 7406...
7883
            }
7406
            }
7884
            if (array_key_exists($dir, $ignorelist)) {
7407
            if (array_key_exists($dir, $ignorelist)) {
7885
                // This directory features on the ignore list.
7408
                // This directory features on the ignore list.
7886
                continue;
7409
                continue;
7887
            }
7410
            }
7888
            if (filetype($basedir . '/' . $dir) != 'dir') {
7411
            if (filetype($basedir .'/'. $dir) != 'dir') {
7889
                continue;
7412
                continue;
7890
            }
7413
            }
7891
            $plugins[] = $dir;
7414
            $plugins[] = $dir;
7892
        }
7415
        }
7893
        closedir($dirhandle);
7416
        closedir($dirhandle);
Línea 7910... Línea 7433...
7910
 * @param bool $migratedtohook if true this is a deprecated callback, if hook callback is present then do nothing
7433
 * @param bool $migratedtohook if true this is a deprecated callback, if hook callback is present then do nothing
7911
 * @return mixed
7434
 * @return mixed
7912
 *
7435
 *
7913
 * @todo Decide about to deprecate and drop plugin_callback() - MDL-30743
7436
 * @todo Decide about to deprecate and drop plugin_callback() - MDL-30743
7914
 */
7437
 */
7915
function plugin_callback($type, $name, $feature, $action, $params = null, $default = null, bool $migratedtohook = false)
7438
function plugin_callback($type, $name, $feature, $action, $params = null, $default = null, bool $migratedtohook = false) {
7916
{
-
 
7917
    return component_callback($type . '_' . $name, $feature . '_' . $action, (array) $params, $default, $migratedtohook);
7439
    return component_callback($type . '_' . $name, $feature . '_' . $action, (array) $params, $default, $migratedtohook);
7918
}
7440
}
Línea 7919... Línea 7441...
7919
 
7441
 
7920
/**
7442
/**
Línea 7925... Línea 7447...
7925
 * @param array $params parameters of callback function
7447
 * @param array $params parameters of callback function
7926
 * @param mixed $default default value if callback function hasn't been defined, or if it retursn null.
7448
 * @param mixed $default default value if callback function hasn't been defined, or if it retursn null.
7927
 * @param bool $migratedtohook if true this is a deprecated callback, if hook callback is present then do nothing
7449
 * @param bool $migratedtohook if true this is a deprecated callback, if hook callback is present then do nothing
7928
 * @return mixed
7450
 * @return mixed
7929
 */
7451
 */
7930
function component_callback($component, $function, array $params = array(), $default = null, bool $migratedtohook = false)
7452
function component_callback($component, $function, array $params = array(), $default = null, bool $migratedtohook = false) {
7931
{
-
 
7932
    $functionname = component_callback_exists($component, $function);
7453
    $functionname = component_callback_exists($component, $function);
Línea 7933... Línea 7454...
7933
 
7454
 
7934
    if ($functionname) {
7455
    if ($functionname) {
7935
        if ($migratedtohook) {
7456
        if ($migratedtohook) {
7936
            $hookmanager = di::get(hook\manager::class);
7457
            $hookmanager = di::get(hook\manager::class);
7937
            if ($hooks = $hookmanager->get_hooks_deprecating_plugin_callback($function)) {
7458
            if ($hooks = $hookmanager->get_hooks_deprecating_plugin_callback($function)) {
7938
                if ($hookmanager->is_deprecating_hook_present($component, $function)) {
7459
                if ($hookmanager->is_deprecating_hook_present($component, $function)) {
7939
                    // Do not call the old lib.php callback,
7460
                    // Do not call the old lib.php callback,
7940
                    // it is there for compatibility with older Moodle versions only.
7461
                    // it is there for compatibility with older Moodle versions only.
7941
                    return null;
7462
                    return null;
7942
                } else {
7463
                } else if ($hookmanager->warn_on_unmigrated_legacy_hooks()) {
7943
                    $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
7464
                    $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
7944
                    debugging(
7465
                    debugging(
7945
                        "Callback $function in $component component should be migrated to new hook callback for $hookmessage",
7466
                        "Callback $function in $component component should be migrated to new hook callback for $hookmessage",
7946
                        DEBUG_DEVELOPER
-
 
7947
                    );
7467
                        DEBUG_DEVELOPER);
7948
                }
7468
                }
7949
            }
7469
            }
Línea 7950... Línea 7470...
7950
        }
7470
        }
Línea 7968... Línea 7488...
7968
 * @param string $component frankenstyle component name, e.g. 'mod_quiz'
7488
 * @param string $component frankenstyle component name, e.g. 'mod_quiz'
7969
 * @param string $function the rest of the function name, e.g. 'cron' will end up calling 'mod_quiz_cron'
7489
 * @param string $function the rest of the function name, e.g. 'cron' will end up calling 'mod_quiz_cron'
7970
 * @return mixed Complete function name to call if the callback exists or false if it doesn't.
7490
 * @return mixed Complete function name to call if the callback exists or false if it doesn't.
7971
 * @throws coding_exception if invalid component specfied
7491
 * @throws coding_exception if invalid component specfied
7972
 */
7492
 */
7973
function component_callback_exists($component, $function)
7493
function component_callback_exists($component, $function) {
7974
{
-
 
7975
    global $CFG; // This is needed for the inclusions.
7494
    global $CFG; // This is needed for the inclusions.
Línea 7976... Línea 7495...
7976
 
7495
 
7977
    $cleancomponent = clean_param($component, PARAM_COMPONENT);
7496
    $cleancomponent = clean_param($component, PARAM_COMPONENT);
7978
    if (empty($cleancomponent)) {
7497
    if (empty($cleancomponent)) {
Línea 7981... Línea 7500...
7981
    $component = $cleancomponent;
7500
    $component = $cleancomponent;
Línea 7982... Línea 7501...
7982
 
7501
 
7983
    list($type, $name) = core_component::normalize_component($component);
7502
    list($type, $name) = core_component::normalize_component($component);
Línea -... Línea 7503...
-
 
7503
    $component = $type . '_' . $name;
-
 
7504
 
-
 
7505
    // Deprecated plugin type: callbacks not supported.
-
 
7506
    if (\core_component::is_plugintype_in_deprecation($type)) {
-
 
7507
        return false;
7984
    $component = $type . '_' . $name;
7508
    }
7985
 
7509
 
Línea 7986... Línea 7510...
7986
    $oldfunction = $name . '_' . $function;
7510
    $oldfunction = $name.'_'.$function;
7987
    $function = $component . '_' . $function;
7511
    $function = $component.'_'.$function;
7988
 
7512
 
7989
    $dir = core_component::get_component_directory($component);
7513
    $dir = core_component::get_component_directory($component);
Línea 7990... Línea 7514...
7990
    if (empty($dir)) {
7514
    if (empty($dir)) {
7991
        throw new coding_exception('Invalid component used in plugin/component_callback():' . $component);
7515
        throw new coding_exception('Invalid component used in plugin/component_callback():' . $component);
7992
    }
7516
    }
7993
 
7517
 
Línea 7994... Línea 7518...
7994
    // Load library and look for function.
7518
    // Load library and look for function.
7995
    if (file_exists($dir . '/lib.php')) {
7519
    if (file_exists($dir.'/lib.php')) {
7996
        require_once($dir . '/lib.php');
7520
        require_once($dir.'/lib.php');
Línea 8020... Línea 7544...
8020
 * @param   array       $params The arguments to pass into the method.
7544
 * @param   array       $params The arguments to pass into the method.
8021
 * @param   mixed       $default The default value.
7545
 * @param   mixed       $default The default value.
8022
 * @param   bool        $migratedtohook True if the callback has been migrated to a hook.
7546
 * @param   bool        $migratedtohook True if the callback has been migrated to a hook.
8023
 * @return  mixed       The return value.
7547
 * @return  mixed       The return value.
8024
 */
7548
 */
8025
function component_class_callback($classname, $methodname, array $params, $default = null, bool $migratedtohook = false)
7549
function component_class_callback($classname, $methodname, array $params, $default = null, bool $migratedtohook = false) {
8026
{
-
 
8027
    if (!class_exists($classname)) {
7550
    if (!class_exists($classname)) {
8028
        return $default;
7551
        return $default;
8029
    }
7552
    }
Línea 8030... Línea 7553...
8030
 
7553
 
8031
    if (!method_exists($classname, $methodname)) {
7554
    if (!method_exists($classname, $methodname)) {
8032
        return $default;
7555
        return $default;
Línea -... Línea 7556...
-
 
7556
    }
-
 
7557
 
-
 
7558
    // If component can be found (flat class names not supported), and it's a deprecated plugintype, callbacks are unsupported.
-
 
7559
    $component = \core_component::get_component_from_classname($classname);
-
 
7560
    if ($component) {
-
 
7561
        [$type] = \core_component::normalize_component($component);
-
 
7562
        if (\core_component::is_plugintype_in_deprecation($type)) {
-
 
7563
            return $default;
-
 
7564
        }
8033
    }
7565
    }
Línea 8034... Línea 7566...
8034
 
7566
 
8035
    $fullfunction = $classname . '::' . $methodname;
7567
    $fullfunction = $classname . '::' . $methodname;
8036
 
7568
 
Línea 8042... Línea 7574...
8042
        if ($hooks = $hookmanager->get_hooks_deprecating_plugin_callback($callback)) {
7574
        if ($hooks = $hookmanager->get_hooks_deprecating_plugin_callback($callback)) {
8043
            if ($hookmanager->is_deprecating_hook_present($component, $callback)) {
7575
            if ($hookmanager->is_deprecating_hook_present($component, $callback)) {
8044
                // Do not call the old class callback,
7576
                // Do not call the old class callback,
8045
                // it is there for compatibility with older Moodle versions only.
7577
                // it is there for compatibility with older Moodle versions only.
8046
                return null;
7578
                return null;
8047
            } else {
7579
            } else if ($hookmanager->warn_on_unmigrated_legacy_hooks()) {
8048
                $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
7580
                $hookmessage = count($hooks) == 1 ? reset($hooks) : 'one of  ' . implode(', ', $hooks);
8049
                debugging(
-
 
8050
                    "Callback $callback in $component component should be migrated to new hook callback for $hookmessage",
7581
                debugging("Callback $callback in $component component should be migrated to new hook callback for $hookmessage",
8051
                    DEBUG_DEVELOPER
7582
                        DEBUG_DEVELOPER);
8052
                );
-
 
8053
            }
7583
            }
8054
        }
7584
        }
8055
    }
7585
    }
Línea 8056... Línea 7586...
8056
 
7586
 
Línea 8072... Línea 7602...
8072
 * @param mixed $default default value if feature support unknown
7602
 * @param mixed $default default value if feature support unknown
8073
 * @return mixed Feature result (false if not supported, null if feature is unknown,
7603
 * @return mixed Feature result (false if not supported, null if feature is unknown,
8074
 *         otherwise usually true but may have other feature-specific value such as array)
7604
 *         otherwise usually true but may have other feature-specific value such as array)
8075
 * @throws coding_exception
7605
 * @throws coding_exception
8076
 */
7606
 */
8077
function plugin_supports($type, $name, $feature, $default = null)
7607
function plugin_supports($type, $name, $feature, $default = null) {
8078
{
-
 
8079
    global $CFG;
7608
    global $CFG;
Línea 8080... Línea 7609...
8080
 
7609
 
8081
    if ($type === 'mod' and $name === 'NEWMODULE') {
7610
    if ($type === 'mod' and $name === 'NEWMODULE') {
8082
        // Somebody forgot to rename the module template.
7611
        // Somebody forgot to rename the module template.
Línea 8093... Línea 7622...
8093
    if ($type === 'mod') {
7622
    if ($type === 'mod') {
8094
        // We need this special case because we support subplugins in modules,
7623
        // We need this special case because we support subplugins in modules,
8095
        // otherwise it would end up in infinite loop.
7624
        // otherwise it would end up in infinite loop.
8096
        if (file_exists("$CFG->dirroot/mod/$name/lib.php")) {
7625
        if (file_exists("$CFG->dirroot/mod/$name/lib.php")) {
8097
            include_once("$CFG->dirroot/mod/$name/lib.php");
7626
            include_once("$CFG->dirroot/mod/$name/lib.php");
8098
            $function = $component . '_supports';
7627
            $function = $component.'_supports';
8099
            if (!function_exists($function)) {
7628
            if (!function_exists($function)) {
8100
                // Legacy non-frankenstyle function name.
7629
                // Legacy non-frankenstyle function name.
8101
                $function = $name . '_supports';
7630
                $function = $name.'_supports';
8102
            }
7631
            }
8103
        }
7632
        }
-
 
7633
 
8104
    } else {
7634
    } else {
8105
        if (!$path = core_component::get_plugin_directory($type, $name)) {
7635
        if (!$path = core_component::get_plugin_directory($type, $name)) {
8106
            // Non existent plugin type.
7636
            // Non existent plugin type.
8107
            return false;
7637
            return false;
8108
        }
7638
        }
8109
        if (file_exists("$path/lib.php")) {
7639
        if (file_exists("$path/lib.php")) {
8110
            include_once("$path/lib.php");
7640
            include_once("$path/lib.php");
8111
            $function = $component . '_supports';
7641
            $function = $component.'_supports';
8112
        }
7642
        }
8113
    }
7643
    }
Línea 8114... Línea 7644...
8114
 
7644
 
8115
    if ($function and function_exists($function)) {
7645
    if ($function and function_exists($function)) {
Línea 8132... Línea 7662...
8132
 * @todo Check PHP version being required here is it too low?
7662
 * @todo Check PHP version being required here is it too low?
8133
 *
7663
 *
8134
 * @param string $version The version of php being tested.
7664
 * @param string $version The version of php being tested.
8135
 * @return bool
7665
 * @return bool
8136
 */
7666
 */
8137
function check_php_version($version = '5.2.4')
7667
function check_php_version($version='5.2.4') {
8138
{
-
 
8139
    return (version_compare(phpversion(), $version) >= 0);
7668
    return (version_compare(phpversion(), $version) >= 0);
8140
}
7669
}
Línea 8141... Línea 7670...
8141
 
7670
 
8142
/**
7671
/**
Línea 8146... Línea 7675...
8146
 * if there are any mismatches.
7675
 * if there are any mismatches.
8147
 *
7676
 *
8148
 * @param bool $checkupgradeflag check the outagelessupgrade flag to see if an upgrade is running.
7677
 * @param bool $checkupgradeflag check the outagelessupgrade flag to see if an upgrade is running.
8149
 * @return bool
7678
 * @return bool
8150
 */
7679
 */
8151
function moodle_needs_upgrading($checkupgradeflag = true)
7680
function moodle_needs_upgrading($checkupgradeflag = true) {
8152
{
-
 
8153
    global $CFG, $DB;
7681
    global $CFG, $DB;
Línea 8154... Línea 7682...
8154
 
7682
 
8155
    // Say no if there is already an upgrade running.
7683
    // Say no if there is already an upgrade running.
8156
    if ($checkupgradeflag) {
7684
    if ($checkupgradeflag) {
Línea 8191... Línea 7719...
8191
 * the main version.php.
7719
 * the main version.php.
8192
 *
7720
 *
8193
 * @param bool $fromdisk should the version if source code files be used
7721
 * @param bool $fromdisk should the version if source code files be used
8194
 * @return string|false the major version like '2.3', false if could not be determined
7722
 * @return string|false the major version like '2.3', false if could not be determined
8195
 */
7723
 */
8196
function moodle_major_version($fromdisk = false)
7724
function moodle_major_version($fromdisk = false) {
8197
{
-
 
8198
    global $CFG;
7725
    global $CFG;
Línea 8199... Línea 7726...
8199
 
7726
 
8200
    if ($fromdisk) {
7727
    if ($fromdisk) {
8201
        $release = null;
7728
        $release = null;
8202
        require($CFG->dirroot . '/version.php');
7729
        require($CFG->dirroot.'/version.php');
8203
        if (empty($release)) {
7730
        if (empty($release)) {
8204
            return false;
7731
            return false;
-
 
7732
        }
8205
        }
7733
 
8206
    } else {
7734
    } else {
8207
        if (empty($CFG->release)) {
7735
        if (empty($CFG->release)) {
8208
            return false;
7736
            return false;
8209
        }
7737
        }
Línea 8222... Línea 7750...
8222
/**
7750
/**
8223
 * Gets the system locale
7751
 * Gets the system locale
8224
 *
7752
 *
8225
 * @return string Retuns the current locale.
7753
 * @return string Retuns the current locale.
8226
 */
7754
 */
8227
function moodle_getlocale()
7755
function moodle_getlocale() {
8228
{
-
 
8229
    global $CFG;
7756
    global $CFG;
Línea 8230... Línea 7757...
8230
 
7757
 
8231
    // Fetch the correct locale based on ostype.
7758
    // Fetch the correct locale based on ostype.
8232
    if ($CFG->ostype == 'WINDOWS') {
7759
    if ($CFG->ostype == 'WINDOWS') {
Línea 8246... Línea 7773...
8246
 * Sets the system locale
7773
 * Sets the system locale
8247
 *
7774
 *
8248
 * @category string
7775
 * @category string
8249
 * @param string $locale Can be used to force a locale
7776
 * @param string $locale Can be used to force a locale
8250
 */
7777
 */
8251
function moodle_setlocale($locale = '')
7778
function moodle_setlocale($locale='') {
8252
{
-
 
8253
    global $CFG;
7779
    global $CFG;
Línea 8254... Línea 7780...
8254
 
7780
 
Línea 8255... Línea 7781...
8255
    static $currentlocale = ''; // Last locale caching.
7781
    static $currentlocale = ''; // Last locale caching.
Línea 8271... Línea 7797...
8271
    // Due to some strange BUG we cannot set the LC_TIME directly, so we fetch current values,
7797
    // Due to some strange BUG we cannot set the LC_TIME directly, so we fetch current values,
8272
    // set LC_ALL and then set values again. Just wondering why we cannot set LC_ALL only??? - stronk7
7798
    // set LC_ALL and then set values again. Just wondering why we cannot set LC_ALL only??? - stronk7
8273
    // Some day, numeric, monetary and other categories should be set too, I think. :-/.
7799
    // Some day, numeric, monetary and other categories should be set too, I think. :-/.
Línea 8274... Línea 7800...
8274
 
7800
 
8275
    // Get current values.
7801
    // Get current values.
8276
    $monetary = setlocale(LC_MONETARY, 0);
7802
    $monetary= setlocale (LC_MONETARY, 0);
8277
    $numeric = setlocale(LC_NUMERIC, 0);
7803
    $numeric = setlocale (LC_NUMERIC, 0);
8278
    $ctype   = setlocale(LC_CTYPE, 0);
7804
    $ctype   = setlocale (LC_CTYPE, 0);
8279
    if ($CFG->ostype != 'WINDOWS') {
7805
    if ($CFG->ostype != 'WINDOWS') {
8280
        $messages = setlocale(LC_MESSAGES, 0);
7806
        $messages= setlocale (LC_MESSAGES, 0);
8281
    }
7807
    }
8282
    // Set locale to all.
7808
    // Set locale to all.
8283
    $result = setlocale(LC_ALL, $currentlocale);
7809
    $result = setlocale (LC_ALL, $currentlocale);
8284
    // If setting of locale fails try the other utf8 or utf-8 variant,
7810
    // If setting of locale fails try the other utf8 or utf-8 variant,
8285
    // some operating systems support both (Debian), others just one (OSX).
7811
    // some operating systems support both (Debian), others just one (OSX).
8286
    if ($result === false) {
7812
    if ($result === false) {
8287
        if (stripos($currentlocale, '.UTF-8') !== false) {
7813
        if (stripos($currentlocale, '.UTF-8') !== false) {
8288
            $newlocale = str_ireplace('.UTF-8', '.UTF8', $currentlocale);
7814
            $newlocale = str_ireplace('.UTF-8', '.UTF8', $currentlocale);
8289
            setlocale(LC_ALL, $newlocale);
7815
            setlocale (LC_ALL, $newlocale);
8290
        } else if (stripos($currentlocale, '.UTF8') !== false) {
7816
        } else if (stripos($currentlocale, '.UTF8') !== false) {
8291
            $newlocale = str_ireplace('.UTF8', '.UTF-8', $currentlocale);
7817
            $newlocale = str_ireplace('.UTF8', '.UTF-8', $currentlocale);
8292
            setlocale(LC_ALL, $newlocale);
7818
            setlocale (LC_ALL, $newlocale);
8293
        }
7819
        }
8294
    }
7820
    }
8295
    // Set old values.
7821
    // Set old values.
8296
    setlocale(LC_MONETARY, $monetary);
7822
    setlocale (LC_MONETARY, $monetary);
8297
    setlocale(LC_NUMERIC, $numeric);
7823
    setlocale (LC_NUMERIC, $numeric);
8298
    if ($CFG->ostype != 'WINDOWS') {
7824
    if ($CFG->ostype != 'WINDOWS') {
8299
        setlocale(LC_MESSAGES, $messages);
7825
        setlocale (LC_MESSAGES, $messages);
8300
    }
7826
    }
8301
    if ($currentlocale == 'tr_TR' or $currentlocale == 'tr_TR.UTF-8') {
7827
    if ($currentlocale == 'tr_TR' or $currentlocale == 'tr_TR.UTF-8') {
8302
        // To workaround a well-known PHP problem with Turkish letter Ii.
7828
        // To workaround a well-known PHP problem with Turkish letter Ii.
8303
        setlocale(LC_CTYPE, $ctype);
7829
        setlocale (LC_CTYPE, $ctype);
8304
    }
7830
    }
Línea 8305... Línea 7831...
8305
}
7831
}
8306
 
7832
 
Línea 8312... Línea 7838...
8312
 * @category string
7838
 * @category string
8313
 * @param string $string The text to be searched for words. May be HTML.
7839
 * @param string $string The text to be searched for words. May be HTML.
8314
 * @param int|null $format
7840
 * @param int|null $format
8315
 * @return int The count of words in the specified string
7841
 * @return int The count of words in the specified string
8316
 */
7842
 */
8317
function count_words($string, $format = null)
7843
function count_words($string, $format = null) {
8318
{
-
 
8319
    // Before stripping tags, add a space after the close tag of anything that is not obviously inline.
7844
    // Before stripping tags, add a space after the close tag of anything that is not obviously inline.
8320
    // Also, br is a special case because it definitely delimits a word, but has no close tag.
7845
    // Also, br is a special case because it definitely delimits a word, but has no close tag.
8321
    $string = preg_replace('~
7846
    $string = preg_replace('~
8322
            (                                   # Capture the tag we match.
7847
            (                                   # Capture the tag we match.
8323
                </                              # Start of close tag.
7848
                </                              # Start of close tag.
Línea 8359... Línea 7884...
8359
 * @category string
7884
 * @category string
8360
 * @param string $string The text to be searched for letters. May be HTML.
7885
 * @param string $string The text to be searched for letters. May be HTML.
8361
 * @param int|null $format
7886
 * @param int|null $format
8362
 * @return int The count of letters in the specified text.
7887
 * @return int The count of letters in the specified text.
8363
 */
7888
 */
8364
function count_letters($string, $format = null)
7889
function count_letters($string, $format = null) {
8365
{
-
 
8366
    if ($format !== null && $format != FORMAT_PLAIN) {
7890
    if ($format !== null && $format != FORMAT_PLAIN) {
8367
        // Match the usual text cleaning before display.
7891
        // Match the usual text cleaning before display.
8368
        // Ideally we should apply multilang filter only here, other filters might add extra text.
7892
        // Ideally we should apply multilang filter only here, other filters might add extra text.
8369
        $string = format_text($string, $format, ['filter' => false, 'noclean' => false, 'para' => false]);
7893
        $string = format_text($string, $format, ['filter' => false, 'noclean' => false, 'para' => false]);
8370
    }
7894
    }
Línea 8379... Línea 7903...
8379
 * Generate and return a random string of the specified length.
7903
 * Generate and return a random string of the specified length.
8380
 *
7904
 *
8381
 * @param int $length The length of the string to be created.
7905
 * @param int $length The length of the string to be created.
8382
 * @return string
7906
 * @return string
8383
 */
7907
 */
8384
function random_string($length = 15)
7908
function random_string($length=15) {
8385
{
-
 
8386
    $randombytes = random_bytes($length);
7909
    $randombytes = random_bytes($length);
8387
    $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
7910
    $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
8388
    $pool .= 'abcdefghijklmnopqrstuvwxyz';
7911
    $pool .= 'abcdefghijklmnopqrstuvwxyz';
8389
    $pool .= '0123456789';
7912
    $pool .= '0123456789';
8390
    $poollen = strlen($pool);
7913
    $poollen = strlen($pool);
8391
    $string = '';
7914
    $string = '';
8392
    for ($i = 0; $i < $length; $i++) {
7915
    for ($i = 0; $i < $length; $i++) {
8393
        $rand = ord($randombytes[$i]);
7916
        $rand = ord($randombytes[$i]);
8394
        $string .= substr($pool, ($rand % ($poollen)), 1);
7917
        $string .= substr($pool, ($rand%($poollen)), 1);
8395
    }
7918
    }
8396
    return $string;
7919
    return $string;
8397
}
7920
}
Línea 8398... Línea 7921...
8398
 
7921
 
Línea 8403... Línea 7926...
8403
 * larger pool of characters and generates a string between 24 and 32 characters
7926
 * larger pool of characters and generates a string between 24 and 32 characters
8404
 *
7927
 *
8405
 * @param int $length Optional if set generates a string to exactly this length
7928
 * @param int $length Optional if set generates a string to exactly this length
8406
 * @return string
7929
 * @return string
8407
 */
7930
 */
8408
function complex_random_string($length = null)
7931
function complex_random_string($length=null) {
8409
{
-
 
8410
    $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
7932
    $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
8411
    $pool .= '`~!@#%^&*()_+-=[];,./<>?:{} ';
7933
    $pool .= '`~!@#%^&*()_+-=[];,./<>?:{} ';
8412
    $poollen = strlen($pool);
7934
    $poollen = strlen($pool);
8413
    if ($length === null) {
7935
    if ($length===null) {
8414
        $length = floor(rand(24, 32));
7936
        $length = floor(rand(24, 32));
8415
    }
7937
    }
8416
    $randombytes = random_bytes($length);
7938
    $randombytes = random_bytes($length);
8417
    $string = '';
7939
    $string = '';
8418
    for ($i = 0; $i < $length; $i++) {
7940
    for ($i = 0; $i < $length; $i++) {
8419
        $rand = ord($randombytes[$i]);
7941
        $rand = ord($randombytes[$i]);
8420
        $string .= $pool[($rand % $poollen)];
7942
        $string .= $pool[($rand%$poollen)];
8421
    }
7943
    }
8422
    return $string;
7944
    return $string;
8423
}
7945
}
Línea 8424... Línea 7946...
8424
 
7946
 
Línea 8431... Línea 7953...
8431
 * @param int $ideal ideal string length
7953
 * @param int $ideal ideal string length
8432
 * @param boolean $exact if false, $text will not be cut mid-word
7954
 * @param boolean $exact if false, $text will not be cut mid-word
8433
 * @param string $ending The string to append if the passed string is truncated
7955
 * @param string $ending The string to append if the passed string is truncated
8434
 * @return string $truncate shortened string
7956
 * @return string $truncate shortened string
8435
 */
7957
 */
8436
function shorten_text($text, $ideal = 30, $exact = false, $ending = '...')
7958
function shorten_text($text, $ideal=30, $exact = false, $ending='...') {
8437
{
-
 
8438
    // If the plain text is shorter than the maximum length, return the whole text.
7959
    // If the plain text is shorter than the maximum length, return the whole text.
8439
    if (core_text::strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) {
7960
    if (core_text::strlen(preg_replace('/<.*?>/', '', $text)) <= $ideal) {
8440
        return $text;
7961
        return $text;
8441
    }
7962
    }
Línea 8459... Línea 7980...
8459
            // If it's an "empty element" with or without xhtml-conform closing slash (f.e. <br/>).
7980
            // If it's an "empty element" with or without xhtml-conform closing slash (f.e. <br/>).
8460
            if (!preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $linematchings[1])) {
7981
            if (!preg_match('/^<(\s*.+?\/\s*|\s*(img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param)(\s.+?)?)>$/is', $linematchings[1])) {
8461
                if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $linematchings[1], $tagmatchings)) {
7982
                if (preg_match('/^<\s*\/([^\s]+?)\s*>$/s', $linematchings[1], $tagmatchings)) {
8462
                    // Record closing tag.
7983
                    // Record closing tag.
8463
                    $tagdetails[] = (object) array(
7984
                    $tagdetails[] = (object) array(
8464
                        'open' => false,
7985
                            'open' => false,
8465
                        'tag'  => core_text::strtolower($tagmatchings[1]),
7986
                            'tag'  => core_text::strtolower($tagmatchings[1]),
8466
                        'pos'  => core_text::strlen($truncate),
7987
                            'pos'  => core_text::strlen($truncate),
8467
                    );
7988
                        );
-
 
7989
 
8468
                } else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $linematchings[1], $tagmatchings)) {
7990
                } else if (preg_match('/^<\s*([^\s>!]+).*?>$/s', $linematchings[1], $tagmatchings)) {
8469
                    // Record opening tag.
7991
                    // Record opening tag.
8470
                    $tagdetails[] = (object) array(
7992
                    $tagdetails[] = (object) array(
8471
                        'open' => true,
7993
                            'open' => true,
8472
                        'tag'  => core_text::strtolower($tagmatchings[1]),
7994
                            'tag'  => core_text::strtolower($tagmatchings[1]),
8473
                        'pos'  => core_text::strlen($truncate),
7995
                            'pos'  => core_text::strlen($truncate),
8474
                    );
7996
                        );
8475
                } else if (preg_match('/^<!--\[if\s.*?\]>$/s', $linematchings[1], $tagmatchings)) {
7997
                } else if (preg_match('/^<!--\[if\s.*?\]>$/s', $linematchings[1], $tagmatchings)) {
8476
                    $tagdetails[] = (object) array(
7998
                    $tagdetails[] = (object) array(
8477
                        'open' => true,
7999
                            'open' => true,
8478
                        'tag'  => core_text::strtolower('if'),
8000
                            'tag'  => core_text::strtolower('if'),
8479
                        'pos'  => core_text::strlen($truncate),
8001
                            'pos'  => core_text::strlen($truncate),
8480
                    );
8002
                    );
8481
                } else if (preg_match('/^<!--<!\[endif\]-->$/s', $linematchings[1], $tagmatchings)) {
8003
                } else if (preg_match('/^<!--<!\[endif\]-->$/s', $linematchings[1], $tagmatchings)) {
8482
                    $tagdetails[] = (object) array(
8004
                    $tagdetails[] = (object) array(
8483
                        'open' => false,
8005
                            'open' => false,
8484
                        'tag'  => core_text::strtolower('if'),
8006
                            'tag'  => core_text::strtolower('if'),
8485
                        'pos'  => core_text::strlen($truncate),
8007
                            'pos'  => core_text::strlen($truncate),
8486
                    );
8008
                    );
8487
                }
8009
                }
8488
            }
8010
            }
8489
            // Add html-tag to $truncate'd text.
8011
            // Add html-tag to $truncate'd text.
8490
            $truncate .= $linematchings[1];
8012
            $truncate .= $linematchings[1];
Línea 8498... Línea 8020...
8498
            $entitieslength = 0;
8020
            $entitieslength = 0;
8499
            // Search for html entities.
8021
            // Search for html entities.
8500
            if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $linematchings[2], $entities, PREG_OFFSET_CAPTURE)) {
8022
            if (preg_match_all('/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $linematchings[2], $entities, PREG_OFFSET_CAPTURE)) {
8501
                // Calculate the real length of all entities in the legal range.
8023
                // Calculate the real length of all entities in the legal range.
8502
                foreach ($entities[0] as $entity) {
8024
                foreach ($entities[0] as $entity) {
8503
                    if ($entity[1] + 1 - $entitieslength <= $left) {
8025
                    if ($entity[1]+1-$entitieslength <= $left) {
8504
                        $left--;
8026
                        $left--;
8505
                        $entitieslength += core_text::strlen($entity[0]);
8027
                        $entitieslength += core_text::strlen($entity[0]);
8506
                    } else {
8028
                    } else {
8507
                        // No more characters left.
8029
                        // No more characters left.
8508
                        break;
8030
                        break;
Línea 8587... Línea 8109...
8587
 * @param string $filename file name
8109
 * @param string $filename file name
8588
 * @param int $length ideal string length
8110
 * @param int $length ideal string length
8589
 * @param bool $includehash Whether to include a file hash in the shortened version. This ensures uniqueness.
8111
 * @param bool $includehash Whether to include a file hash in the shortened version. This ensures uniqueness.
8590
 * @return string $shortened shortened file name
8112
 * @return string $shortened shortened file name
8591
 */
8113
 */
8592
function shorten_filename($filename, $length = MAX_FILENAME_SIZE, $includehash = false)
8114
function shorten_filename($filename, $length = MAX_FILENAME_SIZE, $includehash = false) {
8593
{
-
 
8594
    $shortened = $filename;
8115
    $shortened = $filename;
8595
    // Extract a part of the filename if it's char size exceeds the ideal string length.
8116
    // Extract a part of the filename if it's char size exceeds the ideal string length.
8596
    if (core_text::strlen($filename) > $length) {
8117
    if (core_text::strlen($filename) > $length) {
8597
        // Exclude extension if present in filename.
8118
        // Exclude extension if present in filename.
8598
        $mimetypes = get_mimetypes_array();
8119
        $mimetypes = get_mimetypes_array();
Línea 8616... Línea 8137...
8616
 * @param array $path The paths to reduce the length.
8137
 * @param array $path The paths to reduce the length.
8617
 * @param int $length Ideal string length
8138
 * @param int $length Ideal string length
8618
 * @param bool $includehash Whether to include a file hash in the shortened version. This ensures uniqueness.
8139
 * @param bool $includehash Whether to include a file hash in the shortened version. This ensures uniqueness.
8619
 * @return array $result Shortened paths in array.
8140
 * @return array $result Shortened paths in array.
8620
 */
8141
 */
8621
function shorten_filenames(array $path, $length = MAX_FILENAME_SIZE, $includehash = false)
8142
function shorten_filenames(array $path, $length = MAX_FILENAME_SIZE, $includehash = false) {
8622
{
-
 
8623
    $result = null;
8143
    $result = null;
Línea 8624... Línea 8144...
8624
 
8144
 
8625
    $result = array_reduce($path, function ($carry, $singlepath) use ($length, $includehash) {
8145
    $result = array_reduce($path, function($carry, $singlepath) use ($length, $includehash) {
8626
        $carry[] = shorten_filename($singlepath, $length, $includehash);
8146
        $carry[] = shorten_filename($singlepath, $length, $includehash);
8627
        return $carry;
8147
        return $carry;
Línea 8628... Línea 8148...
8628
    }, []);
8148
    }, []);
Línea 8636... Línea 8156...
8636
 *
8156
 *
8637
 * @param int $startdate Timestamp for the start date
8157
 * @param int $startdate Timestamp for the start date
8638
 * @param int $thedate Timestamp for the end date
8158
 * @param int $thedate Timestamp for the end date
8639
 * @return string
8159
 * @return string
8640
 */
8160
 */
8641
function getweek($startdate, $thedate)
8161
function getweek ($startdate, $thedate) {
8642
{
-
 
8643
    if ($thedate < $startdate) {
8162
    if ($thedate < $startdate) {
8644
        return 0;
8163
        return 0;
8645
    }
8164
    }
Línea 8646... Línea 8165...
8646
 
8165
 
Línea 8654... Línea 8173...
8654
 * {@link http://es2.php.net/manual/en/function.str-shuffle.php#73254}
8173
 * {@link http://es2.php.net/manual/en/function.str-shuffle.php#73254}
8655
 *
8174
 *
8656
 * @param int $maxlen  The maximum size of the password being generated.
8175
 * @param int $maxlen  The maximum size of the password being generated.
8657
 * @return string
8176
 * @return string
8658
 */
8177
 */
8659
function generate_password($maxlen = 10)
8178
function generate_password($maxlen=10) {
8660
{
-
 
8661
    global $CFG;
8179
    global $CFG;
Línea 8662... Línea 8180...
8662
 
8180
 
8663
    if (empty($CFG->passwordpolicy)) {
8181
    if (empty($CFG->passwordpolicy)) {
8664
        $fillers = PASSWORD_DIGITS;
8182
        $fillers = PASSWORD_DIGITS;
Línea 8698... Línea 8216...
8698
        while ($nonalphanum > strlen($passwordnonalphanum)) {
8216
        while ($nonalphanum > strlen($passwordnonalphanum)) {
8699
            $passwordnonalphanum .= PASSWORD_NONALPHANUM;
8217
            $passwordnonalphanum .= PASSWORD_NONALPHANUM;
8700
        }
8218
        }
Línea 8701... Línea 8219...
8701
 
8219
 
8702
        // Now mix and shuffle it all.
8220
        // Now mix and shuffle it all.
8703
        $password = str_shuffle(substr(str_shuffle($passwordlower), 0, $lower) .
8221
        $password = str_shuffle (substr(str_shuffle ($passwordlower), 0, $lower) .
8704
            substr(str_shuffle($passwordupper), 0, $upper) .
8222
                                 substr(str_shuffle ($passwordupper), 0, $upper) .
8705
            substr(str_shuffle($passworddigits), 0, $digits) .
8223
                                 substr(str_shuffle ($passworddigits), 0, $digits) .
8706
            substr(str_shuffle($passwordnonalphanum), 0, $nonalphanum) .
8224
                                 substr(str_shuffle ($passwordnonalphanum), 0 , $nonalphanum) .
8707
            substr(str_shuffle($passwordlower .
8225
                                 substr(str_shuffle ($passwordlower .
8708
                $passwordupper .
8226
                                                     $passwordupper .
8709
                $passworddigits .
8227
                                                     $passworddigits .
8710
                $passwordnonalphanum), 0, $additional));
8228
                                                     $passwordnonalphanum), 0 , $additional));
Línea 8711... Línea 8229...
8711
    }
8229
    }
8712
 
8230
 
Línea 8713... Línea 8231...
8713
    return substr($password, 0, $maxlen);
8231
    return substr ($password, 0, $maxlen);
8714
}
8232
}
8715
 
8233
 
Línea 8727... Línea 8245...
8727
 * @param bool $localized use localized decimal separator
8245
 * @param bool $localized use localized decimal separator
8728
 * @param bool $stripzeros If true, removes final zeros after decimal point. It will be ignored and the trailing zeros after
8246
 * @param bool $stripzeros If true, removes final zeros after decimal point. It will be ignored and the trailing zeros after
8729
 *                         the decimal point are always striped if $decimalpoints is -1.
8247
 *                         the decimal point are always striped if $decimalpoints is -1.
8730
 * @return string locale float
8248
 * @return string locale float
8731
 */
8249
 */
8732
function format_float($float, $decimalpoints = 1, $localized = true, $stripzeros = false)
8250
function format_float($float, $decimalpoints=1, $localized=true, $stripzeros=false) {
8733
{
-
 
8734
    if (is_null($float)) {
8251
    if (is_null($float)) {
8735
        return '';
8252
        return '';
8736
    }
8253
    }
8737
    if ($localized) {
8254
    if ($localized) {
8738
        $separator = get_string('decsep', 'langconfig');
8255
        $separator = get_string('decsep', 'langconfig');
Línea 8761... Línea 8278...
8761
 *
8278
 *
8762
 * @param string $localefloat locale aware float representation
8279
 * @param string $localefloat locale aware float representation
8763
 * @param bool $strict If true, then check the input and return false if it is not a valid number.
8280
 * @param bool $strict If true, then check the input and return false if it is not a valid number.
8764
 * @return mixed float|bool - false or the parsed float.
8281
 * @return mixed float|bool - false or the parsed float.
8765
 */
8282
 */
8766
function unformat_float($localefloat, $strict = false)
8283
function unformat_float($localefloat, $strict = false) {
8767
{
-
 
8768
    $localefloat = trim((string)$localefloat);
8284
    $localefloat = trim((string)$localefloat);
Línea 8769... Línea 8285...
8769
 
8285
 
8770
    if ($localefloat == '') {
8286
    if ($localefloat == '') {
8771
        return null;
8287
        return null;
Línea 8786... Línea 8302...
8786
 * Unlike PHP's shuffle() this function works on any machine.
8302
 * Unlike PHP's shuffle() this function works on any machine.
8787
 *
8303
 *
8788
 * @param array $array The array to be rearranged
8304
 * @param array $array The array to be rearranged
8789
 * @return array
8305
 * @return array
8790
 */
8306
 */
8791
function swapshuffle($array)
8307
function swapshuffle($array) {
8792
{
-
 
Línea 8793... Línea 8308...
8793
 
8308
 
8794
    $last = count($array) - 1;
8309
    $last = count($array) - 1;
8795
    for ($i = 0; $i <= $last; $i++) {
8310
    for ($i = 0; $i <= $last; $i++) {
8796
        $from = rand(0, $last);
8311
        $from = rand(0, $last);
Línea 8805... Línea 8320...
8805
 * Like {@link swapshuffle()}, but works on associative arrays
8320
 * Like {@link swapshuffle()}, but works on associative arrays
8806
 *
8321
 *
8807
 * @param array $array The associative array to be rearranged
8322
 * @param array $array The associative array to be rearranged
8808
 * @return array
8323
 * @return array
8809
 */
8324
 */
8810
function swapshuffle_assoc($array)
8325
function swapshuffle_assoc($array) {
8811
{
-
 
Línea 8812... Línea 8326...
8812
 
8326
 
8813
    $newarray = array();
8327
    $newarray = array();
Línea 8814... Línea 8328...
8814
    $newkeys = swapshuffle(array_keys($array));
8328
    $newkeys = swapshuffle(array_keys($array));
Línea 8828... Línea 8342...
8828
 *
8342
 *
8829
 * @param array $array
8343
 * @param array $array
8830
 * @param int $draws
8344
 * @param int $draws
8831
 * @return array
8345
 * @return array
8832
 */
8346
 */
8833
function draw_rand_array($array, $draws)
8347
function draw_rand_array($array, $draws) {
8834
{
-
 
Línea 8835... Línea 8348...
8835
 
8348
 
Línea 8836... Línea 8349...
8836
    $return = array();
8349
    $return = array();
Línea 8861... Línea 8374...
8861
 *
8374
 *
8862
 * @param string $a The first Microtime
8375
 * @param string $a The first Microtime
8863
 * @param string $b The second Microtime
8376
 * @param string $b The second Microtime
8864
 * @return string
8377
 * @return string
8865
 */
8378
 */
8866
function microtime_diff($a, $b)
8379
function microtime_diff($a, $b) {
8867
{
-
 
8868
    list($adec, $asec) = explode(' ', $a);
8380
    list($adec, $asec) = explode(' ', $a);
8869
    list($bdec, $bsec) = explode(' ', $b);
8381
    list($bdec, $bsec) = explode(' ', $b);
8870
    return $bsec - $asec + $bdec - $adec;
8382
    return $bsec - $asec + $bdec - $adec;
8871
}
8383
}
Línea 8876... Línea 8388...
8876
 *
8388
 *
8877
 * @param string $list The string to explode into array bits
8389
 * @param string $list The string to explode into array bits
8878
 * @param string $separator The separator used within the list string
8390
 * @param string $separator The separator used within the list string
8879
 * @return array The now assembled array
8391
 * @return array The now assembled array
8880
 */
8392
 */
8881
function make_menu_from_list($list, $separator = ',')
8393
function make_menu_from_list($list, $separator=',') {
8882
{
-
 
Línea 8883... Línea 8394...
8883
 
8394
 
8884
    $array = array_reverse(explode($separator, $list), true);
8395
    $array = array_reverse(explode($separator, $list), true);
8885
    foreach ($array as $key => $item) {
8396
    foreach ($array as $key => $item) {
8886
        $outarray[$key + 1] = trim($item);
8397
        $outarray[$key+1] = trim($item);
8887
    }
8398
    }
8888
    return $outarray;
8399
    return $outarray;
Línea 8889... Línea 8400...
8889
}
8400
}
Línea 8899... Línea 8410...
8899
 * @todo Finish documenting this function or better deprecated this completely!
8410
 * @todo Finish documenting this function or better deprecated this completely!
8900
 *
8411
 *
8901
 * @param int $gradingtype
8412
 * @param int $gradingtype
8902
 * @return array
8413
 * @return array
8903
 */
8414
 */
8904
function make_grades_menu($gradingtype)
8415
function make_grades_menu($gradingtype) {
8905
{
-
 
8906
    global $DB;
8416
    global $DB;
Línea 8907... Línea 8417...
8907
 
8417
 
8908
    $grades = array();
8418
    $grades = array();
8909
    if ($gradingtype < 0) {
8419
    if ($gradingtype < 0) {
8910
        if ($scale = $DB->get_record('scale', array('id' => (-$gradingtype)))) {
8420
        if ($scale = $DB->get_record('scale', array('id'=> (-$gradingtype)))) {
8911
            return make_menu_from_list($scale->scale);
8421
            return make_menu_from_list($scale->scale);
8912
        }
8422
        }
8913
    } else if ($gradingtype > 0) {
8423
    } else if ($gradingtype > 0) {
8914
        for ($i = $gradingtype; $i >= 0; $i--) {
8424
        for ($i=$gradingtype; $i>=0; $i--) {
8915
            $grades[$i] = $i . ' / ' . $gradingtype;
8425
            $grades[$i] = $i .' / '. $gradingtype;
8916
        }
8426
        }
8917
        return $grades;
8427
        return $grades;
8918
    }
8428
    }
8919
    return $grades;
8429
    return $grades;
Línea 8926... Línea 8436...
8926
 *
8436
 *
8927
 * @uses $_SERVER
8437
 * @uses $_SERVER
8928
 * @param string $extra Extra string to append to the end of the code
8438
 * @param string $extra Extra string to append to the end of the code
8929
 * @return string
8439
 * @return string
8930
 */
8440
 */
8931
function make_unique_id_code($extra = '')
8441
function make_unique_id_code($extra = '') {
8932
{
-
 
Línea 8933... Línea 8442...
8933
 
8442
 
8934
    $hostname = 'unknownhost';
8443
    $hostname = 'unknownhost';
8935
    if (!empty($_SERVER['HTTP_HOST'])) {
8444
    if (!empty($_SERVER['HTTP_HOST'])) {
8936
        $hostname = $_SERVER['HTTP_HOST'];
8445
        $hostname = $_SERVER['HTTP_HOST'];
Línea 8945... Línea 8454...
8945
    $date = gmdate("ymdHis");
8454
    $date = gmdate("ymdHis");
Línea 8946... Línea 8455...
8946
 
8455
 
Línea 8947... Línea 8456...
8947
    $random =  random_string(6);
8456
    $random =  random_string(6);
8948
 
8457
 
8949
    if ($extra) {
8458
    if ($extra) {
8950
        return $hostname . '+' . $date . '+' . $random . '+' . $extra;
8459
        return $hostname .'+'. $date .'+'. $random .'+'. $extra;
8951
    } else {
8460
    } else {
8952
        return $hostname . '+' . $date . '+' . $random;
8461
        return $hostname .'+'. $date .'+'. $random;
Línea 8953... Línea 8462...
8953
    }
8462
    }
Línea 8968... Línea 8477...
8968
 * @param string $addr    The address you are checking
8477
 * @param string $addr    The address you are checking
8969
 * @param string $subnetstr    The string of subnet addresses
8478
 * @param string $subnetstr    The string of subnet addresses
8970
 * @param bool $checkallzeros    The state to whether check for 0.0.0.0
8479
 * @param bool $checkallzeros    The state to whether check for 0.0.0.0
8971
 * @return bool
8480
 * @return bool
8972
 */
8481
 */
8973
function address_in_subnet($addr, $subnetstr, $checkallzeros = false)
8482
function address_in_subnet($addr, $subnetstr, $checkallzeros = false) {
8974
{
-
 
Línea 8975... Línea 8483...
8975
 
8483
 
8976
    if ($addr == '0.0.0.0' && !$checkallzeros) {
8484
    if ($addr == '0.0.0.0' && !$checkallzeros) {
8977
        return false;
8485
        return false;
8978
    }
8486
    }
Línea 9021... Línea 8529...
9021
                    }
8529
                    }
9022
                    continue;
8530
                    continue;
9023
                }
8531
                }
9024
                $ipparts = explode(':', $ip);
8532
                $ipparts = explode(':', $ip);
9025
                $modulo  = $mask % 16;
8533
                $modulo  = $mask % 16;
9026
                $ipnet   = array_slice($ipparts, 0, ($mask - $modulo) / 16);
8534
                $ipnet   = array_slice($ipparts, 0, ($mask-$modulo)/16);
9027
                $addrnet = array_slice($addrparts, 0, ($mask - $modulo) / 16);
8535
                $addrnet = array_slice($addrparts, 0, ($mask-$modulo)/16);
9028
                if (implode(':', $ipnet) === implode(':', $addrnet)) {
8536
                if (implode(':', $ipnet) === implode(':', $addrnet)) {
9029
                    if ($modulo == 0) {
8537
                    if ($modulo == 0) {
9030
                        return true;
8538
                        return true;
9031
                    }
8539
                    }
9032
                    $pos     = ($mask - $modulo) / 16;
8540
                    $pos     = ($mask-$modulo)/16;
9033
                    $ipnet   = hexdec($ipparts[$pos]);
8541
                    $ipnet   = hexdec($ipparts[$pos]);
9034
                    $addrnet = hexdec($addrparts[$pos]);
8542
                    $addrnet = hexdec($addrparts[$pos]);
9035
                    $mask    = 0xffff << (16 - $modulo);
8543
                    $mask    = 0xffff << (16 - $modulo);
9036
                    if (($addrnet & $mask) == ($ipnet & $mask)) {
8544
                    if (($addrnet & $mask) == ($ipnet & $mask)) {
9037
                        return true;
8545
                        return true;
9038
                    }
8546
                    }
9039
                }
8547
                }
-
 
8548
 
9040
            } else {
8549
            } else {
9041
                // IPv4.
8550
                // IPv4.
9042
                if ($ipv6) {
8551
                if ($ipv6) {
9043
                    continue;
8552
                    continue;
9044
                }
8553
                }
Línea 9057... Línea 8566...
9057
                $mask = 0xffffffff << (32 - $mask);
8566
                $mask = 0xffffffff << (32 - $mask);
9058
                if (((ip2long($addr) & $mask) == (ip2long($ip) & $mask))) {
8567
                if (((ip2long($addr) & $mask) == (ip2long($ip) & $mask))) {
9059
                    return true;
8568
                    return true;
9060
                }
8569
                }
9061
            }
8570
            }
-
 
8571
 
9062
        } else if (strpos($subnet, '-') !== false) {
8572
        } else if (strpos($subnet, '-') !== false) {
9063
            // 2: xxx.xxx.xxx.xxx-yyy or  xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy. A range of IP addresses in the last group.
8573
            // 2: xxx.xxx.xxx.xxx-yyy or  xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy. A range of IP addresses in the last group.
9064
            $parts = explode('-', $subnet);
8574
            $parts = explode('-', $subnet);
9065
            if (count($parts) != 2) {
8575
            if (count($parts) != 2) {
9066
                continue;
8576
                continue;
Línea 9093... Línea 8603...
9093
                $addrend = hexdec($addrparts[7]);
8603
                $addrend = hexdec($addrparts[7]);
Línea 9094... Línea 8604...
9094
 
8604
 
9095
                if (($addrend >= $start) and ($addrend <= $end)) {
8605
                if (($addrend >= $start) and ($addrend <= $end)) {
9096
                    return true;
8606
                    return true;
-
 
8607
                }
9097
                }
8608
 
9098
            } else {
8609
            } else {
9099
                // IPv4.
8610
                // IPv4.
9100
                if ($ipv6) {
8611
                if ($ipv6) {
9101
                    continue;
8612
                    continue;
Línea 9113... Línea 8624...
9113
 
8624
 
9114
                if ((ip2long($addr) >= ip2long($ipstart)) and (ip2long($addr) <= ip2long($ipend))) {
8625
                if ((ip2long($addr) >= ip2long($ipstart)) and (ip2long($addr) <= ip2long($ipend))) {
9115
                    return true;
8626
                    return true;
9116
                }
8627
                }
-
 
8628
            }
9117
            }
8629
 
9118
        } else {
8630
        } else {
9119
            // 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx.
8631
            // 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx.
9120
            if (strpos($subnet, ':') !== false) {
8632
            if (strpos($subnet, ':') !== false) {
9121
                // IPv6.
8633
                // IPv6.
9122
                if (!$ipv6) {
8634
                if (!$ipv6) {
9123
                    continue;
8635
                    continue;
9124
                }
8636
                }
9125
                $parts = explode(':', $subnet);
8637
                $parts = explode(':', $subnet);
9126
                $count = count($parts);
8638
                $count = count($parts);
9127
                if ($parts[$count - 1] === '') {
8639
                if ($parts[$count-1] === '') {
9128
                    unset($parts[$count - 1]); // Trim trailing :'s.
8640
                    unset($parts[$count-1]); // Trim trailing :'s.
9129
                    $count--;
8641
                    $count--;
9130
                    $subnet = implode('.', $parts);
8642
                    $subnet = implode('.', $parts);
9131
                }
8643
                }
9132
                $isip = cleanremoteaddr($subnet, false); // Normalise.
8644
                $isip = cleanremoteaddr($subnet, false); // Normalise.
Línea 9136... Línea 8648...
9136
                    }
8648
                    }
9137
                    continue;
8649
                    continue;
9138
                } else if ($count > 8) {
8650
                } else if ($count > 8) {
9139
                    continue;
8651
                    continue;
9140
                }
8652
                }
9141
                $zeros = array_fill(0, 8 - $count, '0');
8653
                $zeros = array_fill(0, 8-$count, '0');
9142
                $subnet = $subnet . ':' . implode(':', $zeros) . '/' . ($count * 16);
8654
                $subnet = $subnet.':'.implode(':', $zeros).'/'.($count*16);
9143
                if (address_in_subnet($addr, $subnet)) {
8655
                if (address_in_subnet($addr, $subnet)) {
9144
                    return true;
8656
                    return true;
9145
                }
8657
                }
-
 
8658
 
9146
            } else {
8659
            } else {
9147
                // IPv4.
8660
                // IPv4.
9148
                if ($ipv6) {
8661
                if ($ipv6) {
9149
                    continue;
8662
                    continue;
9150
                }
8663
                }
9151
                $parts = explode('.', $subnet);
8664
                $parts = explode('.', $subnet);
9152
                $count = count($parts);
8665
                $count = count($parts);
9153
                if ($parts[$count - 1] === '') {
8666
                if ($parts[$count-1] === '') {
9154
                    unset($parts[$count - 1]); // Trim trailing .
8667
                    unset($parts[$count-1]); // Trim trailing .
9155
                    $count--;
8668
                    $count--;
9156
                    $subnet = implode('.', $parts);
8669
                    $subnet = implode('.', $parts);
9157
                }
8670
                }
9158
                if ($count == 4) {
8671
                if ($count == 4) {
9159
                    $subnet = cleanremoteaddr($subnet, false); // Normalise.
8672
                    $subnet = cleanremoteaddr($subnet, false); // Normalise.
Línea 9162... Línea 8675...
9162
                    }
8675
                    }
9163
                    continue;
8676
                    continue;
9164
                } else if ($count > 4) {
8677
                } else if ($count > 4) {
9165
                    continue;
8678
                    continue;
9166
                }
8679
                }
9167
                $zeros = array_fill(0, 4 - $count, '0');
8680
                $zeros = array_fill(0, 4-$count, '0');
9168
                $subnet = $subnet . '.' . implode('.', $zeros) . '/' . ($count * 8);
8681
                $subnet = $subnet.'.'.implode('.', $zeros).'/'.($count*8);
9169
                if (address_in_subnet($addr, $subnet)) {
8682
                if (address_in_subnet($addr, $subnet)) {
9170
                    return true;
8683
                    return true;
9171
                }
8684
                }
9172
            }
8685
            }
9173
        }
8686
        }
Línea 9182... Línea 8695...
9182
 * @param string $string The string to write
8695
 * @param string $string The string to write
9183
 * @param string $eol The end of line char(s) to use
8696
 * @param string $eol The end of line char(s) to use
9184
 * @param string $sleep Period to make the application sleep
8697
 * @param string $sleep Period to make the application sleep
9185
 *                      This ensures any messages have time to display before redirect
8698
 *                      This ensures any messages have time to display before redirect
9186
 */
8699
 */
9187
function mtrace($string, $eol = "\n", $sleep = 0)
8700
function mtrace($string, $eol="\n", $sleep=0) {
9188
{
-
 
9189
    global $CFG;
8701
    global $CFG;
Línea 9190... Línea 8702...
9190
 
8702
 
9191
    if (isset($CFG->mtrace_wrapper) && function_exists($CFG->mtrace_wrapper)) {
8703
    if (isset($CFG->mtrace_wrapper) && function_exists($CFG->mtrace_wrapper)) {
9192
        $fn = $CFG->mtrace_wrapper;
8704
        $fn = $CFG->mtrace_wrapper;
Línea 9214... Línea 8726...
9214
/**
8726
/**
9215
 * Helper to {@see mtrace()} an exception or throwable, including all relevant information.
8727
 * Helper to {@see mtrace()} an exception or throwable, including all relevant information.
9216
 *
8728
 *
9217
 * @param Throwable $e the error to ouptput.
8729
 * @param Throwable $e the error to ouptput.
9218
 */
8730
 */
9219
function mtrace_exception(Throwable $e): void
8731
function mtrace_exception(Throwable $e): void {
9220
{
-
 
9221
    $info = get_exception_info($e);
8732
    $info = get_exception_info($e);
Línea 9222... Línea 8733...
9222
 
8733
 
9223
    $message = $info->message;
8734
    $message = $info->message;
9224
    if ($info->debuginfo) {
8735
    if ($info->debuginfo) {
Línea 9235... Línea 8746...
9235
 * Replace 1 or more slashes or backslashes to 1 slash
8746
 * Replace 1 or more slashes or backslashes to 1 slash
9236
 *
8747
 *
9237
 * @param string $path The path to strip
8748
 * @param string $path The path to strip
9238
 * @return string the path with double slashes removed
8749
 * @return string the path with double slashes removed
9239
 */
8750
 */
9240
function cleardoubleslashes($path)
8751
function cleardoubleslashes ($path) {
9241
{
-
 
9242
    return preg_replace('/(\/|\\\){1,}/', '/', $path);
8752
    return preg_replace('/(\/|\\\){1,}/', '/', $path);
9243
}
8753
}
Línea 9244... Línea 8754...
9244
 
8754
 
9245
/**
8755
/**
9246
 * Is the current ip in a given list?
8756
 * Is the current ip in a given list?
9247
 *
8757
 *
9248
 * @param string $list
8758
 * @param string $list
9249
 * @return bool
8759
 * @return bool
9250
 */
8760
 */
9251
function remoteip_in_list($list)
-
 
9252
{
8761
function remoteip_in_list($list) {
Línea 9253... Línea 8762...
9253
    $clientip = getremoteaddr(null);
8762
    $clientip = getremoteaddr(null);
9254
 
8763
 
9255
    if (!$clientip) {
8764
    if (!$clientip) {
Línea 9263... Línea 8772...
9263
 * Returns most reliable client address
8772
 * Returns most reliable client address
9264
 *
8773
 *
9265
 * @param string $default If an address can't be determined, then return this
8774
 * @param string $default If an address can't be determined, then return this
9266
 * @return string The remote IP address
8775
 * @return string The remote IP address
9267
 */
8776
 */
9268
function getremoteaddr($default = '0.0.0.0')
8777
function getremoteaddr($default='0.0.0.0') {
9269
{
-
 
9270
    global $CFG;
8778
    global $CFG;
Línea 9271... Línea 8779...
9271
 
8779
 
9272
    if (!isset($CFG->getremoteaddrconf)) {
8780
    if (!isset($CFG->getremoteaddrconf)) {
9273
        // This will happen, for example, before just after the upgrade, as the
8781
        // This will happen, for example, before just after the upgrade, as the
Línea 9284... Línea 8792...
9284
    }
8792
    }
9285
    if (!($variablestoskip & GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR)) {
8793
    if (!($variablestoskip & GETREMOTEADDR_SKIP_HTTP_X_FORWARDED_FOR)) {
9286
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
8794
        if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
9287
            $forwardedaddresses = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);
8795
            $forwardedaddresses = explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']);
Línea 9288... Línea 8796...
9288
 
8796
 
9289
            $forwardedaddresses = array_filter($forwardedaddresses, function ($ip) {
8797
            $forwardedaddresses = array_filter($forwardedaddresses, function($ip) {
9290
                global $CFG;
8798
                global $CFG;
9291
                return !\core\ip_utils::is_ip_in_subnet_list($ip, $CFG->reverseproxyignore ?? '', ',');
8799
                return !\core\ip_utils::is_ip_in_subnet_list($ip, $CFG->reverseproxyignore ?? '', ',');
Línea 9292... Línea 8800...
9292
            });
8800
            });
Línea 9326... Línea 8834...
9326
 *
8834
 *
9327
 * @param string $addr IPv4 or IPv6 address
8835
 * @param string $addr IPv4 or IPv6 address
9328
 * @param bool $compress use IPv6 address compression
8836
 * @param bool $compress use IPv6 address compression
9329
 * @return string normalised ip address string, null if error
8837
 * @return string normalised ip address string, null if error
9330
 */
8838
 */
9331
function cleanremoteaddr($addr, $compress = false)
8839
function cleanremoteaddr($addr, $compress=false) {
9332
{
-
 
9333
    $addr = trim($addr);
8840
    $addr = trim($addr);
Línea 9334... Línea 8841...
9334
 
8841
 
9335
    if (strpos($addr, ':') !== false) {
8842
    if (strpos($addr, ':') !== false) {
9336
        // Can be only IPv6.
8843
        // Can be only IPv6.
9337
        $parts = explode(':', $addr);
8844
        $parts = explode(':', $addr);
Línea 9338... Línea 8845...
9338
        $count = count($parts);
8845
        $count = count($parts);
9339
 
8846
 
9340
        if (strpos($parts[$count - 1], '.') !== false) {
8847
        if (strpos($parts[$count-1], '.') !== false) {
9341
            // Legacy ipv4 notation.
8848
            // Legacy ipv4 notation.
9342
            $last = array_pop($parts);
8849
            $last = array_pop($parts);
9343
            $ipv4 = cleanremoteaddr($last, true);
8850
            $ipv4 = cleanremoteaddr($last, true);
9344
            if ($ipv4 === null) {
8851
            if ($ipv4 === null) {
9345
                return null;
8852
                return null;
9346
            }
8853
            }
9347
            $bits = explode('.', $ipv4);
8854
            $bits = explode('.', $ipv4);
9348
            $parts[] = dechex($bits[0]) . dechex($bits[1]);
8855
            $parts[] = dechex($bits[0]).dechex($bits[1]);
9349
            $parts[] = dechex($bits[2]) . dechex($bits[3]);
8856
            $parts[] = dechex($bits[2]).dechex($bits[3]);
9350
            $count = count($parts);
8857
            $count = count($parts);
Línea 9351... Línea 8858...
9351
            $addr = implode(':', $parts);
8858
            $addr = implode(':', $parts);
Línea 9429... Línea 8936...
9429
 * Is IP address a public address?
8936
 * Is IP address a public address?
9430
 *
8937
 *
9431
 * @param string $ip The ip to check
8938
 * @param string $ip The ip to check
9432
 * @return bool true if the ip is public
8939
 * @return bool true if the ip is public
9433
 */
8940
 */
9434
function ip_is_public($ip)
8941
function ip_is_public($ip) {
9435
{
-
 
9436
    return (bool) filter_var($ip, FILTER_VALIDATE_IP, (FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE));
8942
    return (bool) filter_var($ip, FILTER_VALIDATE_IP, (FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE));
9437
}
8943
}
Línea 9438... Línea 8944...
9438
 
8944
 
9439
/**
8945
/**
9440
 * This function will make a complete copy of anything it's given,
8946
 * This function will make a complete copy of anything it's given,
9441
 * regardless of whether it's an object or not.
8947
 * regardless of whether it's an object or not.
9442
 *
8948
 *
9443
 * @param mixed $thing Something you want cloned
8949
 * @param mixed $thing Something you want cloned
9444
 * @return mixed What ever it is you passed it
8950
 * @return mixed What ever it is you passed it
9445
 */
8951
 */
9446
function fullclone($thing)
-
 
9447
{
8952
function fullclone($thing) {
9448
    return unserialize(serialize($thing));
8953
    return unserialize(serialize($thing));
Línea 9449... Línea 8954...
9449
}
8954
}
9450
 
8955
 
Línea 9456... Línea 8961...
9456
 * @param int $min The minimum value
8961
 * @param int $min The minimum value
9457
 * @param int $value The value to check
8962
 * @param int $value The value to check
9458
 * @param int $max The maximum value
8963
 * @param int $max The maximum value
9459
 * @return int
8964
 * @return int
9460
 */
8965
 */
9461
function bounded_number($min, $value, $max)
8966
function bounded_number($min, $value, $max) {
9462
{
-
 
9463
    if ($value < $min) {
8967
    if ($value < $min) {
9464
        return $min;
8968
        return $min;
9465
    }
8969
    }
9466
    if ($value > $max) {
8970
    if ($value > $max) {
9467
        return $max;
8971
        return $max;
Línea 9473... Línea 8977...
9473
 * Check if there is a nested array within the passed array
8977
 * Check if there is a nested array within the passed array
9474
 *
8978
 *
9475
 * @param array $array
8979
 * @param array $array
9476
 * @return bool true if there is a nested array false otherwise
8980
 * @return bool true if there is a nested array false otherwise
9477
 */
8981
 */
9478
function array_is_nested($array)
8982
function array_is_nested($array) {
9479
{
-
 
9480
    foreach ($array as $value) {
8983
    foreach ($array as $value) {
9481
        if (is_array($value)) {
8984
        if (is_array($value)) {
9482
            return true;
8985
            return true;
9483
        }
8986
        }
9484
    }
8987
    }
Línea 9491... Línea 8994...
9491
 * values ready for use, and each of the individual stats provided
8994
 * values ready for use, and each of the individual stats provided
9492
 * separately as well.
8995
 * separately as well.
9493
 *
8996
 *
9494
 * @return array
8997
 * @return array
9495
 */
8998
 */
9496
function get_performance_info()
8999
function get_performance_info() {
9497
{
-
 
9498
    global $CFG, $PERF, $DB, $PAGE;
9000
    global $CFG, $PERF, $DB, $PAGE;
Línea 9499... Línea 9001...
9499
 
9001
 
9500
    $info = array();
9002
    $info = array();
Línea 9507... Línea 9009...
9507
    }
9009
    }
9508
    $info['html'] .= '<ul class="list-unstyled row mx-md-0">';         // Holds userfriendly HTML representation.
9010
    $info['html'] .= '<ul class="list-unstyled row mx-md-0">';         // Holds userfriendly HTML representation.
Línea 9509... Línea 9011...
9509
 
9011
 
Línea 9510... Línea 9012...
9510
    $info['realtime'] = microtime_diff($PERF->starttime, microtime());
9012
    $info['realtime'] = microtime_diff($PERF->starttime, microtime());
9511
 
9013
 
Línea 9512... Línea 9014...
9512
    $info['html'] .= '<li class="timeused col-sm-4">' . $info['realtime'] . ' secs</li> ';
9014
    $info['html'] .= '<li class="timeused col-sm-4">'.$info['realtime'].' secs</li> ';
9513
    $info['txt'] .= 'time: ' . $info['realtime'] . 's ';
9015
    $info['txt'] .= 'time: '.$info['realtime'].'s ';
Línea 9514... Línea 9016...
9514
 
9016
 
9515
    // GET/POST (or NULL if $_SERVER['REQUEST_METHOD'] is undefined) is useful for txt logged information.
9017
    // GET/POST (or NULL if $_SERVER['REQUEST_METHOD'] is undefined) is useful for txt logged information.
9516
    $info['txt'] .= 'method: ' . ($_SERVER['REQUEST_METHOD'] ?? "NULL") . ' ';
9018
    $info['txt'] .= 'method: ' . ($_SERVER['REQUEST_METHOD'] ?? "NULL") . ' ';
9517
 
9019
 
9518
    if (function_exists('memory_get_usage')) {
9020
    if (function_exists('memory_get_usage')) {
9519
        $info['memory_total'] = memory_get_usage();
9021
        $info['memory_total'] = memory_get_usage();
9520
        $info['memory_growth'] = memory_get_usage() - $PERF->startmemory;
9022
        $info['memory_growth'] = memory_get_usage() - $PERF->startmemory;
Línea 9521... Línea 9023...
9521
        $info['html'] .= '<li class="memoryused col-sm-4">RAM: ' . display_size($info['memory_total']) . '</li> ';
9023
        $info['html'] .= '<li class="memoryused col-sm-4">RAM: '.display_size($info['memory_total']).'</li> ';
9522
        $info['txt']  .= 'memory_total: ' . $info['memory_total'] . 'B (' . display_size($info['memory_total']) . ') memory_growth: ' .
9024
        $info['txt']  .= 'memory_total: '.$info['memory_total'].'B (' . display_size($info['memory_total']).') memory_growth: '.
9523
            $info['memory_growth'] . 'B (' . display_size($info['memory_growth']) . ') ';
9025
            $info['memory_growth'].'B ('.display_size($info['memory_growth']).') ';
9524
    }
9026
    }
9525
 
9027
 
Línea 9526... Línea 9028...
9526
    if (function_exists('memory_get_peak_usage')) {
9028
    if (function_exists('memory_get_peak_usage')) {
9527
        $info['memory_peak'] = memory_get_peak_usage();
9029
        $info['memory_peak'] = memory_get_peak_usage();
9528
        $info['html'] .= '<li class="memoryused col-sm-4">RAM peak: ' . display_size($info['memory_peak']) . '</li> ';
9030
        $info['html'] .= '<li class="memoryused col-sm-4">RAM peak: '.display_size($info['memory_peak']).'</li> ';
9529
        $info['txt']  .= 'memory_peak: ' . $info['memory_peak'] . 'B (' . display_size($info['memory_peak']) . ') ';
9031
        $info['txt']  .= 'memory_peak: '.$info['memory_peak'].'B (' . display_size($info['memory_peak']).') ';
9530
    }
9032
    }
Línea 9531... Línea 9033...
9531
 
9033
 
9532
    $info['html'] .= '</ul><ul class="list-unstyled row mx-md-0">';
9034
    $info['html'] .= '</ul><ul class="list-unstyled row mx-md-0">';
9533
    $inc = get_included_files();
9035
    $inc = get_included_files();
9534
    $info['includecount'] = count($inc);
9036
    $info['includecount'] = count($inc);
Línea 9558... Línea 9060...
9558
            $info['html'] .= "<li class='$key col-sm-4'>$nicenames[$key]: $value </li> ";
9060
            $info['html'] .= "<li class='$key col-sm-4'>$nicenames[$key]: $value </li> ";
9559
            $info['txt'] .= "$key: $value ";
9061
            $info['txt'] .= "$key: $value ";
9560
        }
9062
        }
9561
    }
9063
    }
Línea 9562... Línea 9064...
9562
 
9064
 
9563
    $info['dbqueries'] = $DB->perf_get_reads() . '/' . $DB->perf_get_writes();
9065
    $info['dbqueries'] = $DB->perf_get_reads().'/'.$DB->perf_get_writes();
9564
    $info['html'] .= '<li class="dbqueries col-sm-4">DB reads/writes: ' . $info['dbqueries'] . '</li> ';
9066
    $info['html'] .= '<li class="dbqueries col-sm-4">DB reads/writes: '.$info['dbqueries'].'</li> ';
9565
    $info['txt'] .= 'db reads/writes: ' . $info['dbqueries'] . ' ';
9067
    $info['txt'] .= 'db reads/writes: '.$info['dbqueries'].' ';
9566
 
9068
 
9567
    if ($DB->want_read_slave()) {
9069
    if ($DB->want_read_replica()) {
9568
        $info['dbreads_slave'] = $DB->perf_get_reads_slave();
9070
        $info['dbreads_replica'] = $DB->perf_get_reads_replica();
9569
        $info['html'] .= '<li class="dbqueries col-sm-4">DB reads from slave: ' . $info['dbreads_slave'] . '</li> ';
9071
        $info['html'] .= '<li class="dbqueries col-sm-4">DB reads from replica: '.$info['dbreads_replica'].'</li> ';
9570
        $info['txt'] .= 'db reads from slave: ' . $info['dbreads_slave'] . ' ';
9072
        $info['txt'] .= 'db reads from replica: '.$info['dbreads_replica'].' ';
Línea 9571... Línea 9073...
9571
    }
9073
    }
9572
 
9074
 
9573
    $info['dbtime'] = round($DB->perf_get_queries_time(), 5);
9075
    $info['dbtime'] = round($DB->perf_get_queries_time(), 5);
Línea 9574... Línea 9076...
9574
    $info['html'] .= '<li class="dbtime col-sm-4">DB queries time: ' . $info['dbtime'] . ' secs</li> ';
9076
    $info['html'] .= '<li class="dbtime col-sm-4">DB queries time: '.$info['dbtime'].' secs</li> ';
9575
    $info['txt'] .= 'db queries time: ' . $info['dbtime'] . 's ';
9077
    $info['txt'] .= 'db queries time: ' . $info['dbtime'] . 's ';
9576
 
9078
 
Línea 9590... Línea 9092...
9590
    // /proc will only work under some linux configurations
9092
    // /proc will only work under some linux configurations
9591
    // while uptime is there under MacOSX/Darwin and other unices.
9093
    // while uptime is there under MacOSX/Darwin and other unices.
9592
    if (is_readable('/proc/loadavg') && $loadavg = @file('/proc/loadavg')) {
9094
    if (is_readable('/proc/loadavg') && $loadavg = @file('/proc/loadavg')) {
9593
        list($serverload) = explode(' ', $loadavg[0]);
9095
        list($serverload) = explode(' ', $loadavg[0]);
9594
        unset($loadavg);
9096
        unset($loadavg);
9595
    } else if (function_exists('is_executable') && is_executable('/usr/bin/uptime') && $loadavg = `/usr/bin/uptime`) {
9097
    } else if ( function_exists('is_executable') && is_executable('/usr/bin/uptime') && $loadavg = `/usr/bin/uptime` ) {
9596
        if (preg_match('/load averages?: (\d+[\.,:]\d+)/', $loadavg, $matches)) {
9098
        if (preg_match('/load averages?: (\d+[\.,:]\d+)/', $loadavg, $matches)) {
9597
            $serverload = $matches[1];
9099
            $serverload = $matches[1];
9598
        } else {
9100
        } else {
9599
            trigger_error('Could not parse uptime output!');
9101
            trigger_error('Could not parse uptime output!');
9600
        }
9102
        }
9601
    }
9103
    }
9602
    if (!empty($serverload)) {
9104
    if (!empty($serverload)) {
9603
        $info['serverload'] = $serverload;
9105
        $info['serverload'] = $serverload;
9604
        $info['html'] .= '<li class="serverload col-sm-4">Load average: ' . $info['serverload'] . '</li> ';
9106
        $info['html'] .= '<li class="serverload col-sm-4">Load average: '.$info['serverload'].'</li> ';
9605
        $info['txt'] .= "serverload: {$info['serverload']} ";
9107
        $info['txt'] .= "serverload: {$info['serverload']} ";
9606
    }
9108
    }
Línea 9607... Línea 9109...
9607
 
9109
 
9608
    // Display size of session if session started.
9110
    // Display size of session if session started.
Línea 9844... Línea 9346...
9844
 
9346
 
Línea 9845... Línea 9347...
9845
        $html .= html_writer::table($table);
9347
        $html .= html_writer::table($table);
9846
 
9348
 
9847
        $info['cachesused'] = "$hits / $misses / $sets";
9349
        $info['cachesused'] = "$hits / $misses / $sets";
9848
        $info['html'] .= $html;
9350
        $info['html'] .= $html;
9849
        $info['txt'] .= $text . '. ';
9351
        $info['txt'] .= $text.'. ';
9850
    } else {
9352
    } else {
9851
        $info['cachesused'] = '0 / 0 / 0';
9353
        $info['cachesused'] = '0 / 0 / 0';
9852
        $info['html'] .= '<div class="cachesused">Caches used (hits/misses/sets): 0/0/0</div>';
9354
        $info['html'] .= '<div class="cachesused">Caches used (hits/misses/sets): 0/0/0</div>';
Línea 9898... Línea 9400...
9898
        }
9400
        }
9899
        $info['html'] .= html_writer::table($table);
9401
        $info['html'] .= html_writer::table($table);
9900
        $info['txt'] .= $text . '. ';
9402
        $info['txt'] .= $text . '. ';
9901
    }
9403
    }
Línea 9902... Línea 9404...
9902
 
9404
 
9903
    $info['html'] = '<div class="performanceinfo siteinfo container-fluid px-md-0 overflow-auto pt-3">' . $info['html'] . '</div>';
9405
    $info['html'] = '<div class="performanceinfo siteinfo container-fluid px-md-0 overflow-auto pt-3">'.$info['html'].'</div>';
9904
    return $info;
9406
    return $info;
Línea 9905... Línea 9407...
9905
}
9407
}
9906
 
9408
 
Línea 9912... Línea 9414...
9912
 * @param string $filepath Original filepath
9414
 * @param string $filepath Original filepath
9913
 * @param string $prefix Prefix to use for the temporary name
9415
 * @param string $prefix Prefix to use for the temporary name
9914
 * @return string|bool New file path or false if failed
9416
 * @return string|bool New file path or false if failed
9915
 * @since Moodle 3.10
9417
 * @since Moodle 3.10
9916
 */
9418
 */
9917
function rename_to_unused_name(string $filepath, string $prefix = '_temp_')
9419
function rename_to_unused_name(string $filepath, string $prefix = '_temp_') {
9918
{
-
 
9919
    $dir = dirname($filepath);
9420
    $dir = dirname($filepath);
9920
    $basename = $dir . '/' . $prefix;
9421
    $basename = $dir . '/' . $prefix;
9921
    $limit = 0;
9422
    $limit = 0;
9922
    while ($limit < 100) {
9423
    while ($limit < 100) {
9923
        // Select a new name based on a random number.
9424
        // Select a new name based on a random number.
Línea 9943... Línea 9444...
9943
 *
9444
 *
9944
 * @param string $dir directory path
9445
 * @param string $dir directory path
9945
 * @param bool $contentonly
9446
 * @param bool $contentonly
9946
 * @return bool success, true also if dir does not exist
9447
 * @return bool success, true also if dir does not exist
9947
 */
9448
 */
9948
function remove_dir($dir, $contentonly = false)
9449
function remove_dir($dir, $contentonly=false) {
9949
{
-
 
9950
    if (!is_dir($dir)) {
9450
    if (!is_dir($dir)) {
9951
        // Nothing to do.
9451
        // Nothing to do.
9952
        return true;
9452
        return true;
9953
    }
9453
    }
Línea 9966... Línea 9466...
9966
 
9466
 
9967
    if (!$handle = opendir($dir)) {
9467
    if (!$handle = opendir($dir)) {
9968
        return false;
9468
        return false;
9969
    }
9469
    }
9970
    $result = true;
9470
    $result = true;
9971
    while (false !== ($item = readdir($handle))) {
9471
    while (false!==($item = readdir($handle))) {
9972
        if ($item != '.' && $item != '..') {
9472
        if ($item != '.' && $item != '..') {
9973
            if (is_dir($dir . '/' . $item)) {
9473
            if (is_dir($dir.'/'.$item)) {
9974
                $result = remove_dir($dir . '/' . $item) && $result;
9474
                $result = remove_dir($dir.'/'.$item) && $result;
9975
            } else {
9475
            } else {
9976
                $result = unlink($dir . '/' . $item) && $result;
9476
                $result = unlink($dir.'/'.$item) && $result;
9977
            }
9477
            }
9978
        }
9478
        }
9979
    }
9479
    }
9980
    closedir($handle);
9480
    closedir($handle);
Línea 9993... Línea 9493...
9993
 *
9493
 *
9994
 * @param mixed $obj Name of class or real object to test
9494
 * @param mixed $obj Name of class or real object to test
9995
 * @param string $property name of property to find
9495
 * @param string $property name of property to find
9996
 * @return bool true if property exists
9496
 * @return bool true if property exists
9997
 */
9497
 */
9998
function object_property_exists($obj, $property)
9498
function object_property_exists( $obj, $property ) {
9999
{
-
 
10000
    if (is_string($obj)) {
9499
    if (is_string( $obj )) {
10001
        $properties = get_class_vars($obj);
9500
        $properties = get_class_vars( $obj );
10002
    } else {
9501
    } else {
10003
        $properties = get_object_vars($obj);
9502
        $properties = get_object_vars( $obj );
10004
    }
9503
    }
10005
    return array_key_exists($property, $properties);
9504
    return array_key_exists( $property, $properties );
10006
}
9505
}
Línea 10007... Línea 9506...
10007
 
9506
 
10008
/**
9507
/**
10009
 * Converts an object into an associative array
9508
 * Converts an object into an associative array
Línea 10017... Línea 9516...
10017
 * and return all available properties in getIterator()
9516
 * and return all available properties in getIterator()
10018
 *
9517
 *
10019
 * @param mixed $var
9518
 * @param mixed $var
10020
 * @return array
9519
 * @return array
10021
 */
9520
 */
10022
function convert_to_array($var)
9521
function convert_to_array($var) {
10023
{
-
 
10024
    $result = array();
9522
    $result = array();
Línea 10025... Línea 9523...
10025
 
9523
 
10026
    // Loop over elements/properties.
9524
    // Loop over elements/properties.
10027
    foreach ($var as $key => $value) {
9525
    foreach ($var as $key => $value) {
Línea 10040... Línea 9538...
10040
 * Detect a custom script replacement in the data directory that will
9538
 * Detect a custom script replacement in the data directory that will
10041
 * replace an existing moodle script
9539
 * replace an existing moodle script
10042
 *
9540
 *
10043
 * @return string|bool full path name if a custom script exists, false if no custom script exists
9541
 * @return string|bool full path name if a custom script exists, false if no custom script exists
10044
 */
9542
 */
10045
function custom_script_path()
9543
function custom_script_path() {
10046
{
-
 
10047
    global $CFG, $SCRIPT;
9544
    global $CFG, $SCRIPT;
Línea 10048... Línea 9545...
10048
 
9545
 
10049
    if ($SCRIPT === null) {
9546
    if ($SCRIPT === null) {
10050
        // Probably some weird external script.
9547
        // Probably some weird external script.
Línea 10066... Línea 9563...
10066
 * is in moodlelib because it does not rely on loading any of the MNET code.
9563
 * is in moodlelib because it does not rely on loading any of the MNET code.
10067
 *
9564
 *
10068
 * @param object $user A valid user object
9565
 * @param object $user A valid user object
10069
 * @return bool        True if the user is from a remote Moodle.
9566
 * @return bool        True if the user is from a remote Moodle.
10070
 */
9567
 */
10071
function is_mnet_remote_user($user)
9568
function is_mnet_remote_user($user) {
10072
{
-
 
10073
    global $CFG;
9569
    global $CFG;
Línea 10074... Línea 9570...
10074
 
9570
 
10075
    if (!isset($CFG->mnet_localhost_id)) {
9571
    if (!isset($CFG->mnet_localhost_id)) {
10076
        include_once($CFG->dirroot . '/mnet/lib.php');
9572
        include_once($CFG->dirroot . '/mnet/lib.php');
Línea 10084... Línea 9580...
10084
 
9580
 
10085
/**
9581
/**
10086
 * This function will search for browser prefereed languages, setting Moodle
9582
 * This function will search for browser prefereed languages, setting Moodle
10087
 * to use the best one available if $SESSION->lang is undefined
9583
 * to use the best one available if $SESSION->lang is undefined
10088
 */
9584
 */
10089
function setup_lang_from_browser()
-
 
10090
{
9585
function setup_lang_from_browser() {
Línea 10091... Línea 9586...
10091
    global $CFG, $SESSION, $USER;
9586
    global $CFG, $SESSION, $USER;
10092
 
9587
 
10093
    if (!empty($SESSION->lang) or !empty($USER->lang) or empty($CFG->autolang)) {
9588
    if (!empty($SESSION->lang) or !empty($USER->lang) or empty($CFG->autolang)) {
Línea 10107... Línea 9602...
10107
 
9602
 
10108
    $order = 1.0;
9603
    $order = 1.0;
10109
    foreach ($rawlangs as $lang) {
9604
    foreach ($rawlangs as $lang) {
10110
        if (strpos($lang, ';') === false) {
9605
        if (strpos($lang, ';') === false) {
10111
            $langs[(string)$order] = $lang;
9606
            $langs[(string)$order] = $lang;
10112
            $order = $order - 0.01;
9607
            $order = $order-0.01;
10113
        } else {
9608
        } else {
10114
            $parts = explode(';', $lang);
9609
            $parts = explode(';', $lang);
10115
            $pos = strpos($parts[1], '=');
9610
            $pos = strpos($parts[1], '=');
10116
            $langs[substr($parts[1], $pos + 1)] = $parts[0];
9611
            $langs[substr($parts[1], $pos+1)] = $parts[0];
10117
        }
9612
        }
10118
    }
9613
    }
Línea 10119... Línea 9614...
10119
    krsort($langs, SORT_NUMERIC);
9614
    krsort($langs, SORT_NUMERIC);
Línea 10144... Línea 9639...
10144
 * Any errors just result in the proxy being used (least bad)
9639
 * Any errors just result in the proxy being used (least bad)
10145
 *
9640
 *
10146
 * @param string $url url to check
9641
 * @param string $url url to check
10147
 * @return boolean true if we should bypass the proxy
9642
 * @return boolean true if we should bypass the proxy
10148
 */
9643
 */
10149
function is_proxybypass($url)
9644
function is_proxybypass( $url ) {
10150
{
-
 
10151
    global $CFG;
9645
    global $CFG;
Línea 10152... Línea 9646...
10152
 
9646
 
10153
    // Sanity check.
9647
    // Sanity check.
10154
    if (empty($CFG->proxyhost) or empty($CFG->proxybypass)) {
9648
    if (empty($CFG->proxyhost) or empty($CFG->proxybypass)) {
10155
        return false;
9649
        return false;
Línea 10156... Línea 9650...
10156
    }
9650
    }
10157
 
9651
 
10158
    // Get the host part out of the url.
9652
    // Get the host part out of the url.
10159
    if (!$host = parse_url($url, PHP_URL_HOST)) {
9653
    if (!$host = parse_url( $url, PHP_URL_HOST )) {
Línea 10160... Línea 9654...
10160
        return false;
9654
        return false;
10161
    }
9655
    }
Línea 10162... Línea 9656...
10162
 
9656
 
10163
    // Get the possible bypass hosts into an array.
9657
    // Get the possible bypass hosts into an array.
10164
    $matches = explode(',', $CFG->proxybypass);
9658
    $matches = explode( ',', $CFG->proxybypass );
Línea 10179... Línea 9673...
10179
 * Check if the passed navigation is of the new style
9673
 * Check if the passed navigation is of the new style
10180
 *
9674
 *
10181
 * @param mixed $navigation
9675
 * @param mixed $navigation
10182
 * @return bool true for yes false for no
9676
 * @return bool true for yes false for no
10183
 */
9677
 */
10184
function is_newnav($navigation)
9678
function is_newnav($navigation) {
10185
{
-
 
10186
    if (is_array($navigation) && !empty($navigation['newnav'])) {
9679
    if (is_array($navigation) && !empty($navigation['newnav'])) {
10187
        return true;
9680
        return true;
10188
    } else {
9681
    } else {
10189
        return false;
9682
        return false;
10190
    }
9683
    }
Línea 10197... Línea 9690...
10197
 *
9690
 *
10198
 * @param string $var The variable name
9691
 * @param string $var The variable name
10199
 * @param object $object The object to check
9692
 * @param object $object The object to check
10200
 * @return boolean
9693
 * @return boolean
10201
 */
9694
 */
10202
function in_object_vars($var, $object)
9695
function in_object_vars($var, $object) {
10203
{
-
 
10204
    $classvars = get_class_vars(get_class($object));
9696
    $classvars = get_class_vars(get_class($object));
10205
    $classvars = array_keys($classvars);
9697
    $classvars = array_keys($classvars);
10206
    return in_array($var, $classvars);
9698
    return in_array($var, $classvars);
10207
}
9699
}
Línea 10212... Línea 9704...
10212
 *
9704
 *
10213
 * @param array $array
9705
 * @param array $array
10214
 * @param bool $keepkeyassoc
9706
 * @param bool $keepkeyassoc
10215
 * @return array
9707
 * @return array
10216
 */
9708
 */
10217
function object_array_unique($array, $keepkeyassoc = true)
9709
function object_array_unique($array, $keepkeyassoc = true) {
10218
{
-
 
10219
    $duplicatekeys = array();
9710
    $duplicatekeys = array();
10220
    $tmp         = array();
9711
    $tmp         = array();
Línea 10221... Línea 9712...
10221
 
9712
 
10222
    foreach ($array as $key => $val) {
9713
    foreach ($array as $key => $val) {
Línea 10243... Línea 9734...
10243
 * Is a userid the primary administrator?
9734
 * Is a userid the primary administrator?
10244
 *
9735
 *
10245
 * @param int $userid int id of user to check
9736
 * @param int $userid int id of user to check
10246
 * @return boolean
9737
 * @return boolean
10247
 */
9738
 */
10248
function is_primary_admin($userid)
9739
function is_primary_admin($userid) {
10249
{
-
 
10250
    $primaryadmin =  get_admin();
9740
    $primaryadmin =  get_admin();
Línea 10251... Línea 9741...
10251
 
9741
 
10252
    if ($userid == $primaryadmin->id) {
9742
    if ($userid == $primaryadmin->id) {
10253
        return true;
9743
        return true;
Línea 10259... Línea 9749...
10259
/**
9749
/**
10260
 * Returns the site identifier
9750
 * Returns the site identifier
10261
 *
9751
 *
10262
 * @return string $CFG->siteidentifier, first making sure it is properly initialised.
9752
 * @return string $CFG->siteidentifier, first making sure it is properly initialised.
10263
 */
9753
 */
10264
function get_site_identifier()
9754
function get_site_identifier() {
10265
{
-
 
10266
    global $CFG;
9755
    global $CFG;
10267
    // Check to see if it is missing. If so, initialise it.
9756
    // Check to see if it is missing. If so, initialise it.
10268
    if (empty($CFG->siteidentifier)) {
9757
    if (empty($CFG->siteidentifier)) {
10269
        set_config('siteidentifier', random_string(32) . $_SERVER['HTTP_HOST']);
9758
        set_config('siteidentifier', random_string(32) . $_SERVER['HTTP_HOST']);
10270
    }
9759
    }
Línea 10278... Línea 9767...
10278
 *
9767
 *
10279
 * @param string $password   password to be checked against the password policy
9768
 * @param string $password   password to be checked against the password policy
10280
 * @param integer $maxchars  maximum number of consecutive identical characters
9769
 * @param integer $maxchars  maximum number of consecutive identical characters
10281
 * @return bool
9770
 * @return bool
10282
 */
9771
 */
10283
function check_consecutive_identical_characters($password, $maxchars)
9772
function check_consecutive_identical_characters($password, $maxchars) {
10284
{
-
 
Línea 10285... Línea 9773...
10285
 
9773
 
10286
    if ($maxchars < 1) {
9774
    if ($maxchars < 1) {
10287
        return true; // Zero 0 is to disable this check.
9775
        return true; // Zero 0 is to disable this check.
10288
    }
9776
    }
Línea 10308... Línea 9796...
10308
    return true;
9796
    return true;
10309
}
9797
}
Línea 10310... Línea 9798...
10310
 
9798
 
10311
/**
9799
/**
-
 
9800
 * Helper function to do partial function binding.
10312
 * Helper function to do partial function binding.
9801
 *
-
 
9802
 * This is useful for cases such as preg_replace_callback where you may want to partially bind values.
10313
 * so we can use it for preg_replace_callback, for example
9803
 *
10314
 * this works with php functions, user functions, static methods and class methods
9804
 * The use of named arguments is recommended for clarity.
10315
 * it returns you a callback that you can pass on like so:
9805
 * Please note that providing arguments in a different order may have mixed results for built-in functions.
10316
 *
9806
 *
10317
 * $callback = partial('somefunction', $arg1, $arg2);
9807
 * $callback = partial('somefunction', $arg1, $arg2);
10318
 *     or
9808
 *     or
10319
 * $callback = partial(array('someclass', 'somestaticmethod'), $arg1, $arg2);
9809
 * $callback = partial(array('someclass', 'somestaticmethod'), $arg1, $arg2);
10320
 *     or even
9810
 *     or even
10321
 * $obj = new someclass();
9811
 * $obj = new someclass();
10322
 * $callback = partial(array($obj, 'somemethod'), $arg1, $arg2);
9812
 * $callback = partial(array($obj, 'somemethod'), $arg1, $arg2);
10323
 *
9813
 *
10324
 * and then the arguments that are passed through at calltime are appended to the argument list.
9814
 * and then the arguments that are passed through at calltime are appended to the argument list.
10325
 *
9815
 *
10326
 * @param mixed $function a php callback
9816
 * @param callable $function a php callback
10327
 * @param mixed $arg1,... $argv arguments to partially bind with
9817
 * @param mixed ...$initialargs The arguments to provide for the initial bind
10328
 * @return array Array callback
9818
 * @return callable
10329
 */
-
 
10330
function partial()
-
 
10331
{
-
 
10332
    if (!class_exists('partial')) {
-
 
10333
        /**
-
 
10334
         * Used to manage function binding.
-
 
10335
         * @copyright  2009 Penny Leach
-
 
10336
         * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
-
 
10337
         */
-
 
10338
        class partial
-
 
10339
        {
-
 
10340
            /** @var array */
-
 
10341
            public $values = array();
9819
 */
10342
            /** @var string The function to call as a callback. */
-
 
10343
            public $func;
-
 
10344
            /**
-
 
10345
             * Constructor
-
 
10346
             * @param string $func
-
 
10347
             * @param array $args
-
 
10348
             */
9820
function partial(callable $callable, ...$initialargs): callable {
10349
            public function __construct($func, $args)
-
 
10350
            {
-
 
10351
                $this->values = $args;
-
 
10352
                $this->func = $func;
-
 
10353
            }
-
 
10354
            /**
-
 
10355
             * Calls the callback function.
-
 
10356
             * @return mixed
-
 
10357
             */
-
 
10358
            public function method()
-
 
10359
            {
-
 
10360
                $args = func_get_args();
-
 
10361
                return call_user_func_array($this->func, array_merge($this->values, $args));
-
 
10362
            }
-
 
10363
        }
-
 
10364
    }
-
 
10365
    $args = func_get_args();
-
 
10366
    $func = array_shift($args);
-
 
10367
    $p = new partial($func, $args);
-
 
10368
    return array($p, 'method');
9821
    return fn (...$args) => $callable(...$initialargs, ...$args);
Línea 10369... Línea 9822...
10369
}
9822
}
10370
 
9823
 
10371
/**
9824
/**
10372
 * helper function to load up and initialise the mnet environment
9825
 * helper function to load up and initialise the mnet environment
10373
 * this must be called before you use mnet functions.
9826
 * this must be called before you use mnet functions.
10374
 *
9827
 *
10375
 * @return mnet_environment the equivalent of old $MNET global
9828
 * @return mnet_environment the equivalent of old $MNET global
10376
 */
-
 
10377
function get_mnet_environment()
9829
 */
10378
{
9830
function get_mnet_environment() {
10379
    global $CFG;
9831
    global $CFG;
10380
    require_once($CFG->dirroot . '/mnet/lib.php');
9832
    require_once($CFG->dirroot . '/mnet/lib.php');
10381
    static $instance = null;
9833
    static $instance = null;
Línea 10390... Línea 9842...
10390
 * during xmlrpc server code execution, any code wishing to access
9842
 * during xmlrpc server code execution, any code wishing to access
10391
 * information about the remote peer must use this to get it.
9843
 * information about the remote peer must use this to get it.
10392
 *
9844
 *
10393
 * @return mnet_remote_client|false the equivalent of old $MNETREMOTE_CLIENT global
9845
 * @return mnet_remote_client|false the equivalent of old $MNETREMOTE_CLIENT global
10394
 */
9846
 */
10395
function get_mnet_remote_client()
9847
function get_mnet_remote_client() {
10396
{
-
 
10397
    if (!defined('MNET_SERVER')) {
9848
    if (!defined('MNET_SERVER')) {
10398
        debugging(get_string('notinxmlrpcserver', 'mnet'));
9849
        debugging(get_string('notinxmlrpcserver', 'mnet'));
10399
        return false;
9850
        return false;
10400
    }
9851
    }
10401
    global $MNET_REMOTE_CLIENT;
9852
    global $MNET_REMOTE_CLIENT;
Línea 10410... Línea 9861...
10410
 * to setup the object returned by {@link get_mnet_remote_client}
9861
 * to setup the object returned by {@link get_mnet_remote_client}
10411
 *
9862
 *
10412
 * @param mnet_remote_client $client the client to set up
9863
 * @param mnet_remote_client $client the client to set up
10413
 * @throws moodle_exception
9864
 * @throws moodle_exception
10414
 */
9865
 */
10415
function set_mnet_remote_client($client)
9866
function set_mnet_remote_client($client) {
10416
{
-
 
10417
    if (!defined('MNET_SERVER')) {
9867
    if (!defined('MNET_SERVER')) {
10418
        throw new moodle_exception('notinxmlrpcserver', 'mnet');
9868
        throw new moodle_exception('notinxmlrpcserver', 'mnet');
10419
    }
9869
    }
10420
    global $MNET_REMOTE_CLIENT;
9870
    global $MNET_REMOTE_CLIENT;
10421
    $MNET_REMOTE_CLIENT = $client;
9871
    $MNET_REMOTE_CLIENT = $client;
Línea 10425... Línea 9875...
10425
 * return the jump url for a given remote user
9875
 * return the jump url for a given remote user
10426
 * this is used for rewriting forum post links in emails, etc
9876
 * this is used for rewriting forum post links in emails, etc
10427
 *
9877
 *
10428
 * @param stdclass $user the user to get the idp url for
9878
 * @param stdclass $user the user to get the idp url for
10429
 */
9879
 */
10430
function mnet_get_idp_jump_url($user)
9880
function mnet_get_idp_jump_url($user) {
10431
{
-
 
10432
    global $CFG;
9881
    global $CFG;
Línea 10433... Línea 9882...
10433
 
9882
 
10434
    static $mnetjumps = array();
9883
    static $mnetjumps = array();
10435
    if (!array_key_exists($user->mnethostid, $mnetjumps)) {
9884
    if (!array_key_exists($user->mnethostid, $mnetjumps)) {
Línea 10443... Línea 9892...
10443
/**
9892
/**
10444
 * Gets the homepage to use for the current user
9893
 * Gets the homepage to use for the current user
10445
 *
9894
 *
10446
 * @return int One of HOMEPAGE_*
9895
 * @return int One of HOMEPAGE_*
10447
 */
9896
 */
10448
function get_home_page()
9897
function get_home_page() {
10449
{
-
 
10450
    global $CFG;
9898
    global $CFG;
Línea 10451... Línea 9899...
10451
 
9899
 
10452
    if (isloggedin() && !isguestuser() && !empty($CFG->defaulthomepage)) {
9900
    if (isloggedin() && !empty($CFG->defaulthomepage)) {
10453
        // If dashboard is disabled, home will be set to default page.
9901
        // If dashboard is disabled, home will be set to default page.
10454
        $defaultpage = get_default_home_page();
9902
        $defaultpage = get_default_home_page();
10455
        if ($CFG->defaulthomepage == HOMEPAGE_MY) {
9903
        if ($CFG->defaulthomepage == HOMEPAGE_MY && (!isguestuser() || !empty($CFG->allowguestmymoodle))) {
10456
            if (!empty($CFG->enabledashboard)) {
9904
            if (!empty($CFG->enabledashboard)) {
10457
                return HOMEPAGE_MY;
9905
                return HOMEPAGE_MY;
10458
            } else {
9906
            } else {
10459
                return $defaultpage;
9907
                return $defaultpage;
10460
            }
9908
            }
10461
        } else if ($CFG->defaulthomepage == HOMEPAGE_MYCOURSES) {
9909
        } else if ($CFG->defaulthomepage == HOMEPAGE_MYCOURSES && !isguestuser()) {
10462
            return HOMEPAGE_MYCOURSES;
9910
            return HOMEPAGE_MYCOURSES;
10463
        } else {
9911
        } else if ($CFG->defaulthomepage == HOMEPAGE_USER && !isguestuser()) {
10464
            $userhomepage = (int) get_user_preferences('user_home_page_preference', $defaultpage);
9912
            $userhomepage = get_user_preferences('user_home_page_preference', $defaultpage);
10465
            if (empty($CFG->enabledashboard) && $userhomepage == HOMEPAGE_MY) {
9913
            if (empty($CFG->enabledashboard) && $userhomepage == HOMEPAGE_MY) {
10466
                // If the user was using the dashboard but it's disabled, return the default home page.
9914
                // If the user was using the dashboard but it's disabled, return the default home page.
-
 
9915
                $userhomepage = $defaultpage;
-
 
9916
            } else if (get_default_home_page_url()) {
10467
                $userhomepage = $defaultpage;
9917
                return HOMEPAGE_URL;
10468
            }
9918
            }
-
 
9919
            return (int) $userhomepage;
-
 
9920
        } else if (get_default_home_page_url()) {
10469
            return $userhomepage;
9921
            return HOMEPAGE_URL;
10470
        }
9922
        }
10471
    }
9923
    }
10472
    return HOMEPAGE_SITE;
9924
    return HOMEPAGE_SITE;
Línea 10476... Línea 9928...
10476
 * Returns the default home page to display if current one is not defined or can't be applied.
9928
 * Returns the default home page to display if current one is not defined or can't be applied.
10477
 * The default behaviour is to return Dashboard if it's enabled or My courses page if it isn't.
9929
 * The default behaviour is to return Dashboard if it's enabled or My courses page if it isn't.
10478
 *
9930
 *
10479
 * @return int The default home page.
9931
 * @return int The default home page.
10480
 */
9932
 */
10481
function get_default_home_page(): int
9933
function get_default_home_page(): int {
10482
{
-
 
10483
    global $CFG;
9934
    global $CFG;
Línea 10484... Línea 9935...
10484
 
9935
 
10485
    return (!isset($CFG->enabledashboard) || $CFG->enabledashboard) ? HOMEPAGE_MY : HOMEPAGE_MYCOURSES;
9936
    return (!isset($CFG->enabledashboard) || $CFG->enabledashboard) ? HOMEPAGE_MY : HOMEPAGE_MYCOURSES;
Línea 10486... Línea 9937...
10486
}
9937
}
-
 
9938
 
-
 
9939
/**
-
 
9940
 * Get the default home page as a URL where it has been configured as one via site configuration or user preference
-
 
9941
 *
-
 
9942
 * It is assumed that callers have already checked that {@see get_home_page} returns {@see HOMEPAGE_URL} prior to
-
 
9943
 * calling this method
-
 
9944
 *
-
 
9945
 * @return \core\url|null
-
 
9946
 */
-
 
9947
function get_default_home_page_url(): ?\core\url {
-
 
9948
    global $CFG;
-
 
9949
 
-
 
9950
    if (substr((string)$CFG->defaulthomepage, 0, 1) === '/' &&
-
 
9951
            ($defaulthomepage = clean_param($CFG->wwwroot . $CFG->defaulthomepage, PARAM_LOCALURL))) {
-
 
9952
        return new \core\url($defaulthomepage);
-
 
9953
    }
-
 
9954
 
-
 
9955
    if ($CFG->defaulthomepage == HOMEPAGE_USER) {
-
 
9956
        $userhomepage = get_user_preferences('user_home_page_preference');
-
 
9957
        if (substr((string)$userhomepage, 0, 1) === '/' &&
-
 
9958
                ($userhomepage = clean_param($CFG->wwwroot . $userhomepage, PARAM_LOCALURL))) {
-
 
9959
            return new \core\url($userhomepage);
-
 
9960
        }
-
 
9961
    }
-
 
9962
 
-
 
9963
    return null;
-
 
9964
}
10487
 
9965
 
10488
/**
9966
/**
10489
 * Gets the name of a course to be displayed when showing a list of courses.
9967
 * Gets the name of a course to be displayed when showing a list of courses.
10490
 * By default this is just $course->fullname but user can configure it. The
9968
 * By default this is just $course->fullname but user can configure it. The
10491
 * result of this function should be passed through print_string.
9969
 * result of this function should be passed through print_string.
10492
 * @param stdClass|core_course_list_element $course Moodle course object
9970
 * @param stdClass|core_course_list_element $course Moodle course object
10493
 * @return string Display name of course (either fullname or short + fullname)
9971
 * @return string Display name of course (either fullname or short + fullname)
10494
 */
-
 
10495
function get_course_display_name_for_list($course)
9972
 */
10496
{
9973
function get_course_display_name_for_list($course) {
10497
    global $CFG;
9974
    global $CFG;
10498
    if (!empty($CFG->courselistshortnames)) {
9975
    if (!empty($CFG->courselistshortnames)) {
10499
        if (!($course instanceof stdClass)) {
9976
        if (!($course instanceof stdClass)) {
Línea 10511... Línea 9988...
10511
 * Arrays may contain only integers or strings as both keys and values. Nested arrays are allowed.
9988
 * Arrays may contain only integers or strings as both keys and values. Nested arrays are allowed.
10512
 *
9989
 *
10513
 * @param string $expression
9990
 * @param string $expression
10514
 * @return array|bool either parsed array or false if parsing was impossible.
9991
 * @return array|bool either parsed array or false if parsing was impossible.
10515
 */
9992
 */
10516
function unserialize_array($expression)
9993
function unserialize_array($expression) {
10517
{
-
 
Línea 10518... Línea 9994...
10518
 
9994
 
10519
    // Check the expression is an array.
9995
    // Check the expression is an array.
10520
    if (!preg_match('/^a:(\d+):/', $expression)) {
9996
    if (!preg_match('/^a:(\d+):/', $expression)) {
10521
        return false;
9997
        return false;
Línea 10522... Línea 9998...
10522
    }
9998
    }
Línea 10523... Línea 9999...
10523
 
9999
 
10524
    $values = (array) unserialize_object($expression);
10000
    $values = (array) unserialize_object($expression);
10525
 
10001
 
10526
    // Callback that returns true if the given value is an unserialized object, executes recursively.
10002
    // Callback that returns true if the given value is an unserialized object, executes recursively.
10527
    $invalidvaluecallback = static function ($value) use (&$invalidvaluecallback): bool {
10003
    $invalidvaluecallback = static function($value) use (&$invalidvaluecallback): bool {
10528
        if (is_array($value)) {
10004
        if (is_array($value)) {
10529
            return (bool) array_filter($value, $invalidvaluecallback);
10005
            return (bool) array_filter($value, $invalidvaluecallback);
Línea 10547... Línea 10023...
10547
 * otherwise we would return an instances of {@see __PHP_Incomplete_class} for malformed strings
10023
 * otherwise we would return an instances of {@see __PHP_Incomplete_class} for malformed strings
10548
 *
10024
 *
10549
 * @param string $input
10025
 * @param string $input
10550
 * @return stdClass
10026
 * @return stdClass
10551
 */
10027
 */
10552
function unserialize_object(string $input): stdClass
10028
function unserialize_object(string $input): stdClass {
10553
{
-
 
10554
    $instance = (array) unserialize($input, ['allowed_classes' => [stdClass::class]]);
10029
    $instance = (array) unserialize($input, ['allowed_classes' => [stdClass::class]]);
10555
    return (object) $instance;
10030
    return (object) $instance;
10556
}
10031
}
Línea 10557... Línea 10032...
10557
 
10032
 
10558
/**
-
 
10559
 * The lang_string class
-
 
10560
 *
-
 
10561
 * This special class is used to create an object representation of a string request.
-
 
10562
 * It is special because processing doesn't occur until the object is first used.
-
 
10563
 * The class was created especially to aid performance in areas where strings were
-
 
10564
 * required to be generated but were not necessarily used.
-
 
10565
 * As an example the admin tree when generated uses over 1500 strings, of which
-
 
10566
 * normally only 1/3 are ever actually printed at any time.
-
 
10567
 * The performance advantage is achieved by not actually processing strings that
-
 
10568
 * arn't being used, as such reducing the processing required for the page.
-
 
10569
 *
-
 
10570
 * How to use the lang_string class?
-
 
10571
 *     There are two methods of using the lang_string class, first through the
-
 
10572
 *     forth argument of the get_string function, and secondly directly.
-
 
10573
 *     The following are examples of both.
-
 
10574
 * 1. Through get_string calls e.g.
-
 
10575
 *     $string = get_string($identifier, $component, $a, true);
-
 
10576
 *     $string = get_string('yes', 'moodle', null, true);
-
 
10577
 * 2. Direct instantiation
-
 
10578
 *     $string = new lang_string($identifier, $component, $a, $lang);
-
 
10579
 *     $string = new lang_string('yes');
-
 
10580
 *
-
 
10581
 * How do I use a lang_string object?
-
 
10582
 *     The lang_string object makes use of a magic __toString method so that you
-
 
10583
 *     are able to use the object exactly as you would use a string in most cases.
-
 
10584
 *     This means you are able to collect it into a variable and then directly
-
 
10585
 *     echo it, or concatenate it into another string, or similar.
-
 
10586
 *     The other thing you can do is manually get the string by calling the
-
 
10587
 *     lang_strings out method e.g.
-
 
10588
 *         $string = new lang_string('yes');
-
 
10589
 *         $string->out();
-
 
10590
 *     Also worth noting is that the out method can take one argument, $lang which
-
 
10591
 *     allows the developer to change the language on the fly.
-
 
10592
 *
-
 
10593
 * When should I use a lang_string object?
-
 
10594
 *     The lang_string object is designed to be used in any situation where a
-
 
10595
 *     string may not be needed, but needs to be generated.
-
 
10596
 *     The admin tree is a good example of where lang_string objects should be
-
 
10597
 *     used.
-
 
10598
 *     A more practical example would be any class that requries strings that may
-
 
10599
 *     not be printed (after all classes get renderer by renderers and who knows
-
 
10600
 *     what they will do ;))
-
 
10601
 *
-
 
10602
 * When should I not use a lang_string object?
-
 
10603
 *     Don't use lang_strings when you are going to use a string immediately.
-
 
10604
 *     There is no need as it will be processed immediately and there will be no
-
 
10605
 *     advantage, and in fact perhaps a negative hit as a class has to be
-
 
10606
 *     instantiated for a lang_string object, however get_string won't require
-
 
10607
 *     that.
-
 
10608
 *
-
 
10609
 * Limitations:
-
 
10610
 * 1. You cannot use a lang_string object as an array offset. Doing so will
-
 
10611
 *     result in PHP throwing an error. (You can use it as an object property!)
-
 
10612
 *
-
 
10613
 * @package    core
-
 
10614
 * @category   string
-
 
10615
 * @copyright  2011 Sam Hemelryk
-
 
10616
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
-
 
10617
 */
-
 
10618
class lang_string
-
 
10619
{
-
 
10620
 
-
 
10621
    /** @var string The strings identifier */
-
 
10622
    protected $identifier;
-
 
10623
    /** @var string The strings component. Default '' */
-
 
10624
    protected $component = '';
-
 
10625
    /** @var array|stdClass Any arguments required for the string. Default null */
-
 
10626
    protected $a = null;
-
 
10627
    /** @var string The language to use when processing the string. Default null */
-
 
10628
    protected $lang = null;
-
 
10629
 
-
 
10630
    /** @var string The processed string (once processed) */
-
 
10631
    protected $string = null;
-
 
10632
 
-
 
10633
    /**
-
 
10634
     * A special boolean. If set to true then the object has been woken up and
-
 
10635
     * cannot be regenerated. If this is set then $this->string MUST be used.
-
 
10636
     * @var bool
-
 
10637
     */
-
 
10638
    protected $forcedstring = false;
-
 
10639
 
-
 
10640
    /**
-
 
10641
     * Constructs a lang_string object
-
 
10642
     *
-
 
10643
     * This function should do as little processing as possible to ensure the best
-
 
10644
     * performance for strings that won't be used.
-
 
10645
     *
-
 
10646
     * @param string $identifier The strings identifier
-
 
10647
     * @param string $component The strings component
-
 
10648
     * @param stdClass|array|mixed $a Any arguments the string requires
-
 
10649
     * @param string $lang The language to use when processing the string.
-
 
10650
     * @throws coding_exception
-
 
10651
     */
-
 
10652
    public function __construct($identifier, $component = '', $a = null, $lang = null)
-
 
10653
    {
-
 
10654
        if (empty($component)) {
-
 
10655
            $component = 'moodle';
-
 
10656
        }
-
 
10657
 
-
 
10658
        $this->identifier = $identifier;
-
 
10659
        $this->component = $component;
-
 
10660
        $this->lang = $lang;
-
 
10661
 
-
 
10662
        // We MUST duplicate $a to ensure that it if it changes by reference those
-
 
10663
        // changes are not carried across.
-
 
10664
        // To do this we always ensure $a or its properties/values are strings
-
 
10665
        // and that any properties/values that arn't convertable are forgotten.
-
 
10666
        if ($a !== null) {
-
 
10667
            if (is_scalar($a)) {
-
 
10668
                $this->a = $a;
-
 
10669
            } else if ($a instanceof lang_string) {
-
 
10670
                $this->a = $a->out();
-
 
10671
            } else if (is_object($a) or is_array($a)) {
-
 
10672
                $a = (array)$a;
-
 
10673
                $this->a = array();
-
 
10674
                foreach ($a as $key => $value) {
-
 
10675
                    // Make sure conversion errors don't get displayed (results in '').
-
 
10676
                    if (is_array($value)) {
-
 
10677
                        $this->a[$key] = '';
-
 
10678
                    } else if (is_object($value)) {
-
 
10679
                        if (method_exists($value, '__toString')) {
-
 
10680
                            $this->a[$key] = $value->__toString();
-
 
10681
                        } else {
-
 
10682
                            $this->a[$key] = '';
-
 
10683
                        }
-
 
10684
                    } else {
-
 
10685
                        $this->a[$key] = (string)$value;
-
 
10686
                    }
-
 
10687
                }
-
 
10688
            }
-
 
10689
        }
-
 
10690
 
-
 
10691
        if (debugging(false, DEBUG_DEVELOPER)) {
-
 
10692
            if (clean_param($this->identifier, PARAM_STRINGID) == '') {
-
 
10693
                throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of the string identifier. Please check your string definition');
-
 
10694
            }
-
 
10695
            if (!empty($this->component) && clean_param($this->component, PARAM_COMPONENT) == '') {
-
 
10696
                throw new coding_exception('Invalid string compontent. Please check your string definition');
-
 
10697
            }
-
 
10698
            if (!get_string_manager()->string_exists($this->identifier, $this->component)) {
-
 
10699
                debugging('String does not exist. Please check your string definition for ' . $this->identifier . '/' . $this->component, DEBUG_DEVELOPER);
-
 
10700
            }
-
 
10701
        }
-
 
10702
    }
-
 
10703
 
-
 
10704
    /**
-
 
10705
     * Processes the string.
-
 
10706
     *
-
 
10707
     * This function actually processes the string, stores it in the string property
-
 
10708
     * and then returns it.
-
 
10709
     * You will notice that this function is VERY similar to the get_string method.
-
 
10710
     * That is because it is pretty much doing the same thing.
-
 
10711
     * However as this function is an upgrade it isn't as tolerant to backwards
-
 
10712
     * compatibility.
-
 
10713
     *
-
 
10714
     * @return string
-
 
10715
     * @throws coding_exception
-
 
10716
     */
-
 
10717
    protected function get_string()
-
 
10718
    {
-
 
10719
        global $CFG;
-
 
10720
 
-
 
10721
        // Check if we need to process the string.
-
 
10722
        if ($this->string === null) {
-
 
10723
            // Check the quality of the identifier.
-
 
10724
            if ($CFG->debugdeveloper && clean_param($this->identifier, PARAM_STRINGID) === '') {
-
 
10725
                throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of the string identifier. Please check your string definition', DEBUG_DEVELOPER);
-
 
10726
            }
-
 
10727
 
-
 
10728
            // Process the string.
-
 
10729
            $this->string = get_string_manager()->get_string($this->identifier, $this->component, $this->a, $this->lang);
-
 
10730
            // Debugging feature lets you display string identifier and component.
-
 
10731
            if (isset($CFG->debugstringids) && $CFG->debugstringids && optional_param('strings', 0, PARAM_INT)) {
-
 
10732
                $this->string .= ' {' . $this->identifier . '/' . $this->component . '}';
-
 
10733
            }
-
 
10734
        }
-
 
10735
        // Return the string.
-
 
10736
        return $this->string;
-
 
10737
    }
-
 
10738
 
-
 
10739
    /**
-
 
10740
     * Returns the string
-
 
10741
     *
-
 
10742
     * @param string $lang The langauge to use when processing the string
-
 
10743
     * @return string
-
 
10744
     */
-
 
10745
    public function out($lang = null)
-
 
10746
    {
-
 
10747
        if ($lang !== null && $lang != $this->lang && ($this->lang == null && $lang != current_language())) {
-
 
10748
            if ($this->forcedstring) {
-
 
10749
                debugging('lang_string objects that have been used cannot be printed in another language. (' . $this->lang . ' used)', DEBUG_DEVELOPER);
-
 
10750
                return $this->get_string();
-
 
10751
            }
-
 
10752
            $translatedstring = new lang_string($this->identifier, $this->component, $this->a, $lang);
-
 
10753
            return $translatedstring->out();
-
 
10754
        }
-
 
10755
        return $this->get_string();
-
 
10756
    }
-
 
10757
 
-
 
10758
    /**
-
 
10759
     * Magic __toString method for printing a string
-
 
10760
     *
-
 
10761
     * @return string
-
 
10762
     */
-
 
10763
    public function __toString()
-
 
10764
    {
-
 
10765
        return $this->get_string();
-
 
10766
    }
-
 
10767
 
-
 
10768
    /**
-
 
10769
     * Magic __set_state method used for var_export
-
 
10770
     *
-
 
10771
     * @param array $array
-
 
10772
     * @return self
-
 
10773
     */
-
 
10774
    public static function __set_state(array $array): self
-
 
10775
    {
-
 
10776
        $tmp = new lang_string($array['identifier'], $array['component'], $array['a'], $array['lang']);
-
 
10777
        $tmp->string = $array['string'];
-
 
10778
        $tmp->forcedstring = $array['forcedstring'];
-
 
10779
        return $tmp;
-
 
10780
    }
-
 
10781
 
-
 
10782
    /**
-
 
10783
     * Prepares the lang_string for sleep and stores only the forcedstring and
-
 
10784
     * string properties... the string cannot be regenerated so we need to ensure
-
 
10785
     * it is generated for this.
-
 
10786
     *
-
 
10787
     * @return array
-
 
10788
     */
-
 
10789
    public function __sleep()
-
 
10790
    {
-
 
10791
        $this->get_string();
-
 
10792
        $this->forcedstring = true;
-
 
10793
        return array('forcedstring', 'string', 'lang');
-
 
10794
    }
-
 
10795
 
-
 
10796
    /**
-
 
10797
     * Returns the identifier.
-
 
10798
     *
-
 
10799
     * @return string
-
 
10800
     */
-
 
10801
    public function get_identifier()
-
 
10802
    {
-
 
10803
        return $this->identifier;
-
 
10804
    }
-
 
10805
 
-
 
10806
    /**
-
 
10807
     * Returns the component.
-
 
10808
     *
-
 
10809
     * @return string
-
 
10810
     */
-
 
10811
    public function get_component()
-
 
10812
    {
-
 
10813
        return $this->component;
-
 
10814
    }
-
 
10815
}
-
 
10816
 
-
 
10817
/**
10033
/**
10818
 * Get human readable name describing the given callable.
10034
 * Get human readable name describing the given callable.
10819
 *
10035
 *
10820
 * This performs syntax check only to see if the given param looks like a valid function, method or closure.
10036
 * This performs syntax check only to see if the given param looks like a valid function, method or closure.
10821
 * It does not check if the callable actually exists.
10037
 * It does not check if the callable actually exists.
10822
 *
10038
 *
10823
 * @param callable|string|array $callable
10039
 * @param callable|string|array $callable
10824
 * @return string|bool Human readable name of callable, or false if not a valid callable.
10040
 * @return string|bool Human readable name of callable, or false if not a valid callable.
10825
 */
10041
 */
10826
function get_callable_name($callable)
-
 
Línea 10827... Línea 10042...
10827
{
10042
function get_callable_name($callable) {
10828
 
10043
 
-
 
10044
    if (!is_callable($callable, true, $name)) {
10829
    if (!is_callable($callable, true, $name)) {
10045
        return false;
10830
        return false;
10046
 
10831
    } else {
10047
    } else {
10832
        return $name;
10048
        return $name;
Línea 10841... Línea 10057...
10841
 * Good thing is there is no false negative.
10057
 * Good thing is there is no false negative.
10842
 * Note that it's possible to force the result of this check by specifying $CFG->site_is_public in config.php
10058
 * Note that it's possible to force the result of this check by specifying $CFG->site_is_public in config.php
10843
 *
10059
 *
10844
 * @return bool
10060
 * @return bool
10845
 */
10061
 */
10846
function site_is_public()
10062
function site_is_public() {
10847
{
-
 
10848
    global $CFG;
10063
    global $CFG;
Línea 10849... Línea 10064...
10849
 
10064
 
10850
    // Return early if site admin has forced this setting.
10065
    // Return early if site admin has forced this setting.
10851
    if (isset($CFG->site_is_public)) {
10066
    if (isset($CFG->site_is_public)) {
Línea 10872... Línea 10087...
10872
 *
10087
 *
10873
 * @param string $password
10088
 * @param string $password
10874
 * @param int $pepperlength The length of the used peppers
10089
 * @param int $pepperlength The length of the used peppers
10875
 * @return bool
10090
 * @return bool
10876
 */
10091
 */
10877
function exceeds_password_length(string $password, int $pepperlength = 0): bool
10092
function exceeds_password_length(string $password, int $pepperlength = 0): bool {
10878
{
-
 
10879
    return (strlen($password) > (MAX_PASSWORD_CHARACTERS + $pepperlength));
10093
    return (strlen($password) > (MAX_PASSWORD_CHARACTERS + $pepperlength));
10880
}
10094
}
Línea 10881... Línea 10095...
10881
 
10095
 
10882
/**
10096
/**
Línea 10891... Línea 10105...
10891
 * @param array $array
10105
 * @param array $array
10892
 * @param mixed $filter The value to filter on
10106
 * @param mixed $filter The value to filter on
10893
 * @param bool $strict Whether to apply a strit test with the filter
10107
 * @param bool $strict Whether to apply a strit test with the filter
10894
 * @return array
10108
 * @return array
10895
 */
10109
 */
10896
function moodle_array_keys_filter(array $array, mixed $filter, bool $strict = false): array
10110
function moodle_array_keys_filter(array $array, mixed $filter, bool $strict = false): array {
10897
{
-
 
10898
    return array_keys(array_filter(
10111
    return array_keys(array_filter(
10899
        $array,
10112
        $array,
10900
        function ($value, $key) use ($filter, $strict): bool {
10113
        function($value, $key) use ($filter, $strict): bool {
10901
            if ($strict) {
10114
            if ($strict) {
10902
                return $value === $filter;
10115
                return $value === $filter;
10903
            }
10116
            }
10904
            return $value == $filter;
10117
            return $value == $filter;
10905
        },
10118
        },