__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

www-data@216.73.216.10: ~ $
<?php
// This file is part of Moodle - https://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.

namespace core;

use stdClass, IteratorAggregate, ArrayIterator;
use coding_exception, moodle_url;

/**
 * Basic moodle context abstraction class.
 *
 * Google confirms that no other important framework is using "context" class,
 * we could use something else like mcontext or moodle_context, but we need to type
 * this very often which would be annoying and it would take too much space...
 *
 * This class is derived from stdClass for backwards compatibility with
 * odl $context record that was returned from DML $DB->get_record()
 *
 * @package   core_access
 * @category  access
 * @copyright Petr Skoda
 * @license   https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 * @since     Moodle 4.2
 *
 * @property-read int $id context id
 * @property-read int $contextlevel CONTEXT_SYSTEM, CONTEXT_COURSE, etc.
 * @property-read int $instanceid id of related instance in each context
 * @property-read string $path path to context, starts with system context
 * @property-read int $depth
 * @property-read bool $locked true means write capabilities are ignored in this context or parents
 */
abstract class context extends stdClass implements IteratorAggregate {

    /** @var string Default sorting of capabilities in {@see get_capabilities} */
    protected const DEFAULT_CAPABILITY_SORT = 'contextlevel, component, name';

    /**
     * The context id
     * Can be accessed publicly through $context->id
     * @var int
     */
    protected $_id;

    /**
     * The context level
     * Can be accessed publicly through $context->contextlevel
     * @var int One of CONTEXT_* e.g. CONTEXT_COURSE, CONTEXT_MODULE
     */
    protected $_contextlevel;

    /**
     * Id of the item this context is related to e.g. COURSE_CONTEXT => course.id
     * Can be accessed publicly through $context->instanceid
     * @var int
     */
    protected $_instanceid;

    /**
     * The path to the context always starting from the system context
     * Can be accessed publicly through $context->path
     * @var string
     */
    protected $_path;

    /**
     * The depth of the context in relation to parent contexts
     * Can be accessed publicly through $context->depth
     * @var int
     */
    protected $_depth;

    /**
     * Whether this context is locked or not.
     *
     * Can be accessed publicly through $context->locked.
     *
     * @var int
     */
    protected $_locked;

    /**
     * @var array Context caching info
     */
    private static $cache_contextsbyid = array();

    /**
     * @var array Context caching info
     */
    private static $cache_contexts = array();

    /**
     * Context count
     * Why do we do count contexts? Because count($array) is horribly slow for large arrays
     * @var int
     */
    protected static $cache_count = 0;

    /**
     * @var array Context caching info
     */
    protected static $cache_preloaded = array();

    /**
     * @var context\system The system context once initialised
     */
    protected static $systemcontext = null;

    /**
     * Returns short context name.
     *
     * @since Moodle 4.2
     *
     * @return string
     */
    public static function get_short_name(): string {
        // NOTE: it would be more correct to make this abstract,
        // unfortunately there are tests that attempt to mock context classes.
        throw new \coding_exception('get_short_name() method must be overridden in custom context levels');
    }

    /**
     * Resets the cache to remove all data.
     */
    protected static function reset_caches() {
        self::$cache_contextsbyid = array();
        self::$cache_contexts = array();
        self::$cache_count = 0;
        self::$cache_preloaded = array();

        self::$systemcontext = null;
    }

    /**
     * Adds a context to the cache. If the cache is full, discards a batch of
     * older entries.
     *
     * @param context $context New context to add
     * @return void
     */
    protected static function cache_add(context $context) {
        if (isset(self::$cache_contextsbyid[$context->id])) {
            // Already cached, no need to do anything - this is relatively cheap, we do all this because count() is slow.
            return;
        }

        if (self::$cache_count >= CONTEXT_CACHE_MAX_SIZE) {
            $i = 0;
            foreach (self::$cache_contextsbyid as $ctx) {
                $i++;
                if ($i <= 100) {
                    // We want to keep the first contexts to be loaded on this page, hopefully they will be needed again later.
                    continue;
                }
                if ($i > (CONTEXT_CACHE_MAX_SIZE / 3)) {
                    // We remove oldest third of the contexts to make room for more contexts.
                    break;
                }
                unset(self::$cache_contextsbyid[$ctx->id]);
                unset(self::$cache_contexts[$ctx->contextlevel][$ctx->instanceid]);
                self::$cache_count--;
            }
        }

        self::$cache_contexts[$context->contextlevel][$context->instanceid] = $context;
        self::$cache_contextsbyid[$context->id] = $context;
        self::$cache_count++;
    }

