Parent Directory
|
Revision Log
|
Revision Graph
Updated to drupal 5.x
| 1 | <?php |
| 2 | |
| 3 | // $Id: aggregation.module,v 1.3 2007/02/23 07:08:09 mistknight Exp $ |
| 4 | |
| 5 | /** |
| 6 | * A number of defs to ease naming |
| 7 | */ |
| 8 | define("FEEDS_ARENT_ASSIGNED_TERM_UNDER_ACTIVE_VOCABULARY", 1); |
| 9 | define("FTP_REQUEST_FAILED", 2); |
| 10 | define("HTTP_REQUEST_FAILED", 3); |
| 11 | define("MALFORMED_XML", 4); |
| 12 | define("AGGREGATION_FAILED", 5); |
| 13 | define("EMPTY_IMAGE", 6); |
| 14 | define("COULD_NOT_WRITE_TO_FILE", 7); |
| 15 | |
| 16 | // These two variables are needed to get the etag and/or last modified |
| 17 | |
| 18 | static $etag; |
| 19 | static $last_modified; |
| 20 | |
| 21 | $GLOBALS['aggregation_item_count'] = 0; |
| 22 | |
| 23 | /** |
| 24 | * Implementation of hook_help |
| 25 | */ |
| 26 | function aggregation_help($section) |
| 27 | { |
| 28 | switch ($section) |
| 29 | { |
| 30 | case 'admin/help#aggregation': |
| 31 | $output = '<p>'. t('The aggregation module is a module that is responsible for aggregating any XML feed, custom feeds need a feed_handler. Check the accompanying readme file.') .'</p>'; |
| 32 | $output .= '<p>' .t('Visit the <a href="!admin-settings">settings</a> page to tweak its behavior', array('!admin-settings'=> url('admin/settings/aggregation'))); |
| 33 | return $output; |
| 34 | } |
| 35 | } |
| 36 | |
| 37 | |
| 38 | /** |
| 39 | * Implementation of hook_perm(). |
| 40 | */ |
| 41 | function aggregation_perm() |
| 42 | { |
| 43 | return array('manage aggregation feeds', 'manage aggregation items', 'view aggregation items', |
| 44 | 'manage own feed items'); |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * Implementation of hook_node_info(). |
| 49 | */ |
| 50 | function aggregation_node_info() |
| 51 | { |
| 52 | return array |
| 53 | ( |
| 54 | 'aggregation_feed' => array('name' => t('Feed'), 'module' => 'aggregation_feed', 'description' => t('Represents the feed the site aggregates from. Items are generated from feeds during cron runs.'), 'has_title' => TRUE, 'title_label' => t('Feed name'), 'has_body' => FALSE), |
| 55 | 'aggregation_item' => array('name' => t('Feed Item'), 'module' => 'aggregation_item', 'description' => t('Items are usually auto-generated on cron runs, but this type exists in case you would like to manually add an item.')) |
| 56 | ); |
| 57 | } |
| 58 | |
| 59 | /** |
| 60 | * Implementation of hook_menu(). |
| 61 | * |
| 62 | */ |
| 63 | function aggregation_menu($may_cache) |
| 64 | { |
| 65 | $items = array(); |
| 66 | |
| 67 | if (!$may_cache) |
| 68 | { |
| 69 | $items[] = array( |
| 70 | 'path' => 'admin/settings/aggregation', |
| 71 | 'title' => t('Aggregation'), |
| 72 | 'description' => t('These options control the general behavior of the aggregation module.'), |
| 73 | 'callback' => 'drupal_get_form', |
| 74 | 'callback arguments' => array('aggregation_admin_settings'), |
| 75 | 'access' => user_access('administer site configuration'), |
| 76 | 'type' => MENU_NORMAL_ITEM); |
| 77 | } |
| 78 | |
| 79 | return $items; |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * This is the function that will be called instead of the old hook_settings |
| 84 | */ |
| 85 | function aggregation_admin_settings() |
| 86 | { |
| 87 | $form = array(); |
| 88 | |
| 89 | $vocabs = taxonomy_get_vocabularies('aggregation_feed'); |
| 90 | |
| 91 | foreach ($vocabs AS $vid => $vocab_object) |
| 92 | $vocabs[$vid] = $vocab_object->name; |
| 93 | |
| 94 | $form['aggregation_current_vid'] = array( |
| 95 | '#type' => 'select', |
| 96 | '#title' => t('Please specify the aggregation feed vid to use as meta for aggregation types'), |
| 97 | '#default_value' => variable_get('aggregation_current_vid', -1), |
| 98 | '#options' => $vocabs, |
| 99 | '#description' => t('The vocabularies determine the aggregation\'s parsing types. So change this value if you want to switch from the default vocabulary.'), |
| 100 | '#required' => TRUE |
| 101 | ); |
| 102 | |
| 103 | $form['aggregation_item_time_to_live'] = array( |
| 104 | '#type' => 'textfield', |
| 105 | '#default_value' => variable_get('aggregation_item_time_to_live', 30), |
| 106 | '#required' => TRUE, |
| 107 | '#title' => t('Please specify the number of DAYS an item will live'), |
| 108 | '#description' => t('If aggregation_feed is set to delete old items, this variable will determine the age after which an item will be deleted') |
| 109 | ); |
| 110 | |
| 111 | $form['aggregation_enable_logging'] = array( |
| 112 | '#type' => 'checkbox', |
| 113 | '#default_value' => variable_get('aggregation_enable_logging', 1), |
| 114 | '#title' => t('Log Operations'), |
| 115 | '#description' => t('After moving to production, you may wish to disable this if you feel everything is stable enough. But it\'s recommended you keep it on. Fatal errors will ALWAYS be logged.') |
| 116 | ); |
| 117 | |
| 118 | $form['aggregation_image_to_display'] = array( |
| 119 | '#type' => 'textfield', |
| 120 | '#default_value' => variable_get('aggregation_image_to_display', 'preview'), |
| 121 | '#required' => TRUE, |
| 122 | '#title' => t('Image to display'), |
| 123 | '#description' => t('This is the image size that will be displayed on aggregated items\' node page.') |
| 124 | ); |
| 125 | |
| 126 | $form['aggregation_enable_cron'] = array( |
| 127 | '#type' => 'checkbox', |
| 128 | '#default_value' => variable_get('aggregation_enable_cron', 1), |
| 129 | '#title' => t('Enable Cron'), |
| 130 | '#description' => t('Remove this check if you want to stop aggregation temporarily.') |
| 131 | ); |
| 132 | |
| 133 | $form['aggregation_feeds_to_refresh_per_cron'] = array( |
| 134 | '#type' => 'textfield', |
| 135 | '#default_value' => variable_get('aggregation_feeds_to_refresh_per_cron', 7), |
| 136 | '#required' => TRUE, |
| 137 | '#title' => t('The number of feeds to refresh every cron'), |
| 138 | '#description' => t('This is important if you have many feeds that may slow the site.').'<br />'. |
| 139 | t('All feeds will eventually be processed, so this option will simply slow the process down to alleviate congestion') |
| 140 | ); |
| 141 | |
| 142 | $form['aggregation_feed_refresh_cooldown'] = array( |
| 143 | '#type' => 'textfield', |
| 144 | '#default_value' => variable_get('aggregation_feed_refresh_cooldown', 0), |
| 145 | '#required' => TRUE, |
| 146 | '#title' => t('Time Between Feeds'), |
| 147 | '#description' => t('Does your server die when a refresh occurs? Try setting this IN SECONDS.') |
| 148 | ); |
| 149 | |
| 150 | return system_settings_form($form); |
| 151 | } |
| 152 | |
| 153 | /** |
| 154 | * This function validates the settings form |
| 155 | */ |
| 156 | function aggregation_validate_settings($form) |
| 157 | { |
| 158 | if (!is_numeric($form['aggregation_item_time_to_live'])) |
| 159 | form_set_error('aggregation_item_time_to_live', t('This field must be numeric.')); |
| 160 | |
| 161 | if ($form['aggregation_item_time_to_live'] <= 0) |
| 162 | form_set_error('aggregation_item_time_to_live', t('This field must be a positive number.')); |
| 163 | |
| 164 | if (!is_numeric($form['aggregation_feeds_to_refresh_per_cron'])) |
| 165 | form_set_error('aggregation_feeds_to_refresh_per_cron', t('This field must be numeric.')); |
| 166 | |
| 167 | if ($form['aggregation_feeds_to_refresh_per_cron'] <= 0) |
| 168 | form_set_error('aggregation_feeds_to_refresh_per_cron', t('This field must be a positive number.')); |
| 169 | |
| 170 | if (!is_numeric($form['aggregation_feed_refresh_cooldown'])) |
| 171 | form_set_error('aggregation_feed_refresh_cooldown', t('This field must be numeric.')); |
| 172 | |
| 173 | if ($form['aggregation_feed_refresh_cooldown'] < 0) |
| 174 | form_set_error('aggregation_feed_refresh_cooldown', t('This field must be positive or zero.')); |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * Implementation of hook_cron(). |
| 179 | */ |
| 180 | function aggregation_cron() |
| 181 | { |
| 182 | if (!variable_get('aggregation_enable_cron', TRUE)) |
| 183 | { |
| 184 | watchdog('aggregation', 'You seem to have disabled aggregation from aggregation settings.'); |
| 185 | return; |
| 186 | } |
| 187 | $vid = variable_get('aggregation_current_vid', -1); |
| 188 | if ($vid == -1) |
| 189 | { |
| 190 | watchdog('aggregation', 'For some reason, aggregation\'s vocabulary is not set.'. |
| 191 | 'Try visiting aggregation\'s settings to set it!'); |
| 192 | return; |
| 193 | } |
| 194 | |
| 195 | $max_exec_time = ini_get('max_execution_time'); |
| 196 | $max_exec_time = (int)$max_exec_time; |
| 197 | |
| 198 | if (!ini_get('safe_mode')) |
| 199 | set_time_limit(20 * 60); |
| 200 | |
| 201 | $feeds = db_query_range("SELECT n.nid FROM {aggregation_feed} af, {node} n ". |
| 202 | "WHERE af.nid = n.nid AND af.enabled = 'yes' AND (UNIX_TIMESTAMP() - af.last_refreshed) >= af.refresh_interval * 60 ORDER BY af.last_refreshed", 0, variable_get('aggregation_feeds_to_refresh_per_cron', 7)); |
| 203 | |
| 204 | while ($feed_nid = db_fetch_object($feeds)->nid) |
| 205 | { |
| 206 | db_query("UPDATE {aggregation_feed} SET last_refreshed = %d WHERE nid = %d", time(), $feed_nid); |
| 207 | |
| 208 | $feed = node_load($feed_nid); |
| 209 | aggregation_feed_prepare($feed); |
| 210 | |
| 211 | try { |
| 212 | $GLOBALS['aggregation_item_count'] = $feed->promote_to_frontpage - 1; |
| 213 | |
| 214 | $success = _aggregation_parse($feed, $vid); |
| 215 | |
| 216 | $GLOBALS['aggregation_item_count'] = 0; |
| 217 | |
| 218 | if (is_null($success)) continue; |
| 219 | |
| 220 | if (!$success) |
| 221 | throw new Exception('Something wrong occured during the aggregation process!', AGGREGATION_FAILED); |
| 222 | |
| 223 | if (variable_get('aggregation_enable_logging', TRUE)) |
| 224 | watchdog('aggregation', 'aggregation has finished aggregating items from '.$feed->title); |
| 225 | |
| 226 | // using this instead of node_save for performance reasons |
| 227 | db_query("UPDATE {aggregation_feed} SET etag = '%s', ". |
| 228 | "last_modified = %d, last_refreshed = %d WHERE nid = %d", $feed->etag, |
| 229 | $feed->last_modified, time(), $feed->nid); |
| 230 | |
| 231 | if ($feed->delete_old_items) |
| 232 | { |
| 233 | $items_to_be_deleted = db_query("SELECT n.nid FROM {node} n, ". |
| 234 | "{aggregation_item} ai WHERE n.nid = ai.nid AND ai.fid = %d AND ". |
| 235 | "(UNIX_TIMESTAMP() - n.created) >= %d", $feed->nid, |
| 236 | variable_get('aggregation_item_time_to_live', 30) * 24 * 60 * 60); |
| 237 | |
| 238 | while ($item = db_fetch_object($items_to_be_deleted)) |
| 239 | node_delete($item->nid); |
| 240 | } |
| 241 | } |
| 242 | catch (Exception $e) { |
| 243 | $GLOBALS['aggregation_item_count'] = 0; |
| 244 | watchdog('aggregation', $e->getMessage(), WATCHDOG_ERROR, l(t('view'), "node/$feed->nid")); |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | if (!ini_get('safe_mode') && is_numeric($max_exec_time) && $max_exec_time > 0) |
| 249 | set_time_limit($max_exec_time); |
| 250 | } |
| 251 | |
| 252 | /* Following are the aggregation_feed hooks */ |
| 253 | |
| 254 | /** |
| 255 | * Implementation of hook_access(). |
| 256 | */ |
| 257 | |
| 258 | function aggregation_feed_access($op, $node) |
| 259 | { |
| 260 | return user_access('manage aggregation feeds'); |
| 261 | } |
| 262 | |
| 263 | /** |
| 264 | * Implementation of hook_form(). |
| 265 | */ |
| 266 | |
| 267 | function aggregation_feed_form(&$node, &$param) |
| 268 | { |
| 269 | $form = array(); |
| 270 | |
| 271 | $form['title'] = array ( |
| 272 | '#type' => 'textfield', |
| 273 | '#default_value' => $node->title, |
| 274 | '#required' => TRUE, |
| 275 | '#title' => t(node_get_types('type', 'aggregation_feed')->title_label), |
| 276 | '#description' => t('Enter something descriptive to identify your feed.') |
| 277 | ); |
| 278 | |
| 279 | $form['original_author'] = array( |
| 280 | '#type' => 'textfield', |
| 281 | '#default_value' => $node->original_author, |
| 282 | '#required' => TRUE, |
| 283 | '#title' => t('Original Author'), |
| 284 | '#description' => t('Please specify the original author for the items of this feed.') |
| 285 | ); |
| 286 | |
| 287 | $form['url'] = array ( |
| 288 | '#type' => 'textfield', |
| 289 | '#default_value' => $node->url, |
| 290 | '#required' => TRUE, |
| 291 | '#title' => t('Feed URL'), |
| 292 | '#description' => t('Please provide the feed URL.') |
| 293 | ); |
| 294 | |
| 295 | $form['authentication'] = array ( |
| 296 | '#type' => 'fieldset', |
| 297 | '#title' => t('Authentication Settings'), |
| 298 | '#collapsible' => TRUE, |
| 299 | '#collapsed' => FALSE, |
| 300 | '#tree' => FALSE |
| 301 | ); |
| 302 | |
| 303 | $form['authentication']['username'] = array( |
| 304 | '#type' => 'textfield', |
| 305 | '#default_value' => $node->username, |
| 306 | '#required' => FALSE, |
| 307 | '#description' => t('If your site uses authentication, please specify the username here.'), |
| 308 | '#title' => t('Enter Username') |
| 309 | ); |
| 310 | |
| 311 | $description = t('If your site uses authentication, please specify the password here.'); |
| 312 | |
| 313 | // This indicates we're in edit mode, in which case I'd like to add an additional directive |
| 314 | if ($node->password) |
| 315 | $description .= '<br />'. |
| 316 | t('(leave empty to preserve value)'); |
| 317 | |
| 318 | $form['authentication']['password'] = array( |
| 319 | '#type' => 'password', |
| 320 | '#default_value' => $node->password, |
| 321 | '#required' => FALSE, |
| 322 | '#description' => $description, |
| 323 | '#title' => 'Enter Password' |
| 324 | ); |
| 325 | |
| 326 | $description = t('If your site uses authentication, please retype your password here.'); |
| 327 | |
| 328 | // This indicates we're in edit mode, in which case I'd like to add an additional directive |
| 329 | if ($node->password) |
| 330 | $description .= '<br />'. |
| 331 | t('(leave empty to preserve value)'); |
| 332 | |
| 333 | $form['authentication']['repeat_password'] = array( |
| 334 | '#type' => 'password', |
| 335 | '#default_value' => $node->password, |
| 336 | '#required' => FALSE, |
| 337 | '#description' => $description, |
| 338 | '#title' => t('Retype Your Password') |
| 339 | ); |
| 340 | |
| 341 | $form['refresh_interval'] = array( |
| 342 | '#type' => 'textfield', |
| 343 | '#default_value' => $node->refresh_interval, |
| 344 | '#required' => TRUE, |
| 345 | '#title' => t('Refresh Interval'), |
| 346 | '#description' => t('Please specify the refresh interval IN MINUTES.') |
| 347 | ); |
| 348 | |
| 349 | $form['title_as_guid_interval'] = array( |
| 350 | '#type' => 'textfield', |
| 351 | '#default_value' => $node->title_as_guid_interval ? $node->title_as_guid_interval : 0, |
| 352 | '#required' => TRUE, |
| 353 | '#title' => t('Title as GUID interval'), |
| 354 | '#description' => t('When a feed contains no GUID or image URL, then the title is it\'s guid. This field '. |
| 355 | 'specifies the time period the title is considered as a GUID. If you provide a GUID or image URL then '. |
| 356 | 'this field value is irrelevant. If not, then you can set this to 0 which would prevent any new article '. |
| 357 | 'with the same title from ever entering (unless the old one is deleted) - this could also be achieved by sending '. |
| 358 | 'the title as the GUID - , or you can set it to the time IN HOURS the title will act as a GUID, after which '. |
| 359 | 'any other article still in the feed with the same title will enter the system.') |
| 360 | ); |
| 361 | |
| 362 | $form['enabled'] = array( |
| 363 | '#type' => 'checkbox', |
| 364 | '#default_value' => $node->enabled, |
| 365 | '#title' => t('Enabled'), |
| 366 | '#description' => t('Use this checkbox to enable/disable refreshing this feed.') |
| 367 | ); |
| 368 | |
| 369 | $form['publish_new_items'] = array( |
| 370 | '#type' => 'checkbox', |
| 371 | '#default_value' => $node->publish_new_items, |
| 372 | '#description' => t('Use this checkbox to publish all aggregated feed items.'), |
| 373 | '#title' => t('Publish items') |
| 374 | ); |
| 375 | |
| 376 | $form['aggregate_to_moderation_queue'] = array( |
| 377 | '#type' => 'checkbox', |
| 378 | '#default_value' => $node->aggregate_to_moderation_queue, |
| 379 | '#description' => t('Use this checkbox to send aggregated items to the moderation queue. Weather they appear on the site or not depends on the \'publish items\', not weather they are on the moderation queue.'), |
| 380 | '#title' => t('Add aggregated items to moderation queue') |
| 381 | ); |
| 382 | |
| 383 | $form['sticky_items'] = array( |
| 384 | '#type' => 'checkbox', |
| 385 | '#default_value' => $node->sticky_items, |
| 386 | '#description' => t('All items aggregated from this feed will be sticky.'), |
| 387 | '#title' => t('Sticky items') |
| 388 | ); |
| 389 | |
| 390 | $form['enable_comments_on_articles'] = array( |
| 391 | '#type' => 'checkbox', |
| 392 | '#default_value' => $node->enable_comments_on_articles, |
| 393 | '#description' => t('All aggregated articles will have commenting set to read/write.'), |
| 394 | '#title' => t('Aggregated article comments') |
| 395 | ); |
| 396 | |
| 397 | $form['enable_comments_on_images'] = array( |
| 398 | '#type' => 'checkbox', |
| 399 | '#default_value' => $node->enable_comments_on_images, |
| 400 | '#description' => t('All aggregated images will have commenting set to read/write.'), |
| 401 | '#title' => t('Aggregated images\' comments') |
| 402 | ); |
| 403 | |
| 404 | $form['delete_old_items'] = array( |
| 405 | '#type' => 'checkbox', |
| 406 | '#default_value' => $node->delete_old_items, |
| 407 | '#description' => t('Use this checkbox to delete items older than (n) days, change this value from the settings. Uncheck and items under this feed will never be deleted until this option is turned on.'), |
| 408 | '#title' => t('Delete Old Items') |
| 409 | ); |
| 410 | |
| 411 | $form['promote_to_frontpage'] = array( |
| 412 | '#type' => 'textfield', |
| 413 | '#default_value' => $node->promote_to_frontpage ? $node->promote_to_frontpage : 0, |
| 414 | '#required' => TRUE, |
| 415 | '#title' => t('Promote to frontpage'), |
| 416 | '#description' => t('Please specify the number of articles to promote to the frontpage.') |
| 417 | ); |
| 418 | |
| 419 | $form['item_taxonomies'] = array ( |
| 420 | '#type' => 'fieldset', |
| 421 | '#title' => t('Item Taxonomies'), |
| 422 | '#collapsible' => TRUE, |
| 423 | '#collapsed' => FALSE, |
| 424 | '#tree' => FALSE, |
| 425 | '#description' => t('These taxonomies will be assigned to all items under this feed.') |
| 426 | ); |
| 427 | |
| 428 | $fakeform = array(); |
| 429 | $fakeform['#node'] = new stdClass(); |
| 430 | |
| 431 | if ($node->item_categories) |
| 432 | $fakeform['#node']->taxonomy = $node->item_categories; |
| 433 | |
| 434 | // This part will trick taxonomy into believing it's dealing with an aggregation_item |
| 435 | $fakeform['type']['#value'] = 'aggregation_item'; |
| 436 | $fakeform['#node']->type = 'aggregation_item'; |
| 437 | |
| 438 | taxonomy_form_alter('aggregation_item_node_form', $fakeform); |
| 439 | |
| 440 | $form['item_taxonomies']['item_categories'] = $fakeform['taxonomy']; |
| 441 | |
| 442 | return $form; |
| 443 | } |
| 444 | |
| 445 | /** |
| 446 | * Implementation of hook_validate(). |
| 447 | */ |
| 448 | |
| 449 | function aggregation_feed_validate(&$node) |
| 450 | { |
| 451 | if (!is_numeric($node->refresh_interval) || $node->refresh_interval < 0) |
| 452 | form_set_error('refresh_interval', 'The refresh interval is a numeric value greater than or equal to 0.'); |
| 453 | else if (!is_numeric($node->title_as_guid_interval) || $node->title_as_guid_interval < 0) |
| 454 | form_set_error('title_as_guid_interval', 'The title as GUID interval is a positive numeric or 0.'); |
| 455 | else if (!is_numeric($node->promote_to_frontpage) || $node->promote_to_frontpage < 0) |
| 456 | form_set_error('promote_to_frontpage', 'The number of items to promote to the frontpage is a positive numeric or 0.'); |
| 457 | else if ($node->password != $node->repeat_password) |
| 458 | form_set_error('password', 'Your passwords did not match.'); |
| 459 | } |
| 460 | |
| 461 | /** |
| 462 | * Implementation of hook_submit(). |
| 463 | */ |
| 464 | |
| 465 | function aggregation_feed_submit(&$node) |
| 466 | { |
| 467 | $node->enabled = $node->enabled ? 'yes' : 'no'; |
| 468 | $node->publish_new_items = $node->publish_new_items ? 'yes' : 'no'; |
| 469 | $node->delete_old_items = $node->delete_old_items ? 'yes' : 'no'; |
| 470 | $node->aggregate_to_moderation_queue = $node->aggregate_to_moderation_queue ? 'yes' : 'no'; |
| 471 | $node->sticky_items = $node->sticky_items ? 'yes' : 'no'; |
| 472 | $node->enable_comments_on_articles = $node->enable_comments_on_articles ? 'yes' : 'no'; |
| 473 | $node->enable_comments_on_images = $node->enable_comments_on_images ? 'yes' : 'no'; |
| 474 | $node->etag = ''; |
| 475 | $node->last_modified = 0; |
| 476 | |
| 477 | $node->title = trim($node->title); |
| 478 | $node->original_author = trim($node->original_author); |
| 479 | $node->url = trim($node->url); |
| 480 | $node->username = trim($node->username); |
| 481 | $node->password = trim($node->password); |
| 482 | |
| 483 | $node->item_categories = serialize($node->item_categories); |
| 484 | } |
| 485 | |
| 486 | /** |
| 487 | * Implementation of hook_prepare(). |
| 488 | */ |
| 489 | |
| 490 | function aggregation_feed_prepare(&$node) |
| 491 | { |
| 492 | $node->refresh_interval = $node->refresh_interval ? $node->refresh_interval : 15; |
| 493 | |
| 494 | $node->enabled = $node->enabled ? ($node->enabled == 'yes' ? TRUE : FALSE) : TRUE; |
| 495 | |
| 496 | $node->publish_new_items = $node->publish_new_items ? |
| 497 | ($node->publish_new_items == 'yes' ? TRUE : FALSE) : TRUE; |
| 498 | |
| 499 | $node->delete_old_items = $node->delete_old_items ? |
| 500 | ($node->delete_old_items == 'yes' ? TRUE : FALSE) : FALSE; |
| 501 | |
| 502 | $node->aggregate_to_moderation_queue = $node->aggregate_to_moderation_queue ? |
| 503 | ($node->aggregate_to_moderation_queue == 'yes' ? TRUE : FALSE) : FALSE; |
| 504 | |
| 505 | $node->sticky_items = $node->sticky_items ? ($node->sticky_items == 'yes' ? TRUE : FALSE) : FALSE; |
| 506 | |
| 507 | $node->enable_comments_on_articles = $node->enable_comments_on_articles ? |
| 508 | ($node->enable_comments_on_articles == 'yes' ? TRUE : FALSE) : FALSE; |
| 509 | |
| 510 | $node->enable_comments_on_images = $node->enable_comments_on_images ? |
| 511 | ($node->enable_comments_on_images == 'yes' ? TRUE : FALSE) : FALSE; |
| 512 | |
| 513 | if ($node->item_categories && $node->item_categories != '') |
| 514 | $node->item_categories = unserialize($node->item_categories); |
| 515 | |
| 516 | // There's a specific format needed to reconstruct a form, we're creating it now |
| 517 | if ($node->item_categories) |
| 518 | { |
| 519 | $formatted_item_categories = array(); |
| 520 | if (is_array($node->item_categories)) |
| 521 | { |
| 522 | foreach ($node->item_categories AS $vid => $tids) |
| 523 | { |
| 524 | if (is_array($tids) && count($tids) > 0) |
| 525 | { |
| 526 | foreach ($tids AS $tid => $tid) |
| 527 | if ($tid > 0) |
| 528 | $formatted_item_categories[$tid] = taxonomy_get_term($tid); |
| 529 | } |
| 530 | else if (is_string($tids)) |
| 531 | { |
| 532 | if ($tids > 0) |
| 533 | $formatted_item_categories[$tids] = taxonomy_get_term($tids); |
| 534 | } |
| 535 | } |
| 536 | } |
| 537 | |
| 538 | $node->item_categories = $formatted_item_categories; |
| 539 | } |
| 540 | } |
| 541 | |
| 542 | /** |
| 543 | * Implementation of hook_load(). |
| 544 | */ |
| 545 | |
| 546 | function aggregation_feed_load($node) |
| 547 | { |
| 548 | return db_fetch_object(db_query("SELECT original_author, url, username, password, ". |
| 549 | "refresh_interval, title_as_guid_interval, enabled, publish_new_items, aggregate_to_moderation_queue, ". |
| 550 | "sticky_items, enable_comments_on_articles, enable_comments_on_images, promote_to_frontpage, ". |
| 551 | "delete_old_items, item_categories, etag, last_modified FROM {aggregation_feed} WHERE nid = %d", $node->nid)); |
| 552 | } |
| 553 | |
| 554 | /** |
| 555 | * Implementation of hook_insert(). |
| 556 | */ |
| 557 | |
| 558 | function aggregation_feed_insert($node) |
| 559 | { |
| 560 | db_query("INSERT INTO {aggregation_feed} (nid, original_author, url, username, password, ". |
| 561 | "refresh_interval, title_as_guid_interval, enabled, publish_new_items, aggregate_to_moderation_queue, sticky_items, enable_comments_on_articles, enable_comments_on_images, promote_to_frontpage, delete_old_items, item_categories, etag, last_modified, last_refreshed) VALUES ". |
| 562 | "(%d, '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', %d ,'%s', '%s', '%s', %d, %d)", |
| 563 | $node->nid, $node->original_author, $node->url, $node->username, $node->password, |
| 564 | $node->refresh_interval, $node->title_as_guid_interval, $node->enabled, $node->publish_new_items, |
| 565 | $node->aggregate_to_moderation_queue, $node->sticky_items, $node->enable_comments_on_articles, |
| 566 | $node->enable_comments_on_images, $node->promote_to_frontpage, $node->delete_old_items, $node->item_categories, |
| 567 | '', 0, 0); |
| 568 | } |
| 569 | |
| 570 | /** |
| 571 | * Implementation of hook_update(). |
| 572 | */ |
| 573 | |
| 574 | function aggregation_feed_update($node) |
| 575 | { |
| 576 | if (trim($node->password) != '') |
| 577 | { |
| 578 | db_query("UPDATE {aggregation_feed} SET original_author = '%s', url = '%s', ". |
| 579 | "username = '%s', password = '%s', refresh_interval = %d, title_as_guid_interval = %d, enabled = '%s', ". |
| 580 | "publish_new_items = '%s', aggregate_to_moderation_queue = '%s', sticky_items = '%s', enable_comments_on_articles = '%s', enable_comments_on_images = '%s', promote_to_frontpage = %d, delete_old_items = '%s', item_categories = '%s', ". |
| 581 | "last_modified = %d, last_refreshed = %d WHERE nid = %d", |
| 582 | $node->original_author, $node->url, $node->username, $node->password, |
| 583 | $node->refresh_interval, $node->title_as_guid_interval, $node->enabled, $node->publish_new_items, |
| 584 | $node->aggregate_to_moderation_queue, $node->sticky_items, $node->enable_comments_on_articles, |
| 585 | $node->enable_comments_on_images, $node->promote_to_frontpage, |
| 586 | $node->delete_old_items, $node->item_categories, |
| 587 | ($node->etag && $node->etag != '') ? $node->etag : '', |
| 588 | ($node->last_modified && $node->last_modified != 0) ? $node->last_modified : 0, |
| 589 | 0, $node->nid); |
| 590 | } |
| 591 | else |
| 592 | { |
| 593 | db_query("UPDATE {aggregation_feed} SET original_author = '%s', url = '%s', ". |
| 594 | "username = '%s', refresh_interval = %d, title_as_guid_interval = %d, enabled = '%s', ". |
| 595 | "publish_new_items = '%s', aggregate_to_moderation_queue = '%s', sticky_items = '%s', enable_comments_on_articles = '%s', enable_comments_on_images = '%s', promote_to_frontpage = %d, delete_old_items = '%s', item_categories = '%s', ". |
| 596 | "etag = '%s', last_modified = %d, last_refreshed = %d WHERE nid = %d", |
| 597 | $node->original_author, $node->url, $node->username, |
| 598 | $node->refresh_interval, $node->title_as_guid_interval, $node->enabled, $node->publish_new_items, |
| 599 | $node->aggregate_to_moderation_queue, $node->sticky_items, $node->enable_comments_on_articles, |
| 600 | $node->enable_comments_on_images, $node->promote_to_frontpage, |
| 601 | $node->delete_old_items, $node->item_categories, |
| 602 | ($node->etag && $node->etag != '') ? $node->etag : '', |
| 603 | ($node->last_modified && $node->last_modified != 0) ? $node->last_modified : 0, |
| 604 | 0, $node->nid); |
| 605 | } |
| 606 | |
| 607 | } |
| 608 | |
| 609 | /** |
| 610 | * Implementation of hook_delete(). |
| 611 | */ |
| 612 | |
| 613 | function aggregation_feed_delete(&$node) |
| 614 | { |
| 615 | $items = _aggregation_get_feed_items($node->nid); |
| 616 | |
| 617 | while ($item = db_fetch_object($items)) |
| 618 | node_delete($item->nid); |
| 619 | |
| 620 | db_query("DELETE FROM {aggregation_feed} WHERE nid = %d", $node->nid); |
| 621 | } |
| 622 | |
| 623 | /* Following are the aggregation_item hooks */ |
| 624 | |
| 625 | /** |
| 626 | * Implementation of hook_access(). |
| 627 | */ |
| 628 | |
| 629 | function aggregation_item_access($op, $node) |
| 630 | { |
| 631 | global $user; |
| 632 | |
| 633 | if ($op == 'create') return user_access('manage aggregation items'); |
| 634 | if ($op == 'update' || $op == 'delete') |
| 635 | return (user_access('manage own feed items') && ($user->uid == $node->uid)); |
| 636 | if ($op == 'view') return user_access('view aggregation items'); |
| 637 | } |
| 638 | |
| 639 | /** |
| 640 | * Implementation of hook_form(). |
| 641 | */ |
| 642 | |
| 643 | function aggregation_item_form(&$node, &$param) |
| 644 | { |
| 645 | $form = array(); |
| 646 | |
| 647 | $form['title'] = array ( |
| 648 | '#type' => 'textfield', |
| 649 | '#default_value' => $node->title, |
| 650 | '#required' => TRUE, |
| 651 | '#title' => t(node_get_types('type', 'aggregation_item')->title_label), |
| 652 | '#description' => t('The title of your feed item.') |
| 653 | ); |
| 654 | |
| 655 | $form['teaser'] = array ( |
| 656 | '#type' => 'textarea', |
| 657 | '#default_value' => $node->teaser, |
| 658 | '#required' => FALSE, |
| 659 | '#title' => t('Teaser'), |
| 660 | '#description' => t('This is the article\'s teaser.') |
| 661 | ); |
| 662 | |
| 663 | $form['body'] = array ( |
| 664 | '#type' => 'textarea', |
| 665 | '#default_value' => $node->body, |
| 666 | '#required' => FALSE, |
| 667 | '#title' => t(node_get_types('type', 'aggregation_item')->body_label), |
| 668 | '#description' => t('This is the main body of your article.') |
| 669 | ); |
| 670 | |
| 671 | $form['original_author'] = array( |
| 672 | '#type' => 'textfield', |
| 673 | '#default_value' => $node->original_author, |
| 674 | '#required' => TRUE, |
| 675 | '#title' => t('Original Author'), |
| 676 | '#description' => t('Specify the author of this feed item.'), |
| 677 | ); |
| 678 | |
| 679 | $form['url'] = array ( |
| 680 | '#type' => 'textfield', |
| 681 | '#default_value' => $node->url, |
| 682 | '#required' => FALSE, |
| 683 | '#title' => t('Original URL'), |
| 684 | '#description' => t('Provide the URL of the original article if needed.') |
| 685 | ); |
| 686 | |
| 687 | $form['image_id'] = array ( |
| 688 | '#type' => 'textfield', |
| 689 | '#default_value' => $node->image_id, |
| 690 | '#required' => FALSE, |
| 691 | '#title' => t('Image ID'), |
| 692 | '#description' => t('Provide an image id to attach an image.') |
| 693 | ); |
| 694 | |
| 695 | $description = t('The GUID is a unique string that distingishes your article from '. |
| 696 | 'all others and prevents a second aggregation. Please provide it if available.'); |
| 697 | |
| 698 | // This indicates we're in edit mode, in which case I'd like to add an additional directive |
| 699 | if ($node->story_guid) |
| 700 | $description .= '<br />'. |
| 701 | t('(leave empty to preserve value)'); |
| 702 | |
| 703 | $form['story_guid'] = array ( |
| 704 | '#type' => 'textfield', |
| 705 | '#default_value' => '', |
| 706 | '#required' => FALSE, |
| 707 | '#title' => t('GUID'), |
| 708 | '#description' => $description |
| 709 | ); |
| 710 | |
| 711 | $feeds = db_query('SELECT n.nid, n.title FROM {node} n, {aggregation_feed} af '. |
| 712 | 'WHERE n.nid = af.nid'); |
| 713 | |
| 714 | if (db_num_rows($feeds) != 0) |
| 715 | { |
| 716 | $feed_array = array(); |
| 717 | |
| 718 | $feed_array[0] = '<none>'; |
| 719 | |
| 720 | while ($feed = db_fetch_object($feeds)) |
| 721 | $feed_array[$feed->nid] = $feed->title; |
| 722 | |
| 723 | $form['fid'] = array ( |
| 724 | '#type' => 'select', |
| 725 | '#default_value' => $node->fid, |
| 726 | '#required' => TRUE, |
| 727 | '#title' => t('Source Feed'), |
| 728 | '#description' => t('Provide the source feed if valid for this item.'), |
| 729 | '#options' => $feed_array |
| 730 | ); |
| 731 | } |
| 732 | |
| 733 | return $form; |
| 734 | } |
| 735 | |
| 736 | /** |
| 737 | * Implementation of hook_validate(). |
| 738 | */ |
| 739 | |
| 740 | function aggregation_item_validate(&$node) |
| 741 | { |
| 742 | if (trim($node->image_id) != '') |
| 743 | { |
| 744 | if (!is_numeric($node->image_id)) |
| 745 | form_set_error('image_id', 'The image id must be numeric.'); |
| 746 | // A node load is simply too costly, so I'm going to directly query instead. |
| 747 | else if ($node->image_id != 0 && db_fetch_object(db_query("SELECT COUNT(n.nid) AS image_count FROM {node} n ". |
| 748 | "WHERE n.nid = %d AND n.type = 'image'", $node->image_id))->image_count == 0) |
| 749 | form_set_error('image_id', 'This image ID seems to be incorrect!'); |
| 750 | } |
| 751 | } |
| 752 | |
| 753 | /** |
| 754 | * Implementation of hook_submit(). |
| 755 | */ |
| 756 | |
| 757 | function aggregation_item_submit(&$node) |
| 758 | { |
| 759 | if (!$node->fid) |
| 760 | $node->fid = 0; |
| 761 | |
| 762 | if ($node->image_id == '') |
| 763 | $node->image_id = 0; |
| 764 | |
| 765 | if (trim($node->story_guid) != '') |
| 766 | $node->story_guid = crc32($node->story_guid); |
| 767 | else |
| 768 | $node->story_guid = ''; |
| 769 | } |
| 770 | |
| 771 | /** |
| 772 | * Implementation of hook_prepare(). |
| 773 | */ |
| 774 | |
| 775 | function aggregation_item_prepare(&$node) |
| 776 | { |
| 777 | |
| 778 | } |
| 779 | |
| 780 | /** |
| 781 | * Implementation of hook_load(). |
| 782 | */ |
| 783 | |
| 784 | function aggregation_item_load($node) |
| 785 | { |
| 786 | return db_fetch_object(db_query('SELECT url, original_author, story_guid, '. |
| 787 | 'fid, image_id, image_guid FROM {aggregation_item} WHERE nid = %d', $node->nid)); |
| 788 | } |
| 789 | |
| 790 | /** |
| 791 | * Implementation of hook_insert(). |
| 792 | */ |
| 793 | |
| 794 | function aggregation_item_insert($node) |
| 795 | { |
| 796 | db_query("INSERT INTO {aggregation_item} (nid, url, original_author, ". |
| 797 | "story_guid, fid, image_id, image_guid) VALUES (%d, '%s', '%s', %d, %d, ". |
| 798 | "%d, %d)", $node->nid, $node->url, $node->original_author, $node->story_guid, $node->fid, $node->image_id, $node->image_guid ? $node->image_guid : 0); |
| 799 | } |
| 800 | |
| 801 | /** |
| 802 | * Implementation of hook_update(). |
| 803 | */ |
| 804 | |
| 805 | function aggregation_item_update($node) |
| 806 | { |
| 807 | if ($node->story_guid === '') |
| 808 | db_query("UPDATE {aggregation_item} SET url = '%s', original_author = '%s', ". |
| 809 | "fid = %d, image_id = %d, image_guid = %d ". |
| 810 | "WHERE nid = %d", $node->url, $node->original_author, $node->fid, $node->image_id, |
| 811 | $node->image_guid ? $node->image_guid : 0, $node->nid); |
| 812 | else |
| 813 | db_query("UPDATE {aggregation_item} SET url = '%s', original_author = '%s', ". |
| 814 | "story_guid = %d, fid = %d, image_id = %d, image_guid = %d ". |
| 815 | "WHERE nid = %d", $node->url, $node->original_author, $node->story_guid, $node->fid, |
| 816 | $node->image_id, $node->image_guid ? $node->image_guid : 0, $node->nid); |
| 817 | } |
| 818 | |
| 819 | /** |
| 820 | * Implementation of hook_delete(). |
| 821 | */ |
| 822 | |
| 823 | function aggregation_item_delete(&$node) |
| 824 | { |
| 825 | if (db_fetch_object(db_query( |
| 826 | "SELECT count(nid) AS image_count FROM {aggregation_item} WHERE image_id = %d", $node->image_id)) |
| 827 | ->image_count == 1) node_delete($node->image_id); |
| 828 | |
| 829 | db_query("UPDATE {aggregation_feed} SET etag = '', last_modified = 0 WHERE nid = %d", $node->fid); |
| 830 | |
| 831 | db_query('DELETE FROM {aggregation_item} WHERE nid = %d', $node->nid); |
| 832 | } |
| 833 | |
| 834 | /** |
| 835 | * This function is the implementation of hook_view |
| 836 | */ |
| 837 | |
| 838 | function aggregation_item_view(&$node, $teaser = FALSE, $page = FALSE) |
| 839 | { |
| 840 | if ($node->image_id > 0) |
| 841 | { |
| 842 | $image = node_load($node->image_id); |
| 843 | $node->image = $image; |
| 844 | |
| 845 | // theme image |
| 846 | $image_render = theme('aggregation_image_render', $image); |
| 847 | } |
| 848 | else |
| 849 | { |
| 850 | $node->image_nid = NULL; |
| 851 | $node->image = NULL; |
| 852 | |
| 853 | $image_render = ''; |
| 854 | } |
| 855 | |
| 856 | // theme body |
| 857 | $body_render = theme('aggregation_body_render', $node->body); |
| 858 | |
| 859 | // theme the final item |
| 860 | $node->content['body']['#value'] = theme('aggregation_item_render', $image_render, $body_render); |
| 861 | |
| 862 | return $node; |
| 863 | |
| 864 | } |
| 865 | |
| 866 | function theme_aggregation_item_render($image_render, $body_render) |
| 867 | { |
| 868 | return "<div class=\"aggregation_item\">{$image_render}{$body_render}</div>"; |
| 869 | } |
| 870 | |
| 871 | function theme_aggregation_body_render($body) |
| 872 | { |
| 873 | return '<div class="aggregation_item_body">'.$body.'</div>'; |
| 874 | } |
| 875 | |
| 876 | function theme_aggregation_image_render($image) |
| 877 | { |
| 878 | return '<div class="aggregation_item_image">'.'<img src="'.base_path().file_directory_path().'/'.$image->images[variable_get('aggregation_image_to_display', 'preview')].'" />'. |
| 879 | '</div>'; |
| 880 | } |
| 881 | |
| 882 | /* Following are the module's private methods */ |
| 883 | |
| 884 | /** |
| 885 | * This function returns the feed items for a particular feed |
| 886 | */ |
| 887 | |
| 888 | function _aggregation_get_feed_items($fid) |
| 889 | { |
| 890 | return db_query("SELECT n.nid FROM {node} n, {aggregation_item} ai WHERE n.nid = ai.nid AND ai.fid = %d", $fid); |
| 891 | } |
| 892 | |
| 893 | /** |
| 894 | * This method retrieved the etag and last_modified tags |
| 895 | */ |
| 896 | |
| 897 | function read_etag_and_modified($ch, $header) |
| 898 | { |
| 899 | global $etag; |
| 900 | global $last_modified; |
| 901 | |
| 902 | $length = strlen($header); |
| 903 | if(strstr($header, "Last-Modified:")) |
| 904 | { |
| 905 | $last_modified = strtotime(substr($header, 15)); |
| 906 | } |
| 907 | if (strstr($header, "ETag:")) |
| 908 | { |
| 909 | $etag = substr($header, 6); |
| 910 | } |
| 911 | return $length; |
| 912 | } |
| 913 | |
| 914 | /** |
| 915 | * This function returns the data in a URL (XML, image, etc...) |
| 916 | */ |
| 917 | function aggregation_get_URL($url, $username = NULL, $password = NULL, $feed = NULL, |
| 918 | $feed_etag = NULL, $feed_last_modified = NULL) |
| 919 | { |
| 920 | global $etag; |
| 921 | global $last_modified; |
| 922 | |
| 923 | if (trim($username) == '') $username = NULL; |
| 924 | if (trim($password) == '') $password = NULL; |
| 925 | |
| 926 | $headers = array(); |
| 927 | |
| 928 | if (!is_null($feed_etag) && $feed_etag != '') |
| 929 | $headers['If-None-Match'] = $feed_etag; |
| 930 | |
| 931 | if (!is_null($feed_last_modified) && $feed_last_modified != 0) |
| 932 | $headers['If-Modified-Since'] = gmdate('D, d M Y H:i:s', $feed_last_modified) .' GMT'; |
| 933 | |
| 934 | if(count($headers) > 0) |
| 935 | { |
| 936 | $temp = array(); |
| 937 | |
| 938 | foreach ($headers as $header => $value) |
| 939 | $temp[] = $header .': '. $value; |
| 940 | |
| 941 | $headers = $temp; |
| 942 | } |
| 943 | |
| 944 | $ch = curl_init(); |
| 945 | |
| 946 | $is_ftp = FALSE; |
| 947 | |
| 948 | if (stripos($url, 'ftp://') !== FALSE) |
| 949 | $is_ftp = TRUE; |
| 950 | |
| 951 | if (!$is_ftp) |
| 952 | curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)"); |
| 953 | |
| 954 | if (is_array($headers) && count($headers) > 0 && !$is_ftp) |
| 955 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); |
| 956 | |
| 957 | if (!$is_ftp) |
| 958 | curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_etag_and_modified'); |
| 959 | |
| 960 | if (!$is_ftp) |
| 961 | { |
| 962 | curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); |
| 963 | curl_setopt($ch, CURLOPT_MAXREDIRS, 5); |
| 964 | } |
| 965 | |
| 966 | if (!is_null($username) && !is_null($password)) |
| 967 | { |
| 968 | curl_setopt($ch, CURLOPT_USERPWD, "$username:$password"); |
| 969 | if (!$is_ftp) |
| 970 | curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_ANY); |
| 971 | } |
| 972 | curl_setopt($ch, CURLOPT_URL, $url); |
| 973 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); |
| 974 | if ($is_ftp) |
| 975 | curl_setopt($ch, CURLOPT_FTP_USE_EPSV, FALSE); |
| 976 | curl_setopt($ch, CURLOPT_TIMEOUT, 15); |
| 977 | $data = curl_exec($ch); |
| 978 | |
| 979 | $return_code = curl_getinfo($ch); |
| 980 | $return_code = $return_code['http_code']; |
| 981 | |
| 982 | $error = curl_error($ch); |
| 983 | |
| 984 | curl_close($ch); |
| 985 | unset($ch); |
| 986 | |
| 987 | if ($return_code != 304) |
| 988 | { |
| 989 | // It was an FTP request but failed |
| 990 | if ($is_ftp && $return_code != 226) |
| 991 | { |
| 992 | $fragment = ''; |
| 993 | |
| 994 | if (!is_null($feed)) |
| 995 | $fragment = " while processing feed \"$feed->title\""; |
| 996 | |
| 997 | throw new Exception("FTP request returned error code \"$return_code\"". |
| 998 | "$fragment on \"$url\"", FTP_REQUEST_FAILED); |
| 999 | } |
| 1000 | |
| 1001 | // It was an HTTP request but failed |
| 1002 | if (!$is_ftp && $return_code != 200) |
| 1003 | { |
| 1004 | $fragment = ''; |
| 1005 | |
| 1006 | if (!is_null($feed)) |
| 1007 | $fragment = " while processing feed \"$feed->title\""; |
| 1008 | |
| 1009 | throw new Exception("HTTP request returned error code \"$return_code\"". |
| 1010 | "$fragment on \"$url\"", HTTP_REQUEST_FAILED); |
| 1011 | } |
| 1012 | } |
| 1013 | else |
| 1014 | return FALSE; |
| 1015 | |
| 1016 | if (!is_null($feed_etag) && !is_null($feed_last_modified)) |
| 1017 | return array($data, $etag, $last_modified); |
| 1018 | |
| 1019 | return $data; |
| 1020 | } |
| 1021 | |
| 1022 | /** |
| 1023 | * This function returns the simpleXML object of a given string, or throws an exception |
| 1024 | * if the string is in an invalid XML format |
| 1025 | */ |
| 1026 | function aggregation_get_XML($string, $feed = NULL) |
| 1027 | { |
| 1028 | @ $xml = simplexml_load_string($string, NULL, LIBXML_NOERROR | LIBXML_NOWARNING); |
| 1029 | |
| 1030 | // We got a malformed XML |
| 1031 | if ($xml === FALSE) |
| 1032 | { |
| 1033 | $fragment = ''; |
| 1034 | |
| 1035 | if (!is_null($feed)) |
| 1036 | $fragment = " while processing feed \"$feed->title\""; |
| 1037 | |
| 1038 | throw new Exception("XML malformed$fragment", MALFORMED_XML); |
| 1039 | } |
| 1040 | |
| 1041 | return $xml; |
| 1042 | } |
| 1043 | |
| 1044 | /* This is where we'll implement the handler functions */ |
| 1045 | |
| 1046 | /** |
| 1047 | * This is the generic feed XML handler, it calls the user implemented handler, it is meant as |
| 1048 | * a wrapper to the actual call |
| 1049 | */ |
| 1050 | function _aggregation_parse($feed, $vid) |
| 1051 | { |
| 1052 | $handler_name = ''; |
| 1053 | |
| 1054 | foreach ($feed->taxonomy AS $tid => $term_object) |
| 1055 | if ($term_object->vid == $vid) |
| 1056 | { |
| 1057 | $handler_name = $term_object->name; |
| 1058 | break; |
| 1059 | } |
| 1060 | |
| 1061 | if ($handler_name == '') |
| 1062 | throw new Exception('Did you change the vocabulary name without re-assigning the feeds?', |
| 1063 | FEEDS_ARENT_ASSIGNED_TERM_UNDER_ACTIVE_VOCABULARY); |
| 1064 | |
| 1065 | $data = aggregation_get_URL($feed->url, $feed->username, $feed->password, $feed, |
| 1066 | $feed->etag, $feed->last_modified); |
| 1067 | |
| 1068 | if ($data === FALSE) |
| 1069 | { |
| 1070 | watchdog('aggregation', t("Feed \"%s\" was not modified since last refresh", array('%s' => $feed->title))); |
| 1071 | return NULL; |
| 1072 | } |
| 1073 | |
| 1074 | $feed->etag = $data[1]; |
| 1075 | $feed->last_modified = $data[2]; |
| 1076 | $data = $data[0]; |
| 1077 | |
| 1078 | $feed_xml = aggregation_get_XML($data, $feed); |
| 1079 | |
| 1080 | require_once(drupal_get_path('module', 'aggregation')."/feed_handlers/$handler_name.inc"); |
| 1081 | |
| 1082 | try { |
| 1083 | call_user_func_array('_aggregation_'.$handler_name.'_parse', array($feed_xml, $feed)); |
| 1084 | } catch (Exception $e) { |
| 1085 | throw new Exception('Check your feed_handler! Also consider handling the exception in your code: <br />'. |
| 1086 | 'All items after the exception have been skipped! Internal handling would prevent this.<br />'. |
| 1087 | 'If you catch an exception, please save the object and throw it when you\'re done to preserve logging.<br >'. |
| 1088 | $e->getMessage(), $e->getCode()); |
| 1089 | } |
| 1090 | db_query("UPDATE {aggregation_feed} SET last_refreshed = %d WHERE nid = %d", time(), $feed->nid); |
| 1091 | return TRUE; |
| 1092 | } |
| 1093 | |
| 1094 | /** |
| 1095 | * This internal function is responsible for adding items |
| 1096 | */ |
| 1097 | function _aggregation_add_item($title, $body, $teaser, $original_author, $feed, |
| 1098 | $additional_taxonomies, $timestamp = NULL, $original_item_url = NULL, $guid = NULL, |
| 1099 | $image_array = NULL) |
| 1100 | { |
| 1101 | if (!is_null($title)) $title = trim($title); |
| 1102 | if (!is_null($body)) $body = trim($body); |
| 1103 | if (!is_null($teaser)) $teaser = trim($teaser); |
| 1104 | if (!is_null($original_author)) $original_author = trim($original_author); |
| 1105 | if (!is_null($original_item_url)) $original_item_url = trim($original_item_url); |
| 1106 | if (!is_null($guid)) $guid = trim($guid); |
| 1107 | |
| 1108 | if (is_array($image_array)) |
| 1109 | { |
| 1110 | if (!is_null($image_array['url'])) $image_array['url'] = trim($image_array['url']); |
| 1111 | if (!$image_array['url'] || empty($image_array['url'])) |
| 1112 | $image_array = NULL; |
| 1113 | else |
| 1114 | { |
| 1115 | if (!is_null($image_array['title'])) $image_array['title'] = trim($image_array['title']); |
| 1116 | if (!is_null($image_array['guid'])) $image_array['guid'] = trim($image_array['guid']); |
| 1117 | if (!is_null($image_array['teaser'])) $image_array['teaser'] = trim($image_array['teaser']); |
| 1118 | if (!is_null($image_array['body'])) $image_array['body'] = trim($image_array['body']); |
| 1119 | if (!is_null($image_array['url'])) $image_array['url'] = trim($image_array['url']); |
| 1120 | |
| 1121 | if (is_null($image_array['title']) || empty($image_array['title'])) |
| 1122 | $image_array['title'] = $title; |
| 1123 | |
| 1124 | if (is_null($image_array['guid']) || empty($image_array['guid'])) |
| 1125 | $image_array['guid'] = $image_array['url']; |
| 1126 | |
| 1127 | if (is_null($image_array['body']) || empty($image_array['body'])) |
| 1128 | $image_array['body'] = $image_array['title']; |
| 1129 | |
| 1130 | if (is_null($image_array['teaser']) || empty($image_array['teaser'])) |
| 1131 | $image_array['teaser'] = $image_array['title']; |
| 1132 | |
| 1133 | if (is_null($image_array['timestamp'])) |
| 1134 | $image_array['timestamp'] = time(); |
| 1135 | |
| 1136 | if (is_null($guid) || empty($guid)) |
| 1137 | $guid = $image_array['url']; |
| 1138 | } |
| 1139 | } |
| 1140 | |
| 1141 | if (!is_null($guid) && !empty($guid)) // check item exists by checking GUID |
| 1142 | { |
| 1143 | if (db_fetch_object(db_query("SELECT COUNT(nid) AS node_count FROM {aggregation_item} ". |
| 11 |