__  __    __   __  _____      _            _          _____ _          _ _ 
 |  \/  |   \ \ / / |  __ \    (_)          | |        / ____| |        | | |
 | \  / |_ __\ V /  | |__) | __ ___   ____ _| |_ ___  | (___ | |__   ___| | |
 | |\/| | '__|> <   |  ___/ '__| \ \ / / _` | __/ _ \  \___ \| '_ \ / _ \ | |
 | |  | | |_ / . \  | |   | |  | |\ V / (_| | ||  __/  ____) | | | |  __/ | |
 |_|  |_|_(_)_/ \_\ |_|   |_|  |_| \_/ \__,_|\__\___| |_____/|_| |_|\___V 2.1
 if you need WebShell for Seo everyday contact me on Telegram
 Telegram Address : @jackleet
        
        
For_More_Tools: Telegram: @jackleet | Bulk Smtp support mail sender | Business Mail Collector | Mail Bouncer All Mail | Bulk Office Mail Validator | Html Letter private



Upload:

Command:

[email protected]: ~ $
<?php
/**
 * Akeeba Engine
 *
 * @package   akeebaengine
 * @copyright Copyright (c)2006-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
 * @license   GNU General Public License version 3, or later
 */

namespace Akeeba\S3;

use Akeeba\S3\Response\Error;

// Protection against direct access
defined('AKEEBAENGINE') || die();


class Request
{
	/**
	 * The HTTP verb to use
	 *
	 * @var  string
	 */
	private $verb = 'GET';

	/**
	 * The bucket we are using
	 *
	 * @var  string
	 */
	private $bucket = '';

	/**
	 * The object URI, relative to the bucket's root
	 *
	 * @var  string
	 */
	private $uri = '';

	/**
	 * The remote resource we are querying
	 *
	 * @var  string
	 */
	private $resource = '';

	/**
	 * Query string parameters
	 *
	 * @var  array
	 */
	private $parameters = [];

	/**
	 * Amazon-specific headers to pass to the request
	 *
	 * @var  array
	 */
	private $amzHeaders = [];

	/**
	 * Regular HTTP headers to send in the request
	 *
	 * @var  array
	 */
	private $headers = [
		'Host'         => '',
		'Date'         => '',
		'Content-MD5'  => '',
		'Content-Type' => '',
	];

	/**
	 * Input data for the request
	 *
	 * @var  Input
	 */
	private $input = null;

	/**
	 * The file resource we are writing data to
	 *
	 * @var  resource|null
	 */
	private $fp = null;

	/**
	 * The Amazon S3 configuration object
	 *
	 * @var Configuration
	 */
	private $configuration = null;

	/**
	 * The response object
	 *
	 * @var  Response
	 */
	private $response = null;

	/**
	 * The location of the CA certificate cache. It can be a file or a directory. If it's not specified, the location
	 * set in AKEEBA_CACERT_PEM will be used
	 *
	 * @var  string|null
	 */
	private $caCertLocation = null;

	/**
	 * Constructor
	 *
	 * @param   string         $verb           HTTP verb, e.g. 'POST'
	 * @param   string         $bucket         Bucket name, e.g. 'example-bucket'
	 * @param   string         $uri            Object URI
	 * @param   Configuration  $configuration  The Amazon S3 configuration object to use
	 *
	 * @return  void
	 */
	function __construct(string $verb, string $bucket, string $uri, Configuration $configuration)
	{
		$this->verb          = $verb;
		$this->bucket        = $bucket;
		$this->uri           = '/';
		$this->configuration = $configuration;

		if (!empty($uri))
		{
			$this->uri = '/' . str_replace('%2F', '/', rawurlencode($uri));
		}

		$this->headers['Host'] = $this->getHostName($configuration, $this->bucket);
		$this->resource        = $this->uri;

		if (($this->bucket !== '') && $configuration->getUseLegacyPathStyle())
		{
			$this->resource = '/' . $this->bucket . $this->uri;

			$this->uri = $this->resource;
		}

		// The date must always be added as a header
		$this->headers['Date'] = gmdate('D, d M Y H:i:s O');

		// S3-"compatible" services use a different date format. Because why not?
		if (strpos($this->headers['Host'], '.amazonaws.com') === false)
		{
			$this->headers['Date'] = gmdate('D, d M Y H:i:s T');
		}

		// If there is a security token we need to set up the X-Amz-Security-Token header
		$token = $this->configuration->getToken();

		if (!empty($token))
		{
			$this->setAmzHeader('x-amz-security-token', $token);
		}

		// Initialize the response object
		$this->response = new Response();
	}

	/**
	 * Get the input object
	 *
	 * @return  Input|null
	 */
	public function getInput(): ?Input
	{
		return $this->input;
	}

	/**
	 * Set the input object
	 *
	 * @param   Input  $input
	 *
	 * @return  void
	 */
	public function setInput(Input $input): void
	{
		$this->input = $input;
	}

	/**
	 * Set a request parameter
	 *
	 * @param   string       $key    The parameter name
	 * @param   string|null  $value  The parameter value
	 *
	 * @return  void
	 */
	public function setParameter(string $key, ?string $value): void
	{
		$this->parameters[$key] = $value;
	}

	/**
	 * Set a request header
	 *
	 * @param   string  $key    The header name
	 * @param   string  $value  The header value
	 *
	 * @return  void
	 */
	public function setHeader(string $key, string $value): void
	{
		$this->headers[$key] = $value;
	}

	/**
	 * Set an x-amz-meta-* header
	 *
	 * @param   string  $key    The header name
	 * @param   string  $value  The header value
	 *
	 * @return  void
	 */
	public function setAmzHeader(string $key, string $value): void
	{
		$this->amzHeaders[$key] = $value;
	}

	/**
	 * Get the HTTP verb of this request
	 *
	 * @return  string
	 */
	public function getVerb(): string
	{
		return $this->verb;
	}

	/**
	 * Get the S3 bucket's name
	 *
	 * @return  string
	 */
	public function getBucket(): string
	{
		return $this->bucket;
	}

	/**
	 * Get the absolute URI of the resource we're accessing
	 *
	 * @return  string
	 */
	public function getResource(): string
	{
		return $this->resource;
	}

	/**
	 * Get the parameters array
	 *
	 * @return  array
	 */
	public function getParameters(): array
	{
		return $this->parameters;
	}

	/**
	 * Get the Amazon headers array
	 *
	 * @return  array
	 */
	public function getAmzHeaders(): array
	{
		return $this->amzHeaders;
	}

	/**
	 * Get the other headers array
	 *
	 * @return  array
	 */
	public function getHeaders(): array
	{
		return $this->headers;
	}

	/**
	 * Get a reference to the Amazon configuration object
	 *
	 * @return  Configuration
	 */
	public function getConfiguration(): Configuration
	{
		return $this->configuration;
	}

	/**
	 * Get the file pointer resource (for PUT and POST requests)
	 *
	 * @return  resource|null
	 */
	public function &getFp()
	{
		return $this->fp;
	}

	/**
	 * Set the data resource as a file pointer
	 *
	 * @param   resource  $fp
	 */
	public function setFp($fp): void
	{
		$this->fp = $fp;
	}

	/**
	 * Get the certificate authority location
	 *
	 * @return  string|null
	 */
	public function getCaCertLocation(): ?string
	{
		if (!empty($this->caCertLocation))
		{
			return $this->caCertLocation;
		}

		if (defined('AKEEBA_CACERT_PEM'))
		{
			return AKEEBA_CACERT_PEM;
		}

		return null;
	}

	/**
	 * @param   null|string  $caCertLocation
	 */
	public function setCaCertLocation(?string $caCertLocation): void
	{
		if (empty($caCertLocation))
		{
			$caCertLocation = null;
		}

		if (!is_null($caCertLocation) && !is_file($caCertLocation) && !is_dir($caCertLocation))
		{
			$caCertLocation = null;
		}

		$this->caCertLocation = $caCertLocation;
	}

	/**
	 * Get a pre-signed URL for the request.
	 *
	 * Typically used to pre-sign GET requests to objects, i.e. give shareable pre-authorized URLs for downloading
	 * private or otherwise inaccessible files from S3.
	 *
	 * @param   int|null  $lifetime  Lifetime in seconds
	 * @param   bool      $https     Use HTTPS ($hostBucket should be false for SSL verification)?
	 *
	 * @return  string  The authenticated URL, complete with signature
	 */
	public function getAuthenticatedURL(?int $lifetime = null, bool $https = false): string
	{
		$this->processParametersIntoResource();
		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());

		return $signer->getAuthenticatedURL($lifetime, $https);
	}

	/**
	 * Get the S3 response
	 *
	 * @return  Response
	 */
	public function getResponse(bool $rawResponse = false): Response
	{
		$this->processParametersIntoResource();

		$schema = 'http://';

		if ($this->configuration->isSSL())
		{
			$schema = 'https://';
		}

		// Very special case. IF the URI ends in /?location AND the region is us-east-1 (Host is
		// s3-external-1.amazonaws.com) THEN the host MUST become s3.amazonaws.com for the request to work. This is case
		// of us not knowing the region of the bucket, therefore having to use a special endpoint which lets us query
		// the region of the bucket without knowing its region. See
		// http://stackoverflow.com/questions/27091816/retrieve-buckets-objects-without-knowing-buckets-region-with-aws-s3-rest-api
		if ((substr($this->uri, -10) == '/?location') && ($this->headers['Host'] == 's3-external-1.amazonaws.com'))
		{
			$this->headers['Host'] = 's3.amazonaws.com';
		}

		$url = $schema . $this->headers['Host'] . $this->uri;

		// Basic setup
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_USERAGENT, 'AkeebaBackupProfessional/S3PostProcessor');

		if ($this->configuration->isSSL())
		{
			// Set the CA certificate cache location
			$caCert = $this->getCaCertLocation();

			if (!empty($caCert))
			{
				if (is_dir($caCert))
				{
					@curl_setopt($curl, CURLOPT_CAPATH, $caCert);
				}
				else
				{
					@curl_setopt($curl, CURLOPT_CAINFO, $caCert);
				}
			}

			/**
			 * Verify the host name in the certificate and the certificate itself.
			 *
			 * Caveat: if your bucket contains dots in the name we have to turn off host verification due to the way the
			 * S3 SSL certificates are set up.
			 */
			$isAmazonS3  = (substr($this->headers['Host'], -14) == '.amazonaws.com')
			               || substr(
				                  $this->headers['Host'], -16
			                  ) == 'amazonaws.com.cn';
			$tooManyDots = substr_count($this->headers['Host'], '.') > 4;

			$verifyHost = ($isAmazonS3 && $tooManyDots) ? 0 : 2;

			curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, $verifyHost);
			curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);
		}

		curl_setopt($curl, CURLOPT_URL, $url);

		/**
		 * Set the optional x-amz-date header for third party services.
		 *
		 * Amazon S3 proper expects to get the date from the Date header. Third party services typically implement the
		 * (wrongly) documented behaviour of using the x-amz-date header but, if it's missing, fall back to the Date
		 * header. Wasabi does not fall back; it only uses the x-amz-date header which is why we have to set it here if
		 * the request iss not made to Amazon S3 proper.
		 */
		$this->headers['x-amz-date'] = strpos($this->headers['Host'], '.amazonaws.com') !== false
			? ''
			: (new \DateTime($this->headers['Date']))->format('Ymd\THis\Z');

		/**
		 * Remove empty headers.
		 *
		 * While Amazon S3 proper and most third party implementations have no problem with that, there a few of them
		 * (such as Synology C2) which choke on empty headers.
		 */
		$this->headers = array_filter($this->headers);

		// Get the request signature
		$signer = Signature::getSignatureObject($this, $this->configuration->getSignatureMethod());
		$signer->preProcessHeaders($this->headers, $this->amzHeaders);

		// Headers
		$headers = [];

		foreach ($this->amzHeaders as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$headers[] = $header . ': ' . $value;
			}
		}

		foreach ($this->headers as $header => $value)
		{
			if (strlen($value) > 0)
			{
				$headers[] = $header . ': ' . $value;
			}
		}

		$headers[] = 'Authorization: ' . $signer->getAuthorizationHeader();

		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($curl, CURLOPT_HEADER, false);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
		curl_setopt($curl, CURLOPT_WRITEFUNCTION, [$this, '__responseWriteCallback']);
		curl_setopt($curl, CURLOPT_HEADERFUNCTION, [$this, '__responseHeaderCallback']);
		curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);

		// Request types
		switch ($this->verb)
		{
			case 'GET':
				break;

			case 'PUT':
			case 'POST':
				if (!is_object($this->input) || !($this->input instanceof Input))
				{
					$this->input = new Input();
				}

				$size = $this->input->getSize();
				$type = $this->input->getInputType();

				if ($type == Input::INPUT_DATA)
				{
					curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $this->verb);

					$data = $this->input->getDataReference();

					if (strlen($data ?? ''))
					{
						curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
					}

					if ($size > 0)
					{
						curl_setopt($curl, CURLOPT_BUFFERSIZE, $size);
					}
				}
				else
				{
					curl_setopt($curl, CURLOPT_PUT, true);
					curl_setopt($curl, CURLOPT_INFILE, $this->input->getFp());

					if ($size > 0)
					{
						curl_setopt($curl, CURLOPT_INFILESIZE, $size);
					}
				}


				break;

			case 'HEAD':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'HEAD');
				curl_setopt($curl, CURLOPT_NOBODY, true);
				break;

			case 'DELETE':
				curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'DELETE');
				break;

			default:
				break;
		}

		// Execute, grab errors
		$this->response->resetBody();

		if (curl_exec($curl))
		{
			$this->response->code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
		}
		else
		{
			$this->response->error = new Error(
				curl_errno($curl),
				curl_error($curl),
				$this->resource
			);
		}

		@curl_close($curl);

		// Set the body data
		$this->response->finaliseBody($rawResponse);

		// Clean up file resources
		if (!is_null($this->fp) && is_resource($this->fp))
		{
			try
			{
				@fclose($this->fp);
			}
			catch (\Throwable $e)
			{
			}
		}

		return $this->response;
	}


	/**
	 * cURL write callback
	 *
	 * @param   resource   &$curl  cURL resource
	 * @param   string     &$data  Data
	 *
	 * @return  int  Length in bytes
	 */
	protected function __responseWriteCallback($curl, string $data): int
	{
		if (in_array($this->response->code, [0, 200, 206]) && !is_null($this->fp) && is_resource($this->fp))
		{
			return fwrite($this->fp, $data);
		}

		$this->response->addToBody($data);

		return strlen($data);
	}

	/**
	 * cURL header callback
	 *
	 * @param   resource   $curl  cURL resource
	 * @param   string    &$data  Data
	 *
	 * @return  int  Length in bytes
	 */
	protected function __responseHeaderCallback($curl, string $data): int
	{
		if (($strlen = strlen($data)) <= 2)
		{
			return $strlen;
		}

		if (substr($data, 0, 4) == 'HTTP')
		{
			$this->response->code = (int) substr($data, 9, 3);

			return $strlen;
		}

		// Ignore malformed headers without a value.
		if (strpos($data, ':') === false)
		{
			return $strlen;
		}

		[$header, $value] = explode(':', trim($data), 2);
		$header = trim($header ?? '');
		$value  = trim($value ?? '');

		switch (strtolower($header))
		{
			case 'last-modified':
				$this->response->setHeader('time', strtotime($value));
				break;

			case 'content-length':
				$this->response->setHeader('size', (int) $value);
				break;

			case 'content-type':
				$this->response->setHeader('type', $value);
				break;

			case 'etag':
				$this->response->setHeader('hash', trim($value, '"'));
				break;

			default:
				$this->response->setHeader(strtolower($header), is_numeric($value) ? (int) $value : $value);

				if (preg_match('/^x-amz-meta-.*$/', $header))
				{
					$this->setHeader($header, is_numeric($value) ? (int) $value : $value);
				}
				break;
		}

		return $strlen;
	}

	/**
	 * Processes $this->parameters as a query string into $this->resource
	 *
	 * @return  void
	 */
	private function processParametersIntoResource(): void
	{
		if (count($this->parameters))
		{
			$query = substr($this->uri, -1) !== '?' ? '?' : '&';

			ksort($this->parameters);

			foreach ($this->parameters as $var => $value)
			{
				if ($value == null || $value == '')
				{
					$query .= $var . '&';
				}
				else
				{
					// Parameters must be URL-encoded
					$query .= $var . '=' . rawurlencode($value) . '&';
				}
			}

			$query     = substr($query, 0, -1);
			$this->uri .= $query;

			if (array_key_exists('acl', $this->parameters) || array_key_exists('location', $this->parameters)
			    || array_key_exists('torrent', $this->parameters)
			    || array_key_exists('logging', $this->parameters)
			    || array_key_exists('uploads', $this->parameters)
			    || array_key_exists('uploadId', $this->parameters)
			    || array_key_exists('partNumber', $this->parameters)
			)
			{
				$this->resource .= $query;
			}
		}
	}

	/**
	 * Get the region-specific hostname for an operation given a configuration and a bucket name. This ensures we can
	 * always use an HTTPS connection, even with buckets containing dots in their names, without SSL certificate host
	 * name validation issues.
	 *
	 * Please note that this requires the pathStyle flag to be set in Configuration because Amazon RECOMMENDS using the
	 * virtual-hosted style request where applicable. See http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
	 * Quoting this documentation:
	 * "Although the path-style is still supported for legacy applications, we recommend using the virtual-hosted style
	 * where applicable."
	 *
	 * @param   Configuration  $configuration
	 * @param   string         $bucket
	 *
	 * @return  string
	 */
	private function getHostName(Configuration $configuration, string $bucket): string
	{
		// http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
		$endpoint = $configuration->getEndpoint();
		$region   = $configuration->getRegion();

		// If it's a bucket in China we need to use a different endpoint
		if (($endpoint == 's3.amazonaws.com') && (substr($region, 0, 3) == 'cn-'))
		{
			$endpoint = 'amazonaws.com.cn';
		}

		/**
		 * If there is no bucket we use the default endpoint, whatever it is. For Amazon S3 this format is only used
		 * when we are making account-level, cross-region requests, e.g. list all buckets. For S3-compatible APIs it
		 * depends on the API, but generally it's just for listing available buckets.
		 */
		if (empty($bucket))
		{
			return $endpoint;
		}

		/**
		 * Are we using v2 signatures? In this case we use the endpoint defined by the user without translating it.
		 */
		if ($configuration->getSignatureMethod() != 'v4')
		{
			// Legacy path style: the hostname is the endpoint
			if ($configuration->getUseLegacyPathStyle())
			{
				return $endpoint;
			}

			// Virtual hosting style: the hostname is the bucket, dot and endpoint.
			return $bucket . '.' . $endpoint;
		}

		/**
		 * Only applies to Amazon S3 proper.
		 *
		 * When using the Amazon S3 with the v4 signature API we have to use a different hostname per region. The
		 * mapping can be found in https://docs.aws.amazon.com/general/latest/gr/s3.html#s3_region
		 *
		 * This means changing the endpoint to s3.REGION.amazonaws.com with the following exceptions:
		 * For China: s3.REGION.amazonaws.com.cn
		 *
		 * v4 signing does NOT support non-Amazon endpoints.
		 */
		if (in_array($endpoint, ['s3.amazonaws.com', 'amazonaws.com.cn']))
		{
			// Most endpoints: s3-REGION.amazonaws.com
			$regionalEndpoint = $region . '.amazonaws.com';

			// Exception: China
			if (substr($region, 0, 3) == 'cn-')
			{
				// Chinese endpoint, e.g.: s3.cn-north-1.amazonaws.com.cn
				$regionalEndpoint = $regionalEndpoint . '.cn';
			}

			// If dual-stack URLs are enabled then prepend the endpoint
			if ($configuration->getDualstackUrl())
			{
				$endpoint = 's3.dualstack.' . $regionalEndpoint;
			}
			else
			{
				$endpoint = 's3.' . $regionalEndpoint;
			}
		}

		// Legacy path style access: return just the endpoint
		if ($configuration->getUseLegacyPathStyle())
		{
			return $endpoint;
		}

		// Recommended virtual hosting access: bucket, dot, endpoint.
		return $bucket . '.' . $endpoint;
	}
}

Filemanager

Name Type Size Permission Actions
Exception Folder 0775
Response Folder 0775
Signature Folder 0775
Acl.php File 712 B 0664
Configuration.php File 8.13 KB 0664
Connector.php File 26.84 KB 0664
Input.php File 15.38 KB 0664
Request.php File 18.49 KB 0664
Response.php File 6.02 KB 0664
Signature.php File 2.16 KB 0664
StorageClass.php File 2.59 KB 0664
aliasing.php File 739 B 0664
Filemanager