Developers

Accessing files

Two different problems share this name: getting at a hub's files on the server, and reading and writing files from inside your code. This page covers the first and points at the chapter that covers the second.

Reaching the server

A hub runs on a Linux server and you work on it over SSH. From a terminal:

ssh username@hub.example.org

For file transfer, use sFTP, which runs over the same SSH connection and encrypts commands and data alike. An ordinary FTP client cannot talk to it.

sftp username@hub.example.org

Any current SSH client works. Windows ships OpenSSH, so ssh and sftp work from PowerShell or the Command Prompt; PuTTY and WinSCP are the long-standing graphical alternatives. macOS and Linux have ssh and sftp installed already.

Inside an sftp session, get and put transfer a file, ls and cd work on the remote side, lls and lcd on the local side, and help lists the rest. scp -r and rsync -a are usually quicker for a whole directory.

Finding the hub

The web root is the hub's document root, conventionally /www/<hubname> on a Hubzero server. Many sites keep a second, development copy alongside it, often /www/dev. Both are ordinary directories; nothing in the CMS depends on the name.

Underneath, the layout is the one described in Structure: core/ holds the platform, app/ holds this hub's configuration, extensions, cache, and uploads, and index.php at the root is the only entry point.

Two things to know before you edit anything in place:

  • Files must stay readable by the web server user, apache on Enterprise Linux. A file you create over sFTP is owned by you.
  • Everything under app/ is a running hub's state and is not in the repository. Everything under core/ is, so an edit there is a change you will have to carry forward or contribute back.

Reading and writing files from code

Do not use PHP's fopen and unlink directly. The CMS has a file API, so that the same calls work whether the hub writes to local disk or over FTP, and so uploads are virus-scanned and paths are normalised on the way through.

The entry point is the Filesystem facade, which resolves to Hubzero\Filesystem\Filesystem:

use Filesystem;

if (Filesystem::exists($path))
{
	$contents = Filesystem::read($path);
}

Filesystem::write($path, $contents);
Filesystem::makeDirectory($dir);
Filesystem::delete($path);

exists(), read(), write(), append(), prepend(), copy(), move(), rename(), delete(), upload(), makeDirectory(), copyDirectory(), deleteDirectory(), isDirectory(), isFile(), isWritable(), size(), mimetype(), lastModified() and listContents() are all on the class, along with four macros — files(), directories(), directoryTree() and emptyDirectory() — registered by the service provider at boot.

Filesystem is the full chapter: the adapters, the macro mechanism, the safe-path rules, and the archive types.

What it looks like when it goes wrong: Filesystem::read() on a path that is not there throws FileNotFoundException, so an unguarded read of a missing upload takes the whole page down. A file that exists but that the web server user cannot read is worse: PHP's file_get_contents() warns and returns false, which read() casts to a string, so you get an empty string and a blank patch of page with nothing in the log but a warning. Test exists() first, and check what write() returns — it is a boolean, and a failed write is not an exception.

Rewritten and checked against 2.4-main @ 348f0057c2 on 2026-09-10.