public function test_replace_ampersands()
 {
     $this->assertSame("This & that  ", replace_ampersands_not_followed_by_entity("This & that  "));
     $this->assertSame("This &nbsp that  ", replace_ampersands_not_followed_by_entity("This &nbsp that  "));
 }
Example #2
0
/**
* Given a simple string, this function returns the string
* processed by enabled string filters if $CFG->filterall is enabled
*
* This function should be used to print short strings (non html) that
* need filter processing e.g. activity titles, post subjects,
* glossary concepts.
*
* @global object
* @global object
* @global object
* @staticvar bool $strcache
* @param string $string The string to be filtered.
* @param boolean $striplinks To strip any link in the result text.
                             Moodle 1.8 default changed from false to true! MDL-8713
* @param array $options options array/object or courseid
* @return string
*/
function format_string($string, $striplinks = true, $options = NULL)
{
    global $CFG, $COURSE, $PAGE;
    //We'll use a in-memory cache here to speed up repeated strings
    static $strcache = false;
    if (empty($CFG->version) or $CFG->version < 2010072800 or during_initial_install()) {
        // do not filter anything during installation or before upgrade completes
        return $string = strip_tags($string);
    }
    if ($strcache === false or count($strcache) > 2000) {
        // this number might need some tuning to limit memory usage in cron
        $strcache = array();
    }
    if (is_numeric($options)) {
        // legacy courseid usage
        $options = array('context' => get_context_instance(CONTEXT_COURSE, $options));
    } else {
        $options = (array) $options;
        // detach object, we can not modify it
    }
    if (empty($options['context'])) {
        // fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(
        $options['context'] = $PAGE->context;
    } else {
        if (is_numeric($options['context'])) {
            $options['context'] = get_context_instance_by_id($options['context']);
        }
    }
    if (!$options['context']) {
        // we did not find any context? weird
        return $string = strip_tags($string);
    }
    //Calculate md5
    $md5 = md5($string . '<+>' . $striplinks . '<+>' . $options['context']->id . '<+>' . current_language());
    //Fetch from cache if possible
    if (isset($strcache[$md5])) {
        return $strcache[$md5];
    }
    // First replace all ampersands not followed by html entity code
    // Regular expression moved to its own method for easier unit testing
    $string = replace_ampersands_not_followed_by_entity($string);
    if (!empty($CFG->filterall)) {
        $string = filter_manager::instance()->filter_string($string, $options['context']);
    }
    // If the site requires it, strip ALL tags from this string
    if (!empty($CFG->formatstringstriptags)) {
        $string = strip_tags($string);
    } else {
        // Otherwise strip just links if that is required (default)
        if ($striplinks) {
            //strip links in string
            $string = strip_links($string);
        }
        $string = clean_text($string);
    }
    //Store to cache
    $strcache[$md5] = $string;
    return $string;
}
Example #3
0
/**
 * Given a simple string, this function returns the string
 * processed by enabled string filters if $CFG->filterall is enabled
 *
 * This function should be used to print short strings (non html) that
 * need filter processing e.g. activity titles, post subjects,
 * glossary concepts.
 *
 * @staticvar bool $strcache
 * @param string $string The string to be filtered. Should be plain text, expect
 * possibly for multilang tags.
 * @param boolean $striplinks To strip any link in the result text. Moodle 1.8 default changed from false to true! MDL-8713
 * @param array $options options array/object or courseid
 * @return string
 */
