【问题标题】:PHP: read a remote file (ideally using fopen)PHP:读取远程文件(最好使用 fopen)
【发布时间】:2019-01-06 01:37:06
【问题描述】:

我想使用 PHP 读取远程文本文件(最好使用 fopen)。当我在本地文件上使用此函数时,我的脚本使用 fopen 工作。

我试过了:

$file = fopen ("http://abc.abc.abc", "r");
if (!$file) {
    echo "<p>Unable to open remote file.\n";
    exit;
}

我得到了:

警告:fopen(http://abc.abc.abc):打开流失败:由于目标机器主动拒绝,无法建立连接。在第 2 行的 C:\xampp\htdocs\NMR\nmrTest5.php 中无法打开远程文件。

我读到phpseclib 可能是一个不错的选择,因为我可以使用 WinSCP (SFTP) 或使用 Puttyfor 访问我的文件,所以我尝试了这个(在将所有文件从 phpseclib 复制到我的目录之后)希望我可以在本地复制文件,然后用 fopen 读取它(这不是遇到的最好的事情,但我可以忍受):

include('Net/SFTP.php');

$sftp = new Net_SFTP('abc.abc.abc');
if (!$sftp->login('username', 'pass')) {
    exit('Login Failed');
} 

我得到了:

注意:在第 1561 行的 C:\xampp\htdocs\NMR\Net\SSH2.php 中找不到兼容的服务器到客户端加密算法 登录失败

有趣的是,如果我连接到服务器(使用 WinSCP),我会收到不同的消息:

注意:从第 3362 行 C:\xampp\htdocs\NMR\Net\SSH2.php 中的套接字读取错误

注意:第 1471 行 C:\xampp\htdocs\NMR\Net\SSH2.php 中的服务器关闭了连接 登录失败

知道如何让它工作吗?理想情况下,我会使用 fopen,但我愿意接受其他解决方案。

【问题讨论】:

  • 要将fopenfilefile_get_contents 用于URL,您需要在php.ini 中启用allow_url_fopen 或使用ini_set。否则,正如给出的答案所说,使用 cURL 来获取 URL 的内容
  • 您是否尝试了解错误消息? fopen()生成的那条很清楚:“无法连接,因为目标机器主动拒绝”。您的代码没有问题,远程计算机不接受连接。你能在浏览器中打开网址(http://abc.abc.abc)吗?如果可以,那么fopen() 也应该可以打开它。如果不能,则可能是 URL 不正确,无论您如何尝试都无法打开。
  • @axiac:是的,我试图理解我的错误信息。我认为你是对的,我只是无法在浏览器中打开 URL。我发布了我所做的,尽可能多地提供信息,并表明我自己尝试了一些东西。这也是我尝试使用 phpseclib 的原因,因为我知道我可以使用 SFTP 协议(​​使用 WinSCP)访问文件。我仍在调查 Tanvir Ahmed 给出的答案,但如果我需要使用 SFTP,我不确定它是否会起作用。
  • 对于 phpseclib,您可能没有设置 include_path。你可以这样做:set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
  • @neubert:感谢您的评论。我已经设置了 include_path,现在当我运行我的脚本时,我什么也没有告诉我它有效。 (我还在我的代码中添加了Else echo "it works!";,我得到:它有效)。现在我需要处理我的文件......我认为我正在朝着正确的方向前进。谢谢。

标签: php fopen phpseclib


【解决方案1】:

这就是我使用 phpseclib 解决问题的方式,正如@neubert 在我的问题的 cmets 中所建议的那样。

我首先在我的服务器上添加了phpseclib 文件夹。然后我在我的 PHP 文件中使用了这段代码来访问我在远程服务器上的文件:

//needed for phpseclib
set_include_path(get_include_path() . PATH_SEPARATOR . 'phpseclib');
include_once('Net/SFTP.php');

//connection to the server
$sftp = new Net_SFTP('abc.abc.abc');
if (!$sftp->login('my_login', 'my_password')) {
  exit('Login Failed');
}

//dump entire file in a string, convert to an array and check number of lines

else {
  $text = $sftp->get('full_path_to_my_file');
}
$myArray = explode("\n", $text);
$nbline = count($myArray);

【讨论】:

  • 这是获取文件(下载)的基本方法。它应该适用于大多数用例,但如果由于带宽使用和文件同步问题需要对远程文件进行大量更新,则它并不理想。
【解决方案2】:

我自己刚刚解决了这个确切的问题,在任何一个地方都找不到任何好的文档来说明如何完成这个。

我刚刚创建了一个使用 Monolog 的日志服务,并且基本上基于正在写入/创建的日志文件创建了一个自定义流处理程序。因此,它需要一种资源(例如由fopen 创建的资源)才能将日志文件写入 SFTP 服务器。

我让它像这样使用 ssh2 库工作:

$connection = ssh2_connect($this->host, 22);
ssh2_auth_password($connection, $this->user, $this->password);

$sftp = ssh2_sftp($connection);

//some stuff to do with whether the file already exists or not

$fh=fopen("ssh2.sftp://$sftp".ssh2_sftp_realpath($sftp,".")."/$this->logName/$this->fileName", 'a+');

return new StreamHandler($fh);

一切都很顺利,直到我将该服务集成到另一个项目中并意识到这仅适用于我的开发机器,因为它安装了libssh2as outlined in this question

不幸的是,生产服务器并不那么容易添加库。因此,我发现自己正在寻找不同的解决方案。

我在其他项目中使用过phpseclib,但仅用于基本的get()put() 和一些nlist() 调用。

为了让这个工作我不得不使用Stream 对象。没有很好的记录,但有a good discussion here

根据那里的信息,加上在SFTP 类中的一些挖掘,尤其是get() 函数,这就是我设法使用phpseclib 实现相同功能的方法

SFTP\Stream::register();
$sftpFileSystem = new SFTP($this->host);
if (!$sftpFileSystem->login($this->user, $this->password)) {
    throw new Exception("Error logging in to central logging system. Please check the local logs and email for details", 1);
}

$context = [
    'sftp' => [
        'sftp' => $sftpFileSystem
    ],
];

//some stuff to do with whether the file already exists or not
$remote_file = $sftpFileSystem->realpath('test.txt');

$sftpStream = fopen("sftp://.{$remote_file}", 'a+', null, stream_context_create($context));
if (!$sftpStream) {
    exit(1);
}

return new StreamHandler($sftpStream);

注意在对fopen() 的调用中sftp:// 后面的点(.)。浪费了我半个小时!

【讨论】:

  • 感谢@DazBaldwin 的回答。我刚刚发布了我最终用于我的小应用程序的内容。这个对我有用。我不确定我是否理解您回答中的所有内容,但它看起来像是我一直在使用的更复杂的版本。感谢您发布您的答案!
  • 感谢您的反馈。如果您特别希望我扩展任何内容,我很乐意编辑答案以涵盖它。不得不承认,虽然SFTP\Stream::register() 的调用实在是太奇怪了 =0]
【解决方案3】:

我在使用 fopen 时遇到了类似的问题。 Curl 对于这些目的很有用。

请检查以下基本示例函数(如果 url 是 https,请取消注释 CURLOPT_SSL_VERIFYPEER = FALSE 行)。

$url = '***THE URL***';
$result = get_web_page_by_curl($url);

if ($result['errno'] != 0) echo 'error: bad url, timeout, redirect loop ...';
if ($result['http_code'] != 200) echo 'error: no page, no permissions, no service ...';
else {
    $page = $result['content'];
    echo $page;
}

function get_web_page_by_curl($url) {
    $agent = "Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax)";

    $options = array(
        CURLOPT_RETURNTRANSFER => true,     // return web page
        CURLOPT_HEADER         => false,    // don't return headers
        CURLOPT_FOLLOWLOCATION => true,     // follow redirects
        CURLOPT_ENCODING       => "",       // handle all encodings
        CURLOPT_USERAGENT      => $agent,   // who am i
        CURLOPT_AUTOREFERER    => true,     // set referer on redirect
        CURLOPT_CONNECTTIMEOUT => 120,      // timeout on connect
        CURLOPT_TIMEOUT        => 120,      // timeout on response
        CURLOPT_MAXREDIRS      => 10,       // stop after 10 redirects
        //CURLOPT_SSL_VERIFYPEER => FALSE   // this line makes it work under https 
    );

    $ch = curl_init($url);
    curl_setopt_array($ch, $options);
    $content = curl_exec($ch);
    $err     = curl_errno($ch);
    $errmsg  = curl_error($ch);
    $header  = curl_getinfo($ch);
    curl_close($ch);

    $header['errno']   = $err;
    $header['errmsg']  = $errmsg;
    $header['content'] = $content;
    return $header;
}

【讨论】:

  • 感谢您的帮助。它对我不起作用(到目前为止)。我的服务器是否有可能不接受 http 或 https 协议。我该如何测试呢?我知道它使用端口 22 接受 SFTP(我必须使用我的用户名和密码才能做到这一点)。另外,如果有帮助,我正在尝试访问 Linux 服务器,而不是 Web 服务器(我认为这两件事是不同的,但我不确定)
  • 实际上网络服务器被配置为运行在 linux、unix、windows 或其他机器上。当您点击 url: http://abc.abc.abc 时,您正在尝试使用 http 协议访问网络服务器(可能在 linux 服务器中)。您是否检查过 curl 调用的调试信息?你能检查一下你的服务器是否启用了 curl 吗?您可以使用 phpinfo() 来实现。
  • 我运行了 phpinfo(),我看到 curl 已启用。但正如其他人在上述 cmets 中提到的那样,我认为我的问题之一是我的服务器不接受 http 协议。它似乎接受 SFTP。也许我可以使用 SFTP 以某种方式使其与 curl 一起工作。我会进一步调查。
  • 网址可以公开访问吗?当你在浏览器中点击 url 时你能得到页面吗?如果是,那么 curl 就足够了(您需要检查 curl 选项)。如果没有,并且内容位于 Linux 服务器上的安全位置,那么您可以考虑使用 ftp 或 sftp 连接。
  • 我的网址不可公开访问。我已经能够使用 phpseclib 获取我的文件(通过设置 @neubert 建议的 include_path。现在我可以下载我的文件。如果我不必下载它会更好(只需阅读它就像我以前用fopen() 会更好)但我现在可以忍受了。谢谢你的帮助。
猜你喜欢
  • 2012-08-06
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多