PageRenderTime 31ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/administrator/components/com_kunena/install/model.php

https://github.com/viollarr/alab
PHP | 1799 lines | 1455 code | 192 blank | 152 comment | 351 complexity | ccfd640f572a2d49bd28d4ac7d352181 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-2.0, AGPL-3.0, Apache-2.0, BSD-3-Clause, GPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * @version $Id: install.php 1244 2009-12-02 04:10:31Z mahagr$
  4. * @package Kunena
  5. * @subpackage com_kunena
  6. * @copyright Copyright (C) 2008 - 2009 Kunena Team. All rights reserved..
  7. * @license GNU General Public License <http://www.gnu.org/copyleft/gpl.html>
  8. * @link http://www.kunena.org
  9. */
  10. //
  11. // Dont allow direct linking
  12. defined ( '_JEXEC' ) or die ( 'Restricted access' );
  13. // Minimum version requirements
  14. DEFINE('KUNENA_MIN_PHP', '5.2.3');
  15. DEFINE('KUNENA_MIN_MYSQL', '4.1.19');
  16. DEFINE ( 'KUNENA_MIN_JOOMLA15', '1.5.20' );
  17. DEFINE ( 'KUNENA_MIN_JOOMLA16', '1.6.4' );
  18. DEFINE ( 'KUNENA_MIN_JOOMLA17', '1.7.0' );
  19. jimport ( 'joomla.application.component.model' );
  20. jimport ( 'joomla.filesystem.folder' );
  21. jimport ( 'joomla.filesystem.file' );
  22. jimport ( 'joomla.filesystem.path' );
  23. jimport ( 'joomla.filesystem.archive' );
  24. jimport ( 'joomla.installer.installer' );
  25. require_once JPATH_ADMINISTRATOR . '/components/com_kunena/api.php';
  26. /**
  27. * Install Model for Kunena
  28. *
  29. * @package Kunena
  30. * @subpackage com_kunena
  31. * @since 1.6
  32. */
  33. class KunenaModelInstall extends JModel {
  34. /**
  35. * Flag to indicate model state initialization.
  36. *
  37. * @var boolean
  38. * @since 1.6
  39. */
  40. protected $__state_set = false;
  41. protected $_req = false;
  42. protected $_versionprefix = false;
  43. protected $_installed = array();
  44. protected $_versions = array();
  45. protected $_action = false;
  46. protected $_errormsg = null;
  47. protected $_versiontablearray = null;
  48. protected $_versionarray = null;
  49. public $steps = null;
  50. public function __construct() {
  51. parent::__construct ();
  52. $this->db = JFactory::getDBO ();
  53. ignore_user_abort ( true );
  54. $this->setState ( 'default_max_time', @ini_get ( 'max_execution_time' ) );
  55. @set_time_limit ( 300 );
  56. $this->setState ( 'max_time', @ini_get ( 'max_execution_time' ) );
  57. $this->_versiontablearray = array (array ('prefix' => 'kunena_', 'table' => 'kunena_version' ), array ('prefix' => 'fb_', 'table' => 'fb_version' ) );
  58. $this->_kVersions = array (
  59. array ('component' => null, 'prefix' => null, 'version' => null, 'date' => null ) );
  60. $this->_fbVersions = array (
  61. array ('component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.4', 'date' => '2007-12-23', 'table' => 'fb_sessions', 'column' => 'currvisit' ),
  62. array ('component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.3', 'date' => '2007-09-04', 'table' => 'fb_categories', 'column' => 'headerdesc' ),
  63. array ('component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.2', 'date' => '2007-08-03', 'table' => 'fb_users', 'column' => 'rank' ),
  64. array ('component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.1', 'date' => '2007-05-20', 'table' => 'fb_users', 'column' => 'uhits' ),
  65. array ('component' => 'FireBoard', 'prefix' => 'fb_', 'version' => '1.0.0', 'date' => '2007-04-15', 'table' => 'fb_messages' ),
  66. array ('component' => null, 'prefix' => null, 'version' => null, 'date' => null ) );
  67. $this->_sbVersions = array (
  68. array('component'=>'JoomlaBoard','prefix'=> 'sb_', 'version' =>'v1.0.5', 'date' => '0000-00-00', 'table' => 'sb_messages'),
  69. array ('component' => null, 'prefix' => null, 'version' => null, 'date' => null ) );
  70. $this->steps = array (
  71. array ('step' => '', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_INSTALL') ),
  72. array ('step' => 'Prepare', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_PREPARE') ),
  73. array ('step' => 'Extract', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_EXTRACT') ),
  74. array ('step' => 'Language', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_LANGUAGES') ),
  75. array ('step' => 'Plugins', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_PLUGINS') ),
  76. array ('step' => 'Database', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_DATABASE') ),
  77. array ('step' => 'Finish', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_FINISH') ),
  78. array ('step' => '', 'menu' => JText::_('COM_KUNENA_INSTALL_STEP_COMPLETE') ) );
  79. }
  80. /**
  81. * Installer object destructor
  82. *
  83. * @access public
  84. * @since 1.6
  85. */
  86. public function __destruct() {
  87. }
  88. /**
  89. * Installer cleanup after installation
  90. *
  91. * @access public
  92. * @since 1.6
  93. */
  94. public function cleanup() {
  95. }
  96. public function getModel() {
  97. return $this;
  98. }
  99. /**
  100. * Overridden method to get model state variables.
  101. *
  102. * @param string Optional parameter name.
  103. * @param mixed The default value to use if no state property exists by name.
  104. * @return object The property where specified, the state object where omitted.
  105. * @since 1.6
  106. */
  107. public function getState($property = null, $default = null) {
  108. // if the model state is uninitialized lets set some values we will need from the request.
  109. if ($this->__state_set === false) {
  110. $app = JFactory::getApplication ();
  111. $this->setState ( 'action', $step = $app->getUserState ( 'com_kunena.install.action', null ) );
  112. $this->setState ( 'step', $step = $app->getUserState ( 'com_kunena.install.step', 0 ) );
  113. $this->setState ( 'task', $task = $app->getUserState ( 'com_kunena.install.task', 0 ) );
  114. $this->setState ( 'version', $task = $app->getUserState ( 'com_kunena.install.version', null ) );
  115. if ($step == 0)
  116. $app->setUserState ( 'com_kunena.install.status', array () );
  117. $this->setState ( 'status', $app->getUserState ( 'com_kunena.install.status' ) );
  118. $this->__state_set = true;
  119. }
  120. $value = parent::getState ( $property );
  121. return (is_null ( $value ) ? $default : $value);
  122. }
  123. public function getStatus() {
  124. return $this->getState ( 'status', array() );
  125. }
  126. public function getAction() {
  127. return $this->getState ( 'action', null );
  128. }
  129. public function getStep() {
  130. return $this->getState ( 'step', 0 );
  131. }
  132. public function getTask() {
  133. return $this->getState ( 'task', 0 );
  134. }
  135. public function getVersion() {
  136. return $this->getState ( 'version', null );
  137. }
  138. public function setAction($action) {
  139. $this->setState ( 'action', $action );
  140. $app = JFactory::getApplication ();
  141. $app->setUserState ( 'com_kunena.install.action', $action );
  142. }
  143. public function setStep($step) {
  144. $this->setState ( 'step', ( int ) $step );
  145. $app = JFactory::getApplication ();
  146. $app->setUserState ( 'com_kunena.install.step', ( int ) $step );
  147. $this->setTask(0);
  148. }
  149. public function setTask($task) {
  150. $this->setState ( 'task', ( int ) $task );
  151. $app = JFactory::getApplication ();
  152. $app->setUserState ( 'com_kunena.install.task', ( int ) $task );
  153. }
  154. public function setVersion($version) {
  155. $this->setState ( 'version', $version );
  156. $app = JFactory::getApplication ();
  157. $app->setUserState ( 'com_kunena.install.version', $version );
  158. }
  159. public function addStatus($task, $result = false, $msg = '', $id = null) {
  160. $status = $this->getState ( 'status' );
  161. $step = $this->getStep();
  162. if ($id === null) {
  163. $status [] = array ('step' => $step, 'task'=>$task, 'success' => $result, 'msg' => $msg );
  164. } else {
  165. unset($status [$id]);
  166. $status [$id] = array ('step' => $step, 'task'=>$task, 'success' => $result, 'msg' => $msg );
  167. }
  168. $this->setState ( 'status', $status );
  169. $app = JFactory::getApplication ();
  170. $app->setUserState ( 'com_kunena.install.status', $status );
  171. }
  172. function getError() {
  173. $status = $this->getState ( 'status', array () );
  174. $error = 0;
  175. foreach ( $status as $cur ) {
  176. $error = ! $cur ['success'];
  177. if ($error)
  178. break;
  179. }
  180. return $error;
  181. }
  182. public function getSteps() {
  183. return $this->steps;
  184. }
  185. public function extract($path, $filename, $dest = null, $silent = false) {
  186. if (! $dest)
  187. $dest = $path;
  188. $file = $path . '/' . $filename;
  189. $text = '';
  190. $success = true;
  191. if (file_exists ( $file )) {
  192. if (!JFolder::exists($dest)) {
  193. $success = JFolder::create($dest);
  194. }
  195. if ($success) $success = JArchive::extract ( $file, $dest );
  196. if (! $success) {
  197. $text .= JText::sprintf('COM_KUNENA_INSTALL_EXTRACT_FAILED', $file);
  198. $text .= $this->_getJoomlaArchiveError($file);
  199. }
  200. } else {
  201. $text .= JText::sprintf('COM_KUNENA_INSTALL_EXTRACT_MISSING', $file);
  202. }
  203. if ($success && !$silent)
  204. $this->addStatus ( JText::sprintf('COM_KUNENA_INSTALL_EXTRACT_STATUS', $filename), $success, $text );
  205. return $success;
  206. }
  207. function installLanguage($tag, $name = '') {
  208. $exists = false;
  209. $success = true;
  210. $destinations = array(
  211. 'site'=>JPATH_SITE . '/components/com_kunena',
  212. 'admin'=>JPATH_ADMINISTRATOR . '/components/com_kunena'
  213. );
  214. foreach ($destinations as $key=>$dest) {
  215. if ($success != true) continue;
  216. $installdir = "{$dest}/language/{$tag}";
  217. // If we are installing Kunena from archive, we need to unzip language file
  218. if (!Kunena::isSVN() && JFolder::exists(KPATH_ADMIN . '/archive')) {
  219. $path = JPATH_ADMINISTRATOR . '/components/com_kunena/archive';
  220. $version = Kunena::version();
  221. $file = "com_kunena.{$tag}.{$key}_v{$version}".file_get_contents("{$path}/fileformat");
  222. if (file_exists("$path/$file")) {
  223. $success = $this->extract ( $path, $file, $installdir, true );
  224. }
  225. }
  226. // Install language from dest/language/xx-XX
  227. if ($success == true && is_dir($installdir)) {
  228. $exists = true;
  229. if (version_compare(JVERSION, '1.6', '>')) {
  230. // Joomla 1.6+
  231. // Older versions installed language files into main folders
  232. // Those files need to be removed to bring language up to date!
  233. jimport('joomla.filesystem.folder');
  234. $files = JFolder::files($installdir, '\.ini$');
  235. foreach ($files as $filename) {
  236. if (file_exists(JPATH_SITE."/language/{$tag}/{$filename}")) JFile::delete(JPATH_SITE."/language/{$tag}/{$filename}");
  237. if (file_exists(JPATH_ADMINISTRATOR."/language/{$tag}/{$filename}")) JFile::delete(JPATH_ADMINISTRATOR."/language/{$tag}/{$filename}");
  238. }
  239. } else {
  240. // Joomla 1.5
  241. // Use installer to get files into the right place
  242. $installer = new JInstaller ( );
  243. if ($installer->install ( $installdir )) {
  244. $success = true;
  245. } else {
  246. $success = -1;
  247. }
  248. }
  249. }
  250. }
  251. if ($exists && $name) $this->addStatus ( JText::sprintf('COM_KUNENA_INSTALL_LANGUAGE', $name), $success);
  252. return $success;
  253. }
  254. function publishPlugin($folder, $name, $enable = 1) {
  255. if (KUNENA_JOOMLA_COMPAT == '1.5') {
  256. $query = "UPDATE #__plugins SET published='{$enable}' WHERE folder='{$folder}' AND element='{$name}'";
  257. } else {
  258. $query = "UPDATE #__extensions SET enabled='{$enable}' WHERE type='plugin' AND folder='{$folder}' AND element='{$name}'";
  259. }
  260. $this->db->setQuery ( $query );
  261. $this->db->query ();
  262. if ($this->db->getErrorNum ())
  263. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  264. return true;
  265. }
  266. function installPlugin($path, $file, $name) {
  267. $success = false;
  268. $dest = JPATH_ROOT.'/tmp/kinstall_plugin';
  269. $query = "SELECT * FROM #__plugins WHERE element='$name'";
  270. $this->db->setQuery ( $query );
  271. $plugin = $this->db->loadObject ();
  272. if (is_object($plugin)) {
  273. $installer = new JInstaller ( );
  274. $installer->uninstall ( 'plugin', $plugin->id );
  275. }
  276. $this->extract ( $path, $file, $dest );
  277. $installer = new JInstaller ( );
  278. if ($installer->install ( $dest )) {
  279. // TODO: fix this when needed again
  280. $success = $this->publishPlugin('', $name);
  281. }
  282. JFolder::delete($dest);
  283. $this->addStatus ( JText::sprintf('COM_KUNENA_INSTALL_PLUGIN_STATUS', $name), $success);
  284. }
  285. function uninstallPlugin($folder, $name) {
  286. if (KUNENA_JOOMLA_COMPAT == '1.5') {
  287. $query = "SELECT id FROM #__plugins WHERE folder='{$folder}' AND element='{$name}'";
  288. } else {
  289. $query = "SELECT extension_id FROM #__extensions WHERE type='plugin' AND folder='{$folder}' AND element='{$name}'";
  290. }
  291. $this->db->setQuery ( $query );
  292. $pluginid = $this->db->loadResult ();
  293. if ($pluginid) {
  294. $installer = new JInstaller ( );
  295. $installer->uninstall ( 'plugin', $pluginid );
  296. }
  297. }
  298. function installSystemPlugin() {
  299. $src = KPATH_ADMIN . '/install/system';
  300. $dest = JPATH_ROOT.'/tmp/kinstall_plugin';
  301. JFolder::copy($src, $dest);
  302. // We need to have only one manifest which is named as kunena.xml
  303. if (KUNENA_JOOMLA_COMPAT == '1.5') {
  304. JFile::delete($dest.'/kunena.j16.xml');
  305. } else {
  306. JFile::delete($dest.'/kunena.xml');
  307. JFile::move($dest.'/kunena.j16.xml', $dest.'/kunena.xml');
  308. }
  309. $installer = new JInstaller ( );
  310. if ($installer->install ( $dest )) {
  311. $success = $this->publishPlugin('system', 'kunena');
  312. }
  313. JFolder::delete($dest);
  314. $this->addStatus ( JText::sprintf('COM_KUNENA_INSTALL_PLUGIN_STATUS', 'System - Kunena'), $success);
  315. }
  316. public function stepPrepare() {
  317. $results = array ();
  318. $this->setVersion(null);
  319. $this->setAvatarStatus();
  320. $this->setAttachmentStatus();
  321. $this->addStatus ( JText::_('COM_KUNENA_INSTALL_STEP_PREPARE'), true );
  322. $action = $this->getAction();
  323. if ($action == 'install' || $action == 'migrate') {
  324. // Let's start from clean database
  325. $this->deleteTables('kunena_');
  326. $this->deleteMenu();
  327. }
  328. $installed = $this->getDetectVersions();
  329. if ($action == 'migrate' && $installed['fb']->component) {
  330. $version = $installed['fb'];
  331. $results [] = $this->migrateTable ( strtolower($version->prefix), strtolower($version->prefix) . 'version', 'kunena_version' );
  332. } else {
  333. $version = $installed['kunena'];
  334. }
  335. $this->setVersion($version);
  336. require_once KPATH_ADMIN.'/install/schema.php';
  337. $schema = new KunenaModelSchema();
  338. $results[] = $schema->updateSchemaTable('kunena_version');
  339. // Insert data from the old version, if it does not exist in the version table
  340. if ($version->id == 0 && $version->component) {
  341. $this->insertVersionData ( $version->version, $version->versiondate, $version->build, $version->versionname, null );
  342. }
  343. foreach ( $results as $i => $r )
  344. if ($r)
  345. $this->addStatus ( ucfirst($r ['action']) . ' ' . $r ['name'], true );
  346. $this->insertVersion ( 'migrateDatabase' );
  347. if (! $this->getError ())
  348. $this->setStep ( $this->getStep()+1 );
  349. $this->checkTimeout(true);
  350. }
  351. public function stepLanguage() {
  352. $lang = JFactory::getLanguage();
  353. $languages = $lang->getKnownLanguages();
  354. foreach ($languages as $language) {
  355. $this->installLanguage($language['tag'], $language['name']);
  356. }
  357. if (! $this->getError ())
  358. $this->setStep($this->getStep()+1);
  359. }
  360. public function stepExtract() {
  361. $path = JPATH_ADMINISTRATOR . '/components/com_kunena/archive';
  362. if (!is_file("{$path}/fileformat")) {
  363. $this->setStep($this->getStep()+1);
  364. return;
  365. }
  366. $ext = file_get_contents("{$path}/fileformat");
  367. static $files = array(
  368. array('name'=>'com_kunena-admin', 'dest'=>KPATH_ADMIN),
  369. array('name'=>'com_kunena-site', 'dest'=>KPATH_SITE),
  370. array('name'=>'com_kunena-media', 'dest'=>KPATH_MEDIA)
  371. );
  372. $task = $this->getTask();
  373. if (isset($files[$task])) {
  374. $file = $files[$task];
  375. if (file_exists ( $path . '/' . $file['name'] . $ext )) {
  376. $this->extract ( $path, $file['name'] . $ext, $file['dest'], Kunena::isSVN() );
  377. }
  378. $this->setTask($task+1);
  379. } else {
  380. if (! $this->getError ())
  381. $this->setStep($this->getStep()+1);
  382. }
  383. }
  384. public function stepPlugins() {
  385. $path = JPATH_ADMINISTRATOR . '/components/com_kunena/archive';
  386. $this->installSystemPlugin();
  387. if (! $this->getError ())
  388. $this->setStep ( $this->getStep()+1 );
  389. }
  390. public function stepDatabase() {
  391. $task = $this->getTask();
  392. switch ($task) {
  393. case 0:
  394. if ($this->migrateDatabase ())
  395. $this->setTask($task+1);
  396. break;
  397. case 1:
  398. if ($this->installDatabase ())
  399. $this->setTask($task+1);
  400. break;
  401. case 2:
  402. if ($this->upgradeDatabase ())
  403. $this->setTask($task+1);
  404. break;
  405. case 3:
  406. if ($this->installSampleData ())
  407. $this->setTask($task+1);
  408. break;
  409. case 4:
  410. if ($this->migrateCategoryImages ())
  411. $this->setTask($task+1);
  412. break;
  413. case 5:
  414. if ($this->migrateAvatars ())
  415. $this->setTask($task+1);
  416. break;
  417. case 6:
  418. if ($this->migrateAvatarGalleries ())
  419. $this->setTask($task+1);
  420. break;
  421. case 7:
  422. if ($this->migrateAttachments ())
  423. $this->setTask($task+1);
  424. break;
  425. default:
  426. if (! $this->getError ())
  427. $this->setStep ( $this->getStep()+1 );
  428. }
  429. }
  430. public function stepFinish() {
  431. $entryfiles = array(
  432. array(KPATH_ADMIN, 'api', 'php'),
  433. array(KPATH_ADMIN, 'admin.kunena', 'php'),
  434. array(KPATH_SITE, 'router', 'php'),
  435. array(KPATH_SITE, 'kunena', 'php'),
  436. );
  437. $lang = JFactory::getLanguage();
  438. $lang->load('com_kunena', JPATH_SITE) || $lang->load('com_kunena', KPATH_SITE);
  439. // TODO: remove dependence
  440. require_once (KPATH_ADMIN . '/api.php');
  441. kimport('factory');
  442. require_once (KPATH_SITE . '/class.kunena.php');
  443. $this->createMenu(false);
  444. CKunenaTools::reCountBoards();
  445. foreach ($entryfiles as $fileparts) {
  446. list($path, $filename, $ext) = $fileparts;
  447. if (is_file("{$path}/{$filename}.new.{$ext}")) {
  448. $success = JFile::delete("{$path}/{$filename}.{$ext}");
  449. if (!$success) $this->addStatus ( JText::_('COM_KUNENA_INSTALL_DELETE_STATUS_FAIL')." {$filename}.{$ext}", false, '' );
  450. $success = JFile::move("{$path}/{$filename}.new.{$ext}", "{$path}/{$filename}.{$ext}");
  451. if (!$success) $this->addStatus ( JText::_('COM_KUNENA_INSTALL_RENAMING_FAIL')." {$filename}.new.{$ext}", false, '' );
  452. }
  453. }
  454. if (! $this->getError ()) {
  455. $this->updateVersionState ( '' );
  456. $this->addStatus ( JText::_('COM_KUNENA_INSTALL_SUCCESS'), true, '' );
  457. $this->setStep ( $this->getStep()+1 );
  458. }
  459. }
  460. public function migrateDatabase() {
  461. $version = $this->getVersion();
  462. if (! empty ( $version->prefix )) {
  463. // Migrate all tables from old installation
  464. $app = JFactory::getApplication ();
  465. $state = $app->getUserState ( 'com_kunena.install.dbstate', null );
  466. // First run: find tables that potentially need migration
  467. if ($state === null) {
  468. $state = $this->listTables ( strtolower($version->prefix) );
  469. }
  470. // Handle only first table in the list
  471. $oldtable = array_shift($state);
  472. if ($oldtable) {
  473. $newtable = preg_replace ( '/^' . strtolower($version->prefix) . '/', 'kunena_', $oldtable );
  474. $result = $this->migrateTable ( strtolower($version->prefix), $oldtable, $newtable );
  475. if ($result) {
  476. $this->addStatus ( ucfirst($result ['action']) . ' ' . $result ['name'], true );
  477. }
  478. // Save user state with remaining tables
  479. $app->setUserState ( 'com_kunena.install.dbstate', $state );
  480. // Database migration continues
  481. return false;
  482. } else {
  483. // Reset user state
  484. $this->updateVersionState ( 'installDatabase' );
  485. $app->setUserState ( 'com_kunena.install.dbstate', null );
  486. }
  487. }
  488. // Database migration complete
  489. return true;
  490. }
  491. public function installDatabase() {
  492. static $schema = null;
  493. static $create = null;
  494. static $tables = null;
  495. if ($schema === null) {
  496. // Run only once: get table creation SQL and existing tables
  497. require_once KPATH_ADMIN.'/install/schema.php';
  498. $schema = new KunenaModelSchema();
  499. $create = $schema->getCreateSQL();
  500. $tables = $this->listTables ( 'kunena_', true );
  501. }
  502. $app = JFactory::getApplication ();
  503. $state = $app->getUserState ( 'com_kunena.install.dbstate', null );
  504. // First run: get all tables
  505. if ($state === null) {
  506. $state = array_keys($create);
  507. }
  508. // Handle only first table in the list
  509. $table = array_shift($state);
  510. if ($table) {
  511. $query = $create[$table];
  512. if (!isset($tables[$table])) {
  513. $result = $schema->updateSchemaTable($table);
  514. if ($result) {
  515. $this->addStatus ( ucfirst($result ['action']) . ' ' . $result ['name'], $result ['success'] );
  516. }
  517. }
  518. // Save user state with remaining tables
  519. $app->setUserState ( 'com_kunena.install.dbstate', $state );
  520. // Database install continues
  521. return false;
  522. } else {
  523. // Reset user state
  524. $this->updateVersionState ( 'upgradeDatabase' );
  525. $app->setUserState ( 'com_kunena.install.dbstate', null );
  526. }
  527. // Database install complete
  528. return true;
  529. }
  530. function migrateConfig() {
  531. require_once KPATH_ADMIN.'/api.php';
  532. kimport('factory');
  533. $config = KunenaFactory::getConfig();
  534. $version = $this->getVersion();
  535. if (version_compare ( $version->version, '1.0.4', "<=" ) ) {
  536. $file = JPATH_ADMINISTRATOR . '/components/com_fireboard/fireboard_config.php';
  537. if (is_file($file)) {
  538. require_once $file;
  539. $fbConfig = (array)$fbConfig;
  540. $keys = $config->GetClassVars ();
  541. foreach ($fbConfig as $key=>$value) {
  542. if (isset ( $keys[$key] )) {
  543. if (is_string ( $config->$key )) {
  544. $config->$key = $value;
  545. } else {
  546. $config->$key = (int)$value;
  547. }
  548. }
  549. }
  550. }
  551. }
  552. $config->remove ();
  553. $config->create ();
  554. }
  555. public function upgradeDatabase() {
  556. static $xml = null;
  557. // If there's no version installed, there's nothing to do
  558. $curversion = $this->getVersion();
  559. if (!$curversion->component) return true;
  560. if ($xml === null) {
  561. // Run only once: Get migration SQL from our XML file
  562. $xml = simplexml_load_file(KPATH_ADMIN.'/install/kunena.install.upgrade.xml');
  563. }
  564. $app = JFactory::getApplication ();
  565. $state = $app->getUserState ( 'com_kunena.install.dbstate', null );
  566. // First run: initialize state and migrate configuration
  567. if ($state === null) {
  568. $state = array();
  569. // Migrate configuration from FB <1.0.5, otherwise update it
  570. $this->migrateConfig();
  571. }
  572. // Allow queries to fail
  573. $this->db->debug(0);
  574. $results = array();
  575. foreach ($xml->upgrade[0] as $version) {
  576. // If we have already upgraded to this version, continue to the next one
  577. $vernum = (string) $version['version'];
  578. if (!empty($state[$vernum]))
  579. continue;
  580. // Update state
  581. $state[$vernum] = 1;
  582. if ($version['version'] == '@'.'kunenaversion'.'@') {
  583. $svn = 1;
  584. $vernum = Kunena::version();
  585. }
  586. if(isset($svn) ||
  587. ($version['versiondate'] > $curversion->versiondate) ||
  588. (version_compare(strtolower($version['version']), strtolower($curversion->version), '>')) ||
  589. (version_compare(strtolower($version['version']), strtolower($curversion->version), '==') &&
  590. $version['build'] > $curversion->build)) {
  591. foreach ($version as $action) {
  592. $result = $this->processUpgradeXMLNode($action);
  593. if ($result) $this->addStatus ( $result ['action'] . ' ' . $result ['name'], $result ['success'] );
  594. }
  595. $this->addStatus ( JText::sprintf('COM_KUNENA_INSTALL_VERSION_UPGRADED',$vernum), true, '', 'upgrade' );
  596. // Save user state with remaining tables
  597. $app->setUserState ( 'com_kunena.install.dbstate', $state );
  598. // Database install continues
  599. return false;
  600. }
  601. }
  602. // Reset user state
  603. $this->updateVersionState ( 'InstallSampleData' );
  604. $app->setUserState ( 'com_kunena.install.dbstate', null );
  605. // Database install complete
  606. return true;
  607. }
  608. function processUpgradeXMLNode($action)
  609. {
  610. $result = null;
  611. $nodeName = $action->getName();
  612. $mode = strtolower((string) $action['mode']);
  613. $success = false;
  614. switch($nodeName) {
  615. case 'phpfile':
  616. $filename = $action['name'];
  617. $include = KPATH_ADMIN . "/install/upgrade/$filename.php";
  618. $function = 'kunena_'.strtr($filename, array('.'=>'', '-'=>'_'));
  619. if(file_exists($include)) {
  620. require( $include );
  621. if (is_callable($function)) {
  622. $result = call_user_func($function, $this);
  623. if (is_array($result)) $success = $result['success'];
  624. else $success = true;
  625. }
  626. }
  627. if (!$success && !$result) {
  628. $result = array('action'=>JText::_('COM_KUNENA_INSTALL_INCLUDE_STATUS'), 'name'=>$filename.'.php', 'success'=>$success);
  629. }
  630. break;
  631. case 'query':
  632. $query = (string)$action;
  633. $this->db->setQuery($query);
  634. $this->db->query();
  635. if (!$this->db->getErrorNum()) {
  636. $success = true;
  637. }
  638. if ($action['mode'] == 'silenterror' || !$this->db->getAffectedRows() || $success)
  639. $result = null;
  640. else
  641. $result = array('action'=>'SQL Query: '.$query, 'name'=>'', 'success'=>$success);
  642. break;
  643. default:
  644. $result = array('action'=>'fail', 'name'=>$nodeName, 'success'=>false);
  645. }
  646. return $result;
  647. }
  648. /*
  649. public function upgradeDatabase() {
  650. kimport ( 'models.schema', 'admin' );
  651. $schema = new KunenaModelSchema ();
  652. $results = $schema->updateSchema ();
  653. foreach ( $results as $i => $r )
  654. if ($r)
  655. $this->addStatus ( $r ['action'] . ' ' . $r ['name'], true );
  656. $this->updateVersionState ( 'installSampleData' );
  657. }
  658. */
  659. public function installSampleData() {
  660. require_once ( KPATH_ADMIN.'/install/data/sampledata.php' );
  661. if (installSampleData ())
  662. $this->addStatus ( JText::_('COM_KUNENA_INSTALL_SAMPLEDATA'), true );
  663. return true;
  664. }
  665. protected function setAvatarStatus($stats = null) {
  666. if (!$stats) {
  667. $stats = new stdClass();
  668. $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0;
  669. }
  670. $app = JFactory::getApplication ();
  671. $app->setUserState ( 'com_kunena.install.avatars', $stats );
  672. }
  673. protected function getAvatarStatus() {
  674. $app = JFactory::getApplication ();
  675. $stats = new stdClass();
  676. $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0;
  677. $stats = $app->getUserState ( 'com_kunena.install.avatars', $stats );
  678. return $stats;
  679. }
  680. public function migrateAvatars() {
  681. $app = JFactory::getApplication ();
  682. $stats = $this->getAvatarStatus();
  683. static $dirs = array (
  684. 'media/kunena/avatars',
  685. 'images/fbfiles/avatars',
  686. 'components/com_fireboard/avatars'
  687. );
  688. $query = "SELECT COUNT(*) FROM #__kunena_users
  689. WHERE userid>{$this->db->quote($stats->current)} AND avatar != '' AND avatar NOT LIKE 'gallery/%' AND avatar NOT LIKE 'users/%'";
  690. $this->db->setQuery ( $query );
  691. $count = $this->db->loadResult ();
  692. if ($this->db->getErrorNum ())
  693. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  694. if (!$stats->current && !$count) return true;
  695. $query = "SELECT userid, avatar FROM #__kunena_users
  696. WHERE userid>{$this->db->quote($stats->current)} AND avatar != '' AND avatar NOT LIKE 'gallery/%' AND avatar NOT LIKE 'users/%'";
  697. $this->db->setQuery ( $query, 0, 1023 );
  698. $users = $this->db->loadObjectList ();
  699. if ($this->db->getErrorNum ())
  700. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  701. foreach ($users as $user) {
  702. $userid = $stats->current = $user->userid;
  703. $avatar = $user->avatar;
  704. $count--;
  705. $file = $newfile = '';
  706. foreach ($dirs as $dir) {
  707. if (!JFile::exists(JPATH_ROOT . "/$dir/$avatar")) continue;
  708. $file = JPATH_ROOT . "/$dir/$avatar";
  709. break;
  710. }
  711. $success = false;
  712. if ($file) {
  713. $file = JPath::clean($file, '/');
  714. // Make sure to copy only supported fileformats
  715. $match = preg_match('/\.(gif|jpg|jpeg|png)$/ui', $file, $matches);
  716. if ($match) {
  717. $ext = JString::strtolower($matches[1]);
  718. // Use new format: users/avatar62.jpg
  719. $newfile = "users/avatar{$userid}.{$ext}";
  720. $destpath = (KPATH_MEDIA ."/avatars/{$newfile}");
  721. if (JFile::exists($destpath)) {
  722. $success = true;
  723. } else {
  724. @chmod($file, 0644);
  725. $success = JFile::copy($file, $destpath);
  726. }
  727. if ($success) {
  728. $stats->migrated++;
  729. } else {
  730. $this->addStatus ( "User: {$userid}, Avatar copy failed: {$file} to {$destpath}", true );
  731. $stats->failed++;
  732. }
  733. } else {
  734. $this->addStatus ( "User: {$userid}, Avatar type not supported: {$file}", true );
  735. $stats->failed++;
  736. $success = true;
  737. }
  738. } else {
  739. // $this->addStatus ( "User: {$userid}, Avatar file was not found: {$avatar}", true );
  740. $stats->missing++;
  741. $success = true;
  742. }
  743. if ($success) {
  744. $query = "UPDATE #__kunena_users SET avatar={$this->db->quote($newfile)} WHERE userid={$this->db->quote($userid)}";
  745. $this->db->setQuery ( $query );
  746. $this->db->query ();
  747. if ($this->db->getErrorNum ())
  748. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  749. }
  750. if ($this->checkTimeout()) break;
  751. }
  752. $this->setAvatarStatus($stats);
  753. if ($count) {
  754. $this->addStatus ( JText::sprintf('COM_KUNENA_MIGRATE_AVATARS',$count), true, '', 'avatar' );
  755. } else {
  756. $this->addStatus ( JText::sprintf('COM_KUNENA_MIGRATE_AVATARS_DONE', $stats->migrated, $stats->missing, $stats->failed), true, '', 'avatar' );
  757. }
  758. return !$count;
  759. }
  760. public function migrateAvatarGalleries() {
  761. $action = $this->getAction();
  762. if ($action != 'migrate') return true;
  763. $srcpath = JPATH_ROOT.'/images/fbfiles/avatars/gallery';
  764. $dstpath = KPATH_MEDIA.'/avatars/gallery';
  765. if (JFolder::exists($srcpath)) {
  766. if (!JFolder::delete($dstpath) || !JFolder::copy($srcpath, $dstpath)) {
  767. $this->addStatus ( "Could not copy avatar galleries from $srcpath to $dstpath", true );
  768. } else {
  769. $this->addStatus ( JText::_('COM_KUNENA_MIGRATE_AVATAR_GALLERY'), true );
  770. }
  771. }
  772. return true;
  773. }
  774. public function migrateCategoryImages() {
  775. $action = $this->getAction();
  776. if ($action != 'migrate') return true;
  777. $srcpath = JPATH_ROOT.'/images/fbfiles/category_images';
  778. $dstpath = KPATH_MEDIA.'/category_images';
  779. if (JFolder::exists($srcpath)) {
  780. if (!JFolder::delete($dstpath) || !JFolder::copy($srcpath, $dstpath)) {
  781. $this->addStatus ( "Could not copy category images from $srcpath to $dstpath", true );
  782. } else {
  783. $this->addStatus ( JText::_('COM_KUNENA_MIGRATE_CATEGORY_IMAGES'), true );
  784. }
  785. }
  786. return true;
  787. }
  788. protected function setAttachmentStatus($stats = null) {
  789. if (!$stats) {
  790. $stats = new stdClass();
  791. $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0;
  792. }
  793. $app = JFactory::getApplication ();
  794. $app->setUserState ( 'com_kunena.install.attachments', $stats );
  795. }
  796. protected function getAttachmentStatus() {
  797. $app = JFactory::getApplication ();
  798. $stats = new stdClass();
  799. $stats->current = $stats->migrated = $stats->failed = $stats->missing = 0;
  800. $stats = $app->getUserState ( 'com_kunena.install.attachments', $stats );
  801. return $stats;
  802. }
  803. public function migrateAttachments() {
  804. $app = JFactory::getApplication ();
  805. $stats = $this->getAttachmentStatus();
  806. static $dirs = array (
  807. 'images/fbfiles/attachments',
  808. 'components/com_fireboard/uploaded',
  809. 'media/kunena/attachments/legacy',
  810. );
  811. $query = "SELECT COUNT(*) FROM #__kunena_attachments
  812. WHERE id>{$this->db->quote($stats->current)} AND hash IS NULL";
  813. $this->db->setQuery ( $query );
  814. $count = $this->db->loadResult ();
  815. if ($this->db->getErrorNum ())
  816. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  817. if (!$stats->current && !$count) return true;
  818. $destpath = KPATH_MEDIA . '/attachments/legacy';
  819. if (!JFolder::exists($destpath.'/images')) {
  820. if (!JFolder::create($destpath.'/images')) {
  821. $this->addStatus ( "Could not create directory for legacy attachments in {$destpath}/images", true );
  822. return true;
  823. }
  824. }
  825. if (!JFolder::exists($destpath.'/files')) {
  826. if (!JFolder::create($destpath.'/files')) {
  827. $this->addStatus ( "Could not create directory for legacy attachments in {$destpath}/files", true );
  828. return true;
  829. }
  830. }
  831. $query = "SELECT * FROM #__kunena_attachments
  832. WHERE id>{$this->db->quote($stats->current)} AND hash IS NULL";
  833. $this->db->setQuery ( $query, 0, 251 );
  834. $attachments = $this->db->loadObjectList ();
  835. if ($this->db->getErrorNum ())
  836. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  837. foreach ($attachments as $attachment) {
  838. $stats->current = $attachment->id;
  839. $count--;
  840. if (preg_match('|/images$|', $attachment->folder)) {
  841. $lastpath = 'images';
  842. $attachment->filetype = 'image/'.strtolower($attachment->filetype);
  843. } else if (preg_match('|/files$|', $attachment->folder)) {
  844. $lastpath = 'files';
  845. } else {
  846. // Only process files in legacy locations, either in original folders or manually copied into /media/kunena/attachments/legacy
  847. continue;
  848. }
  849. $file = '';
  850. if (JFile::exists(JPATH_ROOT . "/{$attachment->folder}/{$attachment->filename}")) {
  851. $file = JPATH_ROOT . "/{$attachment->folder}/{$attachment->filename}";
  852. } else {
  853. foreach ($dirs as $dir) {
  854. if (JFile::exists(JPATH_ROOT . "/{$dir}/{$lastpath}/{$attachment->filename}")) {
  855. $file = JPATH_ROOT . "/{$dir}/{$lastpath}/{$attachment->filename}";
  856. break;
  857. }
  858. }
  859. }
  860. $success = false;
  861. if ($file) {
  862. $file = JPath::clean ( $file, '/' );
  863. $destfile = "{$destpath}/{$lastpath}/{$attachment->filename}";
  864. if (JFile::exists ( $destfile )) {
  865. $success = true;
  866. } else {
  867. @chmod ( $file, 0644 );
  868. $success = JFile::copy ( $file, $destfile );
  869. }
  870. if ($success) {
  871. $stats->migrated ++;
  872. } else {
  873. $this->addStatus ( "Attachment copy failed: {$file} to {$destfile}", true );
  874. $stats->failed ++;
  875. }
  876. } else {
  877. // $this->addStatus ( "Attachment file was not found: {$file}", true );
  878. $stats->missing++;
  879. }
  880. if ($success) {
  881. clearstatcache();
  882. $stat = stat($destfile);
  883. $size = (int)$stat['size'];
  884. $hash = md5_file ( $destfile );
  885. $query = "UPDATE #__kunena_attachments SET folder='media/kunena/attachments/legacy/{$lastpath}', size={$this->db->quote($size)}, hash={$this->db->quote($hash)}, filetype={$this->db->quote($attachment->filetype)}
  886. WHERE id={$this->db->quote($attachment->id)}";
  887. $this->db->setQuery ( $query );
  888. $this->db->query ();
  889. if ($this->db->getErrorNum ())
  890. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  891. }
  892. if ($this->checkTimeout()) break;
  893. }
  894. $this->setAttachmentStatus($stats);
  895. if ($count) {
  896. $this->addStatus ( JText::sprintf('COM_KUNENA_MIGRATE_ATTACHMENTS',$count), true, '', 'attach' );
  897. } else {
  898. // Note: com_fireboard has been replaced by com_kunena during 1.0.8 upgrade, use it instead
  899. $query = "UPDATE #__kunena_messages_text SET message = REPLACE(REPLACE(message, '/images/fbfiles', '/media/kunena/attachments/legacy'), '/components/com_kunena/uploaded', '/media/kunena/attachments/legacy');";
  900. $this->db->setQuery ( $query );
  901. $this->db->query ();
  902. if ($this->db->getErrorNum ())
  903. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  904. $this->addStatus ( JText::sprintf('COM_KUNENA_MIGRATE_ATTACHMENTS_DONE', $stats->migrated, $stats->missing, $stats->failed), true, '', 'attach' );
  905. }
  906. return !$count;
  907. }
  908. public function getRequirements() {
  909. if ($this->_req !== false) {
  910. return $this->_req;
  911. }
  912. $req = new StdClass ();
  913. $req->mysql = $this->db->getVersion ();
  914. $req->php = phpversion ();
  915. $req->joomla = JVERSION;
  916. $req->domdocument = 'DOMDocument';
  917. $req->fail = array ();
  918. if (version_compare ( $req->mysql, KUNENA_MIN_MYSQL, "<" ))
  919. $req->fail ['mysql'] = true;
  920. if (version_compare ( $req->php, KUNENA_MIN_PHP, "<" ))
  921. $req->fail ['php'] = true;
  922. if (version_compare ( $req->joomla, '1.7', ">" ) && version_compare ( $req->joomla, KUNENA_MIN_JOOMLA17, "<" ))
  923. $req->fail ['joomla'] = true;
  924. elseif (version_compare ( $req->joomla, '1.6', ">" ) && version_compare ( $req->joomla, KUNENA_MIN_JOOMLA16, "<" ))
  925. $req->fail ['joomla'] = true;
  926. elseif (version_compare ( $req->joomla, KUNENA_MIN_JOOMLA15, "<" ))
  927. $req->fail ['joomla'] = true;
  928. if(!class_exists('DOMDocument')){
  929. $req->fail ['domdocument'] = true;
  930. }
  931. $this->_req = $req;
  932. return $this->_req;
  933. }
  934. public function getVersionPrefix() {
  935. if ($this->_versionprefix !== false) {
  936. return $this->_versionprefix;
  937. }
  938. $match = $this->detectTable ( $this->_versiontablearray );
  939. if (isset ( $match ['prefix'] ))
  940. $this->_versionprefix = $match ['prefix'];
  941. else
  942. $this->_versionprefix = null;
  943. return $this->_versionprefix;
  944. }
  945. public function getDetectVersions() {
  946. if (!empty($this->_versions)) {
  947. return $this->_versions;
  948. }
  949. $kunena = $this->getInstalledVersion('kunena_', $this->_kVersions);
  950. $fireboard = $this->getInstalledVersion('fb_', $this->_fbVersions);
  951. if (!empty($kunena->state)) {
  952. $this->_versions['failed'] = $kunena;
  953. $kunena = $this->getInstalledVersion('kunena_', $this->_kVersions, true);
  954. if (version_compare ( $kunena->version, '1.6.0-ALPHA', "<" ) ) $kunena->ignore = true;
  955. }
  956. if ($kunena->component && empty($kunena->ignore)) {
  957. $this->_versions['kunena'] = $kunena;
  958. $migrate = false;
  959. } else {
  960. $migrate = $this->isMigration($kunena, $fireboard);
  961. }
  962. if (!empty($fireboard->component) && $migrate) $this->_versions['fb'] = $fireboard;
  963. if (empty($kunena->component)) $this->_versions['kunena'] = $kunena;
  964. else if (!empty($fireboard->component)) {
  965. $uninstall = clone $fireboard;
  966. $uninstall->action = 'RESTORE';
  967. $this->_versions['uninstall'] = $uninstall;
  968. } else {
  969. $uninstall = clone $kunena;
  970. $uninstall->action = 'UNINSTALL';
  971. $this->_versions['uninstall'] = $uninstall;
  972. }
  973. foreach ($this->_versions as $version) {
  974. $version->label = $this->getActionText($version);
  975. $version->description = $this->getActionText($version, 'desc');
  976. $version->hint = $this->getActionText($version, 'hint');
  977. $version->warning = $this->getActionText($version, 'warn');
  978. $version->link = JURI::root().'administrator/index.php?option=com_kunena&view=install&task='.strtolower($version->action).'&'.JUtility::getToken() .'=1';
  979. }
  980. if ($migrate) {
  981. $kunena->warning = $this->getActionText($fireboard, 'warn', 'upgrade');
  982. } else {
  983. $kunena->warning = '';
  984. }
  985. return $this->_versions;
  986. }
  987. public function isMigration($new, $old) {
  988. // If K1.6 not installed: migrate
  989. if (!$new->component || !$this->detectTable ( $new->prefix . 'messages' )) return true;
  990. // If old not installed: upgrade
  991. if (!$old->component || !$this->detectTable ( $old->prefix . 'messages' )) return false;
  992. // If K1.6 is installed and old is not Kunena: upgrade
  993. if ($old->component != 'Kunena') return false;
  994. // User is currently using K1.6: upgrade
  995. if (strtotime($new->installdate) > strtotime($old->installdate)) return false;
  996. // User is currently using K1.0/K1.5: migrate
  997. if (strtotime($new->installdate) < strtotime($old->installdate)) return true;
  998. // Both K1.5 and K1.6 were installed during the same day.. Not going to be easy choice..
  999. // Let's assume that this could be migration
  1000. return true;
  1001. }
  1002. public function getInstalledVersion($prefix, $versionlist, $state = false) {
  1003. if (!$state && isset($this->_installed[$prefix])) {
  1004. return $this->_installed[$prefix];
  1005. }
  1006. if ($prefix === null) {
  1007. $versionprefix = $this->getVersionPrefix ();
  1008. } else if ($this->detectTable ( $prefix . 'version') ) {
  1009. $versionprefix = $prefix;
  1010. } else {
  1011. $versionprefix = null;
  1012. }
  1013. if ($versionprefix) {
  1014. // Version table exists, try to get installed version
  1015. $state = $state ? " WHERE state=''" : "";
  1016. $this->db->setQuery ( "SELECT * FROM " . $this->db->nameQuote ( $this->db->getPrefix () . $versionprefix . 'version' ) . $state . " ORDER BY `id` DESC", 0, 1 );
  1017. $version = $this->db->loadObject ();
  1018. if ($this->db->getErrorNum ())
  1019. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1020. if ($version) {
  1021. $version->version = strtolower ( $version->version );
  1022. $version->prefix = $versionprefix;
  1023. if (version_compare ( $version->version, '1.0.5', ">" ))
  1024. $version->component = 'Kunena';
  1025. else
  1026. $version->component = 'FireBoard';
  1027. $version->version = strtoupper ( $version->version );
  1028. // Version table may contain dummy version.. Ignore it
  1029. if (! $version || version_compare ( $version->version, '0.1.0', "<" ))
  1030. unset ( $version );
  1031. }
  1032. }
  1033. if (!isset ( $version )) {
  1034. // No version found -- try to detect version by searching some missing fields
  1035. $match = $this->detectTable ( $versionlist );
  1036. // Clean install
  1037. if (empty ( $match ))
  1038. return $this->_installed = null;
  1039. // Create version object
  1040. $version = new StdClass ();
  1041. $version->id = 0;
  1042. $version->component = $match ['component'];
  1043. $version->version = strtoupper ( $match ['version'] );
  1044. $version->versiondate = $match ['date'];
  1045. $version->installdate = '';
  1046. $version->build = '';
  1047. $version->versionname = '';
  1048. $version->prefix = $match ['prefix'];
  1049. }
  1050. $version->action = $this->getInstallAction($version);
  1051. return $this->_installed[$prefix] = $version;
  1052. }
  1053. protected function insertVersion($state = 'beginInstall') {
  1054. // Insert data from the new version
  1055. $this->insertVersionData ( Kunena::version(), Kunena::versionDate(), Kunena::versionBuild(), Kunena::versionName(), $state );
  1056. }
  1057. protected function updateVersionState($state) {
  1058. // Insert data from the new version
  1059. $this->db->setQuery ( "UPDATE " . $this->db->nameQuote ( $this->db->getPrefix () . 'kunena_version' ) . " SET state = " . $this->db->Quote ( $state ) . " ORDER BY id DESC LIMIT 1" );
  1060. $this->db->query ();
  1061. if ($this->db->getErrorNum ())
  1062. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1063. }
  1064. function getActionText($version, $type='', $action=null) {
  1065. static $search = array ('#COMPONENT_OLD#','#VERSION_OLD#','#BUILD_OLD#','#VERSION#','#BUILD#');
  1066. $replace = array ($version->component, $version->version, $version->build, Kunena::version(), Kunena::versionBuild());
  1067. if (!$action) $action = $version->action;
  1068. $str = '';
  1069. if ($type == 'hint' || $type == 'warn') {
  1070. $str .= '<strong class="k'.$type.'">'.JText::_('COM_KUNENA_INSTALL_'.$type).'</strong> ';
  1071. }
  1072. if ($action && $type) $type = '_'.$type;
  1073. $str .= str_replace($search, $replace, JText::_('COM_KUNENA_INSTALL_'.$action.$type));
  1074. return $str;
  1075. }
  1076. public function getInstallAction($version = null) {
  1077. if ($version->component === null)
  1078. $this->_action = 'INSTALL';
  1079. else if ($version->prefix != 'kunena_')
  1080. $this->_action = 'MIGRATE';
  1081. else if (version_compare ( strtolower(Kunena::version()), strtolower($version->version), '>' ))
  1082. $this->_action = 'UPGRADE';
  1083. else if (version_compare ( strtolower(Kunena::version()), strtolower($version->version), '<' ))
  1084. $this->_action = 'DOWNGRADE';
  1085. else if (Kunena::versionBuild() && Kunena::versionBuild() > $version->build)
  1086. $this->_action = 'UP_BUILD';
  1087. else if (Kunena::versionBuild() && Kunena::versionBuild() < $version->build)
  1088. $this->_action = 'DOWN_BUILD';
  1089. else
  1090. $this->_action = 'REINSTALL';
  1091. return $this->_action;
  1092. }
  1093. protected function detectTable($detectlist) {
  1094. // Cache
  1095. static $tables = array ();
  1096. static $fields = array ();
  1097. $found = 0;
  1098. if (is_string($detectlist)) $detectlist = array(array('table'=>$detectlist));
  1099. foreach ( $detectlist as $detect ) {
  1100. // If no detection is needed, return current item
  1101. if (! isset ( $detect ['table'] ))
  1102. return $detect;
  1103. $table = $this->db->getPrefix () . $detect ['table'];
  1104. // Match if table exists
  1105. if (! isset ( $tables [$table] )) // Not cached
  1106. {
  1107. $this->db->setQuery ( "SHOW TABLES LIKE " . $this->db->quote ( $table ) );
  1108. $result = $this->db->loadResult ();
  1109. if ($this->db->getErrorNum ())
  1110. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1111. $tables [$table] = $result;
  1112. }
  1113. if (! empty ( $tables [$table] ))
  1114. $found = 1;
  1115. // Match if column in a table exists
  1116. if ($found && isset ( $detect ['column'] )) {
  1117. if (! isset ( $fields [$table] )) // Not cached
  1118. {
  1119. $this->db->setQuery ( "SHOW COLUMNS FROM " . $this->db->nameQuote ( $table ) );
  1120. $result = $this->db->loadObjectList ( 'Field' );
  1121. if ($this->db->getErrorNum ())
  1122. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1123. $fields [$table] = $result;
  1124. }
  1125. if (! isset ( $fields [$table] [$detect ['column']] ))
  1126. $found = 0; // Sorry, no match
  1127. }
  1128. if ($found)
  1129. return $detect;
  1130. }
  1131. return array ();
  1132. }
  1133. // helper function to migrate table
  1134. protected function migrateTable($oldprefix, $oldtable, $newtable) {
  1135. $tables = $this->listTables ( 'kunena_' );
  1136. $oldtables = $this->listTables ( $oldprefix );
  1137. if ($oldtable == $newtable || !isset ( $oldtables [$oldtable] ) || isset ( $tables [$newtable] ))
  1138. return; // Nothing to migrate
  1139. // Make identical copy from the table with new name
  1140. $create = array_pop($this->db->getTableCreate($this->db->getPrefix () . $oldtable));
  1141. $collation = $this->db->getCollation ();
  1142. if (!strstr($collation, 'utf8')) $collation = 'utf8_general_ci';
  1143. if (!$create) return;
  1144. $create = preg_replace('/(DEFAULT )?CHARACTER SET [\w\d]+/', '', $create);
  1145. $create = preg_replace('/(DEFAULT )?CHARSET=[\w\d]+/', '', $create);
  1146. $create = preg_replace('/COLLATE [\w\d_]+/', '', $create);
  1147. $create = preg_replace('/TYPE\s*=?/', 'ENGINE=', $create);
  1148. $create .= " DEFAULT CHARACTER SET utf8 COLLATE {$collation}";
  1149. $query = preg_replace('/'.$this->db->getPrefix () . $oldtable.'/', $this->db->getPrefix () . $newtable, $create);
  1150. $this->db->setQuery ( $query );
  1151. $this->db->query ();
  1152. if ($this->db->getErrorNum ())
  1153. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1154. $this->tables ['kunena_'] [$newtable] = $newtable;
  1155. // And copy data into it
  1156. $sql = "INSERT INTO " . $this->db->nameQuote ( $this->db->getPrefix () . $newtable ) . ' ' . $this->selectWithStripslashes($this->db->getPrefix () . $oldtable );
  1157. $this->db->setQuery ( $sql );
  1158. $this->db->query ();
  1159. if ($this->db->getErrorNum ())
  1160. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1161. return array ('name' => $oldtable, 'action' => 'migrate', 'sql' => $sql );
  1162. }
  1163. function selectWithStripslashes($table) {
  1164. $fields = array_pop($this->db->getTableFields($table));
  1165. $select = array();
  1166. foreach ($fields as $field=>$type) {
  1167. $isString = preg_match('/text|char/', $type);
  1168. $select[] = ($isString ? "REPLACE(REPLACE(REPLACE({$this->db->nameQuote($field)}, {$this->db->Quote('\\\\')}, {$this->db->Quote('\\')}),{$this->db->Quote('\\\'')} ,{$this->db->Quote('\'')}),{$this->db->Quote('\"')} ,{$this->db->Quote('"')}) AS " : '') . $this->db->nameQuote($field);
  1169. }
  1170. $select = implode(', ', $select);
  1171. return "SELECT {$select} FROM {$table}";
  1172. }
  1173. function createVersionTable()
  1174. {
  1175. $tables = $this->listTables ( 'kunena_' );
  1176. if (isset ( $tables ['kunena_version'] ))
  1177. return; // Nothing to migrate
  1178. $collation = $this->db->getCollation ();
  1179. if (!strstr($collation, 'utf8')) $collation = 'utf8_general_ci';
  1180. $query = "CREATE TABLE IF NOT EXISTS `".$this->db->getPrefix()."kunena_version` (
  1181. `id` int(11) NOT NULL AUTO_INCREMENT,
  1182. `version` varchar(20) NOT NULL,
  1183. `versiondate` date NOT NULL,
  1184. `installdate` date NOT NULL,
  1185. `build` varchar(20) NOT NULL,
  1186. `versionname` varchar(40) DEFAULT NULL,
  1187. `state` varchar(32) NOT NULL,
  1188. PRIMARY KEY (`id`)
  1189. ) DEFAULT CHARACTER SET utf8 COLLATE {$collation};";
  1190. $this->db->setQuery($query);
  1191. $this->db->query();
  1192. if ($this->db->getErrorNum ())
  1193. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1194. $this->tables ['kunena_'] ['kunena_version'] = 'kunena_version';
  1195. return array('action'=>'create', 'name'=>'kunena_version', 'sql'=>$query);
  1196. }
  1197. // also insert old version if not in the table
  1198. protected function insertVersionData($version, $versiondate, $build, $versionname, $state = '') {
  1199. $this->db->setQuery ( "INSERT INTO `#__kunena_version`" . "SET `version` = " . $this->db->quote ( $version ) . "," . "`versiondate` = " . $this->db->quote ( $versiondate ) . "," . "`installdate` = CURDATE()," . "`build` = " . $this->db->quote ( $build ) . "," . "`versionname` = " . $this->db->quote ( $versionname ) . "," . "`state` = " . $this->db->quote ( $state ) );
  1200. $this->db->query ();
  1201. if ($this->db->getErrorNum ())
  1202. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1203. }
  1204. protected function listTables($prefix, $reload = false) {
  1205. if (isset ( $this->tables [$prefix] ) && ! $reload) {
  1206. return $this->tables [$prefix];
  1207. }
  1208. $this->db->setQuery ( "SHOW TABLES LIKE " . $this->db->quote ( $this->db->getPrefix () . $prefix . '%' ) );
  1209. $list = $this->db->loadResultArray ();
  1210. if ($this->db->getErrorNum ())
  1211. throw new KunenaInstallerException ( $this->db->getErrorMsg (), $this->db->getErrorNum () );
  1212. $this->tables [$prefix] = array ();
  1213. foreach ( $list as $table ) {
  1214. $table = preg_replace ( '/^' . $this->db->getPrefix () . '/', '', $table );
  1215. $this->tables [$prefix] [$table] = $table;
  1216. }
  1217. return $this->tables [$prefix];
  1218. }
  1219. function deleteTables($prefix) {
  1220. $tables = $this->listTables($prefix);
  1221. foreach ($tables as $table) {
  1222. $this->db->setQuery ( "DROP TABLE IF EXISTS " . $this->db->nameQuote ( $this->db->getPrefix () . $table

Large files files are truncated, but you can click here to view the full file