我require
的 PHP 脚本顶部有一个文件。该文件只有 MySQL 的连接对象:
$c->new mysqli('host','usr','pass','db')
该文件具有400
权限:-r--------
并且我将其/etc/mysql/
远离我的网页根目录(/var/www/html
)。
它工作得很好,除了每天晚上午夜它都会停止,我的所有页面都会收到权限被拒绝的错误:
Warning: require(/etc/mysql/.myfile.php): Failed to open stream: Permission denied in...
如果我将权限更改为444
,请登录我的网站,然后将权限更改回400
。它一直工作到第二天午夜。我可以全天多次登录和注销我的网站,但是当午夜到来时,它就会失败。
造成这种情况的原因是什么以及如何解决?
显然我想保留它,以便只能root
读取该文件,因为它有明文密码。
答案1
这应该是一条评论 - 但空间有限,格式也有限。
你并没有真正对这种情况提供一个很好的解释。
您已经说过您“失去权限”以及如何恢复正常操作,但您没有说明权限是什么后午夜活动。
在确定访问权限时,如果没有所有权详细信息,权限就没有意义。据推测,该文件最初由您的网络服务器 uid 拥有(尽管您实际上并没有说该文件是由从网络服务器运行的脚本访问的)。再说一遍,这些之前和之后是什么?
你是如何确定它在午夜停止的?确切地知道事件发生的时间是解决问题的有用垫脚石。如果它发生在 00:00:00 和 00:03:00 之间,那么很有可能这是由于某些计划任务造成的。这也使其成为很多更容易将事件与系统日志(以及网络服务器日志)交叉引用。
不过,感谢您考虑权限和访问......
您选择的权限并不理想。再次假设这是一个网络服务器,那么该文件只能由 root 用户管理。如果您是唯一维护服务器的人,那么更好的方法是将所有权设置为 bungee1980:wwwgrp (其中 wwwgrp 是网络服务器 uid 的默认组)和权限 -rw-r----- (0750) 。
您选择的位置并不理想。大多数现代操作系统通过强制访问控制机制(RHEL 及其衍生产品上的 SELinux,其他地方的 Apparmor)来限制文件访问。通常将网络服务器限制为仅包含其内容的目录树。虽然出于明显的原因您不希望此文件位于文档根目录中,但您(通常)也不希望允许您的脚本直接从 /etc 中的许多其他文件读取
一个小问题是 PHP提供了一种机制用于设置默认凭据和数据库详细信息(以及运行额外的样板代码在目标脚本之前)。鉴于这可以在您的网络服务器配置中设置,这可能是更合适的凭证工具。
答案2
如果我将权限更改为 444,请登录我的网站,然后将权限更改回 400。
换句话说:使用权限 400,您的脚本无法读取该文件,但使用权限 444,它们可以,然后某个进程将保持文件打开或将凭据保留在 RAM 中,直到午夜,此时某些事件会触发重新启动或清理某种形式的。
您没有提到您正在使用的操作系统/发行版,但我会首先检查/etc/cron.*
任何相关用户的 crontab(通常为/var/spool/cron[/crontabs]
或类似),以查找在午夜运行的任何每日 cron 作业。也许有什么东西可以清理旧的 PHP 会话?或者它可能会logrotate
触发某些事情的重新启动,例如php-fpm
作为每日日志轮换计划的一部分?
如果您的系统使用systemd
,还要检查其计时器单位:systemctl list-units --type=timer
列出所有系统范围的计时器,然后systemctl cat <name>.timer
查看它们。
例如,在 Debian 12 中,logrotate
可以由 触发/etc/cron.daily/logrotate
,它可能anacron
在 中指定的时间运行/etc/cron.d/anacron
,默认是系统运行时的 07:30 到 23:30 之间的最早时间...但实际上会使用这个时间表仅当systemd
不使用时,因为中指定的工作/etc/cron.d/anacron
是有条件的/run/systemd/system
不是现存的。
使用systemd
,logrotate.timer
来代替,它的指定如下:
systemctl cat logrotate.timer
# /lib/systemd/system/logrotate.timer
[Unit]
Description=Daily rotation of log files
Documentation=man:logrotate(8) man:logrotate.conf(5)
[Timer]
OnCalendar=daily
AccuracySec=1h
Persistent=true
[Install]
WantedBy=timers.target
如 中所述man systemd.time
,OnCalendar=daily
的意思是*-*-* 00:00:00
,即每天恰好在午夜。允许AccuracySec=1h
将此计时器与在 00:00 和 01:00 之间触发的其他计时器(如果存在)合并,以优化节能。至少在我的系统上,最终结果似乎是日志轮换正好发生在午夜,除非系统当时停机。
使用systemctl status logrotate.timer
,您可以查看定时器的下一个预定触发时间。