move_uploaded_file 函数出现“failed to open stream: Permission denied”错误

178

在尝试使用Apache 2.2和PHP 5.3在CentOS上配置上传目录时,我一直遇到这个错误。

php.ini中:

upload_tmp_dir = /var/www/html/mysite/tmp_file_upload/

在 httpd.conf 文件中:

Directory /var/www/html/mysite/tmp_file_upload/>
    Options  -Indexes
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>
<Directory /var/www/html/mysite/images/>
                Options -Indexes
</Directory>

CentOS目录权限:

drwxrwxr-x 2 root root 4096 Nov 11 10:01 images
drwxr-xr-x 2 root root 4096 Nov 12 04:54 tmp_file_upload
无论我做什么,上传文件时PHP都会显示以下错误:
警告:move_uploaded_file(images/robot.jpg): failed to open stream: Permission denied in /var/www/html/mysite/process.php on line 78 警告:move_uploaded_file(): Unable to move '/tmp/phpsKD2Qm' to 'images/robot.jpg' in /var/www/html/mysite/process.php on line 78
正如您所看到的,它从未使用php.ini文件中关于上传文件的配置。我在这里做错了什么?

775?也许你的服务器正在以nobody身份运行。只有root用户才能在这种情况下写入(你的“images”权限)... - Konrad Borowski
1
这是什么意思?我如何更改它? - user63898
请记住,所有父目录也需要具有正确的权限。 - Sridhar Sarnobat
这里只是一个脚注,关于我最近的墙撞事件...请记住,有时Linux也可能会变得棘手。我尝试了各种方法,最终将目标目录重命名并重新创建它,然后它就可以正常工作了。权限、所有权等与旧目录完全相同。 - l0ft13
15个回答

216

这是因为 imagestmp_file_upload 只有 root 用户才有写入权限。为了使上传工作正常,我们需要将这些文件夹的所有者设置为与 httpd 进程所有者相同,或者将它们设置为全局可写(不好的做法)。

  1. 检查 Apache 进程所有者:$ps aux | grep httpd。第一列通常是所有者,它将是 nobody
  2. imagestmp_file_upload 的所有者更改为步骤 1 中找到的所有者(如 nobody)。

  3. $sudo chown nobody /var/www/html/mysite/images/
    
    $sudo chown nobody /var/www/html/mysite/tmp_file_upload/
    
  4. 如果需要的话,现在将imagestmp_file_upload的权限更改为可写。@Dmitry Teplyakov的回答中提到过这一点。[看起来您已经完成了此步骤]。

  5. $ sudo chmod -R 0755 /var/www/html/mysite/images/
    
    $ sudo chmod -R 0755 /var/www/html/mysite/tmp_file_upload/
    
  6. 如需了解更多关于这种行为发生的细节,请查阅手册http://php.net/manual/en/ini.core.php#ini.upload-tmp-dir,请注意它也提到了open_basedir指令。


此修复适用于您可能已将服务器的 PHP 类型从 fast_CGI、CGI 更改为 Apache_mod,如 Plesk 等,可以继续使用原始用户权限而不是 Apache。这解决了我的问题。 - elliotrock
1
我也遇到了相同的错误,但是进程和文件夹都属于 jacob(我因为这是我的本地机器),并且所有文件夹都有 755775 的权限。 - limeandcoconut
2
在更改权限后,我不得不重新启动我的apache进程 sudo service httpd restart,然后它工作正常 :) 我没有改变所有者 chown,而是将我的apache进程添加到“www”组,并通过 chgrp 将这些目录添加到同一“www”组 - Ali Saeed

99

您还可以运行此脚本以查找Apache进程所有者:

<?php echo exec('whoami'); ?>

然后将目标目录的所有者更改为您所得到的所有者。使用以下命令:

chown user destination_dir

然后使用命令

chmod 755 destination_dir

更改目标目录的权限。


4
谢谢,这对我有用。我首先使用了Laith Shadeed的方法,但在输入"ps aux | grep httpd"和"<?php echo exec('whoami'); ?>"时,我没有获得相同的结果。有人知道为什么吗? - kukinsula
2
ps aux | grep https 命令无法返回 Web 服务器所有者的名称。 而这个命令可以:ps aux | grep -E '[a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx' | grep -v root | head -1 | cut -d\ -f1来自 Symfony 文档。 - David Jacquel
1
请注意,在上述命令中,“-d\”和“-f1”之间应该有两个空格。如果您直接复制粘贴,可能会出现“cut: bad delimiter”的错误。 - Beejor
17
应该使用 www-data 用户名吗?通常情况下是这样的。 - maxisme
感谢,exec('whoami') 救了我! - Suge
显示剩余2条评论

