PageRenderTime 92ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/administrator/components/com_akeeba/akeeba/platform/joomla25/platform.php

https://bitbucket.org/kraymitchell/saiu
PHP | 660 lines | 469 code | 58 blank | 133 comment | 79 complexity | d1cb11aa046b34d0b8313929a41993c0 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-3.0, BSD-3-Clause, LGPL-2.1, GPL-3.0
  1. <?php
  2. /**
  3. * Akeeba Engine
  4. * The modular PHP5 site backup engine
  5. * @copyright Copyright (c)2009-2012 Nicholas K. Dionysopoulos
  6. * @license GNU GPL version 3 or, at your option, any later version
  7. * @package akeebaengine
  8. *
  9. */
  10. // Protection against direct access
  11. defined('AKEEBAENGINE') or die();
  12. if(!defined('DS')) {
  13. define('DS',DIRECTORY_SEPARATOR); // Still required by Joomla! :(
  14. }
  15. /**
  16. * Joomla! 2.5 platform class
  17. */
  18. class AEPlatformJoomla25 extends AEPlatformAbstract
  19. {
  20. /** @var int Platform class priority */
  21. public $priority = 53;
  22. public $platformName = 'joomla25';
  23. /**
  24. * Performs heuristics to determine if this platform object is the ideal
  25. * candidate for the environment Akeeba Engine is running in.
  26. *
  27. * @return bool
  28. */
  29. public function isThisPlatform()
  30. {
  31. // Make sure _JEXEC is defined
  32. if(!defined('_JEXEC')) return false;
  33. // We need JVERSION to be defined
  34. if(!defined('JVERSION')) return false;
  35. // Check if JFactory exists
  36. if(!class_exists('JFactory')) return false;
  37. // Check if JApplication exists
  38. if(!class_exists('JApplication')) return false;
  39. return version_compare(JVERSION, '2.5.0', 'ge');
  40. }
  41. /**
  42. * Returns an associative array of stock platform directories
  43. * @return array
  44. */
  45. public function get_stock_directories()
  46. {
  47. static $stock_directories = array();
  48. if(empty($stock_directories))
  49. {
  50. $jreg = JFactory::getConfig();
  51. if(version_compare(JVERSION, '3.0', 'ge')) {
  52. $tmpdir = $jreg->get('tmp_path');
  53. } else {
  54. $tmpdir = $jreg->getValue('config.tmp_path');
  55. }
  56. $stock_directories['[SITEROOT]'] = $this->get_site_root();
  57. $stock_directories['[ROOTPARENT]'] = @realpath($this->get_site_root().'/..');
  58. $stock_directories['[SITETMP]'] = $tmpdir;
  59. $stock_directories['[DEFAULT_OUTPUT]'] = $this->get_site_root().'/administrator/components/com_akeeba/backup';
  60. }
  61. return $stock_directories;
  62. }
  63. /**
  64. * Returns the absolute path to the site's root
  65. * @return string
  66. */
  67. public function get_site_root()
  68. {
  69. static $root = null;
  70. if( empty($root) || is_null($root) )
  71. {
  72. $root = JPATH_ROOT;
  73. if(empty($root) || ($root == DIRECTORY_SEPARATOR) || ($root == '/'))
  74. {
  75. // Try to get the current root in a different way
  76. if(function_exists('getcwd')) {
  77. $root = getcwd();
  78. }
  79. $app = JFactory::getApplication();
  80. if( $app->isAdmin() )
  81. {
  82. if(empty($root)) {
  83. $root = '../';
  84. } else {
  85. $adminPos = strpos($root, 'administrator');
  86. if($adminPos !== false) {
  87. $root = substr($root, 0, $adminPos);
  88. } else {
  89. $root = '../';
  90. }
  91. // Degenerate case where $root = 'administrator'
  92. // without a leading slash before entering this
  93. // if-block
  94. if(empty($root)) $root = '../';
  95. }
  96. }
  97. else
  98. {
  99. if(empty($root) || ($root == DIRECTORY_SEPARATOR) || ($root == '/') ) {
  100. $root = './';
  101. }
  102. }
  103. }
  104. }
  105. return $root;
  106. }
  107. /**
  108. * Returns the absolute path to the installer images directory
  109. * @return string
  110. */
  111. public function get_installer_images_path()
  112. {
  113. return JPATH_ADMINISTRATOR.'/components/com_akeeba/assets/installers';
  114. }
  115. /**
  116. * Returns the active profile number
  117. * @return int
  118. */
  119. public function get_active_profile()
  120. {
  121. if( defined('AKEEBA_PROFILE') )
  122. {
  123. return AKEEBA_PROFILE;
  124. }
  125. else
  126. {
  127. $session = JFactory::getSession();
  128. return $session->get('profile', null, 'akeeba');
  129. }
  130. }
  131. /**
  132. * Returns the selected profile's name. If no ID is specified, the current
  133. * profile's name is returned.
  134. * @return string
  135. */
  136. public function get_profile_name($id = null)
  137. {
  138. if(empty($id)) $id = $this->get_active_profile();
  139. $id = (int)$id;
  140. $sql = 'SELECT `description` FROM `#__ak_profiles` WHERE `id` = '.$id;
  141. $db = AEFactory::getDatabase( $this->get_platform_database_options() );
  142. $db->setQuery($sql);
  143. return $db->loadResult();
  144. }
  145. /**
  146. * Returns the backup origin
  147. * @return string Backup origin: backend|frontend
  148. */
  149. public function get_backup_origin()
  150. {
  151. if(defined('AKEEBA_BACKUP_ORIGIN')) return AKEEBA_BACKUP_ORIGIN;
  152. if(JFactory::getApplication()->isAdmin()) {
  153. return 'backend';
  154. } else {
  155. return 'frontend';
  156. }
  157. }
  158. /**
  159. * Returns a MySQL-formatted timestamp out of the current date
  160. * @param string $date[optional] The timestamp to use. Omit to use current timestamp.
  161. * @return string
  162. */
  163. public function get_timestamp_database($date = 'now')
  164. {
  165. jimport('joomla.utilities.date');
  166. $jdate = new JDate($date);
  167. if(version_compare(JVERSION, '3.0', 'ge')) {
  168. return $jdate->toSql();
  169. } else {
  170. return $jdate->toMySQL();
  171. }
  172. }
  173. /**
  174. * Returns the current timestamp, taking into account any TZ information,
  175. * in the format specified by $format.
  176. * @param string $format Timestamp format string (standard PHP format string)
  177. * @return string
  178. */
  179. public function get_local_timestamp($format)
  180. {
  181. jimport('joomla.utilities.date');
  182. $jregistry = JFactory::getConfig();
  183. if(version_compare(JVERSION, '3.0', 'ge')) {
  184. $tzDefault = $jregistry->get('offset');
  185. } else {
  186. $tzDefault = $jregistry->getValue('config.offset');
  187. }
  188. $user = JFactory::getUser();
  189. $tz = $user->getParam('timezone', $tzDefault);
  190. $dateNow = new JDate('now', $tz);
  191. return $dateNow->format($format, true);
  192. }
  193. /**
  194. * Returns the current host name
  195. * @return string
  196. */
  197. public function get_host()
  198. {
  199. if(!array_key_exists('REQUEST_METHOD', $_SERVER)) {
  200. // Running under CLI
  201. require_once JPATH_ROOT.'/libraries/joomla/environment/uri.php';
  202. $url = AEPlatform::getInstance()->get_platform_configuration_option('siteurl','');
  203. $oURI = new JURI($url);
  204. } else {
  205. // Running under the web server
  206. $oURI = JURI::getInstance();
  207. }
  208. return $oURI->getHost();
  209. }
  210. public function get_site_name()
  211. {
  212. $jconfig = JFactory::getConfig();
  213. if(version_compare(JVERSION, '3.0', 'ge')) {
  214. return $jconfig->get('sitename','');
  215. } else {
  216. return $jconfig->getValue('config.sitename','');
  217. }
  218. }
  219. /**
  220. * Gets the best matching database driver class, according to CMS settings
  221. * @param bool $use_platform If set to false, it will forcibly try to assign one of the primitive type (AEDriverMySQL/AEDriverMySQLi) and NEVER tell you to use an AEPlatformDriver* class
  222. * @return string
  223. */
  224. public function get_default_database_driver( $use_platform = true )
  225. {
  226. $jconfig = JFactory::getConfig();
  227. if(version_compare(JVERSION, '3.0', 'ge')) {
  228. $driver = $jconfig->get('dbtype');
  229. } else {
  230. $driver = $jconfig->getValue('config.dbtype');
  231. }
  232. // Let's see what driver Joomla! uses...
  233. if( $use_platform )
  234. {
  235. $hasNookuContent = file_exists(JPATH_ROOT.'/plugins/system/nooku.php');
  236. switch($driver)
  237. {
  238. // MySQL or MySQLi drivers are known to be working; use their
  239. // Akeeba Engine extended version, AEDriverPlatformJoomla
  240. case 'mysql':
  241. if($hasNookuContent) {
  242. return 'AEDriverMysql';
  243. } else {
  244. return 'AEDriverPlatformJoomla';
  245. }
  246. break;
  247. case 'mysqli':
  248. if($hasNookuContent) {
  249. return 'AEDriverMysqli';
  250. } else {
  251. return 'AEDriverPlatformJoomla';
  252. }
  253. break;
  254. case 'sqlsrv':
  255. case 'sqlazure':
  256. return 'AEDriverPlatformJoomla';
  257. break;
  258. // Some custom driver. Uh oh!
  259. default:
  260. break;
  261. }
  262. }
  263. // Is this a subcase of mysqli or mysql drivers?
  264. if( strtolower(substr($driver, 0, 6)) == 'mysqli' )
  265. {
  266. return 'AEDriverMysqli';
  267. }
  268. elseif( strtolower(substr($driver, 0, 5)) == 'mysql' )
  269. {
  270. return 'AEDriverMysql';
  271. }
  272. elseif( strtolower(substr($driver, 0, 6)) == 'sqlsrv' )
  273. {
  274. return 'AEDriverSqlsrv';
  275. }
  276. elseif( strtolower(substr($driver, 0, 6)) == 'sqlazure' )
  277. {
  278. return 'AEDriverSqlazure';
  279. }
  280. // If we're still here, we have to guesstimate the correct driver. All bets are off.
  281. // And you'd better be using MySQL!!!
  282. if(function_exists('mysqli_connect'))
  283. {
  284. // MySQLi available. Let's use it.
  285. return 'AEDriverMysqli';
  286. }
  287. else
  288. {
  289. // MySQLi is not available; let's use standard MySQL.
  290. return 'AEDriverMysql';
  291. }
  292. }
  293. /**
  294. * Returns a set of options to connect to the default database of the current CMS
  295. * @return array
  296. */
  297. public function get_platform_database_options()
  298. {
  299. static $options;
  300. if(empty($options))
  301. {
  302. $conf = JFactory::getConfig();
  303. if(version_compare(JVERSION, '3.0', 'ge')) {
  304. $options = array(
  305. 'host' => $conf->get('host'),
  306. 'user' => $conf->get('user'),
  307. 'password' => $conf->get('password'),
  308. 'database' => $conf->get('db'),
  309. 'prefix' => $conf->get('dbprefix')
  310. );
  311. } else {
  312. $options = array(
  313. 'host' => $conf->getValue('config.host'),
  314. 'user' => $conf->getValue('config.user'),
  315. 'password' => $conf->getValue('config.password'),
  316. 'database' => $conf->getValue('config.db'),
  317. 'prefix' => $conf->getValue('config.dbprefix')
  318. );
  319. }
  320. }
  321. return $options;
  322. }
  323. /**
  324. * Provides a platform-specific translation function
  325. * @param string $key The translation key
  326. * @return string
  327. */
  328. public function translate($key)
  329. {
  330. return JText::_($key);
  331. }
  332. /**
  333. * Populates global constants holding the Akeeba version
  334. */
  335. public function load_version_defines()
  336. {
  337. if(file_exists(JPATH_COMPONENT_ADMINISTRATOR.'/version.php'))
  338. {
  339. require_once(JPATH_COMPONENT_ADMINISTRATOR.'/version.php');
  340. }
  341. if(!defined('AKEEBA_VERSION')) define("AKEEBA_VERSION", "svn");
  342. if(!defined('AKEEBA_PRO')) define('AKEEBA_PRO', false);
  343. if(!defined('AKEEBA_DATE')) {
  344. jimport('joomla.utilities.date');
  345. $date = new JDate();
  346. define( "AKEEBA_DATE", $date->format('Y-m-d') );
  347. }
  348. }
  349. /**
  350. * Returns the platform name and version
  351. * @param string $platform_name Name of the platform, e.g. Joomla!
  352. * @param string $version Full version of the platform
  353. */
  354. public function getPlatformVersion()
  355. {
  356. $v = new JVersion();
  357. return array(
  358. 'name' => 'Joomla!',
  359. 'version' => $v->getShortVersion()
  360. );
  361. }
  362. /**
  363. * Logs platform-specific directories with _AE_LOG_INFO log level
  364. */
  365. public function log_platform_special_directories()
  366. {
  367. AEUtilLogger::WriteLog(_AE_LOG_INFO, "JPATH_BASE :" . JPATH_BASE );
  368. AEUtilLogger::WriteLog(_AE_LOG_INFO, "JPATH_SITE :" . JPATH_SITE );
  369. AEUtilLogger::WriteLog(_AE_LOG_INFO, "JPATH_ROOT :" . JPATH_ROOT );
  370. AEUtilLogger::WriteLog(_AE_LOG_INFO, "JPATH_CACHE :" . JPATH_CACHE );
  371. AEUtilLogger::WriteLog(_AE_LOG_INFO, "Computed root :" . $this->get_site_root() );
  372. // Detect UNC paths and warn the user
  373. if(DIRECTORY_SEPARATOR == '\\') {
  374. if( (substr(JPATH_ROOT, 0, 2) == '\\\\') || (substr(JPATH_ROOT, 0, 2) == '//') ) {
  375. AEUtilLogger::WriteLog(_AE_LOG_WARNING, 'Your site\'s root is using a UNC path (e.g. \\SERVER\path\to\root). PHP has known bugs which may');
  376. AEUtilLogger::WriteLog(_AE_LOG_WARNING, 'prevent it from working properly on a site like this. Please take a look at');
  377. AEUtilLogger::WriteLog(_AE_LOG_WARNING, 'https://bugs.php.net/bug.php?id=40163 and https://bugs.php.net/bug.php?id=52376. As a result your');
  378. AEUtilLogger::WriteLog(_AE_LOG_WARNING, 'backup may fail.');
  379. }
  380. }
  381. }
  382. /**
  383. * Loads a platform-specific software configuration option
  384. * @param string $key
  385. * @param mixed $default
  386. * @return mixed
  387. */
  388. public function get_platform_configuration_option($key, $default)
  389. {
  390. // Get the component configuration option WITHOUT using the bloody ever-changing Joomla! API...
  391. return AEUtilComconfig::getValue($key, $default);
  392. }
  393. /**
  394. * Returns a list of emails to the Super Administrators
  395. * @return unknown_type
  396. */
  397. public function get_administrator_emails()
  398. {
  399. $db = JFactory::getDbo();
  400. $query = $db->getQuery(true);
  401. $query->select(array(
  402. $db->qn('u').'.'.$db->qn('name'),
  403. $db->qn('u').'.'.$db->qn('email'),
  404. ))
  405. ->from($db->qn('#__users').' AS '.$db->qn('u'))
  406. ->join(
  407. 'INNER', $db->qn('#__user_usergroup_map').' AS '.$db->qn('m').' ON ('.
  408. $db->qn('m').'.'.$db->qn('user_id').' = '.$db->qn('u').'.'.$db->qn('id').')'
  409. )
  410. ->where($db->qn('m').'.'.$db->qn('group_id').' = '.$db->q('8'));
  411. $db->setQuery($query);
  412. $superAdmins = $db->loadAssocList();
  413. $mails = array();
  414. if(!empty($superAdmins))
  415. {
  416. foreach($superAdmins as $admin)
  417. {
  418. $mails[] = $admin['email'];
  419. }
  420. }
  421. return $mails;
  422. }
  423. /**
  424. * Sends a very simple email using the platform's emailer facility
  425. * @param string $to
  426. * @param string $subject
  427. * @param string $body
  428. */
  429. public function send_email($to, $subject, $body, $attachFile = null)
  430. {
  431. AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"-- Fetching mailer object" );
  432. $mailer = AEPlatform::getInstance()->getMailer();
  433. if(!is_object($mailer)) {
  434. AEUtilLogger::WriteLog(_AE_LOG_WARNING,"Could not send email to $to - Reason: Mailer object is not an object; please check your system settings");
  435. return false;
  436. }
  437. AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"-- Creating email message");
  438. $recipient = array($to);
  439. $mailer->addRecipient($recipient);
  440. $mailer->setSubject($subject);
  441. $mailer->setBody($body);
  442. if(!empty($attachFile))
  443. {
  444. AEUtilLogger::WriteLog(_AE_LOG_WARNING, "-- Attaching $attachFile");
  445. if(!file_exists($attachFile) || !(is_file($attachFile) || is_link($attachFile))) {
  446. AEUtilLogger::WriteLog(_AE_LOG_WARNING, "The file does not exist, or it's not a file; no email sent");
  447. return false;
  448. }
  449. if(!is_readable($attachFile)) {
  450. AEUtilLogger::WriteLog(_AE_LOG_WARNING, "The file is not readable; no email sent");
  451. return false;
  452. }
  453. $filesize = @filesize($attachFile);
  454. if($filesize) {
  455. // Check that we have AT LEAST 2.5 times free RAM as the filesize (that's how much we'll need)
  456. if(!function_exists('ini_get')) {
  457. // Assume 8Mb of PHP memory limit (worst case scenario)
  458. $totalRAM = 8388608;
  459. } else {
  460. $totalRAM = ini_get('memory_limit');
  461. if(strstr($totalRAM, 'M')) {
  462. $totalRAM = (int)$totalRAM * 1048576;
  463. } elseif(strstr($totalRAM, 'K')) {
  464. $totalRAM = (int)$totalRAM * 1024;
  465. } elseif(strstr($totalRAM, 'G')) {
  466. $totalRAM = (int)$totalRAM * 1073741824;
  467. } else {
  468. $totalRAM = (int)$totalRAM;
  469. }
  470. if($totalRAM <= 0) {
  471. // No memory limit? Cool! Assume 1Gb of available RAM (which is absurdely abundant as of March 2011...)
  472. $totalRAM = 1086373952;
  473. }
  474. }
  475. if(!function_exists('memory_get_usage')) {
  476. $usedRAM = 8388608;
  477. } else {
  478. $usedRAM = memory_get_usage();
  479. }
  480. $availableRAM = $totalRAM - $usedRAM;
  481. if($availableRAM < 2.5*$filesize) {
  482. AEUtilLogger::WriteLog(_AE_LOG_WARNING, "The file is too big to be sent by email. Please use a smaller Part Size for Split Archives setting.");
  483. AEUtilLogger::WriteLog(_AE_LOG_DEBUG, "Memory limit $totalRAM bytes -- Used memory $usedRAM bytes -- File size $filesize -- Attachment requires approx. ".(2.5*$filesize)." bytes");
  484. return false;
  485. }
  486. } else {
  487. AEUtilLogger::WriteLog(_AE_LOG_WARNING, "Your server fails to report the file size of $attachFile. If the backup crashes, please use a smaller Part Size for Split Archives setting");
  488. }
  489. $mailer->addAttachment($attachFile);
  490. }
  491. AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"-- Sending message");
  492. $result = $mailer->Send();
  493. if($result instanceof JException)
  494. {
  495. AEUtilLogger::WriteLog(_AE_LOG_WARNING,"Could not email $to:");
  496. AEUtilLogger::WriteLog(_AE_LOG_WARNING,$result->getMessage());
  497. $ret = $result->getMessage();
  498. unset($result);
  499. unset($mailer);
  500. return $ret;
  501. }
  502. else
  503. {
  504. AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"-- Email sent");
  505. return true;
  506. }
  507. }
  508. /**
  509. * Deletes a file from the local server using direct file access or FTP
  510. * @param string $file
  511. * @return bool
  512. */
  513. public function unlink($file)
  514. {
  515. if(function_exists('jimport')) {
  516. jimport('joomla.filesystem.file');
  517. $result = JFile::delete($file);
  518. if(!$result) $result = @unlink($file);
  519. } else {
  520. $result = parent::unlink($file);
  521. }
  522. return $result;
  523. }
  524. /**
  525. * Moves a file around within the local server using direct file access or FTP
  526. * @param string $from
  527. * @param string $to
  528. * @return bool
  529. */
  530. public function move($from, $to)
  531. {
  532. if(function_exists('jimport')) {
  533. jimport('joomla.filesystem.file');
  534. $result = JFile::move($from, $to);
  535. // JFile failed. Let's try rename()
  536. if(!$result)
  537. {
  538. $result = @rename($from, $to);
  539. }
  540. // Rename failed, too. Let's try copy/delete
  541. if(!$result)
  542. {
  543. // Try copying with JFile. If it fails, use copy().
  544. $result = JFile::copy($from, $to);
  545. if(!$result) $result = @copy($from, $to);
  546. // If the copy succeeded, try deleting the original with JFile. If it fails, use unlink().
  547. if($result)
  548. {
  549. $result = $this->unlink($from);
  550. }
  551. }
  552. } else {
  553. $result = parent::move($from, $to);
  554. }
  555. return $result;
  556. }
  557. /**
  558. * Registers Akeeba Engine's core classes with JLoader
  559. * @param string $path_prefix The path prefix to look in
  560. */
  561. protected function register_akeeba_engine_classes($path_prefix)
  562. {
  563. global $Akeeba_Class_Map;
  564. jimport('joomla.filesystem.folder');
  565. foreach($Akeeba_Class_Map as $class_prefix => $path_suffix)
  566. {
  567. // Bail out if there is such directory, so as not to have Joomla! throw errors
  568. if(!@is_dir($path_prefix.'/'.$path_suffix)) continue;
  569. $file_list = JFolder::files( $path_prefix.'/'.$path_suffix, '.*\.php' );
  570. if(is_array($file_list) && !empty($file_list)) foreach($file_list as $file)
  571. {
  572. $class_suffix = ucfirst(basename($file, '.php'));
  573. JLoader::register($class_prefix.$class_suffix, $path_prefix.'/'.$path_suffix.'/'.$file );
  574. }
  575. }
  576. }
  577. /**
  578. * Joomla!-specific function to get an instance of the mailer class
  579. * @return JMail
  580. */
  581. public function &getMailer()
  582. {
  583. $mailer = JFactory::getMailer();
  584. if(!is_object($mailer)) {
  585. AEUtilLogger::WriteLog(_AE_LOG_WARNING,"Fetching Joomla!'s mailer was impossible; imminent crash!");
  586. } else {
  587. $emailMethod = $mailer->Mailer;
  588. AEUtilLogger::WriteLog(_AE_LOG_DEBUG,"-- Joomla!'s mailer is using $emailMethod mail method.");
  589. }
  590. return $mailer;
  591. }
  592. }