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

/administrator/components/com_admintools/liveupdate/classes/download.php

https://gitlab.com/endomorphosis/OLAAaction
PHP | 333 lines | 211 code | 44 blank | 78 comment | 46 complexity | d17c3a74e8313e47a9619ed8f205054e MD5 | raw file
  1. <?php
  2. /**
  3. * @package LiveUpdate
  4. * @copyright Copyright ©2011 Nicholas K. Dionysopoulos / AkeebaBackup.com
  5. * @license GNU LGPLv3 or later <http://www.gnu.org/copyleft/lesser.html>
  6. */
  7. defined('_JEXEC') or die();
  8. /**
  9. * Allows downloading packages over the web to your server
  10. */
  11. class LiveUpdateDownloadHelper
  12. {
  13. /**
  14. * Downloads from a URL and saves the result as a local file
  15. * @param <type> $url
  16. * @param <type> $target
  17. * @return bool True on success
  18. */
  19. public static function download($url, $target)
  20. {
  21. // Import Joomla! libraries
  22. jimport('joomla.filesystem.file');
  23. /** @var bool Did we try to force permissions? */
  24. $hackPermissions = false;
  25. // Make sure the target does not exist
  26. if(JFile::exists($target)) {
  27. if(!@unlink($target)) {
  28. JFile::delete($target);
  29. }
  30. }
  31. // Try to open the output file for writing
  32. $fp = @fopen($target, 'wb');
  33. if($fp === false) {
  34. // The file can not be opened for writing. Let's try a hack.
  35. if( JFile::write($target, '') ) {
  36. if( self::chmod($target, 511) ) {
  37. $fp = @fopen($target, 'wb');
  38. $hackPermissions = true;
  39. }
  40. }
  41. }
  42. $result = false;
  43. if($fp !== false)
  44. {
  45. // First try to download directly to file if $fp !== false
  46. $adapters = self::getAdapters();
  47. $result = false;
  48. while(!empty($adapters) && ($result === false)) {
  49. // Run the current download method
  50. $method = 'get' . strtoupper( array_shift($adapters) );
  51. $result = self::$method($url, $fp);
  52. // Check if we have a download
  53. if($result === true) {
  54. // The download is complete, close the file pointer
  55. @fclose($fp);
  56. // If the filesize is not at least 1 byte, we consider it failed.
  57. clearstatcache();
  58. $filesize = @filesize($target);
  59. if($filesize <= 0) {
  60. $result = false;
  61. $fp = @fopen($target, 'wb');
  62. }
  63. }
  64. }
  65. // If we have no download, close the file pointer
  66. if($result === false) {
  67. @fclose($fp);
  68. }
  69. }
  70. if($result === false)
  71. {
  72. // Delete the target file if it exists
  73. if(file_exists($target)) {
  74. if( !@unlink($target) ) {
  75. JFile::delete($target);
  76. }
  77. }
  78. // Download and write using JFile::write();
  79. $result = JFile::write($target, self::downloadAndReturn($url) );
  80. }
  81. return $result;
  82. }
  83. /**
  84. * Downloads from a URL and returns the result as a string
  85. * @param <type> $url
  86. * @return mixed Result string on success, false on failure
  87. */
  88. public static function downloadAndReturn($url)
  89. {
  90. $adapters = self::getAdapters();
  91. $result = false;
  92. while(!empty($adapters) && ($result === false)) {
  93. // Run the current download method
  94. $method = 'get' . strtoupper( array_shift($adapters) );
  95. $result = self::$method($url, null);
  96. }
  97. return $result;
  98. }
  99. /**
  100. * Does the server support PHP's cURL extension?
  101. * @return bool True if it is supported
  102. */
  103. private static function hasCURL()
  104. {
  105. static $result = null;
  106. if(is_null($result))
  107. {
  108. $result = function_exists('curl_init');
  109. }
  110. return $result;
  111. }
  112. /**
  113. * Downloads the contents of a URL and writes them to disk (if $fp is not null)
  114. * or returns them as a string (if $fp is null)
  115. * @param string $url The URL to download from
  116. * @param resource $fp The file pointer to download to. Omit to return the contents.
  117. * @return bool|string False on failure, true on success ($fp not null) or the URL contents (if $fp is null)
  118. */
  119. private static function &getCURL($url, $fp = null)
  120. {
  121. $result = false;
  122. $ch = curl_init($url);
  123. if( !@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1) ) {
  124. // Safe Mode is enabled. We have to fetch the headers and
  125. // parse any redirections present in there.
  126. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  127. curl_setopt($ch, CURLOPT_FAILONERROR, true);
  128. curl_setopt($ch, CURLOPT_HEADER, true);
  129. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  130. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  131. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  132. curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  133. // Get the headers
  134. $data = curl_exec($ch);
  135. curl_close($ch);
  136. // Init
  137. $newURL = $url;
  138. // Parse the headers
  139. $lines = explode("\n", $data);
  140. foreach($lines as $line) {
  141. if(substr($line, 0, 9) == "Location:") {
  142. $newURL = trim(substr($line,9));
  143. }
  144. }
  145. // Download from the new URL
  146. return self::getCURL($newURL, $fp);
  147. } else {
  148. @curl_setopt($ch, CURLOPT_MAXREDIRS, 20);
  149. }
  150. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  151. curl_setopt($ch, CURLOPT_FAILONERROR, true);
  152. curl_setopt($ch, CURLOPT_HEADER, false);
  153. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  154. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  155. curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
  156. curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  157. // Pretend we are IE7, so that webservers play nice with us
  158. curl_setopt($ch, 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)');
  159. if(is_resource($fp)) {
  160. curl_setopt($ch, CURLOPT_FILE, $fp);
  161. }
  162. $result = curl_exec($ch);
  163. curl_close($ch);
  164. return $result;
  165. }
  166. /**
  167. * Does the server support URL fopen() wrappers?
  168. * @return bool
  169. */
  170. private static function hasFOPEN()
  171. {
  172. static $result = null;
  173. if(is_null($result))
  174. {
  175. // If we are not allowed to use ini_get, we assume that URL fopen is
  176. // disabled.
  177. if(!function_exists('ini_get')) {
  178. $result = false;
  179. } else {
  180. $result = ini_get('allow_url_fopen');
  181. }
  182. }
  183. return $result;
  184. }
  185. private static function &getFOPEN($url, $fp = null)
  186. {
  187. $result = false;
  188. // Track errors
  189. if( function_exists('ini_set') ) {
  190. $track_errors = ini_set('track_errors',true);
  191. }
  192. // Open the URL for reading
  193. if(function_exists('stream_context_create')) {
  194. // PHP 5+ way (best)
  195. $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)');
  196. $context = stream_context_create( array( 'http' => $httpopts ) );
  197. $ih = @fopen($url, 'r', false, $context);
  198. } else {
  199. // PHP 4 way (actually, it's just a fallback as we can't run Admin Tools in PHP4)
  200. if( function_exists('ini_set') ) {
  201. 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)');
  202. }
  203. $ih = @fopen($url, 'r');
  204. }
  205. // If fopen() fails, abort
  206. if( !is_resource($ih) ) {
  207. return $result;
  208. }
  209. // Try to download
  210. $bytes = 0;
  211. $result = true;
  212. $return = '';
  213. while (!feof($ih) && $result)
  214. {
  215. $contents = fread($ih, 4096);
  216. if ($contents === false) {
  217. @fclose($ih);
  218. $result = false;
  219. return $result;
  220. } else {
  221. $bytes += strlen($contents);
  222. if(is_resource($fp)) {
  223. $result = @fwrite($fp, $contents);
  224. } else {
  225. $return .= $contents;
  226. unset($contents);
  227. }
  228. }
  229. }
  230. @fclose($ih);
  231. if(is_resource($fp)) {
  232. return $result;
  233. } elseif( $result === true ) {
  234. return $return;
  235. } else {
  236. return $result;
  237. }
  238. }
  239. /**
  240. * Detect and return available download adapters
  241. * @return array
  242. */
  243. private static function getAdapters()
  244. {
  245. // Detect available adapters
  246. $adapters = array();
  247. if(self::hasCURL()) $adapters[] = 'curl';
  248. if(self::hasFOPEN()) $adapters[] = 'fopen';
  249. return $adapters;
  250. }
  251. /**
  252. * Change the permissions of a file, optionally using FTP
  253. * @param string $file Absolute path to file
  254. * @param int $mode Permissions, e.g. 0755
  255. */
  256. private static function chmod($path, $mode)
  257. {
  258. if(is_string($mode))
  259. {
  260. $mode = octdec($mode);
  261. if( ($mode < 0600) || ($mode > 0777) ) $mode = 0755;
  262. }
  263. // Initialize variables
  264. jimport('joomla.client.helper');
  265. $ftpOptions = JClientHelper::getCredentials('ftp');
  266. // Check to make sure the path valid and clean
  267. $path = JPath::clean($path);
  268. if ($ftpOptions['enabled'] == 1) {
  269. // Connect the FTP client
  270. jimport('joomla.client.ftp');
  271. $ftp = &JFTP::getInstance(
  272. $ftpOptions['host'], $ftpOptions['port'], null,
  273. $ftpOptions['user'], $ftpOptions['pass']
  274. );
  275. }
  276. if(@chmod($path, $mode))
  277. {
  278. $ret = true;
  279. } elseif ($ftpOptions['enabled'] == 1) {
  280. // Translate path and delete
  281. jimport('joomla.client.ftp');
  282. $path = JPath::clean(str_replace(JPATH_ROOT, $ftpOptions['root'], $path), '/');
  283. // FTP connector throws an error
  284. $ret = $ftp->chmod($path, $mode);
  285. } else {
  286. return false;
  287. }
  288. }
  289. }