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

+200 -25
View File
@@ -179,26 +179,47 @@ abstract class _File
{
$class->container = $container;
}
/* Make sure images don't have HTML in the comments, which can cause be an XSS in older versions of IE */
$class->storageExtension = $storageExtension;
/* Image-specific stuff */
$ext = mb_substr( $filename, ( mb_strrpos( $filename, '.' ) + 1 ) );
if( $isSafe === FALSE and in_array( $ext, \IPS\Image::$imageExtensions ) )
if( in_array( $ext, \IPS\Image::$imageExtensions ) and ( !$isSafe or \IPS\Image::exifSupported() ) )
{
$contentToCheck = $data;
/* Get contents */
if( $data === NULL AND $filePath !== NULL )
{
$handle = fopen( $filePath, 'r');
$contentToCheck = fread( $handle, 2048 );
fclose( $handle );
$data = \file_get_contents( $filePath );
$filePath = NULL;
}
if( static::checkXssInFile( $contentToCheck ) )
/* Make sure images don't have HTML in the comments, which can cause be an XSS in older versions of IE */
$image = NULL;
if( !$isSafe and static::checkXssInFile( $data ) )
{
throw new \DomainException( "SECURITY_EXCEPTION_RAISED", 99 );
/* Try to just strip the EXIF */
$image = \IPS\Image::create( $data );
$image->resize( 100, 100 );
$data = (string) $image;
/* And if it still fails, throw an error */
if ( static::checkXssInFile( $data ) )
{
throw new \DomainException( "SECURITY_EXCEPTION_RAISED", 99 );
}
}
/* Correct orientation */
if ( \IPS\Image::exifSupported() )
{
$image = $image ?: \IPS\Image::create( $data );
if ( $image->hasBeenRotated )
{
$data = (string) \IPS\Image::create( $data );
}
}
}
/* Set the name */
$class->setFilename( $filename, $obscure );
@@ -448,6 +469,7 @@ abstract class _File
public static function get( $storageExtension, $url )
{
$class = static::getClass( $storageExtension, $url );
$class->storageExtension = $storageExtension;
$class->url = $url;
$class->load();
return $class;
@@ -464,7 +486,7 @@ abstract class _File
{
return static::getClass( $configurationId )->removeOrphanedFiles( $fileIndex, \IPS\Application::allExtensions( 'core', 'FileStorage', FALSE ) );
}
/**
* Determine if the change in configuration warrants a move process
*
@@ -510,9 +532,9 @@ abstract class _File
/**
* This is primarily a utility function to convert old style full URLs (http://site.com/uploads/monthly_04_2015/file.txt) into the new style (monthly_04_2015/file.txt)
* @deprecated 4.1.0
*
* return string|boolean URL (string) if URL needed repairing, or FALSE if it did not.
* @deprecated 4.1.0
* @return string|boolean URL (string) if URL needed repairing, or FALSE if it did not.
*/
public static function repairUrl( $url )
{
@@ -550,6 +572,11 @@ abstract class _File
*/
public $configurationId;
/**
* @brief Storage Extension (core_Theme, etc)
*/
public $storageExtension;
/**
* @brief Original Filename
*/
@@ -638,6 +665,77 @@ abstract class _File
}
}
/**
* Send file with byte-offset supported. Requires a path to a locally stored file. This method can be more efficient than
* getting the file contents and printing as the file contents do not need to be stored in memory, however files will need to
* be written to disk and removed, and the method is only useful if there is a way to retrieve a file without storing the
* contents in memory already.
*
* @param string $file Path to file
* @param int|null $start Start point to print from (for ranges)
* @param int|null $length Length to print to (for ranges)
* @param int|null $throttle Throttle speed
* @return void
*/
protected function sendFile( $file, $start=NULL, $length=NULL, $throttle=NULL )
{
/* Turn off output buffering if it is on */
while( ob_get_level() > 0 )
{
ob_end_clean();
}
if( $throttle === NULL AND !($start AND $length) AND function_exists('readfile') )
{
readfile( $file );
}
else
{
if( $fh = fopen( $file, 'rb' ) )
{
$read = ( $throttle !== NULL ) ? $throttle : 4096;
if( $start AND $length )
{
fseek( $fh, $start );
while( $length AND !feof( $fh ) )
{
if( $read > $length )
{
$read = $length;
}
echo fread( $fh, $read );
flush();
$length -= $read;
if( $throttle )
{
sleep( 1 );
}
}
}
else
{
while( ! feof( $fh ) )
{
echo fread( $fh, $read );
flush();
if( $throttle )
{
sleep( 1 );
}
}
}
fclose( $fh );
}
}
}
/**
* Get Contents
*
@@ -691,15 +789,30 @@ abstract class _File
public function setFilename( $filename, $obscure=TRUE )
{
$this->originalFilename = $filename;
/* Make sure name doesn't have anything that may break URLs */
if ( preg_match( '#[^a-zA-Z0-9!\-_\.\*\(\)\@]#', $filename ) )
{
$filename = uniqid() . '_' . preg_replace( '#[^a-zA-Z0-9!\-_\.\*\(\)\@]#', '', $filename );
}
if ( $obscure )
{
$this->filename = static::obscureFilename( $filename );
$filename = static::obscureFilename( $filename );
}
else
{
$this->filename = $filename;
$filename = $filename;
}
/* Most operating systems allow a max filename length of 255 bytes, so we should make sure we don't go over that */
if( \strlen( $filename ) > 200 )
{
/* If the filename is over 200 chars, grab the first 100 and the last 100 and concatenate with a dash - this should help ensure we retain the most useful info */
$filename = mb_substr( $filename, 0, 100 ) . '-' . mb_substr( $filename, -100 );
}
$this->filename = $filename;
}
/**
@@ -763,7 +876,6 @@ abstract class _File
if ( static::isFullyQualifiedUrl( $url ) )
{
$url = mb_substr( $url, mb_strlen( $this->baseUrl() ) + 1 );
}
$exploded = explode( '/', $url );
@@ -824,6 +936,36 @@ abstract class _File
return $this->container . '/' . $this->filename;
}
/**
* The configuration settings have been updated
*
* @return void
*/
public function settingsUpdated()
{
$settings = json_decode( \IPS\Settings::i()->upload_settings, TRUE );
foreach( $settings as $method => $id )
{
if ( $id == $this->configurationId )
{
$exploded = explode( '_', str_replace( 'filestorage__', '', $method ) );
$classname = "IPS\\{$exploded[0]}\\extensions\\core\\FileStorage\\{$exploded[1]}";
if ( method_exists( $classname, 'settingsUpdated' ) )
{
$classname::settingsUpdated( $this->configuration );
}
}
}
/* Clear guest page caches */
\IPS\Data\Cache::i()->clearAll();
/* Clear datastore */
\IPS\Data\Store::i()->clearAll();
}
/**
* Return the fully qualified URL
*
@@ -988,14 +1130,15 @@ abstract class _File
$data['attach_is_image'] = TRUE;
$data['attach_img_width'] = $dimensions[0];
$data['attach_img_height'] = $dimensions[1];
unset( $image );
$data['attach_thumb_location'] = (string) $this->thumbnail( 'core_Attachment', $thumbDims[0], $thumbDims[1] );
$data['attach_thumb_width'] = static::$thumbnailDimensions[0];
$data['attach_thumb_height'] = static::$thumbnailDimensions[1];
if ( $dimensions[0] > $thumbDims[0] or $dimensions[1] > $thumbDims[1] )
{
$data['attach_thumb_location'] = (string) $this->thumbnail( 'core_Attachment', $thumbDims[0], $thumbDims[1] );
$data['attach_thumb_width'] = static::$thumbnailDimensions[0];
$data['attach_thumb_height'] = static::$thumbnailDimensions[1];
$this->attachmentThumbnailUrl = $data['attach_thumb_location'];
$this->attachmentThumbnailUrl = $data['attach_thumb_location'];
}
}
catch ( \InvalidArgumentException $e ) { }
@@ -1259,6 +1402,38 @@ abstract class _File
return 'application/x-unknown'; // This, slightly unusual, type is needed to stop some browsers adding random extensions
}
/**
* Return a value pulled from php.ini in bytes
*
* @note This function is intended to normalize values for things like post_max_size which could be -1, 0, 8383900, 8M, 1G, etc.
* @return float
*/
public static function returnBytes( $size )
{
$size = trim( $size );
if( !$size OR $size == -1 )
{
return 0;
}
/* Get the last character, which may be 'm' or may be a number */
$last = mb_strtolower( $size[ \strlen( $size ) - 1 ] );
/* Adjust value as necessary - note that we do not break intentionally */
switch( $last )
{
case 'g':
$size *= 1024;
case 'm':
$size *= 1024;
case 'k':
$size *= 1024;
}
return (float) $size;
}
/* !Mime-Type Map */