PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/administrator/components/com_admintools/models/update.php

https://gitlab.com/endomorphosis/OLAAaction
PHP | 476 lines | 316 code | 56 blank | 104 comment | 49 complexity | 65f42c502b48e2340c2e54f8ab5b39f0 MD5 | raw file
  1. <?php
  2. /**
  3. * @package AdminTools
  4. * @copyright Copyright (c)2010 Nicholas K. Dionysopoulos
  5. * @license GNU General Public License version 3, or later
  6. * @version $Id: update.php 82 2010-10-23 19:13:50Z nikosdion $
  7. */
  8. // Protect from unauthorized access
  9. defined('_JEXEC') or die('Restricted Access');
  10. jimport('joomla.application.component.model');
  11. /**
  12. * The Live Update model
  13. *
  14. */
  15. class AdmintoolsModelUpdate extends JModel
  16. {
  17. private $update_url = '';
  18. private $isPro = false;
  19. /**
  20. * Public constructor
  21. * @param unknown_type $config
  22. */
  23. public function __construct( $config = array() )
  24. {
  25. parent::__construct($config);
  26. // Determine the appropriate update URL based on whether we're on Core or Professional edition
  27. jimport('joomla.filesystem.file');
  28. $this->isPro = JFile::exists(JPATH_COMPONENT_ADMINISTRATOR.DS.'tables'.DS.'redirs.php');
  29. if($this->isPro)
  30. {
  31. $this->update_url = 'https://www.akeebabackup.com/updates/atpro.ini';
  32. }
  33. else
  34. {
  35. $this->update_url = 'https://www.akeebabackup.com/updates/atcore.ini';
  36. }
  37. }
  38. /**
  39. * Does the server support URL fopen() wrappers?
  40. * @return bool
  41. */
  42. private function hasURLfopen()
  43. {
  44. // If we are not allowed to use ini_get, we assume that URL fopen is
  45. // disabled.
  46. if(!function_exists('ini_get'))
  47. return false;
  48. if( !ini_get('allow_url_fopen') )
  49. return false;
  50. return true;
  51. }
  52. /**
  53. * Does the server support the cURL extension?
  54. * @return bool
  55. */
  56. private function hascURL()
  57. {
  58. if(!function_exists('curl_exec'))
  59. {
  60. return false;
  61. }
  62. return true;
  63. }
  64. /**
  65. * Returns the date and time when the last update check was made.
  66. * @return JDate
  67. */
  68. private function lastUpdateCheck()
  69. {
  70. // Get a reference to component's parameters
  71. $component =& JComponentHelper::getComponent( 'com_admintools' );
  72. $params = new JParameter($component->params);
  73. $lastdate = $params->get('lastupdatecheck', '2009-04-02');
  74. jimport('joomla.utilities.date');
  75. $date = new JDate($lastdate);
  76. return $date;
  77. }
  78. /**
  79. * Gets an object with the latest version information, taken from the update.ini data
  80. * @return JObject|bool An object holding the data, or false on failure
  81. */
  82. private function getLatestVersion($force = false)
  83. {
  84. $inidata = false;
  85. jimport('joomla.utilities.date');
  86. $curdate = new JDate();
  87. $lastdate = $this->lastUpdateCheck();
  88. $difference = ($curdate->toUnix(false) - $lastdate->toUnix(false)) / 3600;
  89. $inidata = $this->getUpdateINIcached();
  90. $cached = false;
  91. // Make sure we ask the server at most every 24 hrs (unless $force is true)
  92. if( ($difference < 24) && (!empty($inidata)) && (!$force) )
  93. {
  94. $cached = true;
  95. // Cached INI data is valid
  96. }
  97. // Prefer to use cURL if it exists and we don't have cached data
  98. elseif( $this->hascURL() )
  99. {
  100. $inidata = $this->getUpdateINIcURL();
  101. }
  102. // If cURL doesn't exist, or if it returned an error, try URL fopen() wrappers
  103. elseif( $this->hasURLfopen() )
  104. {
  105. $inidata = $this->getUpdateINIfopen();
  106. }
  107. // Make sure we do have INI data and not junk...
  108. if($inidata != false)
  109. {
  110. if( strpos($inidata, '; Live Update provision file') !== 0 )
  111. {
  112. $inidata = false;
  113. }
  114. }
  115. // If we have a valid update.ini, update the cache and read the version information
  116. if($inidata != false)
  117. {
  118. if(!$cached) $this->setUpdateINIcached($inidata);
  119. require_once JPATH_COMPONENT_ADMINISTRATOR.DS.'helpers'.DS.'ini.php';
  120. $parsed=AdmintoolsHelperINI::parse_ini_file($inidata, false, true);
  121. // Determine status by parsing the version
  122. $version = $parsed['version'];
  123. if( preg_match('#^[0-9\.]*a[0-9\.]*#', $version) == 1 )
  124. {
  125. $status = 'alpha';
  126. } elseif( preg_match('#^[0-9\.]*b[0-9\.]*#', $version) == 1 )
  127. {
  128. $status = 'beta';
  129. } elseif( preg_match('#^[0-9\.]*$#', $version) == 1 )
  130. {
  131. $status = 'stable';
  132. } else {
  133. $status = 'svn';
  134. }
  135. // Special processing for the link in Admin Tools Professional
  136. $suffix = '';
  137. if($this->isPro)
  138. {
  139. $component =& JComponentHelper::getComponent( 'com_admintools' );
  140. $params = new JParameter($component->params);
  141. $username = $params->get('update_username', '');
  142. $password = $params->get('update_password', '');
  143. if( !empty($username) && !empty($password) )
  144. {
  145. $suffix = '?username='.urlencode($username).'&password='.urlencode($password).'&format=raw';
  146. }
  147. }
  148. $ret = new JObject;
  149. $ret->version = $parsed['version'];
  150. $ret->status = $status;
  151. $ret->reldate = $parsed['date'];
  152. $ret->url = $parsed['link'];
  153. $ret->urlsuffix = $suffix;
  154. return $ret;
  155. }
  156. return false;
  157. }
  158. /**
  159. * Retrieves the update.ini data using URL fopen() wrappers
  160. * @return string|bool The update.ini contents, or FALSE on failure
  161. */
  162. private function getUpdateINIfopen()
  163. {
  164. return @file_get_contents($this->update_url);
  165. }
  166. /**
  167. * Retrieves the update.ini data using cURL extention calls
  168. * @return string|bool The update.ini contents, or FALSE on failure
  169. */
  170. private function getUpdateINIcURL()
  171. {
  172. $process = curl_init($this->update_url);
  173. curl_setopt($process, CURLOPT_HEADER, 0);
  174. // Pretend we are IE7, so that webservers play nice with us
  175. curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)');
  176. curl_setopt($process,CURLOPT_ENCODING , 'gzip');
  177. curl_setopt($process, CURLOPT_TIMEOUT, 5);
  178. curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
  179. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  180. // The @ sign allows the next line to fail if open_basedir is set or if safe mode is enabled
  181. @curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
  182. @curl_setopt($process, CURLOPT_MAXREDIRS, 20);
  183. $inidata = curl_exec($process);
  184. curl_close($process);
  185. return $inidata;
  186. }
  187. private function getUpdateINIcached()
  188. {
  189. $component =& JComponentHelper::getComponent( 'com_admintools' );
  190. $params = new JParameter($component->params);
  191. $inidata = $params->get('updateini', "");
  192. return json_decode($inidata);
  193. }
  194. /**
  195. * Caches the update.ini contents to database
  196. * @param $inidata string The update.ini data
  197. */
  198. private function setUpdateINIcached($inidata)
  199. {
  200. $component =& JComponentHelper::getComponent( 'com_admintools' );
  201. $params = new JParameter($component->params);
  202. jimport('joomla.utilities.date');
  203. $date = new JDate();
  204. $params->set('updateini', json_encode($inidata) );
  205. $params->set('lastupdatecheck', $date->toUnix(false));
  206. $db =& JFactory::getDBO();
  207. $data = $params->toString();
  208. global $mainframe;
  209. if( !is_object($mainframe) )
  210. {
  211. // Joomla! 1.6
  212. $sql = 'UPDATE `#__extensions` SET `params` = '.$db->Quote($data).' WHERE '.
  213. "`element` = 'com_admintools' AND `type` = 'component'";
  214. }
  215. else
  216. {
  217. // Joomla! 1.5
  218. $sql = 'UPDATE `#__components` SET `params` = '.$db->Quote($data).' WHERE '.
  219. "`option` = 'com_admintools' AND `parent` = 0 AND `menuid` = 0";
  220. }
  221. $db->setQuery($sql);
  222. $db->query();
  223. }
  224. /**
  225. * Is the Live Update supported on this server?
  226. * @return bool
  227. */
  228. public function isLiveUpdateSupported()
  229. {
  230. return $this->hasURLfopen() || $this->hascURL();
  231. }
  232. /**
  233. * Searches for updates and returns an object containing update information
  234. * @return JObject An object with members: supported, update_available,
  235. * current_version, current_date, latest_version, latest_date,
  236. * package_url
  237. */
  238. public function &getUpdates($force = false)
  239. {
  240. jimport('joomla.utilities.date');
  241. $ret = new JObject();
  242. if(!$this->isLiveUpdateSupported())
  243. {
  244. $ret->supported = false;
  245. $ret->update_available = false;
  246. return $ret;
  247. }
  248. else
  249. {
  250. $ret->supported = true;
  251. $update = $this->getLatestVersion($force);
  252. // FIX 2.3: Fail gracefully if the update data couldn't be retrieved
  253. if(!is_object($update) || ($update === false))
  254. {
  255. $ret->supported = false;
  256. $ret->update_available = false;
  257. return $ret;
  258. }
  259. // Check if we need to upgrade, by release date
  260. jimport('joomla.utilities.date');
  261. require_once JPATH_COMPONENT_ADMINISTRATOR.DS.'version.php';
  262. $curdate = new JDate(ADMINTOOLS_DATE);
  263. $curdate = $curdate->toUnix(false);
  264. $relobject = new JDate($update->reldate);
  265. $reldate = $relobject->toUnix(false);
  266. $ret->latest_date = $relobject->toFormat('%Y-%m-%d');
  267. $version = ADMINTOOLS_VERSION;
  268. if( preg_match('#^[0-9\.]*a[0-9\.]*#', $version) == 1 )
  269. {
  270. $status = 'alpha';
  271. } elseif( preg_match('#^[0-9\.]*b[0-9\.]*#', $version) == 1 )
  272. {
  273. $status = 'beta';
  274. } elseif( preg_match('#^[0-9\.]*$#', $version) == 1 )
  275. {
  276. $status = 'stable';
  277. } else {
  278. $status = 'svn';
  279. }
  280. $ret->update_available = ($reldate > $curdate);
  281. $ret->current_version = ADMINTOOLS_VERSION;
  282. $ret->current_date = ADMINTOOLS_DATE;
  283. $ret->current_status = $status;
  284. $ret->latest_version = $update->version;
  285. $ret->status = $update->status;
  286. $ret->package_url = $update->url;
  287. $ret->package_url_suffix = $update->urlsuffix;
  288. return $ret;
  289. }
  290. }
  291. function downloadPackage($url, $target)
  292. {
  293. jimport('joomla.filesystem.file');
  294. // PART I. CREATE AN OUTPUT FILE
  295. // I'm hating myself for this... It is ugly, UGLY and OUTRIGHT UGLY, but my users
  296. // seem to not be able to handle permissions of the tmp directory correctly. *sigh*
  297. // In order to better be safe than sorry, we create the file with JFile::write(),
  298. // try to write to it, or chmod it to all writable and reopen if we couldn't.
  299. // Brian, if you get to read this: I also dispose of the file later on, so don't
  300. // red-flag this component, okay?
  301. // i. Try to create the file with JFile
  302. $data = '';
  303. $result = JFile::write($target, $data);
  304. if($result === false) {
  305. // Uh-oh! JFile couldn't write to the file.
  306. return false;
  307. }
  308. // ii. Moment of truth: try to open write-only
  309. $fp = @fopen($target, 'wb');
  310. if( $fp === false )
  311. {
  312. // iii. The reason I hate myself right now: mess around w/ permissions
  313. // Try to chmod to all writable
  314. $fixpermsModel = JModel::getInstance('Fixperms','AdmintoolsModel');
  315. $fixpermsModel->chmod($target, 511);
  316. // Try to open for writing
  317. $fp = fopen($target, 'wb');
  318. // If we still can't write to it, let's fail
  319. if( $fp === false ) return false;
  320. }
  321. $use_fopen = false;
  322. if(function_exists('curl_exec'))
  323. {
  324. // By default, try using cURL
  325. $process = curl_init($url);
  326. curl_setopt($process, CURLOPT_AUTOREFERER, true);
  327. curl_setopt($process, CURLOPT_FAILONERROR, true);
  328. @curl_setopt($process, CURLOPT_FOLLOWLOCATION, true);
  329. curl_setopt($process, CURLOPT_HEADER, false);
  330. curl_setopt($process, CURLOPT_RETURNTRANSFER, true);
  331. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  332. curl_setopt($process, CURLOPT_CONNECTTIMEOUT, 10);
  333. curl_setopt($process, CURLOPT_TIMEOUT, 30);
  334. @curl_setopt($process, CURLOPT_MAXREDIRS, 20);
  335. // Pretend we are IE7, so that webservers play nice with us
  336. curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)');
  337. curl_setopt($process, CURLOPT_FILE, $fp);
  338. $result = curl_exec($process);
  339. curl_close($process);
  340. fclose($fp);
  341. clearstatcache();
  342. if( filesize($target) == 0 ) {
  343. // Sometimes cURL silently fails. Bad boy. Bad, bad boy!
  344. $use_fopen = true;
  345. $fp = @fopen($target, 'wb');
  346. }
  347. }
  348. else
  349. {
  350. $use_fopen = true;
  351. }
  352. if($use_fopen) {
  353. // Track errors
  354. $track_errors = ini_set('track_errors',true);
  355. // Open the URL for reading
  356. if(function_exists('stream_context_create')) {
  357. // PHP 5+ way (best)
  358. $httpopts = Array('user_agent'=>'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)');
  359. $context = stream_context_create( array( 'http' => $httpopts ) );
  360. $ih = @fopen($url, 'r', false, $context);
  361. } else {
  362. // PHP 4 way (actually, it's just a fallback as we can't run Admin Tools in PHP4)
  363. ini_set('user_agent', 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)');
  364. $ih = @fopen($url, 'r');
  365. }
  366. // If the fopen() fails, we fail.
  367. return false;
  368. // Download
  369. $bytes = 0;
  370. $result = true;
  371. while (!feof($ih) && $result)
  372. {
  373. $contents = fread($ih, 4096);
  374. if ($contents == false) {
  375. @fclose($ih);
  376. JError::raiseError('500',"Downloading $url failed after $bytes bytes");
  377. $result = false;
  378. } else {
  379. $bytes += strlen($contents);
  380. fwrite($fp, $contents);
  381. }
  382. }
  383. // Close the handlers
  384. @fclose($ih);
  385. @fclose($fp);
  386. }
  387. // In case something went foul, let's try to make things right
  388. if(function_exists('curl_exec') && ($result === false))
  389. {
  390. // I will try to download to memory and write to disk using JFile::write().
  391. // Note: when doing a full reinstall this will most likely cause a memory outage :p
  392. // By default, try using cURL
  393. $process = curl_init($url);
  394. curl_setopt($process, CURLOPT_AUTOREFERER, true);
  395. curl_setopt($process, CURLOPT_FAILONERROR, true);
  396. @curl_setopt($process, CURLOPT_FOLLOWLOCATION, true);
  397. curl_setopt($process, CURLOPT_HEADER, false);
  398. curl_setopt($process, CURLOPT_RETURNTRANSFER, true);
  399. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  400. curl_setopt($process, CURLOPT_CONNECTTIMEOUT, 10);
  401. curl_setopt($process, CURLOPT_TIMEOUT, 30);
  402. @curl_setopt($process, CURLOPT_MAXREDIRS, 20);
  403. // Pretend we are IE7, so that webservers play nice with us
  404. curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)');
  405. $result = curl_exec($process);
  406. curl_close($process);
  407. if($result !== false) {
  408. $result = JFile::write($target, $result);
  409. }
  410. }
  411. // If the process failed, we fail. Simple, huh?
  412. if($result === false) return false;
  413. // If the process succeedeed:
  414. // i. Fix the permissions to 0644
  415. $fixpermsModel = JModel::getInstance('Fixperms','AdmintoolsModel');
  416. $fixpermsModel->chmod($target, 0644);
  417. // ii. Return the base name
  418. return basename($target);
  419. }
  420. }