e03435ecf517f178e23ec40af9d4f0e9cb5266f6
[atutor.git] / mods / wiki / plugins / lib / feedparse.php
1 <?php
2 /*
3    Deciphers RSS and Atom feeds into a simple array/hash structure. Does not
4    evaluate MIME parameters, but elsewhise is rather compliant, even if it
5    only uses simplified and data-oriented XML extraction.
6    It often can evaluate RDF/"RSS"-1.0 feeds, if they aren't too RDFish
7    (no real parser for that), adn the text-only RSS3.0 is also supported.
8
9    @depends: http, http_cached, xml
10 */
11
12
13 #-- fetches, caches and decodes RSS/Atom feeds
14 function ewiki_feed_get($url) {
15    global $ewiki_cache_ctype;
16    if ($xml = ewiki_cache_url($url)) {
17       return ewiki_feed_parse($xml);
18    }
19 }
20
21
22 #-- decodes RSS/Atom feeds into struct/hash
23 function ewiki_feed_parse($xml, $ctype="text/xml") {
24    $xml = trim($xml);
25    $r = array();
26    #-- guess charset
27    if (preg_match("/charset=[\"']?([-\w\d]+)/i", $ctype, $uu)) {
28       $charset = $uu[1];
29    }
30    else {
31       $charset = "ISO-8859-1";   // default for most stuff over HTTP
32    }
33    #-- xml
34    if ($xml[0] == "<") {
35       $xml = new easy_xml_rss($xml, $charset);
36       $xml->parse();
37       if (isset($xml->channel)) {
38          $r = array($xml->channel, $xml->item);
39       }         
40    }
41    #-- text/rfc822 rss
42    else {
43       $item = ewiki_decode_rfc822($xml);
44       $channel = $item[0];
45       unset($item[0]);
46       $r = array($channel, $item);
47    }
48    #-- unified timestamps
49    if ($r[1]) foreach($r[1] as $i=>$d) {
50       $r[1][$i]["time"] = ewiki_decode_datetime($d["pubDate"]);
51    }
52    return($r);
53 }
54
55
56 #-- separates multiple blocks of name:value pairs
57 function ewiki_decode_rfc822($text) {
58    $blocks = array();
59    foreach (preg_split("/\r?\n\r?\n/", $xml) as $part) {
60       $r = array();
61       foreach (preg_split("/\r?\n(?>[^\s])/") as $field)
62       {
63          $r[trim(strtolower(strtok($field, ":")))]
64             = trim(preg_replace("/\s+/", " ", strtok("\000")));
65       }
66       $blocks[] = $r;
67    }
68    return($blocks);
69 }
70
71
72 #-- tries to decipher a date+time string into a unixish timestamp
73 function ewiki_decode_datetime($str, $localize=1, $gmt=0) {
74    $done = 0;
75    $months = array_flip(array("Err", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"));
76    
77    #-- 8601
78    if (($str[4] == "-")
79    and preg_match("/(\d+)-(\d+)-(\d+)(T(\d+):(\d+)(:(\d+))?)?/", $str, $uu)) {
80       $t = gmmktime($uu[5], $uu[6], $uu[8], $uu[2], $uu[3], $uu[1]);
81    }
82    #-- mbox, ANSI C asctime()
83    elseif (($str[3] == " ")
84    and preg_match("/\w+ (\w+) +(\d+) (\d+):(\d+):(\d+) (\d+)/", $str, $uu)) {
85       $t = gmmktime($uu[3], $uu[4], $uu[5], $months[$uu[1]], $uu[2], $uu[6]);
86       $gmt = 1;
87    }
88    #-- rfc822/1123, (rfc850/1036), mostly for HTTP
89    elseif (1
90    and preg_match("/\w+, (\d+)[- ](\w+)[- ](\d+) (\d+):(\d+):(\d+)/", $str, $uu)) {
91       $t = gmmktime($uu[4], $uu[5], $uu[6], $months[$uu[2]], $uu[1], $uu[3]);
92       $gmt = 1;
93    }
94    #-- already was a timestamp
95    elseif (((int)$str) == $str) {
96       $t = (int)$str;
97       $gmt = 1;
98    }
99    #-- last resort
100    else {
101       $t = strtotime($str);
102       $gmt = 1;
103    }
104
105    #-- is local time (iso8601 only)
106    if (!$gmt && $localize && preg_match('/([+-])(\d+):(\d+)$/', $str, $uu)) {
107       $dt = $uu[1] * 60 + $uu[2];
108       if ($uu[1] == "+") {
109          $t -= $dt;
110       }
111       else {
112          $t += $dt;
113       }
114    }
115    
116    return($t);
117 }
118
119
120 ?>