Question

I am working on a PHP web app on a Linux web server for grades and documents for a course that I am co-teaching. The page I am writing at the moment is for submitting assignments, where the student selects an assignment from a drop-down menu and then uploads the assignment and submits. On submit, all the information about the submission goes into a MySQL table, and the file is moved to a permanent location on the file system. Ideally, this would be something highly organized by assignment, student, and version, but all I want right now is to get the file upload working in principle, so for now it just sends stuff to the directory ~/phptest/ (permissions for which are set to 755, though I have tried 777 just for tests, and that didn't work either). Here is the code as it is now:

($dbh is an instance of an expanded DB handle class I created to make these specific DB transactions cleaner)


if(isset($_POST['submit'])) {
    $assignmentID = $_POST['assID'];
    $tmp = "/home/username/phptest/"; 
    $info = pathinfo($_FILES['file']['name']);
    $filename = $info['basename'];
    $ext = $info['extension'];
    if(1) { //strcmpall($ext,array('tar.gz','zip'))) {
        if($_FILES['file']['size'] < 1000000) {
            $path = $tmp . $filename;
            if(move_uploaded_file($_FILES['file']['tmp_name'], $path)) {
                $versionQuery = $dbh->select(array('version'),array('a01_submissions'),array("studentID='$studentID'","assignmentID='$assignmentID'"));
                if(count($versionQuery)) {
                    $versionArray = $dbh->colToArray($versionQuery,'version');
                    $version = max($versionArray)+1;
                }
                else $version = 1;
                echo "Version $version.\n";
                $week = $dbh->getOne('week','a01_assignments','id',$assignmentID);
                $dbh->insert("a01_submissions",array('studentID','assignmentID','version','filePath'),array($studentID,$assignmentID,$version,addslashes($newpath)));
                echo "File $filename sucessfully uploaded and stored at $newpath.\n";
            }
            else echo $moved . "
\n"; } else die("File cannot exceed 1MB"); } else die("Bad file extension."); } else { // HTML to display the submission screen }

My problem, though, is that move_uploaded_file only works for directories with 777 permissions. Closer inspection reveals that this is because PHP is uploading stuff as the user 'apache', and therefore can't write to directories owned by my username with o-w. I saw solutions posted by users in the PHP docs that suggested using chown to reclaim the files, but I don't have a high enough permission level to do this. Is there an elegant solution to this problem that does not involve trying to get my username higher permissions?

Was it helpful?

Solution

Get the sysadmin to put you in the same user group as apache or ideally create a new group called something like developers and add the apache user and yourself to it.

Otherwise you could try using PHP's chmod or chown functions immediately after the file upload. If you run chmod($filepath, 0777); that should be a good test of whether it will work for you or not.

OTHER TIPS

Short answer: There isn't an elegant solution, as this is conceptually wrong. There is a reason why the file is owned by the web server user in the first place. It is the web server which created the file (from the OS point of view), so he should own it.

Long answer: What are the reasons behind the fact that you do want the file to be owned by an other user?

  1. Security Well, as soon as the file is not owned by the web server any more, it can not be overwritten by it so if an attacker takes over the web server, he or she can not alter the assignments any more. Granted. But instead of doing Weird Stuff™ a web application should focus on what it is supposed to do and securing the web server surely is not one of it's tasks. A proper application architecture and some standard security measures should do the same trick and inherently hold a lot more security than just changing the owner of the file. If you absolutely have to move the data around, you could either set up a watch folder using a tool like incron or inotincoming. In case your security needs are high, you should think of implementing a SELinux profile on your web server.
  2. Underlying business logic It is a bad idea to implement complex workflows all by yourself. If you have additional business logic regarding the processing of the documents, I'd suggest using either Apache Camel or Apache Servicemix, which in turn uses Camel, but provides a lot more features. Apache camel is a Wrouting and mediation engine", which roughly translates to "it processes messages according to Enterprise Integration Patterns. That in turn means it converts, splits, enriches, routes or filters any given payload. There is an excellent file processing module which automates a lot of stuff you have to take care for yourself when implementing business logic (processing, resuming interrupted processing, creating backups and such). Camel supports php too (though I would not recommend using php the first place, but that is admittedly completely biased). You can chain this with incron or inotincoming
  3. Access It might be that you want to access those files via ftp, but not add the ftp user to the web server group. Easy solution: use the "others" permissions. It is not that setting the other's permission broadcasts the files among the internet. Make sure you have a read only permission for "others" set and you are good to go. Another solution might be to set up a ftp server with virtual users.

Bottom line: there is always a solution without undermining the sense, much less the implementation of security measures.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top