aggregator.module 14.4 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 iid DESC LIMIT $limit");
44 45

    while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
46
      $output .= "<li><a href=\"". check_output($item->link) ."\">". check_output($item->title) ."</a></li>";
47 48
    }

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)) {
Dries's avatar
 
Dries committed
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

Dries's avatar
 
Dries committed
94 95 96
      $items = array_reverse(explode("</item>", $data[0]));

      foreach ($items as $item) {
97
        $t = eregi("<title>(.*)</title>", $item, $title);
Dries's avatar
 
Dries committed
98
        $l = eregi("<link>(.*)</link>", $item, $link);
99 100 101 102
        $a = eregi("<author>(.*)</author>", $item, $author);
        $d = eregi("<description>(.*)</description>", $item, $description);

        if ($l || $t || $a || $d) {
Dries's avatar
 
Dries committed
103
          import_save_item(array(fid => $feed[fid], title => $title[1], link => $link[1], author => $author[1], description => $description[1], attributes => $feed[attributes]));
104 105 106 107 108 109
        }
      }

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

  return "feed '$feed[title]' updated.";
115 116
}

Dries's avatar
 
Dries committed
117
function import_save_item($edit) {
118
  if ($edit[iid] && $edit[title]) {
119
    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]'");
120 121 122 123 124 125
  }
  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]) ."'"))) {
126
      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() ."')");
127 128 129 130
    }
  }
}

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

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

  $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
147
function import_save_bundle($edit) {
148
  if ($edit[bid] && $edit[title]) {
149
    db_query("UPDATE bundle SET title = '". check_input($edit[title]) ."', attributes = '". check_input($edit[attributes]) ."' WHERE bid = '". check_input($edit[bid]) ."'");
150 151 152 153 154
  }
  else if ($edit[bid]) {
    db_query("DELETE FROM bundle WHERE bid = '". check_input($edit[bid]) ."'");
  }
  else {
155
    db_query("INSERT INTO bundle (title, attributes) VALUES ('". check_input($edit[title]) ."', '". check_input($edit[attributes]) ."')");
156
  }
Dries's avatar
 
Dries committed
157 158

  module_rehash_blocks("import");
159 160
}

Dries's avatar
 
Dries committed
161
function import_form_feed($edit = array()) {
162 163 164 165 166
  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
167
  $form .= form_textfield("Link", "link", $edit[link], 50, 128, "The fully-qualified URL of the feed.");
168
  $form .= form_textfield("Attributes", "attributes", $edit[attributes], 50, 128, "A comma-seperated list of keywords describing the feed.");
169 170 171 172 173 174 175 176 177 178 179 180 181
  $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
182
function import_save_feed($edit) {
183
  if ($edit[fid] && $edit[title]) {
184
    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]) ."'");
185 186 187 188 189 190 191
    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 {
192
    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]) ."')");
193 194 195
  }
}

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

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

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

Dries's avatar
 
Dries committed
211
function import_view_feed() {
212 213
  $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
214 215
  $output .= "<h3>Feed overview</h3>";
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
Dries's avatar
 
Dries committed
216
  $output .= " <tr><th>site</th><th>attributes</th><th>items</th><th>last update</th><th>next update</th><th colspan=\"3\">operations</th></tr>\n";
217
  while ($feed = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
218
    $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";
219
  }
Dries's avatar
 
Dries committed
220
  $output .= "</table>\n";
221 222 223

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

Dries's avatar
 
Dries committed
224 225 226
  $output .= "<h3>Bundle overview</h3>";
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
  $output .= " <tr><th>title</th><th>attributes</th><th>operations</th></tr>\n";
227
  while ($bundle = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
228
    $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";
229
  }
Dries's avatar
 
Dries committed
230
  $output .= "</table>\n";
231 232 233 234

  return $output;
}

Dries's avatar
 
Dries committed
235
function import_view_item() {
236 237 238 239
  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");

Dries's avatar
 
Dries committed
240 241 242
  $output .= "<form action=\"$REQUEST_URI\" method=\"post\">\n";
  $output .= "<table border=\"1\" cellpadding=\"2\" cellspacing=\"2\">\n";
  $output .= " <tr><th>time</th><th>feed</th><th>item</th></tr>\n";
243
  while ($item = db_fetch_object($result)) {
Dries's avatar
 
Dries committed
244
    $output .= " <tr><td valign=\"top\" nowrap=\"nowrap\">". format_date($item->timestamp, "custom", "m/d/y") ."<br />".format_date($item->timestamp, "custom", "H:i") ."</td><td align=\"center\" valign=\"top\" nowrap=\"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";
245
  }
Dries's avatar
 
Dries committed
246 247 248
  $output .= "</table>\n";
  $output .= "<input type=\"submit\" name=\"op\" value=\"Save attributes\" />\n";
  $output .= "</form>\n";
249 250 251 252

  return $output;
}

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

Dries's avatar
 
Dries committed
256
  if (user_access("administer news feeds")) {
Dries's avatar
 
Dries committed
257

Dries's avatar
 
Dries committed
258
    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 />";
Dries's avatar
 
Dries committed
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281

    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
282
        print import_view_feed();
Dries's avatar
 
Dries committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307
        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();
308 309 310 311
  }
}

?>