You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PlexShare/fuel/core/classes/file/area.php

278 lines
7.2 KiB

7 years ago
<?php
/**
* Part of the Fuel framework.
*
* @package Fuel
* @version 1.8
* @author Fuel Development Team
* @license MIT License
* @copyright 2010 - 2016 Fuel Development Team
* @link http://fuelphp.com
*/
namespace Fuel\Core;
class File_Area
{
/**
* @var string path to basedir restriction, null for no restriction
*/
protected $basedir = null;
/**
* @var array array of allowed extensions, null for all
*/
protected $extensions = null;
/**
* @var string base url for files, null for not available
*/
protected $url = null;
/**
* @var bool whether or not to use file locks when doing file operations
*/
protected $use_locks = false;
/**
* @var array contains file handler per file extension
*/
protected $file_handlers = array();
protected function __construct(array $config = array())
{
foreach ($config as $key => $value)
{
if (property_exists($this, $key))
{
$this->{$key} = $value;
}
}
if ( ! empty($this->basedir))
{
$this->basedir = realpath($this->basedir) ?: $this->basedir;
}
}
/**
* Factory for area objects
*
* @param array
* @return File_Area
*/
public static function forge(array $config = array())
{
return new static($config);
}
/**
* Handler factory for given path
*
* @param string $path path to file or directory
* @param array $config optional config
* @param array $content
* @return File_Handler_File
* @throws \FileAccessException when outside basedir restriction or disallowed file extension
* @throws \OutsideAreaException
*/
public function get_handler($path, array $config = array(), $content = array())
{
$path = $this->get_path($path);
if (is_file($path))
{
$info = pathinfo($path);
// deal with path names without an extension
isset($info['extension']) or $info['extension'] = '';
// check file extension
if ( ! empty($this->extensions) && ! in_array($info['extension'], $this->extensions))
{
throw new \FileAccessException('File operation not allowed: disallowed file extension.');
}
// create specific handler when available
if (array_key_exists($info['extension'], $this->file_handlers))
{
$class = '\\'.ltrim($this->file_handlers[$info['extension']], '\\');
return $class::forge($path, $config, $this);
}
return \File_Handler_File::forge($path, $config, $this);
}
elseif (is_dir($path))
{
return \File_Handler_Directory::forge($path, $config, $this, $content);
}
// still here? path is invalid
throw new \FileAccessException('Invalid path for file or directory.');
}
/**
* Does this area use file locks?
*
* @return bool
*/
public function use_locks()
{
return $this->use_locks;
}
/**
* Are the shown extensions limited, and if so to which?
*
* @return array
*/
public function extensions()
{
return $this->extensions;
}
/**
* Translate relative path to real path, throws error when operation is not allowed
*
* @param string $path
* @return string
* @throws \FileAccessException when outside basedir restriction or disallowed file extension
* @throws \OutsideAreaException
*/
public function get_path($path)
{
$pathinfo = is_dir($path) ? array('dirname' => $path, 'extension' => null, 'basename' => '') : pathinfo($path);
// make sure we have a dirname to work with
isset($pathinfo['dirname']) or $pathinfo['dirname'] = '';
// do we have a basedir, and is the path already prefixed by the basedir? then just deal with the double dots...
if ( ! empty($this->basedir) && substr($pathinfo['dirname'], 0, strlen($this->basedir)) == $this->basedir)
{
$pathinfo['dirname'] = realpath($pathinfo['dirname']);
}
else
{
// attempt to get the realpath(), otherwise just use path with any double dots taken out when basedir is set (for security)
$pathinfo['dirname'] = ( ! empty($this->basedir) ? realpath($this->basedir.DS.$pathinfo['dirname']) : realpath($pathinfo['dirname']) )
?: ( ! empty($this->basedir) ? $this->basedir.DS.str_replace('..', '', $pathinfo['dirname']) : $pathinfo['dirname']);
}
// basedir prefix is required when it is set (may cause unexpected errors when realpath doesn't work)
if ( ! empty($this->basedir) && substr($pathinfo['dirname'], 0, strlen($this->basedir)) != $this->basedir)
{
throw new \OutsideAreaException('File operation not allowed: given path is outside the basedir for this area.');
}
// check file extension
if ( ! empty(static::$extensions) && array_key_exists($pathinfo['extension'], static::$extensions))
{
throw new \FileAccessException('File operation not allowed: disallowed file extension.');
}
return $pathinfo['dirname'].DS.$pathinfo['basename'];
}
/**
* Translate relative path to accessible path, throws error when operation is not allowed
*
* @param string
* @return string
* @throws \LogicException when no url is set or no basedir is set and file is outside DOCROOT
*/
public function get_url($path)
{
if(empty($this->url))
{
throw new \LogicException('File operation now allowed: cannot create a file url without an area url.');
}
$path = $this->get_path($path);
$basedir = $this->basedir;
empty($basedir) and $basedir = DOCROOT;
if(stripos($path, $basedir) !== 0)
{
throw new \LogicException('File operation not allowed: cannot create file url whithout a basedir and file outside DOCROOT.');
}
return rtrim($this->url, '/').'/'.ltrim(str_replace(DS, '/', substr($path, strlen($basedir))), '/');
}
/* -------------------------------------------------------------------------------------
* Allow all File methods to be used from an area directly
* ------------------------------------------------------------------------------------- */
public function create($basepath, $name, $contents = null)
{
return \File::create($basepath, $name, $contents, $this);
}
public function create_dir($basepath, $name, $chmod = null)
{
return \File::create_dir($basepath, $name, $chmod, $this);
}
public function read($path, $as_string = false)
{
return \File::read($path, $as_string, $this);
}
public function read_dir($path, $depth = 0, $filter = null)
{
$content = \File::read_dir($path, $depth, $filter, $this);
return $this->get_handler($path, array(), $content);
}
public function rename($path, $new_path)
{
return \File::rename($path, $new_path, $this);
}
public function rename_dir($path, $new_path)
{
return \File::rename_dir($path, $new_path, $this);
}
public function copy($path, $new_path)
{
return \File::copy($path, $new_path, $this);
}
public function copy_dir($path, $new_path)
{
return \File::copy_dir($path, $new_path, $this);
}
public function delete($path)
{
return \File::delete($path, $this);
}
public function delete_dir($path, $recursive = true, $delete_top = true)
{
return \File::delete_dir($path, $recursive, $delete_top, $this);
}
public function update($basepath, $name, $new_content)
{
return \File::update($basepath, $name, $new_content, $this);
}
public function get_permissions($path)
{
return \File::get_permissions($path, $this);
}
public function get_time($path, $type)
{
return \File::get_time($path, $type, $this);
}
public function get_size($path)
{
return \File::get_size($path, $this);
}
}