    /**
     * Removes a context from the cache.
     *
     * @param context $context Context object to remove
     * @return void
     */
    protected static function cache_remove(context $context) {
        if (!isset(self::$cache_contextsbyid[$context->id])) {
            // Not cached, no need to do anything - this is relatively cheap, we do all this because count() is slow.
            return;
        }
        unset(self::$cache_contexts[$context->contextlevel][$context->instanceid]);
        unset(self::$cache_contextsbyid[$context->id]);

        self::$cache_count--;

        if (self::$cache_count < 0) {
            self::$cache_count = 0;
        }
    }

    /**
     * Gets a context from the cache.
     *
     * @param int $contextlevel Context level
     * @param int $instance Instance ID
     * @return context|bool Context or false if not in cache
     */
    protected static function cache_get($contextlevel, $instance) {
        if (isset(self::$cache_contexts[$contextlevel][$instance])) {
            return self::$cache_contexts[$contextlevel][$instance];
        }
        return false;
    }

    /**
     * Gets a context from the cache based on its id.
     *
     * @param int $id Context ID
     * @return context|bool Context or false if not in cache
     */
    protected static function cache_get_by_id($id) {
        if (isset(self::$cache_contextsbyid[$id])) {
            return self::$cache_contextsbyid[$id];
        }
        return false;
    }

    /**
     * Preloads context information from db record and strips the cached info.
     *
     * @param stdClass $rec
     * @return context|null (modifies $rec)
     */
    protected static function preload_from_record(stdClass $rec) {
        $notenoughdata = false;
        $notenoughdata = $notenoughdata || empty($rec->ctxid);
        $notenoughdata = $notenoughdata || empty($rec->ctxlevel);
        $notenoughdata = $notenoughdata || !isset($rec->ctxinstance);
        $notenoughdata = $notenoughdata || empty($rec->ctxpath);
        $notenoughdata = $notenoughdata || empty($rec->ctxdepth);
        $notenoughdata = $notenoughdata || !isset($rec->ctxlocked);
        if ($notenoughdata) {
            // The record does not have enough data, passed here repeatedly or context does not exist yet.
            if (isset($rec->ctxid) && !isset($rec->ctxlocked)) {
                debugging('Locked value missing. Code is possibly not usings the getter properly.', DEBUG_DEVELOPER);
            }
            return null;
        }

        $record = (object) [
            'id' => $rec->ctxid,
            'contextlevel' => $rec->ctxlevel,
            'instanceid' => $rec->ctxinstance,
            'path' => $rec->ctxpath,
            'depth' => $rec->ctxdepth,
            'locked' => $rec->ctxlocked,
        ];

        unset($rec->ctxid);
        unset($rec->ctxlevel);
        unset($rec->ctxinstance);
        unset($rec->ctxpath);
        unset($rec->ctxdepth);
        unset($rec->ctxlocked);

        return self::create_instance_from_record($record);
    }


    /* ====== magic methods ======= */

    /**
     * Magic setter method, we do not want anybody to modify properties from the outside
     * @param string $name
     * @param mixed $value
     */
    public function __set($name, $value) {
        debugging('Can not change context instance properties!');
    }

    /**
     * Magic method getter, redirects to read only values.
     * @param string $name
     * @return mixed
     */
    public function __get($name) {
        switch ($name) {
            case 'id':
                return $this->_id;
            case 'contextlevel':
                return $this->_contextlevel;
            case 'instanceid':
                return $this->_instanceid;
            case 'path':
                return $this->_path;
            case 'depth':
                return $this->_depth;
            case 'locked':
                return $this->is_locked();

            default:
                debugging('Invalid context property accessed! '.$name);
                return null;
        }
    }

    /**
     * Full support for isset on our magic read only properties.
     * @param string $name
     * @return bool
     */
    public function __isset($name) {
        switch ($name) {
            case 'id':
                return isset($this->_id);
            case 'contextlevel':
                return isset($this->_contextlevel);
            case 'instanceid':
                return isset($this->_instanceid);
            case 'path':
                return isset($this->_path);
            case 'depth':
                return isset($this->_depth);
            case 'locked':
                // Locked is always set.
                return true;
            default:
                return false;
        }
    }

