Virtual.php 46 KB

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