为什么此SFTP下载这么慢?

时间:2020-07-24 14:24:12

标签: javascript php laravel sftp

单击时,我有一个下载按钮,下载文件大约需要15秒钟,因为它必须通过SFTP进入服务器,找到正确的路径/文件,然后返回响应。

<a class="btn btn-primary btn-sm text-primary btn-download-1" onclick="startDownload('1')"><i class="fa fa-download "></i></a>

这是startDownload功能:

function startDownload(interfaceId) {
    window.location = "/nodes/interface/capture/download?port=" + interfaceId;
}

/nodes/interface/capture/download中的后端代码:

public function download_files()
{

    $dir = '';
    $portNumber = Request::get('port');
    $zipMe = false;

    $remotePath = "/home/john/logs/".$dir."/";

    if (!isset($dir) || $dir == null) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $acsIp =  explode('://', env('ACS_URL'));
    $acsIp =  explode(':',$acsIp[1])[0];
    $sftp = new SFTP($acsIp.':22');

    if (!$sftp->login('john', '***')) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    // Get into the Specified Directory
    $sftpConn = Storage::disk('sftp');

    $SFTPFiles = $sftpConn->allFiles('/'.$dir);

    if ( count($SFTPFiles) > 0 ) {
        foreach ($SFTPFiles as $file) {
            $fileName = $file;
            break;
        }

    } else {
        \Log::info('Files Not found in the Remote!');
        return redirect()->back()->withInput()->withFlashDanger('Files Not found in the Remote!');
    }

    // Create and give 777 permission to remote-files directory
    if (!is_dir(public_path('remote-files/'.$dir))) {
        mkdir(public_path('remote-files/'.$dir), 0777, true);
    }

    $filesToZip = [];

    foreach ( $SFTPFiles as $fileName ) {
        if ( $fileName == '..' || $fileName == '.' ) {
            continue;
        } else if ( $fileName == '' ) {
            \Log::info('File not found');
            continue;
        }

        $fileName     = explode("/", $fileName);
        $onlyFileName = (!empty($fileName) && isset($fileName[1])) ? $fileName[1] : "";
        $filepath = $remotePath.$onlyFileName;

        if (strpos($onlyFileName , $portNumber) !== false) {


            // Download the remote file at specified location in Local
            if (!$sftp->get($filepath, 'remote-files/'.$dir.'/'.$onlyFileName))
            {
                die("Error downloading file ".$filepath);
            }

            $file = public_path('remote-files/'.$dir.'/').$onlyFileName;

            $headers = array(
                'Content-Description: File Transfer',
                'Content-Type: application/octet-stream',
                'Content-Disposition: attachment; filename="'.basename($file).'"',
                'Cache-Control: must-revalidate',
                'Pragma: public',
                'Content-Length: ' . filesize($file)
            );

            return Response::download($file, $onlyFileName, $headers);
        }

        // IF File is exists in Directory
        if ( file_exists( public_path('remote-files/'.$dir.'/').$onlyFileName ) ) {
            $filesToZip[] = public_path('remote-files/'.$dir.'/').$onlyFileName;
            \Log::info('File Generated '.'remote-files/'.$dir.'/'.$onlyFileName);

            // Remove Files from public/remote-files
            $this->removeDirAndFiles('', public_path('remote-files/'.$dir));
            exit;

        } else {
            \Log::info('File not Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
        }
    }
}

此代码确实有效,但是耗时约15秒,对于用例而言太长了。

有没有办法加快速度?我的代码有什么问题吗?还是可以预期的?我应该考虑切换到SCP吗?我应该重新考虑身份验证吗?

2 个答案:

答案 0 :(得分:5)

我更改了功能,以测量各个部分的时间,因此您可以通过查看该字符串“ ### [TIME]-”

public function download_files()
{
    $start = time();
    $dir = '';
    $portNumber = Request::get('port');
    $zipMe = false;

    \Log::info("### [TIME] -- t1 =  " . (time() - $start));

    $remotePath = "/home/john/logs/".$dir."/";

    if (!isset($dir) || $dir == null) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $acsIp =  explode('://', env('ACS_URL'));
    $acsIp =  explode(':',$acsIp[1])[0];

    $t1 = time();

    $sftp = new SFTP($acsIp.':22');

    $t2 = time();
    \Log::info("### [TIME] -- SFTP Instantiation took " . ($t2 - $t1) . " secs");

    if (!$sftp->login('john', '***')) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $t1 = time();
    // Get into the Specified Directory
    $sftpConn = Storage::disk('sftp');

    $SFTPFiles = $sftpConn->allFiles('/'.$dir);

    $t2 = time();
    \Log::info("### [TIME] -- SFTPFiles list took " . ($t2 - $t1) . " secs");


    // this loop is not clear to me, you basically take the first element and
    // exit the loop
    if ( count($SFTPFiles) > 0 ) {
        foreach ($SFTPFiles as $file) {
            $fileName = $file;
            break;
        }
    } else {
        \Log::info('Files Not found in the Remote!');
        return redirect()->back()->withInput()->withFlashDanger('Files Not found in the Remote!');
}

    $t1 = time();

    // Create and give 777 permission to remote-files directory
    if (!is_dir(public_path('remote-files/'.$dir))) {
        mkdir(public_path('remote-files/'.$dir), 0777, true);
    }

    $t2 = time();
    \Log::info("### [TIME] -- Directory creation took " . ($t2 - $t1) . " secs");

    $filesToZip = [];
    $t1 = time();
    foreach ( $SFTPFiles as $fileName ) 
    {
        $start_loop_time = time();
        \Log::info("### [TIME] -- Loop for $fileName took " . (time() - $t1) . " secs");

        if ( $fileName == '..' || $fileName == '.' ) {
            continue;
        } else if ( $fileName == '' ) {
            \Log::info('File not found');
            continue;
        }

        $fileName     = explode("/", $fileName);
        $onlyFileName = (!empty($fileName) && isset($fileName[1])) ? $fileName[1] : "";
        $filepath = $remotePath.$onlyFileName;

        if (strpos($onlyFileName , $portNumber) !== false) {

             $responseCreationStart = time();
            // Download the remote file at specified location in Local
            if (!$sftp->get($filepath, 'remote-files/'.$dir.'/'.$onlyFileName))
            {
                die("Error downloading file ".$filepath);
            }

            $file = public_path('remote-files/'.$dir.'/').$onlyFileName;

            $headers = array(
                'Content-Description: File Transfer',
                'Content-Type: application/octet-stream',
                'Content-Disposition: attachment; filename="'.basename($file).'"',
                'Cache-Control: must-revalidate',
                'Pragma: public',
                'Content-Length: ' . filesize($file)
            );
            $responseCreationEnd = time();
            \Log::info("### [TIME] -- Response creation took " . ($responseCreationEnd  - $responseCreationStart ) . " secs");
            return Response::download($file, $onlyFileName, $headers);

        }

        // IF File is exists in Directory
        if ( file_exists( public_path('remote-files/'.$dir.'/').$onlyFileName ) ) {
            $t3 = time();
            $filesToZip[] = public_path('remote-files/'.$dir.'/').$onlyFileName;
            \Log::info('File Generated '.'remote-files/'.$dir.'/'.$onlyFileName);

            // Remove Files from public/remote-files
            $this->removeDirAndFiles('', public_path('remote-files/'.$dir));
            $t4 = time();
            \Log::info("### [TIME] -- Deletion took " . ($t4 - $t3) . " secs");
            exit;

        } else {
            \Log::info('File not Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
        }

        \Log::info("### [TIME] -- Loop end reached in  " . (time() - $start_loop_time ) . " secs");
    }
}

答案 1 :(得分:1)

您是否在代码中的任何地方设置了$dir变量?因为按照我的阅读方式,它的唯一内容是而且永远都是一个空字符串。

这在其他浏览器中也需要很长时间吗?按下按钮后,浏览器检查器的“网络”选项卡中是否弹出任何值得注意的东西?

此外,也许您可​​以尝试将函数放在按钮元素中而不是超链接中。
也许这种延迟是浏览器内部存在的某种超时,因为它期望加载另一个页面?

因此,建议您尝试一下该按钮,而不是使用该按钮的超链接:

<button class="btn btn-primary btn-sm text-primary btn-download-1" onclick="startDownload('1')"><i class="fa fa-download "></i></button>

我很好奇会发生什么。 让我们保持最新状态!