35
这对我有用。
sudo adduser <username> www-data
sudo chown -R www-data:www-data /var/www
sudo chmod -R g+rwX /var/www

然后注销或重启计算机。

如果SELinux报错,请尝试以下操作:

sudo semanage fcontext -a -t httpd_sys_rw_content_t '/var/www(/.*)?'
sudo restorecon -Rv '/var/www(/.*)?'

26
如果您使用的是Mac OS X操作系统,请进入您网站的根目录或文件夹。然后右键单击文件夹,在弹出菜单中选择“获取信息”,找到底部的“共享和权限”选项卡,打开它并将所有只读权限更改为读写权限。请确保解锁,然后点击设置图标,并选择“应用于包含项目”选项。

1
你为什么要评论Mac OS,他的问题是关于Linux系统的? - Kmeixner
3
@Kmeixner这个问题是关于Linux的,但我在我的OSX上也遇到了完全相同的问题。谢谢您的评论,在我更改了Mac上/private/var/tmp文件夹中的写入选项后,它对我起作用了。 - Salam

15

我希望在之前的建议中添加这个。如果您正在使用启用了SELinux的Linux版本,则还应在shell中执行以下操作:

chcon -R --type httpd_sys_rw_content_t /path/to/your/directory

除了通过组或更改目录的所有者为您的Web服务器用户授予权限之外。


在此之后,可能还需要包括 restorecon -R -v /path/to/your/directory。请参阅 https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Security-Enhanced_Linux/sect-Security-Enhanced_Linux-SELinux_Contexts_Labeling_Files-Persistent_Changes_semanage_fcontext.html。 - AbsoluteƵERØ
可能是真的,但我认为chcon只是“更改上下文”的假设。你正在查看的是首先使用“semanage fcontext”,将其放入某些设置文件“file_contexts.local”,但它从未更改上下文。 - Chris
@Chris,谢谢你。这解决了我的问题。你能否详细说明一下这个命令的作用?我查看了man页面和chcon的信息,但没有找到你输入的类型值。我有点困惑。 - joker
它使目录或文件对Web服务器(httpd)可读...我真的不想解释selinux,因为我自己对它的理解很浅薄...请参见https://www.nsa.gov/what-we-do/research/selinux/documentation/和https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security-enhanced_linux/index。 - Chris

12

更改此文件夹的权限

# chmod -R 0755 /var/www/html/mysite/images/

(注:本命令涉及修改文件夹权限,请谨慎操作。)<\p>

1
现在它是这样的: drwxrwxr-x 2 root root 4096 Nov 11 10:01 images 还有: drwxrwxr-x 2 root root 4096 Nov 12 04:54 tmp_file_upload 但仍然出现相同的错误。 - user63898

11
尝试这个:
  1. 打开 /etc/apache2/envvars 文件

sudo gedit /etc/apache2/envvars
  • www-data 替换为您的用户名 your_username

  • "export APACHE_RUN_USER=www-data" 
    

    替换为

    export APACHE_RUN_USER='your_username' 
    

    1
    重新启动Apache($ sudo service apache2 restart),以查看<?php echo exec('whoami'); ?>的效果。 - Xopi García

    7

    即使我已经成功运行了composer,我仍然遇到了这个相关的问题。我更新了composer,但在运行composer installphp composer.phar install时出现以下错误:

    ...无法打开流:拒绝权限...

    经过大量研究,我发现更改文件夹权限的先前答案有效。它们只是稍微不同的目录。

    在我的OS X上安装中,缓存文件位于/Users/[USER]/.composer/cache,我遇到了麻烦,因为缓存文件归根用户所有。将'.composer'的所有权递归地更改为我的用户解决了这个问题。

    这是我所做的:

    sudo chown -R [USER] cache
    

    然后我再次运行composer install,哇!

    5

    当apache用户(www-data)没有在文件夹中写入权限时,会出现此问题。为了解决此问题,您需要将用户放入组ww-data中。

    我刚刚做了这个:

    执行此php代码<?php echo exec('whoami'); ?>,以发现由apache使用的用户。然后,在终端中执行命令:

    user@machine:/# cd /var/www/html
    
    user@machine:/var/www/html# ls -l
    

    它将返回类似以下的内容:
    total of files
    
    drwxr-xr-x 7 user group size date folder
    

    我保留了用户,但将组更改为www-data。

    chown -R user:www-data yourprojectfoldername
    
    chmod 775 yourprojectfoldername
    

    5
    解决方案非常简单。只需右键单击IMAGE(目标)文件夹,转到属性,点击权限选项卡,将其他人的访问权限更改为“创建和删除文件”。

    最快的方法是使用GUI进行FTP传输(如FileZilla、WinSCP),但前提是你必须使用GUI界面。 - CLOUGH

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接