Вывод результатов по мере выполнения PHP... Как: ajax, qjuery, flush?
В свободное время учусь web-программированию методом "реализации пришедших_в_голову идей"
И вот у меня задача: есть php скрипт, в стиле
ob_start();
for($i=1;$i<=15;$i++)
{
$T_SOCK=@fsockopen($T_HOST,$PORTS[$i],$err1,$err2,3);
if($T_SOCK)
{
echo "<br>Открыт:",$PORTS[$i];
fclose($T_SOCK);
}
else {echo "<br>Закрыт:",$PORTS[$i];}
flush(); ob_flush();
}
ob_end();
}...
И я захотел чтобы результат выводился постепенно, по мере проверки конкретного порта.
Гугл рассказал мне про flush(), ob_flush() и прочее подобное. Но тут проблемы: При тестировании, в некоторых браузерах (chrome, IE) оказалось что для начала буфер требуется забить миниму 256 символами. :(
Эксперимент с php.ini (output_buffering и implicit_flush) ничего не дал. [COLOR="DimGray"](Возможно браузеры игнорируют эти настройки? Тестировал на последнем денвере..)[/COLOR]
Ладно, думаю, черт с ним - сначала выпустил ~300 пробелов. Везде заработало (кроме сафари,[COLOR="DimGray"] вроде как должна быть кроссбраузерность?))[/COLOR] ), но результат выводится рывками, то по 1 строке? нормально, то сразу охапками по 2-3.
Переставлял flush'ы и так и сяк. Много уже попробовал.
Думается можно решить по другому задачу.
Прочитал про ajax, jquery. Попытка что-то найти в сети привела к тоннам мануалов, документаций, по безпредметной теме, хотя я искал всего-лишь пример или решение того, как сделать "порезультатный" вывод.
В общем ищу советов, идей, подсказок, с учетом моих новичковых знаний
Спасибо
пхп-скрипт будет тестировать только один порт, какой ему укажется в запросе.
А вот уже ЖС, будет перебирать порты и слать запросы для чека каждого.
Имхо это не ефетивно.
Также можешь покопать в сторону Comet
А по-поводу ЖС, я так понял можно будет достичь многопоточности?
Вот накидал пример на скорую руку. Использую Prototype, а не jquery, хотя мождно и чистом ЖС сделать не приниципиально.
Гланвое понять идею, а уже пото модифицировать под свои требвоания.
[highlight=javascript]
for(i=0; i<100; i++)
{
new Ajax.Request('/getPortStatus?port='+i,{
method:get,
onSuccess: function(transport) { $('port-'+i).update(transport.responseText); }
})
}
[/highlight]
[highlight=php]
$i=$_GET['port'];
$T_SOCK=@fsockopen($T_HOST,$PORTS[$i],$err1,$err2,3);
if($T_SOCK)
{
echo "<br>Открыт:",$PORTS[$i];
fclose($T_SOCK);
}
else {echo "<br>Закрыт:",$PORTS[$i];}
[/highlight]
[COLOR="Silver"]P.S. Сам пример может и не совсем рабочий, накидывал сразу на форум.. мож де и ошибся в чем..[/COLOR]
Принцип, на котором вообще, как я понимаю, может работать такая реализация:
- В теле страницы есть некий js код
- Он отправляет по одному проверочному запросу php скрипту
- При этом, js код, не перезагружая страницу, тут же возвращает результат
Суть верна?
Сделать по подобному хочу
Ещё такой вопрос, если я js циклом без задержек скармливаю скрипту массив, следовательно это всё сразу и обрабатывается. Может нужна пауза?
И возможна ли защита от подделки get запроса? Я о том, что js лежит в теле страницы, передавать ею порт опасно - не сложно написать парсер, отправляющий свои любые порты. Может в php сразу поместить массив портов, в js будет просто передавать индекс.. Либо контролировать на уровне скрипта php поступаемые порты
[COLOR="DimGray"](Это наверно уже просто размышления вслух)[/COLOR]
Принцип, на котором вообще, как я понимаю, может работать такая реализация:
- В теле страницы есть некий js код
- Он отправляет по одному проверочному запросу php скрипту
- При этом, js код, не перезагружая страницу, тут же возвращает результат
Суть верна?
Абсолютно
интерестно.. а в ИЕ оно нормально работает? У мну ИЕ нету, проверить не могу..
Ещё такой вопрос, если я js циклом без задержек скармливаю скрипту массив, следовательно это всё сразу и обрабатывается. Может нужна пауза?
Думаю да. задержка будет полезной. Но это все зависит от нагрузок что сервак выдерживает, кол-во одновременных юзеров на сайте...
Как вариант разбивать диапазоны на группы, и делать след запрос только после получения ответа.
т.е. в моем примере, следуйщий порт запрашивать уже в методе onSuccess
И возможна ли защита от подделки get запроса? Я о том, что js лежит в теле страницы, передавать ею порт опасно - не сложно написать парсер, отправляющий свои любые порты. Может в php сразу поместить массив портов, в js будет просто передавать индекс.. Либо контролировать на уровне скрипта php поступаемые порты
[COLOR="DimGray"](Это наверно уже просто размышления вслух)[/COLOR]
Ничего не возможного нету. то что пришло на ум первым. это ставить куку юзерю и при каждом запросе проверять ее правильность, значение которое будет в куке как-то генерить..
Или просто в качестве параметра передавать некий ключь, который тоже будет каждому юзеру выдаваться, по какому-то алгоритму.
На ЖС и прототайпах - можно конечно, но как по мне, это увеличит время выполнения...
Попробуйте flush();
echo $i.'<br/>';
flush();
sleep(1);
}
У меня сей код выводит информацию сразу после эхи, а не пока пройдет 15 циклов... Может и вам пригодится.. буферизирование, мне кажется, здесь ни к чему...
И еще... проверьте у себя max_execution_time кажется так параметр называется.... обычно максимальное время выполнения 30 секунд... Вряд ли этого хватит на все порты... так что измените это значение в большую сторону... если можете...
Извините, если неправильно понял задячу.
upd.1
Вижу, flush вы попробовали... только не знаю, зачем ob_start() и т.д...
upd.2
Проверил в хроме.. действительно лажа... :( А в ФФ нормально... тогда наверное, аяксом...
upd.3
Попробуйте как здесь: _http://mr-faster.com/long-time-job.html
Может изменение буфера в 0 байт поможет...
1) клиент может отвалиться по таймауту подключения
2) система может прибить длительный запрос
3) можно уложить DDoS-ом Web-сервер.
Я бы для длительных задач изготавливал отдельный демон. Постановка задачи демону - запись в специальную таблицу в БД. В этой же таблице можно организовать хранение прогресса выполнения задачи а также её состояение, в случае если работу демона решили прервать, а какую-то задачу он не выполнил.
Да, даже в ie работает.
[QUOTE="Kesano"]Попробуйте flush();[/QUOTE]
Это был бы самый короткий и верный способ.
Но вот Ваш пример
А вот пример со сканером
Его код:
$T_HOST = $_SERVER['REMOTE_ADDR'];
echo $T_HOST;
$PORTS=array(1=>21,2=>23,3=>25,4=>53,5=>80,6=>110,7=>139,8=>8000,
9=>8080,10=>3128,11=>3389,12=>6588,13=>1080,14=>5900,15=>8888);
for($i=1;$i<=15;$i++)
{
$T_SOCK=@fsockopen($T_HOST,$PORTS[$i],$err1,$err2,3);
if($T_SOCK)
{
echo "<br>Открыт:",$PORTS[$i];
fclose($T_SOCK);
}
else {echo "<br>Закрыт:",$PORTS[$i];}
flush();
sleep(1);
}
?>
У меня (Chrome) нормально не работает ни первый, ни второй.
Я понимаю это потому, что буфер для вывода не накопил минимального кол-ва информации для выводы.
Если дома, на денвере я могу поэкспериментировать с конфигами, то к сожалению у хостера не могу.[COLOR="Silver"] Мне предоставлен только ftp доступ[/COLOR]
Поэтому видимо, от простой идеи с flush стоит отказать теперь уже?
Kesano, пока писал сообщение, вы уже обновили своё)
hardcase, роль Бд может выполнить файл, а демон следит за его изменением. Или я не так всё понял?
1) клиент может отвалиться по таймауту подключения
А если указаны четки временные рамки на каждую операцию, и они около 3-4 сек.
Т.е. это время на каждую проверку порта, слишком большой тайм-аут вроде не должен быть
Все зависит от интенсивности запросов и сложности операций, которые там выполняются.
hardcase, роль Бд может выполнить файл, а демон следит за его изменением. Или я не так всё понял?
А как вы себе представляете разруливание параллельного доступа на запись? ;) Файл может выступать в роли БД только в режиме чтения.
Да, как-то не подумал. :)
Пока, честно говоря, на основе моего опыта я могу попробовать через прототайп. Остальное понятно в теории, но не в прямой реализации
С таким же успехом можно и на Сервелате сделать. ;)
В ближайшее время попробую сделать на js (prototype, jquery).
[COLOR="Gray"]Если будут вопросы, Я апну их в этой темке, Вы не против?)[/COLOR]
Взял за основу код Lone Wolf, мало пока его понимаю, но сделал так:
Файл index.php
<body>
<div id="port-1">...</div>
<div id="port-80">...</div>
<div id="port-139">...</div>
<div id="port-3389">...</div>
<script language="javascript" type="text/javascript">
for(i=0; i<4; i++)
{
new Ajax.Request('/portcheck.php?ind='+i,{
method:get,
onSuccess: function(transport) { $('port-'+i).update(transport.responseText); }
});
}
</script>
</body>
</html>
Запрос идет сюда. Файл portcheck.php
$ports=array(1,80,139,3389);
$i=$_GET['ind'];
$T_SOCK=@fsockopen($T_HOST,$ports[$i],$err1,$err2,3);
if($T_SOCK)
{
echo "<br>Открыт:",$ports[$i];
fclose($T_SOCK);
}
else {echo "<br>Закрыт:",$ports[$i];}
return $T_SOCK;
?>
Отдельно GET запрос на скрипт идет, и нормально возвращает echo...
Теоретически прикидываю что надо доработать где-то после onSuccess
...
Заработало, когда сделал вот так:
{
document.write(i);
new Ajax.Request('/portcheck.php?ind='+i,
{
method:'get',
onSuccess: function(transport){
var response = transport.responseText || "no response text";
alert("Success! \n\n" + response);
},
onFailure: function(){ alert('Something went wrong...') }
});
}
...
Осталось поиграться вот с этой ф-ией
Ну вот, окончательно заработало если делать вот так:
:)
[HTML]<html>
<head>
<script src="prototype.js" type="text/javascript">
</script>
</head>
<body>
<div id="port-0">...</div>
<div id="port-1">...</div>
<div id="port-2">...</div>
<div id="port-3">...</div>
<script language="javascript" type="text/javascript">
for(i=0;i<4;i++)
{
new Ajax.Updater($('port-'+i), '/portcheck.php?ind='+i, { method: 'get' });
}
</script>
</body>
</html>[/HTML]
Только вот тут конечно и мультипоточно, это круто. Но открытые порты обновляются быстрее чем закрытые (т. к. они там-аута ждут)
Думаю с апдейтером очерёдность вывода не выполнить?
Решил приступить к старой задачи (описанной тут).
Столкнулся с трудностью. Казалось мультипоточность это хорошо.. ан нет ):
prototype скрипт отправляет php запросы подряд, но php обрабатывает их все с разными кол-вом времени (от 0 до 3 секунд). Результат приходит ассинхронно и беспорядком.
Как я могу отправлять запросы по очереди? Как контролировать выполнение и возврат предыдущего?
Вот какие наброски
{
var i=0;
while(i<8)
{
new Ajax.Request('portcheck.php?ind='+i,
{
method:'get',
onSuccess: function(transport)
{
var response = transport.responseText || "Error";
col_full.insert(response);
},
});
i++;
}
}
/* и такой вариант */
function fullchk2()
{
var i=0;
while(i<8)
{
tmp=new Ajax.Updater($('col_full'), 'portcheck.php?ind='+i, {
method: 'get',
insertion: 'bottom'
});
i++;
}
}
Мне надо сделать запросы последовательно, только после того, как предыдущий обновил страницу
$ss = str_repeat(" ", 1024); // заполнить начальный буфер вывода! (1кБайт)
echo $ss."<pre/>";
$T_HOST = $_SERVER['REMOTE_ADDR'];
echo $T_HOST;
$PORTS=array(1=>21,2=>23,3=>25,4=>53,5=>80,6=>110,7=>139,8=>8000,
9=>8080,10=>3128,11=>3389,12=>6588,13=>1080,14=>5900,15=>8888);
for($i=1;$i<=15;$i++)
{
$T_SOCK = @fsockopen ($T_HOST,$PORTS[$i],$err1,$err2,3);
if($T_SOCK)
{
echo "\nОткрыт:", $PORTS[$i];
fclose($T_SOCK);
}
else {echo "\nЗакрыт:", $PORTS[$i];}
flush();
usleep(10000);
}
echo "\n--------------";
echo "\nDone";
?>
вот нормально работает во всех браузерах кроме Opera , этот браузер не отдает буфер вывода пока php скрипт не завершит работу