MDL-22982

1. rename repository.class to lib.php
2. fixed repository_callback.php
3. repository_ajax use moodle default exception handler
4. improve file_get_user_used_space performance
This commit is contained in:
Dongsheng Cai
2010-07-05 07:27:49 +00:00
parent 2d5a051e14
commit e35194bec4
32 changed files with 1508 additions and 1585 deletions
+1
View File
@@ -101,6 +101,7 @@ $string['instancesforadmin'] = 'common instance(s)';
$string['instancesforothers'] = 'private instance(s)';
$string['invalidjson'] = 'Invalid JSON string';
$string['invalidplugin'] = 'Invalid repository {$a} plug-in';
$string['invalidfiletype'] = '{$a} filetype cannot be accepted.';
$string['invalidrepositoryid'] = 'Invalid repository ID';
$string['isactive'] = 'Active?';
$string['keyword'] = 'Keyword';
+16 -25
View File
@@ -514,26 +514,17 @@ function file_get_draft_area_info($draftitemid) {
* @return int total bytes
*/
function file_get_user_used_space() {
global $DB, $CFG, $USER;
global $DB, $USER;
$usercontext = get_context_instance(CONTEXT_USER, $USER->id);
$totalbytes = 0;
$files = array();
//TODO: rewrite to true sql SUM(), this is goign to run out of memory if limits are hight!
$file_records = $DB->get_records('files', "contextid = ? AND component = 'user' AND filearea != 'draft'", array($usercontext->id));
foreach ($file_records as $file_record) {
if ($file_record->filename === '.') {
continue;
}
// doesn't count same files
if (!isset($files[$file_record->contenthash])) {
$totalbytes += $file_record->filesize;
} else {
$files[$file_record->contenthash] = true;
}
}
return (int)$totalbytes;
$sql = "SELECT SUM(files1.filesize) AS totalbytes FROM {files} files1
JOIN (SELECT contenthash, filename, MAX(id) AS id
FROM {files}
WHERE contextid = ? AND component = ? AND filearea != ?
GROUP BY contenthash, filename) files2 ON files1.id = files2.id";
$params = array('contextid'=>$usercontext->id, 'component'=>'user', 'filearea'=>'draft');
$record = $DB->get_record_sql($sql, $params);
return (int)$record->totalbytes;
}
/**
@@ -2874,7 +2865,7 @@ class curl_cache {
}
/**
* @todo Document this function
* Get cached value
*
* @global object
* @global object
@@ -2901,10 +2892,10 @@ class curl_cache {
}
/**
* @todo Document this function
* Set cache value
*
* @global object
* @global object
* @global object $CFG
* @global object $USER
* @param mixed $param
* @param mixed $val
*/
@@ -2917,7 +2908,7 @@ class curl_cache {
}
/**
* @todo Document this function
* Remove cache files
*
* @param int $expire The number os seconds before expiry
*/
@@ -2936,8 +2927,8 @@ class curl_cache {
/**
* delete current user's cache file
*
* @global object
* @global object
* @global object $CFG
* @global object $USER
*/
public function refresh(){
global $CFG, $USER;
+1 -1
View File
@@ -42,7 +42,7 @@ require_once("$CFG->dirroot/$CFG->admin/generator.php");
$repository_plugins = get_list_of_plugins('repository');
foreach ($repository_plugins as $plugin) {
require_once($CFG->dirroot . "/repository/$plugin/repository.class.php");
require_once($CFG->dirroot . "/repository/$plugin/lib.php");
Mock::generatePartial("repository_$plugin", "partialmock_$plugin", array('send_package'));
}
@@ -202,8 +202,8 @@ class repository_alfresco extends repository {
return array('path'=>$path, 'url'=>$url);
}
public function print_search($client_id) {
$str = parent::print_search($client_id);
public function print_search() {
$str = parent::print_search();
$str .= '<label>Space: </label><br /><select name="space">';
foreach ($this->user_session->stores as $v) {
$str .= '<option ';
+260 -24
View File
@@ -16,8 +16,13 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* dropbox class
* A helper class to access dropbox resources
* repository_dropbox class
* This plugin is used to access user's dropbox files
*
* TODO:
* Dropbox has problems to process filepath with spaces, tried to use
* urlencode filepath, still doesn't work
* http://code.google.com/p/dropbox-php/ has the same problem
*
* @since 2.0
* @package moodlecore
@@ -27,32 +32,263 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/locallib.php');
require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
require_once($CFG->libdir.'/oauthlib.php');
class repository_dropbox extends repository {
private $dropbox;
public $files;
public $logged=false;
class dropbox extends oauth_helper {
private $mode = 'sandbox';
private $dropbox_api = 'http://api.dropbox.com/0';
private $dropbox_content_api = 'http://api-content.dropbox.com/0';
function __construct($args) {
parent::__construct($args);
/**
* Constructor of dropbox plugin
* @param int $repositoryid
* @param object $context
* @param array $options
*/
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
global $SESSION, $CFG;
$options['page'] = optional_param('p', 1, PARAM_INT);
parent::__construct($repositoryid, $context, $options);
$this->setting = 'dropbox_';
$this->dropbox_key = $this->get_option('dropbox_key');
$this->dropbox_secret = $this->get_option('dropbox_secret');
$this->access_key = get_user_preferences($this->setting.'_access_key', '');
$this->access_secret = get_user_preferences($this->setting.'_access_secret', '');
if (!empty($this->access_key) && !empty($this->access_secret)) {
$this->logged = true;
}
$this->callback = new moodle_url($CFG->wwwroot.'/repository/repository_ajax.php', array(
'callback'=>'yes',
'repo_id'=>$repositoryid
));
$args = array(
'oauth_consumer_key'=>$this->dropbox_key,
'oauth_consumer_secret'=>$this->dropbox_secret,
'oauth_callback' => $this->callback->out(false),
'api_root' => 'http://api.dropbox.com/0/oauth',
);
$this->dropbox = new dropbox($args);
}
public function get_listing($path='/', $token='', $secret='') {
$url = $this->dropbox_api.'/metadata/'.$this->mode.$path;
$content = $this->get($url, array(), $token, $secret);
$data = json_decode($content);
return $data;
/**
* Check if moodle has got access token and secret
* @return bool
*/
public function check_login() {
return !empty($this->logged);
}
public function get_account_info($token, $secret) {
$url = $this->dropbox_api.'/account/info';
$content = $this->get($url, array(), $token, $secret);
return $content;
/**
* Generate dropbox login url
* @return array
*/
public function print_login() {
$result = $this->dropbox->request_token();
set_user_preference($this->setting.'_request_secret', $result['oauth_token_secret']);
$url = $result['authorize_url'];
if ($this->options['ajax']) {
$ret = array();
$popup_btn = new stdclass;
$popup_btn->type = 'popup';
$popup_btn->url = $url;
$ret['login'] = array($popup_btn);
return $ret;
} else {
echo '<a target="_blank" href="'.$this->flickr->auth().'">'.get_string('login', 'repository').'</a>';
}
}
public function get_file($filepath, $saveas) {
$url = 'http://api-content.dropbox.com/0/files/sandbox'.$filepath;
$content = $this->get($url, array());
file_put_contents($saveas, $content);
return array('path'=>$saveas, 'url'=>$url);
/**
* Request access token
* @return array
*/
public function callback() {
$token = optional_param('oauth_token', '', PARAM_TEXT);
$secret = get_user_preferences($this->setting.'_request_secret', '');
$access_token = $this->dropbox->get_access_token($token, $secret);
set_user_preference($this->setting.'_access_key', $access_token['oauth_token']);
set_user_preference($this->setting.'_access_secret', $access_token['oauth_token_secret']);
}
/**
* Get dropbox files
* @param string $path
* @param int $page
* @return array
*/
public function get_listing($path = '', $page = '1') {
global $OUTPUT;
if (empty($path) || $path=='/') {
$path = '/';
} else {
$path = file_correct_filepath($path);
}
$result = $this->dropbox->get_listing($path, $this->access_key, $this->access_secret);
$current_path = file_correct_filepath($result->path);
if (empty($result->path)) {
$current_path = '/';
}
$list = array();
$list['list'] = array();
// process breacrumb trail
$list['path'] = array(
array('name'=>'Dropbox Sandbox', 'path'=>'/')
);
$trail = '';
if (!empty($path)) {
$parts = explode('/', $path);
if (count($parts) > 1) {
foreach ($parts as $part) {
if (!empty($part)) {
$trail .= ('/'.$part);
$list['path'][] = array('name'=>$part, 'path'=>$trail);
}
}
} else {
$list['path'][] = array('name'=>$path, 'path'=>$path);
}
}
$list['manage'] = false;
$list['dynload'] = true;
$list['nosearch'] = true;
$files = $result->contents;
foreach ($files as $file) {
if ($file->is_dir) {
$list['list'][] = array(
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
'path' => file_correct_filepath($file->path),
'size' => $file->size,
'date' => $file->modified,
'thumbnail' => $OUTPUT->pix_url('f/folder-32').'',
'children' => array(),
);
} else {
$list['list'][] = array(
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
'source' => $file->path,
'size' => $file->size,
'date' => $file->modified,
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 32)).''
);
}
}
return $list;
}
/**
* Logout from dropbox
* @return array
*/
public function logout() {
set_user_preference($this->setting.'_access_key', '');
set_user_preference($this->setting.'_access_secret', '');
$this->access_key = '';
$this->access_secret = '';
return $this->print_login();
}
/**
* Set dropbox option
* @param array $options
* @return mixed
*/
public function set_option($options = array()) {
if (!empty($options['dropbox_key'])) {
set_config('dropbox_key', trim($options['dropbox_key']), 'dropbox');
}
if (!empty($options['dropbox_secret'])) {
set_config('dropbox_secret', trim($options['dropbox_secret']), 'dropbox');
}
unset($options['dropbox_key']);
unset($options['dropbox_secret']);
$ret = parent::set_option($options);
return $ret;
}
/**
* Get dropbox options
* @param string $config
* @return mixed
*/
public function get_option($config = '') {
if ($config==='dropbox_key') {
return trim(get_config('dropbox', 'dropbox_key'));
} elseif ($config==='dropbox_secret') {
return trim(get_config('dropbox', 'dropbox_secret'));
} else {
$options['dropbox_key'] = trim(get_config('dropbox', 'dropbox_key'));
$options['dropbox_secret'] = trim(get_config('dropbox', 'dropbox_secret'));
}
$options = parent::get_option($config);
return $options;
}
/**
*
* @param string $photo_id
* @param string $file
* @return string
*/
public function get_file($filepath, $saveas = '') {
$this->dropbox->set_access_token($this->access_key, $this->access_secret);
return $this->dropbox->get_file($filepath, $saveas);
}
/**
* Add Plugin settings input to Moodle form
* @param object $mform
*/
public function type_config_form($mform) {
global $CFG;
$key = get_config('dropbox', 'dropbox_key');
$secret = get_config('dropbox', 'dropbox_secret');
if (empty($key)) {
$key = '';
}
if (empty($secret)) {
$secret = '';
}
$strrequired = get_string('required');
$mform->addElement('text', 'dropbox_key', get_string('apikey', 'repository_dropbox'), array('value'=>$key,'size' => '40'));
$mform->addElement('text', 'dropbox_secret', get_string('secret', 'repository_dropbox'), array('value'=>$secret,'size' => '40'));
$mform->addRule('dropbox_key', $strrequired, 'required', null, 'client');
$mform->addRule('dropbox_secret', $strrequired, 'required', null, 'client');
$str_getkey = get_string('instruction', 'repository_dropbox');
$mform->addElement('static', null, '', $str_getkey);
}
/**
* Option names of dropbox plugin
* @return array
*/
public static function get_type_option_names() {
return array('dropbox_key', 'dropbox_secret');
}
/**
* Dropbox plugin supports all kinds of files
* @return array
*/
public function supported_filetypes() {
return '*';
}
/**
* User cannot use the external link to dropbox
* @return int
*/
public function supported_returntypes() {
return FILE_INTERNAL;
}
}
+58
View File
@@ -0,0 +1,58 @@
<?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/>.
/**
* dropbox class
* A helper class to access dropbox resources
*
* @since 2.0
* @package moodlecore
* @subpackage repository
* @copyright 2010 Dongsheng Cai
* @author Dongsheng Cai <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
require_once($CFG->libdir.'/oauthlib.php');
class dropbox extends oauth_helper {
private $mode = 'sandbox';
private $dropbox_api = 'http://api.dropbox.com/0';
private $dropbox_content_api = 'http://api-content.dropbox.com/0';
function __construct($args) {
parent::__construct($args);
}
public function get_listing($path='/', $token='', $secret='') {
$url = $this->dropbox_api.'/metadata/'.$this->mode.$path;
$content = $this->get($url, array(), $token, $secret);
$data = json_decode($content);
return $data;
}
public function get_account_info($token, $secret) {
$url = $this->dropbox_api.'/account/info';
$content = $this->get($url, array(), $token, $secret);
return $content;
}
public function get_file($filepath, $saveas) {
$url = 'http://api-content.dropbox.com/0/files/sandbox'.$filepath;
$content = $this->get($url, array());
file_put_contents($saveas, $content);
return array('path'=>$saveas, 'url'=>$url);
}
}
-293
View File
@@ -1,293 +0,0 @@
<?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/>.
/**
* repository_dropbox class
* This plugin is used to access user's dropbox files
*
* TODO:
* Dropbox has problems to process filepath with spaces, tried to use
* urlencode filepath, still doesn't work
* http://code.google.com/p/dropbox-php/ has the same problem
*
* @since 2.0
* @package moodlecore
* @subpackage repository
* @copyright 2010 Dongsheng Cai
* @author Dongsheng Cai <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once($CFG->dirroot.'/repository/dropbox/lib.php');
class repository_dropbox extends repository {
private $dropbox;
public $files;
public $logged=false;
/**
* Constructor of dropbox plugin
* @param int $repositoryid
* @param object $context
* @param array $options
*/
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
global $SESSION, $CFG;
$options['page'] = optional_param('p', 1, PARAM_INT);
parent::__construct($repositoryid, $context, $options);
$this->setting = 'dropbox_';
$this->dropbox_key = $this->get_option('dropbox_key');
$this->dropbox_secret = $this->get_option('dropbox_secret');
$this->access_key = get_user_preferences($this->setting.'_access_key', '');
$this->access_secret = get_user_preferences($this->setting.'_access_secret', '');
if (!empty($this->access_key) && !empty($this->access_secret)) {
$this->logged = true;
}
$this->callback = new moodle_url($CFG->wwwroot.'/repository/repository_callback.php', array(
'repo_id'=>$repositoryid
));
$args = array(
'oauth_consumer_key'=>$this->dropbox_key,
'oauth_consumer_secret'=>$this->dropbox_secret,
'oauth_callback' => $this->callback->out(false),
'api_root' => 'http://api.dropbox.com/0/oauth',
);
$this->dropbox = new dropbox($args);
}
/**
* Check if moodle has got access token and secret
* @return bool
*/
public function check_login() {
return !empty($this->logged);
}
/**
* Generate dropbox login url
* @return array
*/
public function print_login() {
$result = $this->dropbox->request_token();
set_user_preference($this->setting.'_request_secret', $result['oauth_token_secret']);
$url = $result['authorize_url'];
if ($this->options['ajax']) {
$ret = array();
$popup_btn = new stdclass;
$popup_btn->type = 'popup';
$popup_btn->url = $url;
$ret['login'] = array($popup_btn);
return $ret;
} else {
echo '<a target="_blank" href="'.$this->flickr->auth().'">'.get_string('login', 'repository').'</a>';
}
}
/**
* Request access token
* @return array
*/
public function callback() {
$token = optional_param('oauth_token', '', PARAM_TEXT);
$secret = get_user_preferences($this->setting.'_request_secret', '');
$access_token = $this->dropbox->get_access_token($token, $secret);
set_user_preference($this->setting.'_access_key', $access_token['oauth_token']);
set_user_preference($this->setting.'_access_secret', $access_token['oauth_token_secret']);
}
/**
* Get dropbox files
* @param string $path
* @param int $page
* @return array
*/
public function get_listing($path = '', $page = '1') {
global $OUTPUT;
if (empty($path) || $path=='/') {
$path = '/';
} else {
$path = file_correct_filepath($path);
}
$result = $this->dropbox->get_listing($path, $this->access_key, $this->access_secret);
$current_path = file_correct_filepath($result->path);
if (empty($result->path)) {
$current_path = '/';
}
$list = array();
$list['list'] = array();
// process breacrumb trail
$list['path'] = array(
array('name'=>'Dropbox Sandbox', 'path'=>'/')
);
$trail = '';
if (!empty($path)) {
$parts = explode('/', $path);
if (count($parts) > 1) {
foreach ($parts as $part) {
if (!empty($part)) {
$trail .= ('/'.$part);
$list['path'][] = array('name'=>$part, 'path'=>$trail);
}
}
} else {
$list['path'][] = array('name'=>$path, 'path'=>$path);
}
}
$list['manage'] = false;
$list['dynload'] = true;
$list['nosearch'] = true;
$files = $result->contents;
foreach ($files as $file) {
if ($file->is_dir) {
$list['list'][] = array(
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
'path' => file_correct_filepath($file->path),
'size' => $file->size,
'date' => $file->modified,
'thumbnail' => $OUTPUT->pix_url('f/folder-32').'',
'children' => array(),
);
} else {
$list['list'][] = array(
'title' => substr($file->path, strpos($file->path, $current_path)+strlen($current_path)),
'source' => $file->path,
'size' => $file->size,
'date' => $file->modified,
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($file->path, 32)).''
);
}
}
return $list;
}
/**
* Logout from dropbox
* @return array
*/
public function logout() {
set_user_preference($this->setting.'_access_key', '');
set_user_preference($this->setting.'_access_secret', '');
$this->access_key = '';
$this->access_secret = '';
return $this->print_login();
}
/**
* Set dropbox option
* @param array $options
* @return mixed
*/
public function set_option($options = array()) {
if (!empty($options['dropbox_key'])) {
set_config('dropbox_key', trim($options['dropbox_key']), 'dropbox');
}
if (!empty($options['dropbox_secret'])) {
set_config('dropbox_secret', trim($options['dropbox_secret']), 'dropbox');
}
unset($options['dropbox_key']);
unset($options['dropbox_secret']);
$ret = parent::set_option($options);
return $ret;
}
/**
* Get dropbox options
* @param string $config
* @return mixed
*/
public function get_option($config = '') {
if ($config==='dropbox_key') {
return trim(get_config('dropbox', 'dropbox_key'));
} elseif ($config==='dropbox_secret') {
return trim(get_config('dropbox', 'dropbox_secret'));
} else {
$options['dropbox_key'] = trim(get_config('dropbox', 'dropbox_key'));
$options['dropbox_secret'] = trim(get_config('dropbox', 'dropbox_secret'));
}
$options = parent::get_option($config);
return $options;
}
/**
*
* @param string $photo_id
* @param string $file
* @return string
*/
public function get_file($filepath, $saveas = '') {
$this->dropbox->set_access_token($this->access_key, $this->access_secret);
return $this->dropbox->get_file($filepath, $saveas);
}
/**
* Add Plugin settings input to Moodle form
* @param object $mform
*/
public function type_config_form($mform) {
global $CFG;
$key = get_config('dropbox', 'dropbox_key');
$secret = get_config('dropbox', 'dropbox_secret');
if (empty($key)) {
$key = '';
}
if (empty($secret)) {
$secret = '';
}
$strrequired = get_string('required');
$mform->addElement('text', 'dropbox_key', get_string('apikey', 'repository_dropbox'), array('value'=>$key,'size' => '40'));
$mform->addElement('text', 'dropbox_secret', get_string('secret', 'repository_dropbox'), array('value'=>$secret,'size' => '40'));
$mform->addRule('dropbox_key', $strrequired, 'required', null, 'client');
$mform->addRule('dropbox_secret', $strrequired, 'required', null, 'client');
$str_getkey = get_string('instruction', 'repository_dropbox');
$mform->addElement('static', null, '', $str_getkey);
}
/**
* Option names of dropbox plugin
* @return array
*/
public static function get_type_option_names() {
return array('dropbox_key', 'dropbox_secret');
}
/**
* Dropbox plugin supports all kinds of files
* @return array
*/
public function supported_filetypes() {
return '*';
}
/**
* User cannot use the external link to dropbox
* @return int
*/
public function supported_returntypes() {
return FILE_INTERNAL;
}
}
+10 -8
View File
@@ -97,7 +97,7 @@ M.core_filepicker.init = function(Y, options) {
params['env']=this.options.env;
// the form element only accept certain file types
params['accepted_types']=this.options.accepted_types;
params['sesskey']=M.cfg.sesskey;
params['sesskey'] = M.cfg.sesskey;
params['client_id'] = args.client_id;
params['itemid'] = this.options.itemid?this.options.itemid:0;
params['maxbytes'] = this.options.maxbytes?this.options.maxbytes:-1;
@@ -124,9 +124,8 @@ M.core_filepicker.init = function(Y, options) {
return;
}
// error checking
if (data && data.e) {
//Y.one(panel_id).set('innerHTML', 'ERROR: '+data.e);
scope.print_msg(data.e, 'error');
if (data && data.error) {
scope.print_msg(data.error, 'error');
scope.list();
return;
} else {
@@ -189,7 +188,6 @@ M.core_filepicker.init = function(Y, options) {
}
this.msg_dlg.setHeader(type);
this.msg_dlg.show();
},
build_tree: function(node, level) {
var client_id = this.options.client_id;
@@ -653,7 +651,7 @@ M.core_filepicker.init = function(Y, options) {
}
if (count==0) {
if (this.options.externallink) {
list.set('innerHTML', M.str.repository.norepositoriesavexternalailable);
list.set('innerHTML', M.str.repository.norepositoriesexternalavailable);
} else {
list.set('innerHTML', M.str.repository.norepositoriesavailable);
}
@@ -962,6 +960,7 @@ M.core_filepicker.init = function(Y, options) {
create_upload_form: function(data) {
var client_id = this.options.client_id;
Y.one('#panel-'+client_id).set('innerHTML', '');
var types = this.options.accepted_types;
this.print_header();
var id = data.upload.id+'_'+client_id;
@@ -971,8 +970,11 @@ M.core_filepicker.init = function(Y, options) {
str += '<tr><td class="mdl-right">';
str += '<label for="'+id+'_file">'+data.upload.label+': </label></td>';
str += '<td class="mdl-left"><input type="file" id="'+id+'_file" name="repo_upload_file" />';
str += '<input type="hidden" name="itemid" value="'+this.options.itemid+'" /></tr>';
str += '<tr>';
str += '<input type="hidden" name="itemid" value="'+this.options.itemid+'" />';
for (var i in types) {
str += '<input type="hidden" name="accepted_types[]" value="'+types[i]+'" />';
}
str += '</td></tr><tr>';
str += '<td class="mdl-right"><label>'+M.str.repository.author+': </label></td>';
str += '<td class="mdl-left"><input type="text" name="author" value="'+this.options.author+'" /></td>';
str += '</tr>';
+2 -2
View File
@@ -80,8 +80,8 @@ $sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instanc
'WHERE i.id=? AND i.typeid=r.id';
if ($repository = $DB->get_record_sql($sql, array($repo_id))) {
$type = $repository->type;
if (file_exists($CFG->dirroot.'/repository/'.$type.'/repository.class.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/repository.class.php');
if (file_exists($CFG->dirroot.'/repository/'.$type.'/lib.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/lib.php');
$classname = 'repository_' . $type;
try {
$repo = new $classname($repo_id, $contextid, array('ajax'=>false, 'name'=>$repository->name));
@@ -389,6 +389,7 @@ class repository_flickr_public extends repository {
public function get_link($photo_id) {
global $CFG;
$result = $this->flickr->photos_getSizes($photo_id);
throw new file_exception('abc');
$url = '';
if(!empty($result[4])) {
$url = $result[4]['source'];
@@ -68,7 +68,7 @@ class repository_googledocs extends repository {
$ret = array();
$popup_btn = new stdclass;
$popup_btn->type = 'popup';
$returnurl = $CFG->wwwroot.'/repository/repository_callback.php?repo_id='.$this->id;
$returnurl = $CFG->wwwroot.'/repository/repository_ajax.php?callback=yes&repo_id='.$this->id;
$popup_btn->url = google_authsub::login_url($returnurl, google_docs::REALM);
$ret['login'] = array($popup_btn);
return $ret;
+46 -74
View File
@@ -426,7 +426,7 @@ class repository_type {
* To use repository plugin, see:
* http://docs.moodle.org/en/Development:Repository_How_to_Create_Plugin
* class repository is an abstract class, some functions must be implemented in subclass.
* See an example: repository/boxnet/repository.class.php
* See an example: repository/boxnet/lib.php
*
* A few notes:
* // for ajax file picker, this will print a json string to tell file picker
@@ -457,15 +457,20 @@ abstract class repository {
* 1. Initialize context and options
* 2. Accept necessary parameters
*
* @param integer $repositoryid
* @param integer $contextid
* @param array $options
* @param integer $repositoryid repository instance id
* @param integer|object a context id or context object
* @param array $options repository options
*/
public function __construct($repositoryid, $contextid = SYSCONTEXTID, $options = array(), $readonly = 0) {
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array(), $readonly = 0) {
$this->id = $repositoryid;
$this->context = get_context_instance_by_id($contextid);
if (!empty($context->id)) {
$this->context = $context;
} else {
$this->context = get_context_instance_by_id($context);
}
$this->readonly = $readonly;
$this->options = array();
if (is_array($options)) {
$options = array_merge($this->get_option(), $options);
} else {
@@ -480,10 +485,10 @@ abstract class repository {
}
/**
* Return a type for a given type name.
* Get a repository type object by a given type name.
* @global object $DB
* @param string $typename the type name
* @return repository_type
* @param string $typename the repository type name
* @return repository_type|bool
*/
public static function get_type_by_typename($typename) {
global $DB;
@@ -496,7 +501,7 @@ abstract class repository {
}
/**
* Return a type for a given type id.
* Get the repository type by a given repository type id.
* @global object $DB
* @param int $id the type id
* @return object
@@ -512,9 +517,10 @@ abstract class repository {
}
/**
* Return all repository types ordered by sortorder
* first type in returnedarray[0], second type in returnedarray[1], ...
* Return all repository types ordered by sortorder field
* first repository type in returnedarray[0], second repository type in returnedarray[1], ...
* @global object $DB
* @global object $CFG
* @param boolean $visible can return types by visiblity, return all types if null
* @return array Repository types
*/
@@ -528,7 +534,7 @@ abstract class repository {
}
if ($records = $DB->get_records('repository',$params,'sortorder')) {
foreach($records as $type) {
if (file_exists($CFG->dirroot . '/repository/'. $type->type .'/repository.class.php')) {
if (file_exists($CFG->dirroot . '/repository/'. $type->type .'/lib.php')) {
$types[] = new repository_type($type->type, (array)get_config($type->type), $type->visible, $type->sortorder);
}
}
@@ -538,14 +544,15 @@ abstract class repository {
}
/**
* Check context
* @param int $ctx_id
* To check if the context id is valid
* @global object $USER
* @param int $contextid
* @return boolean
*/
public static function check_context($ctx_id) {
public static function check_context($contextid) {
global $USER;
$context = get_context_instance_by_id($ctx_id);
$context = get_context_instance_by_id($contextid);
$level = $context->contextlevel;
if ($level == CONTEXT_COURSE) {
@@ -556,7 +563,7 @@ abstract class repository {
}
} else if ($level == CONTEXT_USER) {
$c = get_context_instance(CONTEXT_USER, $USER->id);
if ($c->id == $ctx_id) {
if ($c->id == $contextid) {
return true;
} else {
return false;
@@ -626,8 +633,8 @@ abstract class repository {
}
$onlyvisible = isset($args['onlyvisible']) ? $args['onlyvisible'] : true;
$returntypes = isset($args['return_types']) ? $args['return_types'] : 3;
$type = isset($args['type']) ? $args['type'] : null;
$returntypes = isset($args['return_types']) ? $args['return_types'] : 3;
$params = array();
$sql = "SELECT i.*, r.type AS repositorytype, r.sortorder, r.visible
@@ -681,10 +688,10 @@ abstract class repository {
$accepted_types = '*';
}
foreach ($records as $record) {
if (!file_exists($CFG->dirroot . '/repository/'. $record->repositorytype.'/repository.class.php')) {
if (!file_exists($CFG->dirroot . '/repository/'. $record->repositorytype.'/lib.php')) {
continue;
}
require_once($CFG->dirroot . '/repository/'. $record->repositorytype.'/repository.class.php');
require_once($CFG->dirroot . '/repository/'. $record->repositorytype.'/lib.php');
$options['visible'] = $record->visible;
$options['name'] = $record->name;
$options['type'] = $record->repositorytype;
@@ -723,12 +730,10 @@ abstract class repository {
}
}
if (!$onlyvisible || ($repository->is_visible() && !$repository->disabled)) {
// check capability in current context
if (!empty($current_context)) {
$capability = has_capability('repository/'.$record->repositorytype.':view', $current_context);
} else {
// TODO: what should we do if current context isn't set?
$capability = has_capability('repository/'.$record->repositorytype.':view', get_system_context());
}
if ($is_supported && $capability) {
@@ -757,8 +762,7 @@ abstract class repository {
if (!$instance = $DB->get_record_sql($sql, array($id))) {
return false;
}
require_once($CFG->dirroot . '/repository/'. $instance->repositorytype
. '/repository.class.php');
require_once($CFG->dirroot . '/repository/'. $instance->repositorytype.'/lib.php');
$classname = 'repository_' . $instance->repositorytype;
$options['typeid'] = $instance->typeid;
$options['type'] = $instance->repositorytype;
@@ -771,7 +775,7 @@ abstract class repository {
}
/**
* call a static function. Any additional arguments than plugin and function will be passed through.
* Call a static function. Any additional arguments than plugin and function will be passed through.
* @global object $CFG
* @param string $plugin
* @param string $function
@@ -781,7 +785,7 @@ abstract class repository {
global $CFG;
//check that the plugin exists
$typedirectory = $CFG->dirroot . '/repository/'. $plugin . '/repository.class.php';
$typedirectory = $CFG->dirroot . '/repository/'. $plugin . '/lib.php';
if (!file_exists($typedirectory)) {
//throw new repository_exception('invalidplugin', 'repository');
return false;
@@ -798,8 +802,7 @@ abstract class repository {
$args = func_get_args();
if (count($args) <= 2) {
$args = array();
}
else {
} else {
array_shift($args);
array_shift($args);
}
@@ -963,13 +966,12 @@ abstract class repository {
//if the context is SYSTEM, so we call it from administration page
$admin = ($context->id == SYSCONTEXTID) ? true : false;
if ($admin) {
$baseurl = "$CFG->httpswwwroot/$CFG->admin/repositoryinstance.php?sesskey=" . sesskey();
$output .= "<div ><h2 style='text-align: center'>" . get_string('siteinstances', 'repository') . " ";
$output .= "</h2></div>";
$baseurl = new moodle_url('/'.$CFG->admin.'/repositoryinstance.php', array('sesskey'=>sesskey()));
$output .= $OUTPUT->heading(get_string('siteinstances', 'repository'));
} else {
$baseurl = $CFG->httpswwwroot . '/repository/manage_instances.php?contextid=' . $context->id . '&amp;sesskey=' . sesskey();
$baseurl = new moodle_url('/repository/manage_instances.php', array('contextid'=>$context->id, 'sesskey'=>sesskey()));
}
$url = new moodle_url($baseurl);
$url = $baseurl;
$namestr = get_string('name');
$pluginstr = get_string('plugin', 'repository');
@@ -1044,8 +1046,9 @@ abstract class repository {
if (!empty($type) && $type->get_visible()) {
$instanceoptionnames = repository::static_function($type->get_typename(), 'get_instance_option_names');
if (!empty($instanceoptionnames)) {
$instancehtml .= '<li><a href="'.$baseurl.'&amp;new='.$type->get_typename().'">'.get_string('createxxinstance', 'repository', get_string('pluginname', 'repository_'.$type->get_typename()))
.'</a></li>';
$baseurl->param('new', $type->get_typename());
$instancehtml .= '<li><a href="'.$baseurl->out().'">'.get_string('createxxinstance', 'repository', get_string('pluginname', 'repository_'.$type->get_typename())). '</a></li>';
$baseurl->remove_params('new');
$addable++;
}
}
@@ -1056,9 +1059,11 @@ abstract class repository {
$instanceoptionnames = repository::static_function($typename, 'get_instance_option_names');
if (!empty($instanceoptionnames)) { //create a unique type of instance
$addable = 1;
$instancehtml .= "<form action='".$baseurl."&amp;new=".$typename."' method='post'>
<p style='text-align:center'><input type='submit' value='".get_string('createinstance', 'repository')."'/></p>
$baseurl->param('new', $typename);
$instancehtml .= "<form action='".$baseurl->out()."' method='post'>
<p><input type='submit' value='".get_string('createinstance', 'repository')."'/></p>
</form>";
$baseurl->remove_params('new');
}
}
@@ -1074,8 +1079,7 @@ abstract class repository {
}
/**
* Decide where to save the file, can be
* reused by sub class
* Decide where to save the file, can be overwriten by subclass
* @param string filename
*/
public function prepare_file($filename) {
@@ -1217,7 +1221,7 @@ abstract class repository {
public static function create($type, $userid, $context, $params, $readonly=0) {
global $CFG, $DB;
$params = (array)$params;
require_once($CFG->dirroot . '/repository/'. $type . '/repository.class.php');
require_once($CFG->dirroot . '/repository/'. $type . '/lib.php');
$classname = 'repository_' . $type;
if ($repo = $DB->get_record('repository', array('type'=>$type))) {
$record = new stdclass;
@@ -1289,37 +1293,6 @@ abstract class repository {
return false;
}
/**
* Cache login details for repositories
* @global object $DB
* @param string $username
* @param string $password
* @param integer $userid The id of specific user
* @return integer Id of the record
*/
public function store_login($username = '', $password = '', $userid = 1) {
global $DB;
$repository = new stdclass;
if (!empty($this->id)) {
$repository->id = $this->id;
} else {
$repository->userid = $userid;
$repository->repositorytype = $this->type;
$repository->contextid = $this->context->id;
}
if ($entry = $DB->get_record('repository', $repository)) {
$repository->id = $entry->id;
$repository->username = $username;
$repository->password = $password;
return $DB->update_record('repository', $repository);
} else {
$repository->username = $username;
$repository->password = $password;
return $DB->insert_record('repository', $repository);
}
}
/**
* Save settings for repository instance
* $repo->set_option(array('api_key'=>'f2188bde132', 'name'=>'dongsheng'));
@@ -1548,6 +1521,7 @@ abstract class repository {
public static function get_instance_option_names() {
return array();
}
public function get_short_filename($str, $maxlength) {
if (strlen($str) >= $maxlength) {
return trim(substr($str, 0, $maxlength)).'...';
@@ -1569,8 +1543,6 @@ abstract class repository {
class repository_exception extends moodle_exception {
}
/**
* This is a class used to define a repository instance form
*
+15
View File
@@ -1,5 +1,20 @@
<?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/>.
function xmldb_repository_local_install() {
global $CFG;
$result = true;
@@ -75,7 +75,6 @@ class repository_local extends repository {
$itemid = $params['itemid'];
$filename = $params['filename'];
$filearea = $params['filearea'];
$component = $params['component'];
$filepath = $params['filepath'];
$context = get_context_instance_by_id($params['contextid']);
}
@@ -83,7 +82,6 @@ class repository_local extends repository {
$itemid = null;
$filename = null;
$filearea = null;
$component = null;
$filepath = null;
$context = get_system_context();
}
@@ -91,7 +89,7 @@ class repository_local extends repository {
try {
$browser = get_file_browser();
if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
if ($fileinfo = $browser->get_file_info($context, $filearea, $itemid, $filepath, $filename)) {
// build path navigation
$pathnodes = array();
$encodedpath = base64_encode(serialize($fileinfo->get_params()));
@@ -119,7 +117,7 @@ class repository_local extends repository {
$encodedpath = base64_encode(serialize($params));
// hide user_private area from local plugin, user should
// use private file plugin to access private files
if ($params['component'] = 'user' and $params['filearea'] == 'private') {
if ($params['filearea'] == 'user_private') {
continue;
}
$node = array(
@@ -184,7 +182,7 @@ class repository_local extends repository {
* @param string $new_filepath the new path in draft area
* @return array The information of file
*/
public function copy_to_area($encoded, $new_filearea='ignored', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
public function copy_to_area($encoded, $new_filearea='user_draft', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
global $USER, $DB;
$info = array();
@@ -193,15 +191,14 @@ class repository_local extends repository {
$user_context = get_context_instance(CONTEXT_USER, $USER->id);
// the final file
$contextid = $params['contextid'];
$component = $params['component'];
$filearea = $params['filearea'];
$filepath = $params['filepath'];
$filename = $params['filename'];
$fileitemid = $params['itemid'];
$context = get_context_instance_by_id($contextid);
try {
$file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
$file_info->copy_to_storage($user_context->id, 'user', 'draft', $new_itemid, $new_filepath, $new_filename);
$file_info = $browser->get_file_info($context, $filearea, $fileitemid, $filepath, $filename);
$file_info->copy_to_storage($user_context->id, $new_filearea, $new_itemid, $new_filepath, $new_filename);
} catch (Exception $e) {
throw $e;
}
@@ -65,7 +65,7 @@ class repository_picasa extends repository {
public function print_login(){
global $CFG;
$returnurl = $CFG->wwwroot.'/repository/repository_callback.php?repo_id='.$this->id;
$returnurl = $CFG->wwwroot.'/repository/repository_ajax.php?callback=yes&repo_id='.$this->id;
$authurl = google_authsub::login_url($returnurl, google_picasa::REALM);
if($this->options['ajax']){
$ret = array();
@@ -30,7 +30,7 @@ define('DEFAULT_RECENT_FILES_NUM', 50);
class repository_recent extends repository {
/**
* initialize recent plugin
* Initialize recent plugin
* @param int $repositoryid
* @param int $context
* @param array $options
@@ -65,23 +65,20 @@ class repository_recent extends repository {
private function get_recent_files($limitfrom = 0, $limit = DEFAULT_RECENT_FILES_NUM) {
global $USER, $DB;
// TODO: this is not really secure, we should validate the result with file_browser (skodak)
// TODO: should exclude user_draft area files?
$sql = 'SELECT * FROM {files} files1
JOIN (SELECT contenthash, filename, MAX(id) AS id
FROM {files}
WHERE userid = :userid AND filename != :filename AND filearea != :filearea
WHERE userid = ? AND filename != ? AND filearea != ?
GROUP BY contenthash, filename) files2 ON files1.id = files2.id
ORDER BY files1.timemodified DESC';
$params = array('userid'=>$USER->id, 'filename'=>'.', 'filearea'=>'draft');
$params = array('userid'=>$USER->id, 'filename'=>'.', 'filearea'=>'user_draft');
$rs = $DB->get_recordset_sql($sql, $params, $limitfrom, $limit);
$result = array();
foreach ($rs as $file_record) {
$info = array();
$info['contextid'] = $file_record->contextid;
$info['itemid'] = $file_record->itemid;
$info['component'] = $file_record->component;
$info['filearea'] = $file_record->filearea;
$info['filepath'] = $file_record->filepath;
$info['filename'] = $file_record->filename;
@@ -124,7 +121,6 @@ class repository_recent extends repository {
} catch (Exception $e) {
throw new repository_exception('emptyfilelist', 'repository_recent');
}
$ret['list'] = $list;
$ret['list'] = array_filter($list, array($this, 'filter'));
return $ret;
}
@@ -165,13 +161,13 @@ class repository_recent extends repository {
*
* @global object $USER
* @global object $DB
* @param string $encoded The information of file, it is base64 encoded php serialized data
* @param string $encoded The information of file, it is base64 encoded php seriablized data
* @param string $new_filename The intended name of file
* @param string $new_itemid itemid
* @param string $new_filepath the new path in draft area
* @return array The information of file
*/
public function copy_to_area($encoded, $new_filearea='ignored', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
public function copy_to_area($encoded, $new_filearea='user_draft', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
global $USER, $DB;
$info = array();
$fs = get_file_storage();
@@ -179,10 +175,7 @@ class repository_recent extends repository {
$params = unserialize(base64_decode($encoded));
$user_context = get_context_instance(CONTEXT_USER, $USER->id);
//TODO: this is really HORRIBLE!!! Where is any security check??????? (skodak)
$contextid = $params['contextid'];
$component = $params['component'];
$filearea = $params['filearea'];
$filepath = $params['filepath'];
$filename = $params['filename'];
@@ -191,17 +184,14 @@ class repository_recent extends repository {
// XXX:
// When user try to pick a file from other filearea, normally file api will use file browse to
// operate the files with capability check, but in some areas, users don't have permission to
// browse the files (for example, forum attachment area).
// browse the files (for example, forum_attachment area).
//
// To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
// capability check, we will use a better workaround to improve it.
//
// TODO: no this is a BIG security hole, we should really use file_browser here and instead filter the available files (skodak)
//
if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
$file_record = array('contextid'=>$user_context->id, 'component'=>'user', 'filearea'=>'draft',
if ($stored_file = $fs->get_file($contextid, $filearea, $fileitemid, $filepath, $filename)) {
$file_record = array('contextid'=>$user_context->id, 'filearea'=>$new_filearea,
'itemid'=>$new_itemid, 'filepath'=>$new_filepath, 'filename'=>$new_filename);
if ($file = $fs->get_file($user_context->id, 'user' ,'draft', $new_itemid, $new_filepath, $new_filename)) {
if ($file = $fs->get_file($user_context->id, $new_filearea, $new_itemid, $new_filepath, $new_filename)) {
$file->delete();
}
$fs->create_file_from_storedfile($file_record, $stored_file);
+114 -152
View File
@@ -26,6 +26,8 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('AJAX_SCRIPT', true);
require_once(dirname(dirname(__FILE__)).'/config.php');
require_once(dirname(dirname(__FILE__)).'/lib/filelib.php');
require_once(dirname(__FILE__).'/lib.php');
@@ -35,7 +37,6 @@ require_login();
/// Parameters
$action = optional_param('action', '', PARAM_ALPHA);
$repo_id = optional_param('repo_id', 0, PARAM_INT); // Pepository ID
$client_id = optional_param('client_id', '', PARAM_RAW); // Client ID
$contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID
$env = optional_param('env', 'filepicker', PARAM_ALPHA); // Opened in editor or moodleform
$license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT);
@@ -45,6 +46,7 @@ $itemid = optional_param('itemid', 0, PARAM_INT); // Itemid
$page = optional_param('page', '', PARAM_RAW); // Page
$maxbytes = optional_param('maxbytes', 0, PARAM_INT); // Maxbytes
$req_path = optional_param('p', '', PARAM_RAW); // Path
$accepted_types = optional_param('accepted_types', '*', PARAM_RAW);
$saveas_filename = optional_param('title', '', PARAM_FILE); // save as file name
$saveas_path = optional_param('savepath', '/', PARAM_PATH); // save as file path
$search_text = optional_param('s', '', PARAM_CLEANHTML);
@@ -55,7 +57,6 @@ header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
$err = new stdclass;
$err->client_id = $client_id;
if (!confirm_sesskey()) {
$err->error = get_string('invalidsesskey');
@@ -64,7 +65,7 @@ if (!confirm_sesskey()) {
/// Check permissions
if (! (isloggedin() && repository::check_context($contextid)) ) {
$err->e = get_string('nopermissiontoaccess', 'repository');
$err->error = get_string('nopermissiontoaccess', 'repository');
die(json_encode($err));
}
@@ -88,20 +89,14 @@ switch ($action) {
$list = array();
foreach($repos as $repo){
if ($repo->global_search()) {
try {
$ret = $repo->search($search_text);
array_walk($ret['list'], 'repository_attach_id', $repo->id); // See function below
$tmp = array_merge($list, $ret['list']);
$list = $tmp;
} catch (repository_exception $e) {
$err->e = $e->getMessage();
die(json_encode($err));
}
$ret = $repo->search($search_text);
array_walk($ret['list'], 'repository_attach_id', $repo->id); // See function below
$tmp = array_merge($list, $ret['list']);
$list = $tmp;
}
}
$listing = array('list'=>$list);
$listing['gsearch'] = true;
$listing['client_id'] = $client_id;
die(json_encode($listing));
break;
@@ -118,23 +113,18 @@ $sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instanc
'WHERE i.id=? AND i.typeid=r.id';
if (!$repository = $DB->get_record_sql($sql, array($repo_id))) {
$err->e = get_string('invalidrepositoryid', 'repository');
$err->error = get_string('invalidrepositoryid', 'repository');
die(json_encode($err));
} else {
$type = $repository->type;
}
if (file_exists($CFG->dirroot.'/repository/'.$type.'/repository.class.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/repository.class.php');
if (file_exists($CFG->dirroot.'/repository/'.$type.'/lib.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/lib.php');
$classname = 'repository_' . $type;
try {
$repo = new $classname($repo_id, $contextid, array('ajax'=>true, 'name'=>$repository->name, 'type'=>$type, 'client_id'=>$client_id));
} catch (repository_exception $e){
$err->e = $e->getMessage();
die(json_encode($err));
}
$repo = new $classname($repo_id, $contextid, array('ajax'=>true, 'name'=>$repository->name, 'type'=>$type));
} else {
$err->e = get_string('invalidplugin', 'repository', $type);
$err->error = get_string('invalidplugin', 'repository', $type);
die(json_encode($err));
}
@@ -144,160 +134,132 @@ switch ($action) {
case 'signin':
case 'list':
if ($repo->check_login()) {
try {
$listing = $repo->get_listing($req_path, $page);
$listing['client_id'] = $client_id;
$listing['repo_id'] = $repo_id;
echo json_encode($listing);
} catch (repository_exception $e) {
$err->e = $e->getMessage();
die(json_encode($err));
}
$listing = $repo->get_listing($req_path, $page);
$listing['repo_id'] = $repo_id;
echo json_encode($listing);
break;
} else {
$action = 'login';
}
case 'login':
try {
$listing = $repo->print_login();
$listing['client_id'] = $client_id;
$listing['repo_id'] = $repo_id;
echo json_encode($listing);
} catch (repository_exception $e){
$err->e = $e->getMessage();
die(json_encode($err));
}
$listing = $repo->print_login();
$listing['repo_id'] = $repo_id;
echo json_encode($listing);
break;
case 'logout':
$logout = $repo->logout();
$logout['client_id'] = $client_id;
$logout['repo_id'] = $repo_id;
echo json_encode($logout);
break;
case 'searchform':
$search_form['form'] = $repo->print_search($client_id);
$search_form['client_id'] = $client_id;
$search_form['form'] = $repo->print_search();
echo json_encode($search_form);
break;
case 'search':
try {
$search_result = $repo->search($search_text, (int)$page);
$search_result['client_id'] = $client_id;
$search_result['repo_id'] = $repo_id;
$search_result['search_result'] = true;
echo json_encode($search_result);
} catch (repository_exception $e) {
$err->e = $e->getMessage();
die(json_encode($err));
}
$search_result = $repo->search($search_text, (int)$page);
$search_result['repo_id'] = $repo_id;
$search_result['search_result'] = true;
echo json_encode($search_result);
break;
case 'download':
try {
// We have two special repoisitory type need to deal with
// local and recent plugins don't added new files to moodle, just add new records to database
// so we don't check user quota and maxbytes here
if (in_array($repo->options['type'], array('local', 'recent', 'user'))) {
try {
$fileinfo = $repo->copy_to_area($source, 'draft', $itemid, $saveas_path, $saveas_filename);
} catch (Exception $e) {
throw $e;
}
// validate mimetype
$mimetypes = array();
if (in_array('*', $accepted_types) or $accepted_types == '*') {
$mimetypes = '*';
} else {
foreach ($accepted_types as $type) {
$mimetypes = mimeinfo('type', $type);
}
if (!in_array(mimeinfo('type', $saveas_filename), $mimetypes)) {
throw new moodle_exception('invalidfiletype', 'repository', '', mimeinfo('type', $_FILES[$elname]['name']));
}
}
// We have two special repoisitory type need to deal with
// local and recent plugins don't added new files to moodle, just add new records to database
// so we don't check user quota and maxbytes here
if (in_array($repo->options['type'], array('local', 'recent', 'user'))) {
$fileinfo = $repo->copy_to_area($source, 'draft', $itemid, $saveas_path, $saveas_filename);
$info = array();
$info['file'] = $fileinfo['title'];
$info['id'] = $itemid;
$info['url'] = $CFG->httpswwwroot.'/draftfile.php/'.$fileinfo['contextid'].'/user_draft/'.$itemid.'/'.$fileinfo['title'];
$filesize = $fileinfo['filesize'];
if (($maxbytes!==-1) && ($filesize>$maxbytes)) {
throw new file_exception('maxbytes');
}
echo json_encode($info);
die; // ends here!!
} else {
$allowexternallink = (int)get_config(null, 'repositoryallowexternallinks');
if (!empty($allowexternallink)) {
$allowexternallink = true;
} else {
$allowexternallink = false;
}
// allow external links in url element all the time
$allowexternallink = ($allowexternallink || ($env == 'url'));
// Use link of the files
if ($allowexternallink and $linkexternal === 'yes' and ($repo->supported_returntypes() & FILE_EXTERNAL)) {
// use external link
$link = $repo->get_link($source);
$info = array();
$info['client_id'] = $client_id;
$info['file'] = $fileinfo['title'];
$info['id'] = $itemid;
$info['url'] = $CFG->httpswwwroot.'/draftfile.php/'.$fileinfo['contextid'].'/user_draft/'.$itemid.'/'.$fileinfo['title'];
$filesize = $fileinfo['filesize'];
if (($maxbytes!==-1) && ($filesize>$maxbytes)) {
$info['filename'] = $saveas_filename;
$info['type'] = 'link';
$info['url'] = $link;
echo json_encode($info);
die;
} else {
// Download file to moodle
$file = $repo->get_file($source, $saveas_filename);
if ($file['path'] === false) {
$err->error = get_string('cannotdownload', 'repository');
die(json_encode($err));
}
// check if exceed maxbytes
if (($maxbytes!==-1) && (filesize($file['path']) > $maxbytes)) {
throw new file_exception('maxbytes');
}
// check if exceed user quota
$userquota = file_get_user_used_space();
if (filesize($file['path'])+$userquota>=(int)$CFG->userquota) {
throw new file_exception('userquotalimit');
}
$record = new stdclass;
$record->filepath = $saveas_path;
$record->filename = $saveas_filename;
$record->component = 'user';
$record->filearea = 'draft';
$record->itemid = $itemid;
if (!empty($file['license'])) {
$record->license = $file['license'];
} else {
$record->license = $license;
}
if (!empty($file['author'])) {
$record->author = $file['author'];
} else {
$record->author = $author;
}
$record->source = !empty($file['url']) ? $file['url'] : '';
$info = repository::move_to_filepool($file['path'], $record);
if (empty($info)) {
$info['e'] = get_string('error', 'moodle');
}
echo json_encode($info);
die; // ends here!!
} else {
$allowexternallink = (int)get_config(null, 'repositoryallowexternallinks');
if (!empty($allowexternallink)) {
$allowexternallink = true;
} else {
$allowexternallink = false;
}
// allow external links in url element all the time
$allowexternallink = ($allowexternallink || ($env == 'url'));
// Use link of the files
if ($allowexternallink and $linkexternal === 'yes' and ($repo->supported_returntypes() || FILE_EXTERNAL)) {
// use external link
try {
$link = $repo->get_link($source);
} catch (repository_exception $e){
throw $e;
}
$info = array();
$info['filename'] = $saveas_filename;
$info['type'] = 'link';
$info['url'] = $link;
echo json_encode($info);
die;
} else {
// Download file to moodle
$file = $repo->get_file($source, $saveas_filename);
if ($file['path'] === false) {
$err->e = get_string('cannotdownload', 'repository');
die(json_encode($err));
}
// check if exceed maxbytes
if (($maxbytes!==-1) && (filesize($file['path']) > $maxbytes)) {
throw new file_exception('maxbytes');
}
// check if exceed user quota
$userquota = file_get_user_used_space();
if (filesize($file['path'])+$userquota>=(int)$CFG->userquota) {
throw new file_exception('userquotalimit');
}
$record = new stdclass;
$record->filepath = $saveas_path;
$record->filename = $saveas_filename;
$record->component = 'user';
$record->filearea = 'draft';
$record->itemid = $itemid;
if (!empty($file['license'])) {
$record->license = $file['license'];
} else {
$record->license = $license;
}
if (!empty($file['author'])) {
$record->author = $file['author'];
} else {
$record->author = $author;
}
$record->source = !empty($file['url']) ? $file['url'] : '';
$info = repository::move_to_filepool($file['path'], $record);
if (empty($info)) {
$info['e'] = get_string('error', 'moodle');
}
echo json_encode($info);
die;
}
die;
}
} catch (Exception $e) {
$err->e = $e->getMessage();
die(json_encode($err));
}
break;
case 'upload':
try {
$result = $repo->upload();
$result['client_id'] = $client_id;
echo json_encode($result);
} catch (Exception $e){
$err->e = $e->getMessage();
$err->client_id = $client_id;
die(json_encode($err));
}
$result = $repo->upload();
echo json_encode($result);
break;
}
+6 -15
View File
@@ -17,7 +17,7 @@
/**
* The Web service script that is called from the filepicker front end
* Repository instance callback script
*
* @since 2.0
* @package moodlecore
@@ -33,36 +33,27 @@ require_once(dirname(__FILE__).'/lib.php');
require_login();
/// Parameters
$repo_id = required_param('repo_id', PARAM_INT); // Repository ID
$client_id = optional_param('client_id', '', PARAM_RAW); // Client ID
$contextid = optional_param('ctx_id', SYSCONTEXTID, PARAM_INT); // Context ID
$repo_id = required_param('repo_id', PARAM_INT); // Repository ID
/// Headers to make it not cacheable
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Sat, 26 Jul 1997 05:00:00 GMT');
/// Check permissions
if (repository::check_context($contextid)) { //TODO: this is weird (skodak)
print_error('nopermissiontoaccess', 'repository');
}
/// Wait as long as it takes for this script to finish
set_time_limit(0);
/// Get repository instance information
$sql = 'SELECT i.name, i.typeid, r.type FROM {repository} r, {repository_instances} i '.
$sql = 'SELECT i.name, i.typeid, r.type, i.contextid FROM {repository} r, {repository_instances} i '.
'WHERE i.id=? AND i.typeid=r.id';
$repository = $DB->get_record_sql($sql, array($repo_id), '*', MUST_EXIST);
$type = $repository->type;
if (file_exists($CFG->dirroot.'/repository/'.$type.'/repository.class.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/repository.class.php');
if (file_exists($CFG->dirroot.'/repository/'.$type.'/lib.php')) {
require_once($CFG->dirroot.'/repository/'.$type.'/lib.php');
$classname = 'repository_' . $type;
$repo = new $classname($repo_id, $contextid, array('ajax'=>true, 'name'=>$repository->name, 'type'=>$type, 'client_id'=>$client_id)); //TODO: this is very weird constructor! (skodak)
$repo = new $classname($repo_id, $repository->contextid);
} else {
print_error('invalidplugin', 'repository', $type);
}
+15
View File
@@ -1,5 +1,20 @@
<?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/>.
function xmldb_repository_upload_install() {
global $CFG;
$result = true;
@@ -16,37 +16,21 @@
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* repository_upload class
* A subclass of repository, which is used to upload file
* A repository plugin to allow user uploading files
*
* @since 2.0
* @package moodlecore
* @subpackage repository
* @copyright 2009 Dongsheng Cai
* @author Dongsheng Cai <dongsheng@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class repository_upload extends repository {
/**
*
* @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->itemid = optional_param('itemid', '', PARAM_INT);
$this->license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT);
$this->author = optional_param('author', '', PARAM_TEXT);
$this->filepath = urldecode(optional_param('savepath', '/', PARAM_PATH));
}
private $mimetypes = array();
/**
* Print a upload form
*
* @return array
*/
public function print_login() {
@@ -55,44 +39,101 @@ class repository_upload extends repository {
/**
* Process uploaded file
*
* @return array
* @return array|bool
*/
public function upload() {
try {
$record = new stdclass;
$record->filearea = 'draft';;
$record->component = 'user';;
$record->filepath = $this->filepath;
$record->itemid = $this->itemid;
$record->license = $this->license;
$record->author = $this->author;
$this->info = $this->upload_to_filepool('repo_upload_file', $record);
} catch(Exception $e) {
throw $e;
global $USER, $CFG;
$types = optional_param('accepted_types', '*', PARAM_RAW);
if ((is_array($types) and in_array('*', $types)) or $types == '*') {
$this->mimetypes = '*';
} else {
foreach ($types as $type) {
$this->mimetypes[] = mimeinfo('type', $type);
}
}
return $this->info;
$record = new stdclass;
$record->filearea = 'draft';
$record->component = 'user';
$record->filepath = urldecode(optional_param('savepath', '/', PARAM_PATH));
$record->itemid = optional_param('itemid', 0, PARAM_INT);
$record->license = optional_param('license', $CFG->sitedefaultlicense, PARAM_TEXT);
$record->author = optional_param('author', '', PARAM_TEXT);
$context = get_context_instance(CONTEXT_USER, $USER->id);
$elname = 'repo_upload_file';
$fs = get_file_storage();
$browser = get_file_browser();
if ($record->filepath !== '/') {
$record->filepath = file_correct_filepath($record->filepath);
}
if (!isset($_FILES[$elname])) {
throw new moodle_exception('nofile');
}
if (!empty($_FILES[$elname]['error'])) {
throw new moodle_exception('maxbytes');
}
if (empty($record->filename)) {
$record->filename = $_FILES[$elname]['name'];
}
if ($this->mimetypes != '*') {
// check filetype
if (!in_array(mimeinfo('type', $_FILES[$elname]['name']), $this->mimetypes)) {
throw new moodle_exception('invalidfiletype', 'repository', '', mimeinfo('type', $_FILES[$elname]['name']));
}
}
$userquota = file_get_user_used_space();
if (filesize($_FILES[$elname]['tmp_name'])+$userquota>=(int)$CFG->userquota) {
throw new file_exception('userquotalimit');
}
if (empty($record->itemid)) {
$record->itemid = 0;
}
if ($file = $browser->get_file_info($context, $record->filearea, $record->itemid, $record->filepath, $record->filename)) {
$file->delete();
//throw new moodle_exception('fileexist');
}
$record->contextid = $context->id;
$record->userid = $USER->id;
$record->source = '';
$stored_file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']);
return array(
'url'=>file_draftfile_url($record->itemid, $record->filepath, $record->filename),
'id'=>$record->itemid,
'file'=>$record->filename);
}
/**
* Return a upload form
* @return array
*/
public function get_listing() {
global $CFG;
$ret = array();
$ret['nologin'] = true;
$ret['nosearch'] = true;
$ret['norefresh'] = true;
// define upload form in file picker
$ret['upload'] = array('label'=>get_string('attachment', 'repository'), 'id'=>'repo-form');
if (has_capability('moodle/course:managefiles', $this->context)) {
$ret['manage'] = $CFG->wwwroot .'/files/index.php';
}
$ret['list'] = array();
$ret['dynload'] = false;
$ret['upload'] = array('label'=>get_string('attachment', 'repository'), 'id'=>'repo-form');
return $ret;
}
/**
* Define the name of this repository
* Define the readable name of this repository
* @return string
*/
public function get_name(){
@@ -110,63 +151,12 @@ class repository_upload extends repository {
/**
* Upload file to local filesystem pool
* @param string $elname name of element
* @param object $record
* @param string $filearea
* @param string $filepath
* @param string $filename - use specified filename, if not specified name of uploaded file used
* @param bool $override override file if exists
* @return mixed stored_file object or false if error; may throw exception if duplicate found
*/
public function upload_to_filepool($elname, $record, $override = true) {
global $USER, $CFG;
$context = get_context_instance(CONTEXT_USER, $USER->id);
$fs = get_file_storage();
if ($record->filepath !== '/') {
$record->filepath = trim($record->filepath, '/');
$record->filepath = '/'.$record->filepath.'/';
}
if (!isset($_FILES[$elname])) {
throw new moodle_exception('nofile');
}
if (!empty($_FILES[$elname]['error'])) {
throw new moodle_exception('maxbytes');
}
if (empty($record->filename)) {
$record->filename = $_FILES[$elname]['name'];
}
if (empty($record->itemid)) {
$record->itemid = 0;
}
if ($file = $fs->get_file($context->id, 'user', 'draft', $record->itemid, $record->filepath, $record->filename)) {
if ($override) {
$file->delete();
} else {
throw new moodle_exception('fileexist');
}
}
$record->contextid = $context->id;
$record->component = 'user';
$record->filearea = 'draft';
$record->userid = $USER->id;
$record->source = '';
try {
$file = $fs->create_file_from_pathname($record, $_FILES[$elname]['tmp_name']);
} catch (Exception $e) {
//TODO: ??? (skodak)
$e->obj = $_FILES[$elname];
throw $e;
}
return array(
'url'=>file_draftfile_url($file->get_itemid(), $file->get_filepath(), $file->get_filename()),
'id'=>$record->itemid,
'file'=>$file->get_filename()
);
}
}
+152 -689
View File
@@ -1,702 +1,165 @@
<?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
*/
// 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/>.
/**
* 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.
* repository_url class
* A subclass of repository, which is used to download a file from a specific url
*
* 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.
* @since 2.0
* @package moodlecore
* @subpackage repository
* @copyright 2009 Dongsheng Cai
* @author Dongsheng Cai <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
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'];
require_once(dirname(__FILE__).'/locallib.php');
// 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'] );
class repository_url extends repository {
// 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'];
/**
* @param int $repositoryid
* @param object $context
* @param array $options
*/
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()){
global $CFG;
parent::__construct($repositoryid, $context, $options);
if (!empty($options['client_id'])) {
// will be used to construct download form
$this->client_id = $options['client_id'];
}
$this->file_url = optional_param('file', '', PARAM_RAW);
}
// 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 );
}
public function get_file($url, $file = '') {
global $CFG;
//$CFG->repository_no_delete = true;
$path = $this->prepare_file($file);
$fp = fopen($path, 'w');
$c = new curl;
$c->download(array(array('url'=>$url, 'file'=>$fp)));
return array('path'=>$path, 'url'=>$url);
}
// If relative URL path doesn't start with /, merge with base path
if ( $r['path'][0] != '/' )
{
$base = mb_strrchr( $b['path'], '/', TRUE, 'UTF-8' );
if ( $base === FALSE ) $base = '';
$r['path'] = $base . '/' . $r['path'];
}
$r['path'] = url_remove_dot_segments( $r['path'] );
return join_url( $r );
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-'.$this->client_id;
$url->type = 'text';
$url->name = 'file';
$ret['login'] = array($url);
$ret['login_btn_label'] = get_string('download', 'repository_url');
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='') {
global $CFG, $OUTPUT;
$ret = array();
$curl = new curl;
$msg = $curl->head($this->file_url);
$info = $curl->get_info();
if ($info['http_code'] != 200) {
$ret['e'] = $msg;
} else {
$ret['list'] = array();
$ret['nosearch'] = true;
$ret['nologin'] = true;
$filename = $this->guess_filename($info['url'], $info['content_type']);
if (strstr($info['content_type'], 'text/html') || empty($info['content_type'])) {
// analysis this web page, general file list
$ret['list'] = array();
$content = $curl->get($info['url']);
$this->analyse_page($info['url'], $content, $ret);
} else {
// download this file
$ret['list'][] = array(
'title'=>$filename,
'source'=>$this->file_url,
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($filename, 32))
);
}
}
return $ret;
}
public function analyse_page($baseurl, $content, &$list) {
global $CFG, $OUTPUT;
$urls = extract_html_urls($content);
$images = $urls['img']['src'];
$pattern = '#img(.+)src="?\'?([[:alnum:]:?=&@/._+-]+)"?\'?#i';
if (!empty($images)) {
foreach($images as $url) {
$list['list'][] = array(
'title'=>$this->guess_filename($url, ''),
'source'=>url_to_absolute($baseurl, $url),
'thumbnail'=>url_to_absolute($baseurl, $url),
'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];
}
}
public function get_name(){
return get_string('pluginname', 'repository_url');;
}
public function supported_returntypes() {
return (FILE_INTERNAL | FILE_EXTERNAL);
}
}
/**
* 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 != '/' &&
(mb_strlen($path)-1) == mb_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", "[email protected]",
* "example.com:80", "user:[email protected]: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=TRUE )
{
// 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=TRUE )
{
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;
}
/**
* 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;
}
+702
View File
@@ -0,0 +1,702 @@
<?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
*/
/**
* 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 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 = mb_strrchr( $b['path'], '/', TRUE, 'UTF-8' );
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 != '/' &&
(mb_strlen($path)-1) == mb_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", "[email protected]",
* "example.com:80", "user:[email protected]: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=TRUE )
{
// 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=TRUE )
{
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;
}
/**
* 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;
}
-165
View File
@@ -1,165 +0,0 @@
<?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/>.
/**
* repository_url class
* A subclass of repository, which is used to download a file from a specific url
*
* @since 2.0
* @package moodlecore
* @subpackage repository
* @copyright 2009 Dongsheng Cai
* @author Dongsheng Cai <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(dirname(__FILE__).'/lib.php');
class repository_url extends repository {
/**
* @param int $repositoryid
* @param object $context
* @param array $options
*/
public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()){
global $CFG;
parent::__construct($repositoryid, $context, $options);
if (!empty($options['client_id'])) {
// will be used to construct download form
$this->client_id = $options['client_id'];
}
$this->file_url = optional_param('file', '', PARAM_RAW);
}
public function get_file($url, $file = '') {
global $CFG;
//$CFG->repository_no_delete = true;
$path = $this->prepare_file($file);
$fp = fopen($path, 'w');
$c = new curl;
$c->download(array(array('url'=>$url, 'file'=>$fp)));
return array('path'=>$path, 'url'=>$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-'.$this->client_id;
$url->type = 'text';
$url->name = 'file';
$ret['login'] = array($url);
$ret['login_btn_label'] = get_string('download', 'repository_url');
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='') {
global $CFG, $OUTPUT;
$ret = array();
$curl = new curl;
$msg = $curl->head($this->file_url);
$info = $curl->get_info();
if ($info['http_code'] != 200) {
$ret['e'] = $msg;
} else {
$ret['list'] = array();
$ret['nosearch'] = true;
$ret['nologin'] = true;
$filename = $this->guess_filename($info['url'], $info['content_type']);
if (strstr($info['content_type'], 'text/html') || empty($info['content_type'])) {
// analysis this web page, general file list
$ret['list'] = array();
$content = $curl->get($info['url']);
$this->analyse_page($info['url'], $content, $ret);
} else {
// download this file
$ret['list'][] = array(
'title'=>$filename,
'source'=>$this->file_url,
'thumbnail' => $OUTPUT->pix_url(file_extension_icon($filename, 32))
);
}
}
return $ret;
}
public function analyse_page($baseurl, $content, &$list) {
global $CFG, $OUTPUT;
$urls = extract_html_urls($content);
$images = $urls['img']['src'];
$pattern = '#img(.+)src="?\'?([[:alnum:]:?=&@/._+-]+)"?\'?#i';
if (!empty($images)) {
foreach($images as $url) {
$list['list'][] = array(
'title'=>$this->guess_filename($url, ''),
'source'=>url_to_absolute($baseurl, $url),
'thumbnail'=>url_to_absolute($baseurl, $url),
'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];
}
}
public function get_name(){
return get_string('pluginname', 'repository_url');;
}
public function supported_returntypes() {
return (FILE_INTERNAL | FILE_EXTERNAL);
}
}
@@ -69,23 +69,19 @@ class repository_user extends repository {
$ret['nologin'] = true;
$list = array();
//TODO: this is weird, why not only user context? (skodak)
if (!empty($encodedpath)) {
$params = unserialize(base64_decode($encodedpath));
if (is_array($params)) {
$itemid = $params['itemid'];
$filename = $params['filename'];
$filearea = $params['filearea'];
$component = $params['component'];
$filepath = $params['filepath'];
$context = get_context_instance_by_id($params['contextid']);
}
} else {
$itemid = 0;
$filename = null;
$component = 'user';
$filearea = 'private';
$filearea = 'user_private';
$filepath = '/';
$context = get_context_instance(CONTEXT_USER, $USER->id);
}
@@ -93,11 +89,11 @@ class repository_user extends repository {
try {
$browser = get_file_browser();
if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
if ($fileinfo = $browser->get_file_info($context, $filearea, $itemid, $filepath, $filename)) {
$pathnodes = array();
$level = $fileinfo;
$params = $fileinfo->get_params();
while ($level && $params['filearea'] == 'private' && $params['component'] == 'user') {
while ($level && $params['filearea'] == 'user_private') {
$encodedpath = base64_encode(serialize($level->get_params()));
$pathnodes[] = array('name'=>$level->get_visible_name(), 'path'=>$encodedpath);
$level = $level->get_parent();
@@ -170,7 +166,7 @@ class repository_user extends repository {
* @param string $new_filepath the new path in draft area
* @return array The information of file
*/
public function copy_to_area($encoded, $new_filearea='ignored', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
public function copy_to_area($encoded, $new_filearea='user_draft', $new_itemid = '', $new_filepath = '/', $new_filename = '') {
global $USER, $DB;
$info = array();
@@ -179,15 +175,14 @@ class repository_user extends repository {
$user_context = get_context_instance(CONTEXT_USER, $USER->id);
// the final file
$contextid = $params['contextid'];
$component = $params['component'];
$filearea = $params['filearea'];
$filepath = $params['filepath'];
$filename = $params['filename'];
$fileitemid = $params['itemid'];
$context = get_context_instance_by_id($contextid);
try {
$file_info = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
$file_info->copy_to_storage($user_context->id, 'user', 'draft', $new_itemid, $new_filepath, $new_filename);
$file_info = $browser->get_file_info($context, $filearea, $fileitemid, $filepath, $filename);
$file_info->copy_to_storage($user_context->id, $new_filearea, $new_itemid, $new_filepath, $new_filename);
} catch (Exception $e) {
throw $e;
}