コード例 #1
0
ファイル: layout_images_as_feed.php プロジェクト: rair/yacs
 /**
  * list images
  *
  * @param resource the SQL result
  * @return string the rendered text
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // empty list
     if (!SQL::count($result)) {
         $output = array();
         return $output;
     }
     // we return an array of ($url => $attributes)
     $items = array();
     // process all items in the list
     while ($item = SQL::fetch($result)) {
         // get the anchor for this image
         if ($item['anchor']) {
             $anchor = Anchors::get($item['anchor']);
         }
         // url to view the image
         $url = $context['url_to_home'] . $context['url_to_root'] . Images::get_url($item['id']);
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // the title as the label
         if ($item['title']) {
             $label = ucfirst($item['title']) . ' (' . $item['image_name'] . ')';
         } else {
             $label = $item['image_name'];
         }
         // the section
         $section = '';
         if (is_object($anchor)) {
             $section = ucfirst($anchor->get_title());
         }
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author = $item['create_address'] . ' (' . $item['create_name'] . ')';
         if ($item['create_address'] != $item['edit_address']) {
             if ($author) {
                 $author .= ', ';
             }
             $author .= $item['edit_address'] . ' (' . $item['edit_name'] . ')';
         }
         // the description
         $description = Codes::beautify($item['description']);
         // cap the number of words
         $description = Skin::cap($description, 300);
         // fix image references
         $description = preg_replace('#"/([^">]+?)"#', '"' . $context['url_to_home'] . '/$1"', $description);
         $introduction = $description;
         // other rss fields
         $extensions = array();
         // url for enclosure
         $type = Files::get_mime_type($item['image_name']);
         $extensions[] = '<enclosure url="' . $context['url_to_home'] . $context['url_to_root'] . Files::get_path($item['anchor'], 'images') . '/' . $item['image_name'] . '"' . ' length="' . $item['image_size'] . '"' . ' type="' . $type . '" />';
         // list all components for this item
         $items[$url] = array($time, $label, $author, $section, NULL, $introduction, $description, $extensions);
     }
     // end of processing
     SQL::free($result);
     return $items;
 }
コード例 #2
0
ファイル: layout_dates_as_ics.php プロジェクト: rair/yacs
 /**
  * list dates
  *
  * @param resource the SQL result
  * @return string the rendered text
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // build the calendar
     $text = 'BEGIN:VCALENDAR' . CRLF . 'VERSION:2.0' . CRLF . 'PRODID:YACS' . CRLF . 'METHOD:PUBLISH' . CRLF;
     // organization, if any
     if (isset($context['site_name']) && $context['site_name']) {
         $text .= 'X-WR-CALNAME:' . $context['site_name'] . CRLF;
     }
     // process all items in the list
     while ($item = SQL::fetch($result)) {
         // one event at a time
         $text .= 'BEGIN:VEVENT' . CRLF;
         // the event spans limited time
         if (isset($item['duration']) && $item['duration']) {
             $text .= 'DTSTART:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($item['date_stamp'])) . CRLF;
             $text .= 'DTEND:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($item['date_stamp']) + $item['duration'] * 60) . CRLF;
             // a full-day event
         } else {
             $text .= 'DTSTART;VALUE=DATE:' . date('Ymd', SQL::strtotime($item['date_stamp'])) . CRLF;
             $text .= 'DTEND;VALUE=DATE:' . date('Ymd', SQL::strtotime($item['date_stamp']) + 86400) . CRLF;
         }
         // url to view the date
         $text .= 'URL:' . Articles::get_permalink($item) . CRLF;
         // organization, if any
         if (isset($item['introduction']) && $item['introduction']) {
             $text .= 'DESCRIPTION:' . str_replace(array("\n", "\r"), ' ', strip_tags($item['introduction'])) . CRLF;
         }
         // build a valid title
         if (isset($item['title']) && $item['title']) {
             $text .= 'SUMMARY:' . Codes::beautify_title($item['title']) . CRLF;
         }
         // required by Outlook 2003
         if (isset($item['id']) && $item['id']) {
             $text .= 'UID:' . $item['id'] . CRLF;
         }
         // date of creation
         if (isset($item['create_date']) && $item['create_date']) {
             $text .= 'CREATED:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($item['create_date'])) . CRLF;
         }
         // date of last modification
         if (isset($item['edit_date']) && $item['edit_date']) {
             $text .= 'DTSTAMP:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($item['edit_date'])) . CRLF;
         }
         // next event
         $text .= 'SEQUENCE:0' . CRLF . 'END:VEVENT' . CRLF;
     }
     // date of last update
     $text .= 'END:VCALENDAR' . CRLF;
     // end of processing
     SQL::free($result);
     return $text;
 }
コード例 #3
0
ファイル: layout_links_as_feed.php プロジェクト: rair/yacs
 /**
  * list links
  *
  * @param resource the SQL result
  * @return array of resulting items, or NULL
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // we return an array of ($url => $attributes)
     $items = array();
     // empty list
     if (!SQL::count($result)) {
         return $items;
     }
     // process all items in the list
     while ($item = SQL::fetch($result)) {
         // get the anchor for this link
         if ($item['anchor']) {
             $anchor = Anchors::get($item['anchor']);
         }
         // url is the link itself
         $url = $item['link_url'];
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // the title as the label
         if ($item['title']) {
             $label = $item['title'];
         } else {
             $label = $url;
         }
         // the section
         $section = '';
         if (is_object($anchor)) {
             $section = ucfirst($anchor->get_title());
         }
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author = $item['edit_address'] . ' (' . $item['edit_name'] . ')';
         // the description
         $description = Codes::beautify($item['description']);
         // cap the number of words
         $description = Skin::cap($description, 300);
         // fix image references
         $description = preg_replace('#"/([^">]+?)"#', '"' . $context['url_to_home'] . '/$1"', $description);
         $introduction = $description;
         // other rss fields
         $extensions = array();
         // list all components for this item
         $items[$url] = array($time, $label, $author, $section, NULL, $introduction, $description, $extensions);
     }
     // end of processing
     SQL::free($result);
     return $items;
 }
コード例 #4
0
ファイル: layout_users_as_feed.php プロジェクト: rair/yacs
 /**
  * list users
  *
  * @param resource the SQL result
  * @return string the rendered text
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // empty list
     if (!SQL::count($result)) {
         $output = array();
         return $output;
     }
     // we return an array of ($url => $attributes)
     $items = array();
     // process all items in the list
     while ($item = SQL::fetch($result)) {
         // url to view the user profile
         $url = Users::get_permalink($item);
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // item title
         if ($item['full_name']) {
             $label = ucfirst(Skin::strip($item['full_name'], 10));
         } else {
             $label = ucfirst(Skin::strip($item['nick_name'], 10));
         }
         // the section
         $section = '';
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author .= $item['edit_address'] . ' (' . $item['edit_name'] . ')';
         // introduction
         $introduction = Codes::beautify($item['introduction']);
         // the description
         $description = Codes::beautify($item['description']);
         // cap the number of words
         $description = Skin::cap($description, 300);
         // fix image references
         $description = preg_replace('#"/([^">]+?)"#', '"' . $context['url_to_home'] . '/$1"', $description);
         // other rss fields
         $extensions = array();
         // list all components for this item
         $items[$url] = array($time, $label, $author, $section, $icon, $introduction, $description, $extensions);
     }
     // end of processing
     SQL::free($result);
     return $items;
 }
コード例 #5
0
ファイル: article.php プロジェクト: rair/yacs
 /**
  * remember the last action for this article
  *
  * This function is called by related items. What does it do?
  * - On image creation, the adequate code is added to the description field to let the image be displayed inline
  * - On icon selection, the icon field is updated
  * - On thumbnail image selection, the thumbnail image field is updated
  * - On location creation, some code is inserted in the description field to display location name inline
  * - On table creation, some code is inserted in the description field to display the table inline
  *
  * @see articles/article.php
  * @see articles/edit.php
  * @see shared/anchor.php
  *
  * @param string one of the pre-defined action code
  * @param string the id of the item related to this update
  * @param boolean TRUE to not change the edit date of this anchor, default is FALSE
  */
 function touch($action, $origin = NULL, $silently = FALSE)
 {
     global $context;
     // we make extensive use of comments below
     include_once $context['path_to_root'] . 'comments/comments.php';
     // don't go further on import
     if (preg_match('/import$/i', $action)) {
         return;
     }
     // no article bound
     if (!isset($this->item['id'])) {
         return;
     }
     // delegate to overlay
     if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) {
         return;
         // stop on false
     }
     // clear floating objects
     if ($action == 'clear') {
         $this->item['description'] .= ' [clear]';
         $query = "UPDATE " . SQL::table_name('articles') . " SET description='" . SQL::escape($this->item['description']) . "'" . " WHERE id = " . SQL::escape($this->item['id']);
         SQL::query($query);
         return;
     }
     // get the related overlay, if any
     if (!isset($this->overlay)) {
         $this->overlay = NULL;
         if (isset($this->item['overlay'])) {
             $this->overlay = Overlay::load($this->item, 'article:' . $this->item['id']);
         }
     }
     // components of the query
     $query = array();
     // a new comment has been posted
     if ($action == 'comment:create') {
         // purge oldest comments
         Comments::purge_for_anchor('article:' . $this->item['id']);
         // file upload
     } elseif ($action == 'file:create' || $action == 'file:upload') {
         // actually, several files have been added
         $label = '';
         if (!$origin) {
             // only when comments are allowed
             if (!Articles::has_option('no_comments', $this->anchor, $this->item)) {
                 // remember this as an automatic notification
                 $fields = array();
                 $fields['anchor'] = 'article:' . $this->item['id'];
                 $fields['description'] = i18n::s('Several files have been added');
                 $fields['type'] = 'notification';
                 Comments::post($fields);
             }
             // one file has been added
         } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) {
             // this file is eligible for being embedded in the page
             if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) {
                 // the overlay may prevent embedding
                 if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
                 } else {
                     $label = '[embed=' . $origin . ']';
                 }
                 // else add a comment to take note of the upload
             } else {
                 // only when comments are allowed
                 if (!Articles::has_option('no_comments', $this->anchor, $this->item)) {
                     // remember this as an automatic notification
                     $fields = array();
                     $fields['anchor'] = 'article:' . $this->item['id'];
                     if ($action == 'file:create') {
                         $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']';
                     } else {
                         $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']';
                     }
                     Comments::post($fields);
                 }
             }
         }
         // we are in some interactive thread
         if ($origin && $this->has_option('view_as_chat')) {
             // default is to download the file
             if (!$label) {
                 $label = '[download=' . $origin . ']';
             }
             // this is the first contribution to the thread
             if (!($comment = Comments::get_newest_for_anchor('article:' . $this->item['id']))) {
                 $fields = array();
                 $fields['anchor'] = 'article:' . $this->item['id'];
                 $fields['description'] = $label;
                 // this is a continuated contribution from this authenticated surfer
             } elseif ($comment['type'] != 'notification' && Surfer::get_id() && (isset($comment['create_id']) && Surfer::get_id() == $comment['create_id'])) {
                 $comment['description'] .= BR . $label;
                 $fields = $comment;
                 // else process the contribution as a new comment
             } else {
                 $fields = array();
                 $fields['anchor'] = 'article:' . $this->item['id'];
                 $fields['description'] = $label;
             }
             // only when comments are allowed
             if (!Articles::has_option('no_comments', $this->anchor, $this->item)) {
                 Comments::post($fields);
             }
             // include flash videos in a regular page
         } elseif ($origin && $label) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'";
         }
         // suppress references to a deleted file
     } elseif ($action == 'file:delete' && $origin) {
         // suppress reference in main description field
         $text = Codes::delete_embedded($this->item['description'], 'download', $origin);
         $text = Codes::delete_embedded($text, 'embed', $origin);
         $text = Codes::delete_embedded($text, 'file', $origin);
         // save changes
         $query[] = "description = '" . SQL::escape($text) . "'";
         // append a reference to a new image to the description
     } elseif ($action == 'image:create' && $origin) {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             // the overlay may prevent embedding
             if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
             } else {
                 // list has already started
                 if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) {
                     $this->item['description'] .= ' [image=' . $origin . ']';
                 } else {
                     $this->item['description'] .= "\n\n" . '[image=' . $origin . ']';
                 }
                 $query[] = "description = '" . SQL::escape($this->item['description']) . "'";
             }
         }
         // also use it as thumnail if none has been defined yet
         if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) {
             include_once $context['path_to_root'] . 'images/images.php';
             if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         // refresh stamp only if image update occurs within 6 hours after last edition
         if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) {
             $silently = TRUE;
         }
         // suppress a reference to an image that has been deleted
     } elseif ($action == 'image:delete' && $origin) {
         // suppress reference in main description field
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'";
         // suppress references as icon and thumbnail as well
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
             if ($url = Images::get_thumbnail_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
         }
         // set an existing image as the article icon
     } elseif ($action == 'image:set_as_icon' && $origin) {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 $query[] = "icon_url = '" . SQL::escape($url) . "'";
             }
             // also use it as thumnail if none has been defined yet
             if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         // set an existing image as the article thumbnail
     } elseif ($action == 'image:set_as_thumbnail' && $origin) {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             // use the thumbnail for large files, or the image itself for smaller files
             if ($image['image_size'] > $context['thumbnail_threshold']) {
                 $url = Images::get_thumbnail_href($image);
             } else {
                 $url = Images::get_icon_href($image);
             }
             $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
         } elseif ($origin) {
             $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'";
         }
         // do not remember minor changes
         $silently = TRUE;
         // append a new image, and set it as the article thumbnail
     } elseif ($action == 'image:set_as_both' && $origin) {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
         }
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             // use the thumbnail for large files, or the image itself for smaller files
             if ($image['image_size'] > $context['thumbnail_threshold']) {
                 $url = Images::get_thumbnail_href($image);
             } else {
                 $url = Images::get_icon_href($image);
             }
             $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
         } elseif ($origin) {
             $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'";
         }
         // do not remember minor changes
         $silently = TRUE;
         // add a reference to a location in the article description
     } elseif ($action == 'location:create' && $origin) {
         if (!Codes::check_embedded($this->item['description'], 'location', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [location=' . $origin . ']') . "'";
         }
         // suppress a reference to a location that has been deleted
     } elseif ($action == 'location:delete' && $origin) {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'location', $origin)) . "'";
         // add a reference to a new table in the article description
     } elseif ($action == 'table:create' && $origin) {
         if (!Codes::check_embedded($this->item['description'], 'table', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . "\n" . '[table=' . $origin . ']' . "\n") . "'";
         }
         // suppress a reference to a table that has been deleted
     } elseif ($action == 'table:delete' && $origin) {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'";
     }
     // stamp the update
     if (!$silently) {
         $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='" . SQL::escape($action) . "'," . "edit_date='" . gmstrftime('%Y-%m-%d %H:%M:%S') . "'";
     }
     // update the database
     if (count($query)) {
         $query = "UPDATE " . SQL::table_name('articles') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']);
         SQL::query($query);
     }
     // add this page to the watch list of the contributor, on any action
     if (Surfer::get_id()) {
         Members::assign('article:' . $this->item['id'], 'user:'******'article:' . $this->item['id'], $this->item['active']);
     // always clear the cache, even on no update
     Articles::clear($this->item);
     // get the parent
     if (!$this->anchor) {
         $this->anchor = Anchors::get($this->item['anchor']);
     }
     // propagate the touch upwards
     if (is_object($this->anchor)) {
         $this->anchor->touch('article:update', $this->item['id'], TRUE);
     }
 }