function format_string($string, $striplinks = true, $options = null)
{
    global $CFG, $PAGE;
    // We'll use a in-memory cache here to speed up repeated strings.
    static $strcache = false;
    if (empty($CFG->version) or $CFG->version < 2013051400 or during_initial_install()) {
        // Do not filter anything during installation or before upgrade completes.
        return $string = strip_tags($string);
    }
    if ($strcache === false or count($strcache) > 2000) {
        // This number might need some tuning to limit memory usage in cron.
        $strcache = array();
    }
    if (is_numeric($options)) {
        // Legacy courseid usage.
        $options = array('context' => context_course::instance($options));
    } else {
        // Detach object, we can not modify it.
        $options = (array) $options;
    }
    if (empty($options['context'])) {
        // Fallback to $PAGE->context this may be problematic in CLI and other non-standard pages :-(.
        $options['context'] = $PAGE->context;
    } else {
        if (is_numeric($options['context'])) {
            $options['context'] = context::instance_by_id($options['context']);
        }
    }
    if (!$options['context']) {
        // We did not find any context? weird.
        return $string = strip_tags($string);
    }
    // Calculate md5.
    $md5 = md5($string . '<+>' . $striplinks . '<+>' . $options['context']->id . '<+>' . current_language());
    // Fetch from cache if possible.
    if (isset($strcache[$md5])) {
        return $strcache[$md5];
    }
    // First replace all ampersands not followed by html entity code
    // Regular expression moved to its own method for easier unit testing.
    $string = replace_ampersands_not_followed_by_entity($string);
    if (!empty($CFG->filterall)) {
        $filtermanager = filter_manager::instance();
        $filtermanager->setup_page_for_filters($PAGE, $options['context']);
        // Setup global stuff filters may have.
        $string = $filtermanager->filter_string($string, $options['context']);
    }
    // If the site requires it, strip ALL tags from this string.
    if (!empty($CFG->formatstringstriptags)) {
        $string = str_replace(array('<', '>'), array('&lt;', '&gt;'), strip_tags($string));
    } else {
        // Otherwise strip just links if that is required (default).
        if ($striplinks) {
            // Strip links in string.
            $string = strip_links($string);
        }
        $string = clean_text($string);
    }
    // Store to cache.
    $strcache[$md5] = $string;
    return $string;
}
Example #4
0
 function test_replace_ampersands() {
     $this->assertEquals(replace_ampersands_not_followed_by_entity("This & that &nbsp;"), "This &amp; that &nbsp;");
     $this->assertEquals(replace_ampersands_not_followed_by_entity("This &nbsp that &nbsp;"), "This &amp;nbsp that &nbsp;");
 }
