vendor/contao/core-bundle/src/Resources/contao/library/Contao/File.php line 261

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of Contao.
  4.  *
  5.  * (c) Leo Feyer
  6.  *
  7.  * @license LGPL-3.0-or-later
  8.  */
  9. namespace Contao;
  10. use Contao\CoreBundle\Exception\ResponseException;
  11. use Contao\Image\DeferredImageInterface;
  12. use Contao\Image\ImageDimensions;
  13. use Patchwork\Utf8;
  14. use Symfony\Component\HttpFoundation\BinaryFileResponse;
  15. use Symfony\Component\HttpFoundation\ResponseHeaderBag;
  16. /**
  17.  * Creates, reads, writes and deletes files
  18.  *
  19.  * Usage:
  20.  *
  21.  *     $file = new File('test.txt');
  22.  *     $file->write('This is a test');
  23.  *     $file->close();
  24.  *
  25.  *     $file->delete();
  26.  *
  27.  *     File::putContent('test.txt', 'This is a test');
  28.  *
  29.  * @property integer  $size          The file size
  30.  * @property integer  $filesize      Alias of $size
  31.  * @property string   $name          The file name and extension
  32.  * @property string   $basename      Alias of $name
  33.  * @property string   $dirname       The path of the parent folder
  34.  * @property string   $extension     The lowercase file extension
  35.  * @property string   $origext       The original file extension
  36.  * @property string   $filename      The file name without extension
  37.  * @property string   $tmpname       The name of the temporary file
  38.  * @property string   $path          The file path
  39.  * @property string   $value         Alias of $path
  40.  * @property string   $mime          The mime type
  41.  * @property string   $hash          The MD5 checksum
  42.  * @property string   $ctime         The ctime
  43.  * @property string   $mtime         The mtime
  44.  * @property string   $atime         The atime
  45.  * @property string   $icon          The mime icon name
  46.  * @property string   $dataUri       The data URI
  47.  * @property array    $imageSize     The file dimensions (images only)
  48.  * @property integer  $width         The file width (images only)
  49.  * @property integer  $height        The file height (images only)
  50.  * @property array    $imageViewSize The viewbox dimensions
  51.  * @property integer  $viewWidth     The viewbox width
  52.  * @property integer  $viewHeight    The viewbox height
  53.  * @property boolean  $isImage       True if the file is an image
  54.  * @property boolean  $isGdImage     True if the file can be handled by the GDlib
  55.  * @property boolean  $isSvgImage    True if the file is an SVG image
  56.  * @property integer  $channels      The number of channels (images only)
  57.  * @property integer  $bits          The number of bits for each color (images only)
  58.  * @property boolean  $isRgbImage    True if the file is an RGB image
  59.  * @property boolean  $isCmykImage   True if the file is a CMYK image
  60.  * @property resource $handle        The file handle (returned by fopen())
  61.  * @property string   $title         The file title
  62.  *
  63.  * @author Leo Feyer <https://github.com/leofeyer>
  64.  */
  65. class File extends System
  66. {
  67.     /**
  68.      * File handle
  69.      * @var resource
  70.      */
  71.     protected $resFile;
  72.     /**
  73.      * File name
  74.      * @var string
  75.      */
  76.     protected $strFile;
  77.     /**
  78.      * Temp name
  79.      * @var string
  80.      */
  81.     protected $strTmp;
  82.     /**
  83.      * Files model
  84.      * @var FilesModel
  85.      */
  86.     protected $objModel;
  87.     /**
  88.      * Root dir
  89.      * @var string
  90.      */
  91.     protected $strRootDir;
  92.     /**
  93.      * Pathinfo
  94.      * @var array
  95.      */
  96.     protected $arrPathinfo = array();
  97.     /**
  98.      * Image size
  99.      * @var array
  100.      */
  101.     protected $arrImageSize = array();
  102.     /**
  103.      * Image size runtime cache
  104.      * @var array
  105.      */
  106.     protected static $arrImageSizeCache = array();
  107.     /**
  108.      * Image view size
  109.      * @var array
  110.      */
  111.     protected $arrImageViewSize = array();
  112.     /**
  113.      * Instantiate a new file object
  114.      *
  115.      * @param string $strFile The file path
  116.      *
  117.      * @throws \Exception If $strFile is a directory
  118.      */
  119.     public function __construct($strFile)
  120.     {
  121.         // Handle open_basedir restrictions
  122.         if ($strFile == '.')
  123.         {
  124.             $strFile '';
  125.         }
  126.         $this->strRootDir System::getContainer()->getParameter('kernel.project_dir');
  127.         // Make sure we are not pointing to a directory
  128.         if (is_dir($this->strRootDir '/' $strFile))
  129.         {
  130.             throw new \Exception(sprintf('Directory "%s" is not a file'$strFile));
  131.         }
  132.         $this->import(Files::class, 'Files');
  133.         $this->strFile $strFile;
  134.     }
  135.     /**
  136.      * Close the file handle if it has not been done yet
  137.      */
  138.     public function __destruct()
  139.     {
  140.         if (\is_resource($this->resFile))
  141.         {
  142.             $this->Files->fclose($this->resFile);
  143.         }
  144.     }
  145.     /**
  146.      * Return an object property
  147.      *
  148.      * @param string $strKey The property name
  149.      *
  150.      * @return mixed The property value
  151.      */
  152.     public function __get($strKey)
  153.     {
  154.         switch ($strKey)
  155.         {
  156.             case 'size':
  157.             case 'filesize':
  158.                 return filesize($this->strRootDir '/' $this->strFile);
  159.             case 'name':
  160.             case 'basename':
  161.                 if (!isset($this->arrPathinfo[$strKey]))
  162.                 {
  163.                     $this->arrPathinfo $this->getPathinfo();
  164.                 }
  165.                 return $this->arrPathinfo['basename'];
  166.             case 'dirname':
  167.             case 'filename':
  168.                 if (!isset($this->arrPathinfo[$strKey]))
  169.                 {
  170.                     $this->arrPathinfo $this->getPathinfo();
  171.                 }
  172.                 return $this->arrPathinfo[$strKey];
  173.             case 'extension':
  174.                 if (!isset($this->arrPathinfo['extension']))
  175.                 {
  176.                     $this->arrPathinfo $this->getPathinfo();
  177.                 }
  178.                 return strtolower($this->arrPathinfo['extension']);
  179.             case 'origext':
  180.                 if (!isset($this->arrPathinfo['extension']))
  181.                 {
  182.                     $this->arrPathinfo $this->getPathinfo();
  183.                 }
  184.                 return $this->arrPathinfo['extension'];
  185.             case 'tmpname':
  186.                 return basename($this->strTmp);
  187.             case 'path':
  188.             case 'value':
  189.                 return $this->strFile;
  190.             case 'mime':
  191.                 return $this->getMimeType();
  192.             case 'hash':
  193.                 return $this->getHash();
  194.             case 'ctime':
  195.                 return filectime($this->strRootDir '/' $this->strFile);
  196.             case 'mtime':
  197.                 return filemtime($this->strRootDir '/' $this->strFile);
  198.             case 'atime':
  199.                 return fileatime($this->strRootDir '/' $this->strFile);
  200.             case 'icon':
  201.                 return $this->getIcon();
  202.             case 'dataUri':
  203.                 if ($this->extension == 'svgz')
  204.                 {
  205.                     return 'data:' $this->mime ';base64,' base64_encode(gzdecode($this->getContent()));
  206.                 }
  207.                 return 'data:' $this->mime ';base64,' base64_encode($this->getContent());
  208.             case 'imageSize':
  209.                 if (empty($this->arrImageSize))
  210.                 {
  211.                     $strCacheKey $this->strFile '|' . ($this->exists() ? $this->mtime 0);
  212.                     if (isset(static::$arrImageSizeCache[$strCacheKey]))
  213.                     {
  214.                         $this->arrImageSize = static::$arrImageSizeCache[$strCacheKey];
  215.                     }
  216.                     else
  217.                     {
  218.                         $imageFactory System::getContainer()->get('contao.image.image_factory');
  219.                         try
  220.                         {
  221.                             $dimensions $imageFactory->create($this->strRootDir '/' $this->strFile)->getDimensions();
  222.                             if (!$dimensions->isRelative() && !$dimensions->isUndefined())
  223.                             {
  224.                                 $mapper = array
  225.                                 (
  226.                                     'gif' => IMAGETYPE_GIF,
  227.                                     'jpg' => IMAGETYPE_JPEG,
  228.                                     'jpeg' => IMAGETYPE_JPEG,
  229.                                     'png' => IMAGETYPE_PNG,
  230.                                     'webp' => IMAGETYPE_WEBP,
  231.                                 );
  232.                                 $this->arrImageSize = array
  233.                                 (
  234.                                     $dimensions->getSize()->getWidth(),
  235.                                     $dimensions->getSize()->getHeight(),
  236.                                     $mapper[$this->extension] ?? 0,
  237.                                     'width="' $dimensions->getSize()->getWidth() . '" height="' $dimensions->getSize()->getHeight() . '"',
  238.                                     'bits' => 8,
  239.                                     'channels' => 3,
  240.                                     'mime' => $this->getMimeType()
  241.                                 );
  242.                             }
  243.                         }
  244.                         catch (\Exception $e)
  245.                         {
  246.                             // ignore
  247.                         }
  248.                     }
  249.                     if (!isset(static::$arrImageSizeCache[$strCacheKey]))
  250.                     {
  251.                         static::$arrImageSizeCache[$strCacheKey] = $this->arrImageSize;
  252.                     }
  253.                 }
  254.                 return $this->arrImageSize;
  255.             case 'width':
  256.                 return $this->imageSize[0];
  257.             case 'height':
  258.                 return $this->imageSize[1];
  259.             case 'imageViewSize':
  260.                 if (empty($this->arrImageViewSize))
  261.                 {
  262.                     if ($this->imageSize)
  263.                     {
  264.                         $this->arrImageViewSize = array
  265.                         (
  266.                             $this->imageSize[0],
  267.                             $this->imageSize[1]
  268.                         );
  269.                     }
  270.                     elseif ($this->isSvgImage)
  271.                     {
  272.                         try
  273.                         {
  274.                             $dimensions = new ImageDimensions(
  275.                                 System::getContainer()
  276.                                     ->get('contao.image.imagine_svg')
  277.                                     ->open($this->strRootDir '/' $this->strFile)
  278.                                     ->getSize()
  279.                             );
  280.                             $this->arrImageViewSize = array
  281.                             (
  282.                                 (int) $dimensions->getSize()->getWidth(),
  283.                                 (int) $dimensions->getSize()->getHeight()
  284.                             );
  285.                             if (!$this->arrImageViewSize[0] || !$this->arrImageViewSize[1] || $dimensions->isUndefined())
  286.                             {
  287.                                 $this->arrImageViewSize false;
  288.                             }
  289.                         }
  290.                         catch (\Exception $e)
  291.                         {
  292.                             $this->arrImageViewSize false;
  293.                         }
  294.                     }
  295.                 }
  296.                 return $this->arrImageViewSize;
  297.             case 'viewWidth':
  298.                 // Store in variable as empty() calls __isset() which is not implemented and thus alway true
  299.                 $imageViewSize $this->imageViewSize;
  300.                 return !empty($imageViewSize) ? $imageViewSize[0] : null;
  301.             case 'viewHeight':
  302.                 // Store in variable as empty() calls __isset() which is not implemented and thus alway true
  303.                 $imageViewSize $this->imageViewSize;
  304.                 return !empty($imageViewSize) ? $imageViewSize[1] : null;
  305.             case 'isImage':
  306.                 return $this->isGdImage || $this->isSvgImage;
  307.             case 'isGdImage':
  308.                 return \in_array($this->extension, array('gif''jpg''jpeg''png''webp'));
  309.             case 'isSvgImage':
  310.                 return \in_array($this->extension, array('svg''svgz'));
  311.             case 'channels':
  312.                 return $this->imageSize['channels'];
  313.             case 'bits':
  314.                 return $this->imageSize['bits'];
  315.             case 'isRgbImage':
  316.                 return $this->channels == 3;
  317.             case 'isCmykImage':
  318.                 return $this->channels == 4;
  319.             case 'handle':
  320.                 if (!\is_resource($this->resFile))
  321.                 {
  322.                     $this->resFile fopen($this->strRootDir '/' $this->strFile'r');
  323.                 }
  324.                 return $this->resFile;
  325.             default:
  326.                 return parent::__get($strKey);
  327.         }
  328.     }
  329.     /**
  330.      * Create the file if it does not yet exist
  331.      *
  332.      * @throws \Exception If the file cannot be written
  333.      */
  334.     protected function createIfNotExists()
  335.     {
  336.         // The file exists
  337.         if (file_exists($this->strRootDir '/' $this->strFile))
  338.         {
  339.             return;
  340.         }
  341.         // Handle open_basedir restrictions
  342.         if (($strFolder = \dirname($this->strFile)) == '.')
  343.         {
  344.             $strFolder '';
  345.         }
  346.         // Create the folder
  347.         if (!is_dir($this->strRootDir '/' $strFolder))
  348.         {
  349.             new Folder($strFolder);
  350.         }
  351.         // Open the file
  352.         if (!$this->resFile $this->Files->fopen($this->strFile'wb'))
  353.         {
  354.             throw new \Exception(sprintf('Cannot create file "%s"'$this->strFile));
  355.         }
  356.     }
  357.     /**
  358.      * Check whether the file exists
  359.      *
  360.      * @return boolean True if the file exists
  361.      */
  362.     public function exists()
  363.     {
  364.         return file_exists($this->strRootDir '/' $this->strFile);
  365.     }
  366.     /**
  367.      * Truncate the file and reset the file pointer
  368.      *
  369.      * @return boolean True if the operation was successful
  370.      */
  371.     public function truncate()
  372.     {
  373.         if (\is_resource($this->resFile))
  374.         {
  375.             ftruncate($this->resFile0);
  376.             rewind($this->resFile);
  377.         }
  378.         return $this->write('');
  379.     }
  380.     /**
  381.      * Write data to the file
  382.      *
  383.      * @param mixed $varData The data to be written
  384.      *
  385.      * @return boolean True if the operation was successful
  386.      */
  387.     public function write($varData)
  388.     {
  389.         return $this->fputs($varData'wb');
  390.     }
  391.     /**
  392.      * Append data to the file
  393.      *
  394.      * @param mixed  $varData The data to be appended
  395.      * @param string $strLine The line ending (defaults to LF)
  396.      *
  397.      * @return boolean True if the operation was successful
  398.      */
  399.     public function append($varData$strLine="\n")
  400.     {
  401.         return $this->fputs($varData $strLine'ab');
  402.     }
  403.     /**
  404.      * Prepend data to the file
  405.      *
  406.      * @param mixed  $varData The data to be prepended
  407.      * @param string $strLine The line ending (defaults to LF)
  408.      *
  409.      * @return boolean True if the operation was successful
  410.      */
  411.     public function prepend($varData$strLine="\n")
  412.     {
  413.         return $this->fputs($varData $strLine $this->getContent(), 'wb');
  414.     }
  415.     /**
  416.      * Delete the file
  417.      *
  418.      * @return boolean True if the operation was successful
  419.      */
  420.     public function delete()
  421.     {
  422.         $return $this->Files->delete($this->strFile);
  423.         // Update the database
  424.         if (Dbafs::shouldBeSynchronized($this->strFile))
  425.         {
  426.             Dbafs::deleteResource($this->strFile);
  427.         }
  428.         return $return;
  429.     }
  430.     /**
  431.      * Set the file permissions
  432.      *
  433.      * @param integer $intChmod The CHMOD settings
  434.      *
  435.      * @return boolean True if the operation was successful
  436.      */
  437.     public function chmod($intChmod)
  438.     {
  439.         return $this->Files->chmod($this->strFile$intChmod);
  440.     }
  441.     /**
  442.      * Close the file handle
  443.      *
  444.      * @return boolean True if the operation was successful
  445.      */
  446.     public function close()
  447.     {
  448.         if (\is_resource($this->resFile))
  449.         {
  450.             $this->Files->fclose($this->resFile);
  451.         }
  452.         // Create the file path
  453.         if (!file_exists($this->strRootDir '/' $this->strFile))
  454.         {
  455.             // Handle open_basedir restrictions
  456.             if (($strFolder = \dirname($this->strFile)) == '.')
  457.             {
  458.                 $strFolder '';
  459.             }
  460.             // Create the parent folder
  461.             if (!is_dir($this->strRootDir '/' $strFolder))
  462.             {
  463.                 new Folder($strFolder);
  464.             }
  465.         }
  466.         // Move the temporary file to its destination
  467.         $return $this->Files->rename($this->strTmp$this->strFile);
  468.         $this->strTmp null;
  469.         // Update the database
  470.         if (Dbafs::shouldBeSynchronized($this->strFile))
  471.         {
  472.             $this->objModel Dbafs::addResource($this->strFile);
  473.         }
  474.         return $return;
  475.     }
  476.     /**
  477.      * Return the files model
  478.      *
  479.      * @return FilesModel The files model
  480.      */
  481.     public function getModel()
  482.     {
  483.         if ($this->objModel === null && Dbafs::shouldBeSynchronized($this->strFile))
  484.         {
  485.             $this->objModel FilesModel::findByPath($this->strFile);
  486.         }
  487.         return $this->objModel;
  488.     }
  489.     /**
  490.      * Generate the image if the current file is a deferred image and does not exist yet
  491.      *
  492.      * @return bool True if a deferred image was resized otherwise false
  493.      */
  494.     public function createIfDeferred()
  495.     {
  496.         if (!$this->exists())
  497.         {
  498.             try
  499.             {
  500.                 $image System::getContainer()->get('contao.image.image_factory')->create($this->strRootDir '/' $this->strFile);
  501.                 if ($image instanceof DeferredImageInterface)
  502.                 {
  503.                     System::getContainer()->get('contao.image.resizer')->resizeDeferredImage($image);
  504.                     return true;
  505.                 }
  506.             }
  507.             catch (\Throwable $e)
  508.             {
  509.                 // ignore
  510.             }
  511.         }
  512.         return false;
  513.     }
  514.     /**
  515.      * Return the file content as string
  516.      *
  517.      * @return string The file content without BOM
  518.      */
  519.     public function getContent()
  520.     {
  521.         $this->createIfDeferred();
  522.         $strContent file_get_contents($this->strRootDir '/' . ($this->strTmp ?: $this->strFile));
  523.         // Remove BOMs (see #4469)
  524.         if (strncmp($strContent"\xEF\xBB\xBF"3) === 0)
  525.         {
  526.             $strContent substr($strContent3);
  527.         }
  528.         elseif (strncmp($strContent"\xFF\xFE"2) === 0)
  529.         {
  530.             $strContent substr($strContent2);
  531.         }
  532.         elseif (strncmp($strContent"\xFE\xFF"2) === 0)
  533.         {
  534.             $strContent substr($strContent2);
  535.         }
  536.         return $strContent;
  537.     }
  538.     /**
  539.      * Write to a file
  540.      *
  541.      * @param string $strFile    Relative file name
  542.      * @param string $strContent Content to be written
  543.      */
  544.     public static function putContent($strFile$strContent)
  545.     {
  546.         $objFile = new static($strFile);
  547.         $objFile->write($strContent);
  548.         $objFile->close();
  549.     }
  550.     /**
  551.      * Return the file content as array
  552.      *
  553.      * @return array The file content as array
  554.      */
  555.     public function getContentAsArray()
  556.     {
  557.         return array_map('rtrim'file($this->strRootDir '/' $this->strFile));
  558.     }
  559.     /**
  560.      * Rename the file
  561.      *
  562.      * @param string $strNewName The new path
  563.      *
  564.      * @return boolean True if the operation was successful
  565.      */
  566.     public function renameTo($strNewName)
  567.     {
  568.         $strParent = \dirname($strNewName);
  569.         // Create the parent folder if it does not exist
  570.         if (!is_dir($this->strRootDir '/' $strParent))
  571.         {
  572.             new Folder($strParent);
  573.         }
  574.         $return $this->Files->rename($this->strFile$strNewName);
  575.         // Update the database AFTER the file has been renamed
  576.         $syncSource Dbafs::shouldBeSynchronized($this->strFile);
  577.         $syncTarget Dbafs::shouldBeSynchronized($strNewName);
  578.         // Synchronize the database
  579.         if ($syncSource && $syncTarget)
  580.         {
  581.             $this->objModel Dbafs::moveResource($this->strFile$strNewName);
  582.         }
  583.         elseif ($syncSource)
  584.         {
  585.             $this->objModel Dbafs::deleteResource($this->strFile);
  586.         }
  587.         elseif ($syncTarget)
  588.         {
  589.             $this->objModel Dbafs::addResource($strNewName);
  590.         }
  591.         // Reset the object AFTER the database has been updated
  592.         if ($return != false)
  593.         {
  594.             $this->strFile $strNewName;
  595.             $this->arrImageSize = array();
  596.             $this->arrPathinfo = array();
  597.         }
  598.         return $return;
  599.     }
  600.     /**
  601.      * Copy the file
  602.      *
  603.      * @param string $strNewName The target path
  604.      *
  605.      * @return boolean True if the operation was successful
  606.      */
  607.     public function copyTo($strNewName)
  608.     {
  609.         $strParent = \dirname($strNewName);
  610.         // Create the parent folder if it does not exist
  611.         if (!is_dir($this->strRootDir '/' $strParent))
  612.         {
  613.             new Folder($strParent);
  614.         }
  615.         $return $this->Files->copy($this->strFile$strNewName);
  616.         // Update the database AFTER the file has been renamed
  617.         $syncSource Dbafs::shouldBeSynchronized($this->strFile);
  618.         $syncTarget Dbafs::shouldBeSynchronized($strNewName);
  619.         // Synchronize the database
  620.         if ($syncSource && $syncTarget)
  621.         {
  622.             Dbafs::copyResource($this->strFile$strNewName);
  623.         }
  624.         elseif ($syncTarget)
  625.         {
  626.             Dbafs::addResource($strNewName);
  627.         }
  628.         return $return;
  629.     }
  630.     /**
  631.      * Resize the file if it is an image
  632.      *
  633.      * @param integer $width  The target width
  634.      * @param integer $height The target height
  635.      * @param string  $mode   The resize mode
  636.      *
  637.      * @return boolean True if the image could be resized successfully
  638.      */
  639.     public function resizeTo($width$height$mode='')
  640.     {
  641.         if (!$this->isImage)
  642.         {
  643.             return false;
  644.         }
  645.         System::getContainer()
  646.             ->get('contao.image.image_factory')
  647.             ->create($this->strRootDir '/' $this->strFile, array($width$height$mode), $this->strRootDir '/' $this->strFile)
  648.         ;
  649.         $this->arrPathinfo = array();
  650.         $this->arrImageSize = array();
  651.         // Clear the image size cache as mtime could potentially not change
  652.         unset(static::$arrImageSizeCache[$this->strFile '|' $this->mtime]);
  653.         return true;
  654.     }
  655.     /**
  656.      * Send the file to the browser
  657.      *
  658.      * @param string  $filename An optional filename
  659.      * @param boolean $inline   Show the file in the browser instead of opening the download dialog
  660.      *
  661.      * @throws ResponseException
  662.      */
  663.     public function sendToBrowser($filename=''$inline=false)
  664.     {
  665.         $response = new BinaryFileResponse($this->strRootDir '/' $this->strFile);
  666.         $response->setPrivate(); // public by default
  667.         $response->setAutoEtag();
  668.         $response->setContentDisposition
  669.         (
  670.             $inline ResponseHeaderBag::DISPOSITION_INLINE ResponseHeaderBag::DISPOSITION_ATTACHMENT,
  671.             $filename,
  672.             Utf8::toAscii($this->basename)
  673.         );
  674.         $response->headers->addCacheControlDirective('must-revalidate');
  675.         $response->headers->set('Connection''close');
  676.         $response->headers->set('Content-Type'$this->getMimeType());
  677.         throw new ResponseException($response);
  678.     }
  679.     /**
  680.      * Check if any parent folder contains a .public file
  681.      *
  682.      * @return bool
  683.      */
  684.     public function isUnprotected()
  685.     {
  686.         return (new Folder(\dirname($this->strFile)))->isUnprotected();
  687.     }
  688.     /**
  689.      * Write data to a file
  690.      *
  691.      * @param mixed  $varData The data to be written
  692.      * @param string $strMode The operation mode
  693.      *
  694.      * @return boolean True if the operation was successful
  695.      */
  696.     protected function fputs($varData$strMode)
  697.     {
  698.         if (!\is_resource($this->resFile))
  699.         {
  700.             $this->strTmp 'system/tmp/' md5(uniqid(mt_rand(), true));
  701.             // Copy the contents of the original file to append data
  702.             if (strncmp($strMode'a'1) === && file_exists($this->strRootDir '/' $this->strFile))
  703.             {
  704.                 $this->Files->copy($this->strFile$this->strTmp);
  705.             }
  706.             // Open the temporary file
  707.             if (!$this->resFile $this->Files->fopen($this->strTmp$strMode))
  708.             {
  709.                 return false;
  710.             }
  711.         }
  712.         fwrite($this->resFile$varData);
  713.         return true;
  714.     }
  715.     /**
  716.      * Return the mime type and icon of the file based on its extension
  717.      *
  718.      * @return array An array with mime type and icon name
  719.      */
  720.     protected function getMimeInfo()
  721.     {
  722.         return $GLOBALS['TL_MIME'][$this->extension] ?? array('application/octet-stream''iconPLAIN.svg');
  723.     }
  724.     /**
  725.      * Get the mime type of the file based on its extension
  726.      *
  727.      * @return string The mime type
  728.      */
  729.     protected function getMimeType()
  730.     {
  731.         $arrMime $this->getMimeInfo();
  732.         return $arrMime[0];
  733.     }
  734.     /**
  735.      * Return the file icon depending on the file type
  736.      *
  737.      * @return string The icon name
  738.      */
  739.     protected function getIcon()
  740.     {
  741.         $arrMime $this->getMimeInfo();
  742.         return $arrMime[1];
  743.     }
  744.     /**
  745.      * Return the MD5 hash of the file
  746.      *
  747.      * @return string The MD5 hash
  748.      */
  749.     protected function getHash()
  750.     {
  751.         // Do not try to hash if bigger than 2 GB
  752.         if ($this->filesize >= 2147483648)
  753.         {
  754.             return '';
  755.         }
  756.         return md5_file($this->strRootDir '/' $this->strFile);
  757.     }
  758.     /**
  759.      * Return the path info (binary-safe)
  760.      *
  761.      * @return array The path info
  762.      *
  763.      * @see https://github.com/PHPMailer/PHPMailer/blob/master/class.phpmailer.php#L3520
  764.      */
  765.     protected function getPathinfo()
  766.     {
  767.         $matches = array();
  768.         $return = array('dirname'=>'''basename'=>'''extension'=>'''filename'=>'');
  769.         preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^.\\\\/]+?)|))[\\\\/.]*$%m'$this->strFile$matches);
  770.         if (isset($matches[1]))
  771.         {
  772.             $return['dirname'] = $this->strRootDir '/' $matches[1]; // see #8325
  773.         }
  774.         if (isset($matches[2]))
  775.         {
  776.             $return['basename'] = $matches[2];
  777.         }
  778.         if (isset($matches[5]))
  779.         {
  780.             $return['extension'] = $matches[5];
  781.         }
  782.         if (isset($matches[3]))
  783.         {
  784.             $return['filename'] = $matches[3];
  785.         }
  786.         return $return;
  787.     }
  788. }
  789. class_alias(File::class, 'File');