Тема: HTA JS: FTP-клиент пакетной загрузки/выгрузки файлов на хостинг(Ncftp)
HTA Javascript, Ncftp: FTP-клиент загрузки/выгрузки файлов на хостинг
Дано: Есть сайт на Joomla с установленным компонентом просмотра прайс-листов в формате Excel.
Задача: Обновлять прайсы на сайте, не залезая в админку, и не устанавливая громоздких FTP-клиентов. Технически, проблема сводится к регулярной выгрузке с сайта по протоколу FTP определенного списка файлов, и его последующей загрузке на сайт.
Решение: Использовать консольные (portable) FTP-клиенты и простой графический интерфейс, сделанный на HTA
Изучение проблемы показало, что встроенный ftp-клиент Windows обладает ограниченной функциональностью (не поддерживается пассивный режим, т.е. не работает из-за NAT). Поэтому следует использовать сторонние FTP-клиенты.
Спасибо http://shlykov.info/10/, за качественный обзор консольных клиентов. Из предложенного списка консольных клиентов остановился на Ncftp.
Финальная разработка представляет собой следующие файлы:
ncftpput.exe, ncftpget.exe - консольные FTP-клиенты загрузки/выгрузки файлов по FTP. Взято с http://www.ncftp.com/ncftp/. Там же инструкция по параметрам командной строки.
simpleftp.hta - HTA-приложение: окном выбора локальной папки, и две кнопки Загрузить и Выгрузить, выполняющие пакетную загрузку/выгрузку файлов на FTP-сервер
Параметры соединения с FTP-сервером и список файлов "зашиты" в HTA-коде. Исправляйте соответственно Вашим требованиям.
Приложение задумано для простых офис-менеджеров (чем меньше кнопок и настроек, тем лучше).
В принципе, этот пример можно развить в полноценный FTP-клиент на HTA. Хорошая задача для кодеров-маньяков...:D
simpleftp.hta
<html>
<head>
<title>Обновление прайс-листов сайта http://MySite.ru</title>
<hta:application
applicationName="Обновление прайс-листов сайта http://MySite.ru"
border="dialog"
borderStyle="static"
caption="yes"
contextMenu="no"
icon=""
id="hta"
innerBorder="no"
maximizeButton="no"
minimizeButton="no"
navigable="yes"
scroll="no"
selection="no"
showInTaskBar="yes"
singleInstance="yes"
sysMenu="yes"
version="0.1" />
<style>
body, table { padding: 0px; margin: 0px; background-color: #F5F5F5; color: #000175; font-family: Tahoma; font-size: 12px;}
fieldset {padding: 0px; margin: 7px 5px 5px 5px;}
legend { font-weight: bold; font-style: oblique; font-family: Georgia; padding: 0px 2px;}
div.app { width: 100%; height: 100%; padding: 0px; margin: 0px; }
div.info { background-color: #CCCCCC; padding: 10px 5px 10px 10px; margin: 0px; font-size: 18pt; font-family: Georgia; cursor: pointer; color: White; border-bottom: 1px solid White; border-top: 1px solid White;}
div.menu { background-color: #EEEEEE; padding: 7px 0px 7px 15px; margin: 0px; border-bottom: 1px solid White; font-family: Georgia; font-weight: bold; font-size: 14px;}
div.body { display: none; margin: 0px; padding: 0px 5px;}
div.log { padding: 5px 5px 7px 5px; margin: 0px; height: 170px; overflow: auto;}
div.file { padding: 5px 5px 7px 5px; margin: 0px;}
div.settings { padding: 5px 5px 7px 5px; margin: 0px; height: 250px;}
div.cb {cursor: pointer; border: 1px solid #F5F5F5;}
span.menu { cursor: pointer; padding: 0px 3px;}
span.space {margin-right: 15px;}
button, {background: #EEEEEE; border: 1px solid #CCCCCC; margin: 1px;}
button.menu { cursor: pointer; background-color: #EEEEEE; margin: 0px; padding: 0px; border: none; color: #000175; font-family: Georgia; font-weight: bold; font-size: 14px;}
input { border: 1px solid #DFDFDF; margin: 0px; height: 1.6em;}
input.button {background: #EEEEEE; border: 1px solid #CCCCCC;}
input.checkbox {cursor: pointer; border: none; margin: 0px; padding: 0px;}
</style>
<script type="text/javascript">
var windowWidth = 360;
var windowHeight = 437;
window.resizeTo(windowWidth,windowHeight);
var x = (window.screen.availWidth - windowWidth)/2;
var y = (window.screen.availHeight - windowHeight)/2;
window.moveTo(x,y);
window.onload = function(){
showFiles();
checkJScript();
if(!dirButton.getAttribute("disabled"))dirButton.focus();
writeLog(new Array("версия: " + hta.version));
}
function showFiles(){config.style.display="none";info.style.display="none";files.style.display="block";}
function showConfig(){info.style.display="none";files.style.display="none";config.style.display="block";}
function showInfo(){config.style.display="none";files.style.display="none";info.style.display="block";}
function mouseOver(item){item.style.background="#EEEEEE";item.style.border="1px solid #CCCCCC";}
function mouseOut(item){item.style.background="#F5F5F5";item.style.border="1px solid #F5F5F5";}
// variables
var settings = new Array(3);
var oShell = new ActiveXObject("Wscript.Shell");
var shell = new ActiveXObject("Shell.Application");
var fso = new ActiveXObject("Scripting.FileSystemObject");
var word = null;
var dir = null;
// тут зашиты параметры соединения с FTP и пути к каталогу загрузки-выгрузки на сервере
// меняйте соответственно вашим требованиям
// <PathToFile><PathToDir><FileName> - макроподстановки, для имен файлов и пути к локальному каталогу, используются в алгоритме
var DownloadCommand = "ncftpget -u ftp_user -p ftp_password -P 21 mysite.ru <PathToDir> /www/mysite.ru/components/com_excel/prices/<FileName>" ;
var UploadCommand = "ncftpput -u ftp_user -p ftp_password -P 21 mysite.ru /www/mysite.ru/components/com_excel/prices/ <PathToFile>" ;
//список файлов с прайс-листами
//в цикле по списку выполняется макроподстановка вместо <FileName>
//измените на Ваш список
var xlsFileCount = 20;
var xlsFileArray = new Array(
"1051874570-4.xls",
"1092812908-5.xls",
"1136255424-4.xls",
"1238705087-4.xls",
"1375786074-5.xls",
"1754316211-3.xls",
"1782502850-3.xls",
"2722188756-5.xls",
"2801637963-4.xls",
"2911438163-3.xls",
"3053163155-5.xls",
"3249793829-5.xls",
"3486591861-5.xls",
"3822741412-5.xls",
"3905233543-4.xls",
"4068742619-4.xls",
"4082181836-3.xls",
"451263677-1.xls",
"649715513-4.xls",
"670720701-3.xls"
)
// message box settings
var mbIndex = 1;
var msgBoxPathStr = "Папка загрузки/выгрузки:";
var msgselectDirNoExists = "Папка не найдена. Введите путь к существующей папке! ";
var msgselectDirStr = "Выберите папку с файлами!";
var msgDownloadFileOK = "Прайс-лист загружен с веб-сайта:";
var msgDownloadFilesOK = "Все прайс-листы загружены с веб-сайта в каталог:";
var msgUploadFileOK = "Прайс-лист выгружен на веб-сайт:";
var msgUploadFilesOK = "Все прайс-листы из каталога выгружены на веб-сайт:";
var msgErrorStr = "Ошибка:";
function disableInputs(){
path.setAttribute('disabled', true);
dirButton.setAttribute('disabled', true);
DownloadButton.setAttribute('disabled', true);
UploadButton.setAttribute('disabled', true);
}
function enableInputs(){
path.setAttribute('disabled', false);
dirButton.setAttribute('disabled', false);
DownloadButton.setAttribute('disabled', false);
UploadButton.setAttribute('disabled', false);
}
function isInputsEnabled(){
return !dirButton.getAttribute("disabled") && !DownloadButton.getAttribute("disabled")&& !UploadButton.getAttribute("disabled");
}
function checkJScript(){
try{
if(ScriptEngineMajorVersion() < 5){
disableInputs();
throw new Error("Старая версия JScript;Необходимо: "+ ScriptEngine() + " 5.6;Установленно: " + ScriptEngine() + " " + ScriptEngineMajorVersion() + "." + ScriptEngineMinorVersion() + "." + ScriptEngineBuildVersion());
}
} catch(ex) {
printError(ex);
}
}
function printMsg(div){
var div = document.getElementById("log");
div.appendChild(div);
}
function printError(exception){
var error = new Array(exception.name + " (" + (exception.number & 0xFFFF) + "):");
var disc = exception.description.split(";");
for(var i=0;i<disc.length;i++){
error.push(disc[i]);
}
writeLog(error, true);
}
function PathChanged(){
try {
path.value = path.value.replace('"','');
path.value = path.value.replace('"','');
path.value = fso.GetAbsolutePathName(path.value);
if(fso.FolderExists(path.value)){
dir = path.value;
writeLog(new Array(msgBoxPathStr, dir), false);
DownloadButton.setAttribute('disabled', false);
DownloadButton.focus();
UploadButton.setAttribute('disabled', false);
}else{
dir = path.value;
writeLog(new Array(msgselectDirNoExists, dir), true);
DownloadButton.setAttribute('disabled', true);
UploadButton.setAttribute('disabled', true);
}
} catch (ex) {
printError(ex);
}
}
function selectDir(){
try {
var folder = shell.BrowseForFolder(0, msgselectDirStr, 16, 0);
if (folder != null) {
dir = folder.Self.Path;
path.value = folder.Self.Path;
writeLog(new Array(msgBoxPathStr, dir), false);
DownloadButton.setAttribute('disabled', false);
DownloadButton.focus();
UploadButton.setAttribute('disabled', false);
}
} catch (ex) {
printError(ex);
}
}
function writeLog(msg, error){
var div = document.createElement("div");
if(error){
div.style.background = "#FFE8E1";
} else {
div.style.background = "#ECF0EE";
}
div.style.padding = "2px 2px 2px 2px";
div.style.margin = "2px 0px 2px 0px";
var node = document.createTextNode("[" + mbIndex++ + "] ");
div.appendChild(node);
for(var i=0; i<msg.length; i++){
if(msg[i]!=null){
node = document.createTextNode(msg[i]);
div.appendChild(node);
node = document.createElement("br");
div.appendChild(node);
}
}
var log = document.getElementById("log");
if(log.childNodes.length > 0){
log.insertBefore(div, log.childNodes[0]);
} else {
log.appendChild(div);
}
}
function DownloadPrices(){
try {
disableInputs();
if(dir == null || dir == ""){
throw new Error(msgselectDirStr);
}
for(i=0;i<xlsFileCount;i++){
sCommandLine = "\""+dir+"\"";
sCommandLine = DownloadCommand.replace("<PathToDir>",sCommandLine);
sCommandLine = sCommandLine.replace("<FileName>",xlsFileArray[i]);
if(sCommandLine.length > 0){oShell.Run(sCommandLine,7,true);};
writeLog(new Array(msgDownloadFileOK, xlsFileArray[i]), true);
}
if(sCommandLine.length > 0){oShell.Run(sCommandLine,7,true); };
writeLog(new Array(msgDownloadFilesOK, dir), false);
} catch (ex) {
printError(ex);
} finally {
dir = "";
path.value = "";
disableInputs();
path.setAttribute('disabled', false);
dirButton.setAttribute('disabled', false);
}
}
function UploadPrices(){
try {
disableInputs();
if(dir == null || dir == ""){
throw new Error(msgselectDirStr);
}
for(i=0;i<xlsFileCount;i++){
sCommandLine ="";
sCommandLine = sCommandLine + dir +"\\"+xlsFileArray[i];//"test.test";
if(fso.FileExists(sCommandLine)){
sCommandLine = "\""+sCommandLine+"\"";
sCommandLine = UploadCommand.replace("<PathToFile>",sCommandLine);
if(sCommandLine.length > 0){oShell.Run(sCommandLine,7,true);};
writeLog(new Array(msgUploadFileOK, xlsFileArray[i]), true);
}
}
} catch (ex) {
printError(ex);
} finally {
writeLog(new Array(msgUploadFilesOK, dir), false);
dir = "";
path.value = "";
disableInputs();
path.setAttribute('disabled', false);
dirButton.setAttribute('disabled', false);
}
}
</script>
</head>
<body>
<div class="info">Обновление прайс-листов сайта http://MySite.ru</div>
<div style="padding: 5px"><button style="width:100%;" onclick="DownloadPrices()" id="DownloadButton" disabled="disabled" title="">Загрузить прайсы с веб-сервера</button></div>
<fieldset>
<legend>Папка</legend>
<div class="file">
<input type="text" id="path" style="width:90%;border-right:0px;" onchange="PathChanged();">
<input type="button" value=" » " onclick="selectDir();" id="dirButton" class="button" title="">
</div>
</fieldset>
<div style="padding: 5px"><button style="width:100%;" onclick="UploadPrices()" id="UploadButton" disabled="disabled" title="">Выгрузить прайсы на веб-сервер</button></div>
<fieldset>
<legend>Журнал</legend>
<div class="log" id="log"></div>
</fieldset>
</div>
<div id="files" class="body"></div>
<div id="config" class="body"></div>
<div id="info" class="body"></div>
</body>
</html>Это мое первое HTA-приложение. Спасибо авторам doc2fb.hta за код, использовавший в качестве образца.