    /**
     * All properties are read only, sorry.
     * @param string $name
     */
    public function __unset($name) {
        debugging('Can not unset context instance properties!');
    }

    /* ====== implementing method from interface IteratorAggregate ====== */

    /**
     * Create an iterator because magic vars can't be seen by 'foreach'.
     *
     * Now we can convert context object to array using convert_to_array(),
     * and feed it properly to json_encode().
     */
    public function getIterator(): \Traversable {
        $ret = array(
            'id' => $this->id,
            'contextlevel' => $this->contextlevel,
            'instanceid' => $this->instanceid,
            'path' => $this->path,
            'depth' => $this->depth,
            'locked' => $this->locked,
        );
        return new ArrayIterator($ret);
    }

    /* ====== general context methods ====== */

    /**
     * Constructor is protected so that devs are forced to
     * use context_xxx::instance() or context::instance_by_id().
     *
     * @param stdClass $record
     */
    protected function __construct(stdClass $record) {
        $this->_id = (int)$record->id;
        $this->_contextlevel = (int)$record->contextlevel;
        $this->_instanceid = $record->instanceid;
        $this->_path = $record->path;
        $this->_depth = $record->depth;

        if (isset($record->locked)) {
            $this->_locked = $record->locked;
        } else if (!during_initial_install() && !moodle_needs_upgrading()) {
            debugging('Locked value missing. Code is possibly not usings the getter properly.', DEBUG_DEVELOPER);
        }
    }

    /**
     * This function is also used to work around 'protected' keyword problems in context_helper.
     *
     * @param stdClass $record
     * @return context instance
     */
    protected static function create_instance_from_record(stdClass $record) {
        $classname = context_helper::get_class_for_level($record->contextlevel);

        if ($context = self::cache_get_by_id($record->id)) {
            return $context;
        }

        $context = new $classname($record);
        self::cache_add($context);

        return $context;
    }

    /**
     * Copy prepared new contexts from temp table to context table,
     * we do this in db specific way for perf reasons only.
     */
    protected static function merge_context_temp_table() {
        global $DB;

        /* MDL-11347:
         *  - mysql does not allow to use FROM in UPDATE statements
         *  - using two tables after UPDATE works in mysql, but might give unexpected
         *    results in pg 8 (depends on configuration)
         *  - using table alias in UPDATE does not work in pg < 8.2
         *
         * Different code for each database - mostly for performance reasons
         */

        $dbfamily = $DB->get_dbfamily();
        if ($dbfamily == 'mysql') {
            $updatesql = "UPDATE {context} ct, {context_temp} temp
                             SET ct.path = temp.path,
                                 ct.depth = temp.depth,
                                 ct.locked = temp.locked
                           WHERE ct.id = temp.id";
        } else if ($dbfamily == 'oracle') {
            $updatesql = "UPDATE {context} ct
                             SET (ct.path, ct.depth, ct.locked) =
                                 (SELECT temp.path, temp.depth, temp.locked
                                    FROM {context_temp} temp
                                   WHERE temp.id=ct.id)
                           WHERE EXISTS (SELECT 'x'
                                           FROM {context_temp} temp
                                           WHERE temp.id = ct.id)";
        } else if ($dbfamily == 'postgres' || $dbfamily == 'mssql') {
            $updatesql = "UPDATE {context}
                             SET path = temp.path,
                                 depth = temp.depth,
                                 locked = temp.locked
                            FROM {context_temp} temp
                           WHERE temp.id={context}.id";
        } else {
            // Sqlite and others.
            $updatesql = "UPDATE {context}
                             SET path = (SELECT path FROM {context_temp} WHERE id = {context}.id),
                                 depth = (SELECT depth FROM {context_temp} WHERE id = {context}.id),
                                 locked = (SELECT locked FROM {context_temp} WHERE id = {context}.id)
                             WHERE id IN (SELECT id FROM {context_temp})";
        }

        $DB->execute($updatesql);
    }

