Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
page_rss_feed.inc
1 <?php
17 require_once SQ_CORE_PACKAGE_PATH.'/page/page.inc';
18 require_once SQ_LIB_PATH.'/html_form/html_form.inc';
19 
31 class Page_RSS_Feed extends Page
32 {
33 
34 
41  function __construct($assetid=0)
42  {
43  $this->_ser_attrs = TRUE;
44  parent::__construct($assetid);
45 
46  }//end constructor
47 
48 
59  protected function _getName($short_name=FALSE, $contextid=NULL)
60  {
61  // No context specified, using the current context
62  if ($contextid === NULL) {
63  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
64  }//end if
65 
66  // Obtain the attribute value for Name from the specified Context
67  $values = $GLOBALS['SQ_SYSTEM']->am->getAttributeValuesByName('name', $this->type(), Array($this->id), $contextid);
68  if (empty($values) === TRUE) {
69  return parent::_getName($short_name, $contextid);
70  } else {
71  return $values[$this->id];
72  }
73 
74  }//end _getName()
75 
76 
84  function _getAllowedLinks()
85  {
86  $links = Array();
87  $links[SQ_LINK_NOTICE]['listing_engine'] = Array('card' => 'M', 'exclusive' => FALSE);
88  return $links;
89 
90  }//end _getAllowedLinks()
91 
92 
103  function _createAdditional(&$link)
104  {
105  // set an initial web path
106  $initial_path = strtolower($this->attr('name'));
107  require_once SQ_INCLUDE_PATH.'/general_occasional.inc';
108  $valid_paths = make_valid_web_paths(Array($initial_path));
109  $good_paths = $GLOBALS['SQ_SYSTEM']->am->webPathsInUse($link['asset'], $valid_paths, $this->id, TRUE);
110  return $this->saveWebPaths($good_paths);
111 
112  }//end _createAdditional()
113 
114 
123  function _getAvailableKeywordsOfType($type='')
124  {
125  $keywords = Array();
126  if (empty($type)) return $keywords;
127  $GLOBALS['SQ_SYSTEM']->am->includeAsset($type);
128  $dummy_asset = new $type();
129  $keywords += $dummy_asset->getAvailableKeywords();
130  unset($dummy_asset);
131  return $keywords;
132 
133  }//end _getAvailableKeywordsOfType()
134 
135 
144  function describeLink($linkid)
145  {
146  $link = $GLOBALS['SQ_SYSTEM']->am->getLinkById($linkid);
147  switch (strtolower($link['value'])) {
148  case 'generate_rss' :
149  return translate('listing_engine_asset_link_description');
150  break;
151  default :
152  return parent::describeLink($linkid);
153  break;
154  }
155 
156  }//end describeLink()
157 
158 
182  function printFrontend()
183  {
184  $contextid = $GLOBALS['SQ_SYSTEM']->getContextId();
185 
186  // check http auth if configured to do so
187  if ($this->attr('http_auth') && isset($_SERVER['PHP_AUTH_USER'])) {
188  // spoof normal login
189  $_REQUEST['SQ_ACTION'] = 'login';
190 
191  $_POST['SQ_LOGIN_USERNAME'] = $_SERVER['PHP_AUTH_USER'];
192  $_POST['SQ_LOGIN_PASSWORD'] = $_SERVER['PHP_AUTH_PW'];
193 
194  $_POST['SQ_LOGIN_KEY'] = $GLOBALS['SQ_SYSTEM']->loginKey();
195  $GLOBALS['SQ_SYSTEM']->_processGlobalActions();
196  }
197 
198 
199  // check if read access
200  if (!parent::readAccess()) {
201 
202  ob_start();
203  $GLOBALS['SQ_SYSTEM']->paintLogin(translate('login'), translate('cannot_access_asset', $this->name));
204  $login = ob_get_clean();
205 
206  // handle http authentication
207  if ($this->attr('http_auth')) {
208  header('WWW-Authenticate: Basic realm="'.$this->name.'"');
209  header('HTTP/1.0 401 Unauthorized');
210  }
211  echo $login;
212 
213  return;
214  }
215  // try to get the feed from cache
216  $rss = '';
217  $cm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('cache_manager');
218  $rss = $cm->loadFromCache($this->id, $this->type(), 'ctx'.$contextid);
219 
220  if ($this->charset) {
221  $charset = $this->charset;
222  } else {
223  $charset = SQ_CONF_DEFAULT_CHARACTER_SET;
224  }
225 
226  // if cache returns nothing then build the feed
227  if ($rss !== FALSE) {
228  $rss = unserialize($rss);
229  } else {
230  // get the assets to be listed in the feed
231  $num_assets_as_items = $this->attr('num_assets_as_items');
232  $assets_to_list = Array();
233  $rss_source_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($this->id, SQ_LINK_NOTICE, 'listing_engine', FALSE, 'major', 'generate_rss');
234 
235  if (empty($rss_source_links)) {
236  trigger_error(translate('no_listing_engine_assets_linked'), E_USER_WARNING);
237  return;
238  }
239  foreach ($rss_source_links as $links) {
240  $listing_engine = $GLOBALS['SQ_SYSTEM']->am->getAsset($links['minorid']);
241  $list_of_assets = $listing_engine->getAssetList();
242  $listing_engine->filterAssetList($list_of_assets);
243  $assets_to_list += $list_of_assets;
244  }
245 
246  $channel = $this->attr('channel');
247  $image = $this->attr('image');
248  $items = $this->attr('items');
249 
250  // A feed should consist of both channel and items. If either of them is empty then throw an error
251  // If there are no assets to list then generate a valid empty feed
252  if (empty($channel) || empty($items)) {
253  trigger_error(translate('no_channel_or_items_found'), E_USER_WARNING);
254  return;
255  } else {
256 
257  require_once SQ_FUDGE_PATH.'/rss_feeds/rss_feed_writer.inc';
258  // Create an RSS Feed writer object and set the type and version of the feed to be built
259  $writer = new RSS_Feed_Writer();
260  $type = $this->attr('rss_types');
261  $type = explode('_', $type);
262  $writer->setTypeVersion($type[0], $type[1]);
263 
264  $new_channel = Array();
265  $rss_type = implode('_', $type);
266 
267  // pass the user entered channel array to the _traverseChannel which now converts it into
268  // RSS Feed Writer Class acceptable format
269  $new_channel = $this->_traverseChannel($channel, $rss_type);
270 
271  // check if the user has entered all of the required tags for the channel information
272  $no_errors = $this->validateChannel($new_channel);
273  if (!$no_errors) return;
274 
275  // adding channel info to the writer
276  $writer->addChannel($new_channel);
277 
278  // traverse the image information array in the same way as we did for the channel
279  $new_image = $this->_traverseImage($image);
280 
281  if (!empty($new_image)) {
282  // check if the user has enetered the values for all of the required tags
283  $no_errors = $this->validateImage($new_image);
284  if (!$no_errors) return;
285  // adding image details to the writer
286  $writer->addImage($new_image);
287  }
288 
289  // now we have to add items
290  // Check if the user has eneterd the number of assets that are to be added to the list. If not
291  // then we have to add all the assets to the feed.
292  $new_items = Array();
293  $index = 0;
294  $mm = null;
295  foreach ($assets_to_list as $assetid => $asset_type) {
296  $asset_type = $asset_type[0]['type_code'];
297  foreach ($items as $type => $keywords) {
298  if (!empty($num_assets_as_items)) {
299  if ($index >= $num_assets_as_items) break;
300  }
301 
302  if (strcasecmp($type, $asset_type) == 0) {
303  $asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($assetid);
304  if (!is_null($asset) && ($asset instanceof $asset_type)) {
305  foreach ($keywords as $tag => $keyword) {
306  // if the user enters multiple keywords or some text along with keywords then
307  // we need to pick the keywords and insert the replacements in the entered text.
308  if (strpos($keyword, '%') !== FALSE) {
309  $sub_keywords = Array();
310  require_once SQ_FUDGE_PATH.'/general/text.inc';
311  $sub_keywords = retrieve_keywords_replacements($keyword);
312  $replacements = Array();
313  foreach ($sub_keywords as $key) {
314  $replacements[$key] = $asset->getKeywordReplacement($key);
315  }
316  $replacement = replace_keywords($keyword, $replacements);
317  } else {
318  $replacement = $asset->getKeywordReplacement($keyword);
319  }
320  if (substr($keyword, 0, 15) == 'asset_metadata_') {
321  $metadata_keyword = substr($keyword, 15);
322  if (is_null($mm)) {
323  $mm =& $GLOBALS['SQ_SYSTEM']->getMetadataManager();
324  }
325  // get all the metadata keywords for this asset
326  $metadata_values = $mm->getMetadataFieldValues($assetid, Array($metadata_keyword));
327 
328  foreach ($metadata_values as $field => $value) {
329  $replacement = $value;
330  }
331  }
332  if (strpos($tag, '_') !== FALSE) {
333  $sub_tag = explode('_', $tag);
334  $new_items[$index][$sub_tag[0]]['SUBTAGS'][$sub_tag[1]] = $replacement;
335  } else if (strpos($tag, '.') !== FALSE) {
336  $sub_tag = explode('.', $tag);
337  $new_items[$index][$sub_tag[0]]['ATTRIBUTES'][$sub_tag[1]] = $replacement;
338  } else {
339  $new_items[$index][$tag] = $replacement;
340  }
341  }//end foreach keywords
342  }//end if asset exists
343  $index++;
344  }//end if type and asset_type are equal
345  }//end foreach items
346  }//end foreach assets_to_list
347 
348  $no_errors = $this->validateItems($new_items);
349  if (!$no_errors) return;
350  $writer->addItems($new_items);
351  $rss = $writer->getRSSString(FALSE, $charset);
352  $cm = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('cache_manager');
353  $r = $cm->saveToCache($this->id, $this->type(), 'ctx'.$contextid, serialize($rss));
354  }
355  }
356 
357  header('Content-type: text/xml; charset='.$charset);
358 
359  echo $rss;
360 
361  }//end printFrontend()
362 
363 
373  function _traverseChannel($channel, $rss_type)
374  {
375  // parse the entered channel information and build an array of information in the proper format
376  // For example the channel array now is of the format:
377  /*
378  Array(
379  title => value,
380  description => value,
381  author_name => value,
382  author_email => value,
383  link.href => assetid of the asset whose URL has to be picked up for the value,
384  category.type => value,
385  );
386  */
387  // The above array now gets traversed using the for loop below resulting in an array of the following format
388  /*
389  Array(
390  tag1 => value,
391  tag2 => Array (
392  'SUBTAGS' => Array(
393  subtag1 => value,
394  subtag2 => value,
395  ),
396  ),
397  tag3 => Array (
398  'ATTRIBUTES' => Array(
399  attr1 => value,
400  attr2 => value,
401  )
402  )
403  )
404  */
405  // The example array should get transformed as follows:
406  /*
407  Array(
408  title => value,
409  description => value,
410  author => Array(
411  'SUBTAGS' => Array(
412  name => value,
413  email => value,
414  ),
415  ),
416  link => Array(
417  'ATTRIBUTES' => Array(
418  href => asset url,
419  ),
420  )
421  category => Array(
422  'ATTRIBUTES' => Array(
423  type => value,
424  ),
425  )
426  )
427  */
428  $new_channel = Array();
429  foreach ($channel as $tag => $value) {
430  if (strpos($tag, '_') !== FALSE) {
431  $sub_tag = explode('_', $tag);
432  if ($sub_tag[0] == 'link.href') { // case link.href_text
433  $link_href_tag = explode('.', $sub_tag[0]);
434  $new_channel[$link_href_tag[0]]['ATTRIBUTES'][$link_href_tag[1]] = $value;
435  } else {
436  $new_channel[$sub_tag[0]]['SUBTAGS'][$sub_tag[1]] = $value;
437  }
438  } else if (strpos($tag, '.') !== FALSE) {
439  if ($tag == 'link.href') {
440  if (assert_valid_assetid($value, '', TRUE, FALSE)) {
441  $value = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($value);
442  }
443  }
444  $sub_tag = explode('.', $tag);
445  $new_channel[$sub_tag[0]]['ATTRIBUTES'][$sub_tag[1]] = $value;
446  } else {
447  // converting date values into the respective formats
448  if (in_array($tag, Array('updated', 'pubDate', 'lastBuildDate', 'published'))) {
449  $timestamp = strtotime($value);
450  if (($timestamp == -1) ||($timestamp === FALSE)) {
451  $timestamp = mktime($value);
452  }
453  if ($rss_type == 'rss_2.0') {
454  $value = date('D, j M Y H:i:s O', $timestamp);
455  } else if ($rss_type == 'atom_1.0') {
456  $value = date('Y-m-d', $timestamp).'T'.date('H:i:s', $timestamp).'Z';
457  }
458  } else {
459  if ($tag == 'link') {
460  if (assert_valid_assetid($value, '', TRUE, FALSE)) {
461  $value = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($value);
462  }
463  }
464  }
465  $new_channel[$tag] = $value;
466  }
467  }//end foreach of channel
468  return $new_channel;
469 
470  }//end _traverseChannel()
471 
472 
481  function _traverseImage($image)
482  {
483  $new_image = Array();
484  foreach ($image as $tag => $value) {
485  if (strpos($tag, '_') !== FALSE) {
486  $sub_tag = explode('_', $tag);
487  $new_image[$sub_tag[0]][$sub_tag[1]] = $value;
488  } else {
489  if ($tag == 'link') {
490  if (assert_valid_assetid($value, '', TRUE, FALSE)) {
491  $value = $GLOBALS['SQ_SYSTEM']->am->getAssetURL($value);
492  }
493  }
494  $new_image[$tag] = $value;
495  }
496  } //end foreach where image array is traversed
497  return $new_image;
498 
499  }//end _traverseImage()
500 
501 
510  function validateItems($items=Array())
511  {
512  if (empty($items)) {
513  return TRUE;
514  } else {
515  $required = Array();
516  $rss_type = $this->attr('rss_types');
517  switch ($rss_type) {
518  case 'atom_1.0':
519  $required = Array('id', 'updated', 'title', 'author');
520  break;
521  case 'rss_1.0':
522  $required = Array('link', 'title', 'rdf:about');
523  break;
524  case 'rss_2.0':
525  $required = Array('link', 'title', 'description');
526  break;
527  }
528  foreach ($items as $item) {
529  $keys = array_keys($item);
530  if (in_array('category', $keys)) {
531  $temp = $items['category']['ATTRIBUTUES'];
532  if (!in_array('term', array_keys($temp))) {
533  trigger_error(translate('required_attr_term_unassigned'), E_USER_WARNING);
534  return FALSE;
535  }
536  }
537  if ($rss_type == 'rss_2.0') {
538  if (!in_array('title', $keys)) {
539  if (!in_array('description', $keys)) {
540  trigger_error(translate('required_tag_title_or_description_missing'), E_USER_WARNING);
541  return FALSE;
542  }
543  }
544  continue;
545  }
546  foreach ($required as $req) {
547  if (!in_array($req, $keys)) {
548  trigger_error('Required Tag '.$req.' Is Not Assigned In Items', E_USER_WARNING);
549  return FALSE;
550  }
551  }
552  }
553  return TRUE;
554  }
555 
556  }//end validateItems()
557 
558 
567  function validateChannel($channel=Array())
568  {
569  if (empty($channel)) {
570  trigger_error('Missing Channel Information', E_USER_WARNING);
571  return FALSE;
572  }
573  $required = Array();
574  $rss_type = $this->attr('rss_types');
575  switch ($rss_type) {
576  case 'rss_1.0':
577  $required = Array('title', 'link', 'description', 'rdf:about');
578  break;
579  case 'rss_2.0':
580  $required = Array('title', 'link', 'description');
581  break;
582  case 'atom_1.0':
583  $required = Array('title', 'id', 'updated');
584  }
585  foreach ($required as $tag) {
586  if (!in_array($tag, array_keys($channel))) {
587  trigger_error(translate('required_attribute').' "'.$tag.'" '.translate('missing_for_channel'), E_USER_WARNING);
588  return FALSE;
589  }
590  }
591  return TRUE;
592 
593  }//end validateChannel()
594 
595 
604  function validateImage($image=Array())
605  {
606  if (empty($image)) {
607  trigger_error(translate('missing_image_info'), E_USER_WARNING);
608  return FALSE;
609  }
610  $required = Array();
611  $rss_type = $this->attr('rss_types');
612  switch ($rss_type) {
613  case 'atom_1.0':
614  return TRUE;
615  break;
616  default:
617  $required = Array('title', 'url', 'link');
618  }
619  foreach ($required as $tag) {
620  if (!in_array($tag, array_keys($image))) {
621  trigger_error(translate('required_attribute').' "'.$tag.'" '.translate('missing_for_image'), E_USER_WARNING);
622  return FALSE;
623  }
624  }
625  return TRUE;
626 
627  }//end validateImage()
628 
629 
639  function readAccess($assetids=Array())
640  {
641  if (SQ_IN_LIMBO || SQ_IN_BACKEND) {
642  return parent::readAccess($assetids);
643  }
644  return TRUE;
645 
646  }//end readAccess()
647 
648 
649 }//end class
650 
651 ?>