コード例 #6
0
ファイル: section.php プロジェクト: rair/yacs
 /**
  * remember the last action for this section
  *
  * @see articles/article.php
  * @see shared/anchor.php
  *
  * @param string the description of the last action
  * @param string the id of the item related to this update
  * @param boolean TRUE to not change the edit date of this anchor, default is FALSE
  */
 function touch($action, $origin = NULL, $silently = FALSE)
 {
     global $context;
     // we make extensive use of comments below
     include_once $context['path_to_root'] . 'comments/comments.php';
     // don't go further on import
     if (preg_match('/import$/i', $action)) {
         return;
     }
     // no section bound
     if (!isset($this->item['id'])) {
         return;
     }
     // delegate to overlay
     if (is_object($this->overlay) && $this->overlay->touch($action, $origin, $silently) === false) {
         return;
         // stop on false
     }
     // sanity check
     if (!$origin) {
         logger::remember('sections/section.php: unexpected NULL origin at touch()');
         return;
     }
     // components of the query
     $query = array();
     // a new page has been added to the section
     if ($action == 'article:publish' || $action == 'article:submit') {
         // limit the number of items attached to this section
         if (isset($this->item['maximum_items']) && $this->item['maximum_items'] > 10) {
             Articles::purge_for_anchor('section:' . $this->item['id'], $this->item['maximum_items']);
         }
         // a new comment has been posted
     } elseif ($action == 'comment:create') {
         // purge oldest comments
         Comments::purge_for_anchor('section:' . $this->item['id']);
         // file upload
     } elseif ($action == 'file:create' || $action == 'file:upload') {
         // actually, several files have been added
         $label = '';
         if (!$origin) {
             $fields = array();
             $fields['anchor'] = 'section:' . $this->item['id'];
             $fields['description'] = i18n::s('Several files have been added');
             $fields['type'] = 'notification';
             Comments::post($fields);
             // one file has been added
         } elseif (!Codes::check_embedded($this->item['description'], 'embed', $origin) && ($item = Files::get($origin, TRUE))) {
             // this file is eligible for being embedded in the page
             if (isset($item['file_name']) && Files::is_embeddable($item['file_name'])) {
                 // the overlay may prevent embedding
                 if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
                 } else {
                     $label = '[embed=' . $origin . ']';
                 }
                 // else add a comment to take note of the upload
             } elseif (Comments::allow_creation($this->item, null, 'section')) {
                 $fields = array();
                 $fields['anchor'] = 'section:' . $this->item['id'];
                 if ($action == 'file:create') {
                     $fields['description'] = '[file=' . $item['id'] . ',' . $item['file_name'] . ']';
                 } else {
                     $fields['description'] = '[download=' . $item['id'] . ',' . $item['file_name'] . ']';
                 }
                 Comments::post($fields);
             }
         }
         // include flash videos in a regular page
         if ($label) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' ' . $label) . "'";
         }
         // suppress references to a deleted file
     } elseif ($action == 'file:delete') {
         // suppress reference in main description field
         $text = Codes::delete_embedded($this->item['description'], 'download', $origin);
         $text = Codes::delete_embedded($text, 'embed', $origin);
         $text = Codes::delete_embedded($text, 'file', $origin);
         // save changes
         $query[] = "description = '" . SQL::escape($text) . "'";
         // append a reference to a new image to the description
     } elseif ($action == 'image:create') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             // the overlay may prevent embedding
             if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
             } else {
                 // list has already started
                 if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
                 } else {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'";
                 }
             }
         }
         // also use it as thumnail if none has been defined yet
         if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) {
             include_once $context['path_to_root'] . 'images/images.php';
             if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         // refresh stamp only if image update occurs within 6 hours after last edition
         if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) {
             $silently = TRUE;
         }
         // suppress a reference to an image that has been deleted
     } elseif ($action == 'image:delete') {
         // suppress reference in main description field
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'";
         // suppress references as icon and thumbnail as well
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
             if ($url = Images::get_thumbnail_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
         }
         // set an existing image as the section icon
     } elseif ($action == 'image:set_as_icon') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 $query[] = "icon_url = '" . SQL::escape($url) . "'";
             }
             // also use it as thumnail if none has been defined yet
             if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         } elseif ($origin) {
             $query[] = "icon_url = '" . SQL::escape($origin) . "'";
         }
         $silently = TRUE;
         // set an existing image as the section thumbnail
     } elseif ($action == 'image:set_as_thumbnail') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             // use the thumbnail for large files, or the image itself for smaller files
             if ($image['image_size'] > $context['thumbnail_threshold']) {
                 $url = Images::get_thumbnail_href($image);
             } else {
                 $url = Images::get_icon_href($image);
             }
             $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
         } elseif ($origin) {
             $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'";
         }
         $silently = TRUE;
         // append a new image, and set it as the article thumbnail
     } elseif ($action == 'image:set_as_both') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
         }
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             // use the thumbnail for large files, or the image itself for smaller files
             if ($image['image_size'] > $context['thumbnail_threshold']) {
                 $url = Images::get_thumbnail_href($image);
             } else {
                 $url = Images::get_icon_href($image);
             }
             $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
         } elseif ($origin) {
             $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'";
         }
         // do not remember minor changes
         $silently = TRUE;
         // add a reference to a new table in the section description
     } elseif ($action == 'table:create') {
         if (!Codes::check_embedded($this->item['description'], 'table', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'";
         }
         // suppress a reference to a table that has been deleted
     } elseif ($action == 'table:delete') {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'";
     }
     // stamp the update
     if (!$silently) {
         $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='{$action}'," . "edit_date='" . SQL::escape(gmstrftime('%Y-%m-%d %H:%M:%S')) . "'";
     }
     // update the database
     if (@count($query)) {
         $query = "UPDATE " . SQL::table_name('sections') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']);
         SQL::query($query);
     }
     // always clear the cache, even on no update
     Sections::clear($this->item);
     // get the parent
     if (!$this->anchor) {
         $this->anchor = Anchors::get($this->item['anchor']);
     }
     // propagate the touch upwards silently -- we only want to purge the cache
     if (is_object($this->anchor)) {
         $this->anchor->touch('section:touch', $this->item['id'], TRUE);
     }
 }
