0

我正在开发一个网站,该网站将充当我家用机器的在线 SFTP 客户端。到目前为止,我的解决方案是一个包含站点 UI 的索引(主)php 文件,以及一个与 SFTP 连接管理器 phpseclib 连接的 SFTP PHP 便利类。

index.php

<?php
require_once "php/Membership.php";
require_once "php/ssh.php";
require_once "php/sftp.php";

$sftp = new SFTP();

error_reporting(E_ALL);  // will report any errors your code may have
ini_set("display_errors", 1);

?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!ATTLIST td fileName CDATA #IMPLIED>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>SFTP</title>
<link href="index.css" rel="stylesheet" type="text/css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="index.js"></script>
</head>

<body>
<h1 id="welcome">Welcome</h1>

<div id="container">
<div id="content">

<!--SFTP Files-->
<div style="height:1000px; overflow:auto;">
<?php $sftp->set_table(NULL, NULL);?>
</div>


</div>
</div>
</body>
</html>

SFTP.php

<?php

include('Net/SFTP.php');

class SFTP {

    private $sftp;

    function __construct() {

     $this->sftp = new Net_SFTP('99.99.9999.999');
     if (!$this->sftp->login('user', 'pwd')) {
         exit('Login Failed');
     }
        echo $this->sftp->pwd() . "\r\n";
    }

    function set_table($table, $directory) {
        if (isset($directory)) {
            $this->sftp->chdir($directory);
        }
        echo '<table id="sftpTable" style="border:1px solid;">';
        $result = $this->sftp->nlist();
        foreach ($result as $row) {
            if (substr($row, 0, 1) != '.') {
                echo "<tr>" . "<td class='columnSelect' id=" . $row . "><form method='post' action=''>" . $row . "<input type=\"hidden\" name=\"index\" value=\"" . $row . "\" /></form></td>";
                if (strpos($row,'.') !== false)
                    echo '<td>'. $this->parseBytes($this->sftp->_size($row)) . '</td></tr>';
            }   
        }
        echo '</table>';
    }

    function parseBytes($bytes) {
        if ($bytes / 1074000000 >= 1) {
            return $bytes / 1074000000 . 'GB';
        }
        if ($bytes / 1048576 >= 1) {
            return $bytes / 1048576 . 'MB';
        }
        if ($bytes / 1024 >= 1) {
            return $bytes / 1024 . 'KB';
        }
        return $bytes . 'B'; 
    }
}

?>

现在我面临的问题是似乎是循环逻辑之一。我最初的想法是建立一个以以下方式工作的系统:

  1. 建立到 SFTP 的单例连接
  2. 对该单例进行查询
  3. 在 UI 中显示结果

我计划显示一个表格,其中包含代表服务器目录中不同项目的可点击行。当用户单击其中一行时,我希望系统返回该目录的新项目列表并相应地更新 UI。为了做到这一点,我尝试向每个表格行添加一个隐藏字段来保存该单元格的列表名称。单击单元格时,我需要提取该隐藏字段的值并使用新目录重置表。然后出现了更换屏幕上的表格而不只是呼应新表格的问题。

因此,我的问题是:

存储与每个单元格相关的目录的最佳方法是什么,当单击该单元格时,SFTP 单例会根据新目录重置一个表?

请注意,上面的代码可能存在逻辑错误,对于新查看者来说可能没有什么意义,因为已经进行了许多不同的尝试。另外,需要明确的是,我正在寻找正确方向的方法论点,而不是为我编写代码的人。

提前致谢。

4

1 回答 1

1

In PHP, the singleton paradigm is considered "bad practice".请参阅参考:PHP 单例类的最佳实践

尽管您的 SFTP 类在上面的示例中似乎并未实际实现单例逻辑。

您的下一个挑战是,当您按原样调用网页时,将重新加载整个网页。如果没有某种服务器端缓存,您当前的架构就无法只更新页面的一部分。正如评论中提到的,AJAX 将成为您执行此操作的首选工具。

在 PHP 中浏览器对 Web 服务器的调用之间根本不存在单例。每次您的浏览器访问 Web 服务器时,它必然会创建一个新的 SFTP 连接。每次您的 Web 服务器完成请求时,它都会破坏它正在使用的 SFTP 连接。

您正在寻找的方法论指针:

  1. 在浏览器中有一个加载初始 UI 的页面(我们称之为视图)。您可能至少需要提供一些基本配置,您可能只需让它在第一次调用时加载 100%。
  2. 开发其他一些只提供数据的页面,最好是 json 格式。
  3. 在视图中有javascript(ajax),可以离散地调用服务器以获取数据(您的表)。
  4. 当您在页面周围单击时,ajax 会对正确的页面进行适当的离散调用以提供正确的数据,然后刷新/更新 UI 中的正确元素。

我个人是Memcached的粉丝,用于在服务器请求之间缓存会话数据。话虽如此,有大量缓存服务可用于在 Web 服务器上保存目录列表,直到需要从 SFTP 服务器刷新它。

当您研究针对您的挑战的最佳缓存解决方案时,有必要确保您了解操作码缓存(有许多可供使用的操作码缓存。您有APCXCacheeAcceleratorZend Platform。)和数据缓存( session, variable, userland - 我们推荐memcached)。

但是,如果您的数据足够大(> 1MB),您通常不希望将其缓存在 memcached 之类的任何东西中,您希望将其缓存到本地文件系统,这是我最近如何做到这一点的一个示例大阵列。

/**
 * Will serialize, then write the array to disk, returning the filePath
 * 
 * @param array $array
 * @param string $filePath
 * @return string
 */
function putCacheData(array $array, $filePath = NULL){
    if (empty($filePath)){
        $filePath = tempnam(NULL, 'IMPORT');
    }
    $serializedData = serialize($array);
    file_put_contents($filePath, $serializedData);
    return $filePath;
}

/**
 * Reads the file, unserializes the data, and returns the array.
 * 
 * @param string $filePath
 * @return Array|FALSE
 */
function getCacheData($filePath){
    $array = array();
    if (empty($filePath)){
        logmessage("The filepath: [$filepath] is empty!");
        return $array;
    }

    if (! is_file($filePath)){
        putImportData($array, $filePath);
        return $array;
    }

    return unserialize( file_get_contents( $filePath ) );   
}

然后我们只需将用户会话数据存储$filePath在用户会话数据中(为我们进入 memcached),当我引导每个请求时,我可以检查会话的路径,加载缓存的数据,确定它是否过期,并可选择刷新它。只需确保在活动请求结束之前将数据写入文件即可。

于 2013-10-24T02:59:45.930 回答