This commit is contained in:
Xes
2025-08-14 22:39:38 +02:00
parent 3641e93527
commit 5403f346e3
3370 changed files with 327179 additions and 0 deletions

142
plugin/vchamilo/README.md Normal file
View File

@@ -0,0 +1,142 @@
Virtual Chamilo
===================
Authors : Valery Fremaux (valery.fremaux@gmail.com), Julio Montoya, Angel Quiroz, Yannick Warnier
Virtual Chamilo (or vChamilo) is a feature that allows you to easily run several chamilo instances
sharing the same code base, with separate documents and databases, acting mostly like containers
sharing the same libraries.
With vChamilo, your first Chamilo portal acts as a container (or "controller"), and a seed
(or image) for the Chamilo instances you will install afterwards. This first image should be
created automatically when configuring the plugin, but if it isn't, the plugin will tell you
so and ask to generate one through the interface.
Once the plugin is fully setup, you will be able to create new Chamilo instances in a
matter of minutes (or seconds on powerful servers).
Changelog
=========
*Version 1.7*
Added support for (optional) custom CSS folder
Database upgrade needed:
ALTER TABLE vchamilo ADD COLUMN css_theme_folder varchar(255);
*Version 1.6*
Database upgrade needed:
ALTER TABLE vchamilo ADD COLUMN archive_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN home_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN upload_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN course_url varchar(255);
*Version 1.5*
Improved usability and added validations. No DB update required.
*Version 1.4*
Database upgrade needed:
ALTER TABLE vchamilo ADD COLUMN password_encryption VARCHAR(255);
*Version 1.3*
Added vchamilo import
Version features
===================
This is still a beta version and it is not fully featured with back-office tools.
As such, you will be able to create, edit, copy, delete and even upgrade instances, but a certain
amount of manual work will still be required at the web server level to get your instances running.
How to setup
===================
To set this plugin up, you will need to:
1. Insert the virtualization hook into the Chamilo master configuration file and enable multi-urls:
```
<chamiloroot>/app/config/configuration.php
```
Insert the hook at the end of the file.
```
include_once $_configuration['root_sys'].'plugin/vchamilo/lib/Virtual.php';
Virtual::hookConfiguration($_configuration);
```
And add (or uncomment) the line to enable multi-url:
```
$_configuration['multiple_access_urls'] = true;
```
At this point, make sure there is no caching mechanism maintaining the previous configuration
version before you continue. Enabling the multi-url option should have the immediate effect
of adding a multi-url management link at the bottom of the "Platform" block in the
administration main page.
Take a moment to update the configuration of the default host in the multi-url configuration page
to the real hostname of your main (controller) portal.
2. Change the permissions on the <chamiloroot>/plugin/vchamilo/templates/ directory as it will
be necessary for the plugin to create files and directories there
3. Create a common directory to be used for all Chamilo-related files.
We recommend using <chamiloroot>/var/ for that. Inside that directory, create the following 4
directories: cache/, courses/, home/ and upload/ and give permissions to the web user to write
into them (exactly the same way you did it for the app/ directory when installing Chamilo)
4. Enable and configure the plugin in the Chamilo administration's plugins list
(if in doubt, use the suggested values). Please note that the proxy configuration part is
totally optional and is not maintained by the Chamilo team at this point.
5. Enable additional virtual hosts in your Apache config (unless you use subdirectories). All virtual hosts should point to the same DocumentRoot as the initial Chamilo installation.
6. For each virtual host or subdirectory, you will need to configure specific redirection rules (remember, this is still at beta-level):
```
RewriteEngine On
RewriteRule /app/upload/(.*)$ http://[vchamilo-instance-domain]/[selected-common-dir]/upload/[vchamilo-instance-dir]/$1 [QSA,L]
```
In the example above, you would need to replace everything that is currently within brackets, with
the specific details of each instance. For example:
```
RewriteRule /app/upload/(.*)$ http://beeznest.chamilo.net/var/upload/beeznest-chamilo-net/$1 [QSA,L]
```
Although your vChamilo instances *will* work basically without this rewrite rule, you will end
up observing issues of files not appearing while uploading files on the instance.
Note that the domain of the instance, in the last part of the path, will be transformed
from dot-separated domain (beeznest.chamilo.net) to dash-separated-domain (beeznest-chamilo-net).
7. Finally, go to the "Instances manager" and create new instances. Once an instance has been
created, make sure you edit it and set the "Cache URL" (previously "Archive URL"), "Home URL" and "Upload URL". These should
have the form of the "Web root" of the instance + the common directory + {cache|home|upload} + the
instance domain with dots changed to hyphens.
For example, if you have used "var/" as a common directory and your instance URL (Web Root) is
https://chamilo1.beeznest.com/, then your "Cache URL" would look like this:
https://chamilo1.beeznest.com/var/cache/chamilo1-beeznest-com/
These settings might be complex to setup at first, but once you've created your first instance,
creating a hundred more should be easy.
Important note about file system permissions
-------------
vChamilo instances *need* a central directory where to store all their files. You should create
that directory (as mentioned in point 3 above) and make sure it has the right permissions.
The plugin/vchamilo/templates/ directory also needs to be writeable by the web server.
Additional notes
-------------
The vChamilo plugin can work in combination with the "Chamilo Shell":https://github.com/chamilo/chamilo-lms
(or "chash") to ensure a good level of automatization of heavy processes, like upgrading to a higher version.
Although upgrading still has a manual process (in part), it will certainly save you dozens of hours if
upgrading dozens of portals.

View File

@@ -0,0 +1,25 @@
<?php
/* For licensing terms, see /license.txt */
require_once __DIR__.'/../../../main/inc/global.inc.php';
api_protect_admin_script();
$action = $_GET['what'] ?? '';
define('CHAMILO_INTERNAL', true);
$plugin = VChamiloPlugin::create();
$thisurl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
switch ($action) {
case 'syncthis':
$res = include_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/syncparams.controller.php';
if (!$res) {
echo '<span class="label label-success">Success</span>';
} else {
echo '<span class="label label-danger">Failure<br/>'.$errors.'</span>';
}
break;
}
exit;

View File

@@ -0,0 +1,218 @@
<?php
exit;
global $debuglevel;
global $debugdisplay;
$debuglevel = 4;
$debugdisplay = 4;
define('CLI_SCRIPT', true);
define('CHAMILO_INTERNAL', true);
// this will only run on master chamilo
echo "Starting tool\n";
echo "Chamilo Bulk Nodes Creation v.1.0\n";
echo "=================================\n";
require_once('../../../main/inc/global.inc.php');
require_once('clilib.php'); // cli only functions
// Ensure errors are well explained
ini_set('debug_display', 1);
ini_set('debug_level', E_ALL);
// now get cli options
list($options, $unrecognized) = cli_get_params(
array(
'interactive' => false,
'help' => false,
'config' => false,
'nodes' => '',
'lint' => false,
'verbose' => false
),
array(
'h' => 'help',
'i' => 'interactive',
'c' => 'config',
'n' => 'nodes',
'l' => 'lint',
'v' => 'verbose'
)
);
$interactive = !empty($options['interactive']);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error("Cli unkown options\n".$unrecognized);
}
if ($options['help']) {
$help = "Command line VChamilo Generator.
Please note you must execute this script with the same uid as apache!
Options:
--interactive Blocks on each step and waits for input to continue
-h, --help Print out this help
-c, --config Define an external config file
-n, --nodes A node descriptor CSV file
-l, --lint Decodes node file and give a report on nodes to be created.
Example:
\$sudo -u www-data /usr/bin/php /var/www/chamilo/plugin/vchamilo/cli/bulkcreatenodes.php --nodes=<nodelist>
"; //TODO: localize - to be translated later when everything is finished
echo $help;
die;
}
// Get all options from config file.
if (!empty($options['config'])) {
echo "Loading config : ".$options['config'];
if (!file_exists($options['config'])) {
cli_error('Config file mentioned but not found');
}
$content = file($options['config']);
foreach ($content as $l) {
if (preg_match('/^\s+$/', $l)) continue; // Empty lines.
if (preg_match('/^[#\/!;]/', $l)) continue; // Comments (any form).
if (preg_match('/^(.*?)=(.*)$/', $l, $matches)) {
if (in_array($matches[1], $expectedoptions)) {
$options[trim($matches[1])] = trim($matches[2]);
}
}
}
}
require_once($_configuration['root_sys'].'local/classes/database.class.php'); // cli only functions
require_once($_configuration['root_sys'].'local/classes/textlib.class.php'); // cli only functions
require_once($_configuration['root_sys'].'local/classes/mootochamlib.php'); // moodle like API
require_once($_configuration['root_sys'].'/plugin/vchamilo/lib/vchamilo_plugin.class.php');
global $DB;
if ($options['verbose']) echo "building database manager\n";
$DB = new DatabaseManager();
if ($options['verbose']) echo "building plugin vchamilo\n";
$plugin = VChamiloPlugin::create();
if (empty($options['nodes'])) {
cli_error('Missing node definition. Halt.');
}
if ($options['verbose']) echo "parsing nodelist\n";
$nodes = vchamilo_parse_csv_nodelist($options['nodes'], $plugin);
if ($options['lint']) {
ctrace("Lint mode:\n");
print_object($nodes);
die;
}
if (empty($nodes)) {
cli_error('Node list empty');
}
ctrace('Starting generation');
// Get main admin for further replacement.
$admin = $DB->get_record('user', array('username' => 'admin'));
foreach ($nodes as $data) {
ctrace('Making node '.$data->root_web);
if (!empty($data->template)) {
ctrace('Using template '.$data->template);
if (!vchamilo_template_exists($data->template)) {
ctrace('Template not found. Skipping node.');
continue;
}
}
if ($DB->get_record('vchamilo', array('root_web' => $data->root_web))) {
ctrace('Node exists. skipping');
continue;
}
$data->what = 'addinstance';
$data->registeronly = false;
$NDB = null;
$automation = true;
$return = include($_configuration['root_sys'].'plugin/vchamilo/views/editinstance.controller.php');
if ($return == -1) {
cli_error('Node create process error');
}
// This is specific code for presetting any plugin data per instance from the CSV
ctrace('Setting up ent_installer');
if ($NDB) {
// Copy admin account info from master
$NDB->set_field('user', 'password', $admin->password, array('username' => 'admin'), 'user_id');
// Setting ENT_installer values
if (!empty($data->ent_installer)) {
foreach ($data->ent_installer as $setting => $value) {
$settingrec = new StdClass();
$settingrec->variable = 'ent_installer_'.$setting;
$settingrec->subkey = 'ent_installer';
$settingrec->type = 'setting';
$settingrec->category = 'Plugins';
$settingrec->access_url = 1;
$settingrec->selected_value = $value;
ctrace("Setting up {$settingrec->variable}|{$settingrec->subkey} to $value\n");
if ($oldrec = $NDB->get_record('settings_current', array('variable' => $settingrec->variable, 'subkey' => $settingrec->subkey, 'type' => $settingrec->type))) {
$settingrec->id = $oldrec->id;
$NDB->update_record('settings_current', $settingrec, 'id');
} else {
$NDB->insert_record('settings_current', $settingrec);
}
}
}
// updating other config values
if (!empty($data->config)) {
ctrace("VChamilo has config overrides\n");
foreach ($data->config as $configkey => $configsetting) {
ctrace("Setting up {$configkey}");
// Note you can just alter existing settings here as we cannot pull enough data from csv headers to get a complete setting descriptor.
$settingrec = new StdClass();
$settingrec->variable = $configkey;
if (!empty($settingrec->subkey)) {
$settingrec->subkey = $configsetting->subkey;
}
// $settingrec->type = 'setting';
// $settingrec->category = 'Plugins';
// $settingrec->access_url = 1;
$settingrec->selected_value = $configsetting->value;
if (!empty($settingrec->subkey)) {
$params = array('variable' => $settingrec->variable, 'subkey' => $settingrec->subkey);
} else {
$params = array('variable' => $settingrec->variable);
}
if ($oldrec = $NDB->get_record('settings_current', $params)) {
ctrace("Updating {$settingrec->variable}|{$settingrec->subkey} to $configsetting->value\n");
$settingrec->id = $oldrec->id;
$NDB->update_record('settings_current', $settingrec, 'id');
}
}
}
$NDB->dismount();
} else {
ctrace('No Side CNX for setup');
}
if ($interactive) {
$input = readline("Continue (y/n|r) ?\n");
if ($input == 'r' || $input == 'R') {
// do nothing, just continue
} elseif ($input == 'n' || $input == 'N') {
echo "finishing\n";
exit;
}
}
}

View File

