Version 4.1.19
This commit is contained in:
1 parent
28bd025b35
commit
2bd5025018
2674 files changed
+233518
-77766
No files matched your search
+102
-46
@@ -2,9 +2,9 @@
|
||||
/**
|
||||
* @brief File Class
|
||||
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
|
||||
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
|
||||
* @license http://www.invisionpower.com/legal/standards/
|
||||
* @package IPS Social Suite
|
||||
* @package IPS Community Suite
|
||||
* @since 19 Feb 2013
|
||||
* @version SVN_VERSION_NUMBER
|
||||
*/
|
||||
@@ -52,12 +52,13 @@ abstract class _File
|
||||
* @brief When moving files, do not delete the original immediately but log for later deletion
|
||||
*/
|
||||
const MOVE_DELETE_NOW = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Get class
|
||||
*
|
||||
* @param string|int $storageExtension Storage extension or configuration ID
|
||||
* @param string|\IPS\Http\Url|NULL $url URL to validate storage configs with
|
||||
* @throws \RuntimeException
|
||||
* @return \IPS\File
|
||||
*/
|
||||
public static function getClass( $storageExtension, $url=NULL )
|
||||
@@ -133,7 +134,7 @@ abstract class _File
|
||||
/**
|
||||
* Load storage configurations
|
||||
*
|
||||
* @return void
|
||||
* @return array
|
||||
*/
|
||||
public static function getConfigurations()
|
||||
{
|
||||
@@ -149,6 +150,8 @@ abstract class _File
|
||||
\IPS\Data\Store::i()->storageConfigurations = static::$storageConfigurations;
|
||||
}
|
||||
}
|
||||
|
||||
return static::$storageConfigurations;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,10 +184,10 @@ abstract class _File
|
||||
}
|
||||
|
||||
$class->storageExtension = $storageExtension;
|
||||
|
||||
|
||||
/* Image-specific stuff */
|
||||
$ext = mb_substr( $filename, ( mb_strrpos( $filename, '.' ) + 1 ) );
|
||||
if( in_array( $ext, \IPS\Image::$imageExtensions ) and ( !$isSafe or \IPS\Image::exifSupported() ) )
|
||||
if( in_array( mb_strtolower( $ext ), \IPS\Image::$imageExtensions ) and ( !$isSafe or \IPS\Image::exifSupported() ) )
|
||||
{
|
||||
/* Get contents */
|
||||
if( $data === NULL AND $filePath !== NULL )
|
||||
@@ -199,7 +202,7 @@ abstract class _File
|
||||
{
|
||||
/* Try to just strip the EXIF */
|
||||
$image = \IPS\Image::create( $data );
|
||||
$image->resize( 100, 100 );
|
||||
$image->resize( $image->width, $image->height );
|
||||
$data = (string) $image;
|
||||
|
||||
/* And if it still fails, throw an error */
|
||||
@@ -295,7 +298,7 @@ abstract class _File
|
||||
if( $callback !== NULL )
|
||||
{
|
||||
$contents = file_get_contents( $file['tmp_name'] );
|
||||
$contents = call_user_func( $callback, $contents );
|
||||
$contents = call_user_func( $callback, $contents, $file['name'] );
|
||||
|
||||
$fileObjects[] = static::create( $storageLocation, $file['name'], $contents, $container, FALSE, NULL, $obscure );
|
||||
}
|
||||
@@ -465,9 +468,16 @@ abstract class _File
|
||||
* @param string $storageExtension Storage extension
|
||||
* @param string|\IPS\Http|Url $url URL to file
|
||||
* @return \IPS\File
|
||||
* @throws \OutOfRangeException
|
||||
*/
|
||||
public static function get( $storageExtension, $url )
|
||||
{
|
||||
/* Don't allow something/../../../../etc/passwd */
|
||||
if( mb_strpos( rawurldecode( $url ), '../' ) !== FALSE )
|
||||
{
|
||||
throw new \OutOfRangeException( 'INVALID_PATH' );
|
||||
}
|
||||
|
||||
$class = static::getClass( $storageExtension, $url );
|
||||
$class->storageExtension = $storageExtension;
|
||||
$class->url = $url;
|
||||
@@ -545,8 +555,6 @@ abstract class _File
|
||||
|
||||
foreach( static::$storageConfigurations as $id => $data )
|
||||
{
|
||||
$secondTest = NULL;
|
||||
$thirdTest = NULL;
|
||||
$class = static::getClass( $data['id'] );
|
||||
|
||||
$urlRelative = preg_replace( '#^http(s)?://#', '//', $url );
|
||||
@@ -654,8 +662,8 @@ abstract class _File
|
||||
else
|
||||
{
|
||||
$pointer = 0;
|
||||
|
||||
while( $pointer < \strlen( $contents ) )
|
||||
$contentsLength = \strlen( $contents );
|
||||
while( $pointer < $contentsLength )
|
||||
{
|
||||
print \substr( $contents, $pointer, $throttle );
|
||||
$pointer += $throttle;
|
||||
@@ -685,7 +693,7 @@ abstract class _File
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
if( $throttle === NULL AND !($start AND $length) AND function_exists('readfile') )
|
||||
if( $throttle === NULL AND $start === NULL AND function_exists('readfile') )
|
||||
{
|
||||
readfile( $file );
|
||||
}
|
||||
@@ -695,7 +703,7 @@ abstract class _File
|
||||
{
|
||||
$read = ( $throttle !== NULL ) ? $throttle : 4096;
|
||||
|
||||
if( $start AND $length )
|
||||
if( $start !== NULL AND $length )
|
||||
{
|
||||
fseek( $fh, $start );
|
||||
|
||||
@@ -830,8 +838,13 @@ abstract class _File
|
||||
{
|
||||
$filename = mb_substr( $filename, 0, ( mb_strrpos( $filename, '.' ) ) ) . '_' . $ext;
|
||||
}
|
||||
|
||||
while( preg_match( '#\.(?!(' . implode( '|', static::$safeFileExtensions ) . '))([a-z0-9]{2,4})(\.|$)#i', $filename, $matches ) )
|
||||
{
|
||||
$filename = str_replace( '.' . $matches[2], '_' . $matches[2], $filename );
|
||||
}
|
||||
|
||||
return str_replace( array( ' ', '#' ), '_', $filename ) . '.' . md5( uniqid() ) . ( ( $safe ) ? '.' . $ext : '' );
|
||||
return str_replace( array( ' ', '#' ), '_', $filename ) . '.' . md5( uniqid( \IPS\SUITE_UNIQUE_KEY ) . mt_rand() ) . ( ( $safe ) ? '.' . $ext : '' );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -843,7 +856,6 @@ abstract class _File
|
||||
protected function unObscureFilename( $filename )
|
||||
{
|
||||
$ext = mb_substr( $filename, ( mb_strrpos( $filename, '.' ) + 1 ) );
|
||||
|
||||
if ( mb_strlen( $ext ) == 32 )
|
||||
{
|
||||
preg_match( '#(.*)_([A-Z0-9\-]{2,10})\.([A-Z0-9]{32})#i', $filename, $matches );
|
||||
@@ -852,9 +864,19 @@ abstract class _File
|
||||
{
|
||||
return $matches[1] . '.' . $matches[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Fix foo.pdf.hash */
|
||||
preg_match( '#(.*)\.([A-Z0-9\-]{2,10})\.([A-Z0-9]{32})#i', $filename, $matches );
|
||||
|
||||
if ( isset( $matches[1] ) and isset( $matches[2] ) )
|
||||
{
|
||||
return $matches[1] . '.' . $matches[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( preg_match( "/([a-zA-Z0-9]{32})\." . preg_quote( $ext ) . "$/", $filename ) )
|
||||
|
||||
if( preg_match( "/\.([a-zA-Z0-9]{32})\." . preg_quote( $ext ) . "$/", $filename ) )
|
||||
{
|
||||
return mb_substr( $filename, 0, mb_strlen( $filename ) - ( 34 + mb_strlen( $ext ) ) );
|
||||
}
|
||||
@@ -881,7 +903,7 @@ abstract class _File
|
||||
$exploded = explode( '/', $url );
|
||||
$this->filename = array_pop( $exploded );
|
||||
$this->originalFilename = $this->unObscureFilename( $this->filename );
|
||||
$this->url = new \IPS\Http\Url( $this->fullyQualifiedUrl( $this->url ) );
|
||||
$this->url = \IPS\Http\Url::createFromString( $this->fullyQualifiedUrl( $this->url ), FALSE, TRUE );
|
||||
|
||||
/* Upon upgrade we don't rename every file, so we need to account for this */
|
||||
if( mb_strpos( $this->originalFilename, '.' ) === FALSE )
|
||||
@@ -933,7 +955,7 @@ abstract class _File
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->container . '/' . $this->filename;
|
||||
return $this->container ? ( $this->container . '/' . $this->filename ) : $this->filename;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -975,12 +997,22 @@ abstract class _File
|
||||
{
|
||||
if ( mb_substr( $url, 0, 4 ) !== 'http' AND mb_substr( $url, 0, 2 ) !== '//' )
|
||||
{
|
||||
$url = $this->baseUrl() . '/' . $url;
|
||||
$url = $this->baseUrl() . '/' . $this->encodeFileUrl( $url );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode the file name for the fully qualified URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function encodeFileUrl( $filename )
|
||||
{
|
||||
return \IPS\Http\Url::encodeComponent( \IPS\Http\Url::COMPONENT_PATH, $filename );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move file to a different storage location
|
||||
*
|
||||
@@ -1094,12 +1126,15 @@ abstract class _File
|
||||
* Make into an attachment
|
||||
*
|
||||
* @param string $postKey Post key
|
||||
* @param \IPS\Member|NULL Member who uploaded the attachment
|
||||
* @return array
|
||||
* @throws \DomainException
|
||||
*/
|
||||
public function makeAttachment( $postKey )
|
||||
public function makeAttachment( $postKey, \IPS\Member $member = NULL )
|
||||
{
|
||||
$ext = mb_substr( $this->originalFilename, mb_strrpos( $this->originalFilename, '.' ) + 1 );
|
||||
$ext = mb_substr( $this->originalFilename, mb_strrpos($this->originalFilename, '.') + 1 );
|
||||
|
||||
$memberId = ( $member and $member->member_id ) ? $member->member_id : 0;
|
||||
|
||||
$data = array(
|
||||
'attach_ext' => $ext,
|
||||
@@ -1112,7 +1147,7 @@ abstract class _File
|
||||
'attach_hits' => 0,
|
||||
'attach_date' => time(),
|
||||
'attach_post_key' => $postKey,
|
||||
'attach_member_id' => \IPS\Member::loggedIn()->member_id ?: 0,
|
||||
'attach_member_id' => $memberId,
|
||||
'attach_filesize' => $this->filesize(),
|
||||
'attach_img_width' => 0,
|
||||
'attach_img_height' => 0,
|
||||
@@ -1184,7 +1219,7 @@ abstract class _File
|
||||
}
|
||||
|
||||
/**
|
||||
* Claim Attachments
|
||||
* Claim Attachments and clear autosave content
|
||||
*
|
||||
* @param string $autoSaveKey Auto-save key
|
||||
* @param int|NULL $id1 ID 1
|
||||
@@ -1208,6 +1243,9 @@ abstract class _File
|
||||
), array( 'temp=?', md5( $autoSaveKey . $lang->id ) ) );
|
||||
|
||||
\IPS\Db::i()->update( 'core_attachments', array( 'attach_post_key' => '' ), array( 'attach_post_key=?', md5( $autoSaveKey . $lang->id . ':' . session_id() ) ) );
|
||||
|
||||
|
||||
\IPS\Request::i()->setClearAutosaveCookie( $autoSaveKey . $lang->id );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1220,6 +1258,8 @@ abstract class _File
|
||||
), array( 'temp=?', md5( $autoSaveKey ) ) );
|
||||
|
||||
\IPS\Db::i()->update( 'core_attachments', array( 'attach_post_key' => '' ), array( 'attach_post_key=?', md5( $autoSaveKey . ':' . session_id() ) ) );
|
||||
|
||||
\IPS\Request::i()->setClearAutosaveCookie( $autoSaveKey );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1246,23 +1286,18 @@ abstract class _File
|
||||
}
|
||||
}
|
||||
\IPS\Db::i()->delete( 'core_attachments_map', $where );
|
||||
|
||||
/* Cleanup - this is deliberately slightly different to the one in \IPS\Text\Parser as it will only delete attachments which have been "saved" (i.e. are not in the middle of being posted) */
|
||||
foreach ( \IPS\Db::i()->select( '*', 'core_attachments', array( array( 'attach_id NOT IN(?) AND attach_post_key=?', \IPS\Db::i()->select( 'DISTINCT attachment_id', 'core_attachments_map' ), '' ) ) ) as $attachment )
|
||||
{
|
||||
try
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_attachments', array( 'attach_id=?', $attachment['attach_id'] ) );
|
||||
\IPS\File::get( 'core_Attachment', $attachment['attach_location'] )->delete();
|
||||
if ( $attachment['attach_thumb_location'] )
|
||||
{
|
||||
\IPS\File::get( 'core_Attachment', $attachment['attach_thumb_location'] )->delete();
|
||||
}
|
||||
}
|
||||
catch ( \Exception $e ) { }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This can be used to force a thumbnail name
|
||||
*/
|
||||
public $thumbnailName = NULL;
|
||||
|
||||
/**
|
||||
* @brief This can be used to force a thumbnail container
|
||||
*/
|
||||
public $thumbnailContainer = NULL;
|
||||
|
||||
/**
|
||||
* Make a thumbnail of the file - copies file, resizes and returns new file object
|
||||
*
|
||||
@@ -1295,10 +1330,10 @@ abstract class _File
|
||||
static::$thumbnailDimensions = array( $image->width, $image->height );
|
||||
|
||||
/* What are we calling this? */
|
||||
$thumbnailName = mb_substr( $this->originalFilename, 0, mb_strrpos( $this->originalFilename, '.' ) ) . '.thumb' . mb_substr( $this->originalFilename, mb_strrpos( $this->originalFilename, '.' ) );
|
||||
|
||||
$thumbnailName = $this->thumbnailName ?: mb_substr( $this->originalFilename, 0, mb_strrpos( $this->originalFilename, '.' ) ) . '.thumb' . mb_substr( $this->originalFilename, mb_strrpos( $this->originalFilename, '.' ) );
|
||||
|
||||
/* Create and return */
|
||||
return \IPS\File::create( $storageExtension, $thumbnailName, $image );
|
||||
return \IPS\File::create( $storageExtension, $thumbnailName, $image, $this->thumbnailContainer, FALSE, NULL, $this->thumbnailName ? FALSE : TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1378,7 +1413,8 @@ abstract class _File
|
||||
/* We only need to check the first 1kb of the file...some programs will use more, but this is the most common */
|
||||
$firstBytes = \substr( $data, 0, 1024 );
|
||||
|
||||
if( preg_match( '#(<script|<html|<head|<title|<body|<pre|<table|<a\s+href|<img|<plaintext|<cross\-domain\-policy)(\s|=|>)#si', $firstBytes, $matches ) )
|
||||
/* @see https://mimesniff.spec.whatwg.org/#identifying-a-resource-with-an-unknown-mime-type */
|
||||
if( preg_match( '#(<\!DOCTYPE\s+HTML|<script|<html|<head|<iframe|<h1|<div|<font|<table|<title|<style|<body|<pre|<table|<br|<a\s+href|<img|<plaintext|<cross\-domain\-policy|<\!\-\-|<\?xml)(\s|=|>)#si', $firstBytes, $matches ) )
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
@@ -1395,9 +1431,9 @@ abstract class _File
|
||||
{
|
||||
$extension = mb_strtolower( mb_substr( $filename, mb_strrpos( $filename, '.' ) + 1 ) );
|
||||
|
||||
if ( array_key_exists( $extension, self::$mimeTypes ) )
|
||||
if ( array_key_exists( $extension, static::$mimeTypes ) )
|
||||
{
|
||||
return self::$mimeTypes[ $extension ];
|
||||
return static::$mimeTypes[ $extension ];
|
||||
}
|
||||
|
||||
return 'application/x-unknown'; // This, slightly unusual, type is needed to stop some browsers adding random extensions
|
||||
@@ -1420,6 +1456,9 @@ abstract class _File
|
||||
|
||||
/* Get the last character, which may be 'm' or may be a number */
|
||||
$last = mb_strtolower( $size[ \strlen( $size ) - 1 ] );
|
||||
|
||||
/* Convert $size to a number */
|
||||
$size = intval( preg_replace( '/[^0-9]/', '', $size ) );
|
||||
|
||||
/* Adjust value as necessary - note that we do not break intentionally */
|
||||
switch( $last )
|
||||
@@ -1435,6 +1474,23 @@ abstract class _File
|
||||
return (float) $size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get output for API
|
||||
*
|
||||
* @return array
|
||||
* @apiresponse string name The filename
|
||||
* @apiresponse string url URL to where file is stored
|
||||
* @apiresponse int size Filesize in bytes
|
||||
*/
|
||||
public function apiOutput()
|
||||
{
|
||||
return array(
|
||||
'name' => $this->originalFilename,
|
||||
'url' => (string) $this->url,
|
||||
'size' => $this->filesize()
|
||||
);
|
||||
}
|
||||
|
||||
/* !Mime-Type Map */
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user