aggregator.module 14.3 KB
Newer Older
1 2
<?php

Dries's avatar
 
Dries committed
3
function import_help() {
4
 ?>
Dries's avatar
 
Dries committed
5 6 7 8 9 10
  <P><I>TODO: introduction on syndication and a few pointers to more information.</I></P>
  <P>In Drupal you have <I>feeds</I> and <I>bundles</I>.   Feeds define news sources and bundles categoriz syndicated content by source, topic or any other heuristic.   Bundles provide a generalized way of creating composite feeds.  They allow you, for example, to combine various sport-related feeds into one bundle called "Sport".</P>
  <P>You can have several providers of news feeds.  You can add a feed by clicking the "add feed" link on the import administration pages.  Give the feed a name, supply the URI and a comma-separated list of attributes that you want to associate the feed with.  The update interval defines how often Drupal should go out to try and grab fresh content.  The expiration time defines how long syndicated content is kept in the database.  So set the update and expiration time and save your settings.  You have just defined your first feed.  If you have more feeds repeat as necessary.</P>
  <P>To verify whether your feed works, press "update items" at the overview page.  The number of items that have been sucessfully fetched, should then become visible in the third column of the feed overview.</P>
  <P>Now you have to define some bundles.  Bundles look for feeds that contain one of the keywords associated with the bundle and display those feeds together.  To define a bundle you have to give it a name and a comma-separated list of keywords just like this is the case for feeds.</P>
  <P>Your newly created bundle will now show up in the list of blocks that you can see at the block related administration pages.  There you can customize where and when your bundles will be displayed.</P>
11 12 13
 <?php
}

Dries's avatar
 
Dries committed
14
function import_perm() {
Dries's avatar
 
Dries committed
15 16 17 18 19 20 21 22 23
  return array("administer news feeds");
}

function import_link($type) {
  if ($type == "admin") {
    $links[] = "<a href=\"admin.php?mod=import\">news feeds</a>";
  }

  return $links ? $links : array();
Dries's avatar
 
Dries committed
24 25
}

Dries's avatar
 
Dries committed
26
function import_cron() {
27 28 29
  $result = db_query("SELECT * FROM feed");
  while ($feed = db_fetch_array($result)) {
    // remove expired items:
Dries's avatar
 
Dries committed
30
    db_query("DELETE FROM item WHERE fid = '$feed[fid]' AND timestamp < ". (time() - $feed[uncache]));
31 32

    // update feeds:
Dries's avatar
 
Dries committed
33
    if ($feed[timestamp] + $feed[refresh] < time()) import_update($feed);
34 35 36
  }
}

37 38
function import_bundle($attributes, $limit = 100) {
  if ($attributes) {
39
    // compose query:
40 41
    $keys = explode(",", $attributes);
    foreach ($keys as $key) $where[] = "attributes LIKE '%". trim($key) ."%'";
42

Dries's avatar
 
Dries committed
43
    $result = db_query("SELECT * FROM item WHERE ". implode(" OR ", $where) ." ORDER BY timestamp DESC LIMIT $limit");
44 45 46 47 48

    while ($item = db_fetch_object($result)) {
      $output .= "<LI><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A></LI>";
    }

Dries's avatar
 
Dries committed
49
    return "$output";
50 51 52
  }
}

Dries's avatar
 
Dries committed
53
function import_view_bundle() {
Dries's avatar
 
Dries committed
54
  $result = db_query("SELECT * FROM bundle ORDER BY title");
55
  while ($bundle = db_fetch_object($result)) {
56
    $output .= "<B>$bundle->title</B><UL>". import_bundle($bundle->attributes) ."</UL>";
57 58 59 60
  }
  return $output;
}

Dries's avatar
 
Dries committed
61 62 63 64 65
function import_block() {
  $result = db_query("SELECT * FROM bundle ORDER BY title");
  while ($bundle = db_fetch_object($result)) {
    $i++;
    $blocks[$i][subject] = $bundle->title;
66
    $blocks[$i][content] = import_bundle($bundle->attributes, 10);
Dries's avatar
 
Dries committed
67 68 69 70 71
    $blocks[$i][info] = "$bundle->title bundle";
  }
  return $blocks;
}

Dries's avatar
 
Dries committed
72 73 74 75 76
function import_remove($feed) {
  db_query("DELETE FROM item WHERE fid = '$feed[fid]'");
  return "feed '$feed[title]' reset.";
}

Dries's avatar
 
