diff options
Diffstat (limited to 'engine/classes/ElggFile.php')
| -rw-r--r-- | engine/classes/ElggFile.php | 440 | 
1 files changed, 440 insertions, 0 deletions
| diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php new file mode 100644 index 000000000..23080834b --- /dev/null +++ b/engine/classes/ElggFile.php @@ -0,0 +1,440 @@ +<?php + +/** + * This class represents a physical file. + * + * Create a new ElggFile object and specify a filename, and optionally a + * FileStore (if one isn't specified then the default is assumed.) + * + * Open the file using the appropriate mode, and you will be able to + * read and write to the file. + * + * Optionally, you can also call the file's save() method, this will + * turn the file into an entity in the system and permit you to do + * things like attach tags to the file etc. This is not done automatically + * since there are many occasions where you may want access to file data + * on datastores using the ElggFile interface but do not want to create + * an Entity reference to it in the system (temporary files for example). + * + * @class      ElggFile + * @package    Elgg.Core + * @subpackage DataModel.File + */ +class ElggFile extends ElggObject { +	/** Filestore */ +	private $filestore; + +	/** File handle used to identify this file in a filestore. Created by open. */ +	private $handle; + +	/** +	 * Set subtype to 'file'. +	 * +	 * @return void +	 */ +	protected function initializeAttributes() { +		parent::initializeAttributes(); + +		$this->attributes['subtype'] = "file"; +	} + +	/** +	 * Loads an ElggFile entity. +	 * +	 * @param int $guid GUID of the ElggFile object +	 */ +	public function __construct($guid = null) { +		parent::__construct($guid); + +		// Set default filestore +		$this->filestore = $this->getFilestore(); +	} + +	/** +	 * Set the filename of this file. +	 * +	 * @param string $name The filename. +	 * +	 * @return void +	 */ +	public function setFilename($name) { +		$this->filename = $name; +	} + +	/** +	 * Return the filename. +	 * +	 * @return string +	 */ +	public function getFilename() { +		return $this->filename; +	} + +	/** +	 * Return the filename of this file as it is/will be stored on the +	 * filestore, which may be different to the filename. +	 * +	 * @return string +	 */ +	public function getFilenameOnFilestore() { +		return $this->filestore->getFilenameOnFilestore($this); +	} + +	/** +	 * Return the size of the filestore associated with this file +	 * +	 * @param string $prefix         Storage prefix +	 * @param int    $container_guid The container GUID of the checked filestore +	 * +	 * @return int +	 */ +	public function getFilestoreSize($prefix = '', $container_guid = 0) { +		if (!$container_guid) { +			$container_guid = $this->container_guid; +		} +		$fs = $this->getFilestore(); +		// @todo add getSize() to ElggFilestore +		return $fs->getSize($prefix, $container_guid); +	} + +	/** +	 * Get the mime type of the file. +	 * +	 * @return string +	 */ +	public function getMimeType() { +		if ($this->mimetype) { +			return $this->mimetype; +		} + +		// @todo Guess mimetype if not here +	} + +	/** +	 * Set the mime type of the file. +	 * +	 * @param string $mimetype The mimetype +	 * +	 * @return bool +	 */ +	public function setMimeType($mimetype) { +		return $this->mimetype = $mimetype; +	} + +	/** +	 * Detects mime types based on filename or actual file. +	 * +	 * @param mixed $file    The full path of the file to check. For uploaded files, use tmp_name. +	 * @param mixed $default A default. Useful to pass what the browser thinks it is. +	 * @since 1.7.12 +	 * +	 * @note If $file is provided, this may be called statically +	 * +	 * @return mixed Detected type on success, false on failure. +	 */ +	public function detectMimeType($file = null, $default = null) { +		if (!$file) { +			if (isset($this) && $this->filename) { +				$file = $this->filename; +			} else { +				return false; +			} +		} + +		$mime = false; + +		// for PHP5 folks. +		if (function_exists('finfo_file') && defined('FILEINFO_MIME_TYPE')) { +			$resource = finfo_open(FILEINFO_MIME_TYPE); +			if ($resource) { +				$mime = finfo_file($resource, $file); +			} +		} + +		// for everyone else. +		if (!$mime && function_exists('mime_content_type')) { +			$mime = mime_content_type($file); +		} + +		// default +		if (!$mime) { +			return $default; +		} + +		return $mime; +	} + +	/** +	 * Set the optional file description. +	 * +	 * @param string $description The description. +	 * +	 * @return bool +	 */ +	public function setDescription($description) { +		$this->description = $description; +	} + +	/** +	 * Open the file with the given mode +	 * +	 * @param string $mode Either read/write/append +	 * +	 * @return resource File handler +	 * +	 * @throws IOException|InvalidParameterException +	 */ +	public function open($mode) { +		if (!$this->getFilename()) { +			throw new IOException(elgg_echo('IOException:MissingFileName')); +		} + +		// See if file has already been saved +		// seek on datastore, parameters and name? + +		// Sanity check +		if ( +			($mode != "read") && +			($mode != "write") && +			($mode != "append") +		) { +			$msg = elgg_echo('InvalidParameterException:UnrecognisedFileMode', array($mode)); +			throw new InvalidParameterException($msg); +		} + +		// Get the filestore +		$fs = $this->getFilestore(); + +		// Ensure that we save the file details to object store +		//$this->save(); + +		// Open the file handle +		$this->handle = $fs->open($this, $mode); + +		return $this->handle; +	} + +	/** +	 * Write data. +	 * +	 * @param string $data The data +	 * +	 * @return bool +	 */ +	public function write($data) { +		$fs = $this->getFilestore(); + +		return $fs->write($this->handle, $data); +	} + +	/** +	 * Read data. +	 * +	 * @param int $length Amount to read. +	 * @param int $offset The offset to start from. +	 * +	 * @return mixed Data or false +	 */ +	public function read($length, $offset = 0) { +		$fs = $this->getFilestore(); + +		return $fs->read($this->handle, $length, $offset); +	} + +	/** +	 * Gets the full contents of this file. +	 * +	 * @return mixed The file contents. +	 */ +	public function grabFile() { +		$fs = $this->getFilestore(); +		return $fs->grabFile($this); +	} + +	/** +	 * Close the file and commit changes +	 * +	 * @return bool +	 */ +	public function close() { +		$fs = $this->getFilestore(); + +		if ($fs->close($this->handle)) { +			$this->handle = NULL; + +			return true; +		} + +		return false; +	} + +	/** +	 * Delete this file. +	 * +	 * @return bool +	 */ +	public function delete() { +		$fs = $this->getFilestore(); +		 +		$result = $fs->delete($this); +		 +		if ($this->getGUID() && $result) { +			$result = parent::delete(); +		} +		 +		return $result; +	} + +	/** +	 * Seek a position in the file. +	 * +	 * @param int $position Position in bytes +	 * +	 * @return bool +	 */ +	public function seek($position) { +		$fs = $this->getFilestore(); + +		// @todo add seek() to ElggFilestore +		return $fs->seek($this->handle, $position); +	} + +	/** +	 * Return the current position of the file. +	 * +	 * @return int The file position +	 */ +	public function tell() { +		$fs = $this->getFilestore(); + +		return $fs->tell($this->handle); +	} + +	/** +	 * Return the size of the file in bytes. +	 * +	 * @return int +	 */ +	public function size() { +		return $this->filestore->getFileSize($this); +	} + +	/** +	 * Return a boolean value whether the file handle is at the end of the file +	 * +	 * @return bool +	 */ +	public function eof() { +		$fs = $this->getFilestore(); + +		return $fs->eof($this->handle); +	} + +	/** +	 * Returns if the file exists +	 * +	 * @return bool +	 */ +	public function exists() { +		$fs = $this->getFilestore(); + +		return $fs->exists($this); +	} + +	/** +	 * Set a filestore. +	 * +	 * @param ElggFilestore $filestore The file store. +	 * +	 * @return void +	 */ +	public function setFilestore(ElggFilestore $filestore) { +		$this->filestore = $filestore; +	} + +	/** +	 * Return a filestore suitable for saving this file. +	 * This filestore is either a pre-registered filestore, +	 * a filestore as recorded in metadata or the system default. +	 * +	 * @return ElggFilestore +	 * +	 * @throws ClassNotFoundException +	 */ +	protected function getFilestore() { +		// Short circuit if already set. +		if ($this->filestore) { +			return $this->filestore; +		} + +		// ask for entity specific filestore +		// saved as filestore::className in metadata. +		// need to get all filestore::* metadata because the rest are "parameters" that +		// get passed to filestore::setParameters() +		if ($this->guid) { +			$options = array( +				'guid' => $this->guid, +				'where' => array("n.string LIKE 'filestore::%'"), +			); + +			$mds = elgg_get_metadata($options); + +			$parameters = array(); +			foreach ($mds as $md) { +				list($foo, $name) = explode("::", $md->name); +				if ($name == 'filestore') { +					$filestore = $md->value; +				} +				$parameters[$name] = $md->value; +			} +		} + +		// need to check if filestore is set because this entity is loaded in save() +		// before the filestore metadata is saved. +		if (isset($filestore)) { +			if (!class_exists($filestore)) { +				$msg = elgg_echo('ClassNotFoundException:NotFoundNotSavedWithFile', +					array($filestore, $this->guid)); +				throw new ClassNotFoundException($msg); +			} + +			$this->filestore = new $filestore(); +			$this->filestore->setParameters($parameters); +			// @todo explain why $parameters will always be set here (PhpStorm complains) +		} + +		// this means the entity hasn't been saved so fallback to default +		if (!$this->filestore) { +			$this->filestore = get_default_filestore(); +		} + +		return $this->filestore; +	} + +	/** +	 * Save the file +	 * +	 * Write the file's data to the filestore and save +	 * the corresponding entity. +	 * +	 * @see ElggObject::save() +	 * +	 * @return bool +	 */ +	public function save() { +		if (!parent::save()) { +			return false; +		} + +		// Save datastore metadata +		$params = $this->filestore->getParameters(); +		foreach ($params as $k => $v) { +			$this->setMetaData("filestore::$k", $v); +		} + +		// Now make a note of the filestore class +		$this->setMetaData("filestore::filestore", get_class($this->filestore)); + +		return true; +	} +} | 
