Вход Регистрация
Файл: contao-3.5.8/system/modules/core/library/Contao/File.php
Строк: 661
<?php

/**
 * Contao Open Source CMS
 *
 * Copyright (c) 2005-2016 Leo Feyer
 *
 * @license LGPL-3.0+
 */

namespace Contao;


/**
 * Creates, reads, writes and deletes files
 *
 * Usage:
 *
 *     $file = new File('test.txt');
 *     $file->write('This is a test');
 *     $file->close();
 *
 *     $file->delete();
 *
 *     File::putContent('test.txt', 'This is a test');
 *
 * @property integer  $size          The file size
 * @property integer  $filesize      Alias of $size
 * @property string   $name          The file name and extension
 * @property string   $basename      Alias of $name
 * @property string   $dirname       The path of the parent folder
 * @property string   $extension     The file extension
 * @property string   $filename      The file name without extension
 * @property string   $tmpname       The name of the temporary file
 * @property string   $path          The file path
 * @property string   $value         Alias of $path
 * @property string   $mime          The mime type
 * @property string   $hash          The MD5 checksum
 * @property string   $ctime         The ctime
 * @property string   $mtime         The mtime
 * @property string   $atime         The atime
 * @property string   $icon          The mime icon name
 * @property array    $imageSize     The file dimensions (images only)
 * @property integer  $width         The file width (images only)
 * @property integer  $height        The file height (images only)
 * @property array    $imageViewSize The viewbox dimensions (SVG images only)
 * @property integer  $viewWidth     The viewbox width (SVG images only)
 * @property integer  $viewHeight    The viewbox height (SVG images only)
 * @property boolean  $isImage       True if the file is an image
 * @property boolean  $isGdImage     True if the file can be handled by the GDlib
 * @property boolean  $isSvgImage    True if the file is an SVG image
 * @property integer  $channels      The number of channels (images only)
 * @property integer  $bits          The number of bits for each color (images only)
 * @property boolean  $isRgbImage    True if the file is an RGB image
 * @property boolean  $isCmykImage   True if the file is a CMYK image
 * @property resource $handle        The file handle (returned by fopen())
 * @property string   $title         The file title
 *
 * @author Leo Feyer <https://github.com/leofeyer>
 */
