primo commit

This commit is contained in:
2024-12-17 17:34:10 +01:00
commit e650f8df99
16435 changed files with 2451012 additions and 0 deletions

View File

@ -0,0 +1,113 @@
<?php
/**
* @package FrameworkOnFramework
* @subpackage dispatcher
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Protect from unauthorized access
defined('F0F_INCLUDED') or die;
/**
* Abstract base class for download adapters
*/
abstract class F0FDownloadAdapterAbstract implements F0FDownloadInterface
{
public $priority = 100;
public $name = '';
public $isSupported = false;
public $supportsChunkDownload = false;
public $supportsFileSize = false;
/**
* Does this download adapter support downloading files in chunks?
*
* @return boolean True if chunk download is supported
*/
public function supportsChunkDownload()
{
return $this->supportsChunkDownload;
}
/**
* Does this download adapter support reading the size of a remote file?
*
* @return boolean True if remote file size determination is supported
*/
public function supportsFileSize()
{
return $this->supportsFileSize;
}
/**
* Is this download class supported in the current server environment?
*
* @return boolean True if this server environment supports this download class
*/
public function isSupported()
{
return $this->isSupported;
}
/**
* Get the priority of this adapter. If multiple download adapters are
* supported on a site, the one with the highest priority will be
* used.
*
* @return boolean
*/
public function getPriority()
{
return $this->priority;
}
/**
* Returns the name of this download adapter in use
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Download a part (or the whole) of a remote URL and return the downloaded
* data. You are supposed to check the size of the returned data. If it's
* smaller than what you expected you've reached end of file. If it's empty
* you have tried reading past EOF. If it's larger than what you expected
* the server doesn't support chunk downloads.
*
* If this class' supportsChunkDownload returns false you should assume
* that the $from and $to parameters will be ignored.
*
* @param string $url The remote file's URL
* @param integer $from Byte range to start downloading from. Use null for start of file.
* @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is ignored)
* @param array $params Additional params that will be added before performing the download
*
* @return string The raw file data retrieved from the remote URL.
*
* @throws Exception A generic exception is thrown on error
*/
public function downloadAndReturn($url, $from = null, $to = null, array $params = array())
{
return '';
}
/**
* Get the size of a remote file in bytes
*
* @param string $url The remote file's URL
*
* @return integer The file size, or -1 if the remote server doesn't support this feature
*/
public function getFileSize($url)
{
return -1;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
<?php
/**
* @package FrameworkOnFramework
* @subpackage dispatcher
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Protect from unauthorized access
defined('F0F_INCLUDED') or die;
/**
* A download adapter using the cURL PHP module
*/
class F0FDownloadAdapterCurl extends F0FDownloadAdapterAbstract implements F0FDownloadInterface
{
protected $headers = array();
public function __construct()
{
$this->priority = 110;
$this->supportsFileSize = true;
$this->supportsChunkDownload = true;
$this->name = 'curl';
$this->isSupported = function_exists('curl_init') && function_exists('curl_exec') && function_exists('curl_close');
}
/**
* Download a part (or the whole) of a remote URL and return the downloaded
* data. You are supposed to check the size of the returned data. If it's
* smaller than what you expected you've reached end of file. If it's empty
* you have tried reading past EOF. If it's larger than what you expected
* the server doesn't support chunk downloads.
*
* If this class' supportsChunkDownload returns false you should assume
* that the $from and $to parameters will be ignored.
*
* @param string $url The remote file's URL
* @param integer $from Byte range to start downloading from. Use null for start of file.
* @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is ignored)
* @param array $params Additional params that will be added before performing the download
*
* @return string The raw file data retrieved from the remote URL.
*
* @throws Exception A generic exception is thrown on error
*/
public function downloadAndReturn($url, $from = null, $to = null, array $params = array())
{
$ch = curl_init();
if (empty($from))
{
$from = 0;
}
if (empty($to))
{
$to = 0;
}
if ($to < $from)
{
$temp = $to;
$to = $from;
$from = $temp;
unset($temp);
}
// Default cURL options
$options = array(
CURLOPT_AUTOREFERER => 1,
CURLOPT_SSL_VERIFYPEER => 1,
CURLOPT_SSL_VERIFYHOST => 2,
CURLOPT_SSLVERSION => 0,
CURLOPT_AUTOREFERER => 1,
CURLOPT_URL => $url,
CURLOPT_BINARYTRANSFER => 1,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_CAINFO => __DIR__ . '/cacert.pem',
CURLOPT_HEADERFUNCTION => array($this, 'reponseHeaderCallback')
);
if (!(empty($from) && empty($to)))
{
$options[CURLOPT_RANGE] = "$from-$to";
}
// Add any additional options: Since they are numeric, we must use the array operator. If the jey exists in both
// arrays, only the first one will be used while the second one will be ignored
$options = $params + $options;
@curl_setopt_array($ch, $options);
$this->headers = array();
$result = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
$http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($result === false)
{
$error = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_CURL_ERROR', $errno, $errmsg);
}
elseif (($http_status >= 300) && ($http_status <= 399) && isset($this->headers['Location']) && !empty($this->headers['Location']))
{
return $this->downloadAndReturn($this->headers['Location'], $from, $to, $params);
}
elseif ($http_status > 399)
{
$result = false;
$errno = $http_status;
$error = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_HTTPERROR', $http_status);
}
curl_close($ch);
if ($result === false)
{
throw new Exception($error, $errno);
}
else
{
return $result;
}
}
/**
* Get the size of a remote file in bytes
*
* @param string $url The remote file's URL
*
* @return integer The file size, or -1 if the remote server doesn't support this feature
*/
public function getFileSize($url)
{
$result = -1;
$ch = curl_init();
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSLVERSION, 0);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_NOBODY, true );
curl_setopt($ch, CURLOPT_HEADER, true );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true );
@curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true );
@curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/cacert.pem');
$data = curl_exec($ch);
curl_close($ch);
if ($data)
{
$content_length = "unknown";
$status = "unknown";
$redirection = null;
if (preg_match( "/^HTTP\/1\.[01] (\d\d\d)/", $data, $matches))
{
$status = (int)$matches[1];
}
if (preg_match( "/Content-Length: (\d+)/", $data, $matches))
{
$content_length = (int)$matches[1];
}
if (preg_match( "/Location: (.*)/", $data, $matches))
{
$redirection = (int)$matches[1];
}
if ($status == 200)
{
$result = $content_length;
}
if (($status > 300) && ($status <= 308))
{
if (!empty($redirection))
{
return $this->getFileSize($redirection);
}
return -1;
}
}
return $result;
}
/**
* Handles the HTTP headers returned by cURL
*
* @param resource $ch cURL resource handle (unused)
* @param string $data Each header line, as returned by the server
*
* @return int The length of the $data string
*/
protected function reponseHeaderCallback(&$ch, &$data)
{
$strlen = strlen($data);
if (($strlen) <= 2)
{
return $strlen;
}
if (substr($data, 0, 4) == 'HTTP')
{
return $strlen;
}
list($header, $value) = explode(': ', trim($data), 2);
$this->headers[$header] = $value;
return $strlen;
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* @package FrameworkOnFramework
* @subpackage dispatcher
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Protect from unauthorized access
defined('F0F_INCLUDED') or die;
/**
* A download adapter using URL fopen() wrappers
*/
class F0FDownloadAdapterFopen extends F0FDownloadAdapterAbstract implements F0FDownloadInterface
{
public function __construct()
{
$this->priority = 100;
$this->supportsFileSize = false;
$this->supportsChunkDownload = true;
$this->name = 'fopen';
// If we are not allowed to use ini_get, we assume that URL fopen is
// disabled.
if (!function_exists('ini_get'))
{
$this->isSupported = false;
}
else
{
$this->isSupported = ini_get('allow_url_fopen');
}
}
/**
* Download a part (or the whole) of a remote URL and return the downloaded
* data. You are supposed to check the size of the returned data. If it's
* smaller than what you expected you've reached end of file. If it's empty
* you have tried reading past EOF. If it's larger than what you expected
* the server doesn't support chunk downloads.
*
* If this class' supportsChunkDownload returns false you should assume
* that the $from and $to parameters will be ignored.
*
* @param string $url The remote file's URL
* @param integer $from Byte range to start downloading from. Use null for start of file.
* @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is ignored)
* @param array $params Additional params that will be added before performing the download
*
* @return string The raw file data retrieved from the remote URL.
*
* @throws Exception A generic exception is thrown on error
*/
public function downloadAndReturn($url, $from = null, $to = null, array $params = array())
{
if (empty($from))
{
$from = 0;
}
if (empty($to))
{
$to = 0;
}
if ($to < $from)
{
$temp = $to;
$to = $from;
$from = $temp;
unset($temp);
}
if (!(empty($from) && empty($to)))
{
$options = array(
'http' => array(
'method' => 'GET',
'header' => "Range: bytes=$from-$to\r\n"
),
'ssl' => array(
'verify_peer' => true,
'cafile' => __DIR__ . '/cacert.pem',
'verify_depth' => 5,
)
);
$options = array_merge($options, $params);
$context = stream_context_create($options);
$result = @file_get_contents($url, false, $context, $from - $to + 1);
}
else
{
$options = array(
'http' => array(
'method' => 'GET',
),
'ssl' => array(
'verify_peer' => true,
'cafile' => __DIR__ . '/cacert.pem',
'verify_depth' => 5,
)
);
$options = array_merge($options, $params);
$context = stream_context_create($options);
$result = @file_get_contents($url, false, $context);
}
if ($result === false)
{
$error = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_HTTPERROR');
throw new Exception($error, 1);
}
else
{
return $result;
}
}
}

View File

@ -0,0 +1,495 @@
<?php
/**
* @package FrameworkOnFramework
* @subpackage dispatcher
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Protect from unauthorized access
defined('F0F_INCLUDED') or die;
class F0FDownload
{
/**
* Parameters passed from the GUI when importing from URL
*
* @var array
*/
private $params = array();
/**
* The download adapter which will be used by this class
*
* @var F0FDownloadInterface
*/
private $adapter = null;
/**
* Additional params that will be passed to the adapter while performing the download
*
* @var array
*/
private $adapterOptions = array();
/**
* Creates a new download object and assigns it the most fitting download adapter
*/
public function __construct()
{
// Find the best fitting adapter
$allAdapters = self::getFiles(__DIR__ . '/adapter', array(), array('abstract.php'));
$priority = 0;
foreach ($allAdapters as $adapterInfo)
{
if (!class_exists($adapterInfo['classname'], true))
{
continue;
}
/** @var F0FDownloadAdapterAbstract $adapter */
$adapter = new $adapterInfo['classname'];
if ( !$adapter->isSupported())
{
continue;
}
if ($adapter->priority > $priority)
{
$this->adapter = $adapter;
$priority = $adapter->priority;
}
}
// Load the language strings
F0FPlatform::getInstance()->loadTranslations('lib_f0f');
}
/**
* Forces the use of a specific adapter
*
* @param string $className The name of the class or the name of the adapter, e.g. 'F0FDownloadAdapterCurl' or
* 'curl'
*/
public function setAdapter($className)
{
$adapter = null;
if (class_exists($className, true))
{
$adapter = new $className;
}
elseif (class_exists('F0FDownloadAdapter' . ucfirst($className)))
{
$className = 'F0FDownloadAdapter' . ucfirst($className);
$adapter = new $className;
}
if (is_object($adapter) && ($adapter instanceof F0FDownloadInterface))
{
$this->adapter = $adapter;
}
}
/**
* Returns the name of the current adapter
*
* @return string
*/
public function getAdapterName()
{
if(is_object($this->adapter))
{
$class = get_class($this->adapter);
return strtolower(str_ireplace('F0FDownloadAdapter', '', $class));
}
return '';
}
/**
* Sets the additional options for the adapter
*
* @param array $options
*/
public function setAdapterOptions(array $options)
{
$this->adapterOptions = $options;
}
/**
* Returns the additional options for the adapter
*
* @return array
*/
public function getAdapterOptions()
{
return $this->adapterOptions;
}
/**
* Used to decode the $params array
*
* @param string $key The parameter key you want to retrieve the value for
* @param mixed $default The default value, if none is specified
*
* @return mixed The value for this parameter key
*/
private function getParam($key, $default = null)
{
if (array_key_exists($key, $this->params))
{
return $this->params[$key];
}
else
{
return $default;
}
}
/**
* Download data from a URL and return it
*
* @param string $url The URL to download from
*
* @return bool|string The downloaded data or false on failure
*/
public function getFromURL($url)
{
try
{
return $this->adapter->downloadAndReturn($url, null, null, $this->adapterOptions);
}
catch (Exception $e)
{
return false;
}
}
/**
* Performs the staggered download of file. The downloaded file will be stored in Joomla!'s temp-path using the
* basename of the URL as a filename
*
* The $params array can have any of the following keys
* url The file being downloaded
* frag Rolling counter of the file fragment being downloaded
* totalSize The total size of the file being downloaded, in bytes
* doneSize How many bytes we have already downloaded
* maxExecTime Maximum execution time downloading file fragments, in seconds
* length How many bytes to download at once
*
* The array returned is in the following format:
*
* status True if there are no errors, false if there are errors
* error A string with the error message if there are errors
* frag The next file fragment to download
* totalSize The total size of the downloaded file in bytes, if the server supports HEAD requests
* doneSize How many bytes have already been downloaded
* percent % of the file already downloaded (if totalSize could be determined)
* localfile The name of the local file, without the path
*
* @param array $params A parameters array, as sent by the user interface
*
* @return array A return status array
*/
public function importFromURL($params)
{
$this->params = $params;
// Fetch data
$url = $this->getParam('url');
$localFilename = $this->getParam('localFilename');
$frag = $this->getParam('frag', -1);
$totalSize = $this->getParam('totalSize', -1);
$doneSize = $this->getParam('doneSize', -1);
$maxExecTime = $this->getParam('maxExecTime', 5);
$runTimeBias = $this->getParam('runTimeBias', 75);
$length = $this->getParam('length', 1048576);
if (empty($localFilename))
{
$localFilename = basename($url);
if (strpos($localFilename, '?') !== false)
{
$paramsPos = strpos($localFilename, '?');
$localFilename = substr($localFilename, 0, $paramsPos - 1);
}
}
$tmpDir = JFactory::getConfig()->get('tmp_path', JPATH_ROOT . '/tmp');
$tmpDir = rtrim($tmpDir, '/\\');
// Init retArray
$retArray = array(
"status" => true,
"error" => '',
"frag" => $frag,
"totalSize" => $totalSize,
"doneSize" => $doneSize,
"percent" => 0,
"localfile" => $localFilename
);
try
{
$timer = new F0FUtilsTimer($maxExecTime, $runTimeBias);
$start = $timer->getRunningTime(); // Mark the start of this download
$break = false; // Don't break the step
// Figure out where on Earth to put that file
$local_file = $tmpDir . '/' . $localFilename;
while (($timer->getTimeLeft() > 0) && !$break)
{
// Do we have to initialize the file?
if ($frag == -1)
{
// Currently downloaded size
$doneSize = 0;
if (@file_exists($local_file))
{
@unlink($local_file);
}
// Delete and touch the output file
$fp = @fopen($local_file, 'wb');
if ($fp !== false)
{
@fclose($fp);
}
// Init
$frag = 0;
//debugMsg("-- First frag, getting the file size");
$retArray['totalSize'] = $this->adapter->getFileSize($url);
$totalSize = $retArray['totalSize'];
}
// Calculate from and length
$from = $frag * $length;
$to = $length + $from - 1;
// Try to download the first frag
$required_time = 1.0;
try
{
$result = $this->adapter->downloadAndReturn($url, $from, $to, $this->adapterOptions);
if ($result === false)
{
throw new Exception(JText::sprintf('LIB_FOF_DOWNLOAD_ERR_COULDNOTDOWNLOADFROMURL', $url), 500);
}
}
catch (Exception $e)
{
$result = false;
$error = $e->getMessage();
}
if ($result === false)
{
// Failed download
if ($frag == 0)
{
// Failure to download first frag = failure to download. Period.
$retArray['status'] = false;
$retArray['error'] = $error;
//debugMsg("-- Download FAILED");
return $retArray;
}
else
{
// Since this is a staggered download, consider this normal and finish
$frag = -1;
//debugMsg("-- Import complete");
$totalSize = $doneSize;
$break = true;
}
}
// Add the currently downloaded frag to the total size of downloaded files
if ($result)
{
$filesize = strlen($result);
//debugMsg("-- Successful download of $filesize bytes");
$doneSize += $filesize;
// Append the file
$fp = @fopen($local_file, 'ab');
if ($fp === false)
{
//debugMsg("-- Can't open local file $local_file for writing");
// Can't open the file for writing
$retArray['status'] = false;
$retArray['error'] = JText::sprintf('LIB_FOF_DOWNLOAD_ERR_COULDNOTWRITELOCALFILE', $local_file);
return $retArray;
}
fwrite($fp, $result);
fclose($fp);
//debugMsg("-- Appended data to local file $local_file");
$frag++;
//debugMsg("-- Proceeding to next fragment, frag $frag");
if (($filesize < $length) || ($filesize > $length))
{
// A partial download or a download larger than the frag size means we are done
$frag = -1;
//debugMsg("-- Import complete (partial download of last frag)");
$totalSize = $doneSize;
$break = true;
}
}
// Advance the frag pointer and mark the end
$end = $timer->getRunningTime();
// Do we predict that we have enough time?
$required_time = max(1.1 * ($end - $start), $required_time);
if ($required_time > (10 - $end + $start))
{
$break = true;
}
$start = $end;
}
if ($frag == -1)
{
$percent = 100;
}
elseif ($doneSize <= 0)
{
$percent = 0;
}
else
{
if ($totalSize > 0)
{
$percent = 100 * ($doneSize / $totalSize);
}
else
{
$percent = 0;
}
}
// Update $retArray
$retArray = array(
"status" => true,
"error" => '',
"frag" => $frag,
"totalSize" => $totalSize,
"doneSize" => $doneSize,
"percent" => $percent,
);
}
catch (Exception $e)
{
//debugMsg("EXCEPTION RAISED:");
//debugMsg($e->getMessage());
$retArray['status'] = false;
$retArray['error'] = $e->getMessage();
}
return $retArray;
}
/**
* This method will crawl a starting directory and get all the valid files
* that will be analyzed by __construct. Then it organizes them into an
* associative array.
*
* @param string $path Folder where we should start looking
* @param array $ignoreFolders Folder ignore list
* @param array $ignoreFiles File ignore list
*
* @return array Associative array, where the `fullpath` key contains the path to the file,
* and the `classname` key contains the name of the class
*/
protected static function getFiles($path, array $ignoreFolders = array(), array $ignoreFiles = array())
{
$return = array();
$files = self::scanDirectory($path, $ignoreFolders, $ignoreFiles);
// Ok, I got the files, now I have to organize them
foreach ($files as $file)
{
$clean = str_replace($path, '', $file);
$clean = trim(str_replace('\\', '/', $clean), '/');
$parts = explode('/', $clean);
$return[] = array(
'fullpath' => $file,
'classname' => 'F0FDownloadAdapter' . ucfirst(basename($parts[0], '.php'))
);
}
return $return;
}
/**
* Recursive function that will scan every directory unless it's in the
* ignore list. Files that aren't in the ignore list are returned.
*
* @param string $path Folder where we should start looking
* @param array $ignoreFolders Folder ignore list
* @param array $ignoreFiles File ignore list
*
* @return array List of all the files
*/
protected static function scanDirectory($path, array $ignoreFolders = array(), array $ignoreFiles = array())
{
$return = array();
$handle = @opendir($path);
if ( !$handle)
{
return $return;
}
while (($file = readdir($handle)) !== false)
{
if ($file == '.' || $file == '..')
{
continue;
}
$fullpath = $path . '/' . $file;
if ((is_dir($fullpath) && in_array($file, $ignoreFolders)) || (is_file($fullpath) && in_array($file, $ignoreFiles)))
{
continue;
}
if (is_dir($fullpath))
{
$return = array_merge(self::scanDirectory($fullpath, $ignoreFolders, $ignoreFiles), $return);
}
else
{
$return[] = $path . '/' . $file;
}
}
return $return;
}
}

