Beispiel #1
0
 /**
  * reference another page at this site
  *
  * The function transforms a local reference (e.g;, [code][user=2][/code])
  * to an actual link relative to the YACS directory (e.g., [code]users/view.php/2[/code]),
  * adds a title and, sometimes, set a description as well.
  *
  * @param string any string, maybe with a local reference in it
  * @return an array($url, $title, $description) or NULL
  *
  * @see images/view.php
  * @see links/edit.php
  * @see shared/codes.php
  */
 public static function transform_reference($text)
 {
     global $context;
     // translate this reference to an internal link
     if (preg_match("/^\\[(article|section|file|image|category|user)=(.+?)\\]/i", $text, $matches)) {
         switch ($matches[1]) {
             // article link
             case 'article':
                 if ($item = Articles::get($matches[2])) {
                     return array(Articles::get_permalink($item), $item['title'], $item['introduction']);
                 }
                 return array('', $text, '');
                 // section link
             // section link
             case 'section':
                 if ($item = Sections::get($matches[2])) {
                     return array(Sections::get_permalink($item), $item['title'], $item['introduction']);
                 }
                 return array('', $text, '');
                 // file link
             // file link
             case 'file':
                 if ($item = Files::get($matches[2])) {
                     return array(Files::get_url($matches[2]), $item['title'] ? $item['title'] : str_replace('_', ' ', ucfirst($item['file_name'])));
                 }
                 return array('', $text, '');
                 // image link
             // image link
             case 'image':
                 include_once $context['path_to_root'] . 'images/images.php';
                 if ($item = Images::get($matches[2])) {
                     return array(Images::get_url($matches[2]), $item['title'] ? $item['title'] : str_replace('_', ' ', ucfirst($item['image_name'])));
                 }
                 return array('', $text, '');
                 // category link
             // category link
             case 'category':
                 if ($item = Categories::get($matches[2])) {
                     return array(Categories::get_permalink($item), $item['title'], $item['introduction']);
                 }
                 return array('', $text, '');
                 // user link
             // user link
             case 'user':
                 if ($item = Users::get($matches[2])) {
                     return array(Users::get_permalink($item), $item['full_name'] ? $item['full_name'] : $item['nick_name']);
                 }
                 return array('', $text, '');
         }
     }
     return array('', $text, '');
 }