class File extends System
{

    
/**
     * File handle
     * @var resource
     */
    
protected $resFile;

    
/**
     * File name
     * @var string
     */
    
protected $strFile;

    
/**
     * Temp name
     * @var string
     */
    
protected $strTmp;

    
/**
     * Files model
     * @var FilesModel
     */
    
protected $objModel;

    
/**
     * Pathinfo
     * @var array
     */
    
protected $arrPathinfo = array();

    
/**
     * Image size
     * @var array
     */
    
protected $arrImageSize = array();

    
/**
     * Image view size
     * @var array
     */
    
protected $arrImageViewSize = array();

    
/**
     * Do not create the file
     * @var string
     */
    
protected $blnDoNotCreate false;


    
/**
     * Instantiate a new file object
     *
     * @param string  $strFile        The file path
     * @param boolean $blnDoNotCreate If true, the file will not be autocreated
     *
     * @throws Exception If $strFile is a directory
     */
    
public function __construct($strFile$blnDoNotCreate=false)
    {
        
// No parent::__construct() here

        // Handle open_basedir restrictions
        
if ($strFile == '.')
        {
            
$strFile '';
        }

        
// Make sure we are not pointing to a directory
        
if (is_dir(TL_ROOT '/' $strFile))
        {
            throw new 
Exception(sprintf('Directory "%s" is not a file'$strFile));
        }

        
$this->import('Files');

        
$this->strFile $strFile;
        
$this->blnDoNotCreate $blnDoNotCreate;

        if (!
$blnDoNotCreate)
        {
            
$this->createIfNotExists();
        }
    }


    
/**
     * Close the file handle if it has not been done yet
     */
    
public function __destruct()
    {
        if (
is_resource($this->resFile))
        {
            
$this->Files->fclose($this->resFile);
        }
    }


    
/**
     * Return an object property
     *
     * @param string $strKey The property name
     *
     * @return mixed The property value
     */
    
public function __get($strKey)
    {
        switch (
$strKey)
        {
            case 
'size':
            case 
'filesize':
                return 
filesize(TL_ROOT '/' $this->strFile);
                break;

            case 
'name':
            case 
'basename':
                if (!isset(
$this->arrPathinfo[$strKey]))
                {
                    
$this->arrPathinfo pathinfo(TL_ROOT '/' $this->strFile);
                }
                return 
$this->arrPathinfo['basename'];
                break;

            case 
'dirname':
                if (!isset(
$this->arrPathinfo[$strKey]))
                {
                    
$this->arrPathinfo pathinfo(TL_ROOT '/' $this->strFile);
                }
                return 
$this->arrPathinfo['dirname'];
                break;

            case 
'extension':
                if (!isset(
$this->arrPathinfo['extension']))
                {
                    
$this->arrPathinfo pathinfo(TL_ROOT '/' $this->strFile);
                }
                return 
strtolower($this->arrPathinfo['extension']);
                break;

            case 
'filename':
                if (!isset(
$this->arrPathinfo[$strKey]))
                {
                    
$this->arrPathinfo pathinfo(TL_ROOT '/' $this->strFile);
                }
                return 
$this->arrPathinfo['filename'];
                break;

            case 
'tmpname':
                return 
basename($this->strTmp);
                break;

            case 
'path':
            case 
'value':
                return 
$this->strFile;
                break;

            case 
'mime':
                return 
$this->getMimeType();
                break;

            case 
'hash':
                return 
$this->getHash();
                break;

            case 
'ctime':
                return 
filectime(TL_ROOT '/' $this->strFile);
                break;

            case 
'mtime':
                return 
filemtime(TL_ROOT '/' $this->strFile);
                break;

            case 
'atime':
                return 
fileatime(TL_ROOT '/' $this->strFile);
                break;

            case 
'icon':
                return 
$this->getIcon();
                break;

            case 
'imageSize':
                if (empty(
$this->arrImageSize))
                {
                    if (
$this->isGdImage)
                    {
                        
$this->arrImageSize = @getimagesize(TL_ROOT '/' $this->strFile);
                    }
                    elseif (
$this->isSvgImage)
                    {
                        
$doc = new DOMDocument();

                        if (
$this->extension == 'svgz')
                        {
                            
$doc->loadXML(gzdecode($this->getContent()));
                        }
                        else
                        {
                            
$doc->loadXML($this->getContent());
                        }

                        
$svgElement $doc->documentElement;

                        if (
$svgElement->getAttribute('width') && $svgElement->getAttribute('height') && substr(rtrim($svgElement->getAttribute('width')), -1) != '%' && substr(rtrim($svgElement->getAttribute('height')), -1) != '%')
                        {
                            
$this->arrImageSize = array
                            (
                                
Image::getPixelValue($svgElement->getAttribute('width')),
                                
Image::getPixelValue($svgElement->getAttribute('height'))
                            );
                        }

                        if (
$this->arrImageSize && $this->arrImageSize[0] && $this->arrImageSize[1])
                        {
                            
$this->arrImageSize[2] = 0// replace this with IMAGETYPE_SVG when it becomes available
                            
$this->arrImageSize[3] = 'width="' $this->arrImageSize[0] . '" height="' $this->arrImageSize[1] . '"';
                            
$this->arrImageSize['bits'] = 8;
                            
$this->arrImageSize['channels'] = 3;
                            
$this->arrImageSize['mime'] = $this->getMimeType();
                        }
                        else
                        {
                            
$this->arrImageSize false;
                        }
                    }
                }
                return 
$this->arrImageSize;
                break;

            case 
'width':
                return 
$this->imageSize[0];
                break;

            case 
'height':
                return 
$this->imageSize[1];
                break;

            case 
'imageViewSize':
                if (empty(
$this->arrImageViewSize))
                {
                    if (
$this->imageSize)
                    {
                        
$this->arrImageViewSize = array
                        (
                            
$this->imageSize[0],
                            
$this->imageSize[1]
                        );
                    }
                    elseif (
$this->isSvgImage)
                    {
                        
$doc = new DOMDocument();

                        if (
$this->extension == 'svgz')
                        {
                            
$doc->loadXML(gzdecode($this->getContent()));
                        }
                        else
                        {
                            
$doc->loadXML($this->getContent());
                        }

                        
$svgElement $doc->documentElement;

                        if (
$svgElement->getAttribute('viewBox'))
                        {
                            
$svgViewBox preg_split('/[s,]+/'$svgElement->getAttribute('viewBox'));

                            
$this->arrImageViewSize = array
                            (
                                
intval($svgViewBox[2]),
                                
intval($svgViewBox[3])
                            );
                        }

                        if (!
$this->arrImageViewSize || !$this->arrImageViewSize[0] || !$this->arrImageViewSize[1])
                        {
                            
$this->arrImageViewSize false;
                        }
                    }
                }
                return 
$this->arrImageViewSize;
                break;

            case 
'viewWidth':
                return 
$this->imageViewSize[0];
                break;

            case 
'viewHeight':
                return 
$this->imageViewSize[1];
                break;

            case 
'isImage':
                return 
$this->isGdImage || $this->isSvgImage;
                break;

            case 
'isGdImage':
                return 
in_array($this->extension, array('gif''jpg''jpeg''png'));
                break;

            case 
'isSvgImage':
                return 
in_array($this->extension, array('svg''svgz'));
                break;

            case 
'channels':
                return 
$this->imageSize['channels'];
                break;

            case 
'bits':
                return 
$this->imageSize['bits'];
                break;

            case 
'isRgbImage':
                return (
$this->channels == 3);
                break;

            case 
'isCmykImage':
                return (
$this->channels == 4);
                break;

            case 
'handle':
                if (!
is_resource($this->resFile))
                {
                    
$this->resFile fopen(TL_ROOT '/' $this->strFile'rb');
                }
                return 
$this->resFile;
                break;

            default:
                return 
parent::__get($strKey);
                break;
        }
    }


    
/**
     * Create the file if it does not yet exist
     *
     * @throws Exception If the file cannot be written
     */
    
protected function createIfNotExists()
    {
        
// The file exists
        
if (file_exists(TL_ROOT '/' $this->strFile))
        {
            return;
        }

        
// Handle open_basedir restrictions
        
if (($strFolder dirname($this->strFile)) == '.')
        {
            
$strFolder '';
        }

        
// Create the folder
        
if (!is_dir(TL_ROOT '/' $strFolder))
        {
            new 
Folder($strFolder);
        }

        
// Open the file
        
if (($this->resFile $this->Files->fopen($this->strFile'wb')) == false)
        {
            throw new 
Exception(sprintf('Cannot create file "%s"'$this->strFile));
        }
    }


    
/**
     * Check whether the file exists
     *
     * @return boolean True if the file exists
     */
    
public function exists()
    {
        return 
$this->blnDoNotCreate file_exists(TL_ROOT '/' $this->strFile) : true;
    }


    
/**
     * Truncate the file and reset the file pointer
     *
     * @return boolean True if the operation was successful
     */
    
public function truncate()
    {
        if (
is_resource($this->resFile))
        {
            
ftruncate($this->resFile0);
            
rewind($this->resFile);
        }

        return 
$this->write('');
    }


    
/**
     * Write data to the file
     *
     * @param mixed $varData The data to be written
     *
     * @return boolean True if the operation was successful
     */
    
public function write($varData)
    {
        return 
$this->fputs($varData'wb');
    }


    
/**
     * Append data to the file
     *
     * @param mixed  $varData The data to be appended
     * @param string $strLine The line ending (defaults to LF)
     *
     * @return boolean True if the operation was successful
     */
    
public function append($varData$strLine="n")
    {
        return 
$this->fputs($varData $strLine'ab');
    }


    
/**
     * Prepend data to the file
     *
     * @param mixed  $varData The data to be prepended
     * @param string $strLine The line ending (defaults to LF)
     *
     * @return boolean True if the operation was successful
     */
    
public function prepend($varData$strLine="n")
    {
        return 
$this->fputs($varData $strLine $this->getContent(), 'wb');
    }


    
/**
     * Delete the file
     *
     * @return boolean True if the operation was successful
     */
    
public function delete()
    {
        
$return $this->Files->delete($this->strFile);

        
// Update the database
        
if (Dbafs::shouldBeSynchronized($this->strFile))
        {
            
Dbafs::deleteResource($this->strFile);
        }

        return 
$return;
    }


    
/**
     * Set the file permissions
     *
     * @param integer $intChmod The CHMOD settings
     *
     * @return boolean True if the operation was successful
     */
    
public function chmod($intChmod)
    {
        return 
$this->Files->chmod($this->strFile$intChmod);
    }


    
/**
     * Close the file handle
     *
     * @return boolean True if the operation was successful
     */
    
public function close()
    {
        
$return true;

        if (
is_resource($this->resFile))
        {
            
$return $this->Files->fclose($this->resFile);
        }

        
// Move the temporary file to its destination
        
if ($this->blnDoNotCreate)
        {
            
// Create the file path
            
if (!file_exists(TL_ROOT '/' $this->strFile))
            {
                
// Handle open_basedir restrictions
                
if (($strFolder dirname($this->strFile)) == '.')
                {
                    
$strFolder '';
                }

                
// Create the parent folder
                
if (!is_dir(TL_ROOT '/' $strFolder))
                {
                    new 
Folder($strFolder);
                }
            }

            
$return $this->Files->rename($this->strTmp$this->strFile);
        }

        
// Update the database
        
if (Dbafs::shouldBeSynchronized($this->strFile))
        {
            
$this->objModel Dbafs::addResource($this->strFile);
        }

        return 
$return;
    }


    
/**
     * Return the files model
     *
     * @return FilesModel The files model
     */
    
public function getModel()
    {
        if (
$this->objModel === null && Dbafs::shouldBeSynchronized($this->strFile))
        {
            
$this->objModel FilesModel::findByPath($this->strFile);
        }

        return 
$this->objModel;
    }


    
/**
     * Return the file content as string
     *
     * @return string The file content without BOM
     */
    
public function getContent()
    {
        
$strContent file_get_contents(TL_ROOT '/' $this->strFile);

        
// Remove BOMs (see #4469)
        
if (strncmp($strContent"xEFxBBxBF"3) === 0)
        {
            
$strContent substr($strContent3);
        }
        elseif (
strncmp($strContent"xFFxFE"2) === 0)
        {
            
$strContent substr($strContent2);
        }
        elseif (
strncmp($strContent"xFExFF"2) === 0)
        {
            
$strContent substr($strContent2);
        }

        return 
$strContent;
    }


    
/**
     * Write to a file
     *
     * @param string $strFile    Relative file name
     * @param string $strContent Content to be written
     */
    
public static function putContent($strFile$strContent)
    {
        
$objFile = new static($strFiletrue);
        
$objFile->write($strContent);
        
$objFile->close();
    }


    
/**
     * Return the file content as array
     *
     * @return array The file content as array
     */
    
public function getContentAsArray()
    {
        return 
array_map('rtrim'file(TL_ROOT '/' $this->strFile));
    }


    
/**
     * Rename the file
     *
     * @param string $strNewName The new path
     *
     * @return boolean True if the operation was successful
     */
    
public function renameTo($strNewName)
    {
        
$strParent dirname($strNewName);

        
// Create the parent folder if it does not exist
        
if (!is_dir(TL_ROOT '/' $strParent))
        {
            new 
Folder($strParent);
        }

        
$return $this->Files->rename($this->strFile$strNewName);

        
// Update the database AFTER the file has been renamed
        
$syncSource Dbafs::shouldBeSynchronized($this->strFile);
        
$syncTarget Dbafs::shouldBeSynchronized($strNewName);

        
// Synchronize the database
        
if ($syncSource && $syncTarget)
        {
            
$this->objModel Dbafs::moveResource($this->strFile$strNewName);
        }
        elseif (
$syncSource)
        {
            
$this->objModel Dbafs::deleteResource($this->strFile);
        }
        elseif (
$syncTarget)
        {
            
$this->objModel Dbafs::addResource($strNewName);
        }

        
// Reset the object AFTER the database has been updated
        
if ($return != false)
        {
            
$this->strFile $strNewName;
            
$this->arrImageSize = array();
            
$this->arrPathinfo = array();
        }

        return 
$return;
    }


    
/**
     * Copy the file
     *
     * @param string $strNewName The target path
     *
     * @return boolean True if the operation was successful
     */
    
public function copyTo($strNewName)
    {
        
$strParent dirname($strNewName);

        
// Create the parent folder if it does not exist
        
if (!is_dir(TL_ROOT '/' $strParent))
        {
            new 
Folder($strParent);
        }

        
$this->Files->copy($this->strFile$strNewName);

        
// Update the database AFTER the file has been renamed
        
$syncSource Dbafs::shouldBeSynchronized($this->strFile);
        
$syncTarget Dbafs::shouldBeSynchronized($strNewName);

        
// Synchronize the database
        
if ($syncSource && $syncTarget)
        {
            
Dbafs::copyResource($this->strFile$strNewName);
        }
        elseif (
$syncTarget)
        {
            
Dbafs::addResource($strNewName);
        }

        return 
true;
    }


    
/**
     * Resize the file if it is an image
     *
     * @param integer $width  The target width
     * @param integer $height The target height
     * @param string  $mode   The resize mode
     *
     * @return boolean True if the image could be resized successfully
     */
    
public function resizeTo($width$height$mode='')
    {
        if (!
$this->isImage)
        {
            return 
false;
        }

        
$return Image::resize($this->strFile$width$height$mode);

        if (
$return)
        {
            
$this->arrPathinfo = array();
            
$this->arrImageSize = array();
        }

        return 
$return;
    }


    
/**
     * Send the file to the browser
     *
     * @param string $filename An optional filename
     */
    
public function sendToBrowser($filename=null)
    {
        
// Make sure no output buffer is active
        // @see http://ch2.php.net/manual/en/function.fpassthru.php#74080
        
while (@ob_end_clean());

        
// Prevent session locking (see #2804)
        
session_write_close();

        
// Disable zlib.output_compression (see #6717)
        
ini_set('zlib.output_compression''Off');

        
// Open the "save as …" dialogue
        
header('Content-Type: ' $this->mime);
        
header('Content-Transfer-Encoding: binary');
        
header('Content-Disposition: attachment; filename="' . ($filename ?: $this->basename) . '"');
        
header('Content-Length: ' $this->filesize);
        
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        
header('Pragma: public');
        
header('Expires: 0');
        
header('Connection: close');

        
// Output the file
        
$resFile fopen(TL_ROOT '/' $this->strFile'rb');
        
fpassthru($resFile);
        
fclose($resFile);

        
// Stop the script
        
exit;
    }


    
/**
     * Write data to a file
     *
     * @param mixed  $varData The data to be written
     * @param string $strMode The operation mode
     *
     * @return boolean True if the operation was successful
     */
    
protected function fputs($varData$strMode)
    {
        if (!
is_resource($this->resFile))
        {
            if (!
$this->blnDoNotCreate)
            {
                
// Open the original file
                
if (($this->resFile $this->Files->fopen($this->strFile$strMode)) == false)
                {
                    return 
false;
                }
            }
            else
            {
                
$this->strTmp 'system/tmp/' md5(uniqid(mt_rand(), true));

                
// Copy the contents of the original file to append data
                
if (strncmp($strMode'a'1) === && file_exists(TL_ROOT '/' $this->strFile))
                {
                    
$this->Files->copy($this->strFile$this->strTmp);
                }

                
// Open the temporary file
                
if (($this->resFile $this->Files->fopen($this->strTmp$strMode)) == false)
                {
                    return 
false;
                }
            }
        }

        
fputs($this->resFile$varData);

        return 
true;
    }


    
/**
     * Return the mime type and icon of the file based on its extension
     *
     * @return array An array with mime type and icon name
     */
    
protected function getMimeInfo()
    {
        if (isset(
$GLOBALS['TL_MIME'][$this->extension]))
        {
            return 
$GLOBALS['TL_MIME'][$this->extension];
        }

        return array(
'application/octet-stream''iconPLAIN.gif');
    }


    
/**
     * Get the mime type of the file based on its extension
     *
     * @return string The mime type
     */
    
protected function getMimeType()
    {
        
$arrMime $this->getMimeInfo();

        return 
$arrMime[0];
    }


    
/**
     * Return the file icon depending on the file type
     *
     * @return string The icon name
     */
    
protected function getIcon()
    {
        
$arrMime $this->getMimeInfo();

        return 
$arrMime[1];
    }


    
/**
     * Return the MD5 hash of the file
     *
     * @return string The MD5 hash
     */
    
protected function getHash()
    {
        
// Do not try to hash if bigger than 2 GB
        
if ($this->filesize >= 2147483648)
        {
            return 
'';
        }
        else
        {
            return 
md5_file(TL_ROOT '/' $this->strFile);
        }
    }
}
Онлайн: 1
Реклама