if (!Surfer::is_logged()) { Safe::redirect($context['url_to_home'] . $context['url_to_root'] . 'users/login.php?url=' . urlencode(Versions::get_url($item['id']))); } // permission denied to authenticated user Safe::header('Status: 401 Unauthorized', TRUE, 401); Logger::error(i18n::s('You are not allowed to perform this operation.')); // re-enforce the canonical link } elseif ($context['self_url'] && ($canonical = $context['url_to_home'] . $context['url_to_root'] . Versions::get_url($item['id'])) && strncmp($context['self_url'], $canonical, strlen($canonical))) { Safe::header('Status: 301 Moved Permanently', TRUE, 301); Safe::header('Location: ' . $canonical); Logger::error(Skin::build_link($canonical)); // display the version } else { // display details for this version $context['text'] .= '<dl class="version">' . "\n"; if (($attributes = Safe::unserialize($item['content'])) && @count($attributes)) { $fields = array('title' => array(i18n::s('Title'), '', FALSE), 'introduction' => array('', '', TRUE), 'overlay' => array('', '', FALSE, i18n::s('Content of the overlay has changed')), 'description' => array('', '', TRUE), 'tags' => array(i18n::s('Tags'), '', TRUE), 'trailer' => array(i18n::s('Trailer'), BR, FALSE), 'extra' => array(i18n::s('Extra'), BR, FALSE)); foreach ($fields as $name => $params) { if (isset($attributes[$name])) { $compared = $anchor->diff($name, $attributes[$name]); if ($params[2] || strcmp($compared, $attributes[$name])) { // use a constant string instead of showing differences if (isset($params[3])) { $compared = '<ins>' . $params[3] . '</ins>'; } if ($params[0]) { $context['text'] .= '<div style="margin-bottom: 1em;">' . sprintf(i18n::s('%s: %s'), $params[0], $params[1] . $compared) . '</div>'; } else { $context['text'] .= '<div style="margin-bottom: 1em;">' . $params[1] . $compared . '</div>'; } }
/** * pull most recent notification * * This script will wait for new updates before providing them to caller. * Because of potential time-outs, you have to care of retries. * * @return array attributes of the oldest notification, if any * * @see users/heartbit.php */ public static function pull() { global $context; // return by reference $output = NULL; // only authenticated surfers can be notified if (!Surfer::get_id()) { Safe::header('Status: 401 Unauthorized', TRUE, 401); die(i18n::s('You are not allowed to perform this operation.')); } // only consider recent records -- 180 = 3 minutes * 60 seconds $threshold = gmstrftime('%Y-%m-%d %H:%M:%S', time() - 180); // the query to get time of last update $query = "SELECT * FROM " . SQL::table_name('notifications') . " AS notifications " . " WHERE (notifications.recipient = " . SQL::escape(Surfer::get_id()) . ")" . "\tAND (edit_date >= '" . SQL::escape($threshold) . "')" . " ORDER BY notifications.edit_date" . " LIMIT 1"; // stop if there is nothing to return if (!($record = SQL::query_first($query)) || !isset($record['data'])) { return 'NTR'; } // restore the entire record $output = Safe::unserialize($record['data']); // localize on server-side message displayed by the client software $lines = array(); switch ($output['type']) { case 'alert': // a new item has been created if (strpos($output['action'], ':create')) { $lines[] = sprintf(i18n::s('New page: %s'), $output['title']) . "\n" . sprintf(i18n::s('%s by %s'), ucfirst(Anchors::get_action_label($output['action'])), $output['nick_name']) . "\n"; // surfer prompt $lines[] = i18n::s('Would you like to browse the page?'); // else consider this as an update } else { // provide a localized message $lines[] = sprintf(i18n::s('Updated: %s'), $output['title']) . "\n" . sprintf(i18n::s('%s by %s'), ucfirst(Anchors::get_action_label($output['action'])), $output['nick_name']) . "\n"; // surfer prompt $lines[] = i18n::s('Would you like to browse the page?'); } break; case 'browse': // message is optional if (isset($output['message']) && trim($output['message'])) { $lines[] = sprintf(i18n::s('From %s:'), $output['nick_name']) . "\n" . $output['message'] . "\n"; } // address is mandatory $lines[] = i18n::s('Would you like to browse the page?'); break; case 'hello': // message is optional if (isset($output['message']) && trim($output['message'])) { $lines[] = sprintf(i18n::s('From %s:'), $output['nick_name']) . "\n" . $output['message'] . "\n"; } // address is present on new chat if (isset($output['address']) && trim($output['address'])) { $lines[] = i18n::s('Would you like to browse the page?'); } break; } // content of the dialog box that will be displayed to surfer if (count($lines)) { $output['dialog_text'] = implode("\n", $lines); } // forget this notification $query = "DELETE FROM " . SQL::table_name('notifications') . " WHERE id = " . SQL::escape($record['id']); SQL::query($query, TRUE); // return the new notification return $output; }
/** * restore an old version * * This function returns the content of a previous version, * and also purges the stack of previous versions. * * This function populates the error context, where applicable. * * @param int the id of the version to restore * @return TRUE on success, FALSE otherwise */ public static function restore($id) { global $context; // sanity check if (!$id) { return TRUE; } // select among available items -- exact match $query = "SELECT * FROM " . SQL::table_name('versions') . " AS versions" . " WHERE (versions.id = " . SQL::escape($id) . ")"; if (!($item = SQL::query_first($query))) { return FALSE; } // retrieve the related anchor $anchor = Anchors::get($item['anchor']); if (!is_object($anchor)) { Logger::error(sprintf(i18n::s('Unknown anchor %s'), $item['anchor'])); return FALSE; } // inflate the serialized object if necessary if (strncmp($item['content'], 'a:', 2) && is_callable('gzuncompress')) { $item['content'] = gzuncompress(base64_decode($item['content'])); } // restore the anchor if (!$anchor->restore(Safe::unserialize($item['content']))) { Logger::error(i18n::s('Impossible to restore the previous version.')); return FALSE; } // delete records attached to this anchor after version date $query = "DELETE FROM " . SQL::table_name('versions') . " WHERE (anchor LIKE '" . SQL::escape($item['anchor']) . "')" . " AND (edit_date >= '" . SQL::escape($item['edit_date']) . "')"; SQL::query($query); // anchor has been restored return TRUE; }
/** * restore an instance * * This function unserializes piggy-back data and uses it to populate an overlay instance. * * [php] * // get the record from the database * $item = Articles::get($id); * * // extract overlay data from $item['overlay'] * $overlay = Overlay::load($item, 'article:'.$item['id']); * [/php] * * @see articles/delete.php * @see articles/edit.php * @see articles/view.php * * @param array the hosting array * @param string reference of the containing page (e.g., 'article:123') * @return a restored instance, or NULL */ public static final function load($host, $reference = '') { global $context; if (is_object($host)) { $data = $host->item; } else { $data = $host; } // no overlay yet if (!isset($data['overlay']) || !$data['overlay']) { return NULL; } // retrieve the content of the overlay if (($attributes = Safe::unserialize($data['overlay'])) === FALSE) { return NULL; } // restore unicode entities foreach ($attributes as $name => $value) { if (is_string($value)) { $attributes[$name] = utf8::from_unicode($value); } } // we need a type if (!is_array($attributes) || !isset($attributes['overlay_type'])) { return NULL; } // bind this to current page if (isset($data['id'])) { $attributes['id'] = $data['id']; } // use one particular overlay instance $overlay = Overlay::bind($attributes['overlay_type']); if (is_object($overlay)) { $overlay->attributes = $attributes; // expose all of the anchor interface to the contained overlay if (!is_object($host)) { $overlay->anchor = Anchors::get($reference); } else { $overlay->anchor = $host; } // ready to use! return $overlay; } // unknown overlay type or empty overlay return NULL; }
// display the image full size } else { // initialize the rendering engine Codes::initialize(Images::get_url($item['id'])); // page main content // // insert anchor prefix if (is_object($anchor)) { $context['text'] .= $anchor->get_prefix(); } // retrieve slideshow links if we have an anchor if (is_object($anchor)) { // retrieve information from cache, if any $cache_id = 'images/view.php?id=' . $item['id'] . '#navigation'; if ($data = Cache::get($cache_id)) { $data = Safe::unserialize($data); } else { $data = $anchor->get_neighbours('image', $item); // save in cache $text = serialize($data); Cache::put($cache_id, $text, 'images'); } // links to display previous and next pages, if any $context['text'] .= Skin::neighbours($data, 'slideshow'); // a meta link to prefetch the next page if (isset($data[2]) && $data[2]) { $context['page_header'] .= "\n" . '<link rel="next" href="' . $context['url_to_root'] . $data[2] . '" title="' . encode_field($data[3]) . '" />'; } } // image description $context['text'] .= Skin::build_block($item['description'], 'description');
$credentials = NULL; if (isset($_REQUEST['credentials'])) { $credentials = $_REQUEST['credentials']; } elseif (isset($context['arguments'][0])) { $credentials = $context['arguments'][0]; } $credentials = strip_tags($credentials); // fix credentials if followed by text if ($credentials && ($position = strpos($credentials, '-'))) { $credentials = substr($credentials, 0, $position); } // data has been serialized, then base64 encoded if ($credentials && ($credentials = base64_decode($credentials))) { // json is more efficient, but we may have to fall-back to php serialization if (!($credentials = Safe::json_decode($credentials))) { $credentials = Safe::unserialize($credentials); } } // load localized strings if (is_callable(array('i18n', 'bind'))) { i18n::bind('users'); } // load the skin load_skin('users'); // page title if (!Surfer::is_logged()) { $context['page_title'] = i18n::s('Who are you?'); } else { $context['page_title'] = i18n::s('You are') . ' ' . Surfer::get_name(); } // stop crawlers