Displaying the downloadable file size on MODX website

If your website have download links for files and you have to specify the downloadable file sizes, then you definitely know, how inconvenient is to do it manually. Moreover, we need always remember to keep actual size when we're replacing some of our files with new version, and this additional work doesn't brings a lot of fun.

Let's optimize this process and write a snippet which will automatically output the size of any file placed on our server.

In my example I called the snippet "FileSize". Let's imagine that we have a file named "myfile.zip" with size of 1.44 megabytes (like the 3.5-inch diskette, if you remember), and the file is placed in "assets/files" directory. Also, let's agree that the file path passed to a snippet must be relative to base site url. So, the snippet call will look as follows:

[[FileSize? &path=`assets/files/myfile.zip`]]

And now it's time to code. The file size in PHP can be retrieved with filesize() function. It accepts full file path in filesystem, so first we need to convert the file url to its actual path. Fortunately, MODX has a constant called MODX_BASE_PATH, which contains a full path to main site directory. By combining both base path and relative file path, we will receive a full file path. Let's use it and try to write our snippet.

<?php
$path = MODX_BASE_PATH . $path;
$size = is_file($path) ? filesize($path) : 0;
return $size;

If we save this snippet and call it as described above, it should print something like this:

1509950

Well, this is not exactly what we wanted because the filesize function returns the size in bytes. To fix it, we can alter our snippet with an additional parameter which will accept the one of predefined unit codes (b for bytes, kb for kilobytes, mb for megabytes and gb for gygabytes) and convert the raw bytes to selected unit. Let's do it.

<?php
$path = MODX_BASE_PATH . $path;
$size = is_file($path) ? filesize($path) : 0;
$unit = isset($unit) ? $unit : false;

switch ($unit) {
    case 'kb': $size = $size / 1024; break;
    case 'mb': $size = $size / pow(1024, 2);
break;
    case 'gb': $size = $size / pow(1024, 3);
}

return round($size, 2);

Now we can add the unit parameter to the snippet call in following way:

[[FileSize? &path=`assets/files/myfile.zip` &unit=`mb`]]

And it should print us:

1.44

Much better, but still can be enchanced. In our case, we know the size of our test file and know which unit will work best for this case. But for other files we may have no such information. If another file size will be, say, 700 kilobytes, then the snippet will still return the size also in megabytes as "0.68". So, now we're about to add the final feature to our snippet and teach him automatically detect the best unit for displaying of unknown file size.

<?php
$units = array(
    'gb' => array('size' => 1073741824, 'label' => 'GB'),
    'mb' => array('size' => 1048576,    'label' => 'MB'),
    'kb' => array('size' => 1024,       'label' => 'KB'),
    'b'  => array('size' => 0,          'label' => 'bytes')
);

$path = MODX_BASE_PATH . $path;
$size = is_file($path) ? filesize($path) : 0;
$unit = (isset($unit) && isset($units[$unit])) ? $unit : false;

if ($size > 0) {
    if ($unit === false) {
        // If the unit is not specified, detect it automatically.
        foreach ($units as $key => $properties) {
            if ($size >= $properties['size']) {
                $unit = $key;
                break;
            }
        }
    }
    if ($unit != 'b')
        $size = $size / $units[$unit]['size'];
}
else {
    if ($unit === false) $unit = 'b';
}

return round($size, 2) . ' ' . $units[$unit]['label'];

Well, let's remove the unit parameter from the snippet call, which we have added just recent, and return it to initial form:

[[FileSize? &path=`assets/files/myfile.zip`]]

The output should be:

1.44 MB

As you can see, this time the unit has been choosen automatically. Also, we added the unit label to output, so we have no worries about it anymore. However, we are welcome to specify the unit if we want:

[[FileSize? &path=`assets/files/myfile.zip` &unit=`b`]]

The above example will output us 1509950 bytes.

Browse on GitHub

By on
If you want to repost this article, please keep the source hyperlink