Version 4.1.2

This commit is contained in:
Neo committed 2025-12-19 05:32:19 -08:00
1 parent 3ba79295ee
commit 28bd025b35
1131 files changed
+63658 -20579

No files matched your search

+127 -12
View File
@@ -23,6 +23,13 @@ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
*/
class _Amazon extends \IPS\File
{
/**
* An array of ( configuration_id => array( ext, etx ) ) extensions that require gzip versions storing
* Looks up $storageExtensions of extension classes
*/
protected static $gzipExtensions = array();
/* !ACP Configuration */
/**
@@ -137,7 +144,7 @@ class _Amazon extends \IPS\File
{
return \IPS\Member::loggedIn()->language()->addToStack( 'filehandler_display_name', FALSE, array( 'sprintf' => array( \IPS\Member::loggedIn()->language()->addToStack('filehandler__Amazon'), $settings['bucket'] ) ) );
}
/* !File Handling */
/**
@@ -152,6 +159,42 @@ class _Amazon extends \IPS\File
parent::__construct( $configuration );
}
/**
* Fetch the gzip extensions specific for $this->configurationId
*
* @return array
*/
public function getGzipExtensions()
{
if ( $this->storageExtension and ! array_key_exists( $this->storageExtension, static::$gzipExtensions ) )
{
$bits = explode( '_', $this->storageExtension );
$class = '\IPS\\' . $bits[0] . '\extensions\core\FileStorage\\' . $bits[1];
if ( isset( $class::$storeGzipExtensions ) and is_array( $class::$storeGzipExtensions ) and count( $class::$storeGzipExtensions ) )
{
static::$gzipExtensions[ $this->storageExtension ] = $class::$storeGzipExtensions;
}
else
{
static::$gzipExtensions[ $this->storageExtension ] = array();
}
}
return $this->storageExtension ? static::$gzipExtensions[ $this->storageExtension ] : array();
}
/**
* AWS does not gzip content when serving it, so if we want gzip compressed JS and CSS, we need to store a copy ourselves.
*
* @return boolean
*/
public function needsGzipVersion()
{
/* Use filename and not originalFilename so only true .js and .css files are checked, and not renamed uploads */
return in_array( mb_substr( $this->filename, mb_strrpos( $this->filename, '.' ) + 1 ), $this->getGzipExtensions() );
}
/**
* Return the base URL
*
@@ -162,6 +205,22 @@ class _Amazon extends \IPS\File
return preg_replace( '#^http(s)?://#', '//', ( empty( $this->configuration['custom_url'] ) ) ? rtrim( static::buildBaseUrl( $this->configuration ), '/' ) : $this->configuration['custom_url'] );
}
/**
* Load File Data
*
* @return void
*/
public function load()
{
parent::load();
/* Change the public URL to the gzipped version if the browser supports it */
if ( $this->needsGzipVersion() and ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) and \strpos( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) !== false ) )
{
$this->url = new \IPS\Http\Url( (string) $this->url . '.gz' );
}
}
/**
* Save File
*
@@ -169,20 +228,25 @@ class _Amazon extends \IPS\File
*/
public function save()
{
/* @link http://docs.aws.amazon.com/AmazonS3/latest/dev/UsingMetadata.html regarding cleaning filenames */
if ( preg_match( '#[^a-zA-Z0-9!\-_\.\*\(\)]#', $this->filename ) )
{
$this->filename = uniqid() . '_' . preg_replace( '#[^a-zA-Z0-9!\-_\.\*\(\)]#', '', $this->filename );
}
$this->container = trim( $this->container, '/' );
$this->url = static::buildBaseUrl( $this->configuration ) . "{$this->container}/{$this->filename}";
$this->url = $this->baseUrl() . "/{$this->container}/{$this->filename}";
$response = static::makeRequest( "{$this->container}/{$this->filename}", 'PUT', $this->configuration, $this->configurationId, (string) $this->contents() );
if ( $response->httpResponseCode != 200 )
{
throw new \RuntimeException('COULD_NOT_SAVE_FILE');
}
/* Write the gzip version */
if ( $this->needsGzipVersion() )
{
$response = static::makeRequest( "{$this->container}/{$this->filename}.gz", 'PUT', $this->configuration, $this->configurationId, gzencode( (string) $this->contents() ) );
if ( $response->httpResponseCode != 200 )
{
throw new \RuntimeException('COULD_NOT_SAVE_FILE');
}
}
}
/**
@@ -213,6 +277,12 @@ class _Amazon extends \IPS\File
if ( $response->httpResponseCode == 204 )
{
/* Got a gzip version? */
if ( $this->needsGzipVersion() )
{
static::makeRequest( "{$this->container}/{$this->filename}.gz", 'DELETE', $this->configuration, $this->configurationId );
}
/* Ok */
return;
}
@@ -256,6 +326,25 @@ class _Amazon extends \IPS\File
}
}
/**
* Get filesize (in bytes)
*
* @return string
*/
public function filesize()
{
$this->container = trim( $this->container, '/' );
$response = static::makeRequest( "{$this->container}/{$this->filename}", 'HEAD', $this->configuration, $this->configurationId );
if ( $response->httpResponseCode != 200 OR !isset( $response->httpHeaders['Content-Length'] ) )
{
return parent::filesize();
}
return $response->httpHeaders['Content-Length'];
}
/* !Amazon Utility Methods */
/**
@@ -273,19 +362,45 @@ class _Amazon extends \IPS\File
{
/* Build a request */
$request = \IPS\Http\Url::external( static::buildBaseUrl( $configuration ) . $uri )->request();
/* When using virtual hosted–style buckets with SSL, the SSL wild card certificate only matches buckets that do not contain periods. To work around this, use HTTP or write your own certificate verification logic. @link http://docs.aws.amazon.com/AmazonS3/latest/dev/BucketRestrictions.html */
if ( \IPS\Request::i()->isSecure() and mb_strstr( $configuration['bucket'], '.' ) )
{
$request->sslCheck( FALSE );
}
$date = date('r');
$headers = array( 'Date' => $date, 'Content-Type' => \IPS\File::getMimeType( $uri ), 'Content-MD5' => base64_encode( md5( $content, TRUE ) ), 'x-amz-acl' => 'public-read' );
/* Make sure the file has the correct mime type, even if it is gzipped */
$mimeUri = ( mb_substr( $uri, -3 ) === '.gz' ) ? mb_substr( $uri, 0, -3 ) : $uri;
$headers = array( 'Date' => $date, 'Content-Type' => \IPS\File::getMimeType( $mimeUri ), 'Content-MD5' => base64_encode( md5( $content, TRUE ) ), 'x-amz-acl' => 'public-read' );
if ( $mimeUri !== $uri )
{
$headers['Content-Encoding'] = 'gzip';
}
if( mb_strtoupper( $verb ) === 'PUT' )
{
$headers['Content-Length'] = \strlen( $content );
}
$cacheSeconds = 3600;
$ext = mb_substr( $mimeUri, ( mb_strrpos( $mimeUri, '.' ) + 1 ) );
if ( preg_match( "/\." . preg_quote( $ext ) . "\.([a-zA-Z0-9]{32})\." . preg_quote( $ext ) . "$/", $mimeUri ) )
{
/* This is an obfuscated file, so it will change each time the file is updated so it is safe to cache for longer */
$cacheSeconds = 3600 * 24 * 365;
}
$headers['Cache-Control'] = 'max-age=' . $cacheSeconds;
$headers['Expires'] = date( 'r', time() + $cacheSeconds );
/* We need to strip query string parameters for the signature, but not always (e.g. a subresource such as ?acl needs to be included and multi-
object delete requests must include the query string params). Let the callee decide to do this or not. */
if( isset( $configuration['_strip_querystring'] ) AND $configuration['_strip_querystring'] === TRUE )
{
$uri = preg_replace( "/^(.*?)\?.*$/", "$1", $uri );
$uri = preg_replace( "/^(.*?)\?.*$/", "$1", $uri );
}
$string = implode( "\n", array(