| Новости | 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)