<i id='VthkS'><tr id='VthkS'><dt id='VthkS'><q id='VthkS'><span id='VthkS'><b id='VthkS'><form id='VthkS'><ins id='VthkS'></ins><ul id='VthkS'></ul><sub id='VthkS'></sub></form><legend id='VthkS'></legend><bdo id='VthkS'><pre id='VthkS'><center id='VthkS'></center></pre></bdo></b><th id='VthkS'></th></span></q></dt></tr></i><div id='VthkS'><tfoot id='VthkS'></tfoot><dl id='VthkS'><fieldset id='VthkS'></fieldset></dl></div>

    <small id='VthkS'></small><noframes id='VthkS'>

    1. <tfoot id='VthkS'></tfoot>
      <legend id='VthkS'><style id='VthkS'><dir id='VthkS'><q id='VthkS'></q></dir></style></legend>
      • <bdo id='VthkS'></bdo><ul id='VthkS'></ul>

      流 FTP 下载到输出

      时间:2023-10-31
      <tfoot id='lKmNy'></tfoot>
          <tbody id='lKmNy'></tbody>
          <bdo id='lKmNy'></bdo><ul id='lKmNy'></ul>
              <i id='lKmNy'><tr id='lKmNy'><dt id='lKmNy'><q id='lKmNy'><span id='lKmNy'><b id='lKmNy'><form id='lKmNy'><ins id='lKmNy'></ins><ul id='lKmNy'></ul><sub id='lKmNy'></sub></form><legend id='lKmNy'></legend><bdo id='lKmNy'><pre id='lKmNy'><center id='lKmNy'></center></pre></bdo></b><th id='lKmNy'></th></span></q></dt></tr></i><div id='lKmNy'><tfoot id='lKmNy'></tfoot><dl id='lKmNy'><fieldset id='lKmNy'></fieldset></dl></div>

              1. <legend id='lKmNy'><style id='lKmNy'><dir id='lKmNy'><q id='lKmNy'></q></dir></style></legend>

                <small id='lKmNy'></small><noframes id='lKmNy'>

              2. 本文介绍了流 FTP 下载到输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

                问题描述

                我正在尝试通过 HTTP 从 FTP 将文件流式传输/管道传输到用户的浏览器.也就是说,我正在尝试在 FTP 服务器上打印文件的内容.

                I am trying to stream/pipe a file to the user's browser through HTTP from FTP. That is, I am trying to print the contents of a file on an FTP server.

                这是我目前所拥有的:

                public function echo_contents() {                    
                    $file = fopen('php://output', 'w+');             
                
                    if(!$file) {                                     
                        throw new Exception('Unable to open output');
                    }                                                
                
                    try {                                            
                        $this->ftp->get($this->path, $file);         
                    } catch(Exception $e) {                          
                        fclose($file);  // wtb finally               
                
                        throw $e;                                    
                    }                                                
                
                    fclose($file);                                   
                }                                                    
                

                $this->ftp->get 看起来像这样:

                public function get($path, $stream) {
                    ftp_fget($this->ftp, $stream, $path, FTP_BINARY);  // Line 200
                }
                

                使用这种方法,我只能将小文件发送到用户的浏览器.对于较大的文件,不会打印任何内容,并且出现致命错误(可从 Apache 日志中读取):

                With this approach, I am only able to send small files to the user's browser. For larger files, nothing gets printed and I get a fatal error (readable from Apache logs):

                PHP 致命错误:第 200 行/xxx/ftpconnection.php 中允许的内存大小为 16777216 字节已用尽(尝试分配 15994881 字节)

                PHP Fatal error: Allowed memory size of 16777216 bytes exhausted (tried to allocate 15994881 bytes) in /xxx/ftpconnection.php on line 200

                我尝试用 php://stdout 替换 php://output 没有成功(似乎没有任何东西发送到浏览器).

                I tried replacing php://output with php://stdout without success (nothing seems to be sent to the browser).

                如何在将数据发送到浏览器的同时有效地从 FTP 下载?

                How can I efficiently download from FTP while sending that data to the browser at the same time?

                注意:我不想使用 file_get_contents('ftp://user:pass@host:port/path/to/file'); 或类似的.

                Note: I would not like to use file_get_contents('ftp://user:pass@host:port/path/to/file'); or similar.

                推荐答案

                找到了解决方案!

                创建一个套接字对(匿名管道?).使用非阻塞ftp_nb_fget函数写入管道的一端,echo管道的另一端.

                Create a socket pair (anonymous pipe?). Use the non-blocking ftp_nb_fget function to write to one end of the pipe, and echo the other end of the pipe.

                测试为快速(在 100Mbps 连接上轻松达到 10MB/s),因此没有太多 I/O 开销.

                Tested to be fast (easily 10MB/s on a 100Mbps connection) so there's not much I/O overhead.

                请务必清除所有输出缓冲区.框架通常会缓冲您的输出.

                public function echo_contents() {
                    /* FTP writes to [0].  Data passed through from [1]. */
                    $sockets = stream_socket_pair(STREAM_PF_UNIX, STREAM_SOCK_STREAM, STREAM_IPPROTO_IP);
                
                    if($sockets === FALSE) {
                        throw new Exception('Unable to create socket pair');
                    }
                
                    stream_set_write_buffer($sockets[0], 0);
                    stream_set_timeout($sockets[1], 0);
                
                    try {
                        // $this->ftp is an FtpConnection
                        $get = $this->ftp->get_non_blocking($this->path, $sockets[0]);
                
                        while(!$get->is_finished()) {
                            $contents = stream_get_contents($sockets[1]);
                
                            if($contents !== false) {
                                echo $contents;
                                flush();
                            }
                
                            $get->resume();
                        }
                
                        $contents = stream_get_contents($sockets[1]);
                
                        if($contents !== false) {
                            echo $contents;
                            flush();
                        }
                    } catch(Exception $e) {
                        fclose($sockets[0]);    // wtb finally
                        fclose($sockets[1]);
                
                        throw $e;
                    }
                
                    fclose($sockets[0]);
                    fclose($sockets[1]);
                }
                
                // class FtpConnection
                public function get_non_blocking($path, $stream) {
                    // $this->ftp is the FTP resource returned by ftp_connect
                    return new FtpNonBlockingRequest($this->ftp, $path, $stream);
                }
                
                /* TODO Error handling. */
                class FtpNonBlockingRequest {
                    protected $ftp = NULL;
                    protected $status = NULL;
                
                    public function __construct($ftp, $path, $stream) {
                        $this->ftp = $ftp;
                
                        $this->status = ftp_nb_fget($this->ftp, $stream, $path, FTP_BINARY);
                    }
                
                    public function is_finished() {
                        return $this->status !== FTP_MOREDATA;
                    }
                
                    public function resume() {
                        if($this->is_finished()) {
                            throw BadMethodCallException('Cannot continue download; already finished');
                        }
                
                        $this->status = ftp_nb_continue($this->ftp);
                    }
                }
                

                这篇关于流 FTP 下载到输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

                上一篇:使用 PHP 通过 FTP 下载文件夹 下一篇:如何从 Laravel 的表中获取所有行(也软删除)?

                相关文章

              3. <legend id='5wAxU'><style id='5wAxU'><dir id='5wAxU'><q id='5wAxU'></q></dir></style></legend>
                  • <bdo id='5wAxU'></bdo><ul id='5wAxU'></ul>

                  <small id='5wAxU'></small><noframes id='5wAxU'>

                  <tfoot id='5wAxU'></tfoot>
                  <i id='5wAxU'><tr id='5wAxU'><dt id='5wAxU'><q id='5wAxU'><span id='5wAxU'><b id='5wAxU'><form id='5wAxU'><ins id='5wAxU'></ins><ul id='5wAxU'></ul><sub id='5wAxU'></sub></form><legend id='5wAxU'></legend><bdo id='5wAxU'><pre id='5wAxU'><center id='5wAxU'></center></pre></bdo></b><th id='5wAxU'></th></span></q></dt></tr></i><div id='5wAxU'><tfoot id='5wAxU'></tfoot><dl id='5wAxU'><fieldset id='5wAxU'></fieldset></dl></div>