    /**
     * Get a context instance as an object, from a given context id.
     *
     * @param int $id context id
     * @param int $strictness IGNORE_MISSING means compatible mode, false returned if record not found, debug message if more found;
     *                        MUST_EXIST means throw exception if no record found
     * @return context|bool the context object or false if not found
     */
    public static function instance_by_id($id, $strictness = MUST_EXIST) {
        global $DB;

        if (get_called_class() !== 'core\context' && get_called_class() !== 'core\context_helper') {
            // Some devs might confuse context->id and instanceid, better prevent these mistakes completely.
            throw new coding_exception('use only context::instance_by_id() for real context levels use ::instance() methods');
        }

        if ($id == SYSCONTEXTID) {
            return context\system::instance(0, $strictness);
        }

        if (is_array($id) || is_object($id) || empty($id)) {
            throw new coding_exception('Invalid context id specified context::instance_by_id()');
        }

        if ($context = self::cache_get_by_id($id)) {
            return $context;
        }

        if ($record = $DB->get_record('context', array('id' => $id), '*', $strictness)) {
            return self::create_instance_from_record($record);
        }

        return false;
    }

    /**
     * Update context info after moving context in the tree structure.
     *
     * @param context $newparent
     * @return void
     */
    public function update_moved(context $newparent) {
        global $DB;

        $frompath = $this->_path;
        $newpath = $newparent->path . '/' . $this->_id;

        $trans = $DB->start_delegated_transaction();

        $setdepth = '';
        if (($newparent->depth + 1) != $this->_depth) {
            $diff = $newparent->depth - $this->_depth + 1;
            $setdepth = ", depth = depth + $diff";
        }
        $sql = "UPDATE {context}
                   SET path = ?
                       $setdepth
                 WHERE id = ?";
        $params = array($newpath, $this->_id);
        $DB->execute($sql, $params);

        $this->_path = $newpath;
        $this->_depth = $newparent->depth + 1;

        $sql = "UPDATE {context}
                   SET path = ".$DB->sql_concat("?", $DB->sql_substr("path", strlen($frompath) + 1))."
                       $setdepth
                 WHERE path LIKE ?";
        $params = array($newpath, "{$frompath}/%");
        $DB->execute($sql, $params);

        $this->mark_dirty();

        self::reset_caches();

        $trans->allow_commit();
    }

    /**
     * Set whether this context has been locked or not.
     *
     * @param   bool    $locked
     * @return  $this
     */
    public function set_locked(bool $locked) {
        global $DB;

        if ($this->_locked == $locked) {
            return $this;
        }

        $this->_locked = $locked;
        $DB->set_field('context', 'locked', (int) $locked, ['id' => $this->id]);
        $this->mark_dirty();

        if ($locked) {
            $eventname = '\\core\\event\\context_locked';
        } else {
            $eventname = '\\core\\event\\context_unlocked';
        }
        $event = $eventname::create(['context' => $this, 'objectid' => $this->id]);
        $event->trigger();

        self::reset_caches();

        return $this;
    }

    /**
     * Remove all context path info and optionally rebuild it.
     *
     * @param bool $rebuild
     * @return void
     */
    public function reset_paths($rebuild = true) {
        global $DB;

        if ($this->_path) {
            $this->mark_dirty();
        }
        $DB->set_field_select('context', 'depth', 0, "path LIKE '%/$this->_id/%'");
        $DB->set_field_select('context', 'path', null, "path LIKE '%/$this->_id/%'");
        if ($this->_contextlevel != CONTEXT_SYSTEM) {
            $DB->set_field('context', 'depth', 0, array('id' => $this->_id));
            $DB->set_field('context', 'path', null, array('id' => $this->_id));
            $this->_depth = 0;
            $this->_path = null;
        }

        if ($rebuild) {
            context_helper::build_all_paths(false);
        }

        self::reset_caches();
    }

    /**
     * Delete all data linked to content, do not delete the context record itself
     */
    public function delete_content() {
        global $CFG, $DB;

        blocks_delete_all_for_context($this->_id);
        filter_delete_all_for_context($this->_id);

        require_once($CFG->dirroot . '/comment/lib.php');
        \comment::delete_comments(array('contextid' => $this->_id));

        require_once($CFG->dirroot.'/rating/lib.php');
        $delopt = new stdclass();
        $delopt->contextid = $this->_id;
        $rm = new \rating_manager();
        $rm->delete_ratings($delopt);

        // Delete all files attached to this context.
        $fs = get_file_storage();
        $fs->delete_area_files($this->_id);

        // Delete all repository instances attached to this context.
        require_once($CFG->dirroot . '/repository/lib.php');
        \repository::delete_all_for_context($this->_id);

        // Delete all advanced grading data attached to this context.
        require_once($CFG->dirroot.'/grade/grading/lib.php');
        \grading_manager::delete_all_for_context($this->_id);

        // Now delete stuff from role related tables, role_unassign_all
        // and unenrol should be called earlier to do proper cleanup.
        $DB->delete_records('role_assignments', array('contextid' => $this->_id));
        $DB->delete_records('role_names', array('contextid' => $this->_id));
        $this->delete_capabilities();
    }