@@ -0,0 +1,170 @@
<?php
exit;
/**
* This script is to be used from PHP command line and will create a set
* of Virtual VChamilo automatically from a CSV nodelist description.
* The standard structure of the nodelist is given by the nodelist-dest.csv file.
*/
global $debuglevel;
global $debugdisplay;
$debuglevel = 4;
$debugdisplay = 4;
define('CLI_SCRIPT', true);
define('CHAMILO_INTERNAL', true);
// this will only run on master chamilo
echo "Starting tool\n";
echo "Chamilo Bulk Nodes Creation v.1.0\n";
echo "=================================\n";
require_once('../../../main/inc/global.inc.php');
require_once('clilib.php'); // cli only functions
// Ensure errors are well explained
ini_set('debug_display', 1);
ini_set('debug_level', E_ALL);
// Now get cli options.
list($options, $unrecognized) = cli_get_params(
array(
'interactive' => false,
'help' => false,
'config' => false,
'nodes' => '',
'lint' => false
),
array(
'h' => 'help',
'c' => 'config',
'n' => 'nodes',
'i' => 'interactive',
'l' => 'lint'
)
);
$interactive = !empty($options['interactive']);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help']) {
$help =
"Command line VMoodle Generator.
Please note you must execute this script with the same uid as apache!
Options:
--interactive No interactive questions or confirmations
-h, --help Print out this help
-c, --config Define an external config file
-n, --nodes A node descriptor CSV file
-l, --lint Decodes node file and give a report on nodes to be created.
Example:
\$sudo -u www-data /usr/bin/php /var/www/chamilo19/plugin/vchamilo/cli/bulkdestroynodes.php --nodes=<node-file-path>
"; //TODO: localize - to be translated later when everything is finished
echo $help;
die;
}
// Get all options from config file.
if (!empty($options['config'])) {
echo "Loading config : ".$options['config'];
if (!file_exists($options['config'])) {
cli_error(get_string('confignotfound', 'block_vmoodle'));
}
$content = file($options['config']);
foreach ($content as $l) {
if (preg_match('/^\s+$/', $l)) {
continue; // Empty lines.
}
if (preg_match('/^[#\/!;]/', $l)) {
continue; // Comments (any form).
}
if (preg_match('/^(.*?)=(.*)$/', $l, $matches)) {
if (in_array($matches[1], $expectedoptions)) {
$options[trim($matches[1])] = trim($matches[2]);
}
}
}
}
require_once($_configuration['root_sys'].'local/classes/database.class.php'); // cli only functions
if ($options['verbose']) {
echo "loaded dbclass\n";
}
require_once($_configuration['root_sys'].'local/classes/textlib.class.php'); // cli only functions
if ($options['verbose']) {
echo "loaded textlib\n";
}
require_once($_configuration['root_sys'].'local/classes/mootochamlib.php'); // moodle like API
if ($options['verbose']) {
echo "loaded moodle wrapping\n";
}
require_once($_configuration['root_sys'].'/plugin/vchamilo/lib/vchamilo_plugin.class.php');
if ($options['verbose']) {
echo "loaded vchamilo plugin\n";
}
global $DB;
if ($options['verbose']) {
echo "building database manager\n";
}
$DB = new DatabaseManager();
if ($options['verbose']) {
echo "building plugin vchamilo\n";
}
$plugin = VChamiloPlugin::create();
if (empty($options['nodes'])) {
cli_error(get_string('climissingnodes', 'block_vmoodle'));
}
if ($options['verbose']) {
echo "parsing nodelist\n";
}
$nodes = vchamilo_parse_csv_nodelist($options['nodes'], $plugin);
if ($options['lint']) {
ctrace("Lint mode:\n");
print_object($nodes);
die;
}
if (empty($nodes)) {
cli_error(get_string('cliemptynodelist', 'block_vmoodle'));
}
ctrace('Starting CLI processing');
foreach ($nodes as $n) {
ctrace('Destroying node :'.$n->vhostname);
if (!$DB->get_record('vchamilo', array('root_web' => $n->root_web))) {
ctrace('Node does not exist. Skipping');
continue;
}
/*
* This launches automatically all steps of the controller.management.php script several times
* with the "doadd" action and progressing in steps.
*/
$action = "fulldeleteinstances";
$automation = true;
$return = include($_configuration['root_sys'].'/plugin/vchamilo/views/manage.controller.php');
if ($interactive) {
$input = readline("Continue (y/n|r) ?\n");
if ($input == 'r' || $input == 'R') {
$vmoodlestep--;
} elseif ($input == 'n' || $input == 'N') {
echo "finishing\n";
exit(0);
}
}
}
exit (0);

View File

@@ -0,0 +1,343 @@
<?php
exit;
/**
* Opens and parses/checks a VChamilo instance definition file
* @param string $nodelistlocation
* @param string $plugin
* @return mixed
*/
function vchamilo_parse_csv_nodelist($nodelistlocation = '', $plugin = null) {
global $_configuration;
$vnodes = array();
if (empty($nodelistlocation)) {
$nodelistlocation = $_configuration['root_sys'].'/plugin/vchamilo/nodelist.csv';
}
// decode file
$csv_delimiter = "\;";
$csv_delimiter2 = ";";
// make arrays of valid fields for error checking
$required = array(
'root_web' => 1,
'sitename' => 1,
'institution' => 1,
'main_database' => 1,
'statistics_database' => 1,
'user_personal_database' => 1,
'db_user' => 1,
'db_password' => 1,
'course_folder' => 1,
);
$optional = array(
'db_host' => 1,
'template' => 1,
'table_prefix' => 1,
'single_database' => 1,
'tracking_enabled' => 1,
'visible' => 1,
);
$optionalDefaults = array(
'db_host' => $_configuration['db_host'],
'db_prefix' => 'chm_',
'table_prefix' => '',
'tracking_enabled' => 0,
'single_database' => 1,
'template' => '',
'visible' => 1
);
$patterns = array();
// Metas are accepted patterns (optional)
$metas = array(
'plugin_.*',
'config_.*'
);
// Get header (field names)
$textlib = new textlib();
if (!$fp = fopen($nodelistlocation, 'rb')) {
cli_error($plugin->get_lang('badnodefile', 'vchamilo', $nodelistlocation));
}
// Jump any empty or comment line
$text = fgets($fp, 1024);
$i = 0;
while (vchamilo_is_empty_line_or_format($text, $i == 0)) {
$text = fgets($fp, 1024);
$i++;
}
$headers = explode($csv_delimiter2, $text);
// Check for valid field names
foreach ($headers as $h) {
$header[] = trim($h);
$patternized = implode('|', $patterns)."\\d+";
$metapattern = implode('|', $metas);
if (!(isset($required[$h]) ||
isset($optionalDefaults[$h]) ||
isset($optional[$h]) ||
preg_match("/$patternized/", $h) ||
preg_match("/$metapattern/", $h))) {
cli_error("Node parse : invalidfieldname $h ");
return;
}
if (isset($required[trim($h)])) {
$required[trim($h)] = 0;
}
}
$expectedcols = count($headers);
$i++;
// Check for required fields.
foreach ($required as $key => $value) {
if ($value) { // Required field missing.
cli_error("fieldrequired $key");
return;
}
}
$linenum = 2; // Since header is line 1.
// Take some from admin profile, other fixed by hardcoded defaults.
while (!feof($fp)) {
// Make a new base record.
$vnode = new StdClass();
foreach ($optionalDefaults as $key => $value) {
$vnode->$key = $value;
}
//Note: commas within a field should be encoded as &#44 (for comma separated csv files)
//Note: semicolon within a field should be encoded as &#59 (for semicolon separated csv files)
$text = fgets($fp, 1024);
if (vchamilo_is_empty_line_or_format($text, false)) {
$i++;
continue;
}
$valueset = explode($csv_delimiter2, $text);
if (count($valueset) != $expectedcols) {
cli_error('wrong line count at line '.$i);
}
$f = 0;
foreach ($valueset as $value) {
// Decode encoded commas.
$key = $headers[$f];
if (preg_match('/\|/', $key)) {
list($plugin, $variable) = explode('|', str_replace('plugin_', '', $key));
if (empty($variable)) die("Key error in CSV : $key ");
if (!isset($vnode->$plugin)) {
$vnode->$plugin = new StdClass();
}
$vnode->$plugin->$variable = trim($value);
} else {
if (preg_match('/^config_/', $key)) {
$smartkey = str_replace('config_', '', $key);
$keyparts = implode('|', $smartkey);
$keyvar = $keyparts[0];
$subkey = @$keyparts[1];
$vnode->config->$smartkey = new StdClass;
$vnode->config->$smartkey->subkey = $subkey;
$vnode->config->$smartkey->value = trim($value);
} else {
$vnode->$key = trim($value);
}
}
$f++;
}
$vnodes[] = $vnode;
}
return $vnodes;
}
/**
* Check a CSV input line format for empty or commented lines
* Ensures compatbility to UTF-8 BOM or unBOM formats
* @param resource $text
* @param bool $resetfirst
* @return bool
*/
function vchamilo_is_empty_line_or_format(&$text, $resetfirst = false) {
global $CFG;
static $textlib;
static $first = true;
// We may have a risk the BOM is present on first line
if ($resetfirst) $first = true;
if (!isset($textlib)) $textlib = new textlib(); // Singleton
$text = $textlib->trim_utf8_bom($text);
$first = false;
$text = preg_replace("/\n?\r?/", '', $text);
// last chance
if ('ASCII' == mb_detect_encoding($text)) {
$text = utf8_encode($text);
}
// Check the text is empty or comment line and answer true if it is.
return preg_match('/^$/', $text) || preg_match('/^(\(|\[|-|#|\/| )/', $text);
}
/**
* Get input from user
* @param string $prompt text prompt, should include possible options
* @param string $default default value when enter pressed
* @param array $options list of allowed options, empty means any text
* @param bool $casesensitiveoptions true if options are case sensitive
* @return string entered text
*/
function cli_input($prompt, $default = '', array $options = null, $casesensitiveoptions = false) {
echo $prompt;
echo "\n: ";
$input = fread(STDIN, 2048);
$input = trim($input);
if ($input === '') {
$input = $default;
}
if ($options) {
if (!$casesensitiveoptions) {
$input = strtolower($input);
}
if (!in_array($input, $options)) {
echo "Incorrect value, please retry.\n"; // TODO: localize, mark as needed in install
return cli_input($prompt, $default, $options, $casesensitiveoptions);
}
}
return $input;
}
/**
* Returns cli script parameters.
* @param array $longoptions array of --style options ex:('verbose'=>false)
* @param array $shortmapping array describing mapping of short to long style options ex:('h'=>'help', 'v'=>'verbose')
* @return array array of arrays, options, unrecognised as optionlongname=>value
*/
function cli_get_params(array $longoptions, array $shortmapping = null) {
$shortmapping = (array) $shortmapping;
$options = array();
$unrecognized = array();
if (empty($_SERVER['argv'])) {
// Bad luck, we can continue in interactive mode ;-)
return array($options, $unrecognized);
}
$rawoptions = $_SERVER['argv'];
// Remove anything after '--', options can not be there.
if (($key = array_search('--', $rawoptions)) !== false) {
$rawoptions = array_slice($rawoptions, 0, $key);
}
// Remove script.
unset($rawoptions[0]);
foreach ($rawoptions as $raw) {
if (substr($raw, 0, 2) === '--') {
$value = substr($raw, 2);
$parts = explode('=', $value);
if (count($parts) == 1) {
$key = reset($parts);
$value = true;
} else {
$key = array_shift($parts);
$value = implode('=', $parts);
}
if (array_key_exists($key, $longoptions)) {
$options[$key] = $value;
} else {
$unrecognized[] = $raw;
}
} else if (substr($raw, 0, 1) === '-') {
$value = substr($raw, 1);
$parts = explode('=', $value);
if (count($parts) == 1) {
$key = reset($parts);
$value = true;
} else {
$key = array_shift($parts);
$value = implode('=', $parts);
}
if (array_key_exists($key, $shortmapping)) {
$options[$shortmapping[$key]] = $value;
} else {
$unrecognized[] = $raw;
}
} else {
$unrecognized[] = $raw;
continue;
}
}
// Apply defaults.
foreach ($longoptions as $key=>$default) {
if (!array_key_exists($key, $options)) {
$options[$key] = $default;
}
}
// Finished.
return array($options, $unrecognized);
}
/**
* Print or return section separator string
* @param bool $return false means print, true return as string
* @return mixed void or string
*/
function cli_separator($return = false) {
$separator = str_repeat('-', 79)."\n";
if ($return) {
return $separator;
} else {
echo $separator;
}
}
/**
* Print or return section heading string
* @param string $string text
* @param bool $return false means print, true return as string
* @return mixed void or string
*/
function cli_heading($string, $return = false) {
$string = "== $string ==\n";
if ($return) {
return $string;
} else {
echo $string;
}
}
/**
* Write error notification
* @param $text
* @return void
*/
function cli_problem($text) {
fwrite(STDERR, $text."\n");
}
/**
* Write to standard out and error with exit in error.
*
* @param string $text
* @param int $errorCode
* @return void (does not return)
*/
function cli_error($text, $errorCode = 1) {
fwrite(STDERR, $text);
fwrite(STDERR, "\n");
die($errorCode);
}

View File

@@ -0,0 +1,77 @@
<?php
/* For license terms, see /license.txt */
exit;
/**
* This script should be called by a properly set cron process on your server.
* For more information, check the installation guide in the documentation
* folder.
* Add your own executable scripts below the inclusion of notification.php
* @package chamilo.cron
*/
/**
* Settings that will influence the execution of the cron tasks
*/
//ini_set('max_execution_time',300); //authorize execution for up to 5 minutes
//ini_set('memory_limit','100M'); //authorize script to use up to 100M RAM
/**
* Included cron-ed tasks. You might want to turn error-logging off by
* commenting the first and last line of this section.
*/
define('CLI_SCRIPT', true); // for chamilo imported code
define('CHAMILO_INTERNAL', true);
global $CLI_VCHAMILO_PRECHECK;
$CLI_VCHAMILO_PRECHECK = true; // force first config to be minimal
require __DIR__.'/../../../app/config/configuration.php'; // get boot config
require_once $_configuration['root_sys'].'plugin/vchamilo/cli/clilib.php'; // cli only functions
// Ensure errors are well explained
// now get cli options
list($options, $unrecognized) = cli_get_params(
array(
'help' => false,
'host' => false,
),
array(
'h' => 'help',
'H' => 'host'
)
);
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
}
if ($options['help']) {
$help =
"Command line chamilo CRON
Options:
-h, --help Print out this help
-H, --host Set the host (physical or virtual) to operate on
"; //TODO: localize - to be translated later when everything is finished
echo $help;
die;
}
if (!empty($options['host'])) {
// arms the vchamilo switching
echo('Arming for '.$options['host']."\n"); // mtrace not yet available.
define('CLI_VCHAMILO_OVERRIDE', $options['host']);
}
// replay full config whenever. If vchamilo switch is armed, will switch now config
require $_configuration['root_sys'].'app/config/configuration.php'; // do REALLY force configuration to play again, or the following call will not have config tweaked (require_once)
echo('Config check : playing for '.$_configuration['root_web']."\n");
error_log('[chamilo][cronjob] Starting cron jobs as process '.getmypid());
echo '<pre>';
echo ('[chamilo][cronjob] Starting cron jobs as process '.getmypid()."\n");
require_once $_configuration['root_sys'].'main/cron/notification.php';
error_log('[chamilo][cronjob] Ending cron jobs of process '.getmypid());
echo('[chamilo][cronjob] Ending cron jobs of process '.getmypid()."\n");
echo '</pre>';

View File

@@ -0,0 +1,25 @@
<?php
/* For license terms, see /license.txt */
exit;
/**
* This script should be called by a properly set cron process on your server.
* For more information, check the installation guide in the documentation
* folder.
* Add your own executable scripts below the inclusion of notification.php
* @package chamilo.cron
*/
/**
* Settings that will influence the execution of the cron tasks
*/
//ini_set('max_execution_time',300); //authorize execution for up to 5 minutes
//ini_set('memory_limit','100M'); //authorize script to use up to 100M RAM
/**
* Included cron-ed tasks. You might want to turn error-logging off by
* commenting the first and last line of this section.
*/
define('CLI_SCRIPT', true); // for chamilo imported code
define('CHAMILO_INTERNAL', true);
error_log('[chamilo][cronjob] Starting cron jobs as process '.getmypid());
require_once(dirname(dirname(dirname(__DIR__))).'/main/cron/notification.php');
error_log('[chamilo][cronjob] Ending cron jobs of process '.getmypid());