Beispiel #2
0
if (isset($_REQUEST['id'])) {
    $id = $_REQUEST['id'];
} elseif (isset($context['arguments'][0])) {
    $id = $context['arguments'][0];
}
$id = strip_tags($id);
// additional action, if any
$action = NULL;
if (isset($_REQUEST['action'])) {
    $action = $_REQUEST['action'];
} elseif (isset($context['arguments'][1])) {
    $action = $context['arguments'][1];
}
$action = strip_tags($action);
// get the item from the database
$item = Files::get($id);
// get the related anchor, if any
$anchor = NULL;
if (isset($item['anchor']) && $item['anchor']) {
    $anchor = Anchors::get($item['anchor']);
}
// get related behaviors, if any
$behaviors = NULL;
include_once '../behaviors/behaviors.php';
if (isset($item['id'])) {
    $behaviors = new Behaviors($item, $anchor);
}
// change default behavior
if (isset($item['id']) && is_object($behaviors) && !$behaviors->allow('files/fetch.php', 'file:' . $item['id'])) {
    $permitted = FALSE;
} elseif (Files::allow_access($item, $anchor)) {
Beispiel #3
0
 /** 
  * render a sound object with dewplayer
  * 
  * @global type $context
  * @param type $id
  * @return string 
  */
 public static function render_sound($id)
 {
     global $context;
     // maybe an alternate title has been provided
     $attributes = preg_split("/\\s*,\\s*/", $id, 2);
     $id = $attributes[0];
     $flashvars = '';
     if (isset($attributes[1])) {
         $flashvars = $attributes[1];
     }
     // get the file
     if (!($item = Files::get($id))) {
         $output = '[sound=' . $id . ']';
         return $output;
     }
     // where to get the file
     if (isset($item['file_href']) && $item['file_href']) {
         $url = $item['file_href'];
     } else {
         $url = $context['url_to_home'] . $context['url_to_root'] . 'files/' . str_replace(':', '/', $item['anchor']) . '/' . rawurlencode($item['file_name']);
     }
     // several ways to play flash
     switch (strtolower(substr(strrchr($url, '.'), 1))) {
         // stream a sound file
         case 'mp3':
             // a flash player to stream a sound
             $dewplayer_url = $context['url_to_root'] . 'included/browser/dewplayer.swf';
             if ($flashvars) {
                 $flashvars = 'son=' . $url . '&' . $flashvars;
             } else {
                 $flashvars = 'son=' . $url;
             }
             $output = '<div id="sound_' . $item['id'] . '" class="no_print">Flash plugin or Javascript are turned off. Activate both and reload to view the object</div>' . "\n";
             Page::insert_script('var params = {};' . "\n" . 'params.base = "' . dirname($url) . '/";' . "\n" . 'params.quality = "high";' . "\n" . 'params.wmode = "transparent";' . "\n" . 'params.menu = "false";' . "\n" . 'params.flashvars = "' . $flashvars . '";' . "\n" . 'swfobject.embedSWF("' . $dewplayer_url . '", "sound_' . $item['id'] . '", "200", "20", "6", "' . $context['url_to_home'] . $context['url_to_root'] . 'included/browser/expressinstall.swf", false, params);' . "\n");
             return $output;
             // link to file page
         // link to file page
         default:
             // link label
             $text = Skin::strip($item['title'] ? $item['title'] : str_replace('_', ' ', $item['file_name']));
             // make a link to the target page
             $url = Files::get_download_url($item);
             // return a complete anchor
             $output =& Skin::build_link($url, $text, 'basic');
             return $output;
     }
 }
Beispiel #4
0
 /**
  * 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);
     }
 }
Beispiel #5
0
 /**
  * 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);
     }
 }
Beispiel #6
0
 /**
  * load the related item
  *
  * @param int the id of the record to load
  * @param boolean TRUE to always fetch a fresh instance, FALSE to enable cache
  *
  * @see shared/anchor.php
  */
 function load_by_id($id, $mutable = FALSE)
 {
     $this->item = Files::get($id, $mutable);
 }
Beispiel #7
0
 /**
  * process uploaded file
  *
  * This function processes files from the temporary directory, and put them at their definitive
  * place.
  *
  * It returns FALSE if there is a disk error, or if some virus has been detected, or if
  * the operation fails for some other reason (e.g., file size).
  *
  * @param array usually, $_FILES['upload']
  * @param string target location for the file
  * @param mixed reference to the target anchor, of a function to parse every file individually
  * @return mixed file name or array of file names or FALSE if an error has occured
  */
 public static function upload($input, $file_path, $target = NULL, $overlay = NULL)
 {
     global $context, $_REQUEST;
     // size exceeds php.ini settings -- UPLOAD_ERR_INI_SIZE
     if (isset($input['error']) && $input['error'] == 1) {
         Logger::error(i18n::s('The size of this file is over limit.'));
     } elseif (isset($input['error']) && $input['error'] == 2) {
         Logger::error(i18n::s('The size of this file is over limit.'));
     } elseif (isset($input['error']) && $input['error'] == 3) {
         Logger::error(i18n::s('No file has been transmitted.'));
     } elseif (isset($input['error']) && $input['error'] == 4) {
         Logger::error(i18n::s('No file has been transmitted.'));
     } elseif (!$input['size']) {
         Logger::error(i18n::s('No file has been transmitted.'));
     }
     // do we have a file?
     if (!isset($input['name']) || !$input['name'] || $input['name'] == 'none') {
         return FALSE;
     }
     // access the temporary uploaded file
     $file_upload = $input['tmp_name'];
     // $_FILES transcoding to utf8 is not automatic
     $input['name'] = utf8::encode($input['name']);
     // enhance file name
     $file_name = $input['name'];
     $file_extension = '';
     $position = strrpos($input['name'], '.');
     if ($position !== FALSE) {
         $file_name = substr($input['name'], 0, $position);
         $file_extension = strtolower(substr($input['name'], $position + 1));
     }
     $input['name'] = $file_name;
     if ($file_extension) {
         $input['name'] .= '.' . $file_extension;
     }
     // ensure we have a file name
     $file_name = utf8::to_ascii($input['name']);
     // uploads are not allowed
     if (!Surfer::may_upload()) {
         Logger::error(i18n::s('You are not allowed to perform this operation.'));
     } elseif (!Files::is_authorized($input['name'])) {
         Logger::error(i18n::s('This type of file is not allowed.'));
     } elseif ($file_path && !Safe::is_uploaded_file($file_upload)) {
         Logger::error(i18n::s('Possible file attack.'));
     } else {
         // create folders
         if ($file_path) {
             Safe::make_path($file_path);
         }
         // sanity check
         if ($file_path && $file_path[strlen($file_path) - 1] != '/') {
             $file_path .= '/';
         }
         // move the uploaded file
         if ($file_path && !Safe::move_uploaded_file($file_upload, $context['path_to_root'] . $file_path . $file_name)) {
             Logger::error(sprintf(i18n::s('Impossible to move the upload file to %s.'), $file_path . $file_name));
         } else {
             // process the file where it is
             if (!$file_path) {
                 $file_path = str_replace($context['path_to_root'], '', dirname($file_upload));
                 $file_name = basename($file_upload);
             }
             // check against viruses
             $result = Files::has_virus($context['path_to_root'] . $file_path . '/' . $file_name);
             // no virus has been found in this file
             if ($result == 'N') {
                 $context['text'] .= Skin::build_block(i18n::s('No virus has been found.'), 'note');
             }
             // this file has been infected!
             if ($result == 'Y') {
                 // delete this file immediately
                 Safe::unlink($file_path . '/' . $file_name);
                 Logger::error(i18n::s('This file has been infected by a virus and has been rejected!'));
                 return FALSE;
             }
             // explode a .zip file
             include_once $context['path_to_root'] . 'shared/zipfile.php';
             if (preg_match('/\\.zip$/i', $file_name) && isset($_REQUEST['explode_files'])) {
                 $zipfile = new zipfile();
                 // check files extracted from the archive file
                 function explode_callback($name)
                 {
                     global $context;
                     // reject all files put in sub-folders
                     if (($path = substr($name, strlen($context['uploaded_path'] . '/'))) && strpos($path, '/') !== FALSE) {
                         Safe::unlink($name);
                     } elseif (!Files::is_authorized($name)) {
                         Safe::unlink($name);
                     } else {
                         // make it easy to download
                         $ascii = utf8::to_ascii(basename($name));
                         Safe::rename($name, $context['uploaded_path'] . '/' . $ascii);
                         // remember this name
                         $context['uploaded_files'][] = $ascii;
                     }
                 }
                 // extract archive components and save them in mentioned directory
                 $context['uploaded_files'] = array();
                 $context['uploaded_path'] = $file_path;
                 if (!($count = $zipfile->explode($context['path_to_root'] . $file_path . '/' . $file_name, $file_path, '', 'explode_callback'))) {
                     Logger::error(sprintf('Nothing has been extracted from %s.', $file_name));
                     return FALSE;
                 }
                 // one single file has been uploaded
             } else {
                 $context['uploaded_files'] = array($file_name);
             }
             // ensure we know the surfer
             Surfer::check_default_editor($_REQUEST);
             // post-process all uploaded files
             foreach ($context['uploaded_files'] as $file_name) {
                 // this will be filtered by umask anyway
                 Safe::chmod($context['path_to_root'] . $file_path . $file_name, $context['file_mask']);
                 // invoke post-processing function
                 if ($target && is_callable($target)) {
                     call_user_func($target, $file_name, $context['path_to_root'] . $file_path);
                     // we have to update an anchor page
                 } elseif ($target && is_string($target)) {
                     $fields = array();
                     // update a file with the same name for this anchor
                     if ($matching =& Files::get_by_anchor_and_name($target, $file_name)) {
                         $fields['id'] = $matching['id'];
                     } elseif (isset($input['id']) && ($matching = Files::get($input['id']))) {
                         $fields['id'] = $matching['id'];
                         // silently delete the previous version of the file
                         if (isset($matching['file_name'])) {
                             Safe::unlink($file_path . '/' . $matching['file_name']);
                         }
                     }
                     // prepare file record
                     $fields['file_name'] = $file_name;
                     $fields['file_size'] = filesize($context['path_to_root'] . $file_path . $file_name);
                     $fields['file_href'] = '';
                     $fields['anchor'] = $target;
                     // change title
                     if (isset($_REQUEST['title'])) {
                         $fields['title'] = $_REQUEST['title'];
                     }
                     // change has been documented
                     if (!isset($_REQUEST['version']) || !$_REQUEST['version']) {
                         $_REQUEST['version'] = '';
                     } else {
                         $_REQUEST['version'] = ' - ' . $_REQUEST['version'];
                     }
                     // always remember file uploads, for traceability
                     $_REQUEST['version'] = $fields['file_name'] . ' (' . Skin::build_number($fields['file_size'], i18n::s('bytes')) . ')' . $_REQUEST['version'];
                     // add to file history
                     $fields['description'] = Files::add_to_history($matching, $_REQUEST['version']);
                     // if this is an image, maybe we can derive a thumbnail for it?
                     if (Files::is_image($file_name)) {
                         include_once $context['path_to_root'] . 'images/image.php';
                         Image::shrink($context['path_to_root'] . $file_path . $file_name, $context['path_to_root'] . $file_path . 'thumbs/' . $file_name);
                         if (file_exists($context['path_to_root'] . $file_path . 'thumbs/' . $file_name)) {
                             $fields['thumbnail_url'] = $context['url_to_home'] . $context['url_to_root'] . $file_path . 'thumbs/' . rawurlencode($file_name);
                         }
                     }
                     // change active_set
                     if (isset($_REQUEST['active_set'])) {
                         $fields['active_set'] = $_REQUEST['active_set'];
                     }
                     // change source
                     if (isset($_REQUEST['source'])) {
                         $fields['source'] = $_REQUEST['source'];
                     }
                     // change keywords
                     if (isset($_REQUEST['keywords'])) {
                         $fields['keywords'] = $_REQUEST['keywords'];
                     }
                     // change alternate_href
                     if (isset($_REQUEST['alternate_href'])) {
                         $fields['alternate_href'] = $_REQUEST['alternate_href'];
                     }
                     // overlay, if any
                     if (is_object($overlay)) {
                         // allow for change detection
                         $overlay->snapshot();
                         // update the overlay from form content
                         $overlay->parse_fields($_REQUEST);
                         // save content of the overlay in this item
                         $fields['overlay'] = $overlay->save();
                         $fields['overlay_id'] = $overlay->get_id();
                     }
                     // create the record in the database
                     if (!($fields['id'] = Files::post($fields))) {
                         return FALSE;
                     }
                     // record surfer activity
                     Activities::post('file:' . $fields['id'], 'upload');
                 }
             }
             // so far so good
             if (count($context['uploaded_files']) == 1) {
                 return $context['uploaded_files'][0];
             } else {
                 return $context['uploaded_files'];
             }
         }
     }
     // some error has occured
     return FALSE;
 }
Beispiel #8
0
 /**
  * render a link to an object
  *
  * Following types are supported:
  * - article - link to an article page
  * - category - link to a category page
  * - comment - link to a comment page
  * - download - link to a download page
  * - file - link to a file page
  * - flash - display a file as a native flash object, or play a flash video
  * - go
  * - image - display an in-line image
  * - next - link to an article page
  * - previous - link to an article page
  * - section - link to a section page
  * - server - link to a server page
  * - user - link to a user page
  *
  * @param string the type
  * @param string the id, with possible options or variant
  * @return string the rendered text
  **/
 public static function render_object($type, $id)
 {
     global $context;
     $id = Codes::fix_tags($id);
     // depending on type
     switch ($type) {
         // link to an article
         case 'article':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Articles::get($id))) {
                 $output = '[article=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Articles::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, $type);
             }
             return $output;
             // insert article description
         // insert article description
         case 'article.description':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Articles::get($id))) {
                 $output = '[article.description=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Articles::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, 'article');
                 // the introduction text, if any
                 $output .= BR . Codes::beautify($item['introduction']);
                 // load overlay, if any
                 if (isset($item['overlay']) && $item['overlay']) {
                     $overlay = Overlay::load($item, 'article:' . $item['id']);
                     // get text related to the overlay, if any
                     if (is_object($overlay)) {
                         $output .= $overlay->get_text('view', $item);
                     }
                 }
                 // the description, which is the actual page body
                 $output .= '<div>' . Codes::beautify($item['description']) . '</div>';
             }
             return $output;
             // link to a category
         // link to a category
         case 'category':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Categories::get($id))) {
                 $output = '[category=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Categories::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, $type);
             }
             return $output;
             // insert category description
         // insert category description
         case 'category.description':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Categories::get($id))) {
                 $output = '[category.description=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Categories::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, 'category');
                 // the introduction text, if any
                 $output .= BR . Codes::beautify($item['introduction']);
                 // load overlay, if any
                 if (isset($item['overlay']) && $item['overlay']) {
                     $overlay = Overlay::load($item, 'category:' . $item['id']);
                     // get text related to the overlay, if any
                     if (is_object($overlay)) {
                         $output .= $overlay->get_text('view', $item);
                     }
                 }
                 // the description, which is the actual page body
                 $output .= '<div>' . Codes::beautify($item['description']) . '</div>';
             }
             return $output;
             // link to a comment
         // link to a comment
         case 'comment':
             include_once $context['path_to_root'] . 'comments/comments.php';
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Comments::get($id))) {
                 $output = '[comment=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                 } else {
                     $text = i18n::s('View this comment');
                 }
                 // make a link to the target page
                 $url = $context['url_to_home'] . $context['url_to_root'] . Comments::get_url($item['id']);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, 'basic');
             }
             return $output;
             // link to a download
         // link to a download
         case 'download':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Files::get($id))) {
                 // file does not exist anymore
                 if (isset($attributes[1]) && $attributes[1]) {
                     $output = $attributes[1] . '<p class="details">' . i18n::s('[this file has been deleted]') . '</p>';
                 } else {
                     $output = '[download=' . $id . ']';
                 }
             } else {
                 // label for this file
                 $prefix = $text = $suffix = '';
                 // signal restricted and private files
                 if ($item['active'] == 'N') {
                     $prefix .= PRIVATE_FLAG;
                 } elseif ($item['active'] == 'R') {
                     $prefix .= RESTRICTED_FLAG;
                 }
                 // ensure we have a label for this link
                 if (isset($attributes[1]) && $attributes[1]) {
                     $text .= $attributes[1];
                     // this may describe a previous file, which has been replaced
                     if ($item['edit_action'] != 'file:create' && $attributes[1] != $item['file_name']) {
                         $text .= ' <p class="details">' . i18n::s('[this file has been replaced]') . '</p>';
                         $output = $prefix . $text . $suffix;
                         return $output;
                     }
                 } else {
                     $text = Skin::strip($item['title'] ? $item['title'] : str_replace('_', ' ', $item['file_name']));
                 }
                 // flag files uploaded recently
                 if ($item['create_date'] >= $context['fresh']) {
                     $suffix .= NEW_FLAG;
                 } elseif ($item['edit_date'] >= $context['fresh']) {
                     $suffix .= UPDATED_FLAG;
                 }
                 // always download the file
                 $url = $context['url_to_home'] . $context['url_to_root'] . Files::get_url($item['id'], 'fetch', $item['file_name']);
                 // return a complete anchor
                 $output = $prefix . Skin::build_link($url, $text, 'file') . $suffix;
             }
             return $output;
             // link to a file
         // link to a file
         case 'file':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database --ensure we get a fresh copy of the record, not a cached one
             if (!($item = Files::get($id, TRUE))) {
                 // file does not exist anymore
                 if (isset($attributes[1]) && $attributes[1]) {
                     $output = $attributes[1] . '<p class="details">' . i18n::s('[this file has been deleted]') . '</p>';
                 } else {
                     $output = '[file=' . $id . ']';
                 }
             } else {
                 // maybe we want to illustrate this file
                 if ($item['edit_action'] != 'file:create' && isset($attributes[1]) && $attributes[1] || !($output = Files::interact($item))) {
                     // label for this file
                     $output = $prefix = $text = $suffix = '';
                     // signal restricted and private files
                     if ($item['active'] == 'N') {
                         $prefix .= PRIVATE_FLAG;
                     } elseif ($item['active'] == 'R') {
                         $prefix .= RESTRICTED_FLAG;
                     }
                     // ensure we have a label for this link
                     if (isset($attributes[1]) && $attributes[1]) {
                         $text .= $attributes[1];
                         // this may describe a previous file, which has been replaced
                         if ($item['edit_action'] != 'file:create' && $attributes[1] != $item['file_name']) {
                             $text .= '<p class="details">' . i18n::s('[this file has been replaced]') . '</p>';
                             $output = $prefix . $text . $suffix;
                             return $output;
                         }
                     } else {
                         $text .= Skin::strip($item['title'] ? $item['title'] : str_replace('_', ' ', $item['file_name']));
                     }
                     // flag files uploaded recently
                     if ($item['create_date'] >= $context['fresh']) {
                         $suffix .= NEW_FLAG;
                     } elseif ($item['edit_date'] >= $context['fresh']) {
                         $suffix .= UPDATED_FLAG;
                     }
                     // make a link to the target page
                     $url = Files::get_download_url($item);
                     // return a complete anchor
                     $output .= $prefix . Skin::build_link($url, $text, 'basic') . $suffix;
                 }
             }
             return $output;
             // invoke the selector
         // invoke the selector
         case 'go':
             // extract the label, if any
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $name = $attributes[0];
             // ensure we have a label for this link
             if (isset($attributes[1])) {
                 $text = $attributes[1];
             } else {
                 $text = $name;
             }
             // return a complete anchor
             $output = Skin::build_link($context['url_to_home'] . $context['url_to_root'] . normalize_shortcut($name), $text, 'basic');
             return $output;
             // embed an image
         // embed an image
         case 'image':
             include_once $context['path_to_root'] . 'images/images.php';
             // get the variant, if any
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             if (isset($attributes[1])) {
                 $variant = $attributes[1];
             } else {
                 $variant = 'inline';
             }
             // get the image record
             if (!($image = Images::get($id))) {
                 $output = '[image=' . $id . ']';
                 return $output;
             }
             // a title for the image --do not force a title
             if (isset($image['title'])) {
                 $title = $image['title'];
             } else {
                 $title = '';
             }
             // provide thumbnail if not defined, or forced, or for large images
             if (!$image['use_thumbnail'] || $image['use_thumbnail'] == 'A' || $image['use_thumbnail'] == 'Y' && $image['image_size'] > $context['thumbnail_threshold']) {
                 // not inline anymore, but thumbnail --preserve other variants
                 if ($variant == 'inline') {
                     $variant = 'thumbnail';
                 }
                 // where to fetch the image file
                 $href = Images::get_thumbnail_href($image);
                 // to drive to plain image
                 $link = Images::get_icon_href($image);
                 // add an url, if any
             } elseif ($image['link_url']) {
                 // flag large images
                 if ($image['image_size'] > $context['thumbnail_threshold']) {
                     $variant = rtrim('large ' . $variant);
                 }
                 // where to fetch the image file
                 $href = Images::get_icon_href($image);
                 // transform local references, if any
                 include_once $context['path_to_root'] . '/links/links.php';
                 $attributes = Links::transform_reference($image['link_url']);
                 if ($attributes[0]) {
                     $link = $context['url_to_root'] . $attributes[0];
                 } else {
                     $link = $image['link_url'];
                 }
                 // get the <img ... /> element
             } else {
                 // do not append poor titles to inline images
                 if ($variant == 'inline') {
                     $title = '';
                 }
                 // flag large images
                 if ($image['image_size'] > $context['thumbnail_threshold']) {
                     $variant = rtrim('large ' . $variant);
                 }
                 // where to fetch the image file
                 $href = Images::get_icon_href($image);
                 // no link
                 $link = '';
             }
             // use the skin
             if (Images::allow_modification($image['anchor'], $id)) {
                 // build editable image
                 $output =& Skin::build_image($variant, $href, $title, $link, $id);
             } else {
                 $output =& Skin::build_image($variant, $href, $title, $link);
             }
             return $output;
             // embed a stack of images
         // embed a stack of images
         case 'images':
             include_once $context['path_to_root'] . 'images/images.php';
             // get the list of ids
             $ids = preg_split("/\\s*,\\s*/", $id);
             if (!count($ids)) {
                 $output = '[images=id1, id2, ...]';
                 return $output;
             }
             // build the list of images
             $items = array();
             foreach ($ids as $id) {
                 // get the image record
                 if ($image = Images::get($id)) {
                     // a title for the image --do not force a title
                     if (isset($image['title'])) {
                         $title = $image['title'];
                     } else {
                         $title = '';
                     }
                     // provide thumbnail if not defined, or forced, or for large images
                     $variant = 'inline';
                     if (!$image['use_thumbnail'] || $image['use_thumbnail'] == 'A' || $image['use_thumbnail'] == 'Y' && $image['image_size'] > $context['thumbnail_threshold']) {
                         // not inline anymore, but thumbnail
                         $variant = 'thumbnail';
                         // where to fetch the image file
                         $href = Images::get_thumbnail_href($image);
                         // to drive to plain image
                         $link = $context['url_to_root'] . Images::get_url($id);
                         // add an url, if any
                     } elseif ($image['link_url']) {
                         // flag large images
                         if ($image['image_size'] > $context['thumbnail_threshold']) {
                             $variant = rtrim('large ' . $variant);
                         }
                         // where to fetch the image file
                         $href = Images::get_icon_href($image);
                         // transform local references, if any
                         include_once $context['path_to_root'] . '/links/links.php';
                         $attributes = Links::transform_reference($image['link_url']);
                         if ($attributes[0]) {
                             $link = $context['url_to_root'] . $attributes[0];
                         } else {
                             $link = $image['link_url'];
                         }
                         // get the <img ... /> element
                     } else {
                         // flag large images
                         if ($image['image_size'] > $context['thumbnail_threshold']) {
                             $variant = rtrim('large ' . $variant);
                         }
                         // where to fetch the image file
                         $href = Images::get_icon_href($image);
                         // no link
                         $link = '';
                     }
                     // use the skin
                     $label =& Skin::build_image($variant, $href, $title, $link);
                     // add item to the stack
                     $items[] = $label;
                 }
             }
             // format the list
             $output = '';
             if (count($items)) {
                 // stack items
                 $output = Skin::finalize_list($items, 'stack');
                 // rotate items
                 $output = Skin::rotate($output);
             }
             // done
             return $output;
             // link to the next article
         // link to the next article
         case 'next':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Articles::get($id))) {
                 $output = '[next=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Articles::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, 'next');
             }
             return $output;
             // link to the previous article
         // link to the previous article
         case 'previous':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Articles::get($id))) {
                 $output = '[previous=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Articles::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, 'previous');
             }
             return $output;
             // link to a section
         // link to a section
         case 'section':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Sections::get($id))) {
                 $output = '[section=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = Sections::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, $type);
             }
             return $output;
             // link to a server
         // link to a server
         case 'server':
             include_once $context['path_to_root'] . 'servers/servers.php';
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Servers::get($id))) {
                 $output = '[server=' . $id . ']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } else {
                     $text = Skin::strip($item['title']);
                 }
                 // make a link to the target page
                 $url = $context['url_to_home'] . $context['url_to_root'] . Servers::get_url($id);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, $type);
             }
             return $output;
             // link to a user
         // link to a user
         case 'user':
             // maybe an alternate title has been provided
             $attributes = preg_split("/\\s*,\\s*/", $id, 2);
             $id = $attributes[0];
             // load the record from the database
             if (!($item = Users::get($id))) {
                 $output = '[user='******']';
             } else {
                 // ensure we have a label for this link
                 if (isset($attributes[1])) {
                     $text = $attributes[1];
                     $type = 'basic';
                 } elseif (isset($item['full_name']) && $item['full_name']) {
                     $text = ucfirst($item['full_name']);
                 } else {
                     $text = ucfirst($item['nick_name']);
                 }
                 // make a link to the target page
                 $url = Users::get_permalink($item);
                 // return a complete anchor
                 $output =& Skin::build_link($url, $text, $type);
             }
             return $output;
             // invalid type
         // invalid type
         default:
             $output = '[' . $type . ']';
             return $output;
     }
 }