0

PHPSecLibのSFTP関数を使用して、FTPサーバーからファイルをダウンロードしています。

この線

$sftp->get($fname);

ファイルが最大200MBの場合は機能しますが、300MBの場合、ブラウザは「Firefoxは[download.php]でファイルを見つけることができません」と応答します。つまり、リモートファイルのダウンロードに使用するphpファイルが見つからないということです。

最初は、これはphp.iniの設定によるものだと思いましたがmemory_limit、128Mに設定されているか350Mに設定されているかは関係ありません。200MBのファイルは引き続き機能し、300MBのファイルは失敗します。そして、それは10秒後に失敗するのでmax_execution_timemax_input_time犯人ではないようです。何が間違っている可能性がありますか?

4

2 に答える 2

1

あなたができる他の何か...

<?php
include('Net/SFTP.php');

$sftp = new Net_SFTP('www.domain.tld');
$sftp->login('username', 'password');

$start = 0;
while (true) {
    $response = $sftp->get('1mb', false, $start, 1024);
    $start+= 1024;
    if (empty($response)) {
        break;
    }
    echo $response;
}

すなわち。ファイルを複数のチャンクでダウンロードします。

于 2013-03-24T23:15:00.603 に答える
1

まず、コードを php ファイルの一番上 (インクルードの前でも) に配置することを強くお勧めしますset_time_limit(0);。これは、どれだけの時間がかかるかわからない操作を扱っているためです。

これは、Webサーバー/ブラウザが「長い」期間にわたってデータを送受信しないことでタイムアウトになった場合だと思います. これを修正するには、SFTP.php ファイル、つまり Net_SFTP クラスを少し変更し、get メソッド (phpseclib 0.3.1 の場合は 1482 行目) に移動し、唯一の "while" 制御構造内に何かを追加する必要があります。そこに (関数全体を下に貼り付けます)、次のコードを追加します。

if (strtolower(PHP_SAPI) != 'cli') { // run this if request is handled by a webserver (like your case)
    $my_iter++;

    if($my_iter > 1024){
        $my_iter = 0; // reset the counter
        echo "transferring ... " . date("G:i:s") . "<br />"; // send something to the buffer
    }

    // flush the buffers and prevent the timeout by actually outputting something to the browser
    ob_end_flush();
    ob_flush();
    flush();
    ob_start();
    usleep(100); // just in case, try removing this delay
}

これは基本的に時々何かを出力し (この間の 1024 回の反復)、実際にブラウザーに何かを出力するためにバッファーをフラッシュします。値を自由に調整してください。これらの問題のため、これは Web サーバーから実行することを意図していないコード (SFTP クラス) です。つまり、できますが、このようないくつかの問題に遭遇します。

また、send() を試みる場合は、対応するメソッドで同様の変更を行う必要がありますが、これで問題が解決されることを願っています (少なくとも、これで私のローカル開発ボックスでのタイムアウトの問題が修正されました)。

ここで、約束どおり、メソッドの完全な変更を以下に示します ;-)

function get($remote_file, $local_file = false)
{
    if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
        return false;
    }

    $remote_file = $this->_realpath($remote_file);
    if ($remote_file === false) {
        return false;
    }

    $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
    if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
        return false;
    }

    $response = $this->_get_sftp_packet();
    switch ($this->packet_type) {
        case NET_SFTP_HANDLE:
            $handle = substr($response, 4);
            break;
        case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
            $this->_logError($response);
            return false;
        default:
            user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
            return false;
    }

    if ($local_file !== false) {
        $fp = fopen($local_file, 'wb');
        if (!$fp) {
            return false;
        }
    } else {
        $content = '';
    }

    $read = 0;
    while (true) {
        if (strtolower(PHP_SAPI) != 'cli') { // run this if request is handled by a webserver (like your case)
            $my_iter++;

            if($my_iter > 1024){
                $my_iter = 0; // reset the counter
                echo "transferring ... " . date("G:i:s") . "<br />"; // send something to the buffer
            }

            // flush the buffers and prevent the timeout by actually outputting something to the browser
            ob_end_flush();
            ob_flush();
            flush();
            ob_start();
            usleep(100); // just in case, try removing this delay
        }

        $packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20);
        if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
            if ($local_file !== false) {
                fclose($fp);
            }
            return false;
        }

        $response = $this->_get_sftp_packet();
        switch ($this->packet_type) {
            case NET_SFTP_DATA:
                $temp = substr($response, 4);
                $read+= strlen($temp);
                if ($local_file === false) {
                    $content.= $temp;
                } else {
                    fputs($fp, $temp);
                }
                break;
            case NET_SFTP_STATUS:
                $this->_logError($response);
                break 2;
            default:
                user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS', E_USER_NOTICE);
                if ($local_file !== false) {
                    fclose($fp);
                }
                return false;
        }
    }

    if ($local_file !== false) {
        fclose($fp);
    }

    if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
        return false;
    }

    $response = $this->_get_sftp_packet();
    if ($this->packet_type != NET_SFTP_STATUS) {
        user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
        return false;
    }

    $this->_logError($response);

    // check the status from the NET_SFTP_STATUS case in the above switch after the file has been closed
    if ($status != NET_SFTP_STATUS_OK) {
        return false;
    }

    if (isset($content)) {
        return $content;
    }

    return true;
}
于 2013-03-22T15:20:34.623 に答える