View File

@@ -0,0 +1,12 @@
#
# root_web : a fully qualified domain as wwwroot for the instance
# template : a VChamilo template name (stored from a vchamilo snapshot) or empty if no template
# tracking_enabled : 0 or 1
# single_database : 0 or 1
# main_database : the main database
# statistics_database : if empty, is using main_database
# user_personal_database : if empty, is using main_database
# course_folder : absolute path to course material
#
root_web;template;sitename;institution;db_host;db_user;db_password;table_prefix;db_prefix;tracking_enabled;single_database;main_database;statistics_database;user_personal_database;course_folder
1 #
2 # root_web : a fully qualified domain as wwwroot for the instance
3 # template : a VChamilo template name (stored from a vchamilo snapshot) or empty if no template
4 # tracking_enabled : 0 or 1
5 # single_database : 0 or 1
6 # main_database : the main database
7 # statistics_database : if empty, is using main_database
8 # user_personal_database : if empty, is using main_database
9 # course_folder : absolute path to course material
10 #
11 root_web;template;sitename;institution;db_host;db_user;db_password;table_prefix;db_prefix;tracking_enabled;single_database;main_database;statistics_database;user_personal_database;course_folder

27
plugin/vchamilo/index.php Normal file
View File

@@ -0,0 +1,27 @@
<?php
/**
* @package chamilo.plugin.vchamilo
*/
api_protect_admin_script();
global $virtualChamilo;
$plugin = VChamiloPlugin::create();
// See also the share_user_info plugin
$_template['show_message'] = true;
$_template['title'] = $plugin->get_lang('hostlist');
$table = Database::get_main_table('vchamilo');
$sql = "SELECT sitename, root_web FROM $table WHERE visible = 1";
if ($virtualChamilo == '%') {
$result = Database::query($sql);
$_template['hosts'] = [];
if ($result) {
while ($vchamilo = Database::fetch_assoc($result)) {
$_template['hosts'][] = $vchamilo;
}
}
}

View File

@@ -0,0 +1,79 @@
<?php
/* PHP code to install the plugin
* For example:
*
// To query something to the database
$table = Database::get_main_table(TABLE_MAIN_USER); // TABLE_MAIN_USER is a constant check the main/inc/database.constants.inc.php
$sql = "SELECT firstname, lastname FROM $table_users ";
$users = Database::query($sql);
You can also use the Chamilo classes
$users = UserManager::get_user_list();
*/
api_protect_admin_script();
$table = 'vchamilo';
$tablename = Database::get_main_table($table);
$sql = "
CREATE TABLE IF NOT EXISTS $tablename (
id int NOT NULL AUTO_INCREMENT,
sitename varchar(80) NOT NULL,
slug varchar(255) NOT NULL,
institution varchar(80) NOT NULL,
root_web varchar(120),
db_host varchar(80) NOT NULL,
db_user varchar(16) DEFAULT 'root',
db_password varchar(32),
table_prefix varchar(16),
db_prefix varchar(16),
main_database varchar(60) DEFAULT 'chamilo',
url_append varchar(32),
course_folder varchar(80),
visible int,
lastcrongap int,
lastcron int,
croncount int,
template varchar(255),
password_encryption varchar(255),
archive_url varchar(255),
home_url varchar(255),
upload_url varchar(255),
course_url varchar(255),
css_theme_folder varchar(255),
PRIMARY KEY (id)
) DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;
";
/*ALTER TABLE vchamilo ADD COLUMN archive_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN home_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN upload_url varchar(255);
ALTER TABLE vchamilo ADD COLUMN course_url varchar(255);*/
Database::query($sql);
$table = 'vchamilo_config';
$tablename = Database::get_main_table($table);
// TODO: rename "name" and "value" fields - these are reserved keywords
$sql = "CREATE TABLE IF NOT EXISTS $tablename (
id int(11) NOT NULL AUTO_INCREMENT,
component int(11) NOT NULL,
`name` varchar(64) NOT NULL,
`value` varchar(255) NOT NULL,
longvalue varchar(255) NOT NULL,
PRIMARY KEY (id)
)
";
Database::query($sql);
api_add_setting(0, 'vchamilo_cron_lasthost', 'vchamilo', 'setting', 'Plugins');
api_add_setting(0, 'vchamilo_vcrontime', 'vchamilo', 'setting', 'Plugins');
api_add_setting(0, 'vchamilo_vcrontickperiod', 'vchamilo', 'setting', 'Plugins');
// create root storage directory for templates
global $_configuration;
if (!is_dir($_configuration['root_sys'].'plugin/vchamilo/templates')) {
$mode = api_get_permissions_for_new_directories();
mkdir($_configuration['root_sys'].'plugin/vchamilo/templates', $mode, true);
}

View File

@@ -0,0 +1,16 @@
function ajax_sync_setting(wwwroot, settingid) {
spare = $('#row_'+settingid).html();
formobj = document.forms['settingsform'];
url = wwwroot+'plugin/vchamilo/ajax/service.php?what=syncthis&settingid='+settingid+'&value='+encodeURIComponent(formobj.elements['value_'+settingid].value);
/*if (formobj.elements['del_'+settingid].checked) {
url += '&del=1';
}*/
$('#row_'+settingid).html('<td colspan="7"><img src="'+wwwroot+'plugin/vchamilo/pix/ajax_waiter.gif" /></td>');
$.get(url, function (data) {
$('#row_'+settingid).html(spare);
$('#res_'+settingid).html(data);
} );
}

View File

@@ -0,0 +1,62 @@
/**
* Pop-up testing connection with database.
*/
function opencnxpopup(webroot) {
// Inputted data.
var dbhost = document.getElementById('id_vdbhost').value;
var dblogin = document.getElementById('id_vdbuser').value;
var dbpass = document.getElementById('id_vdbpassword').value;
// PHP file linked the pop-up, and name.
var url = webroot+"/plugin/vchamilo/views/manage.testcnx.php" + "?" + "vdbhost=" + dbhost + "&" + "vdblogin=" + dblogin
+ "&" + "vdbpass=" + dbpass;
// Pop-up's options.
var options = "width=500,height=300,toolbar=no,menubar=no,location=no,scrollbars=no,status=no";
// Opening the pop-up (title not working in Firefox).
var windowobj = window.open(url, '', options);
}
/**
* Activates/desactivates services selection.
*/
function switcherServices(mnetnewsubnetwork) {
// Retrieve 'select' elements from form.
var mnetenabled = document.getElementById('id_mnetenabled');
var multimnet = document.getElementById('id_multimnet');
var services = document.getElementById('id_services');
// Default values for services.
var mnetfreedefault = '0';
var defaultservices = 'default';
var subnetworkservices = 'subnetwork';
// Do the actions.
if (multimnet.value == mnetfreedefault
|| multimnet.value == mnetnewsubnetwork) {
services.value = defaultservices;
services.disabled = true;
} else {
services.disabled = false;
services.value = subnetworkservices;
}
}
function syncSchema(){
var originelement = document.getElementById("id_shortname");
var syncedelement2 = document.getElementById("id_vdbname");
var syncedelement3 = document.getElementById("id_vdatapath");
var syncedelement4 = document.getElementById("id_vhostname");
syncedelement2.value = syncedelement2.value.replace(/<%%INSTANCE%%>/g, originelement.value);
syncedelement3.value = syncedelement3.value.replace(/<%%INSTANCE%%>/g, originelement.value);
syncedelement4.value = syncedelement4.value.replace(/<%%INSTANCE%%>/g, originelement.value);
}
function onLoadInit(){
var originelement = document.getElementById("id_shortname");
originelement.onchange = syncSchema;
}

View File

@@ -0,0 +1,15 @@
function selectallhosts() {
$('.vnodessel').attr('checked', true);
}
function deselectallhosts() {
$('.vnodessel').attr('checked', false);
}
function setpreset(form, select) {
presetvalue = select.options[select.selectedindex].value;
parts = presetvalue.split('/');
form.elements['variable'].value = parts[0];
form.elements['subkey'].value = parts[1];
}

View File

@@ -0,0 +1,123 @@
<?php
/**
* @copyright (c) 2014 Valery Fremaux
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
* @author Valery Fremaux <valery.fremaux@gmail.com>
*/
$strings['archiverealroot'] = 'Cache container real root (system path, no symlinks here)';
$strings['backtoindex'] = 'Back to instance index';
$strings['badconnection'] = 'Connection FAILED';
$strings['cancel'] = 'Cancel';
$strings['choose'] = 'choose...';
$strings['clearcache'] = 'Clear Twig cache';
$strings['clearmastercache'] = 'Clear Twig cache for master';
$strings['closewindow'] = 'Close this window';
$strings['connectionok'] = 'Connection OK';
$strings['continue'] = 'Continue';
$strings['coursefolder'] = 'Physical dir';
$strings['courserealroot'] = 'Course container real root (no symlinks here)';
$strings['datalocation'] = 'Data location';
$strings['datapathavailable'] = 'Data path is available and ready to be used as : <br/>';
$strings['datapathnotavailable'] = 'Data path exists but has already files in it at <br/>';
$strings['datapathcreated'] = 'Data path has been created as :<br/>';
$strings['dbgroup'] = 'Database Settings';
$strings['dbhost'] = 'Database Host';
$strings['dbpassword'] = 'Password';
$strings['dbprefix'] = 'Database prefix';
$strings['dbuser'] = 'Username';
$strings['deleteifempty'] = 'Delete if empty';
$strings['deleteinstances'] = 'Remove instance';
$strings['destroyinstances'] = 'Full delete instance';
$strings['distributevalue'] = 'Distribute configuration value';
$strings['edit'] = 'Edit instance info';
$strings['emptysite'] = 'New empty site';
$strings['enable_virtualisation'] = 'Enable';
$strings['enabled'] = 'enabled';
$strings['enableinstances'] = 'Enable';
$strings['enabling'] = 'General enabling';
$strings['errormuststartwithcourses'] = 'the course folder MUST start with \'courses_\' to avoid directory conflicts';
$strings['homerealroot'] = 'Home container real root (no symlinks here)';
$strings['hostdefinition'] = 'Host definition';
$strings['hostlist'] = 'Other hosts';
$strings['institution'] = 'Institution';
$strings['lastcron'] = 'Last cron';
$strings['maindatabase'] = 'Database name';
$strings['manage_instances'] = 'Go to instance manager';
$strings['newinstance'] = 'Add new instance';
$strings['no'] = 'No';
$strings['plugin_comment'] = 'Allows the virtualization of Chamilo. Use your main Chamilo installation as a hub, then create instances based on the same code but with different databases, and generate snapshots, and manage all instances like VM images.';
$strings['plugin_title'] = 'Virtual Chamilo';
$strings['proxysettings'] = 'Proxy settings';
$strings['registerinstance'] = 'Register an instance';
$strings['rootweb'] = 'Web root';
$strings['savechanges'] = 'Save changes';
$strings['selectall'] = 'Select all';
$strings['selectnone'] = 'Deselect all';
$strings['sendconfigvalue'] = 'Distribute a configuration value';
$strings['setconfigvalue'] = 'Set a configuration value';
$strings['singledatabase'] = 'Single database';
$strings['sitename'] = 'Site Name';
$strings['snapshotinstance'] = 'Snapshot';
$strings['snapshotmaster'] = 'Snapshot master Chamilo';
$strings['statisticsdatabase'] = 'Statistics database';
$strings['successfinishedcapture'] = 'Snapshot of chamilo is finished';
$strings['sync_settings'] = 'Synchronize settings';
$strings['tableprefix'] = 'Table prefix';
$strings['template'] = 'Template';
$strings['templating'] = 'Templating';
$strings['testconnection'] = 'Test database connexion';
$strings['testdatapath'] = 'Test data location';
$strings['userpersonaldatabase'] = 'User personal database';
$strings['vchamilo'] = 'Virtual Chamilo';
$strings['vchamilosnapshot1'] = 'STEP 1 OF 3 : Directories for snapshot have been created. Continue with database backup ...';
$strings['vchamilosnapshot2'] = 'STEP 2 OF 3 : Databases have been backed up. Continue with saving files... beware this step can be long if a lot of content resides in the instance...';
$strings['vchamilosnapshot3'] = 'STEP 3 OF 3 : Files saved.';
$strings['withselection'] = 'With selection: ';
$strings['yes'] = 'Yes';
$strings['mysqlcmds'] = 'Mysql commands location';
$strings['mysqlcmd'] = 'Full path to mysql client command';
$strings['mysqldumpcms'] = 'Full path to mysqldump command';
$strings['sitenameinputerror'] = "Site Name is empty or invalid";
$strings['institutioninputerror'] = "Institution is empty or invalid";
$strings['rootwebinputerror'] = "Root web is empty or invalid";
$strings['databaseinputerror'] = "Database empty";
$strings['coursefolderinputerror'] = "Data location is empty";
$strings['httpproxyhost'] = "HTTP proxy host";
$strings['httpproxyport'] = "HTTP proxy port";
$strings['httpproxybypass'] = "HTTP proxy URL bypass";
$strings['httpproxyuser'] = "HTTP proxy user";
$strings['httpproxypassword'] = "HTTP proxy password";
$strings['variable'] = 'Variable';
$strings['subkey'] = 'Subkey';
$strings['category'] = 'Category';
$strings['accessurl'] = 'Access URL';
$strings['value'] = 'Value';
$strings['syncall'] = 'Sync all the selection';
$strings['syncthis'] = 'Sync this setting';
$strings['SiteNameExample'] = 'Example: Chamilo';
$strings['InstitutionExample'] = 'Example: Chamilo Association';
$strings['RootWebExample'] = 'Example: http://www.chamilo.org/ (with final slash)';
$strings['DatabaseDescription'] = 'A new database will be created with that name.';
$strings['RootWebExists'] = 'An instance with the same root web exists.';
$strings['ImportInstance'] = 'Import instance';
$strings['ConfigurationPath'] = 'Chamilo configuration path';
$strings['UploadRealRoot'] = 'Upload files';
$strings['DatabaseAccessShouldBeDifferentThanMasterChamilo'] = 'Database server should be different than the Chamilo master';
$strings['UrlAppendExample'] = 'Example: /chamilo_v1 (with first slash)';
$strings['FromVersion'] = 'From version';
$strings['CoursePath'] = 'Path to courses directory';
$strings['HomePath'] = 'Path to home directory';
$strings['UploadPath'] = 'Path to upload directory';
$strings['ArchiveUrl'] = 'Cache URL';
$strings['HomeUrl'] = 'Home URL';
$strings['UploadUrl'] = 'Upload URL';
$strings['CourseUrl'] = 'Course URL';
$strings['ThemeFolder'] = 'Theme folder';
$strings['ThemeFolderExplanation'] = 'Theme folder should be located inside the web/css/themes/ folder';

