PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/administrator/components/com_akeeba/models/cpanel.php

https://bitbucket.org/organicdevelopment/joomla-2.5
PHP | 437 lines | 296 code | 48 blank | 93 comment | 54 complexity | 6d36465d749827501eadc76efbda3c61 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-2.0, MIT, BSD-3-Clause, LGPL-2.1
  1. <?php
  2. /**
  3. * @package AkeebaBackup
  4. * @copyright Copyright (c)2009-2012 Nicholas K. Dionysopoulos
  5. * @license GNU General Public License version 3, or later
  6. * @version $Id$
  7. * @since 1.3
  8. */
  9. // Protect from unauthorized access
  10. defined('_JEXEC') or die('Restricted Access');
  11. jimport('joomla.application.component.model');
  12. /**
  13. * The Control Panel model
  14. *
  15. */
  16. class AkeebaModelCpanel extends JModel
  17. {
  18. /**
  19. * Contructor; dummy for now
  20. *
  21. */
  22. public function __construct()
  23. {
  24. parent::__construct();
  25. }
  26. /**
  27. * Get an array of icon definitions for the Control Panel
  28. *
  29. * @return array
  30. */
  31. public function getIconDefinitions()
  32. {
  33. AEPlatform::getInstance()->load_version_defines();
  34. $core = $this->loadIconDefinitions(JPATH_COMPONENT_ADMINISTRATOR.'/views');
  35. if(AKEEBA_PRO) {
  36. $pro = $this->loadIconDefinitions(JPATH_COMPONENT_ADMINISTRATOR.'/plugins/views');
  37. } else {
  38. $pro = array();
  39. }
  40. $ret = array_merge_recursive($core, $pro);
  41. return $ret;
  42. }
  43. private function loadIconDefinitions($path)
  44. {
  45. $ret = array();
  46. if(!@file_exists($path.'/views.ini')) return $ret;
  47. $ini_data = AEUtilINI::parse_ini_file($path.'/views.ini', true);
  48. if(!empty($ini_data))
  49. {
  50. foreach($ini_data as $view => $def)
  51. {
  52. $task = array_key_exists('task',$def) ? $def['task'] : null;
  53. $ret[$def['group']][] = $this->_makeIconDefinition($def['icon'], JText::_($def['label']), $view, $task);
  54. }
  55. }
  56. return $ret;
  57. }
  58. /**
  59. * Returns a list of available backup profiles, to be consumed by JHTML in order to build
  60. * a drop-down
  61. *
  62. * @return array
  63. */
  64. public function getProfilesList()
  65. {
  66. $db = $this->getDBO();
  67. $query = "SELECT ".$db->nameQuote('id').", ".$db->nameQuote('description').
  68. " FROM ".$db->nameQuote('#__ak_profiles').
  69. " ORDER BY ".$db->nameQuote('id')." ASC";
  70. $db->setQuery($query);
  71. $rawList = $db->loadAssocList();
  72. $options = array();
  73. if(!is_array($rawList)) return $options;
  74. foreach($rawList as $row)
  75. {
  76. $options[] = JHTML::_('select.option', $row['id'], $row['description']);
  77. }
  78. return $options;
  79. }
  80. /**
  81. * Returns the active Profile ID
  82. *
  83. * @return int The active profile ID
  84. */
  85. public function getProfileID()
  86. {
  87. $session = JFactory::getSession();
  88. return $session->get('profile', null, 'akeeba');
  89. }
  90. /**
  91. * Creates an icon definition entry
  92. *
  93. * @param string $iconFile The filename of the icon on the GUI button
  94. * @param string $label The label below the GUI button
  95. * @param string $view The view to fire up when the button is clicked
  96. * @return array The icon definition array
  97. */
  98. public function _makeIconDefinition($iconFile, $label, $view = null, $task = null )
  99. {
  100. return array(
  101. 'icon' => $iconFile,
  102. 'label' => $label,
  103. 'view' => $view,
  104. 'task' => $task
  105. );
  106. }
  107. /**
  108. * Was the last backup a failed one? Used to apply magic settings as a means of
  109. * troubleshooting.
  110. *
  111. * @return bool
  112. */
  113. public function isLastBackupFailed()
  114. {
  115. // Get the last backup record ID
  116. $list = AEPlatform::getInstance()->get_statistics_list(array('limitstart' => 0, 'limit' => 1));
  117. if(empty($list)) return false;
  118. $id = $list[0];
  119. $statmodel->setId($id);
  120. $record = AEPlatform::getInstance()->get_statistics($id);
  121. return ($record['status'] == 'fail');
  122. }
  123. /**
  124. * Checks that the media permissions are 0755 for directories and 0644 for files
  125. * and fixes them if they are incorrect.
  126. *
  127. * @param $force bool Forcibly check subresources, even if the parent has correct permissions
  128. *
  129. * @return bool False if we couldn't figure out what's going on
  130. */
  131. public function fixMediaPermissions($force = false)
  132. {
  133. // Are we on Windows?
  134. if (function_exists('php_uname'))
  135. {
  136. $isWindows = stristr(php_uname(), 'windows');
  137. }
  138. else
  139. {
  140. $isWindows = (DIRECTORY_SEPARATOR == '\\');
  141. }
  142. // No point changing permissions on Windows, as they have ACLs
  143. if($isWindows) return true;
  144. // Check the parent permissions
  145. $parent = JPATH_ROOT.'/media/com_akeeba';
  146. $parentPerms = fileperms($parent);
  147. // If we can't determine the parent's permissions, bail out
  148. if($parentPerms === false) return false;
  149. // Fix the parent's permissions if required
  150. if($parentPerms != 0755) {
  151. $this->chmod($parent, 0755);
  152. } else {
  153. if(!$force) return true;
  154. }
  155. // During development we use symlinks and we don't wanna see that big fat warning
  156. if(@is_link($parent)) return true;
  157. jimport('joomla.filesystem.folder');
  158. $result = true;
  159. // Loop through subdirectories
  160. $folders = JFolder::folders($parent,'.',3,true);
  161. foreach($folders as $folder) {
  162. $perms = fileperms($folder);
  163. if($perms != 0755) $result &= $this->chmod($folder, 0755);
  164. }
  165. // Loop through files
  166. $files = JFolder::files($parent,'.',3,true);
  167. foreach($files as $file) {
  168. $perms = fileperms($file);
  169. if($perms != 0644) $result &= $this->chmod($file, 0644);
  170. }
  171. return $result;
  172. }
  173. /**
  174. * Tries to change a folder/file's permissions using direct access or FTP
  175. *
  176. * @param string $path The full path to the folder/file to chmod
  177. * @param int $mode New permissions
  178. */
  179. private function chmod($path, $mode)
  180. {
  181. if(is_string($mode))
  182. {
  183. $mode = octdec($mode);
  184. if( ($mode < 0600) || ($mode > 0777) ) $mode = 0755;
  185. }
  186. // Initialize variables
  187. jimport('joomla.client.helper');
  188. $ftpOptions = JClientHelper::getCredentials('ftp');
  189. // Check to make sure the path valid and clean
  190. $path = JPath::clean($path);
  191. if ($ftpOptions['enabled'] == 1) {
  192. // Connect the FTP client
  193. jimport('joomla.client.ftp');
  194. $ftp = &JFTP::getInstance(
  195. $ftpOptions['host'], $ftpOptions['port'], null,
  196. $ftpOptions['user'], $ftpOptions['pass']
  197. );
  198. }
  199. if(@chmod($path, $mode))
  200. {
  201. $ret = true;
  202. } elseif ($ftpOptions['enabled'] == 1) {
  203. // Translate path and delete
  204. $path = JPath::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $path), '/');
  205. // FTP connector throws an error
  206. $ret = $ftp->chmod($path, $mode);
  207. } else {
  208. return false;
  209. }
  210. }
  211. /**
  212. * Checks if we should enable settings encryption and applies the change
  213. */
  214. public function checkSettingsEncryption()
  215. {
  216. // Do we have a key file?
  217. jimport('joomla.filesystem.file');
  218. $filename = JPATH_COMPONENT_ADMINISTRATOR.'/akeeba/serverkey.php';
  219. if(JFile::exists($filename)) {
  220. // We have a key file. Do we need to disable it?
  221. if(AEPlatform::getInstance()->get_platform_configuration_option('useencryption', -1) == 0) {
  222. // User asked us to disable encryption. Let's do it.
  223. $this->disableSettingsEncryption();
  224. }
  225. } else {
  226. if(!AEUtilSecuresettings::supportsEncryption()) return;
  227. if(AEPlatform::getInstance()->get_platform_configuration_option('useencryption', -1) != 0) {
  228. // User asked us to enable encryption (or he left us with the default setting!). Let's do it.
  229. $this->enableSettingsEncryption();
  230. }
  231. }
  232. }
  233. private function disableSettingsEncryption()
  234. {
  235. // Load the server key file if necessary
  236. jimport('joomla.filesystem.file');
  237. $filename = JPATH_COMPONENT_ADMINISTRATOR.'/akeeba/serverkey.php';
  238. $key = AEUtilSecuresettings::getKey();
  239. // Loop all profiles and decrypt their settings
  240. $profilesModel = JModel::getInstance('Profiles','AkeebaModel');
  241. $profiles = $profilesModel->getProfilesList(true);
  242. $db = $this->getDBO();
  243. foreach($profiles as $profile)
  244. {
  245. $id = $profile->id;
  246. $config = AEUtilSecuresettings::decryptSettings($profile->configuration, $key);
  247. $sql = 'UPDATE '.$db->nameQuote('#__ak_profiles').' SET '.
  248. $db->nameQuote('configuration').' = '.$db->Quote($config)
  249. .' WHERE '.
  250. $db->nameQuote('id').' = '. $db->Quote($id);
  251. $db->setQuery($sql);
  252. $db->query();
  253. }
  254. // Finally, remove the key file
  255. JFile::delete($filename);
  256. }
  257. private function enableSettingsEncryption()
  258. {
  259. $key = $this->createSettingsKey();
  260. if(empty($key) || ($key==false)) return;
  261. // Loop all profiles and encrypt their settings
  262. $profilesModel = JModel::getInstance('Profiles','AkeebaModel');
  263. $profiles = $profilesModel->getProfilesList(true);
  264. $db = $this->getDBO();
  265. foreach($profiles as $profile)
  266. {
  267. $id = $profile->id;
  268. $config = AEUtilSecuresettings::encryptSettings($profile->configuration, $key);
  269. $sql = 'UPDATE '.$db->nameQuote('#__ak_profiles').' SET '.
  270. $db->nameQuote('configuration').' = '.$db->Quote($config)
  271. .' WHERE '.
  272. $db->nameQuote('id').' = '. $db->Quote($id);
  273. $db->setQuery($sql);
  274. $db->query();
  275. }
  276. }
  277. private function createSettingsKey()
  278. {
  279. jimport('joomla.filesystem.file');
  280. $seedA = md5( JFile::read(JPATH_ROOT.'/configuration.php') );
  281. $seedB = md5( microtime() );
  282. $seed = $seedA.$seedB;
  283. $md5 = md5($seed);
  284. for($i = 0; $i < 1000; $i++) {
  285. $md5 = md5( $md5 . md5(rand(0, 2147483647)) );
  286. }
  287. $key = base64_encode( $md5 );
  288. $filecontents = "<?php defined('AKEEBAENGINE') or die(); define('AKEEBA_SERVERKEY', '$key'); ?>";
  289. $filename = JPATH_COMPONENT_ADMINISTRATOR.'/akeeba/serverkey.php';
  290. $result = JFile::write($filename, $filecontents);
  291. if(!$result) {
  292. return false;
  293. } else {
  294. return base64_decode($key);
  295. }
  296. }
  297. /**
  298. * Update the cached live site's URL for the front-end backup feature (altbackup.php)
  299. * and the detected Joomla! libraries path
  300. */
  301. public function updateMagicParameters()
  302. {
  303. $component = JComponentHelper::getComponent( 'com_akeeba' );
  304. if(is_object($component->params) && ($component->params instanceof JRegistry)) {
  305. $params = $component->params;
  306. } else {
  307. $params = new JParameter($component->params);
  308. }
  309. $params->set( 'siteurl', str_replace('/administrator','',JURI::base()) );
  310. if(defined('JPATH_LIBRARIES')) {
  311. $params->set('jlibrariesdir', AEUtilFilesystem::TranslateWinPath(JPATH_LIBRARIES));
  312. } elseif(defined("JPATH_PLATFORM")) {
  313. $params->set('jlibrariesdir', AEUtilFilesystem::TranslateWinPath(JPATH_PLATFORM));
  314. }
  315. if(AKEEBA_JVERSION == '16') {
  316. // Joomla! 1.6
  317. $joomla16 = true;
  318. $params->set( 'jversion', '1.6' );
  319. } else {
  320. // Joomla! 1.5
  321. $joomla16 = false;
  322. $params->set( 'jversion', '1.5' );
  323. }
  324. $db = JFactory::getDBO();
  325. $data = $params->toString();
  326. if($joomla16)
  327. {
  328. // Joomla! 1.6
  329. $sql = 'UPDATE `#__extensions` SET `params` = '.$db->Quote($data).' WHERE '.
  330. "`element` = 'com_akeeba' AND `type` = 'component'";
  331. }
  332. else
  333. {
  334. // Joomla! 1.5
  335. $sql = 'UPDATE `#__components` SET `params` = '.$db->Quote($data).' WHERE '.
  336. "`option` = 'com_akeeba' AND `parent` = 0 AND `menuid` = 0";
  337. }
  338. $db->setQuery($sql);
  339. $db->query();
  340. }
  341. /**
  342. * Makes sure that the Professional release can be updated using Joomla!'s
  343. * own update system. THIS IS AN AKEEBA ORIGINAL!
  344. */
  345. public function applyJoomlaExtensionUpdateChanges()
  346. {
  347. if(!version_compare(JVERSION,'1.7.0','ge')) return;
  348. if(!AKEEBA_PRO) return;
  349. $update_url = 'https://www.akeebabackup.com/index.php?option=com_ars&view=update&task=stream&format=xml&id=2';
  350. $option = 'com_akeeba';
  351. if(!class_exists('LiveUpdateConfig')) return;
  352. $luc = new LiveUpdateConfig();
  353. $dlid = $luc->getAuthorization();
  354. $db = $this->getDbo();
  355. $query = $db->getQuery(true)
  356. ->select(array(
  357. $db->nq('us').'.*',
  358. ))->from($db->nq('#__extensions').' AS '.$db->nq('ex'))
  359. ->innerJoin(
  360. $db->nq('#__update_sites_extensions').' AS '.$db->nq('map').' ON ('.
  361. $db->nq('map').'.'.$db->nq('extension_id').' = '.
  362. $db->nq('ex').'.'.$db->nq('extension_id').')'
  363. )
  364. ->innerJoin(
  365. $db->nq('#__update_sites').' AS '.$db->nq('us').' ON ('.
  366. $db->nq('us').'.'.$db->nq('update_site_id').' = '.
  367. $db->nq('map').'.'.$db->nq('update_site_id').')'
  368. )
  369. ->where(
  370. $db->nq('ex').'.'.$db->nq('element').' = '.$db->q($option)
  371. )
  372. ;
  373. $db->setQuery($query);
  374. $update_site = $db->loadObject();
  375. if($dlid) $dlid = '&'.$dlid;
  376. $proper_url = $update_url.$dlid.'/extension.xml';
  377. if($update_site->location != $proper_url) {
  378. if(in_array('last_check_timestamp', get_object_vars($update_site))) {
  379. $update_site->last_check_timestamp = 0;
  380. }
  381. $update_site->location = $proper_url;
  382. $db->updateObject('#__update_sites', $update_site, 'update_site_id');
  383. }
  384. }
  385. }