first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
@@ -0,0 +1,46 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Privacy Subsystem implementation for repository_url.
*
* @package repository_url
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace repository_url\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy Subsystem for repository_url implementing null_provider.
*
* @copyright 2018 Zig Tan <zig@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}
+37
View File
@@ -0,0 +1,37 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Plugin capabilities.
*
* @package repository_url
* @copyright 2009 Dongsheng Cai
* @author Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$capabilities = array(
'repository/url:view' => array(
'captype' => 'read',
'contextlevel' => CONTEXT_MODULE,
'archetypes' => array(
'user' => CAP_ALLOW
)
)
);
+39
View File
@@ -0,0 +1,39 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Installation for the URL repository
*
* @package repository_url
* @category repository
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* Create a default instance of the URL repository
*
* @return bool A status indicating success or failure
*/
function xmldb_repository_url_install() {
global $CFG;
$result = true;
require_once($CFG->dirroot.'/repository/lib.php');
$urlplugin = new repository_type('url', array(), true);
if(!$id = $urlplugin->create(true)) {
$result = false;
}
return $result;
}
+34
View File
@@ -0,0 +1,34 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Strings for component 'repository_url', language 'en', branch 'MOODLE_20_STABLE'
*
* @package repository_url
* @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['download'] = 'Download';
$string['rename'] = 'Name';
$string['pluginname'] = 'URL downloader';
$string['url'] = 'URL';
$string['url:view'] = 'Use URL downloader in file picker';
$string['validname'] = 'You must provide a valid file name';
$string['configplugin'] = 'URL repository type configuration';
$string['validfiletype'] = 'You must provide a URL to an image file or a page containing images.';
$string['privacy:metadata'] = 'The URL downloader repository plugin does not store or transmit any personal data.';
+300
View File
@@ -0,0 +1,300 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* This plugin is used to access files by providing an url
*
* @since Moodle 2.0
* @package repository_url
* @copyright 2010 Dongsheng Cai {@link http://dongsheng.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->dirroot . '/repository/lib.php');
require_once(__DIR__.'/locallib.php');
/**
* repository_url class
* A subclass of repository, which is used to download a file from a specific url
*
* @since Moodle 2.0
* @package repository_url
* @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class repository_url extends repository {
/** @var int Maximum time of recursion. */
const MAX_RECURSION_TIME = 5;
/** @var int Maximum number of CSS imports. */
protected const MAX_CSS_IMPORTS = 10;
/** @var int CSS import counter. */
protected int $cssimportcounter = 0;
var $processedfiles = array();
/** @var int Recursion counter. */
var $recursioncounter = 0;
/** @var string file URL. */
public $file_url;
/**
* @param int $repositoryid
* @param object $context
* @param array $options
*/
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()){
global $CFG;
parent::__construct($repositoryid, $context, $options);
$this->file_url = optional_param('file', '', PARAM_RAW);
$this->file_url = $this->escape_url($this->file_url);
}
public function check_login() {
if (!empty($this->file_url)) {
return true;
} else {
return false;
}
}
/**
* @return mixed
*/
public function print_login() {
$strdownload = get_string('download', 'repository');
$strname = get_string('rename', 'repository_url');
$strurl = get_string('url', 'repository_url');
if ($this->options['ajax']) {
$url = new stdClass();
$url->label = $strurl.': ';
$url->id = 'fileurl';
$url->type = 'text';
$url->name = 'file';
$ret['login'] = array($url);
$ret['login_btn_label'] = get_string('download', 'repository_url');
$ret['allowcaching'] = true; // indicates that login form can be cached in filepicker.js
return $ret;
} else {
echo <<<EOD
<table>
<tr>
<td>{$strurl}: </td><td><input name="file" type="text" /></td>
</tr>
</table>
<input type="submit" value="{$strdownload}" />
EOD;
}
}
/**
* @param mixed $path
* @param string $search
* @return array
*/
public function get_listing($path='', $page='') {
$ret = array();
$ret['list'] = array();
$ret['nosearch'] = true;
$ret['norefresh'] = true;
$ret['nologin'] = true;
$this->file_url = clean_param($this->file_url, PARAM_URL);
if (empty($this->file_url)) {
throw new repository_exception('validfiletype', 'repository_url');
}
$this->parse_file(null, $this->file_url, $ret, true);
return $ret;
}
/**
* Parses one file (either html or css)
*
* @param string $baseurl (optional) URL of the file where link to this file was found
* @param string $relativeurl relative or absolute link to the file
* @param array $list
* @param bool $mainfile true only for main HTML false and false for all embedded/linked files
*/
protected function parse_file($baseurl, $relativeurl, &$list, $mainfile = false) {
if (preg_match('/([\'"])(.*)\1/', $relativeurl, $matches)) {
$relativeurl = $matches[2];
}
if (empty($baseurl)) {
$url = $relativeurl;
} else {
$url = htmlspecialchars_decode(url_to_absolute($baseurl, $relativeurl), ENT_COMPAT);
}
if (in_array($url, $this->processedfiles)) {
// Avoid endless recursion for the same URL with same parameters.
return;
}
// Remove the query string and anchors before check.
$recursioncheckurl = (new moodle_url($url))->out_omit_querystring();
if (in_array($recursioncheckurl, $this->processedfiles)) {
$this->recursioncounter++;
}
if ($this->recursioncounter >= self::MAX_RECURSION_TIME) {
// Avoid endless recursion for the same URL with different parameters.
return;
}
$this->processedfiles[] = $url;
$curl = new curl;
$curl->setopt(array('CURLOPT_FOLLOWLOCATION' => true, 'CURLOPT_MAXREDIRS' => 3));
$msg = $curl->head($url);
$info = $curl->get_info();
if ($info['http_code'] != 200) {
if ($mainfile) {
$list['error'] = $msg;
}
} else {
$csstoanalyze = '';
if ($mainfile && (strstr($info['content_type'], 'text/html') || empty($info['content_type']))) {
// parse as html
$htmlcontent = $curl->get($info['url']);
$ddoc = new DOMDocument();
@$ddoc->loadHTML($htmlcontent);
// extract <img>
$tags = $ddoc->getElementsByTagName('img');
foreach ($tags as $tag) {
$url = $tag->getAttribute('src');
$this->add_image_to_list($info['url'], $url, $list);
}
// analyse embedded css (<style>)
$tags = $ddoc->getElementsByTagName('style');
foreach ($tags as $tag) {
if ($tag->getAttribute('type') == 'text/css') {
$csstoanalyze .= $tag->textContent."\n";
}
}
// analyse links to css (<link type='text/css' href='...'>)
$tags = $ddoc->getElementsByTagName('link');
foreach ($tags as $tag) {
if ($tag->getAttribute('type') == 'text/css' && strlen($tag->getAttribute('href'))) {
$this->parse_file($info['url'], $tag->getAttribute('href'), $list);
}
}
} else if (strstr($info['content_type'], 'css')) {
// parse as css
$csscontent = $curl->get($info['url']);
$csstoanalyze .= $csscontent."\n";
} else if (strstr($info['content_type'], 'image/')) {
// download this file
$this->add_image_to_list($info['url'], $info['url'], $list);
} else {
$list['error'] = get_string('validfiletype', 'repository_url');
}
// parse all found css styles
if (strlen($csstoanalyze)) {
$urls = extract_css_urls($csstoanalyze);
if (!empty($urls['property'])) {
foreach ($urls['property'] as $url) {
$this->add_image_to_list($info['url'], $url, $list);
}
}
if (!empty($urls['import'])) {
foreach ($urls['import'] as $cssurl) {
// Limit the number of CSS imports to avoid infinite imports.
if ($this->cssimportcounter >= self::MAX_CSS_IMPORTS) {
return;
}
$this->cssimportcounter++;
$this->parse_file($info['url'], $cssurl, $list);
}
}
}
}
}
protected function add_image_to_list($baseurl, $url, &$list) {
if (empty($list['list'])) {
$list['list'] = array();
}
$src = url_to_absolute($baseurl, htmlspecialchars_decode($url, ENT_COMPAT));
foreach ($list['list'] as $image) {
if ($image['source'] == $src) {
return;
}
}
$list['list'][] = array(
'title'=>$this->guess_filename($url, ''),
'source'=>$src,
'thumbnail'=>$src,
'thumbnail_height'=>84,
'thumbnail_width'=>84
);
}
public function guess_filename($url, $type) {
$pattern = '#\/([\w_\?\-.]+)$#';
$matches = null;
preg_match($pattern, $url, $matches);
if (empty($matches[1])) {
return $url;
} else {
return $matches[1];
}
}
/**
* Escapes a url by replacing spaces with %20.
*
* Note: In general moodle does not automatically escape urls, but for the purposes of making this plugin more user friendly
* and make it consistent with some other areas in moodle (such as mod_url), urls will automatically be escaped.
*
* If moodle_url or PARAM_URL is changed to clean characters that need to be escaped, then this function can be removed
*
* @param string $url An unescaped url.
* @return string The escaped url
*/
protected function escape_url($url) {
$url = str_replace('"', '%22', $url);
$url = str_replace('\'', '%27', $url);
$url = str_replace(' ', '%20', $url);
$url = str_replace('<', '%3C', $url);
$url = str_replace('>', '%3E', $url);
return $url;
}
public function supported_returntypes() {
return (FILE_INTERNAL | FILE_EXTERNAL);
}
/**
* Return the source information
*
* @param stdClass $url
* @return string|null
*/
public function get_file_source_info($url) {
return $url;
}
/**
* file types supported by url downloader plugin
*
* @return array
*/
public function supported_filetypes() {
return array('web_image');
}
/**
* Is this repository accessing private data?
*
* @return bool
*/
public function contains_private_data() {
return false;
}
}
+756
View File
@@ -0,0 +1,756 @@
<?php
/**
* Copyright (c) 2008, David R. Nadeau, NadeauSoftware.com.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* * Neither the names of David R. Nadeau or NadeauSoftware.com, nor
* the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/*
* This is a BSD License approved by the Open Source Initiative (OSI).
* See: http://www.opensource.org/licenses/bsd-license.php
*/
defined('MOODLE_INTERNAL') || die();
/**
* Combine a base URL and a relative URL to produce a new
* absolute URL. The base URL is often the URL of a page,
* and the relative URL is a URL embedded on that page.
*
* This function implements the "absolutize" algorithm from
* the RFC3986 specification for URLs.
*
* This function supports multi-byte characters with the UTF-8 encoding,
* per the URL specification.
*
* Parameters:
* baseUrl the absolute base URL.
*
* url the relative URL to convert.
*
* Return values:
* An absolute URL that combines parts of the base and relative
* URLs, or FALSE if the base URL is not absolute or if either
* URL cannot be parsed.
*/
function url_to_absolute( $baseUrl, $relativeUrl )
{
// If relative URL has a scheme, clean path and return.
$r = split_url( $relativeUrl );
if ( $r === FALSE )
return FALSE;
if ( !empty( $r['scheme'] ) )
{
if ( !empty( $r['path'] ) && $r['path'][0] == '/' )
$r['path'] = url_remove_dot_segments( $r['path'] );
return join_url( $r );
}
// Make sure the base URL is absolute.
$b = split_url( $baseUrl );
if ( $b === FALSE || empty( $b['scheme'] ) || empty( $b['host'] ) )
return FALSE;
$r['scheme'] = $b['scheme'];
if (empty($b['path'])) {
$b['path'] = '';
}
// If relative URL has an authority, clean path and return.
if ( isset( $r['host'] ) )
{
if ( !empty( $r['path'] ) )
$r['path'] = url_remove_dot_segments( $r['path'] );
return join_url( $r );
}
unset( $r['port'] );
unset( $r['user'] );
unset( $r['pass'] );
// Copy base authority.
$r['host'] = $b['host'];
if ( isset( $b['port'] ) ) $r['port'] = $b['port'];
if ( isset( $b['user'] ) ) $r['user'] = $b['user'];
if ( isset( $b['pass'] ) ) $r['pass'] = $b['pass'];
// If relative URL has no path, use base path
if ( empty( $r['path'] ) )
{
if ( !empty( $b['path'] ) )
$r['path'] = $b['path'];
if ( !isset( $r['query'] ) && isset( $b['query'] ) )
$r['query'] = $b['query'];
return join_url( $r );
}
// If relative URL path doesn't start with /, merge with base path.
if ($r['path'][0] != '/') {
$base = core_text::strrchr($b['path'], '/', TRUE);
if ($base === FALSE) {
$base = '';
}
$r['path'] = $base . '/' . $r['path'];
}
$r['path'] = url_remove_dot_segments($r['path']);
return join_url($r);
}
/**
* Filter out "." and ".." segments from a URL's path and return
* the result.
*
* This function implements the "remove_dot_segments" algorithm from
* the RFC3986 specification for URLs.
*
* This function supports multi-byte characters with the UTF-8 encoding,
* per the URL specification.
*
* Parameters:
* path the path to filter
*
* Return values:
* The filtered path with "." and ".." removed.
*/
function url_remove_dot_segments( $path )
{
// multi-byte character explode
$inSegs = preg_split( '!/!u', $path );
$outSegs = array( );
foreach ( $inSegs as $seg )
{
if ( $seg == '' || $seg == '.')
continue;
if ( $seg == '..' )
array_pop( $outSegs );
else
array_push( $outSegs, $seg );
}
$outPath = implode( '/', $outSegs );
if ($path[0] == '/') {
$outPath = '/' . $outPath;
}
// Compare last multi-byte character against '/'.
if ($outPath != '/' && (core_text::strlen($path) - 1) == core_text::strrpos($path, '/', 'UTF-8')) {
$outPath .= '/';
}
return $outPath;
}
/**
* This function parses an absolute or relative URL and splits it
* into individual components.
*
* RFC3986 specifies the components of a Uniform Resource Identifier (URI).
* A portion of the ABNFs are repeated here:
*
* URI-reference = URI
* / relative-ref
*
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
*
* relative-ref = relative-part [ "?" query ] [ "#" fragment ]
*
* hier-part = "//" authority path-abempty
* / path-absolute
* / path-rootless
* / path-empty
*
* relative-part = "//" authority path-abempty
* / path-absolute
* / path-noscheme
* / path-empty
*
* authority = [ userinfo "@" ] host [ ":" port ]
*
* So, a URL has the following major components:
*
* scheme
* The name of a method used to interpret the rest of
* the URL. Examples: "http", "https", "mailto", "file'.
*
* authority
* The name of the authority governing the URL's name
* space. Examples: "example.com", "user@example.com",
* "example.com:80", "user:password@example.com:80".
*
* The authority may include a host name, port number,
* user name, and password.
*
* The host may be a name, an IPv4 numeric address, or
* an IPv6 numeric address.
*
* path
* The hierarchical path to the URL's resource.
* Examples: "/index.htm", "/scripts/page.php".
*
* query
* The data for a query. Examples: "?search=google.com".
*
* fragment
* The name of a secondary resource relative to that named
* by the path. Examples: "#section1", "#header".
*
* An "absolute" URL must include a scheme and path. The authority, query,
* and fragment components are optional.
*
* A "relative" URL does not include a scheme and must include a path. The
* authority, query, and fragment components are optional.
*
* This function splits the $url argument into the following components
* and returns them in an associative array. Keys to that array include:
*
* "scheme" The scheme, such as "http".
* "host" The host name, IPv4, or IPv6 address.
* "port" The port number.
* "user" The user name.
* "pass" The user password.
* "path" The path, such as a file path for "http".
* "query" The query.
* "fragment" The fragment.
*
* One or more of these may not be present, depending upon the URL.
*
* Optionally, the "user", "pass", "host" (if a name, not an IP address),
* "path", "query", and "fragment" may have percent-encoded characters
* decoded. The "scheme" and "port" cannot include percent-encoded
* characters and are never decoded. Decoding occurs after the URL has
* been parsed.
*
* Parameters:
* url the URL to parse.
*
* decode an optional boolean flag selecting whether
* to decode percent encoding or not. Default = TRUE.
*
* Return values:
* the associative array of URL parts, or FALSE if the URL is
* too malformed to recognize any parts.
*/
function split_url( $url, $decode=FALSE)
{
// Character sets from RFC3986.
$xunressub = 'a-zA-Z\d\-._~\!$&\'()*+,;=';
$xpchar = $xunressub . ':@% ';
// Scheme from RFC3986.
$xscheme = '([a-zA-Z][a-zA-Z\d+-.]*)';
// User info (user + password) from RFC3986.
$xuserinfo = '(([' . $xunressub . '%]*)' .
'(:([' . $xunressub . ':%]*))?)';
// IPv4 from RFC3986 (without digit constraints).
$xipv4 = '(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})';
// IPv6 from RFC2732 (without digit and grouping constraints).
$xipv6 = '(\[([a-fA-F\d.:]+)\])';
// Host name from RFC1035. Technically, must start with a letter.
// Relax that restriction to better parse URL structure, then
// leave host name validation to application.
$xhost_name = '([a-zA-Z\d\-.%]+)';
// Authority from RFC3986. Skip IP future.
$xhost = '(' . $xhost_name . '|' . $xipv4 . '|' . $xipv6 . ')';
$xport = '(\d*)';
$xauthority = '((' . $xuserinfo . '@)?' . $xhost .
'?(:' . $xport . ')?)';
// Path from RFC3986. Blend absolute & relative for efficiency.
$xslash_seg = '(/[' . $xpchar . ']*)';
$xpath_authabs = '((//' . $xauthority . ')((/[' . $xpchar . ']*)*))';
$xpath_rel = '([' . $xpchar . ']+' . $xslash_seg . '*)';
$xpath_abs = '(/(' . $xpath_rel . ')?)';
$xapath = '(' . $xpath_authabs . '|' . $xpath_abs .
'|' . $xpath_rel . ')';
// Query and fragment from RFC3986.
$xqueryfrag = '([' . $xpchar . '/?' . ']*)';
// URL.
$xurl = '^(' . $xscheme . ':)?' . $xapath . '?' .
'(\?' . $xqueryfrag . ')?(#' . $xqueryfrag . ')?$';
// Split the URL into components.
if ( !preg_match( '!' . $xurl . '!', $url, $m ) )
return FALSE;
if ( !empty($m[2]) ) $parts['scheme'] = strtolower($m[2]);
if ( !empty($m[7]) ) {
if ( isset( $m[9] ) ) $parts['user'] = $m[9];
else $parts['user'] = '';
}
if ( !empty($m[10]) ) $parts['pass'] = $m[11];
if ( !empty($m[13]) ) $h=$parts['host'] = $m[13];
else if ( !empty($m[14]) ) $parts['host'] = $m[14];
else if ( !empty($m[16]) ) $parts['host'] = $m[16];
else if ( !empty( $m[5] ) ) $parts['host'] = '';
if ( !empty($m[17]) ) $parts['port'] = $m[18];
if ( !empty($m[19]) ) $parts['path'] = $m[19];
else if ( !empty($m[21]) ) $parts['path'] = $m[21];
else if ( !empty($m[25]) ) $parts['path'] = $m[25];
if ( !empty($m[27]) ) $parts['query'] = $m[28];
if ( !empty($m[29]) ) $parts['fragment']= $m[30];
if ( !$decode )
return $parts;
if ( !empty($parts['user']) )
$parts['user'] = rawurldecode( $parts['user'] );
if ( !empty($parts['pass']) )
$parts['pass'] = rawurldecode( $parts['pass'] );
if ( !empty($parts['path']) )
$parts['path'] = rawurldecode( $parts['path'] );
if ( isset($h) )
$parts['host'] = rawurldecode( $parts['host'] );
if ( !empty($parts['query']) )
$parts['query'] = rawurldecode( $parts['query'] );
if ( !empty($parts['fragment']) )
$parts['fragment'] = rawurldecode( $parts['fragment'] );
return $parts;
}
/**
* This function joins together URL components to form a complete URL.
*
* RFC3986 specifies the components of a Uniform Resource Identifier (URI).
* This function implements the specification's "component recomposition"
* algorithm for combining URI components into a full URI string.
*
* The $parts argument is an associative array containing zero or
* more of the following:
*
* "scheme" The scheme, such as "http".
* "host" The host name, IPv4, or IPv6 address.
* "port" The port number.
* "user" The user name.
* "pass" The user password.
* "path" The path, such as a file path for "http".
* "query" The query.
* "fragment" The fragment.
*
* The "port", "user", and "pass" values are only used when a "host"
* is present.
*
* The optional $encode argument indicates if appropriate URL components
* should be percent-encoded as they are assembled into the URL. Encoding
* is only applied to the "user", "pass", "host" (if a host name, not an
* IP address), "path", "query", and "fragment" components. The "scheme"
* and "port" are never encoded. When a "scheme" and "host" are both
* present, the "path" is presumed to be hierarchical and encoding
* processes each segment of the hierarchy separately (i.e., the slashes
* are left alone).
*
* The assembled URL string is returned.
*
* Parameters:
* parts an associative array of strings containing the
* individual parts of a URL.
*
* encode an optional boolean flag selecting whether
* to do percent encoding or not. Default = true.
*
* Return values:
* Returns the assembled URL string. The string is an absolute
* URL if a scheme is supplied, and a relative URL if not. An
* empty string is returned if the $parts array does not contain
* any of the needed values.
*/
function join_url( $parts, $encode=FALSE)
{
if ( $encode )
{
if ( isset( $parts['user'] ) )
$parts['user'] = rawurlencode( $parts['user'] );
if ( isset( $parts['pass'] ) )
$parts['pass'] = rawurlencode( $parts['pass'] );
if ( isset( $parts['host'] ) &&
!preg_match( '!^(\[[\da-f.:]+\]])|([\da-f.:]+)$!ui', $parts['host'] ) )
$parts['host'] = rawurlencode( $parts['host'] );
if ( !empty( $parts['path'] ) )
$parts['path'] = preg_replace( '!%2F!ui', '/',
rawurlencode( $parts['path'] ) );
if ( isset( $parts['query'] ) )
$parts['query'] = rawurlencode( $parts['query'] );
if ( isset( $parts['fragment'] ) )
$parts['fragment'] = rawurlencode( $parts['fragment'] );
}
$url = '';
if ( !empty( $parts['scheme'] ) )
$url .= $parts['scheme'] . ':';
if ( isset( $parts['host'] ) )
{
$url .= '//';
if ( isset( $parts['user'] ) )
{
$url .= $parts['user'];
if ( isset( $parts['pass'] ) )
$url .= ':' . $parts['pass'];
$url .= '@';
}
if ( preg_match( '!^[\da-f]*:[\da-f.:]+$!ui', $parts['host'] ) )
$url .= '[' . $parts['host'] . ']'; // IPv6
else
$url .= $parts['host']; // IPv4 or name
if ( isset( $parts['port'] ) )
$url .= ':' . $parts['port'];
if ( !empty( $parts['path'] ) && $parts['path'][0] != '/' )
$url .= '/';
}
if ( !empty( $parts['path'] ) )
$url .= $parts['path'];
if ( isset( $parts['query'] ) )
$url .= '?' . $parts['query'];
if ( isset( $parts['fragment'] ) )
$url .= '#' . $parts['fragment'];
return $url;
}
/**
* This function encodes URL to form a URL which is properly
* percent encoded to replace disallowed characters.
*
* RFC3986 specifies the allowed characters in the URL as well as
* reserved characters in the URL. This function replaces all the
* disallowed characters in the URL with their repective percent
* encodings. Already encoded characters are not encoded again,
* such as '%20' is not encoded to '%2520'.
*
* Parameters:
* url the url to encode.
*
* Return values:
* Returns the encoded URL string.
*/
function encode_url($url) {
$reserved = array(
":" => '!%3A!ui',
"/" => '!%2F!ui',
"?" => '!%3F!ui',
"#" => '!%23!ui',
"[" => '!%5B!ui',
"]" => '!%5D!ui',
"@" => '!%40!ui',
"!" => '!%21!ui',
"$" => '!%24!ui',
"&" => '!%26!ui',
"'" => '!%27!ui',
"(" => '!%28!ui',
")" => '!%29!ui',
"*" => '!%2A!ui',
"+" => '!%2B!ui',
"," => '!%2C!ui',
";" => '!%3B!ui',
"=" => '!%3D!ui',
"%" => '!%25!ui',
);
$url = rawurlencode($url);
$url = preg_replace(array_values($reserved), array_keys($reserved), $url);
return $url;
}
/**
* Extract URLs from a web page.
*
* URLs are extracted from a long list of tags and attributes as defined
* by the HTML 2.0, HTML 3.2, HTML 4.01, and draft HTML 5.0 specifications.
* URLs are also extracted from tags and attributes that are common
* extensions of HTML, from the draft Forms 2.0 specification, from XHTML,
* and from WML 1.3 and 2.0.
*
* The function returns an associative array of associative arrays of
* arrays of URLs. The outermost array's keys are the tag (element) name,
* such as "a" for <a> or "img" for <img>. The values for these entries
* are associative arrays where the keys are attribute names for those
* tags, such as "href" for <a href="...">. Finally, the values for
* those arrays are URLs found in those tags and attributes throughout
* the text.
*
* Parameters:
* text the UTF-8 text to scan
*
* Return values:
* an associative array where keys are tags and values are an
* associative array where keys are attributes and values are
* an array of URLs.
*
* See:
* http://nadeausoftware.com/articles/2008/01/php_tip_how_extract_urls_web_page
*/
function extract_html_urls( $text )
{
$match_elements = array(
// HTML
array('element'=>'a', 'attribute'=>'href'), // 2.0
array('element'=>'a', 'attribute'=>'urn'), // 2.0
array('element'=>'base', 'attribute'=>'href'), // 2.0
array('element'=>'form', 'attribute'=>'action'), // 2.0
array('element'=>'img', 'attribute'=>'src'), // 2.0
array('element'=>'link', 'attribute'=>'href'), // 2.0
array('element'=>'applet', 'attribute'=>'code'), // 3.2
array('element'=>'applet', 'attribute'=>'codebase'), // 3.2
array('element'=>'area', 'attribute'=>'href'), // 3.2
array('element'=>'body', 'attribute'=>'background'), // 3.2
array('element'=>'img', 'attribute'=>'usemap'), // 3.2
array('element'=>'input', 'attribute'=>'src'), // 3.2
array('element'=>'applet', 'attribute'=>'archive'), // 4.01
array('element'=>'applet', 'attribute'=>'object'), // 4.01
array('element'=>'blockquote', 'attribute'=>'cite'), // 4.01
array('element'=>'del', 'attribute'=>'cite'), // 4.01
array('element'=>'frame', 'attribute'=>'longdesc'), // 4.01
array('element'=>'frame', 'attribute'=>'src'), // 4.01
array('element'=>'head', 'attribute'=>'profile'), // 4.01
array('element'=>'iframe', 'attribute'=>'longdesc'), // 4.01
array('element'=>'iframe', 'attribute'=>'src'), // 4.01
array('element'=>'img', 'attribute'=>'longdesc'), // 4.01
array('element'=>'input', 'attribute'=>'usemap'), // 4.01
array('element'=>'ins', 'attribute'=>'cite'), // 4.01
array('element'=>'object', 'attribute'=>'archive'), // 4.01
array('element'=>'object', 'attribute'=>'classid'), // 4.01
array('element'=>'object', 'attribute'=>'codebase'), // 4.01
array('element'=>'object', 'attribute'=>'data'), // 4.01
array('element'=>'object', 'attribute'=>'usemap'), // 4.01
array('element'=>'q', 'attribute'=>'cite'), // 4.01
array('element'=>'script', 'attribute'=>'src'), // 4.01
array('element'=>'audio', 'attribute'=>'src'), // 5.0
array('element'=>'command', 'attribute'=>'icon'), // 5.0
array('element'=>'embed', 'attribute'=>'src'), // 5.0
array('element'=>'event-source','attribute'=>'src'), // 5.0
array('element'=>'html', 'attribute'=>'manifest'), // 5.0
array('element'=>'source', 'attribute'=>'src'), // 5.0
array('element'=>'video', 'attribute'=>'src'), // 5.0
array('element'=>'video', 'attribute'=>'poster'), // 5.0
array('element'=>'bgsound', 'attribute'=>'src'), // Extension
array('element'=>'body', 'attribute'=>'credits'), // Extension
array('element'=>'body', 'attribute'=>'instructions'), // Extension
array('element'=>'body', 'attribute'=>'logo'), // Extension
array('element'=>'div', 'attribute'=>'href'), // Extension
array('element'=>'div', 'attribute'=>'src'), // Extension
array('element'=>'embed', 'attribute'=>'code'), // Extension
array('element'=>'embed', 'attribute'=>'pluginspage'), // Extension
array('element'=>'html', 'attribute'=>'background'), // Extension
array('element'=>'ilayer', 'attribute'=>'src'), // Extension
array('element'=>'img', 'attribute'=>'dynsrc'), // Extension
array('element'=>'img', 'attribute'=>'lowsrc'), // Extension
array('element'=>'input', 'attribute'=>'dynsrc'), // Extension
array('element'=>'input', 'attribute'=>'lowsrc'), // Extension
array('element'=>'table', 'attribute'=>'background'), // Extension
array('element'=>'td', 'attribute'=>'background'), // Extension
array('element'=>'th', 'attribute'=>'background'), // Extension
array('element'=>'layer', 'attribute'=>'src'), // Extension
array('element'=>'xml', 'attribute'=>'src'), // Extension
array('element'=>'button', 'attribute'=>'action'), // Forms 2.0
array('element'=>'datalist', 'attribute'=>'data'), // Forms 2.0
array('element'=>'form', 'attribute'=>'data'), // Forms 2.0
array('element'=>'input', 'attribute'=>'action'), // Forms 2.0
array('element'=>'select', 'attribute'=>'data'), // Forms 2.0
// XHTML
array('element'=>'html', 'attribute'=>'xmlns'),
// WML
array('element'=>'access', 'attribute'=>'path'), // 1.3
array('element'=>'card', 'attribute'=>'onenterforward'), // 1.3
array('element'=>'card', 'attribute'=>'onenterbackward'),// 1.3
array('element'=>'card', 'attribute'=>'ontimer'), // 1.3
array('element'=>'go', 'attribute'=>'href'), // 1.3
array('element'=>'option', 'attribute'=>'onpick'), // 1.3
array('element'=>'template', 'attribute'=>'onenterforward'), // 1.3
array('element'=>'template', 'attribute'=>'onenterbackward'),// 1.3
array('element'=>'template', 'attribute'=>'ontimer'), // 1.3
array('element'=>'wml', 'attribute'=>'xmlns'), // 2.0
);
$match_metas = array(
'content-base',
'content-location',
'referer',
'location',
'refresh',
);
// Extract all elements
if ( !preg_match_all( '/<([a-z][^>]*)>/iu', $text, $matches ) )
return array( );
$elements = $matches[1];
$value_pattern = '=(("([^"]*)")|([^\s]*))';
// Match elements and attributes
foreach ( $match_elements as $match_element )
{
$name = $match_element['element'];
$attr = $match_element['attribute'];
$pattern = '/^' . $name . '\s.*' . $attr . $value_pattern . '/iu';
if ( $name == 'object' )
$split_pattern = '/\s*/u'; // Space-separated URL list
else if ( $name == 'archive' )
$split_pattern = '/,\s*/u'; // Comma-separated URL list
else
unset( $split_pattern ); // Single URL
foreach ( $elements as $element )
{
if ( !preg_match( $pattern, $element, $match ) )
continue;
$m = empty($match[3]) ? (!empty($match[4])?$match[4]:'') : $match[3];
if ( !isset( $split_pattern ) )
$urls[$name][$attr][] = $m;
else
{
$msplit = preg_split( $split_pattern, $m );
foreach ( $msplit as $ms )
$urls[$name][$attr][] = $ms;
}
}
}
// Match meta http-equiv elements
foreach ( $match_metas as $match_meta )
{
$attr_pattern = '/http-equiv="?' . $match_meta . '"?/iu';
$content_pattern = '/content' . $value_pattern . '/iu';
$refresh_pattern = '/\d*;\s*(url=)?(.*)$/iu';
foreach ( $elements as $element )
{
if ( !preg_match( '/^meta/iu', $element ) ||
!preg_match( $attr_pattern, $element ) ||
!preg_match( $content_pattern, $element, $match ) )
continue;
$m = empty($match[3]) ? $match[4] : $match[3];
if ( $match_meta != 'refresh' )
$urls['meta']['http-equiv'][] = $m;
else if ( preg_match( $refresh_pattern, $m, $match ) )
$urls['meta']['http-equiv'][] = $match[2];
}
}
// Match style attributes
$urls['style'] = array( );
$style_pattern = '/style' . $value_pattern . '/iu';
foreach ( $elements as $element )
{
if ( !preg_match( $style_pattern, $element, $match ) )
continue;
$m = empty($match[3]) ? $match[4] : $match[3];
$style_urls = extract_css_urls( $m );
if ( !empty( $style_urls ) )
$urls['style'] = array_merge_recursive(
$urls['style'], $style_urls );
}
// Match style bodies
if ( preg_match_all( '/<style[^>]*>(.*?)<\/style>/siu', $text, $style_bodies ) )
{
foreach ( $style_bodies[1] as $style_body )
{
$style_urls = extract_css_urls( $style_body );
if ( !empty( $style_urls ) )
$urls['style'] = array_merge_recursive(
$urls['style'], $style_urls );
}
}
if ( empty($urls['style']) )
unset( $urls['style'] );
return $urls;
}
/**
* Extract URLs from UTF-8 CSS text.
*
* URLs within @import statements and url() property functions are extracted
* and returned in an associative array of arrays. Array keys indicate
* the use context for the URL, including:
*
* "import"
* "property"
*
* Each value in the associative array is an array of URLs.
*
* Parameters:
* text the UTF-8 text to scan
*
* Return values:
* an associative array of arrays of URLs.
*
* See:
* http://nadeausoftware.com/articles/2008/01/php_tip_how_extract_urls_css_file
*/
function extract_css_urls( $text )
{
$urls = array( );
$url_pattern = '(([^\\\\\'", \(\)]*(\\\\.)?)+)';
$urlfunc_pattern = 'url\(\s*[\'"]?' . $url_pattern . '[\'"]?\s*\)';
$pattern = '/(' .
'(@import\s*[\'"]' . $url_pattern . '[\'"])' .
'|(@import\s*' . $urlfunc_pattern . ')' .
'|(' . $urlfunc_pattern . ')' . ')/iu';
if ( !preg_match_all( $pattern, $text, $matches ) )
return $urls;
// @import '...'
// @import "..."
foreach ( $matches[3] as $match )
if ( !empty($match) )
$urls['import'][] =
preg_replace( '/\\\\(.)/u', '\\1', $match );
// @import url(...)
// @import url('...')
// @import url("...")
foreach ( $matches[7] as $match )
if ( !empty($match) )
$urls['import'][] =
preg_replace( '/\\\\(.)/u', '\\1', $match );
// url(...)
// url('...')
// url("...")
foreach ( $matches[11] as $match )
if ( !empty($match) )
$urls['property'][] =
preg_replace( '/\\\\(.)/u', '\\1', $match );
return $urls;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

+35
View File
@@ -0,0 +1,35 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* URL repository data generator
*
* @package repository_url
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
/**
* URL repository data generator class
*
* @package repository_url
* @category test
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class repository_url_generator extends testing_repository_generator {
}
+92
View File
@@ -0,0 +1,92 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Unit tests for the URL repository.
*
* @package repository_url
* @copyright 2014 John Okely
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace repository_url;
defined('MOODLE_INTERNAL') || die;
global $CFG;
require_once($CFG->dirroot . '/repository/url/lib.php');
/**
* URL repository test case.
*
* @copyright 2014 John Okely
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class lib_test extends \advanced_testcase {
/**
* Check that the url escaper performs as expected
*/
public function test_escape_url(): void {
$this->resetAfterTest();
$repoid = $this->getDataGenerator()->create_repository('url')->id;
$conversions = array(
'http://example.com/test_file.png' => 'http://example.com/test_file.png',
'http://example.com/test%20file.png' => 'http://example.com/test%20file.png',
'http://example.com/test file.png' => 'http://example.com/test%20file.png',
'http://example.com/test file.png?query=string+test&more=string+tests' =>
'http://example.com/test%20file.png?query=string+test&more=string+tests',
'http://example.com/?tag=<p>' => 'http://example.com/?tag=%3Cp%3E',
'http://example.com/"quoted".txt' => 'http://example.com/%22quoted%22.txt',
'http://example.com/\'quoted\'.txt' => 'http://example.com/%27quoted%27.txt',
'' => ''
);
foreach ($conversions as $input => $expected) {
// The constructor uses a optional_param, so we need to hack $_GET.
$_GET['file'] = $input;
$repository = new \repository_url($repoid);
$this->assertSame($expected, $repository->file_url);
}
$exceptions = array(
'%' => true,
'!' => true,
'!https://download.moodle.org/unittest/test.jpg' => true,
'https://download.moodle.org/unittest/test.jpg' => false
);
foreach ($exceptions as $input => $expected) {
$caughtexception = false;
try {
// The constructor uses a optional_param, so we need to hack $_GET.
$_GET['file'] = $input;
$repository = new \repository_url($repoid);
$repository->get_listing();
} catch (\repository_exception $e) {
if ($e->errorcode == 'validfiletype') {
$caughtexception = true;
}
}
$this->assertSame($expected, $caughtexception);
}
unset($_GET['file']);
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
// This file is part of Moodle - http://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 <http://www.gnu.org/licenses/>.
/**
* Version details
*
* @package repository
* @subpackage url
* @copyright 2009 Dongsheng Cai
* @author Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2024042200; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024041600; // Requires this Moodle version.
$plugin->component = 'repository_url'; // Full name of the plugin (used for diagnostics)