Dries committed
77
function import_update($feed) {
78 79 80 81 82 83 84 85 86 87 88 89

  // open socket:
  $url = parse_url($feed[link]);
  $fp = fsockopen($url[host], ($url[port] ? $url[port] : 80), $errno, $errstr, 15);

  if ($fp) {
    // fetch data:
    fputs($fp, "GET $url[path]?$url[query] HTTP/1.0\nUser-Agent: ". variable_get(site_name, "drupal") ."\nHost: $url[host]\nAccept: */*\n\n");
    while(!feof($fp)) $data .= fgets($fp, 128);

    if (strstr($data, "200 OK")) {

Dries's avatar
 
Dries committed
90 91 92
      eregi("<item([^s].*)</item>", $data, $data);

      // print "<PRE>". htmlentities($data[0]) ."</PRE>";
93 94 95

      foreach (explode("</item>", $data[0]) as $item) {
        $t = eregi("<title>(.*)</title>", $item, $title);
Dries's avatar
 
Dries committed
96
        $l = eregi("<link>(.*)</link>", $item, $link);
97 98 99 100
        $a = eregi("<author>(.*)</author>", $item, $author);
        $d = eregi("<description>(.*)</description>", $item, $description);

        if ($l || $t || $a || $d) {
101
          import_save_item(array(fid => $feed[fid], title => $title[0], link => $link[0], author => $author[0], description => $description[0], attributes => $feed[attributes]));
102 103 104 105 106 107 108 109 110
        }
      }

      db_query("UPDATE feed SET timestamp = '". time() ."' WHERE fid = '". $feed[fid] ."'");
    }
    else {
      watchdog("error", "failed to syndicate from '$feed[title]'");
    }
  }
Dries's avatar
 
Dries committed
111 112

  return "feed '$feed[title]' updated.";
113 114
}

Dries's avatar
 
Dries committed
115
function import_save_item($edit) {
116
  if ($edit[iid] && $edit[title]) {
117
    db_query("UPDATE item SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', author = '". check_input($edit[author]) ."', description = '". check_input($edit[description]) ."', attributes = '". check_input($edit[attributes]) ."' WHERE iid = '$edit[iid]'");
118 119 120 121 122 123
  }
  else if ($edit[iid]) {
    db_query("DELETE FROM item WHERE iid = '". check_input($edit[iid]) ."'");
  }
  else {
    if (!db_fetch_object(db_query("SELECT iid FROM item WHERE link = '". check_input($edit[link]) ."'"))) {
124
      db_query("INSERT INTO item (fid, title, link, author, description, attributes, timestamp) VALUES ('". check_input($edit[fid]) ."', '". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[author]) ."', '". check_input($edit[description]) ."', '". check_input($edit[attributes]) ."', '". time() ."')");
125 126 127 128
    }
  }
}

Dries's avatar
 
Dries committed
129
function import_form_bundle($edit = array()) {
130 131 132
  global $REQUEST_URI;

  $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the bundle.");
133
  $form .= form_textfield("Attributes", "attributes", $edit[attributes], 50, 128, "A comma-seperated list of keywords describing the bundle.");
134 135 136 137 138 139 140 141 142 143 144

  $form .= form_submit("Submit");

  if ($edit[bid]) {
    $form .= form_submit(t("Delete"));
    $form .= form_hidden("bid", $edit[bid]);
  }

  return form($REQUEST_URI, $form);
}

Dries's avatar
 