コード例 #7
0
ファイル: comments.php プロジェクト: rair/yacs
 /**
  * wait for updates
  *
  * This script will wait for new updates before providing them to caller.
  * Because of potential time-outs, you have to care of retries.
  *
  * @param string reference to thread (e.g., 'article:123')
  * @param string timestamp of previous update
  * @return array attributes including new comments and a timestamp
  *
  * @see articles/view_as_chat.php
  * @see comments/thread.php
  */
 public static function &pull($anchor, $stamp, $count = 100)
 {
     global $context;
     $timer = 1;
     // some implementations will kill network connections earlier anyway
     Safe::set_time_limit(max(30, $timer));
     // we return formatted text
     $text = '';
     // sanity check
     if (!$anchor) {
         return $text;
     }
     // the query to get time of last update
     $query = "SELECT edit_date, edit_name FROM " . SQL::table_name('comments') . " AS comments " . " WHERE comments.anchor LIKE '" . SQL::escape($anchor) . "'" . " ORDER BY comments.edit_date DESC" . " LIMIT 1";
     // we may timeout ourself, to be safe with network resources
     while (!($stat = SQL::query_first($query)) || isset($stat['edit_date']) && $stat['edit_date'] <= $stamp) {
         // kill the request to avoid repeated transmissions when nothing has changed
         if (--$timer < 1) {
             http::no_content();
             die;
         }
         // preserve server resources
         sleep(1);
     }
     // return an array of variables
     $response = array();
     $response['items'] =& Comments::list_by_thread_for_anchor($anchor, 0, $count, 'thread');
     $response['name'] = strip_tags($stat['edit_name']);
     $response['timestamp'] = SQL::strtotime($stat['edit_date']);
     // return by reference
     return $response;
 }
