Virtual.php 45 KB

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