Нон-стоп работа без крона

Статус
В этой теме нельзя размещать новые ответы.

dig555

Постоялец
Регистрация
22 Июн 2007
Сообщения
365
Реакции
160
Есть парсер. Неважно чего. :-] Работать должен длительное время. Нужно после того как я его закинул на сервак и запустил, иметь возможность, выключить свой комп и идти спать. А скрипт пусть работает на сервере до победного конца. Я знаю точно, что возможно. Но не знаю как :)
Буду благодарен любым ссылкам на примеры/мануалы/вашим советам. Ниже пример парсера вордстата, который был написан для меня года полтора назад. В нём эта фишка реализована. Похоже без AJAX тут не обойтись?
PHP:
if ((STATUS=='BUSY')||(STATUS=='DONE')) {
    tpl_exe(TPL_HEAD);
    tpl_exe(TPL_AJAX,array('action'=>$_SERVER['PHP_SELF']));
    tpl_exe(TPL_TAIL);
    return;
}
Полностью:
PHP:
<?php
header('Connection: Close');
header('Cache-Control: no-cache');
header('Pragma: nocache');
header('Content-Type: text/html;charset=windows-1251');
#### conf
set_time_limit(0);
ignore_user_abort(true);
setlocale(LC_ALL,'ru_RU.CP1251');
define('STATUS_FILE','./xparser.st');
define('PROXYLIST','./proxylist.txt');
define('BADWORDS','./badwords.txt');
define('LETTERS','0-9a-zA-ZабвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ');
define('URL','http://wordstat.yandex.ru/advq?rpt=ppc&key=&shw=1&tm=&checkboxes=&text={$WORD}&regions_text=%C2%F1%E5&regions=');
define('NEWDIRPERMS',0744);
define('STATUSUPDATERATE',10000); # частота обновления статуса в мс. для ie ставить не меньше 10000. опера и фокс нормально работают при меньших значениях
#### conf
function get_status() {
	return file_get_contents(STATUS_FILE);
}
function set_status( $s) { # (IDLE|BUSY|DONE)|*EXTRA*
	$f = fopen(STATUS_FILE,'w');
	fputs($f,$s);
	fflush($f);
	fclose($f);
}
function set_status_busy( $i, $total) {
	set_status('BUSY|'.$i.'~'.$total);
}
function x_headers( $s) {
	header('Content-Length: '.strlen($s));
	echo $s;
}
###### tpl
define('TPL_HEAD','<html>
<head>
<style>
* {
	font-family: Tahoma;
	font-size: 10pt;
	color: black;
}
input, textarea {
	background:color: white;
}
input.b, textarea {
	border: 1px solid #906090;
}
div.e {
	color: yellow;
	background-color: red;
	margin: -20px -20px 0 -20px;
	padding: 10px;
}
</style>
</head>
<body marginheight=0 marginwidth=0 leftmargin=0 topmargin=0>
<table border=0 width=100% height=100% cellpadding=0 cellspacing=0><tr><td align=center>
<table border=1 cellpadding=20 cellspacing=0><tr><td>
');
define('TPL_TAIL','</td></tr></table>
</td></tr></table>
</body>
</html>');
define('TPL_FORM','
<script language=javascript>
function redir() {
	setTimeout("document.location=\'${action}\'",1000);
	return true;
}
</script>
<form action="{$action}" method=post onsubmit="return redir()">
<input type=hidden name=action value=start />
<table border=0 cellpadding=2 cellspacing=0>
<tr><td colspan=2><b>Параметры парсера</b></td></tr>
<tr><td valign=top>Слова для парсинга</td><td><textarea style="width:300px;height:100px;" name=words>{$words}</textarea></td></tr>
<tr><td>Глубина парсинга</td><td><input type=text style="width:30px;" class=b name=limit value="{$limit}" /> страниц</td></tr>
<tr><td>Метод обхода капчи</td><td><input type=radio name=acaptcha id=asleep value=sleep {$acaptcha_sleep} /> <label for=asleep>sleep( )</label><br /><input type=radio name=acaptcha id=aproxy value=proxy {$acaptcha_proxy} /> <label for=aproxy>прокси</label></td></tr>
<tr><td><label for=afilter>Чистить плохие слова?</label></td><td><input type=checkbox name=filter id=afilter {$filter} /></td></tr>
<tr><td><label for=ashuffle>Перемешивать кеи?</label></td><td><input type=checkbox name=shuffle id=ashuffle {$shuffle} /></td></tr>
<tr><td>Разбить результат по</td><td><input type=text style="width:40px;" class=b name=page value="{$page}" /> кеев</td></tr>
<tr><td>Сохранять в каталог</td><td><input type=text style="width:100px;" class=b name=path value="{$path}" /></td></tr>
<tr><td colspan=2 align=right><input type=submit style="width:40px;" class=b value=Go /></td></tr>
</table>
</form>
');
define('TPL_ERROR','<div class=e>{$msg}</div>');
define('TPL_AJAX','
<script language=javascript src="ajax.js"></script>
<script language=javascript>
var __done;
var __c = 0;
function __parse( s) {
	if (s.substr(0,11)=="javascript:") {
		eval(s.slice(11));
		return false;
	}
/*	__c++;
	document.getElementById("jjj").innerHTML = s.slice(5)+" (a="+__c+")";
	return false;*/
	return true;
}
var ao;
function refresh() {
	ao.sndReq("post","{$action}","action=status");
	if (!__done) {
		setTimeout("refresh()",'.STATUSUPDATERATE.');
	}
}
window.onload = function() {
	__done = false;
	ao = new AjaxObject101();
	ao.funcDone = __parse;
	refresh();
}
</script>
<center><b>Процесс пошел</b><br /><br /><div id="jjj">***</div></center>
');
function tpl_exe( $tpl, $args=false) {
	if ($args!==false) {
		extract($args);
	}
	echo eval('return "'.str_replace('"','\"',$tpl).'";');
}
###### tpl
function wrap_msg( $s) {
	tpl_exe(TPL_HEAD);
	echo $s;
	tpl_exe(TPL_TAIL);
	return 0;
}
function translit($cyr_str) {
	$razd="-";
	$cyr_str=strtolower($cyr_str);
	$tr = array (
		"А"=>"a","Б"=>"b","В"=>"v","Г"=>"g",
		"Д"=>"d","Е"=>"e","Ж"=>"zh","З"=>"z","И"=>"i",
		"Й"=>"y","К"=>"k","Л"=>"l","М"=>"m","Н"=>"n",
		"О"=>"o","П"=>"p","Р"=>"r","С"=>"s","Т"=>"t",
		"У"=>"u","Ф"=>"f","Х"=>"h","Ц"=>"c","Ч"=>"ch",
		"Ш"=>"sh","Щ"=>"sch","Ъ"=>"","Ы"=>"y","Ь"=>"",
		"Э"=>"e","Ю"=>"u","Я"=>"ya","а"=>"a","б"=>"b",
		"в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"zh",
		"з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
		"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
		"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
		"ц"=>"c","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"",
		"ы"=>"y","ь"=>"","э"=>"e","ю"=>"u","я"=>"ya", " " => $razd
	);
	$text= strtr($cyr_str, $tr);
	$text=preg_replace("/[^a-z0-9_ -]+/", "", $text);
	return $text;
}
function rulat($words) { 
	$rus = "АаВЕеКкМНОоРрСсТХх"; 
	$eng = "AaBEeKkMHOoPpCcTXx"; 
	return strtr($words,$eng,$rus); 
} 
function array_exclude( &$a, $i, $n) {
	for ($j=$i+1; $j<$n; $j++) {
		$a[$j-1] = $a[$j];
	}
}
$x = explode('|',get_status(),2);
define('STATUS',$x[0]);
define('STATUS_MSG',$x[1]);
if (isset($_POST['action'])) {
	switch ($_POST['action']) {
		case 'start':
			if (STATUS!=='IDLE') {
				header('Location: '.$_SERVER['PHP_SELF']);
				return;
			}
			$words = trim(preg_replace('/[^'.LETTERS.']+/',' ',$_POST['words']));
			$words = array_unique(explode(' ',$words));
			$words = implode(' ',$words);
			$limit = (int)$_POST['limit'];
			$acaptcha = $_POST['acaptcha'];
			$filter = isset($_POST['filter']);
			$shuffle = isset($_POST['shuffle']);
			$page = (int)$_POST['page'];
			$path = trim($_POST['path']);
			$fs = array();
			if (!$words) {
				$fs[] = 'Укажите слова для парсинга';
			}
			if ($limit<=0) {
				$fs[] = 'Укажите глубину парсинга';
			}
			if ($filter&&!file_exists(BADWORDS)) {
				$fs[] = 'Не найден файл с плохими словами';
			}
			if (($acaptcha=='proxy')&&!file_exists(PROXYLIST)) {
				$fs[] = 'Не найден файл со списком прокси';
			}
			if ($page<=0) {
				$fs[] = 'Укажите размер разбиения результата';
			}
			$path = str_replace('\\','/',$path);
			if (substr($path,-1,1)!=='/') {
				$path .= '/';
			}
			if (file_exists($path)&&(!is_dir($path)||!is_writable($path))) {
				$fs[] = 'Нет доступа к каталогу';
			}
			if (!sizeof($fs)&&!file_exists($path)) {
				if (!mkdir($path,NEWDIRPERMS)) {
					$fs[] = 'Не могу создать каталог';
				}
			}
			if (sizeof($fs)) {
				tpl_exe(TPL_HEAD);
				tpl_exe(TPL_ERROR,array('msg'=>implode('<br />',$fs)));
				tpl_exe(TPL_FORM,array(
					'action' => $_SERVER['PHP_SELF'],
					'words' => $words,
					'limit' => $limit,
					'acaptcha_sleep' => $acaptcha=='sleep'?'checked':'',
					'acaptcha_proxy' => $acaptcha=='proxy'?'checked':'',
					'filter' => $filter?'checked':'',
					'shuffle' => $shuffle?'checked':'',
					'page' => $page,
					'path' => $path
				));
				tpl_exe(TPL_TAIL);
				return;
			}
			$words = explode(' ',$words);
			$words_total = sizeof($words);
			$word_count = 0;
			set_status_busy(0,$words_total);
			$RZ = array();
if ($filter) {
			$badwords = strtolower(preg_replace('/\s+/',' ',trim(file_get_contents(BADWORDS))));
			$badwords = explode(' ',$badwords);
			$badwords = array_flip($badwords);
}
if ($acaptcha=='proxy') {
			$proxylist = preg_replace('/\s+/',' ',trim(file_get_contents(PROXYLIST)));
			$proxylist = explode(' ',$proxylist);
			$proxies = sizeof($proxylist);
}
			foreach ($words as $w) {
				set_status_busy($word_count,$words_total);
				$word_count++;
				$RZ[$w] = array(
					'paged' => 0,
					'grabbed' => 0,
					'accepted' => 0
				);
				$url = str_replace('{$WORD}',urlencode($w),URL);
				$buf = array();
for ( $step=0; $step<$limit; $step++) { # by pages
				$RZ[$w]['paged']++;
if ($acaptcha=='sleep')	{
				sleep(rand(5,15));
}
				do {
					$httpok = true;
					$ch=curl_init($url);
if ($acaptcha=='proxy') {
					$proxy = rand(0,$proxies-1);
					curl_setopt($ch, CURLOPT_PROXY, $proxylist[$proxy]);
}
					curl_setopt($ch, CURLOPT_HEADER, 0);
					curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
					curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
					curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
					curl_setopt($ch, CURLOPT_TIMEOUT, 10); 
					curl_setopt($ch, CURLOPT_REFERER, "http://yandex.ru");
					$content=curl_exec($ch);
if ($acaptcha=='proxy') {
					if (curl_errno($ch)) {
						$httpok = false;
						array_exclude($proxylist,$proxy,$proxies);
						$proxies--;
					}
}
					curl_close($ch);
				} while (!$httpok);
				$pos = strpos($content,"Что еще");
				if ($pos !== false) {
					$content = substr($content,0,$pos);
				}
				$RZ[$w]['grabbed'] += preg_match_all('/tm=">(['.LETTERS.' ]+)<\/a>/',$content,$matches);
				foreach ($matches[1] as $v) {
					$is_ok = true; 
if ($filter) { # filter bad words
					$s = explode(' ',$v);
					foreach ($s as $t) {
						$tl = strtolower($t);
						if (isset($badwords[$tl])||isset($badwords[rulat($tl)])) { 
							$is_ok = false; 
							break;
						}
					}
}
					if ($is_ok) {
						$buf[] = $v;
					}
				}
				if (preg_match('/<a href="(\/advq\?[^"]+)">следующая/',$content,$match)) {
					$url = 'http://wordstat.yandex.ru'.str_replace('&amp;','&',$match[1]);
				} else {
					break; # no more pages
				}
}
				$RZ[$w]['accepted'] = sizeof($buf);
				if ($z=sizeof($buf)) {
if ($shuffle) { # shuffle the keys grabbed
					for ($i=1; $i<$z; $i++){
						$a = rand(0,$z-1);
						$b = rand(0,$z-1);
						$ta = $buf[$a];
						$tb = $buf[$b];
						$buf[$a] = $tb;
						$buf[$b] = $ta;
					}
}
					$buf = array_chunk($buf,$page);
					$i = 0;
					foreach ($buf as $x) {
						$f = fopen($path.translit($w).'-'.(++$i).'.txt','w');
						fputs($f,implode("\n",$x));
						fclose($f);
					}
				}
			}
			$total_grabbed = 0;
			$total_accepted = 0;
			foreach ($RZ as $x) {
				$total_grabbed += $x['grabbed'];
				$total_accepted += $x['accepted'];
			}
			set_status('DONE|Обработано '.$words_total.' слов\nВытянуто '.$total_grabbed.' кеев\nСохранено (в каталог '.$path.') '.$total_accepted.' кеев');
			return;
		case 'status':
			if (STATUS=='BUSY') {
				list($a,$b) = explode('~',STATUS_MSG);
				x_headers('jjj=>выполнено '.$a.'/'.$b.' ('.(int)(100*$a/$b).'%)');
				return;
			}
			if (STATUS=='DONE') {
				set_status('IDLE|');
				x_headers('javascript:__done=true;alert("'.STATUS_MSG.'");document.location="'.$_SERVER['PHP_SELF'].'";');
				return;
			}
			return;
		case 'stop':
			if (STATUS!=='BUSY') {
				return;
			}
			return;
	}
}
if ((STATUS=='BUSY')||(STATUS=='DONE')) {
	tpl_exe(TPL_HEAD);
	tpl_exe(TPL_AJAX,array('action'=>$_SERVER['PHP_SELF']));
	tpl_exe(TPL_TAIL);
	return;
}
tpl_exe(TPL_HEAD);
tpl_exe(TPL_FORM,array(
	'action' => $_SERVER['PHP_SELF'],
	'words' => '',
	'limit' => '1',
	'acaptcha_sleep' => 'checked',
	'acaptcha_proxy' => '',
	'filter' => '',
	'shuffle' => '',
	'page' => '1000',
	'path' => './'
));
tpl_exe(TPL_TAIL);
?>
 
set_time_limit(0); - устанавливает выполнение скрипта без ограничения по вермени
ignore_user_abort(true); устанавливает игнорировать разрыв соединения пользователем

Результаты лучше всего писать в файл
 
set_time_limit(0) -- ток тут дело в том что хостеры фиг тебе дадут это сделать
можешь попробовать
там нет ограничения по времени

АЯКС -- а где он у тебя работать будет, если ты комп выключишь ? )))

я бы предложил такой вариант -- при запуске создавать и блокировать файл-флаг
и запуск повесить на частозапрашиваемый объект ( картинка на каком нибудь сайте, или ава)
при вызове скрипта проверять наличие флага и то что он залочен
залочен -- все работает , выходим
не залочен -- скрипт остановился, запускаем его по новой

идея ясна ?
 
set_time_limit(0) -- ток тут дело в том что хостеры фиг тебе дадут это сделать
можешь попробовать
*** скрытое содержание *** там нет ограничения по времени
АЯКС -- а где он у тебя работать будет, если ты комп выключишь ? )))
я бы предложил такой вариант -- при запуске создавать и блокировать файл-флаг
и запуск повесить на частозапрашиваемый объект ( картинка на каком нибудь сайте, или ава)
при вызове скрипта проверять наличие флага и то что он залочен
залочен -- все работает , выходим
не залочен -- скрипт остановился, запускаем его по новой
идея ясна ?
Ясна. :) Только проблема не в том, что крона нет. А в том, что я не хочу его использовать. У меня свой VPS. Так что проблемы с хостингами меня не волнуют. :-] set_time_limit(0) то работает, но скрипт становится всё равно минут через 10. Попробую поковырять php.ini. Файл-флаг сделать неплохо. Если туда записывать статус выполнения, и если он не изменился за минуту, то запускать скрипт по новой. Но это опять крон, внешние файлы, или ещё какая-то хрень ))
а если внешние сервисы использовать типа
*** скрытое содержание ***
Спасибо, но повторюсь, что крон у меня есть. Но чего-то мне с ним связываться не хочется абсолютно. :)
 
У тебя свой VPS - юзай для этих целей PHP CLI. Там хоть демонов вешай.
 
реализовать что-то типа следующего: результаты работы скрипта отдавать в таблицу либо в файлик (а по запросу скрипта чтоб отдавалось содержимое наработанное долгой работой скрипта), либо в меил.

на php всё таки отсутствует понятие сервера приложений. но можно вызвать подчиненный скрипт, который будет вызван, например, вызовом system("php script.php > file.txt"), а если file.txt что-то содержит, т.е результаты работы, то они должны быть выведены.

ну а если результат работы не просто текст, а что-то посложнее, то это посложнее можно сериализовать прямо в файлик.
 
Если сервер апач :

/usr/local/apache/conf/extra/httpd-default.conf

Измени параметр Timeout на 86400 и рестартани апач.

Либо, если нет возможности, посмотри функцию apache_reset_timeout()
 
$arg=$argv[1];
system('/usr/local/bin/php /path/to/script/name.php '.$arg.' > /dev/null 2>&1 &');
в зависимости от никса (синтаксиса утили ps) можно пробивать наличие процесса и его загрузку. т.е. можно выловить ситуации, когда скрипт начал жрать 99%.
system('ps -auxw | grep /usr/local/bin/php | gawk \' { print $3}\' > ps.log &');
опятьже без претензии на лучший вариант. главное функциональность.
 
Парни вы очумели?
Какие "Timeout на 86400 и рестартани апач" и "system('/usr/local/bin/php /path/to/script/name.php '.$arg.' > /dev/null 2>&1 &');"? :eek:

Есть CLI, его для таких целей и создавали.
 
Статус
В этой теме нельзя размещать новые ответы.
Назад
Сверху