    /**
     * Unassign all capabilities from a context.
     */
    public function delete_capabilities() {
        global $DB;

        $ids = $DB->get_fieldset_select('role_capabilities', 'DISTINCT roleid', 'contextid = ?', array($this->_id));
        if ($ids) {
            $DB->delete_records('role_capabilities', array('contextid' => $this->_id));

            // Reset any cache of these roles, including MUC.
            accesslib_clear_role_cache($ids);
        }
    }

    /**
     * Delete the context content and the context record itself
     */
    public function delete() {
        global $DB;

        if ($this->_contextlevel <= CONTEXT_SYSTEM) {
            throw new coding_exception('Cannot delete system context');
        }

        // Double check the context still exists.
        if (!$DB->record_exists('context', array('id' => $this->_id))) {
            self::cache_remove($this);
            return;
        }

        $this->delete_content();
        $DB->delete_records('context', array('id' => $this->_id));
        // Purge static context cache if entry present.
        self::cache_remove($this);

        // Inform search engine to delete data related to this context.
        \core_search\manager::context_deleted($this);
    }

    /* ====== context level related methods ====== */

    /**
     * Utility method for context creation
     *
     * @param int $contextlevel
     * @param int $instanceid
     * @param string $parentpath
     * @return stdClass context record
     */
    protected static function insert_context_record($contextlevel, $instanceid, $parentpath) {
        global $DB;

        $record = new stdClass();
        $record->contextlevel = $contextlevel;
        $record->instanceid = $instanceid;
        $record->depth = 0;
        $record->path = null; // Not known before insert.
        $record->locked = 0;

        $record->id = $DB->insert_record('context', $record);

        // Now add path if known - it can be added later.
        if (!is_null($parentpath)) {
            $record->path = $parentpath.'/'.$record->id;
            $record->depth = substr_count($record->path, '/');
            $DB->update_record('context', $record);
        }

        return $record;
    }

    /**
     * Returns human readable context identifier.
     *
     * @param boolean $withprefix whether to prefix the name of the context with the
     *      type of context, e.g. User, Course, Forum, etc.
     * @param boolean $short whether to use the short name of the thing. Only applies
     *      to course contexts
     * @param boolean $escape Whether the returned name of the thing is to be
     *      HTML escaped or not.
     * @return string the human readable context name.
     */
    public function get_context_name($withprefix = true, $short = false, $escape = true) {
        // Must be implemented in all context levels.
        throw new coding_exception('can not get name of abstract context');
    }

    /**
     * Whether the current context is locked.
     *
     * @return  bool
     */
    public function is_locked() {
        if ($this->_locked) {
            return true;
        }

        if ($parent = $this->get_parent_context()) {
            return $parent->is_locked();
        }

        return false;
    }

    /**
     * Returns the most relevant URL for this context.
     *
     * @return moodle_url
     */
    abstract public function get_url();

    /**
     * Returns context instance database name.
     *
     * @return string|null table name for all levels except system.
     */
    protected static function get_instance_table(): ?string {
        return null;
    }

    /**
     * Returns list of columns that can be used from behat
     * to look up context by reference.
     *
     * @return array list of column names from instance table
     */
    protected static function get_behat_reference_columns(): array {
        return [];
    }

    /**
     * Returns list of all role archetypes that are compatible
     * with role assignments in context level.
     * @since Moodle 4.2
     *
     * @return string[]
     */
    protected static function get_compatible_role_archetypes(): array {
        // Override if archetype roles should be allowed to be assigned in context level.
        return [];
    }

    /**
     * Returns list of all possible parent context levels,
     * it may include itself if nesting is allowed.
     * @since Moodle 4.2
     *
     * @return int[]
     */
    public static function get_possible_parent_levels(): array {
        // Override if other type of parents are expected.
        return [context\system::LEVEL];
    }

    /**
     * Returns array of relevant context capability records.
     *
     * @param string $sort SQL order by snippet for sorting returned capabilities sensibly for display
     * @return array
     */
    abstract public function get_capabilities(string $sort = self::DEFAULT_CAPABILITY_SORT);