コード例 #8
0
ファイル: view.php プロジェクト: rair/yacs
     $details[] = EXPIRED_FLAG . ' ' . sprintf(i18n::s('Category has expired %s'), Skin::build_date($item['expiry_date']));
 }
 // display details, if any
 if (count($details)) {
     $context['page_details'] .= ucfirst(implode(BR, $details)) . BR;
 }
 // other details
 $details = array();
 // additional details for associates and editors
 if (Surfer::is_associate() || is_object($anchor) && $anchor->is_assigned()) {
     // the creator of this category
     if ($item['create_date']) {
         $details[] = sprintf(i18n::s('posted by %s %s'), Users::get_link($item['create_name'], $item['create_address'], $item['create_id']), Skin::build_date($item['create_date']));
     }
     // hide last edition if done by creator, and if less than 24 hours between creation and last edition
     if ($item['create_date'] && $item['create_id'] == $item['edit_id'] && SQL::strtotime($item['create_date']) + 24 * 60 * 60 >= SQL::strtotime($item['edit_date'])) {
     } else {
         if ($item['edit_action']) {
             $action = Anchors::get_action_label($item['edit_action']);
         } else {
             $action = i18n::s('edited');
         }
         $details[] = sprintf(i18n::s('%s by %s %s'), $action, Users::get_link($item['edit_name'], $item['edit_address'], $item['edit_id']), Skin::build_date($item['edit_date']));
     }
     // the number of hits
     if ($item['hits'] > 1) {
         $details[] = Skin::build_number($item['hits'], i18n::s('hits'));
     }
     // rank for this section
     if (intval($item['rank']) != 10000 && Surfer::is_associate()) {
         $details[] = '{' . $item['rank'] . '}';
コード例 #9
0
 /**
  * list articles
  *
  * @param resource the SQL result
  * @return array
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // we return an array of ($url => $attributes)
     $items = array();
     // empty list
     if (!SQL::count($result)) {
         return $items;
     }
     // process all items in the list
     while ($item = SQL::fetch($result)) {
         // get the related overlay, if any
         $overlay = Overlay::load($item, 'category:' . $item['id']);
         // get the anchor
         $anchor = Anchors::get($item['anchor']);
         // provide an absolute link
         $url = Categories::get_permalink($item);
         // build a title
         if (is_object($overlay)) {
             $title = Codes::beautify_title($overlay->get_text('title', $item));
         } else {
             $title = Codes::beautify_title($item['title']);
         }
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // the section
         $root = '';
         if ($item['anchor'] && ($anchor = Anchors::get($item['anchor']))) {
             $root = ucfirst(trim(strip_tags(Codes::beautify_title($anchor->get_title()))));
         }
         // the icon to use
         $icon = '';
         if ($item['thumbnail_url']) {
             $icon = $item['thumbnail_url'];
         } elseif ($item['anchor'] && ($anchor = Anchors::get($item['anchor'])) && is_callable($anchor, 'get_bullet_url')) {
             $icon = $anchor->get_bullet_url();
         }
         if ($icon) {
             $icon = $context['url_to_home'] . $context['url_to_root'] . $icon;
         }
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author = '';
         if (isset($item['create_address'])) {
             $author .= $item['create_address'];
         }
         if (isset($item['create_name']) && trim($item['create_name'])) {
             $author .= ' (' . $item['create_name'] . ')';
         }
         if (isset($item['edit_address']) && trim($item['edit_address']) && $item['create_address'] != $item['edit_address']) {
             if ($author) {
                 $author .= ', ';
             }
             $author .= $item['edit_address'];
             if (isset($item['edit_name']) && trim($item['edit_name'])) {
                 $author .= ' (' . $item['edit_name'] . ')';
             }
         }
         // list all components for this item
         $items[$url] = array($time, $title, $author, $root, $icon, '', '', '');
     }
     // end of processing
     SQL::free($result);
     return $items;
 }
コード例 #10
0
ファイル: fetch_vcard.php プロジェクト: rair/yacs
     // phone number, if any
     if (isset($agent['phone_number']) && $agent['phone_number']) {
         $text .= 'TEL;PREF:' . $agent['phone_number'] . "\r\n";
     }
     // alternate number, if any
     if (isset($agent['alternate_number']) && $agent['alternate_number']) {
         $text .= 'TEL;MSG:' . $agent['alternate_number'] . "\r\n";
     }
     // web mail, if any
     if (isset($agent['email']) && $agent['email']) {
         $text .= 'EMAIL;PREF;INTERNET:' . $agent['email'] . "\r\n";
     }
     $text .= 'END:VCARD' . "\r\n";
 }
 // date of last update
 $text .= 'REV:' . date('Ymd\\THis\\Z', SQL::strtotime($item['edit_date'])) . CRLF . 'END:VCARD' . CRLF;
 //
 // transfer to the user agent
 //
 // no encoding, no compression and no yacs handler...
 if (!headers_sent()) {
     Safe::header('Content-Type: text/x-vcard');
     Safe::header('Content-Transfer-Encoding: binary');
     Safe::header('Content-Length: ' . strlen($text));
 }
 // suggest a download
 if (!headers_sent()) {
     $file_name = utf8::to_ascii(Skin::strip($context['page_title']) . '.vcf');
     Safe::header('Content-Disposition: attachment; filename="' . str_replace('"', '', $file_name) . '"');
 }
 // enable 30-minute caching (30*60 = 1800), even through https, to help IE6 on download
コード例 #11
0
ファイル: mailer.php プロジェクト: rair/yacs
 /**
  * process deferred messages
  *
  * Most often, the server has to stay below a given rate of messages,
  * for example 50 messages per hour.
  *
  * Of course, any lively community will feature bursts of activity and of
  * messages, therefore the need for a shaping mechanism.
  *
  * YACS implements a leaking bucket algorithm to take care of messages sent
  * previously:
  *
  * 1. Initially, the bucket is empty.
  *
  * 2. New messages are queued in the database, to be processed asynchronously.
  *
  * 3. On background ticks, the bucket is decremented. If the bucket becomes
  * empty, and if some messages have been queued, a couple of them are sent, and
  * the bucket is incremented accordingly.
  *
  * Bucket content is managed as value 'bucket.content' saved in the database.
  *
  * The bucket size is given by parameter $context['mail_hourly_maximum'], set
  * in the configuration panel for system parameters.
  *
  * This parameter has a default value of 50, meaning YACS will not send more
  * than 50 messages per hour.
  *
  * Background processing is either added to regular page generation or delegated
  * to an external sub-system (e.g., cron). In case of a large site, we recommend
  * to use the second solution, even if this adds additional setup steps. Your
  * choice will be recorded in the configuration panel for system parameters.
  *
  * @see control/configure.php
  *
  * The number of messages sent on each tick can go up to the bucket size if
  * background processing is external. Else it is one fourth of bucket size, to
  * minimize impact on watching surfer.
  *
  * @see cron.php
  */
 public static function tick_hook()
 {
     global $context;
     // email services have to be activated
     if (!isset($context['with_email']) || $context['with_email'] != 'Y') {
         return;
     }
     // useless if we don't have a valid database connection
     if (!$context['connection']) {
         return;
     }
     // remember start time
     $start = get_micro_time();
     // get bucket size --force it if set to 0
     if (!isset($context['mail_hourly_maximum']) || $context['mail_hourly_maximum'] < 5) {
         $context['mail_hourly_maximum'] = 50;
     }
     // get record related to last tick
     include_once $context['path_to_root'] . 'shared/values.php';
     $bucket = Values::get_record('mailer.bucket.content', 0);
     $bucket['value'] = intval($bucket['value']);
     // some content to leak
     if ($bucket['value'] > 0) {
         // date of last stamp
         if (isset($bucket['edit_date'])) {
             $stamp = SQL::strtotime($bucket['edit_date']);
         } else {
             $stamp = time() - 3600;
         }
         // leak is maximum after one hour
         $leak = intval($context['mail_hourly_maximum'] * (time() - $stamp) / 3600);
         // preserve previous value until actual leak
         if ($leak < 1) {
             return;
         }
         // actual leak
         $bucket['value'] = max(0, $bucket['value'] - $leak);
     }
     // process some messages only when bucket is empty
     $count = 0;
     if ($bucket['value'] < 1) {
         // reduced speed if on-line processing
         if (isset($_SERVER['REMOTE_ADDR'])) {
             $slice = intval($context['mail_hourly_maximum'] / 4);
         } else {
             $slice = intval($context['mail_hourly_maximum']);
         }
         // get some messages, if any
         $query = "SELECT * FROM " . SQL::table_name('messages') . " ORDER BY edit_date LIMIT 0, " . $slice;
         if ($result = SQL::query($query)) {
             // process every message
             while ($item = SQL::fetch($result)) {
                 Mailer::process($item['recipient'], $item['subject'], $item['message'], $item['headers']);
                 // purge the queue
                 $query = 'DELETE FROM ' . SQL::table_name('messages') . ' WHERE id = ' . $item['id'];
                 SQL::query($query);
                 // fill the bucket
                 $bucket['value'] += 1;
                 $count++;
                 // take care of time
                 if (!($count % 50)) {
                     // ensure enough execution time
                     Safe::set_time_limit(30);
                 }
             }
             // close connection
             Mailer::close();
         }
     }
     // remember new state of the bucket
     Values::set('mailer.bucket.content', $bucket['value']);
     // compute execution time
     $time = round(get_micro_time() - $start, 2);
     // report on work achieved
     if ($count > 1) {
         return 'shared/mailer.php: ' . $count . ' messages have been processed (' . $time . ' seconds)' . BR;
     } elseif ($count == 1) {
         return 'shared/mailer.php: 1 message has been processed (' . $time . ' seconds)' . BR;
     } elseif ($bucket['value']) {
         return 'shared/mailer.php: delaying messages (' . $time . ' seconds)' . BR;
     } else {
         return 'shared/mailer.php: nothing to do (' . $time . ' seconds)' . BR;
     }
 }
コード例 #12
0
ファイル: user.php プロジェクト: rair/yacs
 /**
  * remember the last action for this user
  *
  * @param string the description of the last action
  * @param string the id of the item related to this update
  * @param boolean TRUE to not change the edit date of this anchor, default is FALSE
  *
  * @see shared/anchor.php
  */
 function touch($action, $origin = NULL, $silently = FALSE)
 {
     global $context;
     // don't go further on import
     if (preg_match('/import$/i', $action)) {
         return;
     }
     // no item bound
     if (!isset($this->item['id'])) {
         return;
     }
     // sanity check
     if (!$origin) {
         logger::remember('users/user.php: unexpected NULL origin at touch()');
         return;
     }
     // components of the query
     $query = array();
     // append a reference to a new image to the description
     if ($action == 'image:create') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             // the overlay may prevent embedding
             if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
             } else {
                 // list has already started
                 if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
                 } else {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'";
                 }
             }
         }
         // refresh stamp only if image update occurs within 6 hours after last edition
         if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) {
             $silently = TRUE;
         }
         // suppress a reference to an image that has been deleted
     } elseif ($action == 'image:delete') {
         // suppress reference in main description field
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'";
         // suppress references as icon and thumbnail as well
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 if ($this->item['avatar_url'] == $url) {
                     $query[] = "avatar_url = ''";
                 }
             }
             if ($url = Images::get_thumbnail_href($image)) {
                 if ($this->item['avatar_url'] == $url) {
                     $query[] = "avatar_url = ''";
                 }
             }
         }
         // set an existing image as the user avatar
     } elseif ($action == 'image:set_as_avatar') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 $query[] = "avatar_url = '" . SQL::escape($url) . "'";
             }
         }
         $silently = TRUE;
         // set an existing image as the user thumbnail
     } elseif ($action == 'image:set_as_thumbnail') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_thumbnail_href($image)) {
                 $query[] = "avatar_url = '" . SQL::escape($url) . "'";
             }
         }
         $silently = TRUE;
         // append a new image
     } elseif ($action == 'image:set_as_both') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
         }
         // do not remember minor changes
         $silently = TRUE;
         // add a reference to a location in the article description
     } elseif ($action == 'location:create') {
         if (!Codes::check_embedded($this->item['description'], 'location', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [location=' . $origin . ']') . "'";
         }
         // suppress a reference to a location that has been deleted
     } elseif ($action == 'location:delete') {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'location', $origin)) . "'";
         // add a reference to a new table in the user description
     } elseif ($action == 'table:create') {
         if (!Codes::check_embedded($this->item['description'], 'table', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'";
         }
         // suppress a reference to a table that has been deleted
     } elseif ($action == 'table:delete') {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'";
     }
     // stamp the update
     if (!$silently) {
         $query[] = "edit_name='" . SQL::escape(Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(Surfer::get_id()) . "," . "edit_address='" . SQL::escape(Surfer::get_email_address()) . "'," . "edit_action='{$action}'," . "edit_date='" . SQL::escape(gmstrftime('%Y-%m-%d %H:%M:%S')) . "'";
     }
     // clear the cache for users, even for minor updates (e.g., image deletion)
     Users::clear($this->item);
     // ensure we have a valid update query
     if (!@count($query)) {
         return;
     }
     // update the anchor user
     $query = "UPDATE " . SQL::table_name('users') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']);
     SQL::query($query, FALSE, $context['users_connection']);
 }
コード例 #13
0
ファイル: edit.php プロジェクト: rair/yacs
        } elseif (isset($_REQUEST['anchor'])) {
            $link = 'articles/edit.php?anchor=' . $_REQUEST['anchor'];
        } else {
            $link = 'articles/edit.php';
        }
        Safe::redirect($context['url_to_home'] . $context['url_to_root'] . 'users/login.php?url=' . urlencode($link));
    }
    // permission denied to authenticated user
    Safe::header('Status: 401 Unauthorized', TRUE, 401);
    Logger::error(i18n::s('You are not allowed to perform this operation.'));
    // an error occured
} elseif (count($context['error'])) {
    $item = $_REQUEST;
    $with_form = TRUE;
    // page has been assigned to another person during the last 5 minutes
} elseif (isset($item['assign_id']) && $item['assign_id'] && !Surfer::is($item['assign_id']) && SQL::strtotime($item['assign_date']) + 5 * 60 >= time()) {
    // permission denied to authenticated user
    Safe::header('Status: 401 Unauthorized', TRUE, 401);
    $context['text'] .= Skin::build_block(sprintf(i18n::s('This page is currently edited by %s. You have to wait for a new version to be released.'), Users::get_link($item['assign_name'], $item['assign_address'], $item['assign_id'])), 'caution');
    // process uploaded data
} elseif (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') {
    // protect from hackers
    if (isset($_REQUEST['edit_name'])) {
        $_REQUEST['edit_name'] = preg_replace(FORBIDDEN_IN_NAMES, '_', $_REQUEST['edit_name']);
    }
    if (isset($_REQUEST['edit_address'])) {
        $_REQUEST['edit_address'] = encode_link($_REQUEST['edit_address']);
    }
    // track anonymous surfers
    Surfer::track($_REQUEST);
    // set options
コード例 #14
0
ファイル: feed.php プロジェクト: rair/yacs
 $text .= '	<lastBuildDate>' . gmdate('D, d M Y H:i:s') . ' GMT</lastBuildDate>' . "\n" . '	<generator>yacs</generator>' . "\n" . '	<docs>http://blogs.law.harvard.edu/tech/rss</docs>' . "\n" . '	<ttl>5</ttl>' . "\n";
 // list last events
 $events = Logger::get_tail(50, 'all');
 if (is_array($events)) {
     // the actual list of events
     foreach ($events as $event) {
         list($stamp, $surfer, $script, $label, $description) = $event;
         // formatting patterns
         $search = array("|\r\n|", "|<br\\s*/>\n+|i", "|\n\n+[ \t]*-\\s+|i", "|\n[ \t]*-\\s+|i", "|\n\n+[ \t]*\\.\\s+|i", "|\n[ \t]*\\.\\s+|i", "|\n\n+[ \t]*\\*\\s+|i", "|\n[ \t]*\\*\\s+|i", "|\n\n+[ \t]*¤\\s+|i", "|\n[ \t]*¤\\s+|i", "|\n\n+[ \t]*\\•\\s+|i", "|\n[ \t]*\\•\\s+|i", "/\n[ \t]*(From|To|cc|bcc|Subject|Date):(\\s*)/i", "|\n[ \t]*>(\\s*)|i", "|\n[ \t]*\\|(\\s*)|i", "#([\n\t ])([a-z]+?)://([^, <>{}\n\r]+)#is", "#^([a-z]+?)://([^, <>{}\n\r]+)#is", "#([\n\t ])www\\.([a-z0-9\\-]+)\\.([a-z0-9\\-.\\~]+)((?:/[^,< \n\r]*)?)#is", "#([\n\t ])([a-z0-9\\-_.]+?)@([^,< \\.\n\r]+\\.[^,< \n\r]+)#is", "|\n\n|i");
         $replace = array("\n", BR, BR . BR . "- ", BR . "- ", BR . BR . "- ", BR . "- ", BR . BR . "- ", BR . "- ", BR . BR . "- ", BR . "- ", BR . BR . "• ", BR . "• ", BR . "\$1:\$2", BR . ">\$1", BR . "|\$1", "\$1<a href=\"\$2://\$3\">\$2://\$3</a>", "<a href=\"\$1://\$2\">\$1://\$2</a>", "\$1<a href=\"http://www.\$2.\$3\$4\">http://www.\$2.\$3\$4</a>", "\$1<a href=\"mailto:\$2@\$3\">\$2@\$3</a>", BR . BR);
         // build an extensive description field
         $description = nl2br(preg_replace($search, $replace, $description)) . '<p>' . $script . (strlen($surfer) > 1 ? ' for ' . $surfer : '') . ' on ' . $stamp . "</p>";
         // build a unique id
         $id = md5($label . $description . $stamp . $script . $surfer);
         // output one story
         $text .= "\n" . ' <item>' . "\n" . '		<title>' . encode_field(strip_tags($label)) . "</title>\n" . '		<description><![CDATA[ ' . $description . " ]]></description>\n" . '		<pubDate>' . gmdate('D, d M Y H:i:s', SQL::strtotime($stamp)) . " GMT</pubDate>\n" . '		<link>' . $context['url_to_home'] . $context['url_to_root'] . 'agents/?subject=events&amp;id=' . $id . "</link>\n" . '		<guid isPermaLink="false">' . $id . "</guid>\n" . '		<category>' . encode_field($script) . "</category>\n" . "\t</item>\n";
     }
 }
 // the postamble
 $text .= "\n\t</channel>\n" . '</rss>';
 //
 // transfer to the user agent
 //
 // handle the output correctly
 render_raw('text/xml; charset=' . $context['charset']);
 // suggest a name on download
 if (!headers_sent()) {
     $file_name = $context['site_name'] . '.events.rss.xml';
     $file_name =& utf8::to_ascii($file_name);
     Safe::header('Content-Disposition: inline; filename="' . str_replace('"', '', $file_name) . '"');
 }
コード例 #15
0
ファイル: anchor.php プロジェクト: rair/yacs
 /**
  * get date of last modification
  *
  * @see services/check.php
  *
  * @return array the attribute 'timestamp' contains time of last update
  */
 function &check()
 {
     $response = array();
     // 'timestamp'
     if (!isset($this->item['edit_date'])) {
         $response['timestamp'] = '';
     } else {
         $response['timestamp'] = SQL::strtotime($this->item['edit_date']);
     }
     // 'name'
     if (!isset($this->item['edit_name'])) {
         $response['name'] = '';
     } else {
         $response['name'] = strip_tags($this->item['edit_name']);
     }
     return $response;
 }
コード例 #16
0
ファイル: sql.php プロジェクト: rair/yacs
 /**
  * purge idle space
  *
  * This function OPTIMIZEs tables that may create overheads because of
  * frequent deletions, including: cache, links, members, messages,
  * notifications, values, versions, visits.
  *
  * Last purge is recorded as value 'sql.tick'.
  *
  * @param boolean optional TRUE to not report on any error
  * @return a string to be displayed in resulting page, if any
  */
 public static function purge($silent = FALSE)
 {
     global $context;
     // useless if we don't have a valid database connection
     if (!$context['connection']) {
         return;
     }
     // remember start time
     $stamp = get_micro_time();
     // get date of last tick
     include_once $context['path_to_root'] . 'shared/values.php';
     $record = Values::get_record('sql.tick', NULL_DATE);
     // wait at least 8 hours = 24*3600 seconds between ticks
     if (isset($record['edit_date'])) {
         $target = SQL::strtotime($record['edit_date']) + 8 * 3600;
     } else {
         $target = time();
     }
     // request to be delayed
     if ($target > time()) {
         return 'shared/sql.php: wait until ' . gmdate('r', $target) . ' GMT' . BR;
     }
     // recover unused bytes
     $query = 'OPTIMIZE TABLE ' . SQL::table_name('cache') . ', ' . SQL::table_name('links') . ', ' . SQL::table_name('members') . ', ' . SQL::table_name('messages') . ', ' . SQL::table_name('notifications') . ', ' . SQL::table_name('values') . ', ' . SQL::table_name('versions') . ', ' . SQL::table_name('visits');
     $result = SQL::query($query, $silent);
     // remember tick date and resulting text
     Values::set('sql.tick', 'purge');
     // compute execution time
     $time = round(get_micro_time() - $stamp, 2);
     // report on work achieved
     if ($result) {
         return 'shared/sql.php: unused bytes have been recovered (' . $time . ' seconds)' . BR;
     } else {
         return 'shared/sql.php: nothing to recover (' . $time . ' seconds)' . BR;
     }
 }
コード例 #17
0
ファイル: cron.php プロジェクト: rair/yacs
    // remember tick date and resulting text
    Values::set('cron.hourly', $context['text']);
    // log outcome of script execution in debug mode
    if ($context['with_debug'] == 'Y') {
        Logger::remember('cron.php: hourly processing', $context['text'], 'debug');
    }
}
//
// daily jobs
//
echo 'Checking daily jobs...' . BR;
// get date of last run
$record = Values::get_record('cron.daily', NULL_DATE);
// wait at least 1 day = 86400 seconds between runs
if (isset($record['edit_date'])) {
    $target = SQL::strtotime($record['edit_date']) + 86400;
} else {
    $target = time();
}
// request to be delayed
if ($target > time()) {
    echo 'Wait until ' . gmdate('r', $target) . ' GMT' . BR;
} else {
    Values::set('cron.daily', 'running...');
    // do the job and provide feed-back to user
    $context['text'] = Hooks::include_scripts('daily');
    echo $context['text'];
    // remember tick date and resulting text
    Values::set('cron.daily', $context['text']);
    // log outcome of script execution in debug mode
    if ($context['with_debug'] == 'Y') {
コード例 #18
0
ファイル: articles.php プロジェクト: rair/yacs
 /**
  * stamp an article
  *
  * This function is used to change various dates for one article.
  *
  * [*] If a publication date is provided, it is saved along the article.
  * An optional expiry date will be saved as well.
  *
  * [*] If only an expiry date is provided, it is saved along the article.
  *
  * [*] If no date is provided, the review field is updated to the current date and time.
  *
  * Dates are supposed to be in UTC time zone.
  *
  * The name of the surfer is registered as the official publisher.
  * As an alternative, publisher attributes ('name', 'id' and 'address') can be provided
  * in parameters.
  *
  * @param int the id of the item to publish
  * @param string the target publication date, if any
  * @param string the target expiration date, if any
  * @param array attributes of the publisher, if any
  * @return string either a null string, or some text describing an error to be inserted into the html response
  *
  * @see articles/publish.php
  * @see sections/manage.php
  **/
 public static function stamp($id, $publication = NULL, $expiry = NULL, $publisher = NULL)
 {
     global $context;
     // id cannot be empty
     if (!$id || !is_numeric($id)) {
         return i18n::s('No item has the provided id.');
     }
     // server offset
     $server_offset = 0;
     if (isset($context['gmt_offset'])) {
         $server_offset = intval($context['gmt_offset']);
     }
     // surfer offset
     $surfer_offset = Surfer::get_gmt_offset();
     // no publication time is provided
     if (!isset($publication) || !$publication) {
         $publication_stamp = 0;
     } elseif (preg_match('/GMT$/', $publication) && strlen($publication) == 19) {
         // YYMMDD-HH:MM:SS GMT -> HH, MM, SS, MM, DD, YY
         $publication_stamp = gmmktime(intval(substr($publication, 7, 2)), intval(substr($publication, 10, 2)), intval(substr($publication, 13, 2)), intval(substr($publication, 2, 2)), intval(substr($publication, 4, 2)), intval(substr($publication, 0, 2)));
         // time()-like stamp
     } elseif (intval($publication) > 1000000000) {
         // adjust to UTC time zone
         $publication_stamp = intval($publication) + $context['gmt_offset'] * 3600;
         // YYYY-MM-DD HH:MM:SS, or a string that can be readed
     } elseif (($publication_stamp = SQL::strtotime($publication)) != -1) {
     } else {
         return sprintf(i18n::s('"%s" is not a valid date'), $publication);
     }
     // no expiry date
     if (!isset($expiry) || !$expiry) {
         $expiry_stamp = 0;
     } elseif (preg_match('/GMT$/', $expiry) && strlen($expiry) == 19) {
         // YYMMDD-HH:MM:SS GMT -> HH, MM, SS, MM, DD, YY
         $expiry_stamp = gmmktime(substr($expiry, 7, 2), substr($expiry, 10, 2), substr($expiry, 13, 2), substr($expiry, 2, 2), substr($expiry, 4, 2), substr($expiry, 0, 2));
         // time()-like stamp
     } elseif (intval($expiry) > 1000000000) {
         // adjust to server time zone
         $expiry_stamp = intval($expiry) + $context['gmt_offset'] * 3600;
         // YYYY-MM-DD HH:MM:SS, or a string that can be readed
     } elseif (($expiry_stamp = SQL::strtotime($expiry)) != -1) {
     } else {
         return sprintf(i18n::s('"%s" is not a valid date'), $expiry);
     }
     // review date
     $review_stamp = 0;
     if (!$publication_stamp && !$expiry_stamp) {
         $review_stamp = time();
     }
     // shape the query
     $query = array();
     if ($publication_stamp > 0) {
         $query[] = "publish_name='" . SQL::escape(isset($publisher['name']) ? $publisher['name'] : Surfer::get_name()) . "'," . "publish_id=" . SQL::escape(isset($publisher['id']) ? $publisher['id'] : Surfer::get_id()) . "," . "publish_address='" . SQL::escape(isset($publisher['address']) ? $publisher['address'] : Surfer::get_email_address()) . "'," . "publish_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $publication_stamp) . "'," . "edit_name='" . SQL::escape(isset($publisher['name']) ? $publisher['name'] : Surfer::get_name()) . "'," . "edit_id=" . SQL::escape(isset($publisher['id']) ? $publisher['id'] : Surfer::get_id()) . "," . "edit_address='" . SQL::escape(isset($publisher['address']) ? $publisher['address'] : Surfer::get_email_address()) . "'," . "edit_action='article:publish'," . "edit_date='" . gmstrftime('%Y-%m-%d %H:%M:%S') . "'";
     }
     if ($expiry_stamp > 0) {
         $query[] = "expiry_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $expiry_stamp) . "'";
     }
     if ($review_stamp > 0) {
         $query[] = "review_date='" . gmstrftime('%Y-%m-%d %H:%M:%S', $review_stamp) . "'";
     }
     // update an existing record
     $query = "UPDATE " . SQL::table_name('articles') . " SET " . implode(',', $query) . " WHERE id = " . SQL::escape($id);
     if (SQL::query($query) === FALSE) {
         return NULL;
     }
     // remember the publication in weekly and monthly categories
     if ($publication_stamp > 0) {
         Categories::remember('article:' . $id, gmstrftime('%Y-%m-%d %H:%M:%S', $publication_stamp));
     }
     // end of job
     return NULL;
 }
コード例 #19
0
ファイル: category.php プロジェクト: rair/yacs
 /**
  * remember the last action for this category
  *
  * @param string the description of the last action
  * @param string the id of the item related to this update
  * @param boolean TRUE to not change the edit date of this anchor, default is FALSE
  *
  * @see shared/anchor.php
  */
 function touch($action, $origin = NULL, $silently = FALSE)
 {
     global $context;
     // don't go further on import
     if (preg_match('/import$/i', $action)) {
         return;
     }
     // no category bound
     if (!isset($this->item['id'])) {
         return;
     }
     // sanity check
     if (!$origin) {
         logger::remember('categories/category.php: unexpected NULL origin at touch()');
         return;
     }
     // components of the query
     $query = array();
     // append a reference to a new image to the description
     if ($action == 'image:create') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             // the overlay may prevent embedding
             if (is_object($this->overlay) && !$this->overlay->should_embed_files()) {
             } else {
                 // list has already started
                 if (preg_match('/\\[image=[^\\]]+?\\]\\s*$/', $this->item['description'])) {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
                 } else {
                     $query[] = "description = '" . SQL::escape($this->item['description'] . "\n\n" . '[image=' . $origin . ']') . "'";
                 }
             }
         }
         // also use it as thumnail if none has been defined yet
         if (!isset($this->item['thumbnail_url']) || !trim($this->item['thumbnail_url'])) {
             include_once $context['path_to_root'] . 'images/images.php';
             if (($image = Images::get($origin)) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         // refresh stamp only if image update occurs within 6 hours after last edition
         if (SQL::strtotime($this->item['edit_date']) + 6 * 60 * 60 < time()) {
             $silently = TRUE;
         }
         // suppress a reference to an image that has been deleted
     } elseif ($action == 'image:delete') {
         // suppress reference in main description field
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'image', $origin)) . "'";
         // suppress references as icon and thumbnail as well
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
             if ($url = Images::get_thumbnail_href($image)) {
                 if ($this->item['icon_url'] == $url) {
                     $query[] = "icon_url = ''";
                 }
                 if ($this->item['thumbnail_url'] == $url) {
                     $query[] = "thumbnail_url = ''";
                 }
             }
         }
         // set an existing image as the category icon
     } elseif ($action == 'image:set_as_icon') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_icon_href($image)) {
                 $query[] = "icon_url = '" . SQL::escape($url) . "'";
             }
             // also use it as thumnail if none has been defined yet
             if (!(isset($this->item['thumbnail_url']) && trim($this->item['thumbnail_url'])) && ($url = Images::get_thumbnail_href($image))) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         $silently = TRUE;
         // set an existing image as the category thumbnail
     } elseif ($action == 'image:set_as_thumbnail') {
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_thumbnail_href($image)) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         }
         $silently = TRUE;
         // append a new image, and set it as the article thumbnail
     } elseif ($action == 'image:set_as_both') {
         if (!Codes::check_embedded($this->item['description'], 'image', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [image=' . $origin . ']') . "'";
         }
         include_once $context['path_to_root'] . 'images/images.php';
         if ($image = Images::get($origin)) {
             if ($url = Images::get_thumbnail_href($image)) {
                 $query[] = "thumbnail_url = '" . SQL::escape($url) . "'";
             }
         } elseif ($origin) {
             $query[] = "thumbnail_url = '" . SQL::escape($origin) . "'";
         }
         // do not remember minor changes
         $silently = TRUE;
         // add a reference to a new table in the category description
     } elseif ($action == 'table:create') {
         if (!Codes::check_embedded($this->item['description'], 'table', $origin)) {
             $query[] = "description = '" . SQL::escape($this->item['description'] . ' [table=' . $origin . ']') . "'";
         }
         // suppress a reference to a table that has been deleted
     } elseif ($action == 'table:delete') {
         $query[] = "description = '" . SQL::escape(Codes::delete_embedded($this->item['description'], 'table', $origin)) . "'";
     }
     // stamp the update
     if (!$silently) {
         $query[] = "edit_name='" . Surfer::get_name() . "'," . "edit_id=" . Surfer::get_id() . "," . "edit_address='" . Surfer::get_email_address() . "'," . "edit_action='{$action}'," . "edit_date='" . strftime('%Y-%m-%d %H:%M:%S') . "'";
     }
     // ensure we have a valid update query
     if (!@count($query)) {
         return;
     }
     // update the anchor category
     $query = "UPDATE " . SQL::table_name('categories') . " SET " . implode(', ', $query) . " WHERE id = " . SQL::escape($this->item['id']);
     if (SQL::query($query) === FALSE) {
         return;
     }
     // always clear the cache, even on no update
     Categories::clear($this->item);
     // get the parent
     if (!$this->anchor) {
         $this->anchor = Anchors::get($this->item['anchor']);
     }
     // propagate the touch upwards silently -- we only want to purge the cache
     if (is_object($this->anchor)) {
         $this->anchor->touch('category:update', $this->item['id'], TRUE);
     }
 }
