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