View File

@ -0,0 +1,79 @@
<?php
/**
* @package FrameworkOnFramework
* @subpackage dispatcher
* @copyright Copyright (C) 2010-2016 Nicholas K. Dionysopoulos / Akeeba Ltd. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Protect from unauthorized access
defined('F0F_INCLUDED') or die;
interface F0FDownloadInterface
{
/**
* Does this download adapter support downloading files in chunks?
*
* @return boolean True if chunk download is supported
*/
public function supportsChunkDownload();
/**
* Does this download adapter support reading the size of a remote file?
*
* @return boolean True if remote file size determination is supported
*/
public function supportsFileSize();
/**
* Is this download class supported in the current server environment?
*
* @return boolean True if this server environment supports this download class
*/
public function isSupported();
/**
* Get the priority of this adapter. If multiple download adapters are
* supported on a site, the one with the highest priority will be
* used.
*
* @return boolean
*/
public function getPriority();
/**
* Returns the name of this download adapter in use
*
* @return string
*/
public function getName();
/**
* Download a part (or the whole) of a remote URL and return the downloaded
* data. You are supposed to check the size of the returned data. If it's
* smaller than what you expected you've reached end of file. If it's empty
* you have tried reading past EOF. If it's larger than what you expected
* the server doesn't support chunk downloads.
*
* If this class' supportsChunkDownload returns false you should assume
* that the $from and $to parameters will be ignored.
*
* @param string $url The remote file's URL
* @param integer $from Byte range to start downloading from. Use null for start of file.
* @param integer $to Byte range to stop downloading. Use null to download the entire file ($from is ignored)
* @param array $params Additional params that will be added before performing the download
*
* @return string The raw file data retrieved from the remote URL.
*
* @throws Exception A generic exception is thrown on error
*/
public function downloadAndReturn($url, $from = null, $to = null, array $params = array());
/**
* Get the size of a remote file in bytes
*
* @param string $url The remote file's URL
*
* @return integer The file size, or -1 if the remote server doesn't support this feature
*/
public function getFileSize($url);
}