    /**
     * Recursive function which, given a context, find all its children context ids.
     *
     * For course category contexts it will return immediate children and all subcategory contexts.
     * It will NOT recurse into courses or subcategories categories.
     * If you want to do that, call it on the returned courses/categories.
     *
     * When called for a course context, it will return the modules and blocks
     * displayed in the course page and blocks displayed on the module pages.
     *
     * If called on a user/course/module context it _will_ populate the cache with the appropriate
     * contexts ;-)
     *
     * @return array Array of child records
     */
    public function get_child_contexts() {
        global $DB;

        if (empty($this->_path) || empty($this->_depth)) {
            debugging('Can not find child contexts of context '.$this->_id.' try rebuilding of context paths');
            return array();
        }

        $sql = "SELECT ctx.*
                  FROM {context} ctx
                 WHERE ctx.path LIKE ?";
        $params = array($this->_path.'/%');
        $records = $DB->get_records_sql($sql, $params);

        $result = array();
        foreach ($records as $record) {
            $result[$record->id] = self::create_instance_from_record($record);
        }

        return $result;
    }

    /**
     * Determine if the current context is a parent of the possible child.
     *
     * @param   context $possiblechild
     * @param   bool $includeself Whether to check the current context
     * @return  bool
     */
    public function is_parent_of(context $possiblechild, bool $includeself): bool {
        // A simple substring check is used on the context path.
        // The possible child's path is used as a haystack, with the current context as the needle.
        // The path is prefixed with '+' to ensure that the parent always starts at the top.
        // It is suffixed with '+' to ensure that parents are not included.
        // The needle always suffixes with a '/' to ensure that the contextid uses a complete match (i.e. 142/ instead of 14).
        // The haystack is suffixed with '/+' if $includeself is true to allow the current context to match.
        // The haystack is suffixed with '+' if $includeself is false to prevent the current context from matching.
        $haystacksuffix = $includeself ? '/+' : '+';

        $strpos = strpos(
            "+{$possiblechild->path}{$haystacksuffix}",
            "+{$this->path}/"
        );
        return $strpos === 0;
    }

    /**
     * Returns parent contexts of this context in reversed order, i.e. parent first,
     * then grand parent, etc.
     *
     * @param bool $includeself true means include self too
     * @return array of context instances
     */
    public function get_parent_contexts($includeself = false) {
        if (!$contextids = $this->get_parent_context_ids($includeself)) {
            return array();
        }

        // Preload the contexts to reduce DB calls.
        context_helper::preload_contexts_by_id($contextids);

        $result = array();
        foreach ($contextids as $contextid) {
            // Do NOT change this to self!
            $parent = context_helper::instance_by_id($contextid, MUST_EXIST);
            $result[$parent->id] = $parent;
        }

        return $result;
    }

    /**
     * Determine if the current context is a child of the possible parent.
     *
     * @param   context $possibleparent
     * @param   bool $includeself Whether to check the current context
     * @return  bool
     */
    public function is_child_of(context $possibleparent, bool $includeself): bool {
        // A simple substring check is used on the context path.
        // The current context is used as a haystack, with the possible parent as the needle.
        // The path is prefixed with '+' to ensure that the parent always starts at the top.
        // It is suffixed with '+' to ensure that children are not included.
        // The needle always suffixes with a '/' to ensure that the contextid uses a complete match (i.e. 142/ instead of 14).
        // The haystack is suffixed with '/+' if $includeself is true to allow the current context to match.
        // The haystack is suffixed with '+' if $includeself is false to prevent the current context from matching.
        $haystacksuffix = $includeself ? '/+' : '+';

        $strpos = strpos(
            "+{$this->path}{$haystacksuffix}",
            "+{$possibleparent->path}/"
        );
        return $strpos === 0;
    }

    /**
     * Returns parent context ids of this context in reversed order, i.e. parent first,
     * then grand parent, etc.
     *
     * @param bool $includeself true means include self too
     * @return array of context ids
     */
    public function get_parent_context_ids($includeself = false) {
        if (empty($this->_path)) {
            return array();
        }

        $parentcontexts = trim($this->_path, '/'); // Kill leading slash.
        $parentcontexts = explode('/', $parentcontexts);
        if (!$includeself) {
            array_pop($parentcontexts); // And remove its own id.
        }

        return array_reverse($parentcontexts);
    }

