使用php脚本中的rsync同步本地和远程文件夹,而无需输入密码 [英] Sync local and remote folders using rsync from php script without typing password

查看:92
本文介绍了使用php脚本中的rsync同步本地和远程文件夹,而无需输入密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在不提示输入密码的情况下从php脚本中使用rsync同步本地和远程文件夹?

How can I sync local and remote folders using rsync from inside a php script without beeing prompted to type a password?

我已经设置了一个公共密钥来自动为我的用户在远程服务器上登录.

I have already set up a public key to automate the login on remote server for my user.

因此,cli的运行没有任何问题.

So this is running without any problem from cli:

rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/;

但是,当我尝试从PHP脚本(在本地服务器的网页上)运行相同代码时:

But, when I try to run the same from a PHP script (on a webpage in my local server):

$c='rsync -r -a -v -e "ssh -l user" --delete ~/local/file 111.111.11.111:~/remote/';
//exec($c,$data);
passthru($c,$data);
print_r($data);

这是我收到的:

255

并且没有文件从本地上传到远程服务器.

And no file is uploaded from local to remote server.

我在网上搜索了这个线索:

您可以在此处使用BASh和Expect外壳程序代码的组合,但是它并不是很安全,因为那样会自动进行root登录.为nobodyapache(无论哪个用户是Apache,请生成用户密钥)或者,安装phpSuExec,Suhosin或suPHP,以使脚本以调用脚本的用户身份运行."

"You could use a combination of BASh and Expect shell code here, but it wouldn't be very secure, because that would automate the root login. Generate keys for nobody or apache (whatever user as which Apache is being executed). Alternatively, install phpSuExec, Suhosin, or suPHP so that the scripts are run as the user for which they were called."

好吧,我不知道如何以PHP的"apache"运行方式来自动化root登录".也许让脚本以实际用户身份运行是一个更好的主意,我不知道...谢谢!

Well, I don't know how to "automate the root login" for PHP, which is running as "apache". Maybe to make the script run as the actual user is a better idea, I don't know... Thanks!

更新: -正常工作:

passthru('ssh user@111.111.11.111 | ls',$data);

我可以肯定,返回家用推杆的列表,自动登录没有问题.从PHP脚本运行rsync可以解决问题.

Returning a list of the home foder, I can be sure, there is no problem with the automatic login. It mast be something with rsync running from the PHP script.

  • 我也为本地和远程文件夹提供了chmod -R 0777,以防万一.但是我还没有得到.

更新:

所有问题都与以下事实有关:当在命令行上运行时,ssh使用$ HOME/.ssh/上的密钥文件,但是在PHP下,它是使用Apache的用户运行的,因此它可能没有$ HOME;这很多.减去$ HOME/.ssh/id_dsa.因此,您可以明确告诉它使用哪个密钥文件,或者手动创建该目录及其内容."

All the problem is related to the fact that "when ran on commandline, ssh use the keyfiles on $HOME/.ssh/, but under PHP, it's ran using Apache's user, so it might not have a $HOME; much less a $HOME/.ssh/id_dsa. So, either you specifically tell it which keyfile to use, or manually create that directory and its contents."

虽然我无法获得rsync,但这是我将文件从本地传输到远程的方法:

While I cannot get rsync, this is how I got to transfer the file from local to remote:

if($con=ssh2_connect('111.111.11.111',22)) echo 'ok!';
if(ssh2_auth_password($con,'apache','xxxxxx')) echo ' ok!';
if(ssh2_scp_send($con,'localfile','/remotefolder',0755)) echo ' ok!';

本地文件需求:0644 远程文件夹需要:0775

Local file needs: 0644 Remote folder needs: 0775

我猜想解决方案不是要以相同的用户bash运行php ...

I guess if the solution wouldn't be to run php with the same user bash does...

@Yzmir Ramirez提出了这样的建议:我不希望您将密钥复制到可以获取apache的位置" –这是安全性违规.最好将脚本更改为安全地运行用户,然后设置.ssh密钥以在服务器之间进行无密码登录.

@Yzmir Ramirez gave this suggestion: "I don't think you want to "copy the key somewhere where apache can get to it" - that's a security violation. Better to change the script to run as a secure user and then setup the .ssh keys for passwordless login between servers.

这是我必须花费更多时间的事情.如果有人知道如何做到这一点,那将有很大的帮助.

This is something I have to invest some more time. If somebody know how to do this, please, it would be of great help.

推荐答案

当我在我们的应用程序中设置相同的内容时,我也遇到了255个错误,发现它们可能意味着多种含义;它不是特别有用的错误代码.实际上,即使是现在,在该解决方案顺利运行了一年以上之后,我仍然偶尔会在日志中看到255.

When I set this same thing up in an application of ours, I also ran into 255 errors, and found that they can mean a variety of things; it's not a particularly helpful error code. In fact, even now, after the solution's been running smoothly for well over a year, I still see an occasional 255 show up in the logs.

我还要说,要使它正常工作可能会有些麻烦,因为其中涉及多个变量.我发现极其有用的一件事是在变量中构造rsync命令,然后将其记录下来.这样,我可以掌握正在使用的确切rsync命令,并尝试手动运行它.您甚至可以su给apache用户,并在与脚本相同的目录中运行它(或将脚本设置为cwd),这将使其与以编程方式运行时的行为相同.这使调试rsync命令变得更加简单,因为您不必处理Web服务器.另外,当您手动运行它时,如果由于某种未说明的原因而失败,请添加详细程度标志以提高错误输出.

