PageRenderTime 26ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/iCagenda/admin/liveupdate/classes/updatefetch.php

https://gitlab.com/Alzakath/icagenda
PHP | 357 lines | 222 code | 55 blank | 80 comment | 46 complexity | 7e552c91fe3b4a70ca1260b60ed874a7 MD5 | raw file
  1. <?php
  2. /**
  3. *------------------------------------------------------------------------------
  4. * iCagenda v3 by Jooml!C - Events Management Extension for Joomla! 2.5 / 3.x
  5. *------------------------------------------------------------------------------
  6. *
  7. * @package LiveUpdate 2.1.5 - 2.2.1
  8. * @copyright Copyright (c)2010-2013 Nicholas K. Dionysopoulos / AkeebaBackup.com
  9. * @license GNU LGPLv3 or later <http://www.gnu.org/copyleft/lesser.html>
  10. *
  11. * @version 3.1.7 2013-08-28
  12. * @since 1.2.6
  13. */
  14. defined('_JEXEC') or die();
  15. /**
  16. * Fetches the update information from the server or the cache, depending on
  17. * whether the cache is fresh or not.
  18. */
  19. class LiveUpdateFetch extends JObject
  20. {
  21. private $cacheTTL = 24;
  22. private $storage = null;
  23. /**
  24. * One-stop-shop function which fetches update information and tells you
  25. * if there are updates available or not, or if updates are not supported.
  26. *
  27. * @return int 0 = no updates, 1 = updates available, -1 = updates not supported, -2 = fetching updates crashes the server
  28. */
  29. public function hasUpdates($force = false)
  30. {
  31. $updateInfo = $this->getUpdateInformation($force);
  32. if($updateInfo->stuck) return -2;
  33. if(!$updateInfo->supported) return -1;
  34. $config = LiveUpdateConfig::getInstance();
  35. $extInfo = $config->getExtensionInformation();
  36. // Filter by stability level
  37. $minStability = $config->getMinimumStability();
  38. $stability = strtolower($updateInfo->stability);
  39. switch($minStability) {
  40. case 'alpha':
  41. default:
  42. // Reports any stability level as an available update
  43. break;
  44. case 'beta':
  45. // Do not report alphas as available updates
  46. if(in_array($stability, array('alpha'))) return 0;
  47. break;
  48. case 'rc':
  49. // Do not report alphas and betas as available updates
  50. if(in_array($stability, array('alpha','beta'))) return 0;
  51. break;
  52. case 'stable':
  53. // Do not report alphas, betas and rcs as available updates
  54. if(in_array($stability, array('alpha','beta','rc'))) return 0;
  55. break;
  56. }
  57. if(empty($updateInfo->version) && empty($updateInfo->date)) return 0;
  58. // Use the version strategy to determine the availability of an update
  59. switch($config->getVersionStrategy()) {
  60. case 'newest':
  61. JLoader::import('joomla.utilities.date');
  62. if(empty($extInfo)) {
  63. $mine = new JDate('2000-01-01 00:00:00');
  64. } else {
  65. try {
  66. $mine = new JDate($extInfo['date']);
  67. } catch(Exception $e) {
  68. $mine = new JDate('2000-01-01 00:00:00');
  69. }
  70. }
  71. $theirs = new JDate($updateInfo->date);
  72. return ($theirs->toUnix() > $mine->toUnix()) ? 1 : 0;
  73. break;
  74. case 'vcompare':
  75. $mine = $extInfo['version'];
  76. if(empty($mine)) $mine = '0.0.0';
  77. $theirs = $updateInfo->version;
  78. if(empty($theirs)) $theirs = '0.0.0';
  79. return (version_compare($theirs, $mine, 'gt')) ? 1 : 0;
  80. break;
  81. case 'different':
  82. $mine = $extInfo['version'];
  83. if(empty($mine)) $mine = '0.0.0';
  84. $theirs = $updateInfo->version;
  85. if(empty($theirs)) $theirs = '0.0.0';
  86. return ($theirs != $mine) ? 1 : 0;
  87. break;
  88. }
  89. }
  90. /**
  91. * Get the latest version (update) information, either from the cache or
  92. * from the update server.
  93. *
  94. * @param $force bool Set to true to force fetching fresh data from the server
  95. *
  96. * @return stdClass The update information, in object format
  97. */
  98. public function getUpdateInformation($force = false)
  99. {
  100. // Get the Live Update configuration
  101. $config = LiveUpdateConfig::getInstance();
  102. // Get an instance of the storage class
  103. $storageOptions = $config->getStorageAdapterPreferences();
  104. require_once dirname(__FILE__).'/storage/storage.php';
  105. $this->storage = LiveUpdateStorage::getInstance($storageOptions['adapter'], $storageOptions['config']);
  106. // If we are requested to forcibly reload the information, clear old data first
  107. if($force) {
  108. $this->storage->set('lastcheck', null);
  109. $this->storage->set('updatedata', null);
  110. $this->storage->save();
  111. }
  112. // Fetch information from the cache
  113. $lastCheck = $this->storage->get('lastcheck', 0);
  114. $cachedData = $this->storage->get('updatedata', null);
  115. if (!is_object($cachedData))
  116. {
  117. $cachedData = null;
  118. }
  119. if(empty($cachedData)) {
  120. $lastCheck = 0;
  121. }
  122. // Check if the cache is at most $cacheTTL hours old
  123. $now = time();
  124. $maxDifference = $this->cacheTTL * 3600;
  125. $difference = abs($now - $lastCheck);
  126. if(!($force) && ($difference <= $maxDifference)) {
  127. // The cache is fresh enough; return cached data
  128. return $cachedData;
  129. } else {
  130. // The cache is stale; fetch new data, cache it and return it to the caller
  131. $data = $this->getUpdateData($force);
  132. $this->storage->set('lastcheck', $now);
  133. $this->storage->set('updatedata', $data);
  134. $this->storage->save();
  135. return $data;
  136. }
  137. }
  138. /**
  139. * Retrieves the update data from the server, unless previous runs indicate
  140. * that the download process gets stuck and ends up in a WSOD.
  141. *
  142. * @param bool $force Set to true to force fetching new data no matter if the process is marked as stuck
  143. * @return stdClass
  144. */
  145. private function getUpdateData($force = false)
  146. {
  147. $ret = array(
  148. 'supported' => false,
  149. 'stuck' => true,
  150. 'version' => '',
  151. 'date' => '',
  152. 'stability' => '',
  153. 'downloadURL' => '',
  154. 'infoURL' => '',
  155. 'releasenotes' => ''
  156. );
  157. // If the process is marked as "stuck", we won't bother fetching data again; well,
  158. // unless you really force me to, by setting $force = true.
  159. if( ($this->storage->get('stuck',0) != 0) && !$force) return (object)$ret;
  160. $ret['stuck'] = false;
  161. require_once dirname(__FILE__).'/download.php';
  162. // First we mark Live Updates as getting stuck. This way, if fetching the update
  163. // fails with a server error, reloading the page will not result to a White Screen
  164. // of Death again. Hey, Joomla! core team, are you listening? Some hosts PRETEND to
  165. // support cURL or URL fopen() wrappers but using them throws an immediate WSOD.
  166. $this->storage->set('stuck', 1);
  167. $this->storage->save();
  168. $config = LiveUpdateConfig::getInstance();
  169. $extInfo = $config->getExtensionInformation();
  170. $url = $extInfo['updateurl'];
  171. $rawData = LiveUpdateDownloadHelper::downloadAndReturn($url);
  172. // Now that we have some data returned, let's unmark the process as being stuck ;)
  173. $this->storage->set('stuck', 0);
  174. $this->storage->save();
  175. // If we didn't get anything, assume Live Update is not supported (communication error)
  176. if(empty($rawData) || ($rawData == false)) return (object)$ret;
  177. // TODO Detect the content type of the returned update stream. For now, I will pretend it's an INI file.
  178. $data = $this->parseINI($rawData);
  179. $ret['supported'] = true;
  180. return (object)array_merge($ret, $data);
  181. }
  182. /**
  183. * Fetches update information from the server using cURL
  184. * @return string The raw server data
  185. */
  186. private function fetchCURL()
  187. {
  188. $config = LiveUpdateConfig::getInstance();
  189. $extInfo = $config->getExtensionInformation();
  190. $url = $extInfo['updateurl'];
  191. $process = curl_init($url);
  192. $config = new LiveUpdateConfig();
  193. $config->applyCACert($process);
  194. curl_setopt($process, CURLOPT_HEADER, 0);
  195. // Pretend we are Firefox, so that webservers play nice with us
  196. curl_setopt($process, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.14) Gecko/20110105 Firefox/3.6.14');
  197. curl_setopt($process, CURLOPT_ENCODING, 'gzip');
  198. curl_setopt($process, CURLOPT_TIMEOUT, 10);
  199. curl_setopt($process, CURLOPT_RETURNTRANSFER, 1);
  200. curl_setopt($process, CURLOPT_SSL_VERIFYPEER, false);
  201. // The @ sign allows the next line to fail if open_basedir is set or if safe mode is enabled
  202. @curl_setopt($process, CURLOPT_FOLLOWLOCATION, 1);
  203. @curl_setopt($process, CURLOPT_MAXREDIRS, 20);
  204. $inidata = curl_exec($process);
  205. curl_close($process);
  206. return $inidata;
  207. }
  208. /**
  209. * Fetches update information from the server using file_get_contents, which internally
  210. * uses URL fopen() wrappers.
  211. * @return string The raw server data
  212. */
  213. private function fetchFOPEN()
  214. {
  215. $config = LiveUpdateConfig::getInstance();
  216. $extInfo = $config->getExtensionInformation();
  217. $url = $extInfo['updateurl'];
  218. return @file_get_contents($url);
  219. }
  220. /**
  221. * Parses the raw INI data into an array of update information
  222. * @param string $rawData The raw INI data
  223. * @return array The parsed data
  224. */
  225. private function parseINI($rawData)
  226. {
  227. $ret = array(
  228. 'version' => '',
  229. 'date' => '',
  230. 'stability' => '',
  231. 'downloadURL' => '',
  232. 'infoURL' => '',
  233. 'releasenotes' => ''
  234. );
  235. // Get the magic string
  236. $magicPos = strpos($rawData, '; Live Update provision file');
  237. if($magicPos === false) {
  238. // That's not an INI file :(
  239. return $ret;
  240. }
  241. if($magicPos !== 0) {
  242. $rawData = substr($rawData, $magicPos);
  243. }
  244. require_once dirname(__FILE__).'/inihelper.php';
  245. $iniData = LiveUpdateINIHelper::parse_ini_file($rawData, false, true);
  246. // Get the supported platforms
  247. $supportedPlatform = false;
  248. $versionParts = explode('.',JVERSION);
  249. $currentPlatform = $versionParts[0].'.'.$versionParts[1];
  250. if(array_key_exists('platforms', $iniData)) {
  251. $rawPlatforms = explode(',', $iniData['platforms']);
  252. foreach($rawPlatforms as $platform) {
  253. $platform = trim($platform);
  254. if(substr($platform,0,7) != 'joomla/') {
  255. continue;
  256. }
  257. $platform = substr($platform, 7);
  258. if($currentPlatform == $platform) {
  259. $supportedPlatform = true;
  260. }
  261. }
  262. } else {
  263. // Lies, damn lies
  264. $supportedPlatform = true;
  265. }
  266. if(!$supportedPlatform) {
  267. return $ret;
  268. }
  269. $ret['version'] = array_key_exists('version', $iniData) ? $iniData['version'] : '';
  270. $ret['date'] = array_key_exists('date', $iniData) ? $iniData['date'] : '';
  271. $config = LiveUpdateConfig::getInstance();
  272. $auth = $config->getAuthorization();
  273. if(!array_key_exists('link', $iniData)) $iniData['link'] = '';
  274. $glue = strpos($iniData['link'],'?') === false ? '?' : '&';
  275. $ret['downloadURL'] = $iniData['link'] . (empty($auth) ? '' : $glue.$auth);
  276. if(array_key_exists('stability', $iniData)) {
  277. $stability = $iniData['stability'];
  278. } else {
  279. // Stability not defined; guesswork mode enabled
  280. $version = $ret['version'];
  281. if( preg_match('#^[0-9\.]*a[0-9\.]*#', $version) == 1 ) {
  282. $stability = 'alpha';
  283. } elseif( preg_match('#^[0-9\.]*b[0-9\.]*#', $version) == 1 ) {
  284. $stability = 'beta';
  285. } elseif( preg_match('#^[0-9\.]*rc[0-9\.]*#', $version) == 1 ) {
  286. $stability = 'rc';
  287. } elseif( preg_match('#^[0-9\.]*$#', $version) == 1 ) {
  288. $stability = 'stable';
  289. } else {
  290. $stability = 'svn';
  291. }
  292. }
  293. $ret['stability'] = $stability;
  294. if(array_key_exists('releasenotes', $iniData)) {
  295. $ret['releasenotes'] = $iniData['releasenotes'];
  296. }
  297. if(array_key_exists('infourl', $iniData)) {
  298. $ret['infoURL'] = $iniData['infourl'];
  299. }
  300. return $ret;
  301. }
  302. }