Click here to Skip to main content
15,885,027 members
Articles / Programming Languages / PHP

PHPFM: A Single File, Responsive File Manager

Rate me:
Please Sign up or sign in to vote.
4.88/5 (9 votes)
5 Feb 2017CPOL1 min read 36.8K   905   9   6
A very quick file manager for your PHP site

GitLab URL: https://gitlab.com/windowssnt/PHPFileManager. Feel free to contribute!

Introduction

I've tried a few file managers but all seem very complex. Why not making my own one?

  • Single file. Just copy phpfm.php to your root directory and that's all.
  • Bootstrap, jQuery, BootBox, Font Awesome, Chosen, Data Tables
  • Login with HTTP digest if over HTTP and with form if over HTTPS.
  • Multiple users supported with specific root folders and read/write access options per folder.
  • Save users in self or in SQLite database.
  • Create folder.
  • Upload file.
  • Upload multiple files in zip.
  • Download file.
  • Download multiple files in zip.
  • Delete file/files.

Login

If you are in a HTTPS connection, the login is a simple bootstrap form:

For the first login, login as root without password.

The passwords are saved in sha-1 hash form and a logout option is provided (which terminates the session).

If you are in an HTTP connection, the passwords are saved in plain text but the authentication method is HTTP digest, in order to avoid transmitting the raw password.

$users Array

PHP
$users = array('root' => array('admin' => '1','password' => '',
'root' => '.','access' => array('.' => 2)))

The "access" array is itself an array which contains pairs of directories and access levels (1 read, 2 write).

For security, PHPFM never allows access to any file that contains ".." or starts with "/".

If saving the users to self, a simple function is used to serialize the users array:

PHP
function LoadUsers()
{
    global $users;

    if (count($users) == 1 && $users['root']['password'] == "")
        return "\$users = array();\r\n";

    $u = "\$users = array(\r\n";
    $i = 0;
    foreach($users as $username => $user)
    {
        if ($i > 0)
            $u .= ",\r\n";
        $acc = "array(";// array("." => 2)
        $ii = 0;
        foreach($user['access'] as $acxd => $acx)
        {
            if ($ii > 0)
                $acc .= ",";
            $acc .= sprintf("'%s' => %s",$acxd,$acx);
            $ii++;
        }
        $acc .= ")";
        $u .= sprintf("'%s' => array('admin' => '%s','password' => 
        '%s','root' => '%s','access' => %s)",
        $username,$user['admin'],$user['password'],$user['root'],$acc);
        $i++;
    }

    $u .= "\r\n);";
    return $u;
}

If saving to a database, SQLite is used. Once you have created a user (or changed the root password), you cannot anymore switch between the two methods.

Interface

File or Zip Upload

A simple PHP $_FILE form is used:

PHP
if (array_key_exists("zip",$_POST) && $_POST['zip'] == 1)
{
    $zip = new ZipArchive;
    $zip->open($tempfile);
    $nf = $zip->numFiles;
    for($i = 0; $i < $nf ; $i++)
    {
        $fn2 = $zip->getNameIndex($i);
        if (strstr($fn2,"..") !== false || strstr($fn2,"/") === $fn2)
        {
        unlink($tempfile);
        $_SESSION['error'] = "File contains files with .. or /, not allowed.";
        die;
        }
     }
    $zip->extractTo($cr);
}
else
{
   $dbdata = file_get_contents($tempfile);
   $full = $_SESSION['current'].'/'.$fn;
   file_put_contents($full,$dbdata);
}
unlink($tempfile);

File or Zip Download

Either a direct application/octet-stream is used for a single file:

PHP
header('Content-Description: Download');
header('Content-Type: application/octet-stream');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header(sprintf("Content-disposition: attachment;filename=%s",basename($u)));
header('Content-Length: ' . filesize($u));
readfile($u);

or a ZIP download, checking also permissions:

PHP
$what = $_POST['massdownload'];
$fuf = "";
$dp = strrpos($_POST['massdownload'],"/");
if ($dp === false)
    $fuf = $_SESSION['current'].'/';
else
    $fuf = substr($_GET['down'],0,$dp);

if (AccessType($fuf) === 0)
{
    $_SESSION['error'] = "Read access denied to folder <b>$root</b>.";
}
else
{
    $arr = array();
    $items = explode(',',$what);
    foreach($items as $item)
    {
        if (strstr($item,"/") == $item)
            die;
        if (strstr($item,"..") !== false)
            die;
        $full = $_SESSION['current'].'/'.$item;
        enumDir($full,$arr);
    }

    $tz = tempnam(".","zip");
    if (file_exists($tz))
        unlink($tz);
    $tz .= ".zip";
    if (file_exists($tz))
        unlink($tz);
    $zip = new ZipArchive;
    $zipo = $zip->open($tz,ZipArchive::CREATE | ZipArchive::OVERWRITE);
    foreach($arr as $a)
    {
        if (is_dir($a))
            continue;
        $rs = $zip->addFile($a,substr($a,2));
        if (!$rs)
            die;
    }
    $zip->close();
    Down($tz,1);
    unlink($tz);
    die;
}

Have fun!

History

  • 23rd January, 2017: First release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS, Android and Web (HTML/Javascript/CSS).

I 've a PhD in Digital Signal Processing and Artificial Intelligence and I specialize in Pro Audio and AI applications.

My home page: https://www.turbo-play.com

Comments and Discussions

 
QuestionFatal error: Class 'SQLite3' not found in phpfm Pin
Ngô Tứ Lân23-Dec-17 15:22
Ngô Tứ Lân23-Dec-17 15:22 
AnswerRe: Fatal error: Class 'SQLite3' not found in phpfm Pin
Michael Chourdakis31-Dec-17 1:28
mvaMichael Chourdakis31-Dec-17 1:28 
QuestionBroken link? Pin
sinun30-Jan-17 1:54
sinun30-Jan-17 1:54 
AnswerRe: Broken link? Pin
Michael Chourdakis30-Jan-17 3:37
mvaMichael Chourdakis30-Jan-17 3:37 
GeneralRe: Broken link? Pin
sinun31-Jan-17 2:44
sinun31-Jan-17 2:44 
GeneralRe: Broken link? Pin
Michael Chourdakis31-Jan-17 4:36
mvaMichael Chourdakis31-Jan-17 4:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.