View File

@@ -0,0 +1,108 @@
<?php
/**
* @copyright (c) 2014 Valery Fremaux
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
* @author Valery Fremaux <valery.fremaux@gmail.com>
*/
$strings['archiverealroot'] = 'Container effectif de la cache (chemin réel sur disque)';
$strings['backtoindex'] = 'Retour aux instances';
$strings['cancel'] = 'Annuler';
$strings['choose'] = 'Choisir une action...';
$strings['closewindow'] = 'Fermer cette fenêtre';
$strings['continue'] = 'Continuer';
$strings['coursefolder'] = 'Répertoire des cours';
$strings['courserealroot'] = 'Container effectif de cours (chemin réel)';
$strings['clearcache'] = 'Vider le cache Twig';
$strings['clearmastercache'] = 'Vider le cache Twig du maître';
$strings['datalocation'] = 'Emplacement des données';
$strings['datapathavailable'] = 'Le répertoire de données est disponible : <br/>';
$strings['datapathnotavailable'] = 'Le répertoire de données existe mais a déjà des fichiers à l\'emplacement <br/>';
$strings['datapathcreated'] = 'Le répertoire de données a été créé :<br/>';
$strings['dbgroup'] = 'Réglages de base de données';
$strings['dbhost'] = 'Hôte de BdD';
$strings['dbpassword'] = 'Mot de passe';
$strings['dbprefix'] = 'Préfix de base';
$strings['dbuser'] = 'Utilisateur de BdD';
$strings['deleteinstances'] = "Désactiver";
$strings['destroyinstances'] = "Détruire";
$strings['edit'] = 'Modifier les paramètres';
$strings['emptysite'] = 'Nouveau site vide';
$strings['enable_virtualisation'] = 'Activer';
$strings['enabled'] = 'Etat';
$strings['enableinstances'] = "Activer";
$strings['enabling'] = 'Activation';
$strings['errormuststartwithcourses'] = 'Le répertoire de cours doit commencer par \'courses_\' pour éviter les collisions de chemin';
$strings['homerealroot'] = 'Container effectif de pages d\'accueil (chemin réel)';
$strings['hostdefinition'] = 'Définition d\'hôte';
$strings['hostlist'] = 'Les sites du réseau';
$strings['institution'] = 'Institution';
$strings['lastcron'] = 'Dernier cron';
$strings['maindatabase'] = 'Nom de BdD';
$strings['manage_instances'] = 'Aller au gestionnaire d\'instances';
$strings['sync_settings'] = 'Synchroniser des réglages';
$strings['deleteifempty'] = 'Supprimer la clef si vide';
$strings['newinstance'] = "Ajouter une instance";
$strings['no'] = 'Non';
$strings['plugin_comment'] = 'Permettre les chamilos virtuels.';
$strings['plugin_title'] = 'Virtualisation de Chamilo';
$strings['proxysettings'] = 'Réglages du Proxy';
$strings['registerinstance'] = "Enregistrer une instance";
$strings['rootweb'] = 'Racine Web';
$strings['savechanges'] = 'Enregistrer les modifications';
$strings['selectall'] = 'Selectionner tout';
$strings['selectnone'] = 'Déselectionner tout';
$strings['setconfigvalue'] = 'Mettre à jour une variable de configuration';
$strings['distributevalue'] = 'Distribuer la configuration';
$strings['sendconfigvalue'] = 'Distribution d\'une valeur de configuration';
$strings['singledatabase'] = 'Base de données unique';
$strings['sitename'] = 'Nom du site';
$strings['snapshotinstance'] = 'Snapshot';
$strings['snapshotmaster'] = 'Snapshot du Chamilo maître';
$strings['statisticsdatabase'] = 'base de données de statistiques';
$strings['successfinishedcapture'] = 'La capture de Chamilo est terminée';
$strings['tableprefix'] = 'Prefixe de table';
$strings['template'] = 'Modèle';
$strings['templating'] = 'Templating';
$strings['testconnection'] = "Test de la connexion";
$strings['testdatapath'] = "Test de l'emplacement de données";
$strings['userpersonaldatabase'] = 'base de données des données personnelles';
$strings['vchamilo'] = 'Chamilo Virtuel';
$strings['vchamilosnapshot1'] = 'ETAPE 1 DE 3 : Les répertoires de snapshot ont été créés. Continuer avec la capture des bases...';
$strings['vchamilosnapshot2'] = 'ETAPE 2 DE 3 : Les bases ont été capturées. Continuer avec la récupération des fichiers d\'usage... Attention, cette étape peut être longue si la plate-forme est fortement chargée en documents...';
$strings['vchamilosnapshot3'] = 'ETAPE 3 DE 3 : Fichiers capturés.';
$strings['withselection'] = "Avec la sélection : ";
$strings['yes'] = 'Oui';
$strings['mysqlcmds'] = 'Emplacement de la commande Mysql';
$strings['mysqlcmd'] = 'Chemin vers le client mysql';
$strings['mysqldumpcms'] = 'Chemin vers la commande mysqldump';
$strings['sitenameinputerror'] = "Le nom de site est vide";
$strings['institutioninputerror'] = "L'institution est vide ou invalide";
$strings['rootwebinputerror'] = "L'URL d'acces est vide ou invalide";
$strings['databaseinputerror'] = "La base de données n'est pas définie";
$strings['coursefolderinputerror'] = "Le répertoire du cours n'est pas défini";
$strings['httpproxyhost'] = "Hôte Proxy HTTP";
$strings['httpproxyport'] = "Port Proxy HTTP";
$strings['httpproxybypass'] = "Filtre d'URL de proxy (exclusions)";
$strings['httpproxyuser'] = "Utilisateur Proxy";
$strings['httpproxypassword'] = "Mot de passe Proxy";
$strings['variable'] = 'Variable';
$strings['subkey'] = 'Clef';
$strings['category'] = 'Catégorie';
$strings['accessurl'] = 'Sous-site';
$strings['value'] = 'Valeur';
$strings['syncall'] = 'Synchroniser la sélection';
$strings['syncthis'] = 'Synchroniser ce réglage';
$strings['SiteNameExample'] = 'Exemple: Chamilo';
$strings['InstitutionExample'] = 'Exemple: Chamilo Association';
$strings['RootWebExample'] = 'Exemple: http://www.chamilo.org/';
$strings['DatabaseDescription'] = 'Une nouvelle base de données sera créée avec ce nom.';
$strings['RootWebExists'] = 'Une instance avec le même nom existe déjà.';
$strings['FromVersion'] = 'Version d\'origine';
$strings['CoursePath'] = 'Chemin vers répertoire de cours';
$strings['HomePath'] = 'Chemin vers répertoire home';
$strings['UploadPath'] = 'Chemin vers répertoire upload';

View File

@@ -0,0 +1,5 @@
<?php
$strings['FromVersion'] = 'Versión de origen';
$strings['CoursePath'] = 'Ruta hacia carpeta courses';
$strings['HomePath'] = 'Ruta hacia carpeta home';
$strings['UploadPath'] = 'Ruta hacia carpeta upload';

View File

