Click here to Skip to main content
13,701,366 members
Click here to Skip to main content
Add your own
alternative version

Stats

14.6K views
478 downloads
8 bookmarked
Posted 27 Jan 2017
Licenced CPOL

PHPFM : A single file, responsive file manager

, 5 Feb 2017
Rate this:
Please Sign up or sign in to vote.
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 seems 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 provied (which terminates the session).

If you are in a 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

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

The "access" array is itself an array which contains pairs of dircetories 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:

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:

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:

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:

$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

23 - 01 - 2017 : First Release

License

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

Share

About the Author

Michael Chourdakis
Engineer
Greece Greece
I'm working in C++, PHP , Java, Windows, iOS and Android.

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

My home page: http://www.michaelchourdakis.com

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionFatal error: Class 'SQLite3' not found in phpfm Pin
Ngô Tứ Lân23-Dec-17 15:22
memberNgô Tứ Lân23-Dec-17 15:22 
AnswerRe: Fatal error: Class 'SQLite3' not found in phpfm Pin
Michael Chourdakis31-Dec-17 1:28
memberMichael Chourdakis31-Dec-17 1:28 
QuestionBroken link? Pin
sinun30-Jan-17 1:54
membersinun30-Jan-17 1:54 
AnswerRe: Broken link? Pin
Michael Chourdakis30-Jan-17 3:37
memberMichael Chourdakis30-Jan-17 3:37 
GeneralRe: Broken link? Pin
sinun31-Jan-17 2:44
membersinun31-Jan-17 2:44 
GeneralRe: Broken link? Pin
Michael Chourdakis31-Jan-17 4:36
memberMichael 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.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.180910.1 | Last Updated 5 Feb 2017
Article Copyright 2017 by Michael Chourdakis
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid