Новости | FAQ | Авторы | Документация | В действии | Библиотека |
Инструменты | Полезные ссылки | Хостинги | Скачать | Примеры | Форум |
Sanja v.2 06.02.2004 16:37
Код того, что работает у меня на http://www.bougakov.com/blog/friends/############################## # В этот класс вынесен весь код, который # отвечает за чтение RSS потоков с других сайтов. @CLASS rss @USE log.p ############################## # Загрузчик @load[] $result[] ############################## # Получение списка RSS ньюсфидов, которые не обновлялись больше часов, чем # указано в столбце min_refresh_period и их обновление @update_list[] ^if(def $form:limit){ $limit[$form:limit] $limit(^limit.int(15)) }{$limit(15)} <p>Идёт поиск до $limit RSS-лент, которые, согласно графику, уже должны быть обновлены…^; ^MAIN:dbconnect{ $rss_feeds[ ^table::sql{SELECT uri, name, last_update, is_enabled, min_refresh_period, hours_to_keep FROM cityblog_rsslist WHERE is_enabled="yes" AND (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(last_update)) >= (min_refresh_period * 60 * 60) # В часе 60 минут по 60 секунд, если вы не в курсе :-) ORDER BY # last_update RAND() }[$.limit($limit)] ] ^if(def $rss_feeds){ <ol> ^rss_feeds.menu{ <li><a href="$rss_feeds.uri" target="_new">$rss_feeds.name</a> последний раз был открыт $rss_feeds.last_update, выполняется обновление…^;</li> ^update_feed[$rss_feeds.uri] ^void:sql{DELETE FROM cityblog_rssitems WHERE (UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(pubdate)) >= ($rss_feeds.hours_to_keep * 60 * 60) AND link = "$rss_feeds.uri" } } </ol> }{ <p>В настоящий момент таковых нет.</p> } } ############################## # Повторное чтение RSS потока, разбор и запись в базу обновлений: @update_feed[feeduri] # пытаемся загрузить RSS файл с помощью ^file::load # При этом может произойти целая туча неприятностей - другой сервер может не отвечать, # файл окажется испорчен или удалён - на этот случай мы пользуемся оператором ^try ^try{ $error(0) $rss[^file::load[text;^untaint{$feeduri}; $.timeout(5) $.any-status(1) $.headers[ $.User-Agent[CityBlog RSS aggregator from $MAIN:global_server] ] ]] # Поскольку парсер неспособен считать XML-элементы наподобие <item rdf:about="http:// # выскребаем их из документа: $rss_replacements[^table::create{from to encoding="UTF-8" encoding="windows-1251" encoding="utf-8" encoding="windows-1251" encoding='utf-8' encoding='windows-1251' encoding="iso-8859-1" encoding="windows-1251" encoding='iso-8859-1' encoding='windows-1251' rdf: rdf_ &mdash^; - &hellip^; ...  ^; "^; " ” " “ " ©^; (c) «^; " »^; " &trade^; <sup>(TM)</sup> </rdf:RDF> </rss> xmlns= xmln_dis= xmlns: xmln_dis_ <rdf:li <rdf_li <rdf:Seq <rdf_Seq </rdf:Seq </rdf_Seq rdf:resource= rdf_resource= <admin:generatorAgent <admin_generatorAgent <rdf:RDF <rss version="2.0" dc:subject> subject> dc:creator> creator> dc:publisher> publisher> syn:updateFrequency> syn_updateFrequency> syn:updatePeriod> syn_updatePeriod> syn:updateBase> syn_updateBase> sy:updateFrequency> sy_updateFrequency> sy:updatePeriod> sy_updatePeriod> sy:updateBase> sy_updateBase> dc:language> language> dc:rights> rights> dcterms:isReferencedBy dcterms_isReferencedBy admin:errorReportsTo admin_errorReportsTo <content:encoded> <description> </content:encoded> </description> trackback:ping trackback_ping trackback:about trackback_about dc:date> pubDate>}] $rss_text[^untaint{$rss.text}] # Дочищаем текст: $rss_text[^rss_text.replace[$rss_replacements]] # Это - на случай особо извращённых интерпретаций RSS (с <rdf:Seq>): ^if(^rss_text.match[rdf_Seq][]){ $rdf_replacements[^table::create{from to </channel> <items> </items> </rss> </channel></rss>}] $rss_text[^rss_text.replace[$rdf_replacements]] } $xml[^xdoc::create{$rss_text}] # Избавляемся от корневого тега RDF # $xml[^xml.transform[/etc/classes/no_rdf.xsl]] $items[^xml.select[/rss/channel/item]] # <!-- ^taint[html][^rss_text.left(50000)] --> }{ $exception.handled(1) $result[ <b>Не получилось загрузить RSS-поток!</b> ^if(def $rss_text){ <pre>^taint[html][^rss_text.left(1000)]</pre> ^rss_text.save[/etc/temp/^taint[file-spec][^feeduri.match[/][g]{_}].xml] }{ <!-- No RSS feed' text available! -->} <pre>^taint[html][$exception.comment]</pre> ] $rss_text[ ] $error(1) ^log:write[Не получилось загрузить RSS-поток $feeduri] } $updatedcnt(0) ^if(def $items){ # Нам нужно узнать версию RSS-потока, который мы получили. # Тонкость в том, что у RSS 2.0 есть тэг PubDate, а у RSS 0.91 нету. # Поэтому для RSS 2 мы пользуемся тем, что есть, а для старых версий RSS # пользуемся политикой "дата, когда выкачали = дата создания" ^dates:load[] $rss_version[^xml.selectString[string(rss/@version)]] ^for[i](1;$items){ ^if($rss_version eq "2.0"){ $date{^xml.selectString[string(/rss/channel/item[position() = $i]/pubDate)]} # Вы думали, чехарда с датами закончилась? А нифига ;-) # Дата может быть в таком формате - Tue, 30 Sep 2003 14:32:46 MSD # или в таком - Mon, 29 Sep 2003 11:23:12 GMT. A есть ещё обозначение "UTC"... # see also: http://208.30.42.17/logistics/tzhelp.asp # http://www.worldtimezone.com/wtz-names/wtz-msks.html # Нам надо привести это время к нашему локальному ^if(def $date){ $date[^date::create[^dates:string2GMT[$date]]] }{ $date[^date::create[^dates:GMT_datetime[]]] } }{ # Если мы имеем дело с RSS старой версии, берём текущую дату, приведённую к Гринвичу: $date[^date::create[^dates:GMT_datetime[]]] } $title{^xml.selectString[string(/rss/channel/item[position() = $i]/title)]} $link{^xml.selectString[string(/rss/channel/item[position() = $i]/link)]} $description{^xml.selectString[string(/rss/channel/item[position() = $i]/description)]} $countitems[^table::sql{SELECT COUNT(*) AS cnt FROM cityblog_rssitems WHERE link = "$link" }] $counter[$countitems.cnt] $counter(^counter.int(1)) $rep[^table::create{from to ' \' \ \\}] ^if($counter == 0){ ^void:sql{INSERT INTO cityblog_rssitems (feed_id, title, link, description, pubdate) VALUES ('^feeduri.replace[$rep]', '^title.replace[$rep]', '^link.replace[$rep]', '^description.replace[$rep]', '^date.sql-string[]') } ^updatedcnt.inc[] }{ # Эта запись уже выкачивалась, апдейтить не надо. } } # Обновляем запись об этом RSS-фиде в базе: ^if(($updatedcnt >= 0) && ($error != 1)){ ^void:sql{UPDATE cityblog_rsslist SET last_update = NOW() WHERE uri = "$feeduri" } } } Найдено новых записей: <b>${updatedcnt}</b> </p> # Обнуляем переменную: $rss_text[] ############################## # Вывод кешированных RSS-элементов из базы @display[] ^MAIN:dbconnect{ $rss_items[ ^table::sql{SELECT id, feed_id, title, link, description, DATE_FORMAT(pubdate, "%d/%m/%Y, %H:%i") as date FROM cityblog_rssitems ORDER BY pubdate DESC }[$.limit(20) $.offset(^if(def $form:skip){$form:skip}{0})] ] $rss_sources[^hash::sql{select uri, name, last_update, is_enabled, min_refresh_period, hours_to_keep, allow_untaint FROM cityblog_rsslist }] } ^if(def $rss_items){ ^rss_items.menu{ $link[^untaint[as-is]{$rss_items.link}] $feed[^untaint[as-is]{$rss_items.feed_id}] $allow_untaint[$rss_sources.$feed.allow_untaint] <h4> ^if(def ^untaint[as-is]{$rss_sources.$feed.uri}){ <a href="^untaint[as-is]{$rss_sources.$feed.uri}">^untaint[as-is]{$rss_sources.$feed.name}</a> }{ ^untaint[as-is]{$rss_sources.$feed.name} } - <a href="$link">^if(def $rss_items.title){^untaint[as-is]{$rss_items.title}}{Без заголовка}</a> <nobr>($rss_items.date GMT)</nobr></h4> ^if($allow_untaint eq "yes"){ $desc[^untaint[as-is]{$rss_items.description}] }{ $desc[^untaint[html]{$rss_items.description}] # $desc[^desc.match[(^^|[^^="])(http://|ftp://|mailto:)([:a-z0-9~%{}._/?=&@,#-]+)(^^|[^^="])][gi]{${match.1}<a href=${match.2}${match.3} target="_new" title="Ссылка будет открыта в новом окне" class=smallest>${match.2}${match.3}</a>}] ^if(^desc.length[] >= 250){ $desc[^desc.left(250)…^; [<a href="$link">Читать дальше…^;</a>]] } } $cleanup[^table::create{from to <br> <br /> <br /><br /><br /><br /> <br /> <br /><br /><br /> <br /> <br /><br /> <br /> blockquote><br /><br /><br /> blockquote> blockquote><br /><br /> blockquote> blockquote><br /> blockquote> <br /></blockquote> </blockquote> </blockquote><br /> </blockquote> </blockquote><br /> </blockquote> </blockquote><br /> </blockquote> </blockquote><br /> </blockquote> </blockquote><br /> </blockquote> </blockquote><br /> </blockquote>}] ^if(def $desc){ <blockquote> ^desc.replace[$cleanup] </blockquote> }{<blockquote><i>Эта запись - без текста</i></blockquote>} } }На странице с френдлентой вызывается так:
^rss:display[] $skip(^form:skip.int[]) $skip(^eval($skip + 20)) <p>[<a href="./?skip=${skip}">Следующие 20 записей…^;</a>]</p>Рефреш вызывается так:
^rss:update_list[]В коде упоминается класс dates, он неправильный, буду переписывать. Вот его код:
############################## # Класс для работы с датами @CLASS dates ############################## # Получаем текущую дату по Гринвичу из нашей локальной: @load[] # Нам нужно узнать, на сколько сдвинуть текущую дату и время. # Сдвиг складывается из разницы по отношению к Гринвичу + поправки на летнее время $local[^date::now[]] # Летнее время: ^if($MAIN:global_daylight eq "yes"){ # Попадает ли текущая дата в промежуток, когда вводится летнее время? $daylight_lbound[^date::create($local.year;$MAIN:global_daylight_m_start;$MAIN:global_daylight_d_start;0;0;0)] $daylight_ubound[^date::create($local.year;$MAIN:global_daylight_m_end;$MAIN:global_daylight_d_end;0;0;0)] ^if( ($local.day >= $daylight_lbound.day) && ($local.month >= $daylight_lbound.month) && ($local.day <= $daylight_ubound.day) && ($local.month <= $daylight_ubound.month) ){ # Текущая дата - в том, диапазоне, в котором летнее время в силе: $daylight_offset(1) }{ # ...или нет: $daylight_offset(0) } } # Из текущей даты и времени мы должны вычесть час летнего времени и разницу с Гринвичем: $GMTdate[^date::create($local - (($daylight_offset + $MAIN:global_timeoffset)/24))] ############################## # Получаем текущую дату (системную): @local_datetime[] $result[^local.sql-string[]] ############################## # Получаем текущую дату (приведённую к Гринвичу): @GMT_datetime[] $result[^GMTdate.sql-string[]] ############################## # Приводим дату в виде строки ("Mon, 29 Sep 2003 11:23:12 GMT") к Гринвичу: @string2GMT[string] ^string.match[([A-Za-z]{3}), ([0-9]+) ([A-Za-z]{3}) ([0-9]+) ([0-9]+):([0-9]+):([0-9]+) ([A-Za-z]{3,4})][g]{ $year($match.4) $month[$match.3] ^if($month eq Jan){$month(1)} ^if($month eq Feb){$month(2)} ^if($month eq Mar){$month(3)} ^if($month eq Apr){$month(4)} ^if($month eq May){$month(5)} ^if($month eq Jun){$month(6)} ^if($month eq Jul){$month(7)} ^if($month eq Aug){$month(8)} ^if($month eq Sep){$month(9)} ^if($month eq Oct){$month(10)} ^if($month eq Nov){$month(11)} ^if($month eq Dec){$month(12)} $day($match.2) $hour($match.5) $minute($match.6) $second($match.7) $timezonename[$match.8] } # Табличка с названиями временных зон и поправками: # Название Аббр. Поправка # Samoa Standard Time SST -11 # Hawaii-Aleutian Standard Time HST -10 # Alaska Standard Time AKST -9 # Hawaii-Aleutian Daylight Time HDT -9 # Alaska Daylight Time AKDT -8 # Pacific Standard Time PST -8 # Mountain Standard Time MST -7 # Pacific Daylight Time PDT -7 # Central Standard Time CST -6 # Mountain Daylight Time MDT -6 # Central Daylight Time CDT -5 # Eastern Standard Time EST -5 # Atlantic Standard Time AST -4 # Eastern Daylight Time EDT -4 # Atlantic Daylight Time ADT -3 # Greenwich Mean Time GMT 0 # Western Europe Time WET 0 # British Summer Time BST 1 # Central Europe Time CET 1 # Irish Summer Time IST 1 # Western Europe Summer Time WEST 1 # Central Europe Summer Time CEST 2 # Eastern Europe Time EET 2 # Eastern Europe Summer Time EEST 3 # Moscow Time MSK 3 # Moscow Summer Time MSD 4 # Western Standard Time WST 8 # Central Standard Time CST 9.5 # Eastern Standard Time EST 10 ^if(def $year && def $month && def $day){ ^switch[$timezonename]{ ^case[SST]{$tz_offset(-11)} ^case[HST]{$tz_offset(-10)} ^case[AKST]{$tz_offset(-9)} ^case[HDT]{$tz_offset(-9)} ^case[AKDT]{$tz_offset(-8)} ^case[PST]{$tz_offset(-8)} ^case[MST]{$tz_offset(-7)} ^case[PDT]{$tz_offset(-7)} ^case[CST]{$tz_offset(-6)} ^case[MDT]{$tz_offset(-6)} ^case[CDT]{$tz_offset(-5)} ^case[EST]{$tz_offset(-5)} ^case[AST]{$tz_offset(-4)} ^case[EDT]{$tz_offset(-4)} ^case[ADT]{$tz_offset(-3)} ^case[GMT]{$tz_offset(0)} ^case[WET]{$tz_offset(0)} ^case[BST]{$tz_offset(1)} ^case[CET]{$tz_offset(1)} ^case[IST]{$tz_offset(1)} ^case[WEST]{$tz_offset(1)} ^case[CEST]{$tz_offset(2)} ^case[EET]{$tz_offset(2)} ^case[EEST]{$tz_offset(3)} ^case[MSK]{$tz_offset(3)} ^case[MSD]{$tz_offset(4)} ^case[WST]{$tz_offset(8)} ^case[CST]{$tz_offset(9.5)} ^case[EST]{$tz_offset(10)} ^case[DEFAULT]{$tz_offset(0)} } $UnadjustedString[^date::create($year;$month;$day;$hour;$minute;$second)] $GMTString[^date::create($UnadjustedString - ($tz_offset/24))] }{ $GMTString[^date::now[]] } $result[^GMTString.sql-string[]]В auto.p вынесены следующие переменные:
$global_timeoffset(3) $global_timeoffset_string[+03:00] # Ваше локальное время сдвигается летом? $global_daylight[yes] # Это происходит с [день, месяц] по [день, месяц]: # (обычно с 29-Mar по 25-Oct, см. http://www.worldtimezone.com/daylight.htm) $global_daylight_m_start(3) $global_daylight_d_start(29) $global_daylight_m_end(10) $global_daylight_d_end(25)