@@ -0,0 +1,39 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Description of VChamilo.
*
* @copyright (c) 2014 VF Consulting
* @license GNU General Public License - http://www.gnu.org/copyleft/gpl.html
* @author Valery Fremaux <valery.fremaux@gmail.com>
* @author Julio Montoya
*/
class VChamiloPlugin extends Plugin
{
/**
* VChamiloPlugin constructor.
*/
public function __construct()
{
parent::__construct('1.4', 'Valery Fremaux, Julio Montoya');
}
/**
* @return VChamiloPlugin
*/
public static function create()
{
static $result = null;
return $result ? $result : $result = new self();
}
/**
* @return string
*/
public function get_name()
{
return 'vchamilo';
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

106
plugin/vchamilo/plugin.php Normal file
View File

@@ -0,0 +1,106 @@
<?php
/**
* This script is a configuration file for the vchamilo plugin.
* You can use it as a master for other platform plugins (course plugins are slightly different).
* These settings will be used in the administration interface for plugins
* (Chamilo configuration settings->Plugins).
*
* @package chamilo.plugin
*
* @author Julio Montoya <gugli100@gmail.com>
*/
global $_configuration;
/**
* Plugin details (must be present).
*/
/* Plugin config */
//the plugin title
$plugin_info['title'] = 'Chamilo Virtualization';
//the comments that go with the plugin
$plugin_info['comment'] = "Allows the virtualization of Chamilo. Use your main Chamilo installation as a hub, then create instances based on the same code but with different databases, and generate snapshots, and manage all instances like VM images.";
//the plugin version
$plugin_info['version'] = '1.2';
//the plugin author
$plugin_info['author'] = 'Valery Fremaux, Julio Montoya';
/* Plugin optional settings */
/*
* This form will be showed in the plugin settings once the plugin was installed
* in the plugin/hello_world/index.php you can have access to the value: $plugin_info['settings']['hello_world_show_type']
*/
$form = new FormValidator('vchamilo_form');
$plugin = VChamiloPlugin::create();
$form_settings = [
'enable_virtualisation' => Virtual::getConfig('vchamilo', 'enable_virtualisation', true),
'httpproxyhost' => Virtual::getConfig('vchamilo', 'httpproxyhost', true),
'httpproxyport' => Virtual::getConfig('vchamilo', 'httpproxyport', true),
'httpproxybypass' => Virtual::getConfig('vchamilo', 'httpproxybypass', true),
'httpproxyuser' => Virtual::getConfig('vchamilo', 'httpproxyuser', true),
'httpproxypassword' => Virtual::getConfig('vchamilo', 'httpproxypassword', true),
'cmd_mysql' => Virtual::getConfig('vchamilo', 'cmd_mysql', true),
'cmd_mysqldump' => Virtual::getConfig('vchamilo', 'cmd_mysqldump', true),
'course_real_root' => Virtual::getConfig('vchamilo', 'course_real_root', true),
'archive_real_root' => Virtual::getConfig('vchamilo', 'archive_real_root', true),
'home_real_root' => Virtual::getConfig('vchamilo', 'home_real_root', true),
'upload_real_root' => Virtual::getConfig('vchamilo', 'upload_real_root', true),
];
$form->setDefaults($form_settings);
$wwwroot = $_configuration['root_web'];
//A simple select
$options = [0 => $plugin->get_lang('no'), 1 => $plugin->get_lang('yes')];
$form->addLabel(
'',
'<a class="btn btn-primary" href="'.api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php">'.
$plugin->get_lang('manage_instances').'</a>'
);
$form->addElement('header', $plugin->get_lang('enabling'));
$form->addElement('select', 'enable_virtualisation', $plugin->get_lang('enable_virtualisation'), $options);
$form->addElement(
'text',
'course_real_root',
[$plugin->get_lang('courserealroot'), 'Example: '.api_get_path(SYS_PATH).'var/courses/']
);
$form->addElement(
'text',
'archive_real_root',
[$plugin->get_lang('archiverealroot'), 'Example: '.api_get_path(SYS_PATH).'var/cache/']
);
$form->addElement(
'text',
'home_real_root',
[$plugin->get_lang('homerealroot'), 'Example: '.api_get_path(SYS_PATH).'var/home/']
);
$form->addElement(
'text',
'upload_real_root',
[$plugin->get_lang('UploadRealRoot'), 'Example: '.api_get_path(SYS_PATH).'var/upload/']
);
$form->addElement('header', $plugin->get_lang('mysqlcmds'));
$form->addElement('text', 'cmd_mysql', [$plugin->get_lang('mysqlcmd'), 'Example: /usr/bin/mysql']);
$form->addElement('text', 'cmd_mysqldump', [$plugin->get_lang('mysqldumpcmd'), 'Example: /usr/bin/mysqldump']);
$form->addElement('header', $plugin->get_lang('proxysettings'));
$form->addElement('text', 'httpproxyhost', $plugin->get_lang('httpproxyhost'));
$form->addElement('text', 'httpproxyport', $plugin->get_lang('httpproxyport'));
$form->addElement('text', 'httpproxybypass', $plugin->get_lang('httpproxybypass'));
$form->addElement('text', 'httpproxyuser', $plugin->get_lang('httpproxyuser'));
$form->addElement('text', 'httpproxypassword', $plugin->get_lang('httpproxypassword'));
$form->addButtonSave($plugin->get_lang('Save'));
$plugin_info['settings_form'] = $form;
// Set the templates that are going to be used
$plugin_info['templates'] = ['template.tpl'];
$plugin_info['plugin_class'] = get_class($plugin);

View File

@@ -0,0 +1,10 @@
<div class="vchamilo-title">
<h2>{{title}}</h2>
</div>
<div class="vchamilo-host-list">
<ul>
{% for host in hosts %}
<li class="vchamilo-host"> <a href="{{host.url}}">{{host.name}}</a></li>
{% endfor %}
</ul>
</div>

View File

@@ -0,0 +1,2 @@
This directory would be http server writable for templates snapshot to be created.
Set GID to web server group, or give write access to everyone.

View File

@@ -0,0 +1,9 @@
<?php
/* PHP code to uninstall the plugin */
api_protect_admin_script();
$table = Database::get_main_table('vchamilo');
$sql = " DROP TABLE IF EXISTS $table";
Database::query($sql);

294
plugin/vchamilo/vcron.php Normal file
View File

@@ -0,0 +1,294 @@
<?php
/* For license terms, see /license.txt */
exit;
/**
* This file is a cron microclock script.
* It will be used as replacement of setting individual
* cron lines for all virtual instances.
*
* Setup this vcron to run at the smallest period possible, as
* it will schedule all availables vchamilos to be run as required.
* Note that one activaton of this cron may not always run real crons
* or may be run more than one cron.
*
* If used on a big system with clustering, ensure hostnames are adressed
* at the load balancer entry and not on physical hosts
*
* @package plugin/vchamilo
* @category plugins
*
* @author Valery fremaux (valery.fremaux@gmail.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*/
define('CLI_SCRIPT', true); // for chamilo imported code
require_once dirname(dirname(__DIR__)).'/main/inc/global.inc.php';
global $DB;
$DB = new DatabaseManager();
define('ROUND_ROBIN', 0);
define('LOWEST_POSSIBLE_GAP', 1);
global $VCRON;
$VCRON = new stdClass();
$VCRON->ACTIVATION = 'cli'; // choose how individual cron are launched, 'cli' or 'web'
$VCRON->STRATEGY = ROUND_ROBIN; // choose vcron rotation mode
$VCRON->PERIOD = 15 * MINSECS; // used if LOWEST_POSSIBLE_GAP to setup the max gap
$VCRON->TIMEOUT = 300; // time out for CURL call to effective cron
// $VCRON->TRACE = $_configuration['root_sys'].'plugin/vchamilo/log/vcrontrace.log'; // Trace file where to collect cron outputs
$VCRON->TRACE = '/data/log/chamilo/vcrontrace.log'; // Trace file where to collect cron outputs
$VCRON->TRACE_ENABLE = true; // enables tracing
if (!is_dir($_configuration['root_sys'].'plugin/vchamilo/log')) {
$mode = api_get_permissions_for_new_directories();
mkdir($_configuration['root_sys'].'plugin/vchamilo/log', $mode, true);
}
/**
* fire a cron URL using CURL.
*/
function fire_vhost_cron($vhost)
{
global $VCRON;
if ($VCRON->TRACE_ENABLE) {
$CRONTRACE = fopen($VCRON->TRACE, 'a');
}
$ch = curl_init($vhost->root_web.'/main/cron/run.php');
$http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo');
$http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo');
$http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo');
$http_proxy_user = api_get_setting('vchamilo_httpproxyuser', 'vchamilo');
$http_proxy_password = api_get_setting('vchamilo_httpproxypassword', 'vchamilo');
curl_setopt($ch, CURLOPT_TIMEOUT, $VCRON->TIMEOUT);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Chamilo');
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: text/xml charset=UTF-8"]);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// Check for proxy.
if (!empty($http_proxy_host) && !is_proxybypass($uri)) {
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, false);
if (empty($http_proxy_port)) {
echo "Using proxy $http_proxy_host\n";
curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host);
} else {
echo "Using proxy $http_proxy_host:$http_proxy_port\n";
curl_setopt($ch, CURLOPT_PROXY, $http_proxy_host.':'.$http_proxy_port);
}
if (!empty($http_proxy_user) and !empty($http_proxy_password)) {
curl_setopt($ch, CURLOPT_PROXYUSERPWD, $http_proxy_user.':'.$http_proxy_password);
if (defined('CURLOPT_PROXYAUTH')) {
// any proxy authentication if PHP 5.1
curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM);
}
}
}
$timestamp_send = time();
$rawresponse = curl_exec($ch);
$timestamp_receive = time();
if ($rawresponse === false) {
$error = curl_errno($ch).':'.curl_error($ch);
if ($VCRON->TRACE_ENABLE) {
if ($CRONTRACE) {
fputs($CRONTRACE, "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n");
fputs($CRONTRACE, "VCron Error : $error \n");
fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n");
fclose($CRONTRACE);
}
}
echo "VCron started on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n";
echo "VCron Error : $error \n";
echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n";
return false;
}
if ($VCRON->TRACE_ENABLE) {
if ($CRONTRACE) {
fputs($CRONTRACE, "VCron start on $vhost->vhostname : ".api_time_to_hms($timestamp_send)."\n");
fputs($CRONTRACE, $rawresponse."\n");
fputs($CRONTRACE, "VCron stop on $vhost->vhostname : ".api_time_to_hms($timestamp_receive)."\n#################\n\n");
fclose($CRONTRACE);
}
}
echo "VCron start on $vhost->root_web : ".api_time_to_hms($timestamp_send)."\n";
echo $rawresponse."\n";
echo "VCron stop on $vhost->root_web : ".api_time_to_hms($timestamp_receive)."\n#################\n\n";
$vhost->lastcrongap = time() - $vhost->lastcron;
$vhost->lastcron = $timestamp_send;
$vhost->croncount++;
$vhostid = $vhost->id;
unset($vhost->id);
Database::update('vchamilo', (array) $vhost, ['id = ?' => $vhostid]);
}
/**
* fire a cron URL using cli exec.
*/
function exec_vhost_cron($vhost)
{
global $VCRON, $DB, $_configuration;
if ($VCRON->TRACE_ENABLE) {
$CRONTRACE = fopen($VCRON->TRACE, 'a');
}
$cmd = 'php "'.$_configuration['root_sys'].'/plugin/vchamilo/cli/cron.php" --host='.$vhost->root_web;
$timestamp_send = time();
exec($cmd, $rawresponse);
$timestamp_receive = time();
if ($VCRON->TRACE_ENABLE) {
if ($CRONTRACE) {
fputs($CRONTRACE, "VCron start on $vhost->root_web : $timestamp_send\n");
fputs($CRONTRACE, $rawresponse."\n");
fputs($CRONTRACE, "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n");
fclose($CRONTRACE);
}
}
echo "VCron start on $vhost->root_web : $timestamp_send\n";
echo implode("\n", $rawresponse)."\n";
echo "VCron stop on $vhost->root_web : $timestamp_receive\n#################\n\n";
$vhost->lastcrongap = time() - $vhost->lastcron;
$vhost->lastcron = $timestamp_send;
$vhost->croncount++;
$DB->update_record('vchamilo', $vhost, 'id');
}
/**
* check if $url matches anything in proxybypass list.
*
* any errors just result in the proxy being used (least bad)
*
* @global object
*
* @param string $url url to check
*
* @return bool true if we should bypass the proxy
*/
function is_proxybypass($url)
{
$http_proxy_host = api_get_setting('vchamilo_httpproxyhost', 'vchamilo');
$http_proxy_port = api_get_setting('vchamilo_httpproxyport', 'vchamilo');
$http_proxy_bypass = api_get_setting('vchamilo_httpproxybypass', 'vchamilo');
// sanity check
if (empty($http_proxy_host) or empty($http_proxy_bypass)) {
return false;
}
// get the host part out of the url
if (!$host = parse_url($url, PHP_URL_HOST)) {
return false;
}
// get the possible bypass hosts into an array
$matches = explode(',', $http_proxy_bypass);
// check for a match
// (IPs need to match the left hand side and hosts the right of the url,
// but we can recklessly check both as there can't be a false +ve)
$bypass = false;
foreach ($matches as $match) {
$match = trim($match);
// try for IP match (Left side)
$lhs = substr($host, 0, strlen($match));
if (strcasecmp($match, $lhs) == 0) {
return true;
}
// try for host match (Right side)
$rhs = substr($host, -strlen($match));
if (strcasecmp($match, $rhs) == 0) {
return true;
}
}
// nothing matched.
return false;
}
// Main execution sequence
if (!$vchamilos = Database::select('*', 'vchamilo', [], 'all')) {
exit("Nothing to do. No Vhosts");
}
$allvhosts = array_values($vchamilos);
echo "<pre>";
echo "Chamilo VCron... start\n";
echo "Last croned : ".api_get_setting('vchamilo_cron_lasthost', 'vchamilo')."\n";
if ($VCRON->STRATEGY == ROUND_ROBIN) {
$rr = 0;
foreach ($allvhosts as $vhostassoc) {
$vhost = (object) $vhostassoc;
if ($rr == 1) {
api_set_setting('vchamilo_cron_lasthost', $vhost->id);
echo "Round Robin : ".$vhost->root_web."\n";
if ($VCRON->ACTIVATION == 'cli') {
exec_vhost_cron($vhost);
} else {
fire_vhost_cron($vhost);
}
exit('Done.');
}
if ($vhost->id == api_get_setting('vchamilo_cron_lasthost', 'vchamilo')) {
$rr = 1; // take next one
}
}
// We were at last. Loop back and take first.
$firsthost = (object) $allvhosts[0];
api_set_setting('vchamilo_cron_lasthost', $firsthost->id, 'vchamilo');
echo "Round Robin : ".$firsthost->root_web."\n";
if ($VCRON->ACTIVATION == 'cli') {
exec_vhost_cron($firsthost);
} else {
fire_vhost_cron($firsthost);
}
} elseif ($VCRON->STRATEGY == LOWEST_POSSIBLE_GAP) {
// First make measurement of cron period.
if (api_get_setting('vcrontickperiod', 'vchamilo')) {
api_set_setting('vcrontime', time(), 'vchamilo');
return;
}
api_set_setting('vcrontickperiod', time() - api_get_setting('vcrontime', 'vchamilo'), 'vchamilo');
$hostsperturn = max(1, $VCRON->PERIOD / api_get_setting('vcrontickperiod', 'vchamilo') * count($allvhosts));
$i = 0;
foreach ($allvhosts as $vhostassoc) {
$vhost = (object) $vhostassoc;
if ((time() - $vhost->lastcron) > $VCRON->PERIOD) {
if ($VCRON->ACTIVATION == 'cli') {
exec_vhost_cron($vhost);
} else {
fire_vhost_cron($vhost);
}
$i++;
if ($i >= $hostsperturn) {
return;
}
}
}
}

View File

@@ -0,0 +1,78 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
define('CHAMILO_INTERNAL', true);
global $plugin;
require_once __DIR__.'/../../../main/inc/global.inc.php';
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/editinstance_form.php';
api_protect_admin_script();
$htmlHeadXtra[] = '<script src="'.api_get_path(WEB_PLUGIN_PATH).'vchamilo/js/host_form.js" type="text/javascript" language="javascript"></script>';
// get parameters
$id = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : '';
$action = isset($_REQUEST['what']) ? $_REQUEST['what'] : '';
$registeronly = isset($_REQUEST['registeronly']) ? $_REQUEST['registeronly'] : 0;
$plugin = VChamiloPlugin::create();
$thisurl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
if ($id) {
$mode = 'update';
} else {
$mode = $registeronly ? 'register' : 'add';
}
$vhost = (array) Virtual::getInstance($id);
$form = new InstanceForm($plugin, $mode, $vhost);
if ($data = $form->get_data()) {
switch ($data->what) {
case 'addinstance':
case 'registerinstance':
Virtual::addInstance($data);
echo '<a class="btn btn-primary" href="'.api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php'.'">Continue</a>';
exit;
break;
case 'updateinstance':
unset($data->what);
unset($data->submitbutton);
unset($data->registeronly);
unset($data->template);
$data->lastcron = 0;
$data->lastcrongap = 0;
$data->croncount = 0;
$id = $data->vid;
unset($data->vid);
unset($data->testconnection);
unset($data->testdatapath);
unset($data->vid);
Database::update('vchamilo', (array) $data, ['id = ?' => $id], false);
Display::addFlash(Display::return_message(get_lang('Updated')));
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
break;
}
}
if ($id) {
$vhost['vid'] = $vhost['id'];
unset($vhost['id']);
$form->set_data($vhost);
} else {
$vhost['db_host'] = 'localhost';
$vhost['registeronly'] = $registeronly;
$form->set_data($vhost);
}
$content = $form->return_form();
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
$tpl = new Template(get_lang('Instance'), true, true, false, true, false);
$tpl->assign('content', $content);
$tpl->display_one_col_template();

View File

