Accessing the Physical File from a File Object

The File object gives us access to all the metadata about files, and lets us work the file programmatically in blocks and throughout sites and applications. But sometimes we need to access the physical file referenced by the object. For example, in the following operations:

  • Bundling up a collection of files into a ZIP archive
  • Streaming the file to some external process
  • Forcing the file to download to the browser
  • Moving a file across file systems
  • Loading a file resource into an image editor class (for image processing)

In these situations, we need access to what Concrete CMS refers to as a file resource. The file resource gives us access to the actual bytestream of a file. Here's how we get the file resource from a File object:

$file = \File::getByID(3);
$resource = $file->getFileResource();

This returns an instance of \Concrete\Flysystem\File. Once you have this object, you can call the following methods on it:

  • read()
  • getTimestamp()
  • getMimetype()
  • getSize()
  • delete()

Similarly, you can directly get the byte contents of a File object using getFileContents(). You can do a lot with the byte contents of a file.

Example: File Size and Formatting

Obtain the number of the filesize and format nicely.

$file = \File::getByID(3);
$fv = $file->getVersion();
$size = $fv->getFullSize();
$size = Core::make('helper/number')->formatSize($size);

This outputs the filesize using the right byte format.1024bytes = 1KB, 1024KB = 1MB, and so on.

Example: Zipping multiple files into a ZIP Archive

$fileIDs = array(1,2,3);
$zip = new ZipArchive;
$res = $zip->open('/path/to/file.zip', ZipArchive::CREATE);
foreach($fileIDs as $fID) {
    $f = File::getByID($fID);
    $zip->addFromString($f->getFilename(), $f->getFileContents());
}
$zip->close();
Core::make('helper/file')->forceDownload('/path/to/file.zip');

Why do you need to jump through these hoops to work with the physical file? Why not just get the absolute path to the file? Because in Concrete there's no guarantee that the File object you're working with actually has a physical file present on the web server. Remember, every File object in Concrete has its physical file stored in a File StorageLocation object. These StorageLocation objects are usually directories on the same web server – but not always. They course reference an Amazon S3 storage bucket, for example. In this case, there'd be no absolute path on the server to get the file. So instead we use the file resource abstraction, and it will ensure that you can always work with a physical file, even if it's not on the same server.