    /**
     * Returns parent context paths of this context.
     *
     * @param bool $includeself true means include self too
     * @return array of context paths
     */
    public function get_parent_context_paths($includeself = false) {
        if (empty($this->_path)) {
            return array();
        }

        $contextids = explode('/', $this->_path);

        $path = '';
        $paths = array();
        foreach ($contextids as $contextid) {
            if ($contextid) {
                $path .= '/' . $contextid;
                $paths[$contextid] = $path;
            }
        }

        if (!$includeself) {
            unset($paths[$this->_id]);
        }

        return $paths;
    }

    /**
     * Returns parent context
     *
     * @return context|false
     */
    public function get_parent_context() {
        if (empty($this->_path) || $this->_id == SYSCONTEXTID) {
            return false;
        }

        $parentcontexts = trim($this->_path, '/'); // Kill leading slash.
        $parentcontexts = explode('/', $parentcontexts);
        array_pop($parentcontexts); // Self.
        $contextid = array_pop($parentcontexts); // Immediate parent.

        // Do NOT change this to self!
        return context_helper::instance_by_id($contextid, MUST_EXIST);
    }

    /**
     * Is this context part of any course? If yes return course context.
     *
     * @param bool $strict true means throw exception if not found, false means return false if not found
     * @return context\course|false context of the enclosing course, null if not found or exception
     */
    public function get_course_context($strict = true) {
        if ($strict) {
            throw new coding_exception('Context does not belong to any course.');
        } else {
            return false;
        }
    }

    /**
     * Returns sql necessary for purging of stale context instances.
     *
     * @return string cleanup SQL
     */
    protected static function get_cleanup_sql() {
        throw new coding_exception('get_cleanup_sql() method must be implemented in all context levels');
    }

    /**
     * Rebuild context paths and depths at context level.
     *
     * @param bool $force
     * @return void
     */
    protected static function build_paths($force) {
        throw new coding_exception('build_paths() method must be implemented in all context levels');
    }

    /**
     * Create missing context instances at given level
     *
     * @return void
     */
    protected static function create_level_instances() {
        throw new coding_exception('create_level_instances() method must be implemented in all context levels');
    }

    /**
     * Reset all cached permissions and definitions if the necessary.
     * @return void
     */
    public function reload_if_dirty() {
        global $ACCESSLIB_PRIVATE, $USER;

        // Load dirty contexts list if needed.
        if (CLI_SCRIPT) {
            if (!isset($ACCESSLIB_PRIVATE->dirtycontexts)) {
                // We do not load dirty flags in CLI and cron.
                $ACCESSLIB_PRIVATE->dirtycontexts = array();
            }
        } else {
            if (!isset($USER->access['time'])) {
                // Nothing has been loaded yet, so we do not need to check dirty flags now.
                return;
            }

            // From skodak: No idea why -2 is there, server cluster time difference maybe...
            $changedsince = $USER->access['time'] - 2;

            if (!isset($ACCESSLIB_PRIVATE->dirtycontexts)) {
                $ACCESSLIB_PRIVATE->dirtycontexts = get_cache_flags('accesslib/dirtycontexts', $changedsince);
            }

            if (!isset($ACCESSLIB_PRIVATE->dirtyusers[$USER->id])) {
                $ACCESSLIB_PRIVATE->dirtyusers[$USER->id] = get_cache_flag('accesslib/dirtyusers', $USER->id, $changedsince);
            }
        }

        $dirty = false;

        if (!empty($ACCESSLIB_PRIVATE->dirtyusers[$USER->id])) {
            $dirty = true;
        } else if (!empty($ACCESSLIB_PRIVATE->dirtycontexts)) {
            $paths = $this->get_parent_context_paths(true);

            foreach ($paths as $path) {
                if (isset($ACCESSLIB_PRIVATE->dirtycontexts[$path])) {
                    $dirty = true;
                    break;
                }
            }
        }

        if ($dirty) {
            // Reload all capabilities of USER and others - preserving loginas, roleswitches, etc.
            // Then cleanup any marks of dirtyness... at least from our short term memory!
            reload_all_capabilities();
        }
    }