@@ -0,0 +1,579 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Class ChamiloForm.
*/
abstract class ChamiloForm
{
public $_definition_finalized;
protected $_form;
protected $_mode;
protected $_cancelurl;
protected $_customdata;
/**
* ChamiloForm constructor.
*
* @param $mode
* @param $returnurl
* @param $cancelurl
* @param $customdata
*/
public function __construct($mode, $returnurl, $cancelurl, $customdata = [])
{
global $text_dir;
$this->_mode = $mode;
$this->_cancelurl = $cancelurl;
$this->_customdata = $customdata;
$attributes = ['style' => 'width: 60%; float: '.($text_dir == 'rtl' ? 'right;' : 'left;')];
$this->_form = new FormValidator(
$mode.'_instance',
'post',
$returnurl,
'',
$attributes
);
}
abstract public function definition();
abstract public function validation($data, $files = null);
public function validate()
{
return $this->_form->validate();
}
public function display()
{
return $this->_form->display();
}
public function definition_after_data()
{
}
public function return_form()
{
return $this->_form->toHtml();
}
public function is_in_add_mode()
{
return $this->_mode == 'add';
}
/**
* Return submitted data if properly submitted or returns NULL if validation fails or
* if there is no submitted data.
*
* @param bool $slashed true means return data with addslashes applied
*
* @return object submitted data; NULL if not valid or not submitted
*/
public function get_data($slashed = true)
{
$cform = &$this->_form;
if ($this->is_submitted() and $this->is_validated()) {
$data = $cform->exportValues(null, $slashed);
unset($data['sesskey']); // we do not need to return sesskey
if (empty($data)) {
return null;
} else {
return (object) $data;
}
} else {
return null;
}
}
/**
* Return submitted data without validation or NULL if there is no submitted data.
*
* @param bool $slashed true means return data with addslashes applied
*
* @return object submitted data; NULL if not submitted
*/
public function get_submitted_data($slashed = true)
{
$cform = &$this->_form;
if ($this->is_submitted()) {
$data = $cform->exportValues(null, $slashed);
unset($data['sesskey']); // we do not need to return sesskey
if (empty($data)) {
return null;
} else {
return (object) $data;
}
} else {
return null;
}
}
/**
* Check that form was submitted. Does not check validity of submitted data.
*
* @return bool true if form properly submitted
*/
public function is_submitted()
{
return $this->_form->isSubmitted();
}
/**
* Return true if a cancel button has been pressed resulting in the form being submitted.
*
* @return bool true if a cancel button has been pressed
*/
public function is_cancelled()
{
$cform = &$this->_form;
if ($cform->isSubmitted()) {
foreach ($cform->_cancelButtons as $cancelbutton) {
if (optional_param($cancelbutton, 0, PARAM_RAW)) {
return true;
}
}
}
return false;
}
/**
* Check that form data is valid.
* You should almost always use this, rather than {@see validate_defined_fields}.
*
* @return bool true if form data valid
*/
public function is_validated()
{
//finalize the form definition before any processing
if (!$this->_definition_finalized) {
$this->_definition_finalized = true;
$this->definition_after_data();
}
return $this->validate_defined_fields();
}
/**
* Validate the form.
*
* You almost always want to call {@see is_validated} instead of this
* because it calls {@see definition_after_data} first, before validating the form,
* which is what you want in 99% of cases.
*
* This is provided as a separate function for those special cases where
* you want the form validated before definition_after_data is called
* for example, to selectively add new elements depending on a no_submit_button press,
* but only when the form is valid when the no_submit_button is pressed,
*
* @param bool $validateonnosubmit optional, defaults to false. The default behaviour
* is NOT to validate the form when a no submit button has been pressed.
* pass true here to override this behaviour
*
* @return bool true if form data valid
*/
public function validate_defined_fields($validateonnosubmit = false)
{
static $validated = null; // one validation is enough
$cform = &$this->_form;
if ($this->no_submit_button_pressed() && empty($validateonnosubmit)) {
return false;
} elseif ($validated === null) {
$internal_val = $cform->validate();
$files = [];
$file_val = $this->_validate_files($files);
if ($file_val !== true) {
if (!empty($file_val)) {
foreach ($file_val as $element => $msg) {
$cform->setElementError($element, $msg);
}
}
$file_val = false;
}
$data = $cform->exportValues(null, true);
$chamilo_val = $this->validation($data, $files);
if ((is_array($chamilo_val) && count($chamilo_val) !== 0)) {
// non-empty array means errors
foreach ($chamilo_val as $element => $msg) {
$cform->setElementError($element, $msg);
}
$chamilo_val = false;
} else {
// anything else means validation ok
$chamilo_val = true;
}
$validated = ($internal_val && $chamilo_val && $file_val);
}
return $validated;
}
public function no_submit_button_pressed()
{
static $nosubmit = null; // one check is enough
if (!is_null($nosubmit)) {
return $nosubmit;
}
$cform = &$this->_form;
$nosubmit = false;
if (!$this->is_submitted()) {
return false;
}
/*
foreach ($cform->_noSubmitButtons as $nosubmitbutton){
if (optional_param($nosubmitbutton, 0, PARAM_RAW)){
$nosubmit = true;
break;
}
}
return $nosubmit;
*/
return false;
}
/**
* Load in existing data as form defaults. Usually new entry defaults are stored directly in
* form definition (new entry form); this function is used to load in data where values
* already exist and data is being edited (edit entry form).
*
* @param mixed $default_values object or array of default values
* @param bool $slashed true if magic quotes applied to data values
*/
public function set_data($default_values, $slashed = false)
{
if (is_object($default_values)) {
$default_values = (array) $default_values;
}
$filter = $slashed ? 'stripslashes' : null;
$this->_form->setDefaults($default_values, $filter);
}
/**
* Internal method. Validates all uploaded files.
*/
public function _validate_files(&$files)
{
$files = [];
if (empty($_FILES)) {
// we do not need to do any checks because no files were submitted
// note: server side rules do not work for files - use custom verification in validate() instead
return true;
}
$errors = [];
$mform = &$this->_form;
// check the files
$status = $this->_upload_manager->preprocess_files();
// now check that we really want each file
foreach ($_FILES as $elname => $file) {
if ($mform->elementExists($elname) and $mform->getElementType($elname) == 'file') {
$required = $mform->isElementRequired($elname);
if (!empty($this->_upload_manager->files[$elname]['uploadlog']) &&
empty($this->_upload_manager->files[$elname]['clear'])
) {
if (!$required and $file['error'] == UPLOAD_ERR_NO_FILE) {
// file not uploaded and not required - ignore it
continue;
}
$errors[$elname] = $this->_upload_manager->files[$elname]['uploadlog'];
} elseif (!empty($this->_upload_manager->files[$elname]['clear'])) {
$files[$elname] = $this->_upload_manager->files[$elname]['tmp_name'];
}
} else {
error('Incorrect upload attempt!');
}
}
// return errors if found
if ($status && 0 == count($errors)) {
return true;
} else {
$files = [];
return $errors;
}
}
}
/**
* Class InstanceForm.
*/
class InstanceForm extends ChamiloForm
{
/** @var Plugin */
public $_plugin;
public $instance;
/**
* InstanceForm constructor.
*
* @param $plugin
* @param string $mode
*/
public function __construct($plugin, $mode = 'add', $instance = [])
{
global $_configuration;
$this->_plugin = $plugin;
$returnUrl = $_configuration['root_web'].'plugin/vchamilo/views/editinstance.php';
if ($mode == 'update') {
$returnUrl = $_configuration['root_web'].'plugin/vchamilo/views/editinstance.php?vid='.intval($_GET['vid']);
}
$cancelurl = $_configuration['root_web'].'plugin/vchamilo/views/manage.php';
parent::__construct($mode, $returnUrl, $cancelurl);
$this->instance = $instance;
$this->definition();
}
public function definition()
{
global $_configuration;
$form = $this->_form;
$plugin = $this->_plugin;
$form->addElement('hidden', 'vid');
$form->addElement('hidden', 'what', $this->_mode.'instance');
$form->addElement('hidden', 'registeronly');
$form->addHeader($plugin->get_lang('hostdefinition'));
$form->addText(
'sitename',
[
$plugin->get_lang('sitename'),
$plugin->get_lang('SiteNameExample'),
]
);
$form->applyFilter('sitename', 'trim');
$form->addText(
'institution',
[
$plugin->get_lang('institution'),
$plugin->get_lang('InstitutionExample'),
]
);
$form->applyFilter('institution', 'trim');
// Host's name.
$elementWeb = $form->addElement(
'text',
'root_web',
[$this->_plugin->get_lang('rootweb'), $plugin->get_lang('RootWebExample')]
);
$form->applyFilter('root_web', 'trim');
$form->addElement(
'text',
'url_append',
['url_append', $plugin->get_lang('UrlAppendExample')]
);
if ($this->_mode == 'update') {
$encryptList = Virtual::getEncryptList();
$encryptMethod = $form->addElement(
'select',
'password_encryption',
get_lang('EncryptMethodUserPass'),
$encryptList
);
$encryptMethod->freeze();
$elementWeb->freeze();
}
/*
* Database fieldset.
*/
$form->addElement('header', $plugin->get_lang('dbgroup'));
// Database host.
$form->addElement(
'text',
'db_host',
$this->_plugin->get_lang('dbhost'),
['id' => 'id_vdbhost']
);
$form->applyFilter('db_host', 'trim');
// Database login.
$form->addElement(
'text',
'db_user',
$this->_plugin->get_lang('dbuser'),
['id' => 'id_vdbuser']
);
$form->applyFilter('db_user', 'trim');
// Database password.
$form->addElement(
'password',
'db_password',
$this->_plugin->get_lang('dbpassword'),
['id' => 'id_vdbpassword']
);
// Database name.
$form->addText(
'main_database',
[
$plugin->get_lang('maindatabase'),
$plugin->get_lang('DatabaseDescription'),
]
);
// Button for testing database connection.
$form->addElement(
'button',
'testconnection',
$this->_plugin->get_lang('testconnection'),
'check',
'default',
'default',
'',
'onclick="opencnxpopup(\''.$_configuration['root_web'].'\'); return false;"'
);
$form->addText('archive_url', $this->_plugin->get_lang('ArchiveUrl'));
$form->addText('home_url', $this->_plugin->get_lang('HomeUrl'));
$form->addText('upload_url', $this->_plugin->get_lang('UploadUrl'));
$form->addText(
'css_theme_folder',
[
$this->_plugin->get_lang('ThemeFolder'),
$this->_plugin->get_lang('ThemeFolderExplanation'),
],
false
);
//$form->addText('course_url', $this->_plugin->get_lang('CourseUrl'));
/**
* Template selection.
*/
if ($this->is_in_add_mode()) {
$form->addElement('header', $this->_plugin->get_lang('templating'));
$templateoptions = Virtual::getAvailableTemplates();
// Template choice
$form->addSelect(
'template',
$this->_plugin->get_lang('template'),
$templateoptions
);
} else {
if ($this->instance) {
$form->addLabel(
'slug',
$this->instance['slug']
);
$form->addLabel(
'archive_real_root',
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'archive_real_root')).
$this->instance['slug']
);
$form->addLabel(
'course_real_root',
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'course_real_root')).
$this->instance['slug']
);
$form->addLabel(
'home_real_root',
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'home_real_root')).$this->instance['slug']
);
$form->addLabel(
'upload_real_root',
api_add_trailing_slash(Virtual::getConfig('vchamilo', 'upload_real_root')).$this->instance['slug']
);
$form->addLabel(
$this->_plugin->get_lang('template'),
$this->instance['template']
);
}
}
$form->addButtonSave(
$this->_plugin->get_lang('savechanges'),
'submitbutton'
);
// Rules
$form->addRule(
'sitename',
$this->_plugin->get_lang('sitenameinputerror'),
'required',
null,
'client'
);
$form->addRule(
'institution',
$this->_plugin->get_lang('institutioninputerror'),
'required',
null,
'client'
);
$form->addRule(
'root_web',
$this->_plugin->get_lang('rootwebinputerror'),
'required',
null,
'client'
);
$form->addRule(
'main_database',
$this->_plugin->get_lang('databaseinputerror'),
'required',
null,
'client'
);
}
/**
* @param array $data
* @param null $files
*
* @return array
*/
public function validation($data, $files = null)
{
global $plugin;
$errors = [];
$tablename = Database::get_main_table('vchamilo');
$vchamilo = Database::select(
'*',
$tablename,
['where' => [' root_web = ? ' => [$data['root_web']]]],
'first'
);
if ($vchamilo && isset($data['vid']) && $data['vid'] != $vchamilo['id']) {
$errors['root_web'] = $plugin->get_lang('RootWebExists');
}
if (!empty($errors)) {
return $errors;
}
}
}

View File

@@ -0,0 +1,196 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../../../main/inc/global.inc.php';
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
// Security
api_protect_admin_script();
Virtual::checkSettings();
$plugin = VChamiloPlugin::create();
$form = new FormValidator('import', 'post', api_get_self());
// Database host.
$form->addHeader(get_lang('From'));
$form->addText('root_web', [$plugin->get_lang('rootweb'), 'Example: http://www.chamilo.org/']);
$form->addText('db_host', $plugin->get_lang('dbhost'));
$form->applyFilter('db_host', 'trim');
// Database login.
$form->addText('db_user', $plugin->get_lang('dbuser'));
$form->applyFilter('db_user', 'trim');
// Database password.
$form->addElement(
'password',
'db_password',
$plugin->get_lang('dbpassword'),
['id' => 'id_vdbpassword']
);
// Database name.
$form->addText('main_database', [$plugin->get_lang('maindatabase')]);
$form->addText(
'configuration_file',
[
$plugin->get_lang('ConfigurationPath'),
get_lang('Example').': /var/www/site/app/config/configuration.php',
],
true
);
$encryptList = Virtual::getEncryptList();
$form->addSelect(
'password_encryption',
get_lang('EncryptMethodUserPass'),
$encryptList
);
$encryptList = Virtual::getEncryptList();
$versionList = [
'1.11.x',
'1.10.x',
'1.9.x',
];
$form->addSelect(
'version',
$plugin->get_lang('FromVersion'),
array_combine($versionList, $versionList)
);
$form->addText(
'course_path',
[
$plugin->get_lang('CoursePath'),
get_lang('Example').': /var/www/site/virtual/var/courses',
],
true
);
$form->addText(
'home_path',
[
$plugin->get_lang('HomePath'),
get_lang('Example').': /var/www/site/virtual/var/home',
],
true
);
$form->addText(
'upload_path',
[
$plugin->get_lang('UploadPath'),
get_lang('Example').': /var/www/site/virtual/var/upload',
],
true
);
$form->addHeader(get_lang('To'));
$form->addText('to_db_host', $plugin->get_lang('dbhost'));
$form->applyFilter('to_db_host', 'trim');
// Database login.
$form->addText('to_db_user', $plugin->get_lang('dbuser'));
$form->applyFilter('to_db_user', 'trim');
// Database password.
$form->addElement(
'password',
'to_db_password',
$plugin->get_lang('dbpassword'),
['id' => 'id_vdbpassword']
);
// Database name.
$form->addText(
'to_main_database',
[
$plugin->get_lang('maindatabase'),
$plugin->get_lang('DatabaseDescription'),
]
);
$form->addButtonSave($plugin->get_lang('savechanges'), 'submitbutton');
$content = $form->returnForm();
if ($form->validate()) {
$values = $form->getSubmitValues();
$coursePath = $values['course_path'];
$homePath = $values['home_path'];
$confFile = $values['configuration_file'];
$uploadPath = $values['upload_path'];
$isPharFile = str_starts_with(strtolower($confFile), 'phar://')
|| str_starts_with(strtolower($coursePath), 'phar://')
|| str_starts_with(strtolower($homePath), 'phar://')
|| str_starts_with(strtolower($uploadPath), 'phar://');
if ($isPharFile) {
Display::addFlash(
Display::return_message(
$plugin->get_lang('NotAllowed'),
'error'
)
);
} else {
$isWritable = is_dir($coursePath)
&& is_dir($homePath)
&& is_dir($uploadPath)
&& file_exists($confFile)
&& is_readable($confFile);
if ($isWritable) {
$currentHost = api_get_configuration_value('db_host');
$currentDatabase = api_get_configuration_value('main_database');
$currentUser = api_get_configuration_value('db_user');
$currentPassword = api_get_configuration_value('db_password');
if ($values['to_main_database'] !== $currentDatabase &&
$values['to_db_user'] !== $currentUser &&
$values['to_db_password'] !== $currentPassword
) {
} else {
Display::addFlash(
Display::return_message(
$plugin->get_lang('DatabaseAccessShouldBeDifferentThanMasterChamilo'),
'warning'
)
);
}
$vchamilo = new stdClass();
$vchamilo->main_database = $values['main_database'];
$vchamilo->db_user = $values['db_user'];
$vchamilo->db_password = $values['db_password'];
$vchamilo->db_host = $values['db_host'];
$vchamilo->root_web = $values['root_web'];
$vchamilo->import_to_main_database = $values['to_main_database'];
$vchamilo->import_to_db_user = $values['to_db_user'];
$vchamilo->import_to_db_password = $values['to_db_password'];
$vchamilo->import_to_db_host = $values['to_db_host'];
$vchamilo->course_path = $values['course_path'];
$vchamilo->home_path = $values['home_path'];
$vchamilo->upload_path = $values['upload_path'];
$vchamilo->password_encryption = $values['password_encryption'];
Virtual::importInstance($vchamilo, $values['version']);
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
}
}
}
$tpl = new Template(get_lang('Import'), true, true, false, true, false);
$tpl->assign('content', $content);
$tpl->display_one_col_template();

View File