Example #5
0
 /**
  * Get all linked global concepts.
  * @return array
  */
 protected static function get_global_concepts()
 {
     global $DB;
     $cache = \cache::make('mod_glossary', 'concepts');
     $data = $cache->get(0);
     if (is_array($data)) {
         list($glossaries, $allconcepts) = $data;
     } else {
         // Find all global glossaries - no access control here.
         $sql = "SELECT g.id, g.name\n                      FROM {glossary} g\n                      JOIN {course_modules} cm ON (cm.instance = g.id)\n                      JOIN {modules} m ON (m.name = 'glossary' AND m.id = cm.module)\n                     WHERE g.usedynalink = 1 AND g.globalglossary = 1 AND cm.visible = 1 AND m.visible = 1\n                  ORDER BY g.globalglossary, g.id";
         $glossaries = $DB->get_records_sql_menu($sql);
         if (!$glossaries) {
             $data = array(array(), array());
             $cache->set(0, $data);
             return $data;
         }
         foreach ($glossaries as $id => $name) {
             $name = str_replace(':', '-', $name);
             $glossaries[$id] = replace_ampersands_not_followed_by_entity(strip_tags($name));
         }
         $allconcepts = self::fetch_concepts(array_keys($glossaries));
         foreach ($glossaries as $gid => $unused) {
             if (!isset($allconcepts[$gid])) {
                 unset($glossaries[$gid]);
             }
         }
         $cache->set(0, array($glossaries, $allconcepts));
     }
     // NOTE: no access control is here because it would be way too expensive to check access
     //       to all courses that contain the global glossaries.
     return array($glossaries, $allconcepts);
 }
 public function filter($text, array $options = array())
 {
     global $CFG, $DB, $GLOSSARY_EXCLUDECONCEPTS;
     // Trivial-cache - keyed on $cachedcontextid
     static $cachedcontextid;
     static $conceptlist;
     static $nothingtodo;
     // To avoid processing if no glossaries / concepts are found
     // Try to get current course.
     $coursectx = $this->context->get_course_context(false);
     if (!$coursectx) {
         $courseid = 0;
     } else {
         $courseid = $coursectx->instanceid;
     }
     // Initialise/invalidate our trivial cache if dealing with a different context
     if (!isset($cachedcontextid) || $cachedcontextid !== $this->context->id) {
         $cachedcontextid = $this->context->id;
         $conceptlist = array();
         $nothingtodo = false;
     }
     if ($nothingtodo === true || !has_capability('mod/glossary:view', $this->context)) {
         return $text;
     }
     // Create a list of all the concepts to search for.  It may be cached already.
     if (empty($conceptlist)) {
         // Find all the glossaries we need to examine
         if (!($glossaries = $DB->get_records_sql_menu('
                 SELECT g.id, g.name
                   FROM {glossary} g, {course_modules} cm, {modules} m
                  WHERE m.name = \'glossary\'
                    AND cm.module = m.id
                    AND cm.visible = 1
                    AND g.id = cm.instance
                    AND g.usedynalink != 0
                    AND (g.course = ? OR g.globalglossary = 1)
               ORDER BY g.globalglossary, g.id', array($courseid)))) {
             $nothingtodo = true;
             return $text;
         }
         // Make a list of glossary IDs for searching
         $glossarylist = implode(',', array_keys($glossaries));
         // Pull out all the raw data from the database for entries, categories and aliases
         $entries = $DB->get_records_select('glossary_entries', 'glossaryid IN (' . $glossarylist . ') AND usedynalink != 0 AND approved != 0 ', null, '', 'id,glossaryid, concept, casesensitive, 0 AS category, fullmatch');
         $categories = $DB->get_records_select('glossary_categories', 'glossaryid IN (' . $glossarylist . ') AND usedynalink != 0', null, '', 'id,glossaryid,name AS concept, 1 AS casesensitive, 1 AS category, 1 AS fullmatch');
         $aliases = $DB->get_records_sql('
                 SELECT ga.id, ge.id AS entryid, ge.glossaryid,
                        ga.alias AS concept, ge.concept AS originalconcept,
                        casesensitive, 0 AS category, fullmatch
                   FROM {glossary_alias} ga,
                        {glossary_entries} ge
                   WHERE ga.entryid = ge.id
                     AND ge.glossaryid IN (' . $glossarylist . ')
                     AND ge.usedynalink != 0
                     AND ge.approved != 0', null);
         // Combine them into one big list
         $concepts = array();
         if ($entries and $categories) {
             $concepts = array_merge($entries, $categories);
         } else {
             if ($categories) {
                 $concepts = $categories;
             } else {
                 if ($entries) {
                     $concepts = $entries;
                 }
             }
         }
         if ($aliases) {
             $concepts = array_merge($concepts, $aliases);
         }
         if (!empty($concepts)) {
             foreach ($concepts as $key => $concept) {
                 // Trim empty or unlinkable concepts
                 $currentconcept = trim(strip_tags($concept->concept));
                 // Concept must be HTML-escaped, so do the same as format_string
                 // to turn ampersands into &amp;.
                 $currentconcept = replace_ampersands_not_followed_by_entity($currentconcept);
                 if (empty($currentconcept)) {
                     unset($concepts[$key]);
                     continue;
                 } else {
                     $concepts[$key]->concept = $currentconcept;
                 }
                 // Rule out any small integers.  See bug 1446
                 $currentint = intval($currentconcept);
                 if ($currentint && strval($currentint) == $currentconcept && $currentint < 1000) {
                     unset($concepts[$key]);
                 }
             }
         }
         if (empty($concepts)) {
             $nothingtodo = true;
             return $text;
         }
         usort($concepts, 'filter_glossary::sort_entries_by_length');
         $strcategory = get_string('category', 'glossary');
         // Loop through all the concepts, setting up our data structure for the filter
         $conceptlist = array();
         // We will store all the concepts here
         foreach ($concepts as $concept) {
             $glossaryname = str_replace(':', '-', $glossaries[$concept->glossaryid]);
             if ($concept->category) {
                 // Link to a category
                 // TODO: Fix this string usage
                 $title = strip_tags($glossaryname . ': ' . $strcategory . ' ' . $concept->concept);
                 $href_tag_begin = '<a class="glossary autolink category glossaryid' . $concept->glossaryid . '" title="' . $title . '" ' . 'href="' . $CFG->wwwroot . '/mod/glossary/view.php?g=' . $concept->glossaryid . '&amp;mode=cat&amp;hook=' . $concept->id . '">';
             } else {
                 // Link to entry or alias
                 if (!empty($concept->originalconcept)) {
                     // We are dealing with an alias (so show and point to original)
                     $title = str_replace('"', "'", html_entity_decode(strip_tags($glossaryname . ': ' . $concept->originalconcept)));
                     $concept->id = $concept->entryid;
                 } else {
                     // This is an entry
                     // We need to remove entities from the content here because it
                     // will be escaped by html_writer below.
                     $title = str_replace('"', "'", html_entity_decode(strip_tags($glossaryname . ': ' . $concept->concept)));
                 }
                 // hardcoding dictionary format in the URL rather than defaulting
                 // to the current glossary format which may not work in a popup.
                 // for example "entry list" means the popup would only contain
                 // a link that opens another popup.
                 $link = new moodle_url('/mod/glossary/showentry.php', array('courseid' => $courseid, 'eid' => $concept->id, 'displayformat' => 'dictionary'));
                 $attributes = array('href' => $link, 'title' => $title, 'class' => 'glossary autolink concept glossaryid' . $concept->glossaryid);
                 // this flag is optionally set by resource_pluginfile()
                 // if processing an embedded file use target to prevent getting nested Moodles
                 if (isset($CFG->embeddedsoforcelinktarget) && $CFG->embeddedsoforcelinktarget) {
                     $attributes['target'] = '_top';
                 }
                 $href_tag_begin = html_writer::start_tag('a', $attributes);
             }
             $conceptlist[] = new filterobject($concept->concept, $href_tag_begin, '</a>', $concept->casesensitive, $concept->fullmatch);
         }
         $conceptlist = filter_remove_duplicates($conceptlist);
     }
     if (!empty($GLOSSARY_EXCLUDECONCEPTS)) {
         $reducedconceptlist = array();
         foreach ($conceptlist as $concept) {
             if (!in_array($concept->phrase, $GLOSSARY_EXCLUDECONCEPTS)) {
                 $reducedconceptlist[] = $concept;
             }
         }
         return filter_phrases($text, $reducedconceptlist);
     }
     return filter_phrases($text, $conceptlist);
     // Actually search for concepts!
 }
Example #7
0
/**
* Given a simple string, this function returns the string
* processed by enabled string filters if $CFG->filterall is enabled
*
* This function should be used to print short strings (non html) that
* need filter processing e.g. activity titles, post subjects,
* glossary concepts.
*
* @global object
* @global object
* @global object
* @staticvar bool $strcache
* @param string $string The string to be filtered.
* @param boolean $striplinks To strip any link in the result text.
                             Moodle 1.8 default changed from false to true! MDL-8713
* @param int $courseid Current course as filters can, potentially, use it
* @return string
*/
function format_string($string, $striplinks = true, $courseid = NULL)
{
    global $CFG, $COURSE, $PAGE;
    //We'll use a in-memory cache here to speed up repeated strings
    static $strcache = false;
    if ($strcache === false or count($strcache) > 2000) {
        // this number might need some tuning to limit memory usage in cron
        $strcache = array();
    }
    //init course id
    if (empty($courseid)) {
        $courseid = $COURSE->id;
    }
    //Calculate md5
    $md5 = md5($string . '<+>' . $striplinks . '<+>' . $courseid . '<+>' . current_language());
    //Fetch from cache if possible
    if (isset($strcache[$md5])) {
        return $strcache[$md5];
    }
    // First replace all ampersands not followed by html entity code
    // Regular expression moved to its own method for easier unit testing
    $string = replace_ampersands_not_followed_by_entity($string);
    if (!empty($CFG->filterall) && $CFG->version >= 2009040600) {
        // Avoid errors during the upgrade to the new system.
        $context = $PAGE->context;
        $string = filter_manager::instance()->filter_string($string, $context, $courseid);
    }
    // If the site requires it, strip ALL tags from this string
    if (!empty($CFG->formatstringstriptags)) {
        $string = strip_tags($string);
    } else {
        // Otherwise strip just links if that is required (default)
        if ($striplinks) {
            //strip links in string
            $string = strip_links($string);
        }
        $string = clean_text($string);
    }
    //Store to cache
    $strcache[$md5] = $string;
    return $string;
}