You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

428 lines
14 KiB

<?php
// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
//
// All Rights Reserved. See copyright.txt for details and a complete list of authors.
// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
// $Id$
/**
* PerspectiveLib
*
*/
class PerspectiveLib
{
private $perspectives;
private $perspectivePreferences;
/**
*
*/
public function __construct()
{
$this->perspectives = TikiDb::get()->table('tiki_perspectives');
$this->perspectivePreferences = TikiDb::get()->table('tiki_perspective_preferences');
}
/**
* @param $user
* @return int
*/
public function get_preferred_perspective($user)
{
$perspectiveId = null;
if (empty($user)) {
return $perspectiveId;
}
$sql = "SELECT value FROM tiki_user_preferences WHERE prefName='perspective_preferred' AND user=?";
$perspectiveId = TikiDb::get()->getOne($sql, [$user]);
if (is_numeric($perspectiveId)) {
return (int) $perspectiveId;
}
return $perspectiveId;
}
/**
* @param $prefs
* @return int
*/
public function get_current_perspective($prefs)
{
global $user;
$tikilib = TikiLib::lib('tiki');
$perspectiveId = $this->get_preferred_perspective($user);
if (isset($_REQUEST['perspectiveId'])) {
$perspectiveId = (int) $_REQUEST['perspectiveId'];
} elseif (isset($_SESSION['current_perspective'])) {
$perspectiveId = (int) $_SESSION['current_perspective'];
}
if ($perspectiveId) {
return $perspectiveId;
}
if (method_exists($tikilib, "get_ip_address")) {
$ip = $tikilib->get_ip_address();
}
foreach ($this->get_subnet_map($prefs) as $subnet => $perspective) {
if ($this->is_in_subnet($ip, $subnet)) {
return $perspective;
}
}
$currentDomain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
foreach ($this->get_domain_map($prefs) as $domain => $perspective) {
if ($domain == $currentDomain) {
$_SESSION['current_perspective'] = trim($perspective);
$_SESSION['current_perspective_name'] = $this->get_perspective_name($_SESSION['current_perspective']);
return $perspective;
}
}
}
/**
* @param $prefs
* @param $active_pref
* @param $config_pref
* @return array
*/
private function get_map($prefs, $active_pref, $config_pref)
{
if (! $prefs) {
global $prefs;
}
$out = [];
if (( ! empty($prefs[$active_pref]) && $prefs[$active_pref] != 'n' ) && isset($prefs[$config_pref])) {
foreach (explode("\n", $prefs[$config_pref]) as $config) {
if (substr_count($config, ',') == 1) {
// Ignore lines which don't have exactly one comma, such as empty lines.
// TODO: make sure there are no such lines in the first place
list($domain, $perspective) = explode(',', $config);
$out[$domain] = trim($perspective);
}
}
}
return $out;
}
/**
* @param null $prefs
* @return array
*/
public function get_subnet_map($prefs = null)
{
return $this->get_map($prefs, 'site_terminal_active', 'site_terminal_config');
}
/**
* @param null $prefs
* @return array
*/
public function get_domain_map($prefs = null)
{
return $this->get_map($prefs, 'multidomain_active', 'multidomain_config');
}
/**
* @param $ip
* @param $subnet
* @return bool
*/
private function is_in_subnet($ip, $subnet)
{
list($subnet, $size) = explode('/', $subnet);
// Warning - bit shifting ahead.
// Create the real mask from the /X suffix
$mask = 0xFFFFFFFF ^ ((1 << (int) (32 - $size)) - 1);
// Make sure the subnet-relevant part matches for the IP and the subnet being compared
return (ip2long($subnet) & $mask) === (ip2long($ip) & $mask);
}
/**
* Returns a string-indexed array containing the preferences for the given perspective as "pref_name" => "pref_value".
*
*/
public function get_preferences($perspectiveId)
{
$result = TikiDb::get()->query("SELECT pref, value FROM tiki_perspective_preferences WHERE perspectiveId = ?", [ $perspectiveId ]);
$out = [];
while ($row = $result->fetchRow()) {
$out[ $row['pref'] ] = unserialize($row['value']);
}
return $out;
}
public function load_perspective_preferences()
{
global $prefs, $section;
if (! isset($section) || $section != 'admin') {
if ($persp = $this->get_current_perspective($prefs)) {
$perspectivePreferences = $this->get_preferences($persp);
$prefs = $perspectivePreferences + $prefs;
}
}
return $prefs;
}
/**
* @param $perspectiveId
* @return mixed
*/
public function get_perspective($perspectiveId)
{
$result = TikiDb::get()->query("SELECT perspectiveId, name FROM tiki_perspectives WHERE perspectiveId = ?", [ $perspectiveId ]);
if ($info = $result->fetchRow()) {
$perms = Perms::get([ 'type' => 'perspective', 'object' => $perspectiveId ]);
if ($perms->perspective_view) {
$info['preferences'] = $this->get_preferences($perspectiveId);
$this->write_permissions($info, $perms);
return $info;
}
}
}
/**
* Changes the current perspective and redirects if multidomain_switchdomain enabled
*
* @param int $perspective perspective id
* @param bool $by_area switched by the "areas" feature according to content, so keeps the same REQUEST_URI
*/
public function set_perspective($perspective, $by_area = false)
{
global $prefs, $url_scheme, $user, $tikiroot;
$preferred_perspective = $this->get_preferred_perspective($user);
if (empty($perspective) && ! $preferred_perspective) {
unset($_SESSION['current_perspective']);
unset($_SESSION['current_perspective_name']);
} else {
$_SESSION['current_perspective'] = $perspective;
$_SESSION['current_perspective_name'] = $this->get_perspective_name($_SESSION['current_perspective']);
}
if ($this->perspective_exists($perspective) || empty($perspective)) {
if ($prefs['multidomain_switchdomain'] == 'y') {
$perspectiveFound = false;
$domainFound = false;
foreach ($this->get_domain_map() as $domain => $persp) {
$domainFound = $domainFound || (isset($_SERVER['HTTP_HOST']) && $domain == $_SERVER['HTTP_HOST']);
if ($persp == $perspective) {
if (isset($_SERVER['HTTP_HOST']) && $domain != $_SERVER['HTTP_HOST']) {
$path = $tikiroot;
if ($by_area && ! empty($_SERVER['REQUEST_URI'])) {
$path = $_SERVER['REQUEST_URI'];
}
$targetUrl = $url_scheme . '://' . $domain . $path;
if ($prefs['feature_areas'] === 'y') {
header('HTTP/1.0 301 Found');
}
header('Location: ' . $targetUrl);
exit;
}
$perspectiveFound = true;
break;
}
}
if (! $perspectiveFound && $domainFound) {
$accesslib = TikiLib::lib('access');
if (! empty($prefs['multidomain_default_not_categorized'])) {
if ($prefs['multidomain_default_not_categorized'] != $_SERVER['HTTP_HOST']) {
$saveHttpHost = $_SERVER['HTTP_HOST'];
// selfUrl uses HTTP_HOST, and redirect will exit after redirect, so no problem on "tampering" with $_SERVER
$_SERVER['HTTP_HOST'] = $prefs['multidomain_default_not_categorized'];
$accesslib->redirect($accesslib->selfUrl(), '', 301);
$_SERVER['HTTP_HOST'] = $saveHttpHost; // this should never be reach
}
} else {
$accesslib->display_error(
$accesslib->selfUrl(),
tra("Perspective misconfiguration"),
500,
false,
tra('The resource you requested is not available in the current perspective, and the system administrator did not define a default domain to redirect to. Please contact your system administrator, or check the documentation in <a href="http://doc.tiki.org/Perspectives">http://doc.tiki.org/Perspectives</a> related with multi-domain configurations.')
);
}
}
}
}
}
/**
* @param $info
* @param $perms
*/
private function write_permissions(&$info, $perms)
{
$info['can_edit'] = $perms->perspective_edit;
$info['can_remove'] = $perms->perspective_admin;
$info['can_perms'] = $perms->perspective_admin;
}
/**
* Adds or renames a perspective. If $perspectiveId exists, rename it to $name.
* Otherwise, create a new perspective with id $perspectiveId named $name.
* Returns true if and only if the operation succeeds.
*
*/
public function replace_perspective($perspectiveId, $name)
{
if ($perspectiveId) {
$this->perspectives->update(
['name' => $name,],
['perspectiveId' => $perspectiveId,]
);
return $perspectiveId;
} else {
return $this->perspectives->insert(['name' => $name,]);
}
}
/**
* Removes a perspective
*
*/
public function remove_perspective($perspectiveId)
{
if ($perspectiveId) {
$this->perspectives->delete(['perspectiveId' => $perspectiveId]);
$this->perspectivePreferences->deleteMultiple(['perspectiveId' => $perspectiveId]);
}
}
/**
* Replaces all preferences from $perspectiveId with those in the provided string-indexed
* array (in format "pref_name" => "pref_value").
*
*/
public function replace_preferences($perspectiveId, $preferences)
{
$this->perspectivePreferences->deleteMultiple(['perspectiveId' => $perspectiveId]);
$prefslib = TikiLib::lib('prefs');
foreach ($preferences as $pref => $value) {
$value = $prefslib->formatPreference($pref, [$pref => $value]);
$this->set_preference($perspectiveId, $pref, $value);
}
}
/**
* Replaces a specific preference
*
*/
public function replace_preference($preference, $value, $newValue)
{
$this->perspectivePreferences->update(
['value' => serialize($newValue),],
[
'pref' => $preference,
'value' => serialize($value),
]
);
}
/**
* Sets $preference's value for $perspectiveId to $value
*
*/
public function set_preference($perspectiveId, $preference, $value)
{
$this->perspectivePreferences->delete(
[
'perspectiveId' => $perspectiveId,
'pref' => $preference,
]
);
$this->perspectivePreferences->insert(
[
'perspectiveId' => $perspectiveId,
'pref' => $preference,
'value' => serialize($value),
]
);
}
/**
* Returns true if and only if a perspective with the given $perspectiveId exists
*
*/
public function perspective_exists($perspectiveId)
{
$db = TikiDb::get();
$id = $db->getOne(
'SELECT perspectiveId FROM tiki_perspectives WHERE perspectiveId = ?',
[ $perspectiveId ]
);
return ! empty($id);
}
/**
* @param int $offset
* @param $maxRecords
* @return array
*/
public function list_perspectives($offset = 0, $maxRecords = -1)
{
$db = TikiDb::get();
$list = $db->fetchAll("SELECT perspectiveId, name FROM tiki_perspectives", [], $maxRecords, $offset);
$list = Perms::simpleFilter('perspective', 'perspectiveId', 'perspective_view', $list);
foreach ($list as & $info) {
$perms = Perms::get([ 'type' => 'perspective', 'object' => $info['perspectiveId'] ]);
$this->write_permissions($info, $perms);
}
return $list;
}
/**
* Returns one of the perspectives with the given name
*
*/
public function get_perspective_with_given_name($name)
{
$db = TikiDb::get();
return $db->getOne("SELECT perspectiveId FROM tiki_perspectives WHERE name = ?", [ $name ]);
}
/**
* Returns perspective's name from the Id
*
*/
public function get_perspective_name($id)
{
$db = TikiDb::get();
return $db->getOne("SELECT name FROM tiki_perspectives WHERE perspectiveId = ?", [ $id ]);
}
}