0

I am a beginning in Php.

I have been trying for several hours to move an uploaded image to a directory without success. I have already read other questions about the subject, but I have not been able to solve the problem:

1) I have already checked if the directory exists (see output below);

2) It seems that the directory is not writable, but I am not only trying to save the image in a kind of system directory, but also in a simple directory of my computer.

3) The image seems to be uploaded correctly.

4) I have already used "sudo chmod -R 775 /home/daniel/NetBeansProjects/NewPhpProject/photos", but this should not be the problem, since this is not a system directory!

I have no idea what is happening.

Daniel

See my code below:

uploadImage.php

<html>
    <body>
        <h2> Upload your photo. </h2>
        <form action="moveImage.php" method="post"
              enctype="multipart/form-data">
            <label for="file">Filename:</label>
            <input type="file" name="file" id="file"><br>
            <input type="submit" name="submit" value="Submit">
        </form>
    </body>
</html>

movingImage.php

    <?php
    if ($_FILES["file"]["error"] > 0) {
        echo "Error: " . $_FILES["file"]["error"] . "<br>";
    } else {

        //$upload_dir = $_SERVER['DOCUMENT_ROOT'] . "/photos/";
        //$upload_dir = dirname(__FILE__) . "/photos/";
        $upload_dir ="/home/daniel/NetBeansProjects/NewPhpProject". "/photos/";
        echo "upload_dir: " . $upload_dir . "<br>";
        if (file_exists($upload_dir)) {
            if (is_writable($upload_dir)) {
                $target = $upload_dir; //"dirname(__FILE__)" . "photos/";
                $target = $target . basename($_FILES['file']['name']);
                $moved = move_uploaded_file($_FILES['file']['name'], "$target");
            } else {
                echo 'Upload directory is not writable<br>';
            }
        } else {
            echo 'Upload directory does not exist.<br>';
        }
        echo $target . "<br>";
    //  echo dirname(__FILE__)."<br>";
    echo "Upload: " . $_FILES["file"]["name"] . "<br>";
    echo "Type: " . $_FILES["file"]["type"] . "<br>";
    echo "Size: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
    echo "Stored in: " . $_FILES["file"]["tmp_name"];
}
?> 

Output:

upload_dir: /home/daniel/NetBeansProjects/NewPhpProject/photos/

Upload directory is not writable

Upload: FotoCaju.jpeg

Type: image/jpeg

Size: 0.666015625 kB

Stored in: /tmp/phpmTJWMi

