我使用的脚本检查存储在hosts.allow文件中的IP地址,以防止IP映射到我的dyndns主机名,这样一旦我将当前的IP同步到该主机名,我就可以登录我的服务器。出于某种原因,虽然脚本似乎导致了非常间歇性的问题。
在我的hosts.allow文件中我有一个这样的部分:
#SOme.gotdns.com
sshd : 192.168.0.1
#EOme.gotdns.com
#SOme2.gotdns.com
sshd : 192.168.0.2
#EOme2.gotdns.com
我有一个在cron(每分钟)上运行的脚本,如下所示:
#!/usr/bin/php
<?php
$hosts = array('me.gotdns.com','me2.gotdns.com');
foreach($hosts as $host)
{
$ip = gethostbyname($host);
$replaceWith = "#SO".$host."\nsshd : ".$ip."\n#EO".$host;
$filename = '/etc/hosts.allow';
$handle = fopen($filename,'r');
$contents = fread($handle, filesize($filename));
fclose($handle);
if (preg_match('/#SO'.$host.'(.*?)#EO'.$host.'/si', $contents, $regs))
{
$result = $regs[0];
}
if($result != $replaceWith)
{
$newcontents = str_replace($result,$replaceWith,$contents);
$handle = fopen($filename,'w');
if (fwrite($handle, $newcontents) === FALSE) {
}
fclose($handle);
}
}
?>
我遇到的问题是间歇性地删除字符(我假设在替换期间)会导致将来的更新失败,因为它会插入如下内容:
#SOme.gotdns.com
sshd : 192.168.0.1
#EOme.gotdn
注意缺少的&#34; s.com&#34;
这当然意味着我无法访问服务器,任何想法为什么会发生这种情况?
感谢。
答案 0 :(得分:2)
可能是由于脚本执行时间 - 可能太短 - 或者1分钟间隔太短。当cron正在完成这项工作时,另一个脚本程序启动,它可能影响第一个脚本。
答案 1 :(得分:2)
这几乎可以肯定是因为脚本在通过cron再次启动之前的一分钟时间内没有完成执行。您需要实现某种锁定,或使用仅允许运行一次脚本实例的工具。有几种工具可以做到这一点,例如lockrun。
答案 2 :(得分:1)
我想说为了安全地执行此操作,您应该在脚本开头的文件上acquire an exclusive lock,将其全部读入内存,在内存中修改,然后将其写回文件在末尾。就磁盘I / O而言,这也会更加有效。
您还应该更改cron作业以减少运行频率。您当前遇到此问题的原因很可能是因为两个进程同时运行 - 通过锁定文件,如果是这种情况,您可能会有进程堆叠等待获取锁定的风险。每5分钟设置一次应该足够好 - 你的IP不应该经常改变
这样做( FIXED ):
#!/usr/bin/php
<?php
// Settings
$hosts = array(
'me.gotdns.com',
'me2.gotdns.com'
);
$filename = '/etc/hosts.allow';
// No time limit (shouldn't be necessary with CLI, but just in case)
set_time_limit(0);
// Open the file in read/write mode and lock it
// flock() should block until it gets a lock
if ((!$handle = fopen($filename, 'r+')) || !flock($handle, LOCK_EX)) exit(1);
// Read the file
if (($contents = fread($handle, filesize($filename)) === FALSE) exit(1);
// Will be set to true if we actually make any changes to the file
$changed = FALSE;
// Loop hosts list
foreach ($hosts as $host) {
// Get current IP address of host
if (($ip = gethostbyname($host)) == $host) continue;
// Find the entry in the file
$replaceWith = "#SO{$host}\nsshd : {$ip}\n#EO{$host}";
if (preg_match("/#SO{$host}(.*?)#EO{$host}/si", $contents, $regs)) {
// Only do this if there was a match - otherise risk overwriting previous
// entries because you didn't reset the value of $result
if ($regs[0] != $replaceWith) {
$changed = TRUE;
$contents = str_replace($regs[0], $replaceWith, $contents);
}
}
}
// We'll only change the contents of the file if the data changed
if ($changed) {
ftruncate($handle, 0); // Zero the length of the file
rewind($handle); // start writing from the beginning
fwrite($handle, $contents); // write the new data
}
flock($handle, LOCK_UN); // Unlock
fclose($handle); // close