@@ -0,0 +1,373 @@
<?php
/* For licensing terms, see /license.txt */
$table = Database::get_main_table('vchamilo');
if (!defined('CHAMILO_INTERNAL')) {
exit('You cannot use this script this way');
}
$vidlist = isset($_REQUEST['vids']) ? implode("','", array_map('intval', $_REQUEST['vids'])) : '';
switch ($action) {
case 'upgrade':
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/upgrade.php?vid='.$vidlist);
break;
case 'import':
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/import.php');
break;
case 'newinstance':
case 'instance':
$registeronly = isset($_REQUEST['registeronly']) ? $_REQUEST['registeronly'] : 0;
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/editinstance.php?registeronly='.$registeronly);
break;
case 'editinstance':
case 'updateinstance':
$vid = $_REQUEST['vid'];
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/editinstance.php?vid='.$vid);
break;
case 'deleteinstances':
case 'disableinstances':
if (!empty($vidlist)) {
Display::addFlash(Display::return_message("Disabling instance"));
// Make it not visible.
$sql = "UPDATE $table SET visible = 0 WHERE id IN ('$vidlist')";
Database::query($sql);
}
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
break;
case 'enableinstances':
if (!empty($vidlist)) {
Display::addFlash(Display::return_message("Enabling instance"));
$sql = "UPDATE $table SET visible = 1 WHERE id IN ('$vidlist') ";
Database::query($sql);
}
Virtual::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
break;
case 'fulldeleteinstances':
$todelete = [];
// Removes everything.
if (empty($automation)) {
if (!empty($vidlist)) {
$todelete = Database::select('*', 'vchamilo', ['where' => ["id IN ('$vidlist')" => []]]);
}
} else {
$todelete = Database::select(
'*',
'vchamilo',
['where' => ["root_web = '{$n->root_web}' " => []]]
);
}
if ($todelete) {
foreach ($todelete as $fooid => $instance) {
$slug = $instance['slug'];
if (!empty($slug)) {
// Remove all files and eventual symlinks
$absalternatecourse = Virtual::getConfig('vchamilo', 'course_real_root');
$coursedir = $absalternatecourse.$slug;
Display::addFlash(Display::return_message("Deleting $coursedir"));
removeDir($coursedir);
if ($absalternatehome = Virtual::getConfig('vchamilo', 'home_real_root')) {
$homedir = $absalternatehome.'/'.$slug;
Display::addFlash(Display::return_message("Deleting $homedir"));
removeDir($homedir);
}
// delete archive
if ($absalternatearchive = Virtual::getConfig('vchamilo', 'archive_real_root')) {
$archivedir = $absalternatearchive.'/'.$slug;
Display::addFlash(Display::return_message("Deleting $archivedir"));
removeDir($archivedir);
}
// Delete upload
if ($dir = Virtual::getConfig('vchamilo', 'upload_real_root')) {
$dir = $dir.'/'.$slug;
Display::addFlash(Display::return_message("Deleting $dir"));
removeDir($dir);
}
}
$sql = "DELETE FROM {$table} WHERE id = ".$instance['id'];
Database::query($sql);
Display::addFlash(Display::return_message("Removing instance: ".$instance['root_web']));
Virtual::dropDatabase((object) $instance);
}
}
break;
case 'snapshotinstance':
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
$vid = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : '';
if ($vid) {
$vhosts = Database::select('*', 'vchamilo', ['where' => ['id = ?' => $vid]]);
$vhost = (object) array_pop($vhosts);
} else {
$vhost = (object) $_configuration;
$vhost->slug = Virtual::getSlugFromUrl($vhost->root_web);
$vhost->id = 0;
}
// Parsing url for building the template name.
$wwwroot = $vhost->root_web;
$vchamilostep = isset($_REQUEST['step']) ? $_REQUEST['step'] : '';
// Make template directory (files and SQL).
$separator = DIRECTORY_SEPARATOR;
$dirMode = api_get_permissions_for_new_directories();
$backupDir = api_get_path(SYS_PATH).'plugin'.$separator.'vchamilo'.$separator.'templates'.$separator.$vhost->slug.$separator;
$absolute_datadir = $backupDir.'data';
$absolute_sqldir = $backupDir.'dump.sql';
if (!is_dir($backupDir)) {
$result = mkdir($backupDir, $dirMode, true);
if ($result) {
Display::addFlash(
Display::return_message('Directory created: '.$backupDir)
);
} else {
Display::addFlash(
Display::return_message("Cannot create directory: $backupDir check the folder permissions", 'error')
);
}
}
if ($vchamilostep == 0) {
// Create directories, if necessary.
if (!is_dir($absolute_datadir)) {
mkdir($absolute_datadir, $dirMode, true);
mkdir($absolute_datadir.'/home', $dirMode, true);
}
if (empty($fullautomation)) {
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
$content = '<form name"single" action="'.$actionurl.'">';
$content .= '<input type="hidden" name="what" value="snapshotinstance" />';
$content .= '<input type="hidden" name="vid" value="'.$vhost->id.'" />';
$content .= '<input type="hidden" name="step" value="1" />';
$content .= '<input type="submit" class="btn btn-primary" name="go_btn" value="'.$plugin->get_lang('continue').'" />';
$content .= '</form>';
$content .= '</div>';
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
$tpl->assign('message', '<h4>'.$plugin->get_lang('vchamilosnapshot1').'</h4>');
$tpl->assign('content', $content);
$tpl->display_one_col_template();
exit;
} else {
// continue next step
$vchamilostep = 1;
}
}
if ($vchamilostep >= 1) {
if ($wwwroot == $_configuration['root_web']) {
// Make fake Vchamilo record.
$vchamilo = Virtual::makeThis();
$coursePath = api_get_path(SYS_COURSE_PATH);
$homePath = api_get_path(SYS_HOME_PATH);
$archivePath = api_get_path(SYS_ARCHIVE_PATH);
$uploadPath = api_get_path(SYS_UPLOAD_PATH);
} else {
// Get Vchamilo known record.
$vchamilo = Database::select('*', 'vchamilo', ['where' => ['root_web = ?' => [$wwwroot]]], 'first');
$vchamilo = (object) $vchamilo;
$coursePath = Virtual::getConfig('vchamilo', 'course_real_root');
$homePath = Virtual::getConfig('vchamilo', 'home_real_root');
$archivePath = Virtual::getConfig('vchamilo', 'archive_real_root');
$uploadPath = Virtual::getConfig('vchamilo', 'upload_real_root');
$coursePath = $coursePath.'/'.$vchamilo->slug;
$homePath = $homePath.'/'.$vchamilo->slug;
$archivePath = $archivePath.'/'.$vchamilo->slug;
$uploadPath = $uploadPath.'/'.$vchamilo->slug;
}
$content = '';
if ($vchamilostep == 1) {
// Auto dump the databases in a master template folder.
// this will create three files : dump.sql
$result = Virtual::backupDatabase($vchamilo, $absolute_sqldir);
if (empty($fullautomation)) {
if (!$result) {
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
$content .= '<p><form name"single" action="'.$actionurl.'">';
$content .= '<input type="submit" name="go_btn" value="'.$plugin->get_lang('cancel').'" />';
$content .= '</form></p>';
} else {
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
$message = $plugin->get_lang('vchamilosnapshot2');
Display::addFlash(
Display::return_message('Database file created: '.$absolute_sqldir)
);
$content .= '<form name"single" action="'.$actionurl.'">';
$content .= '<input type="hidden" name="what" value="snapshotinstance" />';
$content .= '<input type="hidden" name="vid" value="'.$vhost->id.'" />';
$content .= '<input type="hidden" name="step" value="2" />';
$content .= '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('continue').'" />';
$content .= '</form>';
}
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
$tpl->assign('message', '<h4>'.$message.'</h4>');
$tpl->assign('content', $content);
$tpl->display_one_col_template();
exit;
}
}
Display::addFlash(Display::return_message("Copying from '$homePath' to '{$absolute_datadir}/home' "));
copyDirTo($homePath, $absolute_datadir.'/home/', false);
Display::addFlash(Display::return_message("Copying from '$coursePath' to '$absolute_datadir/courses' "));
copyDirTo($coursePath, $absolute_datadir.'/courses/', false);
Display::addFlash(Display::return_message("Copying from '$uploadPath' to '$absolute_datadir/upload' "));
copyDirTo($uploadPath, $absolute_datadir.'/upload/', false);
// Store original hostname and some config info for further database or filestore replacements.
$FILE = fopen($backupDir.$separator.'manifest.php', 'w');
fwrite($FILE, '<'.'?php ');
fwrite($FILE, "\$templatewwwroot = '".$wwwroot."';\n");
fwrite($FILE, '?'.'>');
fclose($FILE);
// Every step was SUCCESS.
if (empty($fullautomation)) {
Display::addFlash(
Display::return_message(
$plugin->get_lang('successfinishedcapture'),
'success'
)
);
if (empty($vid)) {
$template = Virtual::getConfig('vchamilo', 'default_template');
if (empty($template)) {
Display::addFlash(
Display::return_message('Set default template as <b>'.$vhost->slug.'</b>', 'success', false)
);
$params = [
'subkey' => 'vchamilo',
'title' => 'default_template',
'type' => 'setting',
'category' => 'Plugins',
'variable' => 'vchamilo_default_template',
'selected_value' => $vhost->slug,
'access_url_changeable' => 0,
];
api_set_setting_simple($params);
} else {
Display::addFlash(
Display::return_message('Default template is: <b>'.$vhost->slug.'</b>', 'success', false)
);
}
}
$actionurl = $_configuration['root_web'].'/plugin/vchamilo/views/manage.php';
$content .= '<form name"single" action="'.$actionurl.'">';
$content .= '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('backtoindex').'" />';
$content .= '</form>';
$tpl = new Template(get_lang('Snapshot'), true, true, false, true, false);
$tpl->assign('message', $plugin->get_lang('vchamilosnapshot3'));
$tpl->assign('content', $content);
$tpl->display_one_col_template();
exit;
}
}
break;
case 'clearcache':
// Removes cache directory.
if (empty($automation)) {
if (array_key_exists('vids', $_REQUEST)) {
$toclear = Database::select('*', 'vchamilo', ['where' => ["id IN ('$vidlist')" => []]]);
} else {
$vid = isset($_REQUEST['vid']) ? $_REQUEST['vid'] : 0;
if ($vid) {
$vhosts = Database::select('*', 'vchamilo', ['where' => ['id = ?' => $vid]]);
$vhost = (object) array_pop($vhosts);
$toclear[$vhost->id] = $vhost;
} else {
$toclear[0] = (object) $_configuration;
}
}
} else {
$toclear = Database::select(
'*',
'vchamilo',
['where' => ["root_web = '{$n->root_web}' " => []]]
);
}
foreach ($toclear as $fooid => $instance) {
if ($fooid == 0) {
$templatepath = api_get_path(SYS_ARCHIVE_PATH).'twig';
Display::addFlash(Display::return_message("Deleting master cache $templatepath \n"));
removeDir($templatepath);
} else {
$coursePath = Virtual::getConfig('vchamilo', 'course_real_root');
$homePath = Virtual::getConfig('vchamilo', 'home_real_root');
$archivePath = Virtual::getConfig('vchamilo', 'archive_real_root');
//$uploadPath = Virtual::getConfig('vchamilo', 'upload_real_root');
// Get instance archive
$archivepath = api_get_path(SYS_ARCHIVE_PATH, (array) $instance);
$templatepath = $archivePath.'/'.$instance['slug'].'/twig';
Display::addFlash(Display::return_message("Deleting cache $templatepath \n"));
removeDir($templatepath);
}
}
break;
case 'setconfigvalue':
$select = '<select name="preset" onchange="setpreset(this.form, this)">';
$settings = api_get_settings();
foreach ($settings as $setting) {
$select .= '<option name="'.$setting['variable'].'/'.$setting['subkey'].'">'.
$setting['variable'].' - '.$setting['subkey'].
'</option>';
}
$select .= '</select>';
if (empty($vidlist)) {
api_not_allowed(true, 'No virtual chamilo selected');
}
Display::display_header();
echo '<h2>'.$plugin->get_lang('sendconfigvalue').'</h2>';
echo '<form name="setconfigform">';
echo '<input type="hidden" name="vidlist" value="'.$vidlist.'" />';
echo '<input type="hidden" name="confirm" value="1" />';
echo '<table>';
echo '<tr><td>'.get_lang('variable').'</td><td>'.get_lang('subkey').'</td></tr>';
echo '<tr><td><input type="text" name="variable" value="" size="30" /></td>';
echo '<td><input type="text" name="subkey" value="" size="30" /></td></tr>';
echo '<tr><td colspan="2">'.$select.'</td></tr>';
echo '<tr><td colspan="2">';
echo '<input class="btn btn-primary" type="submit" name="go_btn" value="'.$plugin->get_lang('distributevalue').'"</td></tr>';
echo '</table>';
echo '</form>';
Display::display_footer();
exit;
break;
}

View File