コード例 #20
0
ファイル: event.php プロジェクト: rair/yacs
 /**
  * get event description in ICS format
  *
  * @param string either 'PUBLISH', 'REQUEST', 'CANCEL', ...
  * @return string content of the ICS
  *
  * @see articles/invite.php
  * @see overlays/events/fetch_ics.php
  */
 function get_ics($method = 'PUBLISH')
 {
     global $context;
     // begin calendar
     $text = 'BEGIN:VCALENDAR' . CRLF . 'VERSION:2.0' . CRLF . 'PRODID:' . $context['host_name'] . CRLF;
     // method
     $text .= 'METHOD:' . $method . CRLF;
     // begin event
     $text .= 'BEGIN:VEVENT' . CRLF;
     // date of creation
     if ($value = $this->anchor->get_value('create_date')) {
         $text .= 'DTSTAMP:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($value)) . CRLF;
     }
     // date of last modification --also required by Outlook
     if ($value = $this->anchor->get_value('edit_date')) {
         $text .= 'LAST-MODIFICATION:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($value)) . CRLF;
     }
     // the event spans limited time --duration is expressed in minutes
     if (isset($this->attributes['duration']) && $this->attributes['duration'] && $this->attributes['duration'] < 1440) {
         $text .= 'DTSTART:' . str_replace(array('-', ' ', ':'), array('', 'T', ''), $this->attributes['date_stamp']) . 'Z' . CRLF;
         $text .= 'DTEND:' . gmdate('Ymd\\THis\\Z', SQL::strtotime($this->attributes['date_stamp']) + $this->attributes['duration'] * 60) . CRLF;
         // a full-day event
     } elseif (isset($this->attributes['date_stamp'])) {
         $text .= 'DTSTART;VALUE=DATE:' . date('Ymd', SQL::strtotime($this->attributes['date_stamp'])) . CRLF;
         $text .= 'DTEND;VALUE=DATE:' . date('Ymd', SQL::strtotime($this->attributes['date_stamp']) + 86400) . CRLF;
     }
     // url to view the date
     $text .= 'URL:' . $context['url_to_home'] . $context['url_to_root'] . $this->anchor->get_url() . CRLF;
     // location is the yacs server
     $text .= 'LOCATION:' . $context['host_name'] . CRLF;
     // build a valid title
     if ($value = $this->anchor->get_title()) {
         $text .= 'SUMMARY:' . Codes::beautify_title($value) . CRLF;
     }
     // description is partially automated
     $text .= 'DESCRIPTION:';
     if ($value = $this->anchor->get_title()) {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Topic'), str_replace(array("\n", "\r"), ' ', Codes::beautify_title($value))) . '\\n';
     }
     // dates
     if (isset($this->attributes['date_stamp']) && $this->attributes['date_stamp']) {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Date'), Skin::build_date($this->attributes['date_stamp'], 'standalone')) . '\\n';
     }
     if (isset($this->attributes['duration']) && $this->attributes['duration'] && $this->attributes['duration'] < 1440) {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Duration'), $this->attributes['duration'] . ' ' . i18n::s('minutes')) . '\\n';
     }
     // build a link to the chairman page, if any
     if (isset($this->attributes['chairman']) && ($user = Users::get($this->attributes['chairman']))) {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Chairman'), $user['full_name']) . '\\n';
     } elseif (($owner = $this->anchor->get_value('owner_id')) && ($user = Users::get($owner))) {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Chairman'), $user['full_name']) . '\\n';
     }
     // location
     if ($method != 'CANCEL') {
         $text .= sprintf(i18n::s('%s: %s'), i18n::s('Location'), $context['url_to_home'] . $context['url_to_root'] . $this->anchor->get_url()) . '\\n';
     }
     // meeting has been cancelled
     if ($method == 'CANCEL') {
         $text .= '\\n\\n' . i18n::c('Meeting has been cancelled.');
         // regular meeting
     } else {
         // copy content of the introduction field, if any
         if ($value = $this->anchor->get_value('introduction')) {
             $text .= '\\n' . strip_tags(str_replace(array('</', '/>', "\n", "\r", ','), array('\\n</', '/>\\n', '\\n', ' ', '\\,'), Codes::beautify($value)));
         }
         // copy the induction message, if any
         if (isset($this->attributes['induction_message'])) {
             $text .= '\\n' . strip_tags(str_replace(array('</', '/>', "\n", "\r", ','), array('\\n</', '/>\\n', '\\n', ' ', '\\,'), Codes::render($this->attributes['induction_message'])));
         }
     }
     // end of the description field
     $text .= CRLF;
     // may be used for updates or for cancellation --required by Outlook 2003
     $text .= 'UID:' . crc32($this->anchor->get_reference() . ':' . $context['url_to_root']) . '@' . $context['host_name'] . CRLF;
     // maybe this one has been cancelled
     if ($method == 'CANCEL') {
         $text .= 'STATUS:CANCELLED' . CRLF;
     }
     // sequence is incremented on each revision
     include_once $context['path_to_root'] . 'versions/versions.php';
     $versions = Versions::count_for_anchor($this->anchor->get_reference());
     $text .= 'SEQUENCE:' . $versions . CRLF;
     // more attributes
     $text .= 'PRIORITY:5' . CRLF . 'TRANSP:OPAQUE' . CRLF . 'CLASS:PUBLIC' . CRLF;
     // alarm to remind the meeting
     if ($method != 'CANCEL') {
         $text .= 'BEGIN:VALARM' . CRLF . 'TRIGGER:-PT15M' . CRLF . 'DESCRIPTION:Reminder' . CRLF . 'ACTION:DISPLAY' . CRLF . 'END:VALARM' . CRLF;
     }
     // close event
     $text .= 'END:VEVENT' . CRLF;
     // close calendar
     $text .= 'END:VCALENDAR' . CRLF;
     // done!
     return $text;
 }