I will also say that getting it to work can be a bit of a pain, since there are several variables involved. One thing I found extremely helpful was to construct the rsync command in a variable and then log it. This way, I can grab the exact rsync command being used and try to run it manually. You can even su to the apache user and run it from the same directory as your script (or whatever your script is setting as the cwd), which will make it act the same as when it's run programmatically; this makes it far simpler to debug the rsync command since you're not having to deal with the web server. Also, when you run it manually, if it's failing for some unstated reason, add in verbosity flags to crank up the error output.

下面是我们正在使用的代码,为安全起见对其进行了稍微的编辑.请注意,我们的代码实际上支持到本地和远程服务器的rsync同步,因为目标是完全可配置的,以允许轻松进行测试安装.

Below is the code we're using, slightly edited for security. Note that our code actually supports rsync'ing to both local and remote servers, since the destination is fully configurable to allow easy test installations.

try {
    if ('' != $config['publishSsh']['to']['remote']):
    //we're syncing with a remote server
        $rsyncToRemote = escapeshellarg($config['publishSsh']['to']['remote']) . ':';
        $rsyncTo = $rsyncToRemote . escapeshellarg($config['publishThemes']['to']['path']);
        $keyFile = $config['publishSsh']['to']['keyfile'];
        $rsyncSshCommand = "-e \"ssh -o 'BatchMode yes' -o 'StrictHostKeyChecking no' -q -i '$keyFile' -c arcfour\"";
    else:
    //we're syncing with the local machine
        $rsyncTo = escapeshellarg($config['publishThemes']['to']['path']);
        $rsyncSshCommand = '';
    endif;

    $log->Message("Apache running as user: " . trim(`whoami`), GLCLogger::level_debug);
    $deployCommand = "
        cd /my/themes/folder/; \
        rsync \
        --verbose \
        --delete \
        --recursive \
        --exclude '.DS_Store' \
        --exclude '.svn/' \
        --log-format='Action: %o %n' \
        --stats \
        $rsyncSshCommand \
        ./ \
        $rsyncTo \
         2>&1
    "; //deployCommand
    $log->Message("Deploying with command: \n" . $deployCommand, GLCLogger::level_debug);
    exec($deployCommand, $rsyncOutputLines, $returnValue);
    $log->Message("rsync status code: $returnValue", GLCLogger::level_debug);
    $log->Message("rsync output: \n" . implode("\n", $rsyncOutputLines), GLCLogger::level_debug);
    if (0 != $returnValue):
        $log->Message("Encountered error while publishing themes: <<<$returnValue>>>");
        throw new Exception('rsync error');
    endif;

    /* ... process output ... */
} catch (Exception $e) {
    /* ... handle errors ... */
}

有关代码的几点注意事项:

A couple of things to notice about the code:

  • 我正在使用exec()以便可以将输出捕获到变量中.然后,我对其进行解析,以便可以根据添加,修改和删除了多少文件来记录并报告结果.

  • I'm using exec() so that I can capture the output in a variable. I then parse it so that I can log and report the results in terms of how many files were added, modified, and removed.

我正在组合rsync的标准输出和标准错误流,并同时返回两者.我也在捕获并检查返回结果代码.

I'm combining rsync's standard output and standard error streams and returning both. I'm also capturing and checking the return result code.

在调试模式下,我会记录所有内容,包括运行用户Apache,rsync命令本身以及rsync命令的输出.这样,就像我上面提到的那样,只需快速复制和粘贴即可轻松地与同一用户运行同一命令.

I'm logging everything when in debug mode, including the user Apache is running as, the rsync command itself, and the output of the rsync command. This way, it's trivially easy to run the same command as the same user with just a quick copy-and-paste, as I mention above.

如果rsync命令遇到问题,可以调整其详细程度而不会产生影响,并在日志中查看输出.

If you're having problems with the rsync command, you can adjust its verbosity without impact and see the output in the log.

就我而言,我能够简单地指向适当的密钥文件,而不必过于担心安全性.也就是说,有关如何处理此问题的一些想法:

In my case, I was able to simply point to an appropriate key file and not be overly concerned about security. That said, some thoughts on how to handle this:

  • 为Apache提供对该文件的访问权限并不意味着它必须位于Web目录中;您可以将文件放在Apache用户可以访问的任何位置,甚至可以放在另一台网络计算机上.取决于您的其他安全层,这可能是也可能不是可接受的折衷.

  • Giving Apache access to the file doesn't mean that it has to be in the web directory; you can put the file anywhere that's accessible by the Apache user, even on another network machine. Depending on your other layers of security, this may or may not be an acceptable compromise.

根据要复制的数据,您可能能够在另一台计算机上大量锁定ssh用户的权限,因此,如果有人不法行为设法进入该计算机,则他们的访问权限将最小造成伤害的能力.

Depending on the data you're copying, you may be able to heavily lock down the permissions of the ssh user on the other machine, so that if someone unscrupulous managed to get in there, they'd have minimal ability to do damage.

您可以使用suEXEC以Apache用户以外的其他用户身份运行脚本,从而可以将对该密钥的访问权限锁定为该其他用户.因此,危害Apache用户的人根本无法访问该密钥.

You can use suEXEC to run the script as a user other than the Apache user, allowing you to lock access to your key to that other user. Thus, someone compromising the Apache user simply would not have access to the key.

我希望这会有所帮助.

这篇关于使用php脚本中的rsync同步本地和远程文件夹,而无需输入密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