@@ -0,0 +1,157 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../../../main/inc/global.inc.php';
// Security
api_protect_admin_script();
Virtual::checkSettings();
$action = isset($_GET['what']) ? $_GET['what'] : '';
define('CHAMILO_INTERNAL', true);
$plugin = VChamiloPlugin::create();
$thisurl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
Virtual::requireJs('host_list.js', 'vchamilo', 'head');
if ($action) {
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/manage.controller.php';
}
$query = "SELECT * FROM vchamilo";
$result = Database::query($query);
$instances = [];
while ($instance = Database::fetch_object($result)) {
$instances[$instance->id] = $instance;
}
$templates = Virtual::getAvailableTemplates();
if (empty($templates)) {
$url = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php?what=snapshotinstance';
$url = Display::url($url, $url);
Display::addFlash(
Display::return_message('You need to create a snapshot of master first here:'.$url, 'info', false)
);
}
$table = new HTML_Table(['class' => 'table table-hover table-striped data_table']);
$column = 0;
$row = 0;
// $table->set_additional_parameters($parameters);
$headers = [
'',
$plugin->get_lang('sitename'),
$plugin->get_lang('dbhost').' - '.get_lang('Database'),
$plugin->get_lang('coursefolder'),
$plugin->get_lang('enabled'),
$plugin->get_lang('lastcron'),
'',
];
$attrs = ['center' => 'left'];
$table->addRow($headers, $attrs, 'th');
$i = 0;
foreach ($instances as $instance) {
$checkbox = '<input type="checkbox" class="vnodessel" name="vids[]" value="'.$instance->id.'" />';
$sitelink = $instance->sitename;
if ($instance->visible) {
$status = '<a href="'.$thisurl.'?what=disableinstances&vids[]='.$instance->id.'" >
'.Display::returnFontAwesomeIcon('toggle-on', 2).'</a>';
} else {
$status = '<a href="'.$thisurl.'?what=enableinstances&vids[]='.$instance->id.'" >
'.Display::returnFontAwesomeIcon('toggle-off', 2).'</a>';
}
$cmd = '&nbsp;<a href="'.$thisurl.'?what=editinstance&vid='.$instance->id.'" title="'.$plugin->get_lang('edit').'">
'.Display::returnFontAwesomeIcon('pencil', 2).'</a>';
$cmd .= '&nbsp;<a href="'.$thisurl.'?what=snapshotinstance&vid='.$instance->id.'" title="'.$plugin->get_lang('snapshotinstance').'">
'.Display::returnFontAwesomeIcon('camera', 2).'</a>';
$cmd .= '<a href="'.$thisurl.'?what=upgrade&vids[]='.$instance->id.'" title="'.$plugin->get_lang('Upgrade').'">
&nbsp;'.Display::returnFontAwesomeIcon('wrench', 2).' </a>';
if (!$instance->visible) {
$cmd .= '<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToDelete').'\')) return false;" href="'.$thisurl.'?what=fulldeleteinstances&vids[]='.$instance->id.'" title="'.$plugin->get_lang('destroyinstances').'">
&nbsp;'.Display::returnFontAwesomeIcon('remove', 2).' </a>';
} else {
$cmd .= '<a onclick="javascript:if(!confirm(\''.get_lang('AreYouSureToDelete').'\')) return false;" href="'.$thisurl.'?what=deleteinstances&vids[]='.$instance->id.'" title="'.$plugin->get_lang('deleteinstances').'">
&nbsp;'.Display::returnFontAwesomeIcon('remove', 2).' </a>';
}
$crondate = $instance->lastcron ? date('r', $instance->lastcron) : '';
$data = [
$checkbox,
$sitelink.' '.$instance->institution.' ('.Display::url($instance->root_web, $instance->root_web, ['target' => '_blank']).')',
$instance->db_host.' - '.$instance->main_database,
$instance->slug,
$status,
$crondate,
$cmd,
];
$attrs = ['center' => 'left'];
$table->addRow($data, $attrs, 'td');
$i++;
}
$items = [
[
'url' => $thisurl.'?what=newinstance',
'content' => $plugin->get_lang('newinstance'),
],
[
'url' => $thisurl.'?what=import',
'content' => $plugin->get_lang('ImportInstance'),
],
[
'url' => $thisurl.'?what=snapshotinstance&vid=0',
'content' => $plugin->get_lang('snapshotmaster'),
],
[
'url' => $thisurl.'?what=clearcache&vid=0',
'content' => $plugin->get_lang('clearmastercache'),
],
[
'url' => api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/syncparams.php',
'content' => $plugin->get_lang('sync_settings'),
],
[
'url' => api_get_path(WEB_CODE_PATH).'admin/configure_plugin.php?name=vchamilo',
'content' => get_lang('Settings'),
],
];
$content = Display::page_header('VChamilo Instances');
$content .= Display::actions($items);
$content .= '<form action="'.$thisurl.'">';
$content .= $table->toHtml();
$selectionoptions = ['<option value="0" selected="selected">'.$plugin->get_lang('choose').'</option>'];
$selectionoptions[] = '<option value="deleteinstances">'.$plugin->get_lang('deleteinstances').'</option>';
$selectionoptions[] = '<option value="enableinstances">'.$plugin->get_lang('enableinstances').'</option>';
$selectionoptions[] = '<option value="fulldeleteinstances">'.$plugin->get_lang(
'destroyinstances'
).'</option>';
$selectionoptions[] = '<option value="clearcache">'.$plugin->get_lang('clearcache').'</option>';
$selectionoptions[] = '<option value="setconfigvalue">'.$plugin->get_lang('setconfigvalue').'</option>';
$selectionaction = '<select name="what" onchange="this.form.submit()">'.implode('', $selectionoptions).'</select>';
$content .= '<div class="vchamilo-right"><div></div><div>
<a href="javascript:selectallhosts()">'.$plugin->get_lang('selectall').'</a> -
<a href="javascript:deselectallhosts()">'.$plugin->get_lang('selectnone').'</a> -
&nbsp; - '.$plugin->get_lang('withselection').' '.$selectionaction.'</div></div>';
$content .= '</form>';
if (empty($templates)) {
$content = '';
}
$tpl = new Template(get_lang('VChamilo'), true, true, false, true, false);
$tpl->assign('content', $content);
$tpl->display_one_col_template();

View File

@@ -0,0 +1,55 @@
<?php
/* For licensing terms, see /license.txt */
/**
* Tests database connection.
*
* @package vchamilo
*
* @author Moheissen Fabien (fabien.moheissen@gmail.com)
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
*/
// Loading configuration.
require_once __DIR__.'/../../../main/inc/global.inc.php';
api_protect_admin_script();
global $_configuration;
$plugin = VChamiloPlugin::create();
// Retrieve parameters for database connection test.
$dbParams = [];
$dbParams['db_host'] = $_REQUEST['vdbhost'];
$dbParams['db_user'] = $_REQUEST['vdblogin'];
$dbParams['db_password'] = $_REQUEST['vdbpass'];
$dbParams['root_sys'] = api_get_path(SYS_PATH);
$dbParams = [
'driver' => 'pdo_mysql',
'host' => $_REQUEST['vdbhost'],
'user' => $_REQUEST['vdblogin'],
'password' => $_REQUEST['vdbpass'],
//'dbname' => isset($_configuration['main_database']) ? $_configuration['main_database'] : '',
// Only relevant for pdo_sqlite, specifies the path to the SQLite database.
//'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
// Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
//'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
];
try {
$database = new \Database();
$connection = $database->connect(
$dbParams,
$_configuration['root_sys'],
$_configuration['root_sys'],
true
);
$list = $connection->getSchemaManager()->listDatabases();
echo $plugin->get_lang('connectionok');
} catch (Exception $e) {
echo $plugin->get_lang('badconnection');
exit();
}

View File

@@ -0,0 +1,3 @@
<?php
// Deprecated and vulnerable. Blanked as substitute to removal due to minor version update method.
exit;

View File

@@ -0,0 +1,132 @@
<?php
/* For licensing terms, see /license.txt */
use Doctrine\DBAL\Configuration;
use Doctrine\DBAL\DriverManager;
api_protect_admin_script();
$sql = "SELECT * FROM vchamilo";
$result = Database::query($sql);
$vchamilos = Database::store_result($result, 'ASSOC');
// propagate in all known vchamilos a setting
switch ($action) {
case 'syncall':
exit;
$keys = array_keys($_REQUEST);
$selection = preg_grep('/sel_.*/', $keys);
foreach ($selection as $selkey) {
$settingId = str_replace('sel_', '', $selkey);
if (!is_numeric($settingId)) {
continue;
}
$value = $_REQUEST[$selkey];
$setting = api_get_settings_params_simple(['id = ?' => $settingId]);
$params = [
'title' => $setting['title'],
'variable' => $setting['variable'],
'subkey' => $setting['subkey'],
'category' => $setting['category'],
'access_url' => $setting['access_url'],
];
foreach ($vchamilos as $chm) {
$table = $chm['main_database'].".settings_current ";
$sql = " SELECT * FROM $table
WHERE
variable = '{{$setting['variable']}}' AND
access_url = '{$setting['access_url']}'
";
$result = Database::query($sql);
if (Database::num_rows($result)) {
Database::update($table, ['selected_Value' => $value, ['id' => $settingId]]);
}
}
}
break;
case 'syncthis':
$settingId = isset($_GET['settingid']) ? (int) $_GET['settingid'] : 0;
if ($settingId) {
$deleteIfEmpty = $_REQUEST['del'] ?? '';
$value = $_REQUEST['value'];
// Getting the local setting record.
$setting = api_get_settings_params_simple(['id = ?' => $settingId]);
if (empty($setting)) {
return 0;
}
$params = [
'access_url_changeable' => $setting['access_url_changeable'],
'title' => $setting['title'],
'variable' => $setting['variable'],
'subkey' => $setting['subkey'],
'category' => $setting['category'],
'type' => $setting['type'],
'comment' => $setting['comment'],
'access_url' => $setting['access_url'],
];
$errors = '';
foreach ($vchamilos as $instance) {
$table = 'settings_current';
$config = new Configuration();
$connectionParams = [
'dbname' => $instance['main_database'],
'user' => $instance['db_user'],
'password' => $instance['db_password'],
'host' => $instance['db_host'],
'driver' => 'pdo_mysql',
];
try {
$connection = DriverManager::getConnection($connectionParams, $config);
$variable = $setting['variable'];
$subKey = $setting['subkey'];
$category = $setting['category'];
$accessUrl = $setting['access_url'];
if ($deleteIfEmpty && empty($value)) {
$connection->delete($table, ['selected_value' => $value, 'variable' => $variable, 'access_url' => $accessUrl]);
$case = 'delete';
} else {
$sql = "SELECT * FROM $table
WHERE
variable = '$variable' AND
access_url = '$accessUrl'
";
$result = $connection->fetchAllAssociative($sql);
if (!empty($result)) {
//$sql = "UPDATE $table SET selected_value = '$value' WHERE id = $settingId";
$criteria = ['variable' => $variable];
if (!empty($subKey)) {
$criteria['subkey'] = $subKey;
}
if (!empty($category)) {
$criteria['category'] = $category;
}
$connection->update($table, ['selected_value' => $value], $criteria);
} else {
$connection->insert($table, $params);
}
}
} catch (Exception $e) {
echo $e->getMessage();
}
}
return $errors;
} else {
return "Bad ID. Non numeric";
}
break;
}
return 0;

View File

@@ -0,0 +1,83 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../../../main/inc/global.inc.php';
api_protect_admin_script();
$action = $_GET['what'] ?? '';
define('CHAMILO_INTERNAL', true);
$plugin = VChamiloPlugin::create();
$thisUrl = api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php';
if ($action) {
require_once api_get_path(SYS_PLUGIN_PATH).'vchamilo/views/syncparams.controller.php';
}
$settings = api_get_settings();
$table = new HTML_Table(['class' => 'table']);
$column = 0;
$row = 0;
$headers = [
'',
$plugin->get_lang('variable').' ['.$plugin->get_lang('subkey').']',
$plugin->get_lang('category'),
$plugin->get_lang('accessurl'),
$plugin->get_lang('value'),
'',
];
$attrs = ['center' => 'left'];
$table->addRow($headers, $attrs, 'th');
foreach ($settings as $param) {
if ($param['subkey'] == 'vchamilo') {
continue;
}
$check = '';
$attrs = ['center' => 'left'];
$syncButton = '
<input class="btn btn-default" type="button" name="syncthis"
value="'.$plugin->get_lang('syncthis').'" onclick="ajax_sync_setting(\''.$param['id'].'\')" />
<span id="res_'.$param['id'].'"></span>';
$data = [
$check,
isset($param['subkey']) && !empty($param['subkey']) ? $param['variable'].' ['.$param['subkey'].']' : $param['variable'],
$param['category'],
$param['access_url'],
'<input type="text" disabled name="value_'.$param['id'].'"
value="'.htmlspecialchars($param['selected_value'], ENT_COMPAT, 'UTF-8').'" />'.
'<br />Master value: '.$param['selected_value'],
$syncButton,
];
$row = $table->addRow($data, $attrs, 'td');
$table->setRowAttributes($row, ['id' => 'row_'.$param['id']], true);
}
$content = '<form name="settingsform" action="'.$thisUrl.'">';
$content .= '<input type="hidden" name="what" value="" />';
$content .= $table->toHtml();
$content .= '</form>';
Display::addFlash(Display::return_message($plugin->get_lang('Sync your master settings to all instances.')));
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
$htmlHeadXtra[] = "<script>
function ajax_sync_setting(settingid) {
var webUrl = '".api_get_path(WEB_PATH)."';
var spare = $('#row_'+settingid).html();
var formobj = document.forms['settingsform'];
var url = webUrl + 'plugin/vchamilo/ajax/service.php?what=syncthis&settingid='+settingid+'&value='+encodeURIComponent(formobj.elements['value_'+settingid].value);
$('#row_'+settingid).html('<td colspan=\"7\"><img src=\"'+webUrl+'plugin/vchamilo/pix/ajax_waiter.gif\" /></td>');
$.get(url, function (data) {
$('#row_'+settingid).html(spare);
$('#res_'+settingid).html(data);
});
}
</script>";
$tpl = new Template($plugin->get_lang('SyncSettings'), true, true, false, true, false);
$tpl->assign('content', $content);
$tpl->display_one_col_template();

View File

@@ -0,0 +1,65 @@
<?php
/* For licensing terms, see /license.txt */
$cidReset = true;
require_once __DIR__.'/../../../main/inc/global.inc.php';
$interbreadcrumb[] = ['url' => 'manage.php', 'name' => get_lang('VChamilo')];
// Security
api_protect_admin_script();
Virtual::checkSettings();
$plugin = VChamiloPlugin::create();
$id = isset($_REQUEST['vid']) ? (int) $_REQUEST['vid'] : 0;
$instance = Virtual::getInstance($id);
$canBeUpgraded = Virtual::canBeUpgraded($instance);
$form = new FormValidator('upgrade', 'post', api_get_self().'?vid='.$id);
// Database host.
$form->addHeader(get_lang('Upgrade'));
$form->addText('root_web', $plugin->get_lang('rootweb'));
$form->addText('db_host', $plugin->get_lang('dbhost'));
$form->addText('db_user', $plugin->get_lang('dbuser'));
$form->addText('main_database', [$plugin->get_lang('maindatabase')]);
$form->setDefaults((array) $instance);
if ($canBeUpgraded) {
$form->addLabel(get_lang('From'), $canBeUpgraded);
$form->addLabel(get_lang('To'), api_get_setting('chamilo_database_version'));
$form->addButtonSave(get_lang('Upgrade'));
} else {
Display::addFlash(Display::return_message(get_lang('NothingToUpgrade')));
}
$form->freeze();
$content = $form->returnForm();
if ($form->validate() && $canBeUpgraded) {
$values = $form->getSubmitValues();
require_once api_get_path(SYS_CODE_PATH).'install/install.lib.php';
$manager = Virtual::getConnectionFromInstance($instance, true);
if ($manager) {
ob_start();
$result = migrateSwitch($canBeUpgraded, $manager, false);
$data = ob_get_clean();
if ($result) {
Display::addFlash(Display::return_message(get_lang('Upgraded')));
} else {
Display::addFlash(Display::return_message(get_lang('Error')));
}
$content = $data;
} else {
Display::addFlash(Display::return_message(get_lang('Error')));
}
}
$tpl = new Template(get_lang('Upgrade'), true, true, false, true, false);
$tpl->assign('content', $content);
$tpl->display_one_col_template();