DanielTheRocketMan
  • 3,199
  • 5
  • 36
  • 65
  • 1
    The path to the directory must also be writable. There are a number of solutions, but I think the best would be to make a [symbolic link](http://stackoverflow.com/questions/1951742/how-to-symlink-a-file-in-linux) somewhere that Apache can write to that points to your desired directory. –  Jan 12 '14 at 23:52
  • @MisterMelancholy why a symlink? – Phil Jan 12 '14 at 23:53
  • @Phil Because it's easy to implement, easy to remember if the project gets moved to another box, makes it easy to change the target directory in the future, and doesn't involve changing the permissions to the user's home directory. Permissions exist to keep users safe, so try to avoid giving more permissions than are necessary. –  Jan 12 '14 at 23:56
  • As an alternative to weakening permissions on your `photos` directory, you could look at running the PHP script as the appropriate user via something like suExec or mpm-itk. – Phil Jan 12 '14 at 23:57
  • @MisterMelancholy But you can't just apply permissions to a symlink. The real destination would still need to be writeable by the script. I think the commented out `__DIR__ . '/photos'` is the best approach. – Phil Jan 12 '14 at 23:58
  • @Phil. Very bad idea. If someone hacks Apache and is able to to create files under whatever user Apache is running as, then the whole computer will be contaminated, and all of the user's personal data will be stolen. The system will have to be re-installed, and even backing up and restoring your personal data is not safe since those files may have been modified by a hacker. –  Jan 12 '14 at 23:59
  • @Phil The point of using a sym link is to be able to apply permissions on only one directory (the photos directory), not every directory along the way (like the user's home directory). –  Jan 12 '14 at 23:59
  • @MisterMelancholy So you're saying that [suEXEC](http://httpd.apache.org/docs/2.2/suexec.html), a hugely popular approach to this sort of problem, is a *very bad idea*? – Phil Jan 13 '14 at 00:03
  • Just to be clear, the other commented solutions "$upload_dir = $_SERVER['DOCUMENT_ROOT'] . "/photos/";" and "$upload_dir = dirname(__FILE__) . "/photos/";" were run and the same problem happens. I thought the problem was a kind of directory protection... That's the reason I tried a different directory. – DanielTheRocketMan Jan 13 '14 at 00:04
  • @Phil I'd say so. Do you really want anybody smart enough to find a security vulnerability in your website to have full permissions to the user Apache is executing scripts under? @DanielTheRocketMan Every directory along the way to the directory must also have the necessary permissions. You could apply 755 to `/home`, `/home/Daniel/`, etc, but I wouldn't recommend it for reasons stated in my second comment. –  Jan 13 '14 at 00:09
  • @MisterMelancholy For starters, if somebody *hacked Apache*, you have bigger problems. Also, the scripts would run as a non-privileged user, sandboxed to the configured directories making the entire environment safer from a system perspective. As for your second point, parent directories need only have the execute permission (001) to enable traversal. Only the final directory need be made writable – Phil Jan 13 '14 at 00:13
  • @Phil. My apologies. By hacked Apache, I meant hacked your website and found a way to execute code, which would allow them to hijack Apache. My second point is that even if the user is non-privileged, would you want some hacker to have access to all of your personal information on that computer? Would you want just give more privileges than they'd have with Apache? As for your `001` theory, give it a try. I just tried it, and it didn't work. –  Jan 13 '14 at 00:18

3 Answers3

4

You need to change the directory permissions for /home/daniel/NetBeansProjects/NewPhpProject/photos/. For this, you will use the chmod command.

$: chmod +w /home/daniel/NetBeansProjects/NewPhpProject/photos/

K. S.
  • 586
  • 5
  • 20
  • Unfortunally, this is not the problem. I have just (now) tried it and the problem persists. I guess this is similar to item (4) above. – DanielTheRocketMan Jan 12 '14 at 23:58
  • @DanielTheRocketMan If you're running Apache, it typically runs under the `www-data` user, so that user will have to have write access to that directory. Use `chmod 777 /home/daniel/NetBeansProjects/NewPhpProject/photos/` so that the folder is accessible (r+w+e) publicly. Alternatively, you could `chown` the folder to be owned by www-data, but that wouldn't make any sense because it is within the daniel user's home directory. – K. S. Jan 13 '14 at 00:03
  • I followed your suggestion and the output changes and the line "Upload directory is not writable" disappeared (thank you). However, the image is not in this directory! Is there something missing in my code? – DanielTheRocketMan Jan 13 '14 at 00:16
  • @DanielTheRocketMan Check to see whether or not $moved is true after declaring it with move_uploaded_file. If it's false, check your error logs to see if there's something else wrong. – K. S. Jan 13 '14 at 00:19
  • Thank you again! You are right, $moved is false, but it is quite strange. I checked the error.log (in /var/log/apache2$) and there is no error related to the php executions of the last hour. – DanielTheRocketMan Jan 13 '14 at 00:50
  • 1
    apart from permission issue there is another error in the code, in move_uploaded_file function first parameter is wrong. parameter should have $_FILES['file']['tmp_name'] instead of $_FILES['file']['name']. – Fazle Elahee Jan 13 '14 at 00:57
  • @FazleElahee After solving the permission problems, your comment was fundamental for correcting the code. – DanielTheRocketMan Jan 13 '14 at 01:54
1

PHP.net site comment is_writable:

Note: The results of this function are cached. See clearstatcache() for more details.

Try it. Maybe the result is cached with the result before you have changed the permissions of the folder.

0

The problem is probably that every directory along the way to /home/daniel/NetBeansProjects/NewPhpProject/photos/ must also be writable by Apache.

Since changing permissions to your home directory is generally not a good idea, you should make a symbolic link somewhere that Apache has access to that is outside of public_html (like /var/www) that points to your target directory, which should have the correct permissions for the Apache user.

Community
  • 1
  • 1
  • It seems that this is not the problem either. Maybe I have done something wrong in the php file. I am not sure. Since the computer that I am using now is for testing purposes, I have changed the permissions of var, var/www and var/www/photos. The output shows that the problem persists: upload_dir: /var/www/photos/ /var/www/photos/fotocaju.jpeg not cool (means that $moved is false) Upload: fotocaju.jpeg Type: image/jpeg Size: 0.666015625 kB Stored in: /tmp/phpREleYF – DanielTheRocketMan Jan 13 '14 at 01:16
  • Who owns those directories, and what are the permissions on them? @DanielTheRocketMan –  Jan 13 '14 at 01:23
  • I am working in my laptop! So, in thesis I can change everything. But I believe this is not your question! How do I know the permissions? – DanielTheRocketMan Jan 13 '14 at 01:26
  • @DanielTheRocketMan In the command line, you can type `ls -al` to display detailed information. The user can be anything, the group should be `www-data` or whatever group your Apache user is in, and the permissions should say `drwxrwxr-x` (also known as 775) for directories, and `-rw-rw-r--` (also known as 664) for files. –  Jan 13 '14 at 01:29
  • Now it is working! Thank you! Besides the permission problems, there was also a mistake in the code pointed by @FazleElahee. Please, see comment above! Should I edit the question (code) to avoid the error of others? What is the correct procedure? – DanielTheRocketMan Jan 13 '14 at 01:57
  • You're Welcome! Knowing how Linux permissions work are important to ensure that your server is stable and secure. If you have any questions directly related to Linux, try using the [Linux Stack Exchange](http://unix.stackexchange.com/) (after a Google search of course). @DanielTheRocketMan –  Jan 13 '14 at 01:58
  • 1
    Your first statement is simply not true. The only permission the Apache user needs on `/home`, `/home/daniel`, ... `/home/daniel/NetBeansProjects/NewPhpProject` is the execute bit. See http://unix.stackexchange.com/questions/13858/do-the-parent-directorys-permissions-matter-when-accessing-a-subdirectory – Phil Jan 13 '14 at 02:32