Dries committed
145
function import_save_bundle($edit) {
146
  if ($edit[bid] && $edit[title]) {
147
    db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attributes = '". check_input($edit[attributes]) ."' WHERE bid = '". check_input($edit[bid]) ."'");
148 149 150 151 152
  }
  else if ($edit[bid]) {
    db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'");
  }
  else {
153
    db_query("INSERT INTO bundle (title, attributes) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attributes]) ."')");
154
  }
Dries's avatar
 
Dries committed
155 156

  module_rehash_blocks("import");
157 158
}

Dries's avatar
 
Dries committed
159
function import_form_feed($edit = array()) {
160 161 162 163 164
  global $REQUEST_URI;

  $period = array(900 => format_interval(900), 1800 => format_interval(1800), 3600 => format_interval(3600), 7200 => format_interval(7200), 10800 => format_interval(10800), 21600 => format_interval(21600), 32400 => format_interval(32400), 43200 => format_interval(43200), 64800 => format_interval(64800), 86400 => format_interval(86400), 172800 => format_interval(172800), 259200 => format_interval(259200), 604800 => format_interval(604800), 1209600 => format_interval(1209600), 2419200 => format_interval(2419200));

  $form .= form_textfield("Title", "title", $edit[title], 50, 64, "The name of the feed; typically the name of the website you syndicate content from.");
Dries's avatar
 
Dries committed
165
  $form .= form_textfield("Link", "link", $edit[link], 50, 128, "The fully-qualified URL of the feed.");
166
  $form .= form_textfield("Attributes", "attributes", $edit[attributes], 50, 128, "A comma-seperated list of keywords describing the feed.");
167 168 169 170 171 172 173 174 175 176 177 178 179
  $form .= form_select("Update interval", "refresh", $edit[refresh], $period, "The refresh interval indicating how often you want to update this feed.  Requires crontab.");
  $form .= form_select("Expiration time", "uncache", $edit[uncache], $period, "The time cached items should be kept.  Older items will be automatically discarded.  Requires crontab.");

  $form .= form_submit("Submit");

  if ($edit[fid]) {
    $form .= form_submit(t("Delete"));
    $form .= form_hidden("fid", $edit[fid]);
  }

  return form($REQUEST_URI, $form);
}

Dries's avatar
 
Dries committed
180
function import_save_feed($edit) {
181
  if ($edit[fid] && $edit[title]) {
182
    db_query("UPDATE feed SET title = '". check_input($edit[title]) ."', link = '". check_input($edit[link]) ."', attributes = '". check_input($edit[attributes]) ."', refresh = '". check_input($edit[refresh]) ."', uncache = '". check_input($edit[uncache]) ."' WHERE fid = '". check_input($edit[fid]) ."'");
183 184 185 186 187 188 189
    db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'");
  }
  else if ($edit[fid]) {
    db_query("DELETE FROM feed WHERE fid = '". check_input($edit[fid]) ."'");
    db_query("DELETE FROM item WHERE fid = '". check_input($edit[fid]) ."'");
  }
  else {
190
    db_query("INSERT INTO feed (title, link, attributes, refresh, uncache) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[link]) ."', '". check_input($edit[attributes]) ."', '". check_input($edit[refresh]) ."', '". check_input($edit[uncache]) ."')");
191 192 193
  }
}

Dries's avatar
 
Dries committed
194
function import_save_attributes($edit) {
195
  foreach($edit as $iid => $value) {
196
    db_query("UPDATE item SET attributes = '". check_input($value) ."' WHERE iid = '". check_input($iid) ."'");
197 198 199 200
  }
  return "attributes has been saved";
}

Dries's avatar
 
Dries committed
201
function import_get_feed($fid) {
202 203 204
  return db_fetch_array(db_query("SELECT * FROM feed WHERE fid = '". check_input($fid) ."'"));
}

Dries's avatar
 
Dries committed
205
function import_get_bundle($bid) {
206 207 208
  return db_fetch_array(db_query("SELECT * FROM bundle WHERE bid = '". check_input($bid) ."'"));
}

Dries's avatar
 
Dries committed
209
function import_view_feed() {
210 211
  $result = db_query("SELECT f.*, COUNT(i.iid) AS items FROM feed f LEFT JOIN item i ON f.fid = i.fid GROUP BY f.fid ORDER BY f.title");

Dries's avatar
 
Dries committed
212
  $output .= "<H3>Feed overview</H3>";
213
  $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n";
Dries's avatar
 
Dries committed
214
  $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>items</TH><TH>last update</TH><TH>next update</TH><TH COLSPAN=\"3\">operations</TH></TR>\n";
215
  while ($feed = db_fetch_object($result)) {
216
    $output .= " <TR><TD>". check_output($feed->title) ."</TD><TD>". check_output($feed->attributes) ."</TD><TD>". format_plural($feed->items, "item", "items") ."</TD><TD>". ($feed->timestamp ? format_interval(time() - $feed->timestamp) ." ago" : "never") ."</TD><TD>". ($feed->timestamp ? format_interval($feed->timestamp + $feed->refresh - time()) ." left" : "never") ."</TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$feed->fid\">edit feed</A></TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=remove&id=$feed->fid\">remove items</A></TD><TD><A HREF=\"admin.php?mod=import&type=feed&op=update&id=$feed->fid\">update items</A></TD></TR>\n";
217 218 219 220 221
  }
  $output .= "</TABLE>\n";

  $result = db_query("SELECT * FROM bundle ORDER BY title");

Dries's avatar
 
Dries committed
222
  $output .= "<H3>Bundle overview</H3>";
223 224 225
  $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n";
  $output .= " <TR><TH>title</TH><TH>attributes</TH><TH>operations</TH></TR>\n";
  while ($bundle = db_fetch_object($result)) {
226
    $output .= " <TR><TD>". check_output($bundle->title) ."</TD><TD>". check_output($bundle->attributes) ."</TD><TD><A HREF=\"admin.php?mod=import&type=bundle&op=edit&id=$bundle->bid\">edit bundle</A></TD></TR>\n";
227 228 229 230 231 232
  }
  $output .= "</TABLE>\n";

  return $output;
}

Dries's avatar
 
Dries committed
233
function import_view_item() {
234 235 236 237 238 239 240 241
  global $REQUEST_URI;

  $result = db_query("SELECT i.*, f.title AS feed FROM item i LEFT JOIN feed f ON i.fid = f.fid ORDER BY i.timestamp DESC LIMIT 50");

  $output .= "<FORM ACTION=\"$REQUEST_URI\" METHOD=\"post\">\n";
  $output .= "<TABLE BORDER=\"1\" CELLSPADDING=\"2\" CELLSPACING=\"2\">\n";
  $output .= " <TR><TH>time</TH><TH>feed</TH><TH>item</TH></TR>\n";
  while ($item = db_fetch_object($result)) {
242
    $output .= " <TR><TD VALIGN=\"top\" NOWRAP>". format_date($item->timestamp, "custom", "m/d/y") ."<BR>".format_date($item->timestamp, "custom", "H:i") ."</TD><TD ALIGN=\"center\" VALIGN=\"top\" NOWRAP><A HREF=\"admin.php?mod=import&type=feed&op=edit&id=$item->fid\">". check_output($item->feed) ."</A></TD><TD><A HREF=\"". check_output($item->link) ."\">". check_output($item->title) ."</A>". ($item->description ? "<BR><SMALL><I>". check_output($item->description) ."</I></SMALL>" : "") ."<BR><INPUT TYPE=\"text\" NAME=\"edit[$item->iid]\" VALUE=\"". check_form($item->attributes) ."\" SIZE=\"50\"></TD></TR>\n";
243 244 245 246 247 248 249 250
  }
  $output .= "</TABLE>\n";
  $output .= "<INPUT TYPE=\"submit\" NAME=\"op\" VALUE=\"Save attributes\">\n";
  $output .= "</FORM>\n";

  return $output;
}

Dries's avatar
 
Dries committed
251
function import_admin() {
Dries's avatar
 
Dries committed
252
  global $op, $id, $type, $edit;
Dries's avatar
 
Dries committed
253

Dries's avatar
 
Dries committed
254
  if (user_access("administer news feeds")) {
Dries's avatar
 
Dries committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279

    print "<SMALL><A HREF=\"admin.php?mod=import&type=bundle&op=add\">add new bundle</A> | <A HREF=\"admin.php?mod=import&type=feed&op=add\">add new feed</A> | <A HREF=\"admin.php?mod=import&type=bundle&op=view\">available bundles</A> | <A HREF=\"admin.php?mod=import&type=item&op=view\">available items</A> | <A HREF=\"admin.php?mod=import&op=view\">overview</A> | <A HREF=\"admin.php?mod=import&op=help\">help</A></SMALL><HR>";

    switch($op) {
      case "help":
        print import_help();
        break;
      case "add":
        if ($type == "bundle")
          print import_form_bundle();
        else
          print import_form_feed();
        break;
      case "edit":
        if ($type == "bundle")
          print import_form_bundle(import_get_bundle($id));
        else
          print import_form_feed(import_get_feed($id));
        break;
      case "remove":
        print status(import_remove(import_get_feed($id)));
        print import_view_feed();
        break;
      case "update":
        print status(import_update(import_get_feed($id)));
Dries's avatar
 
Dries committed
280
        print import_view_feed();
Dries's avatar
 
Dries committed
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
        break;
      case "Save attributes":
        print status(import_save_attributes($edit));
        print import_view_item();
        break;
      case "Delete":
        $edit[title] = 0;
        // fall through:
      case "Submit":
        if ($type == "bundle")
          print status(import_save_bundle($edit));
        else
          print status(import_save_feed($edit));
        // fall through:
      default:
        if ($type == "bundle")
          print import_view_bundle();
        else if ($type == "item")
          print import_view_item();
        else
          print import_view_feed();
    }
  }
  else {
    print message_access();
306 307 308 309
  }
}

?>