<?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$
|
|
|
|
/** \file
|
|
* \brief Tiki integrator support class
|
|
*/
|
|
|
|
if (basename($_SERVER['SCRIPT_NAME']) === basename(__FILE__)) {
|
|
die('This script may only be included.');
|
|
}
|
|
|
|
include_once('lib/tikilib.php');
|
|
|
|
class TikiIntegrator
|
|
{
|
|
public $c_rep; //!< cached value for repository data
|
|
|
|
/// Repository management
|
|
//\{
|
|
/// List all
|
|
public function list_repositories($visible_only)
|
|
{
|
|
global $tikilib;
|
|
$values = [];
|
|
$cond = '';
|
|
if ($visible_only == true) {
|
|
$cond = "where `visibility`=?";
|
|
$values[] = 'y';
|
|
}
|
|
$query = "select * from `tiki_integrator_reps` " . $cond . " order by `name`";
|
|
$result = $tikilib->query($query, $values);
|
|
$ret = [];
|
|
while ($res = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
|
|
$ret[] = $res;
|
|
}
|
|
return $ret;
|
|
}
|
|
|
|
/// Add/Update
|
|
public function add_replace_repository($repID, $name, $path, $start, $css, $vis, $cacheable, $exp, $descr)
|
|
{
|
|
global $tikilib;
|
|
$parms = [$name, $path, $start, $css, $vis, $cacheable, $exp, $descr];
|
|
if (strlen($repID) == 0 || $repID == 0) {
|
|
$query = "insert into `tiki_integrator_reps` (`name`,`path`,`start_page`,`css_file`, `visibility`,`cacheable`,`expiration`,`description`) values(?,?,?,?,?,?,?,?)";
|
|
} else {
|
|
$query = "update `tiki_integrator_reps` set `name`=?,`path`=?,`start_page`=?,`css_file`=?,`visibility`=?,`cacheable`=?,`expiration`=?,`description`=? where `repID`=?";
|
|
$parms[] = (int) $repID;
|
|
}
|
|
$result = $tikilib->query($query, $parms);
|
|
// Invalidate cached repository if needed
|
|
if (isset($this->c_rep["repID"]) && ($this->c_rep["repID"] == $repID)) {
|
|
unset($this->c_rep);
|
|
}
|
|
}
|
|
|
|
/// Get one entry by ID
|
|
public function get_repository($repID)
|
|
{
|
|
global $tikilib;
|
|
// Check if we already cache requested repository info
|
|
if (isset($this->c_rep["repID"]) && ($this->c_rep["repID"] == $repID)) {
|
|
return $this->c_rep;
|
|
} else { // Need to select it...
|
|
$query = "select * from `tiki_integrator_reps` where `repID`=?";
|
|
$result = $tikilib->query($query, [$repID]);
|
|
if (! $result->numRows()) {
|
|
return false;
|
|
}
|
|
$res = $result->fetchRow(DB_FETCHMODE_ASSOC);
|
|
$c_rep = $res;
|
|
}
|
|
return $res;
|
|
}
|
|
/// Remove repository and all rules configured for it
|
|
public function remove_repository($repID)
|
|
{
|
|
global $tikilib;
|
|
$query = "delete from `tiki_integrator_rules` where `repID`=?";
|
|
$result = $tikilib->query($query, [$repID]);
|
|
$query = "delete from `tiki_integrator_reps` where `repID`=?";
|
|
$result = $tikilib->query($query, [$repID]);
|
|
// Check if we remove cached repository
|
|
if (isset($this->c_rep["repID"]) && ($this->c_rep["repID"] == $repID)) {
|
|
unset($this->c_rep);
|
|
}
|
|
// Clear cached pages for this repository
|
|
$this->clear_cache($repID);
|
|
}
|
|
//\}
|
|
/// Rules management
|
|
//\{
|
|
/// List rules for given repository
|
|
public function list_rules($repID)
|
|
{
|
|
global $tikilib;
|
|
$query = "select * from `tiki_integrator_rules` where `repID`=? order by `ord`";
|
|
$result = $tikilib->query($query, [$repID]);
|
|
$ret = [];
|
|
while ($res = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
|
|
$ret[] = $res;
|
|
}
|
|
return $ret;
|
|
}
|
|
/// Add or update rule for repository
|
|
public function add_replace_rule($repID, $ruleID, $ord, $srch, $repl, $type, $case, $rxmod, $en, $descr)
|
|
{
|
|
global $tikilib;
|
|
|
|
if ($ord == 0) {
|
|
$query = "select max(`ord`) from `tiki_integrator_rules` where `repID`=?";
|
|
$ord = $tikilib->getOne($query, [$repID]) + 1;
|
|
}
|
|
if (strlen($ruleID) == 0 || $ruleID == 0) {
|
|
$query = "insert into `tiki_integrator_rules`
|
|
(`repID`,`ord`,`srch`,`repl`,`type`,`casesense`,`rxmod`,`enabled`,`description`)
|
|
values(?,?,?,?,?,?,?,?,?)";
|
|
$qparms = [$repID, $ord, $srch, $repl, $type, $case, $rxmod, $en, $descr];
|
|
} else {
|
|
$query = "update `tiki_integrator_rules`
|
|
set `repID`=?,`ord`=?,`srch`=?,`repl`=?,`type`=?,`casesense`=?,
|
|
`rxmod`=?,`enabled`=?,`description`=? where `ruleID`=?";
|
|
$qparms = [$repID, $ord, $srch, $repl, $type, $case, $rxmod, $en, $descr,(int) $ruleID];
|
|
}
|
|
$result = $tikilib->query($query, $qparms);
|
|
// Clear cached pages for this repository
|
|
$this->clear_cache($repID);
|
|
}
|
|
/// Get one entry by ID
|
|
public function get_rule($ruleID)
|
|
{
|
|
global $tikilib;
|
|
$query = "select * from `tiki_integrator_rules` where `ruleID`=?";
|
|
$result = $tikilib->query($query, [$ruleID]);
|
|
if (! $result->numRows()) {
|
|
return false;
|
|
}
|
|
$res = $result->fetchRow(DB_FETCHMODE_ASSOC);
|
|
return $res;
|
|
}
|
|
/// Remove rule
|
|
public function remove_rule($ruleID)
|
|
{
|
|
global $tikilib;
|
|
// Clear cached pages for this repository
|
|
$rule = $this->get_rule($ruleID);
|
|
$this->clear_cache($rule["repID"]);
|
|
// Remove rule
|
|
$query = "delete from `tiki_integrator_rules` where `ruleID`=?";
|
|
$result = $tikilib->query($query, [$ruleID]);
|
|
}
|
|
/// Apply rule to string
|
|
public function apply_rule(&$rep, &$rule, $data)
|
|
{
|
|
// Is there something to search? If no or rule disabled return original data
|
|
if ((strlen($rule["srch"]) == 0) || ($rule["enabled"] != 'y')) {
|
|
return $data;
|
|
}
|
|
// Prepare replace string (subst {path})
|
|
$repl = str_replace('{path}', $rep["path"], $rule["repl"]);
|
|
$repl = str_replace('{repID}', $rep["repID"], $repl);
|
|
//
|
|
$d = $data;
|
|
if ($rule["type"] == 'y') {
|
|
// regex rule. Do replace 'till we have smth to replace (if 'g' modifier present)...
|
|
$g = ! (strpos($rule["rxmod"], 'g') === false);
|
|
$mod = str_replace('g', '', $rule["rxmod"]);
|
|
do {
|
|
$tmp = $d;
|
|
$d = preg_replace('_' . $rule["srch"] . '_' . $mod, $repl, $tmp);
|
|
} while ((strcmp($d, $tmp) != 0) && ($g == true));
|
|
unset($tmp);
|
|
} else {
|
|
// simple str_replace rule
|
|
if ($rule["casesense"] == 'y') {
|
|
$d = str_replace($rule['srch'], $repl, $d);
|
|
} else { // \todo Hmmm... where is str_ireplace() ???
|
|
$d = str_replace($rule["srch"], $repl, $d);
|
|
}
|
|
}
|
|
return $d;
|
|
}
|
|
/// Apply all rules in defined order and returns a filtered text
|
|
public function apply_all_rules($repID, $data)
|
|
{
|
|
$rules = $this->list_rules($repID);
|
|
// Get repository configuration data
|
|
$rep = $this->get_repository($repID);
|
|
if (is_array($rules)) {
|
|
foreach ($rules as $rule) {
|
|
$data = $this->apply_rule($rep, $rule, $data);
|
|
}
|
|
}
|
|
return $data;
|
|
}
|
|
//\}
|
|
/// Build full path to file inside given repository
|
|
public function get_rep_file($rep, $file = '')
|
|
{
|
|
// Is repository path absolute? (start from www root ('/'))
|
|
$p = '';
|
|
if (
|
|
(substr($rep["path"], 0, 7) == 'http://')
|
|
|| (substr($rep["path"], 0, 8) == 'https://')
|
|
) {
|
|
// It is remote repository -- just copy configured path
|
|
$p = $rep["path"];
|
|
} elseif (substr($rep["path"], 0, 1) == '/') {
|
|
// Absolute path: prepend web server root
|
|
$p = $_SERVER['DOCUMENT_ROOT'] . $rep["path"];
|
|
} else { // Relative Tiki base path: get tiki root and append repository path
|
|
// note: little hack here -- assume that __this__ file placed exactly
|
|
// at 2nd dir level in Tiki base dir.
|
|
$p = dirname(dirname(__DIR__)) . '/' . $rep["path"];
|
|
}
|
|
|
|
return $p . '/' . ((strlen($file) > 0) ? $file : $rep["start_page"]);
|
|
}
|
|
/// Return CSS file for given repository
|
|
public function get_rep_css($repID)
|
|
{
|
|
global $style;
|
|
global $style_base;
|
|
|
|
// Return if no CSS file defined for repository
|
|
$rep = $this->get_repository($repID);
|
|
if (! isset($rep["css_file"]) || strlen($rep["css_file"]) == 0) {
|
|
return '';
|
|
}
|
|
|
|
$tiki_root = $_SERVER['DOCUMENT_ROOT'] . dirname($_SERVER['SCRIPT_NAME']);
|
|
// Fill array of dirs to scan (local filesystem, and web based)
|
|
$dirs = [];
|
|
$dirs[] = ['fs' => $tiki_root . "/styles/" . $style_base, 'rel' => "styles/" . $style_base];
|
|
$dirs[] = ['fs' => $tiki_root . "/styles/integrator", 'rel' => "styles/integrator"];
|
|
$dirs[] = ['fs' => $tiki_root . "/" . $rep['path'], 'rel' => "/" . $rep['path']];
|
|
|
|
// Fill array of files to search
|
|
$ts = preg_replace('|\.css|', '', $style); // Tiki style w/o '.css' extension
|
|
$is = preg_replace('|\.css|', '', $rep["css_file"]);
|
|
|
|
$files = [];
|
|
$files[] = $ts . '-' . $rep["css_file"]; // matrix-doxygen.css
|
|
$files[] = $ts . '.' . $rep["css_file"]; // matrix.doxygen.css
|
|
$files[] = $ts . '_' . $rep["css_file"]; // matrix_doxygen.css
|
|
$files[] = $is . '-' . $style; // doxygen-matrix.css
|
|
$files[] = $is . '.' . $style; // doxygen.matrix.css
|
|
$files[] = $is . '_' . $style; // doxygen_matrix.css
|
|
$files[] = $rep["css_file"]; // doxygen.css
|
|
|
|
// Make full list of files to search (combine all dirs with all files)
|
|
$candidates = [];
|
|
foreach ($dirs as $dir) {
|
|
foreach ($files as $file) {
|
|
$candidates[] = ['fs' => $dir['fs'] . '/' . $file, 'rel' => $dir['rel'] . '/' . $file];
|
|
}
|
|
}
|
|
|
|
// Search for CSS file
|
|
foreach ($candidates as $candidate) {
|
|
if (file_exists($candidate['fs'])) {
|
|
return $candidate['rel'];
|
|
}
|
|
}
|
|
// Nothing found...
|
|
return '';
|
|
}
|
|
/**
|
|
* \brief Copy rules from one repository to another
|
|
*
|
|
* Variant #1 (stupid but working):
|
|
* a) get rules list for repository 1
|
|
* b) fix repID for all elements of list
|
|
* c) insert new rules for repository 2
|
|
*
|
|
* Variant #2 (better but need smth special):
|
|
* a) create temporary type=hash table ... (stored in memory and
|
|
* auto deleted on connection close -- is all DBs support this?)
|
|
* a.1) create table name like original_table_name;
|
|
* work for MySQL > 4.1 (smth else?)
|
|
* b) select into it rules of rep 1
|
|
* c) fix it
|
|
* d) copy to main rules table
|
|
*
|
|
*/
|
|
public function copy_rules($srcID, $dstID)
|
|
{
|
|
$rules = $this->list_rules($srcID);
|
|
foreach ($rules as $rule) {
|
|
$this->add_replace_rule(
|
|
$dstID,
|
|
0,
|
|
$rule["ord"],
|
|
$rule["srch"],
|
|
$rule["repl"],
|
|
$rule["type"],
|
|
$rule["casesense"],
|
|
$rule["rxmod"],
|
|
$rule["enabled"],
|
|
$rule["description"]
|
|
);
|
|
}
|
|
}
|
|
/**
|
|
* \brief Filter file
|
|
* Returns ready for integration data from given file. Cache used if neccessary.
|
|
* \param $repID -- repository ID to get file from
|
|
* \param $file -- file name to return data from
|
|
* \param $use_cache -- use or not cache :)
|
|
* \param $url -- URL to associate with cached data
|
|
*
|
|
* \note File is not checked for existence...
|
|
*/
|
|
public function get_file($repID, $file, $use_cache = 'y', $url = '')
|
|
{
|
|
global $tikilib;
|
|
$data = '';
|
|
// Try to get data from cache
|
|
$cacheId = 0;
|
|
if ($use_cache == 'y' && $url != '' && $tikilib->is_cached($url)) {
|
|
$data = $tikilib->get_cache($cacheId = $tikilib->get_cache_id($url));
|
|
}
|
|
|
|
$rep = $this->get_repository($repID);
|
|
|
|
// If smth found in cache return it... else try to get it by usual way.
|
|
if (
|
|
$data != '' && isset($data["data"]) && ($data["data"] != '')
|
|
&& ($rep["expiration"] > 0 ? (time() - $data["refresh"]) < $rep["expiration"] : true)
|
|
) {
|
|
return $data["data"];
|
|
}
|
|
|
|
// Get file content to string
|
|
if (preg_match('#^https?://#', $file)) {
|
|
$data = $tikilib->httprequest($file);
|
|
} else {
|
|
$data = @file_get_contents($file);
|
|
}
|
|
if ($lastError = error_get_last()) {
|
|
$data .= "ERROR: " . $lastError['message'];
|
|
} else {
|
|
// Now we need to hack this file by applying all configured rules...
|
|
$data = $this->apply_all_rules($repID, $data);
|
|
// Add result to cache (remove prev if needed)
|
|
if ($cacheId != 0) {
|
|
$tikilib->remove_cache($cacheId);
|
|
}
|
|
$tikilib->cache_url($url, $data);
|
|
}
|
|
return $data;
|
|
}
|
|
/// Clear cache for given repository
|
|
public function clear_cache($repID)
|
|
{
|
|
global $tikilib;
|
|
// Delete all cached URLs with word 'integrator' in a script
|
|
// name and 'repID' parameter equal to function arg...
|
|
$query = "delete from `tiki_link_cache` where `url` like ?";
|
|
$result = $tikilib->query(
|
|
$query,
|
|
[$tikilib->httpPrefix() . "/%integrator%.php?%repID=" . $repID . "%"]
|
|
);
|
|
}
|
|
/// Clear cache of given file for given repository
|
|
public function clear_cached_file($repID, $file)
|
|
{
|
|
global $tikilib;
|
|
// Delete all cached URLs with word 'integrator' in a script
|
|
// name and 'repID' parameter equal to function arg...
|
|
$query = "delete from `tiki_link_cache` where `url` like ?";
|
|
$result = $tikilib->query(
|
|
$query,
|
|
[$tikilib->httpPrefix() . "/%integrator%.php?repID=" . $repID . (strlen($file) > 0 ? "&file=" . $file : '')]
|
|
);
|
|
}
|
|
}
|