PageRenderTime 45ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/src/libraries/fof/download/adapter/curl.php

https://bitbucket.org/ke2083/transfans.co.uk-website
PHP | 226 lines | 143 code | 36 blank | 47 comment | 24 complexity | 04e54559d88173b6b118054b1d4dbd20 MD5 | raw file
  1. <?php
  2. /**
  3. * @package FrameworkOnFramework
  4. * @subpackage dispatcher
  5. * @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
  6. * @license GNU General Public License version 2 or later; see LICENSE.txt
  7. */
  8. // Protect from unauthorized access
  9. defined('FOF_INCLUDED') or die;
  10. /**
  11. * A download adapter using the cURL PHP module
  12. */
  13. class FOFDownloadAdapterCurl extends FOFDownloadAdapterAbstract implements FOFDownloadInterface
  14. {
  15. protected $headers = array();
  16. public function __construct()
  17. {
  18. $this->priority = 110;
  19. $this->supportsFileSize = true;
  20. $this->supportsChunkDownload = true;
  21. $this->name = 'curl';
  22. $this->isSupported = function_exists('curl_init') && function_exists('curl_exec') && function_exists('curl_close');
  23. }
  24. /**
  25. * Download a part (or the whole) of a remote URL and return the downloaded
  26. * data. You are supposed to check the size of the returned data. If it's
  27. * smaller than what you expected you've reached end of file. If it's empty
  28. * you have tried reading past EOF. If it's larger than what you expected
  29. * the server doesn't support chunk downloads.
  30. *
  31. * If this class' supportsChunkDownload returns false you should assume
  32. * that the $from and $to parameters will be ignored.
  33. *
  34. * @param string $url The remote file's URL
  35. * @param integer $from Byte range to start downloading from. Use null for start of file.
  36. * @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is ignored)
  37. * @param array $params Additional params that will be added before performing the download
  38. *
  39. * @return string The raw file data retrieved from the remote URL.
  40. *
  41. * @throws Exception A generic exception is thrown on error
  42. */
  43. public function downloadAndReturn($url, $from = null, $to = null, array $params = array())
  44. {
  45. $ch = curl_init();
  46. if (empty($from))
  47. {
  48. $from = 0;
  49. }
  50. if (empty($to))
  51. {
  52. $to = 0;
  53. }
  54. if ($to < $from)
  55. {
  56. $temp = $to;
  57. $to = $from;
  58. $from = $temp;
  59. unset($temp);
  60. }
  61. // Default cURL options
  62. $options = array(
  63. CURLOPT_AUTOREFERER => 1,
  64. CURLOPT_SSL_VERIFYPEER => 1,
  65. CURLOPT_SSL_VERIFYHOST => 2,
  66. CURLOPT_SSLVERSION => 0,
  67. CURLOPT_AUTOREFERER => 1,
  68. CURLOPT_URL => $url,
  69. CURLOPT_BINARYTRANSFER => 1,
  70. CURLOPT_RETURNTRANSFER => 1,
  71. CURLOPT_FOLLOWLOCATION => 1,
  72. CURLOPT_CAINFO => __DIR__ . '/cacert.pem',
  73. CURLOPT_HEADERFUNCTION => array($this, 'reponseHeaderCallback')
  74. );
  75. if (!(empty($from) && empty($to)))
  76. {
  77. $options[CURLOPT_RANGE] = "$from-$to";
  78. }
  79. // Add any additional options: Since they are numeric, we must use the array operator. If the jey exists in both
  80. // arrays, only the first one will be used while the second one will be ignored
  81. $options = $params + $options;
  82. @curl_setopt_array($ch, $options);
  83. $this->headers = array();
  84. $result = curl_exec($ch);
  85. $errno = curl_errno($ch);
  86. $errmsg = curl_error($ch);
  87. $http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  88. if ($result === false)
  89. {
  90. $error = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_CURL_ERROR', $errno, $errmsg);
  91. }
  92. elseif (($http_status >= 300) && ($http_status <= 399) && isset($this->headers['Location']) && !empty($this->headers['Location']))
  93. {
  94. return $this->downloadAndReturn($this->headers['Location'], $from, $to, $params);
  95. }
  96. elseif ($http_status > 399)
  97. {
  98. $result = false;
  99. $errno = $http_status;
  100. $error = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_HTTPERROR', $http_status);
  101. }
  102. curl_close($ch);
  103. if ($result === false)
  104. {
  105. throw new Exception($error, $errno);
  106. }
  107. else
  108. {
  109. return $result;
  110. }
  111. }
  112. /**
  113. * Get the size of a remote file in bytes
  114. *
  115. * @param string $url The remote file's URL
  116. *
  117. * @return integer The file size, or -1 if the remote server doesn't support this feature
  118. */
  119. public function getFileSize($url)
  120. {
  121. $result = -1;
  122. $ch = curl_init();
  123. curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
  124. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
  125. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  126. curl_setopt($ch, CURLOPT_SSLVERSION, 0);
  127. curl_setopt($ch, CURLOPT_URL, $url);
  128. curl_setopt($ch, CURLOPT_NOBODY, true );
  129. curl_setopt($ch, CURLOPT_HEADER, true );
  130. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
  131. @curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
  132. @curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/cacert.pem');
  133. $data = curl_exec($ch);
  134. curl_close($ch);
  135. if ($data)
  136. {
  137. $content_length = "unknown";
  138. $status = "unknown";
  139. $redirection = null;
  140. if (preg_match( "/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches))
  141. {
  142. $status = (int)$matches[1];
  143. }
  144. if (preg_match( "/Content-Length: (\d+)/", $data, $matches))
  145. {
  146. $content_length = (int)$matches[1];
  147. }
  148. if (preg_match( "/Location: (.*)/", $data, $matches))
  149. {
  150. $redirection = (int)$matches[1];
  151. }
  152. if ($status == 200)
  153. {
  154. $result = $content_length;
  155. }
  156. if (($status > 300) && ($status <= 308))
  157. {
  158. if (!empty($redirection))
  159. {
  160. return $this->getFileSize($redirection);
  161. }
  162. return -1;
  163. }
  164. }
  165. return $result;
  166. }
  167. /**
  168. * Handles the HTTP headers returned by cURL
  169. *
  170. * @param resource $ch cURL resource handle (unused)
  171. * @param string $data Each header line, as returned by the server
  172. *
  173. * @return int The length of the $data string
  174. */
  175. protected function reponseHeaderCallback(&$ch, &$data)
  176. {
  177. $strlen = strlen($data);
  178. if (($strlen) <= 2)
  179. {
  180. return $strlen;
  181. }
  182. if (substr($data, 0, 4) == 'HTTP')
  183. {
  184. return $strlen;
  185. }
  186. list($header, $value) = explode(': ', trim($data), 2);
  187. $this->headers[$header] = $value;
  188. return $strlen;
  189. }
  190. }