Virtual.php 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Cocur\Slugify\Slugify;
  4. use Doctrine\ORM\EntityManager;
  5. use Symfony\Component\Console\Input\ArrayInput;
  6. /**
  7. * Class Virtual.
  8. */
  9. class Virtual
  10. {
  11. /**
  12. * @param array $_configuration
  13. */
  14. public static function hookConfiguration(&$_configuration)
  15. {
  16. global $virtualChamilo;
  17. if (defined('CLI_SCRIPT') && !defined('CLI_VCHAMILO_OVERRIDE')) {
  18. return;
  19. }
  20. // provides an effective value for the virtual root_web based on domain analysis
  21. self::getHostName($_configuration);
  22. // We are on physical chamilo. Let original config play
  23. $virtualChamiloWebRoot = rtrim($_configuration['vchamilo_web_root'], '/').'/';
  24. $virtualChamilo = [];
  25. if ($_configuration['root_web'] == $virtualChamiloWebRoot) {
  26. return;
  27. }
  28. // pre hook to chamilo main table and get alternate configuration.
  29. // sure Database object is not set up. Soo use bootstrap connection
  30. /** @var \Doctrine\DBAL\Connection $connection */
  31. $connection = self::bootConnection($_configuration);
  32. $query = "SELECT * FROM vchamilo WHERE root_web = '$virtualChamiloWebRoot'";
  33. $result = $connection->executeQuery($query);
  34. if ($result->rowCount()) {
  35. $data = $result->fetch();
  36. $excludes = ['id', 'name'];
  37. $query = "SELECT * FROM settings_current WHERE subkey = 'vchamilo'";
  38. $virtualSettings = $connection->executeQuery($query);
  39. $virtualSettings = $virtualSettings->fetchAll();
  40. $homePath = '';
  41. $coursePath = '';
  42. $archivePath = '';
  43. $uploadPath = '';
  44. $passwordEncryption = '';
  45. foreach ($virtualSettings as $setting) {
  46. switch ($setting['variable']) {
  47. case 'vchamilo_upload_real_root':
  48. $uploadPath = $setting['selected_value'];
  49. break;
  50. case 'vchamilo_home_real_root':
  51. $homePath = $setting['selected_value'];
  52. break;
  53. case 'vchamilo_course_real_root':
  54. $coursePath = $setting['selected_value'];
  55. break;
  56. case 'vchamilo_archive_real_root':
  57. $archivePath = $setting['selected_value'];
  58. break;
  59. case 'vchamilo_password_encryption':
  60. $passwordEncryption = $setting['selected_value'];
  61. break;
  62. }
  63. }
  64. if (empty($homePath) || empty($coursePath) || empty($archivePath) || empty($uploadPath)) {
  65. echo 'Configure correctly the vchamilo plugin';
  66. exit;
  67. }
  68. // Only load if is visible
  69. if ($data && $data['visible'] === '1') {
  70. foreach ($data as $key => $value) {
  71. if (!in_array($key, $excludes)) {
  72. // Avoid empty password_encryption
  73. if ($key == 'password_encryption' && empty($value)) {
  74. continue;
  75. }
  76. $_configuration[$key] = $value;
  77. }
  78. $_configuration['virtual'] = $data['root_web'].'/';
  79. }
  80. $data['SYS_ARCHIVE_PATH'] = self::addTrailingSlash($archivePath).$data['slug'];
  81. $data['SYS_HOME_PATH'] = self::addTrailingSlash($homePath).$data['slug'];
  82. $data['SYS_COURSE_PATH'] = self::addTrailingSlash($coursePath).$data['slug'];
  83. $data['SYS_UPLOAD_PATH'] = self::addTrailingSlash($uploadPath).$data['slug'];
  84. $data['WEB_HOME_PATH'] = self::addTrailingSlash($data['home_url']);
  85. $data['WEB_UPLOAD_PATH'] = self::addTrailingSlash($data['upload_url']);
  86. $data['WEB_ARCHIVE_PATH'] = self::addTrailingSlash($data['archive_url']);
  87. //$data['WEB_COURSE_PATH'] = self::addTrailingSlash($data['course_url']);
  88. if (!empty($passwordEncryption)) {
  89. $_configuration['password_encryption'] = $passwordEncryption;
  90. }
  91. // Instance cannot have multiple urls
  92. $_configuration['multiple_access_urls'] = false;
  93. $_configuration['virtual_css_theme_folder'] = '';
  94. if (isset($data['css_theme_folder']) && !empty($data['css_theme_folder'])) {
  95. $_configuration['virtual_css_theme_folder'] = $data['css_theme_folder'];
  96. }
  97. $virtualChamilo = $data;
  98. } else {
  99. exit("This portal is disabled. Please contact your administrator");
  100. }
  101. } // otherwise it means the plugin was not configured yet
  102. }
  103. /**
  104. * @param array $_configuration
  105. */
  106. public static function getHostName(&$_configuration)
  107. {
  108. if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
  109. $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_configuration['force_https_forwarded_proto'])
  110. ) {
  111. $protocol = 'https';
  112. } else {
  113. if (!empty($_SERVER['HTTPS'])) {
  114. $protocol = 'https';
  115. } else {
  116. $protocol = 'http';
  117. }
  118. }
  119. if (defined('CLI_VCHAMILO_OVERRIDE')) {
  120. $_configuration['vchamilo_web_root'] = CLI_VCHAMILO_OVERRIDE;
  121. $_configuration['vchamilo_name'] = preg_replace('#https?://#', '', CLI_VCHAMILO_OVERRIDE);
  122. // remove radical from override for name
  123. // fake the server signature
  124. global $_SERVER;
  125. $_SERVER['SERVER_NAME'] = $_configuration['vchamilo_name'];
  126. $_SERVER['HTTP_HOST'] = $_configuration['vchamilo_name'];
  127. $_SERVER['QUERY_STRING'] = '';
  128. $_SERVER['REQUEST_URI'] = CLI_VCHAMILO_OVERRIDE;
  129. return;
  130. }
  131. $contentPrefix = '/';
  132. if (isset($_SERVER['CONTEXT_PREFIX']) && !empty($_SERVER['CONTEXT_PREFIX'])) {
  133. $contentPrefix = $_SERVER['CONTEXT_PREFIX'];
  134. } else {
  135. // Getting url_append from URL
  136. if (isset($_SERVER['REQUEST_URI'])) {
  137. $requestUri = $_SERVER['REQUEST_URI'];
  138. if (strpos($requestUri, '/courses/') !== false) {
  139. $result = substr($requestUri, 0, strpos($requestUri, '/courses/'));
  140. if (!empty($result) && $result != '/') {
  141. $contentPrefix = $result;
  142. }
  143. }
  144. }
  145. }
  146. $_configuration['vchamilo_web_root'] = "{$protocol}://".@$_SERVER['HTTP_HOST'].$contentPrefix;
  147. $_configuration['vchamilo_name'] = @$_SERVER['HTTP_HOST'];
  148. if (empty($_configuration['vchamilo_name'])) { // try again with another source if has failed
  149. $_configuration['vchamilo_name'] = "{$protocol}://".$_SERVER['SERVER_NAME'];
  150. if ($_SERVER['SERVER_PORT'] != 80) {
  151. $_configuration['vchamilo_name'] .= ':'.$_SERVER['SERVER_PORT'];
  152. }
  153. $_configuration['vchamilo_name'] = $_SERVER['SERVER_NAME'];
  154. }
  155. }
  156. /**
  157. * @param string $path
  158. *
  159. * @return string
  160. */
  161. public static function addTrailingSlash($path)
  162. {
  163. return substr($path, -1) == '/' ? $path : $path.'/';
  164. }
  165. /**
  166. * provides a side connection to a vchamilo database.
  167. *
  168. * @param array $_configuration
  169. *
  170. * @return \Doctrine\DBAL\Driver\Connection
  171. */
  172. public static function bootConnection(&$_configuration)
  173. {
  174. $dbParams = [
  175. 'driver' => 'pdo_mysql',
  176. 'host' => $_configuration['db_host'],
  177. 'user' => $_configuration['db_user'],
  178. 'password' => $_configuration['db_password'],
  179. 'dbname' => isset($_configuration['main_database']) ? $_configuration['main_database'] : '',
  180. // Only relevant for pdo_sqlite, specifies the path to the SQLite database.
  181. 'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
  182. // Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
  183. 'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
  184. ];
  185. try {
  186. $database = new \Database();
  187. $connection = $database->connect(
  188. $dbParams,
  189. $_configuration['root_sys'],
  190. $_configuration['root_sys'],
  191. true
  192. );
  193. } catch (Exception $e) {
  194. echo 'Side connection failure with '.$_configuration['db_host'].', '.$_configuration['db_user'].', ******** ';
  195. die();
  196. }
  197. return $connection;
  198. }
  199. /**
  200. * @param string $url
  201. */
  202. public static function redirect($url)
  203. {
  204. if (preg_match('#https?://#', $url)) {
  205. header('location: '.$url);
  206. } else {
  207. header('location: '.api_get_path(WEB_PATH).$url);
  208. }
  209. exit;
  210. }
  211. /**
  212. * @param string $course_folder
  213. *
  214. * @return string
  215. */
  216. public static function getHtaccessFragment($course_folder)
  217. {
  218. $str = "
  219. # Change this file to fit your configuration and save it as .htaccess in the courses folder #
  220. # Chamilo mod rewrite
  221. # Comment lines start with # and are not processed
  222. <IfModule mod_rewrite.c>
  223. RewriteEngine On
  224. # Rewrite base is the dir chamilo is installed in with trailing slash
  225. RewriteBase /{$course_folder}/
  226. # Do not rewrite on the main dir
  227. # Change this path to the path of your main folder
  228. RewriteCond %{REQUEST_URI} !^/main/
  229. #replace nasty ampersands by 3 slashes, we change these back in download.php
  230. RewriteRule ([^/]+)/document/(.*)&(.*)$ $1/document/$2///$3 [N]
  231. # Rewrite everything in the scorm folder of a course to the download script
  232. RewriteRule ([^/]+)/scorm/(.*)$ /main/document/download_scorm.php?doc_url=/$2&cDir=$1 [QSA,L]
  233. # Rewrite everything in the document folder of a course to the download script
  234. RewriteRule ([^/]+)/document/(.*)$ /main/document/download.php?doc_url=/$2&cDir=$1 [QSA,L]
  235. # Rewrite everything in the work folder
  236. RewriteRule ([^/]+)/work/(.*)$ /main/work/download.php?file=work/$2&cDir=$1 [QSA,L]
  237. </IfModule>
  238. ";
  239. return $str;
  240. }
  241. /**
  242. * @return string
  243. */
  244. public static function getDefaultCourseIndexFragment()
  245. {
  246. return "<html><head></head><body></body></html>";
  247. }
  248. /**
  249. * @param string $template
  250. *
  251. * @return bool
  252. */
  253. public static function templateExists($template)
  254. {
  255. global $_configuration;
  256. // Find and checktemplate directory (files and SQL).
  257. $separator = DIRECTORY_SEPARATOR;
  258. $templatefoldername = 'plugin'.$separator.'vchamilo'.$separator.'templates';
  259. $relative_datadir = $templatefoldername.$separator.$template.'_sql';
  260. $absolute_datadir = $_configuration['root_sys'].$relative_datadir;
  261. return is_dir($absolute_datadir);
  262. }
  263. /**
  264. * drop a vchamilo instance databases using the physical connection.
  265. *
  266. * @param stdClass $params
  267. * return an array of errors or false if ok
  268. */
  269. public static function dropDatabase($params)
  270. {
  271. $params = clone $params;
  272. if (empty($params->main_database)) {
  273. Display::addFlash(Display::return_message('No database found'));
  274. return;
  275. }
  276. $databaseToDelete = $params->main_database;
  277. unset($params->main_database);
  278. $connection = self::getConnectionFromInstance($params);
  279. if ($connection) {
  280. $databases = $connection->getSchemaManager()->listDatabases();
  281. if (in_array($databaseToDelete, $databases)) {
  282. $connection->getSchemaManager()->dropDatabase(
  283. $databaseToDelete
  284. );
  285. Display::addFlash(
  286. Display::return_message(
  287. 'Database deleted: '.$databaseToDelete
  288. )
  289. );
  290. } else {
  291. Display::addFlash(
  292. Display::return_message(
  293. 'Database does not exist: '.$databaseToDelete
  294. )
  295. );
  296. }
  297. } else {
  298. Display::addFlash(
  299. Display::return_message(
  300. "Cannot connect DB: $databaseToDelete"
  301. )
  302. );
  303. }
  304. return false;
  305. }
  306. /**
  307. * @param stdClass $params
  308. *
  309. * @return bool
  310. */
  311. public static function createDatabase($params)
  312. {
  313. $params = clone $params;
  314. $databaseName = $params->main_database;
  315. unset($params->main_database);
  316. $connection = self::getConnectionFromInstance($params);
  317. if ($connection) {
  318. $databaseList = $connection->getSchemaManager()->listDatabases();
  319. if (!in_array($databaseName, $databaseList)) {
  320. $connection->getSchemaManager()->createDatabase($databaseName);
  321. Display::addFlash(
  322. Display::return_message("Creating DB ".$databaseName)
  323. );
  324. } else {
  325. Display::addFlash(
  326. Display::return_message("DB already exists: ".$databaseName)
  327. );
  328. }
  329. return true;
  330. }
  331. return false;
  332. }
  333. /**
  334. * get a proper SQLdump command.
  335. *
  336. * @param object $vchamilodata the complete new host information
  337. *
  338. * @return string the shell command
  339. */
  340. public static function getDatabaseDumpCmd($vchamilodata)
  341. {
  342. $pgm = self::getConfig('vchamilo', 'mysql_cmd');
  343. if (!$pgm) {
  344. $pgm = '/usr/bin/mysql';
  345. }
  346. $phppgm = str_replace("\\", '/', $pgm);
  347. $phppgm = str_replace("\"", '', $phppgm);
  348. $pgm = str_replace("/", DIRECTORY_SEPARATOR, $pgm);
  349. if (!is_executable($phppgm)) {
  350. throw new Exception('databasecommanddoesnotmatchanexecutablefile');
  351. }
  352. // Retrieves the host configuration (more secure).
  353. $vchamilodata = empty($vchamilodata) ? self::makeThis() : $vchamilodata;
  354. if (strstr($vchamilodata->db_host, ':') !== false) {
  355. list($vchamilodata->db_host, $vchamilodata->db_port) = explode(
  356. ':',
  357. $vchamilodata->db_host
  358. );
  359. }
  360. // Password.
  361. $databasePassword = '';
  362. if (!empty($vchamilodata->db_password)) {
  363. $databasePassword = '-p'.escapeshellarg($vchamilodata->db_password).' ';
  364. }
  365. // Making the command line (see 'vconfig.php' file for defining the right paths).
  366. $sqlcmd = $pgm.' -h'.$vchamilodata->db_host.(isset($vchamilodata->db_port) ? ' -P'.$vchamilodata->db_port.' ' : ' ');
  367. $sqlcmd .= '-u'.$vchamilodata->db_user.' '.$databasePassword;
  368. $sqlcmd .= '%DATABASE% < ';
  369. return $sqlcmd;
  370. }
  371. /**
  372. * @param stdClass $vchamilo
  373. * @param string $template
  374. *
  375. * @return bool
  376. */
  377. public static function loadDbTemplate($vchamilo, $template)
  378. {
  379. global $_configuration;
  380. // Make template directory (files and SQL).
  381. $separator = DIRECTORY_SEPARATOR;
  382. $templatefoldername = 'plugin'.$separator.'vchamilo'.$separator.'templates';
  383. $absolute_datadir = $_configuration['root_sys'].$templatefoldername.$separator.$template.$separator.'dump.sql';
  384. if (!$sqlcmd = self::getDatabaseDumpCmd($vchamilo)) {
  385. return false;
  386. }
  387. $sqlcmd = str_replace('%DATABASE%', $vchamilo->main_database, $sqlcmd);
  388. // Make final commands to execute, depending on the database type.
  389. $import = $sqlcmd.$absolute_datadir;
  390. // Execute the command.
  391. Display::addFlash(Display::return_message("Load database from template dump: \n $import "));
  392. if (!defined('CLI_SCRIPT')) {
  393. putenv('LANG=en_US.utf-8');
  394. }
  395. // ensure utf8 is correctly handled by php exec()
  396. // @see http://stackoverflow.com/questions/10028925/call-a-program-via-shell-exec-with-utf-8-text-input
  397. exec($import, $output, $return);
  398. if (!empty($output)) {
  399. Display::addFlash(Display::return_message(implode("\n", $output)."\n"));
  400. }
  401. return true;
  402. }
  403. /**
  404. * Backups a database for having a snapshot.
  405. *
  406. * @param $vchamilo object The Vchamilo object
  407. * @param $outputfilerad string The output SQL file radical
  408. *
  409. * @return bool if TRUE, dumping database was a success, otherwise FALSE
  410. */
  411. public static function backupDatabase($vchamilo, $outputfilerad)
  412. {
  413. // Separating host and port, if sticked.
  414. if (strstr($vchamilo->db_host, ':') !== false) {
  415. list($host, $port) = explode(':', $vchamilo->db_host);
  416. } else {
  417. $host = $vchamilo->db_host;
  418. }
  419. // By default, empty password.
  420. $pass = '';
  421. $pgm = null;
  422. if (empty($port)) {
  423. $port = 3306;
  424. }
  425. // Password.
  426. if (!empty($vchamilo->db_password)) {
  427. $pass = "-p".escapeshellarg($vchamilo->db_password);
  428. }
  429. // Making the commands for each database.
  430. $cmds = [];
  431. // Windows environments are not supported for this plugin at this time
  432. //if ($CFG->ostype == 'WINDOWS') {
  433. // $cmd_main = "-h{$host} -P{$port} -u{$vchamilo->db_user} {$pass} {$vchamilo->main_database}";
  434. // $cmds[] = $cmd_main . ' > ' . $outputfilerad;
  435. //} else {
  436. $cmd_main = "-h{$host} -P{$port} -u{$vchamilo->db_user} {$pass} {$vchamilo->main_database}";
  437. $cmds[] = $cmd_main.' > '.escapeshellarg($outputfilerad);
  438. //}
  439. $mysqldumpcmd = self::getConfig('vchamilo', 'cmd_mysqldump', true);
  440. $pgm = !empty($mysqldumpcmd) ? stripslashes($mysqldumpcmd) : false;
  441. if (!$pgm) {
  442. $message = "Database dump command not available check here: ";
  443. $url = api_get_path(WEB_CODE_PATH).'admin/configure_plugin.php?name=vchamilo';
  444. $message .= Display::url($url, $url);
  445. Display::addFlash(Display::return_message($message));
  446. return false;
  447. } else {
  448. $phppgm = str_replace("\\", '/', $pgm);
  449. $phppgm = str_replace("\"", '', $phppgm);
  450. $pgm = str_replace('/', DIRECTORY_SEPARATOR, $pgm);
  451. if (!is_executable($phppgm)) {
  452. $message = "Database dump command $phppgm does not match any executable";
  453. Display::addFlash(Display::return_message($message));
  454. return false;
  455. }
  456. // executing all commands
  457. foreach ($cmds as $cmd) {
  458. // Final command.
  459. $cmd = $pgm.' '.$cmd;
  460. // Executes the SQL command.
  461. exec($cmd, $execoutput, $returnvalue);
  462. }
  463. }
  464. // End with success.
  465. return 1;
  466. }
  467. /**
  468. * read manifest values in vchamilo template.
  469. */
  470. public static function getVmanifest($version)
  471. {
  472. $templatewwwroot = '';
  473. // Define the $templatewwwroot content, found in manifest.php for this template
  474. $file = api_get_path(SYS_PATH).'/plugin/vchamilo/templates/'.$version.'/manifest.php';
  475. if (file_exists($file)) {
  476. include $file;
  477. $manifest = new stdClass();
  478. $manifest->templatewwwroot = $templatewwwroot;
  479. // $manifest->templatevdbprefix = $templatevdbprefix;
  480. // $manifest->coursefolder = $coursefolder;
  481. return $manifest;
  482. }
  483. return false;
  484. }
  485. /**
  486. * make a fake vchamilo that represents the current host.
  487. */
  488. public static function makeThis()
  489. {
  490. global $_configuration;
  491. $thisPortal = new stdClass();
  492. $thisPortal->root_web = $_configuration['root_web'];
  493. $thisPortal->db_host = $_configuration['db_host'];
  494. $thisPortal->db_user = $_configuration['db_user'];
  495. $thisPortal->db_password = $_configuration['db_password'];
  496. $thisPortal->main_database = $_configuration['main_database'];
  497. return $thisPortal;
  498. }
  499. /**
  500. * Get available templates for defining a new virtual host.
  501. *
  502. * @return array the available templates, or EMPTY array
  503. */
  504. public static function getAvailableTemplates()
  505. {
  506. global $_configuration;
  507. $separator = DIRECTORY_SEPARATOR;
  508. $templatefoldername = 'plugin'.$separator.'vchamilo'.$separator.'templates';
  509. $tempDir = $_configuration['root_sys'].$templatefoldername;
  510. // Scans the templates.
  511. if (!is_dir($tempDir)) {
  512. $mode = api_get_permissions_for_new_directories();
  513. mkdir($tempDir, $mode, true);
  514. }
  515. $finder = new \Symfony\Component\Finder\Finder();
  516. $dirs = $finder->in($tempDir)->depth('== 0');
  517. // Retrieves template(s) name(s). Should be hostnames.
  518. $templates = [];
  519. /*if ($addEmptyTemplate) {
  520. $templates = array('' => $plugin->get_lang('emptysite'));
  521. }*/
  522. $template = self::getConfig('vchamilo', 'default_template');
  523. if ($dirs) {
  524. /** @var Symfony\Component\Finder\SplFileInfo $dir */
  525. foreach ($dirs as $dir) {
  526. if (is_dir($dir->getPathname())) {
  527. // A template is considered when a dump.sql exists.
  528. if (file_exists($dir->getPathname().'/dump.sql')) {
  529. $templateName = $dir->getRelativePathname();
  530. if ($templateName == $template) {
  531. $templateName .= ' (default)';
  532. }
  533. $templates[$dir->getRelativePathname()] = $templateName;
  534. }
  535. }
  536. }
  537. }
  538. return $templates;
  539. }
  540. /**
  541. * this function set will map standard moodle API calls to chamilo
  542. * internal primitives. This avoids too many changes to do in imported
  543. * code.
  544. */
  545. public static function getConfig($module, $key, $isplugin = true)
  546. {
  547. if ($isplugin) {
  548. $key = $module.'_'.$key;
  549. }
  550. $params = ['variable = ? AND subkey = ?' => [$key, $module]];
  551. $result = api_get_settings_params_simple($params);
  552. if ($result) {
  553. return $result['selected_value'];
  554. }
  555. return false;
  556. }
  557. /**
  558. * @param stdClass $vchamilo
  559. * @param string $template
  560. */
  561. public static function loadFilesFromTemplate($vchamilo, $template)
  562. {
  563. global $_configuration;
  564. // Make template directory (files and SQL).
  565. $separator = DIRECTORY_SEPARATOR;
  566. $templateDir = $_configuration['root_sys'].'plugin'.$separator.'vchamilo'.$separator.'templates'.$separator.$template;
  567. $vchamilo->virtual = true;
  568. $coursePath = self::getConfig('vchamilo', 'course_real_root').$separator.$vchamilo->slug;
  569. $homePath = self::getConfig('vchamilo', 'home_real_root').$separator.$vchamilo->slug;
  570. $archivePath = self::getConfig('vchamilo', 'archive_real_root').$separator.$vchamilo->slug;
  571. $uploadPath = self::getConfig('vchamilo', 'upload_real_root').$separator.$vchamilo->slug;
  572. // get the protocol free hostname
  573. Display::addFlash(
  574. Display::return_message("Copying {$templateDir}/data/courses => $coursePath")
  575. );
  576. copyDirTo(
  577. self::chopLastSlash($templateDir.'/data/courses'),
  578. self::chopLastSlash($coursePath),
  579. false
  580. );
  581. Display::addFlash(
  582. Display::return_message("Copying {$templateDir}/data/archive => $archivePath")
  583. );
  584. copyDirTo(
  585. self::chopLastSlash($templateDir.'/data/archive'),
  586. self::chopLastSlash($archivePath),
  587. false
  588. );
  589. Display::addFlash(
  590. Display::return_message("Copying {$templateDir}/data/home => $homePath")
  591. );
  592. copyDirTo(
  593. self::chopLastSlash($templateDir.'/data/home'),
  594. self::chopLastSlash($homePath),
  595. false
  596. );
  597. // Upload
  598. Display::addFlash(
  599. Display::return_message("Copying {$templateDir}/data/upload => $uploadPath")
  600. );
  601. copyDirTo(
  602. self::chopLastSlash($templateDir.'/data/upload/'),
  603. self::chopLastSlash($uploadPath),
  604. false
  605. );
  606. }
  607. /**
  608. * @param string $path
  609. *
  610. * @return mixed
  611. */
  612. public static function chopLastSlash($path)
  613. {
  614. return preg_replace('/\/$/', '', $path);
  615. }
  616. /**
  617. * @param string $str
  618. */
  619. public static function ctrace($str)
  620. {
  621. error_log($str);
  622. Display::addFlash(Display::return_message($str, 'normal', false));
  623. }
  624. /**
  625. * @param $file
  626. * @param $component
  627. * @param bool $return
  628. *
  629. * @return string
  630. */
  631. public static function requireJs($file, $component, $return = false)
  632. {
  633. global $_configuration, $htmlHeadXtra;
  634. if (preg_match('/^local_/', $component)) {
  635. $component = str_replace('local_', '', $component);
  636. $path = 'local/';
  637. } else {
  638. $path = 'plugin/';
  639. }
  640. // Secure the postslashing of the roots.
  641. $root_web = $_configuration['root_web'].'/';
  642. $root_web = preg_replace('#//$#', '/', $root_web);
  643. $str = '<script type="text/javascript" src="'.$root_web.$path.$component.'/js/'.$file.'"></script>'."\n";
  644. if ($return === 'head') {
  645. $htmlHeadXtra[] = $str;
  646. }
  647. if ($return) {
  648. return $str;
  649. }
  650. echo $str;
  651. }
  652. /**
  653. * @param $file
  654. * @param $component
  655. * @param bool $return
  656. *
  657. * @return string
  658. */
  659. public static function requireCss($file, $component, $return = false)
  660. {
  661. global $_configuration, $htmlHeadXtra;
  662. if (preg_match('/^local_/', $component)) {
  663. $component = str_replace('local_', '', $component);
  664. $path = 'local/';
  665. } else {
  666. $path = 'plugin/';
  667. }
  668. // Secure the postslashing of the roots.
  669. $root_web = $_configuration['root_web'].'/';
  670. $root_web = preg_replace('#//$#', '/', $root_web);
  671. $str = '<link rel="stylesheet" type="text/css" href="'.$root_web.$path.$component.'/'.$file.'.css" />'."\n";
  672. if ($return === 'head') {
  673. $htmlHeadXtra[] = $str;
  674. }
  675. if ($return) {
  676. return $str;
  677. }
  678. echo $str;
  679. }
  680. /**
  681. * @param string $url
  682. *
  683. * @return string
  684. */
  685. public static function getSlugFromUrl($url)
  686. {
  687. $slugify = new Slugify();
  688. $urlInfo = parse_url($url);
  689. if (isset($urlInfo['host'])) {
  690. $path = $urlInfo['path'] != '/' ? '_'.$urlInfo['path'] : '';
  691. return $slugify->slugify($urlInfo['host'].$path);
  692. }
  693. return false;
  694. }
  695. /**
  696. * Check if all settings are complete.
  697. */
  698. public static function checkSettings()
  699. {
  700. $enabled = self::getConfig('vchamilo', 'enable_virtualisation');
  701. if (empty($enabled)) {
  702. api_not_allowed(true, 'Plugin is not enabled');
  703. }
  704. global $virtualChamilo;
  705. if (!isset($virtualChamilo)) {
  706. api_not_allowed(
  707. true,
  708. 'You have to edit the configuration.php. Please check the readme file.'
  709. );
  710. }
  711. $coursePath = self::getConfig('vchamilo', 'course_real_root');
  712. $homePath = self::getConfig('vchamilo', 'home_real_root');
  713. $archivePath = self::getConfig('vchamilo', 'archive_real_root');
  714. $uploadPath = self::getConfig('vchamilo', 'upload_real_root');
  715. $cmdSql = self::getConfig('vchamilo', 'cmd_mysql');
  716. $cmdMySql = self::getConfig('vchamilo', 'cmd_mysqldump');
  717. if (empty($coursePath) || empty($homePath) || empty($uploadPath) || empty($archivePath) || empty($cmdSql) || empty($cmdMySql)) {
  718. api_not_allowed(true, 'You have to complete all plugin settings.');
  719. }
  720. $separator = DIRECTORY_SEPARATOR;
  721. $templatePath = api_get_path(SYS_PATH).'plugin'.$separator.'vchamilo'.$separator.'templates';
  722. $paths = [
  723. $coursePath,
  724. $homePath,
  725. $archivePath,
  726. $uploadPath,
  727. $templatePath,
  728. ];
  729. foreach ($paths as $path) {
  730. $path = trim($path);
  731. if (is_dir($path)) {
  732. if (!is_writable($path)) {
  733. Display::addFlash(
  734. Display::return_message("Directory must have writable permissions: '$path'", 'warning')
  735. );
  736. }
  737. } else {
  738. Display::addFlash(
  739. Display::return_message("Directory doesn't exist: '$path'", 'warning')
  740. );
  741. }
  742. }
  743. }
  744. /**
  745. * @param object $instance
  746. *
  747. * @return bool|\Doctrine\DBAL\Connection
  748. */
  749. public static function getConnectionFromInstance($instance, $getManager = false)
  750. {
  751. $dbParams = [
  752. 'driver' => 'pdo_mysql',
  753. 'host' => $instance->db_host,
  754. 'user' => $instance->db_user,
  755. 'password' => $instance->db_password,
  756. //'dbname' => $instance->main_database,
  757. // Only relevant for pdo_sqlite, specifies the path to the SQLite database.
  758. //'path' => isset($_configuration['db_path']) ? $_configuration['db_path'] : '',
  759. // Only relevant for pdo_mysql, pdo_pgsql, and pdo_oci/oci8,
  760. //'port' => isset($_configuration['db_port']) ? $_configuration['db_port'] : '',
  761. ];
  762. if (!empty($instance->main_database)) {
  763. $dbParams['dbname'] = $instance->main_database;
  764. }
  765. try {
  766. $database = new \Database();
  767. $manager = $database->connect(
  768. $dbParams,
  769. api_get_configuration_value('root_sys'),
  770. api_get_configuration_value('root_sys'),
  771. false,
  772. true
  773. );
  774. if ($getManager) {
  775. return $manager;
  776. }
  777. return $manager->getConnection();
  778. } catch (Exception $e) {
  779. error_log($e->getMessage());
  780. }
  781. return false;
  782. }
  783. /**
  784. * @param $data
  785. */
  786. public static function addInstance($data)
  787. {
  788. if (isset($data->what)) {
  789. unset($data->what);
  790. }
  791. if (isset($data->submitbutton)) {
  792. unset($data->submitbutton);
  793. }
  794. if (isset($data->id)) {
  795. unset($data->id);
  796. }
  797. if (isset($data->vid)) {
  798. unset($data->vid);
  799. }
  800. if (isset($data->testconnection)) {
  801. unset($data->testconnection);
  802. }
  803. if (isset($data->testdatapath)) {
  804. unset($data->testdatapath);
  805. }
  806. $registeronly = $data->registeronly;
  807. unset($data->registeronly);
  808. $data->lastcron = 0;
  809. $data->lastcrongap = 0;
  810. $data->croncount = 0;
  811. if (isset($data->template) && !empty($data->template)) {
  812. $template = $data->template;
  813. } else {
  814. $template = '';
  815. }
  816. $mainDatabase = api_get_configuration_value('main_database');
  817. if ($mainDatabase == $data->main_database) {
  818. Display::addFlash(
  819. Display::return_message('You cannot use the same database as the chamilo master', 'error')
  820. );
  821. return;
  822. }
  823. $databaseName = $data->main_database;
  824. $data->main_database = '';
  825. $connection = self::getConnectionFromInstance($data);
  826. $data->main_database = $databaseName;
  827. if (!$connection) {
  828. Display::addFlash(
  829. Display::return_message(
  830. 'Cannot connect to database with params: '.print_r($data, 1),
  831. 'error'
  832. )
  833. );
  834. return;
  835. }
  836. $data->root_web = api_add_trailing_slash($data->root_web);
  837. $data->archive_url = api_add_trailing_slash($data->archive_url);
  838. $data->home_url = api_add_trailing_slash($data->home_url);
  839. $data->upload_url = api_add_trailing_slash($data->upload_url);
  840. $data->course_url = api_add_trailing_slash($data->course_url);
  841. if (substr($data->root_web, 0, 4) != 'http') {
  842. $data->root_web = api_get_protocol().'://'.$data->root_web;
  843. }
  844. self::ctrace('Registering: '.$data->root_web);
  845. $tablename = Database::get_main_table('vchamilo');
  846. $sql = "SELECT * FROM $tablename
  847. WHERE root_web = '".Database::escape_string($data->root_web)."'";
  848. $result = Database::query($sql);
  849. if (Database::num_rows($result)) {
  850. Database::update($tablename, $data, ['root_web = ?' => $data->root_web]);
  851. $virtualInfo = Database::fetch_array($result);
  852. $slug = $virtualInfo['slug'];
  853. } else {
  854. $slug = $data->slug = self::getSlugFromUrl($data->root_web);
  855. if (empty($slug)) {
  856. Display::addFlash(
  857. Display::return_message('Cannot create slug from url: '.$data->root_web, 'error')
  858. );
  859. return;
  860. }
  861. Database::insert($tablename, (array) $data);
  862. }
  863. if ($registeronly) {
  864. // Stop it now.
  865. self::ctrace('Registering only. out.');
  866. self::redirect(api_get_path(WEB_PLUGIN_PATH).'vchamilo/views/manage.php');
  867. }
  868. // or we continue with physical creation
  869. self::createDirsFromSlug($slug);
  870. if (!$template) {
  871. // Create empty database for install
  872. self::ctrace("Creating database");
  873. self::createDatabase($data);
  874. } else {
  875. // Deploy template database
  876. self::ctrace("Creating databases from template '$template'");
  877. self::createDatabase($data);
  878. self::ctrace("Loading data template '$template'");
  879. self::loadDbTemplate($data, $template);
  880. self::ctrace("Coying files from template '$template'");
  881. self::loadFilesFromTemplate($data, $template);
  882. }
  883. // pluging in site name institution
  884. $settingstable = $data->main_database.'.settings_current';
  885. $accessurltable = $data->main_database.'.access_url';
  886. $sitename = Database::escape_string($data->sitename);
  887. $institution = Database::escape_string($data->institution);
  888. $sqls[] = "UPDATE {$settingstable} SET selected_value = '{$sitename}'
  889. WHERE variable = 'siteName' AND category = 'Platform' ";
  890. $sqls[] = "UPDATE {$settingstable} SET selected_value = '{$institution}'
  891. WHERE variable = 'institution' AND category = 'Platform' ";
  892. $sqls[] = "UPDATE {$accessurltable} SET url = '{$data->root_web}' WHERE id = '1' ";
  893. foreach ($sqls as $sql) {
  894. Database::query($sql);
  895. }
  896. self::ctrace("Finished");
  897. }
  898. /**
  899. * @param stdClass $data
  900. * @param string $fromVersion
  901. */
  902. public static function importInstance($data, $fromVersion)
  903. {
  904. if (isset($data->what)) {
  905. unset($data->what);
  906. }
  907. if (isset($data->submitbutton)) {
  908. unset($data->submitbutton);
  909. }
  910. if (isset($data->id)) {
  911. unset($data->id);
  912. }
  913. if (isset($data->vid)) {
  914. unset($data->vid);
  915. }
  916. if (isset($data->testconnection)) {
  917. unset($data->testconnection);
  918. }
  919. if (isset($data->testdatapath)) {
  920. unset($data->testdatapath);
  921. }
  922. $fromCoursePath = $data->course_path;
  923. $fromHomePath = $data->home_path;
  924. $fromUploadPath = $data->upload_path;
  925. unset($data->course_path);
  926. unset($data->home_path);
  927. unset($data->upload_path);
  928. $newDatabase = clone $data;
  929. $newDatabase->main_database = $newDatabase->import_to_main_database;
  930. $newDatabase->db_user = $newDatabase->import_to_db_user;
  931. $newDatabase->db_password = $newDatabase->import_to_db_password;
  932. $newDatabase->db_host = $newDatabase->import_to_db_host;
  933. unset($newDatabase->import_to_main_database);
  934. unset($newDatabase->import_to_db_user);
  935. unset($newDatabase->import_to_db_password);
  936. unset($newDatabase->import_to_db_host);
  937. unset($data->import_to_main_database);
  938. unset($data->import_to_db_user);
  939. unset($data->import_to_db_password);
  940. unset($data->import_to_db_host);
  941. $data->lastcron = 0;
  942. $data->lastcrongap = 0;
  943. $data->croncount = 0;
  944. $mainDatabase = api_get_configuration_value('main_database');
  945. if ($mainDatabase == $data->main_database) {
  946. Display::addFlash(
  947. Display::return_message('You cannot use the same database as the chamilo master', 'error')
  948. );
  949. return false;
  950. }
  951. self::ctrace('Registering: '.$data->root_web);
  952. $table = Database::get_main_table('vchamilo');
  953. $sql = "SELECT * FROM $table
  954. WHERE root_web = '".Database::escape_string($data->root_web)."'";
  955. $result = Database::query($sql);
  956. $id = null;
  957. if (Database::num_rows($result)) {
  958. Display::addFlash(
  959. Display::return_message('Instance was already added: '.$data->root_web, 'error')
  960. );
  961. return false;
  962. } else {
  963. /** @var EntityManager $em */
  964. $em = self::getConnectionFromInstance($data, true);
  965. if ($em) {
  966. $connection = $em->getConnection();
  967. $statement = $connection->query('SELECT * FROM settings_current');
  968. $settings = $statement->fetchAll();
  969. $settings = array_column(
  970. $settings,
  971. 'selected_value',
  972. 'variable'
  973. );
  974. $institution = $settings['Institution'];
  975. $siteName = $settings['siteName'];
  976. $newDatabase->sitename = $siteName;
  977. $newDatabase->institution = $institution;
  978. $slug = $newDatabase->slug = $data->slug = self::getSlugFromUrl($data->root_web);
  979. $id = Database::insert($table, (array) $newDatabase);
  980. }
  981. }
  982. if (!$id) {
  983. // Show data detail to help debug
  984. //var_dump($data);
  985. throw new Exception('New/Imported instance was not registered - edit '.__FILE__.' on line '.__LINE__.'to var_dump');
  986. }
  987. if (empty($slug)) {
  988. throw new Exception('Slug is empty');
  989. }
  990. self::createDirsFromSlug($slug);
  991. $databaseCreated = self::createDatabase($newDatabase);
  992. if (!$databaseCreated) {
  993. Display::addFlash(
  994. Display::return_message('Error while creating a DB', 'error')
  995. );
  996. return false;
  997. }
  998. $coursePath = self::getConfig('vchamilo', 'course_real_root').'/'.$slug;
  999. $homePath = self::getConfig('vchamilo', 'home_real_root').'/'.$slug;
  1000. $uploadPath = self::getConfig('vchamilo', 'upload_real_root').'/'.$slug;
  1001. $dumpFile = api_get_path(SYS_ARCHIVE_PATH).uniqid($data->main_database.'_dump_', true).'.sql';
  1002. self::ctrace('Create backup from "'.$data->main_database.'" here: '.$dumpFile.' ');
  1003. self::backupDatabase($data, $dumpFile);
  1004. $sqlcmd = self::getDatabaseDumpCmd($newDatabase);
  1005. $sqlcmd = str_replace('%DATABASE%', $newDatabase->main_database, $sqlcmd);
  1006. $import = $sqlcmd.$dumpFile;
  1007. // Execute the command.
  1008. if (!defined('CLI_SCRIPT')) {
  1009. putenv('LANG=en_US.utf-8');
  1010. }
  1011. // ensure utf8 is correctly handled by php exec()
  1012. // @see http://stackoverflow.com/questions/10028925/call-a-program-via-shell-exec-with-utf-8-text-input
  1013. $result = exec($import, $output, $return);
  1014. self::ctrace('Restore backup here "'.$newDatabase->main_database.'" : <br />'.$import.' ');
  1015. self::ctrace($result);
  1016. $command = new \Chash\Command\Installation\UpgradeDatabaseCommand();
  1017. // Creates the helper set
  1018. $helperSet = \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($em);
  1019. $helpers = [
  1020. 'configuration' => new Chash\Helpers\ConfigurationHelper(),
  1021. 'dialog' => new \Symfony\Component\Console\Helper\QuestionHelper(),
  1022. ];
  1023. foreach ($helpers as $name => $helper) {
  1024. $helperSet->set($helper, $name);
  1025. }
  1026. $command->setHelperSet($helperSet);
  1027. $tmpFile = tmpfile();
  1028. $outputStream = new \Symfony\Component\Console\Output\BufferedOutput($tmpFile);
  1029. $arguments = [
  1030. 'from-version' => $fromVersion, // @todo change value
  1031. 'to-version' => '1.11.x',
  1032. 'host' => $newDatabase->db_host,
  1033. 'username' => $newDatabase->db_user,
  1034. 'password' => $newDatabase->db_password,
  1035. 'db_name' => $newDatabase->main_database,
  1036. 'root_sys' => api_get_configuration_value('root_sys'),
  1037. ];
  1038. $input = new ArrayInput($arguments);
  1039. $command->run($input, $outputStream);
  1040. error_log($outputStream->fetch());
  1041. if (file_exists($dumpFile)) {
  1042. unlink($dumpFile);
  1043. }
  1044. // Course
  1045. self::ctrace("Copy from '$fromCoursePath' to backup '$coursePath' ");
  1046. copyDirTo(
  1047. self::chopLastSlash($fromCoursePath),
  1048. self::chopLastSlash($coursePath),
  1049. false
  1050. );
  1051. // Home
  1052. self::ctrace("Copy from '$fromHomePath' to backup '$homePath' ");
  1053. copyDirTo(
  1054. self::chopLastSlash($fromHomePath),
  1055. self::chopLastSlash($homePath),
  1056. false
  1057. );
  1058. // Upload
  1059. self::ctrace("Copy from '$fromUploadPath' to backup '$uploadPath' ");
  1060. copyDirTo(
  1061. self::chopLastSlash($fromUploadPath),
  1062. self::chopLastSlash($uploadPath),
  1063. false
  1064. );
  1065. self::ctrace("Finished");
  1066. }
  1067. /**
  1068. * @param string $slug
  1069. *
  1070. * @return string
  1071. */
  1072. public static function createDirsFromSlug($slug)
  1073. {
  1074. // We continue with physical creation
  1075. // Create course directory for operations.
  1076. // this is very important here (DO NOT USE api_get_path() !!) because storage may be remotely located
  1077. $absAlternateCourse = self::getConfig('vchamilo', 'course_real_root');
  1078. $courseDir = $absAlternateCourse.'/'.$slug;
  1079. $mode = api_get_permissions_for_new_directories();
  1080. if (!is_dir($courseDir)) {
  1081. self::ctrace("Creating physical course dir in $courseDir");
  1082. mkdir($courseDir, $mode, true);
  1083. // initiate default index
  1084. $indexFile = $courseDir.'/index.html';
  1085. if ($indexFile) {
  1086. file_put_contents($indexFile, self::getDefaultCourseIndexFragment());
  1087. }
  1088. $htaccessFile = $courseDir.'/.htaccess';
  1089. if ($htaccessFile) {
  1090. file_put_contents($htaccessFile, self::getHtaccessFragment($slug));
  1091. }
  1092. }
  1093. $absAlternateHome = self::getConfig('vchamilo', 'home_real_root');
  1094. $absAlternateArchive = self::getConfig('vchamilo', 'archive_real_root');
  1095. $absAlternateUpload = self::getConfig('vchamilo', 'upload_real_root');
  1096. // absalternatehome is a vchamilo config setting that tells where the
  1097. // real physical storage for home pages are.
  1098. $homeDir = $absAlternateHome.'/'.$slug;
  1099. $archiveDir = $absAlternateArchive.'/'.$slug;
  1100. $uploadDir = $absAlternateUpload.'/'.$slug;
  1101. $dirs = [
  1102. $homeDir,
  1103. $archiveDir,
  1104. $uploadDir,
  1105. ];
  1106. foreach ($dirs as $dir) {
  1107. self::ctrace("Making dir as $dir");
  1108. if (!is_dir($dir)) {
  1109. if (!mkdir($dir, $mode, true)) {
  1110. self::ctrace("Error creating dir $dir \n");
  1111. }
  1112. }
  1113. }
  1114. }
  1115. /**
  1116. * @param $id
  1117. *
  1118. * @return array|mixed
  1119. */
  1120. public static function getInstance($id)
  1121. {
  1122. $vhost = new stdClass();
  1123. if ($id) {
  1124. $id = (int) $id;
  1125. $sql = "SELECT * FROM vchamilo WHERE id = $id";
  1126. $result = Database::query($sql);
  1127. $vhost = (object) Database::fetch_array($result, 'ASSOC');
  1128. }
  1129. return $vhost;
  1130. }
  1131. /**
  1132. * @param stdClass $instance
  1133. *
  1134. * @return bool|string returns the original version of the app
  1135. */
  1136. public static function canBeUpgraded($instance)
  1137. {
  1138. $connection = self::getConnectionFromInstance($instance);
  1139. if ($connection) {
  1140. $sql = 'SELECT * FROM settings_current WHERE variable = "chamilo_database_version"';
  1141. $statement = $connection->query($sql);
  1142. $settings = $statement->fetchAll();
  1143. $settings = array_column($settings, 'selected_value', 'variable');
  1144. $version = $settings['chamilo_database_version'];
  1145. $versionParts = explode('.', $version);
  1146. $version = implode('.', [$versionParts[0], $versionParts[1], '0']);
  1147. $currentVersion = api_get_setting('chamilo_database_version');
  1148. $versionParts = explode('.', $currentVersion);
  1149. $currentVersion = implode(
  1150. '.',
  1151. [$versionParts[0], $versionParts[1], '0']
  1152. );
  1153. if (version_compare($version, $currentVersion, '<')) {
  1154. return $version;
  1155. }
  1156. }
  1157. return false;
  1158. }
  1159. /**
  1160. * @return array
  1161. */
  1162. public static function getEncryptList()
  1163. {
  1164. $encryptList = [
  1165. 'bcrypt',
  1166. 'sha1',
  1167. 'md5',
  1168. 'none',
  1169. ];
  1170. return array_combine($encryptList, $encryptList);
  1171. }
  1172. }