    /**
     * Mark a context as dirty (with timestamp) so as to force reloading of the context.
     */
    public function mark_dirty() {
        global $CFG, $USER, $ACCESSLIB_PRIVATE;

        if (during_initial_install()) {
            return;
        }

        // Only if it is a non-empty string.
        if (is_string($this->_path) && $this->_path !== '') {
            set_cache_flag('accesslib/dirtycontexts', $this->_path, 1, time() + $CFG->sessiontimeout);
            if (isset($ACCESSLIB_PRIVATE->dirtycontexts)) {
                $ACCESSLIB_PRIVATE->dirtycontexts[$this->_path] = 1;
            } else {
                if (CLI_SCRIPT) {
                    $ACCESSLIB_PRIVATE->dirtycontexts = array($this->_path => 1);
                } else {
                    if (isset($USER->access['time'])) {
                        $ACCESSLIB_PRIVATE->dirtycontexts = get_cache_flags('accesslib/dirtycontexts', $USER->access['time'] - 2);
                    } else {
                        $ACCESSLIB_PRIVATE->dirtycontexts = array($this->_path => 1);
                    }
                    // Flags not loaded yet, it will be done later in $context->reload_if_dirty().
                }
            }
        }
    }
}

Filemanager

Name Type Size Permission Actions
access Folder 0777
analytics Folder 0777
antivirus Folder 0777
attribute Folder 0777
aws Folder 0777
check Folder 0777
content Folder 0777
context Folder 0777
dataformat Folder 0777
dml Folder 0777
event Folder 0777
exception Folder 0777
external Folder 0777
files Folder 0777
form Folder 0777
hook Folder 0777
hub Folder 0777
local Folder 0777
lock Folder 0777
log Folder 0777
message Folder 0777
moodlenet Folder 0777
navigation Folder 0777
oauth2 Folder 0777
output Folder 0777
plugininfo Folder 0777
privacy Folder 0777
progress Folder 0777
reportbuilder Folder 0777
route Folder 0777
router Folder 0777
session Folder 0777
task Folder 0777
tests Folder 0777
update Folder 0777
upgrade Folder 0777
activity_dates.php File 3.02 KB 0777
attribute_helper.php File 9.5 KB 0777
chart_axis.php File 4.26 KB 0777
chart_bar.php File 2.7 KB 0777
chart_base.php File 8.36 KB 0777
chart_line.php File 1.87 KB 0777
chart_pie.php File 1.91 KB 0777
chart_series.php File 6.53 KB 0777
clock.php File 1.07 KB 0777
collator.php File 14.35 KB 0777
component.php File 62.51 KB 0777
content.php File 7.02 KB 0777
context.php File 36.36 KB 0777
context_helper.php File 15.5 KB 0777
cron.php File 26.57 KB 0777
cssparser.php File 1.38 KB 0777
dataformat.php File 5.74 KB 0777
date.php File 37.69 KB 0777
deprecation.php File 8.22 KB 0777
di.php File 5.25 KB 0777
emoticon_manager.php File 7.2 KB 0777
encryption.php File 11.56 KB 0777
filetypes.php File 41.35 KB 0777
formatting.php File 15.48 KB 0777
geopattern.php File 1.26 KB 0777
grades_external.php File 8.28 KB 0777
grading_external.php File 24.24 KB 0777
hooks.php File 3.5 KB 0777
http_client.php File 6.36 KB 0777
invalid_persistent_exception.php File 1.56 KB 0777
ip_utils.php File 14.62 KB 0777
lang_string.php File 10.99 KB 0777
locale.php File 2.85 KB 0777
minify.php File 3.65 KB 0777
notification.php File 7.48 KB 0777
param.php File 41.95 KB 0777
param_clientside_regex.php File 1.36 KB 0777
persistent.php File 33.03 KB 0777
php_time_limit.php File 3.8 KB 0777
plugin_manager.php File 76.82 KB 0777
qrcode.php File 1.39 KB 0777
report_helper.php File 6.7 KB 0777
requirejs.php File 4.82 KB 0777
router.php File 8.77 KB 0777
rtlcss.php File 2 KB 0777
scss.php File 6.69 KB 0777
shutdown_manager.php File 9.55 KB 0777
string_manager.php File 5.18 KB 0777
string_manager_install.php File 9.05 KB 0777
string_manager_standard.php File 29.61 KB 0777
system_clock.php File 1.23 KB 0777
text.php File 24.63 KB 0777
url.php File 29.2 KB 0777
user.php File 68.93 KB 0777
useragent.php File 43.7 KB 0777
userfeedback.php File 6.54 KB 0777
uuid.php File 5.1 KB 0777
Filemanager