mirror of
				https://github.com/Icinga/icingaweb2.git
				synced 2025-10-31 03:14:31 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
 | |
| 
 | |
| namespace Icinga\Util;
 | |
| 
 | |
| use SplFileObject;
 | |
| use ErrorException;
 | |
| use RuntimeException;
 | |
| use Icinga\Exception\NotWritableError;
 | |
| 
 | |
| /**
 | |
|  * File
 | |
|  *
 | |
|  * A class to ease opening files and reading/writing to them.
 | |
|  */
 | |
| class File extends SplFileObject
 | |
| {
 | |
|     /**
 | |
|      * The mode used to open the file
 | |
|      *
 | |
|      * @var string
 | |
|      */
 | |
|     protected $openMode;
 | |
| 
 | |
|     /**
 | |
|      * The access mode to use when creating directories
 | |
|      *
 | |
|      * @var int
 | |
|      */
 | |
|     public static $dirMode = 1528; // 2770
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::__construct()
 | |
|      */
 | |
|     public function __construct($filename, $openMode = 'r', $useIncludePath = false, $context = null)
 | |
|     {
 | |
|         $this->openMode = $openMode;
 | |
|         if ($context === null) {
 | |
|             parent::__construct($filename, $openMode, $useIncludePath);
 | |
|         } else {
 | |
|             parent::__construct($filename, $openMode, $useIncludePath, $context);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create a file using the given access mode and return a instance of File open for writing
 | |
|      *
 | |
|      * @param   string  $path           The path to the file
 | |
|      * @param   int     $accessMode     The access mode to set
 | |
|      * @param   bool    $recursive      Whether missing nested directories of the given path should be created
 | |
|      *
 | |
|      * @return  File
 | |
|      *
 | |
|      * @throws  RuntimeException        In case the file cannot be created or the access mode cannot be set
 | |
|      * @throws  NotWritableError        In case the path's (existing) parent is not writable
 | |
|      */
 | |
|     public static function create($path, $accessMode, $recursive = true)
 | |
|     {
 | |
|         $dirPath = dirname($path);
 | |
|         if ($recursive && !is_dir($dirPath)) {
 | |
|             static::createDirectories($dirPath);
 | |
|         } elseif (! is_writable($dirPath)) {
 | |
|             throw new NotWritableError(sprintf('Path "%s" is not writable', $dirPath));
 | |
|         }
 | |
| 
 | |
|         $file = new static($path, 'x+');
 | |
| 
 | |
|         if (! @chmod($path, $accessMode)) {
 | |
|             $error = error_get_last();
 | |
|             throw new RuntimeException(sprintf(
 | |
|                 'Cannot set access mode "%s" on file "%s" (%s)',
 | |
|                 decoct($accessMode),
 | |
|                 $path,
 | |
|                 $error['message']
 | |
|             ));
 | |
|         }
 | |
| 
 | |
|         return $file;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Create missing directories
 | |
|      *
 | |
|      * @param   string  $path
 | |
|      *
 | |
|      * @throws  RuntimeException        In case a directory cannot be created or the access mode cannot be set
 | |
|      */
 | |
|     protected static function createDirectories($path)
 | |
|     {
 | |
|         $part = strpos($path, DIRECTORY_SEPARATOR) === 0 ? DIRECTORY_SEPARATOR : '';
 | |
|         foreach (explode(DIRECTORY_SEPARATOR, ltrim($path, DIRECTORY_SEPARATOR)) as $dir) {
 | |
|             $part .= $dir . DIRECTORY_SEPARATOR;
 | |
| 
 | |
|             if (! is_dir($part)) {
 | |
|                 if (! @mkdir($part, static::$dirMode)) {
 | |
|                     $error = error_get_last();
 | |
|                     throw new RuntimeException(sprintf(
 | |
|                         'Failed to create missing directory "%s" (%s)',
 | |
|                         $part,
 | |
|                         $error['message']
 | |
|                     ));
 | |
|                 }
 | |
| 
 | |
|                 if (! @chmod($part, static::$dirMode)) {
 | |
|                     $error = error_get_last();
 | |
|                     throw new RuntimeException(sprintf(
 | |
|                         'Failed to set access mode "%s" for directory "%s" (%s)',
 | |
|                         decoct(static::$dirMode),
 | |
|                         $part,
 | |
|                         $error['message']
 | |
|                     ));
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::fwrite()
 | |
|      */
 | |
|     public function fwrite($str, $length = null)
 | |
|     {
 | |
|         $this->assertOpenForWriting();
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = $length === null ? parent::fwrite($str) : parent::fwrite($str, $length);
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::ftruncate()
 | |
|      */
 | |
|     public function ftruncate($size)
 | |
|     {
 | |
|         $this->assertOpenForWriting();
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = parent::ftruncate($size);
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::ftell()
 | |
|      */
 | |
|     public function ftell()
 | |
|     {
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = parent::ftell();
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::flock()
 | |
|      */
 | |
|     public function flock($operation, &$wouldblock = null)
 | |
|     {
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = parent::flock($operation, $wouldblock);
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::fgetc()
 | |
|      */
 | |
|     public function fgetc()
 | |
|     {
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = parent::fgetc();
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @see SplFileObject::fflush()
 | |
|      */
 | |
|     public function fflush()
 | |
|     {
 | |
|         $this->setupErrorHandler();
 | |
|         $retVal = parent::fflush();
 | |
|         restore_error_handler();
 | |
|         return $retVal;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Setup an error handler that throws a RuntimeException for every emitted E_WARNING
 | |
|      */
 | |
|     protected function setupErrorHandler()
 | |
|     {
 | |
|         set_error_handler(
 | |
|             function ($errno, $errstr, $errfile, $errline) {
 | |
|                 restore_error_handler();
 | |
|                 throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
 | |
|             },
 | |
|             E_WARNING
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Assert that the file was opened for writing and throw an exception otherwise
 | |
|      *
 | |
|      * @throws  NotWritableError    In case the file was not opened for writing
 | |
|      */
 | |
|     protected function assertOpenForWriting()
 | |
|     {
 | |
|         if (!preg_match('@w|a|\+@', $this->openMode)) {
 | |
|             throw new NotWritableError('File not open for writing');
 | |
|         }
 | |
|     }
 | |
| }
 |