コード例 #21
0
ファイル: layout_articles_as_feed.php プロジェクト: rair/yacs
 /**
  * list articles
  *
  * @param resource the SQL result
  * @return array
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // we return an array of ($url => $attributes)
     $items = array();
     // empty list
     if (!SQL::count($result)) {
         return $items;
     }
     // process all items in the list
     include_once $context['path_to_root'] . 'articles/article.php';
     include_once $context['path_to_root'] . 'comments/comments.php';
     include_once $context['path_to_root'] . 'locations/locations.php';
     while ($item = SQL::fetch($result)) {
         // get the related overlay, if any
         $overlay = Overlay::load($item, 'article:' . $item['id']);
         // get the anchor
         $anchor = Anchors::get($item['anchor']);
         // provide an absolute link
         $url = Articles::get_permalink($item);
         // build a title
         if (is_object($overlay)) {
             $title = Codes::beautify_title($overlay->get_text('title', $item));
         } else {
             $title = Codes::beautify_title($item['title']);
         }
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // the section
         $section = '';
         if ($item['anchor'] && ($anchor = Anchors::get($item['anchor']))) {
             $section = ucfirst(trim(strip_tags(Codes::beautify_title($anchor->get_title()))));
         }
         // the icon to use
         $icon = '';
         if ($item['thumbnail_url']) {
             $icon = $item['thumbnail_url'];
         } elseif ($item['anchor'] && ($anchor = Anchors::get($item['anchor'])) && is_callable($anchor, 'get_bullet_url')) {
             $icon = $anchor->get_bullet_url();
         }
         if ($icon) {
             $icon = $context['url_to_home'] . $context['url_to_root'] . $icon;
         }
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author = '';
         if (isset($item['create_address'])) {
             $author .= $item['create_address'];
         }
         if (isset($item['create_name']) && trim($item['create_name'])) {
             $author .= ' (' . $item['create_name'] . ')';
         }
         if (isset($item['edit_address']) && trim($item['edit_address']) && $item['create_address'] != $item['edit_address']) {
             if ($author) {
                 $author .= ', ';
             }
             $author .= $item['edit_address'];
             if (isset($item['edit_name']) && trim($item['edit_name'])) {
                 $author .= ' (' . $item['edit_name'] . ')';
             }
         }
         // some introductory text for this article
         $article = new Article();
         $article->load_by_content($item);
         $introduction = $article->get_teaser('teaser');
         // warns on restricted access
         if (isset($item['active']) && $item['active'] != 'Y') {
             $introduction = '[' . i18n::c('Restricted to members') . '] ' . $introduction;
         }
         // fix references
         $introduction = preg_replace('/"\\//', '"' . $context['url_to_home'] . '/', $introduction);
         // the article content
         $description = '';
         // other rss fields
         $extensions = array();
         // the geolocation for this page, if any
         if ($location = Locations::locate_anchor('article:' . $item['id'])) {
             $extensions[] = '<georss:point>' . str_replace(',', ' ', $location) . '</georss:point>';
         }
         // url for comments
         if (is_object($anchor)) {
             $extensions[] = '<comments>' . encode_link($context['url_to_home'] . $context['url_to_root'] . $anchor->get_url('comments')) . '</comments>';
         }
         // count comments
         $comment_count = Comments::count_for_anchor('article:' . $item['id']);
         $extensions[] = '<slash:comments>' . $comment_count . "</slash:comments>";
         // the comment post url
         $extensions[] = '<wfw:comment>' . encode_link($context['url_to_home'] . $context['url_to_root'] . Comments::get_url('article:' . $item['id'], 'service.comment')) . "</wfw:comment>";
         // the comment Rss url
         $extensions[] = '<wfw:commentRss>' . encode_link($context['url_to_home'] . $context['url_to_root'] . Comments::get_url('article:' . $item['id'], 'feed')) . "</wfw:commentRss>";
         // the trackback url
         $extensions[] = '<trackback:ping>' . encode_link($context['url_to_home'] . $context['url_to_root'] . 'links/trackback.php?anchor=' . urlencode('article:' . $item['id'])) . "</trackback:ping>";
         // no trackback:about;
         // list all components for this item
         $items[$url] = array($time, $title, $author, $section, $icon, $introduction, $description, $extensions);
     }
     // end of processing
     SQL::free($result);
     return $items;
 }
コード例 #22
0
ファイル: layout_comments_as_feed.php プロジェクト: rair/yacs
 /**
  * list comments
  *
  * @param resource the SQL result
  * @return string the rendered text
  *
  * @see layouts/layout.php
  **/
 function layout($result)
 {
     global $context;
     // empty list
     if (!SQL::count($result)) {
         $output = array();
         return $output;
     }
     // we return an array of ($url => $attributes)
     $items = array();
     // process all items in the list
     include_once $context['path_to_root'] . 'comments/comments.php';
     while ($item = SQL::fetch($result)) {
         // get the anchor for this comment
         $anchor = NULL;
         if (isset($item['anchor']) && $item['anchor']) {
             $anchor = Anchors::get($item['anchor']);
         }
         // url to read the full comment
         $url = $context['url_to_home'] . $context['url_to_root'] . Comments::get_url($item['id']);
         // time of last update
         $time = SQL::strtotime($item['edit_date']);
         // the title as the label
         $label = '';
         if ($item['create_name']) {
             $label .= ucfirst($item['create_name']);
         }
         if (is_object($anchor)) {
             $label .= ' ' . sprintf(i18n::s('on %s'), $anchor->get_title());
         }
         // the section
         $section = '';
         if (is_object($anchor)) {
             $section = ucfirst($anchor->get_title());
         }
         // the icon to use
         $icon = '';
         if (isset($item['thumbnail_url']) && $item['thumbnail_url']) {
             $icon = $item['thumbnail_url'];
         } elseif (is_object($anchor)) {
             $icon = $anchor->get_thumbnail_url();
         }
         if ($icon) {
             $icon = $context['url_to_home'] . $icon;
         }
         // the author(s) is an e-mail address, according to rss 2.0 spec
         $author = $item['create_address'] . ' (' . $item['create_name'] . ')';
         if ($item['create_address'] != $item['edit_address']) {
             if ($author) {
                 $author .= ', ';
             }
             $author .= $item['edit_address'] . ' (' . $item['edit_name'] . ')';
         }
         // the comment content
         $description = Codes::beautify($item['description']);
         // cap the number of words
         //			$description = Skin::cap($description, 300);
         // fix image references
         $description = preg_replace('#"/([^">]+?)"#', '"' . $context['url_to_home'] . '/$1"', $description);
         $introduction = $description;
         // other rss fields
         $extensions = array();
         // list all components for this item
         $items[$url] = array($time, $label, $author, $section, $icon, $introduction, $description, $extensions);
     }
     // end of processing
     SQL::free($result);
     return $items;
 }