fixed / added mssql support for egw and fixed some other Windows probs on the way ;-)

- knowledgebase is not working: select distinct is not possible with text-columns
- fudforum is not working: is does not use ADOdb and has no own db-layer for mssql
- other apps seem to work, everthing needs through testing - incl. our "old" db's
This commit is contained in:
Ralf Becker 2004-07-25 01:34:59 +00:00
parent 3acc7f3bbe
commit 459a8bd101
13 changed files with 8272 additions and 8 deletions

View File

@ -0,0 +1,929 @@
<?php
/**************************************************************************\
* eGroupWare - EditableTemplates - Storage Objects *
* http://www.egroupware.org *
* Written by Ralf Becker <RalfBecker@outdoor-training.de> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/*!
@class soetemplate
@author ralfbecker
@abstract Storage Objects: Everything to store and retrive the eTemplates.
@discussion eTemplates are stored in the db in table 'phpgw_etemplate' and gets distributed
@discussion through the file 'etemplates.inc.php' in the setup dir of each app. That file gets
@discussion automatically imported in the db, whenever you show a eTemplate of the app. For
@discussion performace reasons the timestamp of the file is stored in the db, so 'new'
@discussion eTemplates need to have a newer file. The distribution-file is generated with the
@discussion function dump, usually by pressing a button in the editor.
@discussion writeLangFile writes an lang-file with all Labels, incorporating an existing one.
@discussion Beside a name eTemplates use the following keys to find the most suitable template
@discussion for an user (in order of precedence):
@discussion 1) User-/Group-Id (not yet implemented)
@discussion 2) preferd languages of the user (templates for all langs have $lang='')
@discussion 3) selected template: verdilak, ... (the default is called '' in the db, not default)
@discussion 4) a version-number of the form, eg: '0.9.13.001' (filled up with 0 same size)
*/
class soetemplate
{
var $public_functions = array(
'init' => True,
'empty_cell' => True,
'new_cell' => True,
'read' => True,
'search' => True,
'save' => True,
'delete' => True,
'dump2setup' => True,
'import_dump' => True,
'writeLangFile' => True
);
var $debug; // =1 show some debug-messages, = 'app.name' show messages only for eTemplate 'app.name'
var $name; // name of the template, e.g. 'infolog.edit'
var $template; // '' = default (not 'default')
var $lang; // '' if general template else language short, e.g. 'de'
var $group; // 0 = not specific else groupId or if < 0 userId
var $version; // like 0.9.13.001
var $size; // witdh,height,border of table
var $style; // embeded CSS style-sheet
var $db,$db_name = 'phpgw_etemplate'; // DB name
var $db_key_cols = array(
'et_name' => 'name',
'et_template' => 'template',
'et_lang' => 'lang',
'et_group' => 'group',
'et_version' => 'version'
);
var $db_data_cols = array(
'et_data' => 'data',
'et_size' => 'size',
'et_style' => 'style',
'et_modified' => 'modified'
);
var $db_cols;
/*!
@function soetemplate
@abstract constructor of the class
@syntax soetemplate($name='',$template='',$lang='',$group=0,$version='',$rows=2,$cols=2)
@param as read
*/
function soetemplate($name='',$template='',$lang='',$group=0,$version='',$rows=2,$cols=2)
{
$this->db = $GLOBALS['phpgw']->db;
$this->db_cols = $this->db_key_cols + $this->db_data_cols;
if (empty($name))
{
$this->init($name,$template,$lang,$group,$version,$rows,$cols);
}
else
{
$this->read($name,$template,$lang,$group,$version,$rows,$cols);
}
}
/*!
@function num2chrs
@abstract generates column-names from index: 'A', 'B', ..., 'AA', 'AB', ..., 'ZZ' (not more!)
@syntax num2chrs($num)
@param $num index to generate name from 1 => 'A'
@result the name
*/
function num2chrs($num)
{
$min = ord('A');
$max = ord('Z') - $min + 1;
if ($num >= $max)
{
$chrs = chr(($num / $max) + $min - 1);
}
$chrs .= chr(($num % $max) + $min);
return $chrs;
}
/*!
@function empty_cell
@abstracts constructor for a new / empty cell (nothing fancy so far)
@syntax empty_cell()
@result the cell
*/
function empty_cell($type='label',$name='')
{
return array(
'type' => $type,
'name' => $name,
);
}
/*!
@function new_cell
@abstract constructs a new cell in a give row or the last row, not existing rows will be created
@syntax new_cell( $row=False )
@param int $row row-number starting with 1 (!)
@param string $type type of the cell
@param string $label label for the cell
@param string $name name of the cell (index in the content-array)
@param array $attributes other attributes for the cell
@returns a reference to the new cell, use $new_cell = &$tpl->new_cell(); (!)
*/
function &new_cell($row=False,$type='label',$label='',$name='',$attributes=False)
{
$row = $row >= 0 ? intval($row) : 0;
if ($row && !isset($this->data[$row]) || !isset($this->data[1])) // new row ?
{
if (!$row) $row = 1;
$this->data[$row] = array();
}
if (!$row) // use last row
{
$row = count($this->data);
while (!isset($this->data[$row]))
{
--$row;
}
}
$row = &$this->data[$row];
$col = $this->num2chrs(count($row));
$cell = &$row[$col];
$cell = $this->empty_cell($type,$name);
if ($label !== '')
{
$attributes['label'] = $label;
}
if (is_array($attributes))
{
foreach($attributes as $name => $value)
{
$cell[$name] = $value;
}
}
return $cell;
}
/*!
@function set_rows_cols()
@abstract initialises rows & cols from the size of the data-array
@syntax set_rows_cols()
*/
function set_rows_cols()
{
$this->rows = count($this->data) - 1;
$this->cols = 0;
for($r = 1; $r <= $this->rows; ++$r)
{
$cols = count($this->data[$r]);
if ($this->cols < $cols)
{
$this->cols = $cols;
}
}
}
/*!
@function init
@abstract initialises all internal data-structures of the eTemplate and sets the keys
@syntax init($name='',$template='',$lang='',$group=0,$version='',$rows=1,$cols=1)
@param $name name of the eTemplate or array with the keys or all data
@param $template,$lang,$group,$version see class
@param $rows,$cols initial size of the template
*/
function init($name='',$template='',$lang='',$group=0,$version='',$rows=1,$cols=1)
{
reset($this->db_cols);
while (list($db_col,$col) = each($this->db_cols))
{
$this->$col = is_array($name) ? $name[$col] : $$col;
}
if ($this->template == 'default')
{
$this->template = '';
}
if ($this->lang == 'default')
{
$this->lang = '';
}
$this->tpls_in_file = is_array($name) ? $name['tpls_in_file'] : 0;
if (is_array($name) && isset($name['data']))
{
$this->set_rows_cols();
return; // data already set
}
$this->size = $this->style = '';
$this->data = array(0 => array());
$this->rows = $rows < 0 ? 1 : $rows;
$this->cols = $cols < 0 ? 1 : $cols;
for ($row = 1; $row <= $rows; ++$row)
{
for ($col = 0; $col < $cols; ++$col)
{
$this->data[$row][$this->num2chrs($col)] = $this->empty_cell();
}
}
}
/*!
@function read
@abstract Reads an eTemplate from the database
@syntax read($name,$template='default',$lang='default',$group=0,$version='')
@param as discripted with the class, with the following exeptions
@param $template as '' loads the prefered template 'default' loads the default one '' in the db
@param $lang as '' loads the pref. lang 'default' loads the default one '' in the db
@param $group is NOT used / implemented yet
@result True if a fitting template is found, else False
*/
function read($name,$template='default',$lang='default',$group=0,$version='')
{
$this->init($name,$template,$lang,$group,$version);
if ($this->debug == 1 || $this->debug == $this->name)
{
echo "<p>soetemplate::read('$this->name','$this->template','$this->lang',$this->group,'$this->version')</p>\n";
}
if (($GLOBALS['phpgw_info']['server']['eTemplate-source'] == 'files' ||
$GLOBALS['phpgw_info']['server']['eTemplate-source'] == 'xslt') && $this->readfile())
{
return True;
}
if ($this->name)
{
$this->test_import($this->name); // import updates in setup-dir
}
$pref_lang = $GLOBALS['phpgw_info']['user']['preferences']['common']['lang'];
$pref_templ = $GLOBALS['phpgw_info']['server']['template_set'];
$sql = "SELECT * FROM $this->db_name WHERE et_name='".$this->db->db_addslashes($this->name)."' AND ";
if (is_array($name))
{
$template = $name['template'];
}
if ($template == 'default')
{
$sql .= "(et_template='".$this->db->db_addslashes($pref_templ)."' OR et_template='')";
}
else
{
$sql .= "et_template='".$this->db->db_addslashes($this->template)."'";
}
$sql .= ' AND ';
if (is_array($name))
{
$lang = $name['lang'];
}
if ($lang == 'default' || $name['lang'] == 'default')
{
$sql .= "(et_lang='".$this->db->db_addslashes($pref_lang)."' OR et_lang='')";
}
else
{
$sql .= "et_lang='".$this->db->db_addslashes($this->lang)."'";
}
if ($this->version != '')
{
$sql .= "AND et_version='".$this->db->db_addslashes($this->version)."'";
}
$sql .= " ORDER BY et_lang DESC,et_template DESC,et_version DESC";
if ($this->debug == $this->name)
{
echo "<p>soetemplate::read: sql='$sql'</p>\n";
}
$this->db->query($sql,__LINE__,__FILE__);
if (!$this->db->next_record())
{
$version = $this->version;
return $this->readfile() && (empty($version) || $version == $this->version);
}
$this->db2obj();
return True;
}
/*!
@function readfile
@abstract Reads an eTemplate from the filesystem, the keys are already set by init in read
@syntax readfile()
@result True if a template is found, else False
*/
function readfile()
{
list($app,$name) = split("\.",$this->name,2);
$template = $this->template == '' ? 'default' : $this->template;
if ($this->lang)
{
$lang = '.' . $this->lang;
}
$first_try = $ext = $GLOBALS['phpgw_info']['server']['eTemplate-source'] == 'xslt' ? '.xsl' : '.xet';
while ((!$lang || !@file_exists($file = PHPGW_SERVER_ROOT . "/$app/templates/$template/$name$lang$ext") &&
!@file_exists($file = PHPGW_SERVER_ROOT . "/$app/templates/default/$name$lang$ext")) &&
!@file_exists($file = PHPGW_SERVER_ROOT . "/$app/templates/$template/$name$ext") &&
!@file_exists($file = PHPGW_SERVER_ROOT . "/$app/templates/default/$name$ext"))
{
if ($ext == $first_try)
{
$ext = $ext == '.xet' ? '.xsl' : '.xet';
if ($this->debug == 1 || $this->name != '' && $this->debug == $this->name)
{
echo "<p>tried '$file' now trying it with extension '$ext' !!!</p>\n";
}
}
else
{
break;
}
}
if ($this->name == '' || $app == '' || $name == '' || !@file_exists($file) || !($f = @fopen($file,'r')))
{
if ($this->debug == 1 || $this->name != '' && $this->debug == $this->name)
{
echo "<p>Can't open template '$this->name' / '$file' !!!</p>\n";
}
return False;
}
$xml = fread ($f, filesize ($file));
fclose($f);
if ($ext == '.xsl')
{
$cell = $this->empty_cell();
$cell['type'] = 'xslt';
$cell['size'] = $this->name;
//$cell['xslt'] = &$xml; xslttemplate class cant use it direct at the moment
$cell['name'] = '';
$this->data = array(0 => array(),1 => array('A' => &$cell));
$this->rows = $this->cols = 1;
}
else
{
if (!is_object($this->xul_io))
{
$this->xul_io = CreateObject('etemplate.xul_io');
}
$loaded = $this->xul_io->import($this,$xml);
if (!is_array($loaded))
{
return False;
}
$this->name = $app . '.' . $name; // if template was copied or app was renamed
$this->tpls_in_file = count($loaded);
}
return True;
}
/*!
@function search
@syntax search($name,$template='default',$lang='default',$group=0,$version='')
@author ralfbecker
@abstract Lists the eTemplates matching the given criteria
@param as discripted with the class, with the following exeptions
@param $template as '' loads the prefered template 'default' loads the default one '' in the db
@param $lang as '' loads the pref. lang 'default' loads the default one '' in the db
@param $group is NOT used / implemented yet
@result array of arrays with the template-params
*/
function search($name,$template='default',$lang='default',$group=0,$version='')
{
if ($this->name)
{
$this->test_import($this->name); // import updates in setup-dir
}
$pref_lang = $GLOBALS['phpgw_info']['user']['preferences']['common']['lang'];
$pref_templ = $GLOBALS['phpgw_info']['server']['template_set'];
if (is_array($name))
{
$template = $name['template'];
$lang = $name['lang'];
$group = $name['group'];
$version = $name['version'];
$name = $name['name'];
}
$sql = "SELECT et_name,et_template,et_lang,et_group,et_version FROM $this->db_name WHERE et_name LIKE '".$this->db->db_addslashes($name)."%'";
if ($template != '' && $template != 'default')
{
$sql .= " AND et_template LIKE '".$this->db->db_addslashes($template)."%'";
}
if ($lang != '' && $lang != 'default')
{
$sql .= " AND et_lang LIKE '".$this->db->db_addslashes($lang)."%'";
}
if ($this->version != '')
{
$sql .= " AND et_version LIKE '".$this->db->db_addslashes($version)."%'";
}
$sql .= " ORDER BY et_name DESC,et_lang DESC,et_template DESC,et_version DESC";
$tpl = new soetemplate;
$tpl->db->query($sql,__LINE__,__FILE__);
$result = array();
while ($tpl->db->next_record())
{
if ($tpl->db->f('et_lang') != '##') // exclude or import-time-stamps
{
$tpl->db2obj();
$result[] = $tpl->as_array();
}
}
if ($this->debug)
{
echo "<p>soetemplate::search('$name') sql='$sql'</p>\n<pre>\n";
print_r($result);
echo "</pre>\n";
}
return $result;
}
/*!
@function db2obj
@abstract copies all cols into the obj and unserializes the data-array
@syntax db2obj()
*/
function db2obj()
{
for (reset($this->db_cols); list($db_col,$name) = each($this->db_cols); )
{
$this->$name = $this->db->f($db_col);
}
$this->data = unserialize(stripslashes($this->data));
if (!is_array($this->data)) $this->data = array();
if ($this->name[0] != '.')
{
reset($this->data); each($this->data);
while (list($row,$cols) = each($this->data))
{
while (list($col,$cell) = each($cols))
{
if (is_array($cell['type']))
{
$this->data[$row][$col]['type'] = $cell['type'][0];
//echo "corrected in $this->name cell $col$row attribute type<br>\n";
}
if (is_array($cell['align']))
{
$this->data[$row][$col]['align'] = $cell['align'][0];
//echo "corrected in $this->name cell $col$row attribute align<br>\n";
}
}
}
}
$this->set_rows_cols();
}
/*!
@function compress_array
@syntax compress_array( $arr )
@author ralfbecker
@abstract to save space in the db all empty values in the array got unset
@discussion The never-'' type field ensures a cell does not disapear completely.
@discussion Calls it self recursivly for arrays / the rows
@param $arr the array to compress
@result the compressed array
*/
function compress_array($arr)
{
if (!is_array($arr))
{
return $arr;
}
while (list($key,$val) = each($arr))
{
if (is_array($val))
{
$arr[$key] = $this->compress_array($val);
}
elseif ($val == '')
{
unset($arr[$key]);
}
}
return $arr;
}
/*!
@function as_array
@abstract returns obj-data as array
@syntax as_array($data_too=0)
@param $data_too 0 = no data array, 1 = data array too, 2 = serialize data array
@result the array
*/
function as_array($data_too=0)
{
$arr = array();
reset($this->db_cols);
while (list($db_col,$col) = each($this->db_cols))
{
if ($col != 'data' || $data_too)
{
$arr[$col] = $this->$col;
}
}
if ($data_too == 2)
{
$arr['data'] = serialize($arr['data']);
}
if ($this->tpls_in_file) {
$arr['tpls_in_file'] = $this->tpls_in_file;
}
return $arr;
}
/*!
@function save
@abstract saves eTemplate-object to db, can be used as saveAs by giving keys as params
@syntax save($name='',$template='.',$lang='.',$group='',$version='.')
@params keys see class
@result the number of affected rows, 1 should be ok, 0 somethings wrong
*/
function save($name='',$template='.',$lang='.',$group='',$version='.')
{
if (is_array($name))
{
$template = $name['template'];
$lang = $name['lang'];
$group = $name['group'];
$version = $name['version'];
$name = $name['name'];
}
if ($name != '')
{
$this->name = $name;
}
if ($lang != '.')
{
$this->lang = $lang;
}
if ($template != '.')
{
$this->template = $template;
}
if ($group != '')
{
$this->group = $group;
}
if ($version != '.')
{
$this->version = $version;
}
if ($this->name == '') // name need to be set !!!
{
return False;
}
if ($this->debug > 0 || $this->debug == $this->name)
{
echo "<p>soetemplate::save('$this->name','$this->template','$this->lang',$this->group,'$this->version')</p>\n";
}
$this->delete(); // so we have always a new insert
if ($this->name[0] != '.') // correct up old messed up templates
{
reset($this->data); each($this->data);
while (list($row,$cols) = each($this->data))
{
while (list($col,$cell) = each($cols))
{
if (is_array($cell['type'])) {
$this->data[$row][$col]['type'] = $cell['type'][0];
//echo "corrected in $this->name cell $col$row attribute type<br>\n";
}
if (is_array($cell['align'])) {
$this->data[$row][$col]['align'] = $cell['align'][0];
//echo "corrected in $this->name cell $col$row attribute align<br>\n";
}
}
}
}
if (!$this->modified)
{
$this->modified = time();
}
$data = $this->as_array(1);
$data['data'] = serialize($this->compress_array($data['data']));
$sql = "INSERT INTO $this->db_name (";
foreach ($this->db_cols as $db_col => $col)
{
$sql .= $db_col . ',';
$vals .= $db_col == 'et_group' ? intval($data[$col]).',' : "'" . $this->db->db_addslashes($data[$col]) . "',";
}
$sql[strlen($sql)-1] = ')';
$sql .= " VALUES ($vals";
$sql[strlen($sql)-1] = ')';
$this->db->query($sql,__LINE__,__FILE__);
return $this->db->affected_rows();
}
/*!
@function delete
@abstract Deletes the eTemplate from the db, object itself is unchanged
@syntax delete()
@result the number of affected rows, 1 should be ok, 0 somethings wrong
*/
function delete()
{
foreach ($this->db_key_cols as $db_col => $col)
{
$vals .= ($vals ? ' AND ' : '') . $db_col . '=' . ($db_col == 'et_group' ? intval($this->$col) : "'".$this->$col."'");
}
$this->db->query("DELETE FROM $this->db_name WHERE $vals",__LINE__,__FILE__);
return $this->db->affected_rows();
}
/*!
@function dump2setup
@abstract dumps all eTemplates to <app>/setup/etemplates.inc.php for distribution
@syntax dump2setup($app)
@param $app app- or template-name
@result the number of templates dumped as message
*/
function dump2setup($app)
{
list($app) = explode('.',$app);
$this->db->query("SELECT * FROM $this->db_name WHERE et_name LIKE '$app%'");
$dir = PHPGW_SERVER_ROOT . "/$app/setup";
if (!is_writeable($dir))
{
return lang("Error: webserver is not allowed to write into '%1' !!!",$dir);
}
$file = "$dir/etemplates.inc.php";
if (file_exists($file))
{
$old_file = "$dir/etemplates.old.inc.php";
if (file_exists($old_file))
{
unlink($old_file);
}
rename($file,$old_file);
}
if (!($f = fopen($file,'w')))
{
return 0;
}
fwrite($f,"<?php\n// eTemplates for Application '$app', generated by etemplate.dump() ".date('Y-m-d H:i')."\n\n".
'/* $'.'Id$ */'."\n\n");
for ($n = 0; $this->db->next_record(); ++$n)
{
$str = '$templ_data[] = array(';
for (reset($this->db_cols); list($db_col,$name) = each($this->db_cols); )
{
$str .= "'$name' => '".$this->db->db_addslashes($this->db->f($db_col))."',";
}
$str .= ");\n\n";
fwrite($f,$str);
}
fclose($f);
return lang("%1 eTemplates for Application '%2' dumped to '%3'",$n,$app,$file);
}
function getToTranslateCell($cell,&$to_trans)
{
$strings = explode('|',$cell['help']);
if ($cell['type'] != 'image')
{
$strings = array_merge($strings,explode('|',$cell['label']));
}
list($extra_row) = explode(',',$cell['size']);
if (substr($cell['type'],0,6) == 'select' && !empty($extra_row) && !intval($extra_row))
{
$strings[] = $extra_row;
}
if (!empty($cell['blur']))
{
$strings[] = $cell['blur'];
}
foreach($strings as $str)
{
if (strlen($str) > 1 && $str[0] != '@')
{
$to_trans[trim(strtolower($str))] = $str;
}
}
}
/*!
@function getToTranslate
@abstract extracts all texts: labels and helptexts from an eTemplate-object
@discussion some extensions use a '|' to squezze multiple texts in a label or help field
@syntax getToTranslate()
@result array with messages as key AND value
*/
function getToTranslate()
{
$to_trans = array();
reset($this->data); each($this->data); // skip width
while (list($row,$cols) = each($this->data))
{
foreach($cols as $col => $cell)
{
$this->getToTranslateCell($cell,$to_trans);
if ($cell['type'] == 'vbox' || $cell['type'] == 'hbox')
{
for ($n = 1; $n <= $cell['size']; ++$n)
{
$this->getToTranslateCell($cell[$n],$to_trans);
}
}
}
}
return $to_trans;
}
/*!
@function getToTranslateApp
@abstract Read all eTemplates of an app an extracts the texts to an array
@syntax getToTranslateApp($app)
@param $app name of the app
@result the array with texts
*/
function getToTranslateApp($app)
{
$to_trans = array();
$tpls = $this->search($app);
$tpl = new soetemplate; // to not alter our own data
while (list(,$keys) = each($tpls))
{
if (($keys['name'] != $last['name'] || // write only newest version
$keys['template'] != $last['template']) &&
!strstr($keys['name'],'test'))
{
$tpl->read($keys);
$to_trans += $tpl->getToTranslate();
$last = $keys;
}
}
return $to_trans;
}
/*!
@function writeLangFile
@abstract Write new lang-file using the existing one and all text from the eTemplates
@syntax writeLangFile($app,$lang='en',$additional='')
@param $app app- or template-name
@param $lang language the messages in the template are, defaults to 'en'
@param $additional extra texts to translate, if you pass here an array with all messages and
@param select-options they get writen too (form is <unique key> => <message>)
@result message with number of messages written (total and new)
*/
function writeLangFile($app,$lang='en',$additional='')
{
if (!$additional)
{
$addtional = array();
}
list($app) = explode('.',$app);
if (!file_exists(PHPGW_SERVER_ROOT.'/developer_tools/inc/class.solangfile.inc.php'))
{
$solangfile = CreateObject('etemplate.solangfile');
}
else
{
$solangfile = CreateObject('developer_tools.solangfile');
}
$langarr = $solangfile->load_app($app,$lang);
if (!is_array($langarr))
{
$langarr = array();
}
$commonarr = $solangfile->load_app('phpgwapi',$lang) + $solangfile->load_app('etemplate',$lang);
$to_trans = $this->getToTranslateApp($app);
if (is_array($additional))
{
//echo "writeLangFile: additional ="; _debug_array($additional);
foreach($additional as $msg)
{
$to_trans[trim(strtolower($msg))] = $msg;
}
}
unset($to_trans['']);
for ($new = $n = 0; list($message_id,$content) = each($to_trans); ++$n)
{
if (!isset($langarr[$message_id]) && !isset($commonarr[$message_id]))
{
if (@isset($langarr[$content])) // caused by not lowercased-message_id's
{
unset($langarr[$content]);
}
$langarr[$message_id] = array(
'message_id' => $message_id,
'app_name' => $app,
'content' => $content
);
++$new;
}
}
ksort($langarr);
$dir = PHPGW_SERVER_ROOT . "/$app/setup";
if (!is_writeable($dir))
{
return lang("Error: webserver is not allowed to write into '%1' !!!",$dir);
}
$file = "$dir/phpgw_$lang.lang";
if (file_exists($file))
{
$old_file = "$dir/phpgw_$lang.old.lang";
if (file_exists($old_file))
{
unlink($old_file);
}
rename($file,$old_file);
}
$solangfile->write_file($app,$langarr,$lang);
$solangfile->loaddb($app,$lang);
return lang("%1 (%2 new) Messages writen for Application '%3' and Languages '%4'",$n,$new,$app,$lang);
}
/*!
@function import_dump
@abstract Imports the dump-file /$app/setup/etempplates.inc.php unconditional (!)
@syntax import_dump($app)
@param $app app name
@result message with number of templates imported
*/
function import_dump($app)
{
include($path = PHPGW_SERVER_ROOT."/$app/setup/etemplates.inc.php");
$templ = new etemplate($app);
for ($n = 0; isset($templ_data[$n]); ++$n)
{
for (reset($this->db_cols); list($db_col,$name) = each($this->db_cols); )
{
$templ->$name = $templ_data[$n][$name];
}
$templ->data = unserialize(stripslashes($templ->data));
if (!$templ->modified)
{
$templ->modified = filemtime($path);
}
$templ->save();
}
return lang("%1 new eTemplates imported for Application '%2'",$n,$app);
}
/*!
@function test_import
@abstract test if new template-import necessary for app and does the import
@discussion Get called on every read of a eTemplate, caches the result in phpgw_info.
@discussion The timestamp of the last import for app gets written into the db.
@syntax test_import($app)
@param $app app- or template-name
*/
function test_import($app) // should be done from the setup-App
{
list($app) = explode('.',$app);
if (!$app || $GLOBALS['phpgw_info']['etemplate']['import_tested'][$app])
{
return ''; // ensure test is done only once per call and app
}
$GLOBALS['phpgw_info']['etemplate']['import_tested'][$app] = True; // need to be done before new ...
$path = PHPGW_SERVER_ROOT."/$app/setup/etemplates.inc.php";
if ($time = @filemtime($path))
{
$templ = new soetemplate(".$app",'','##');
if ($templ->lang != '##' || $templ->modified < $time) // need to import
{
$ret = $this->import_dump($app);
$templ->modified = $time;
$templ->save(".$app",'','##');
}
}
return $ret;
}
};

View File

@ -0,0 +1,578 @@
<?php
/**************************************************************************\
* eGroupWare - InfoLog *
* http://www.eGroupWare.org *
* Written by Ralf Becker <RalfBecker@outdoor-training.de> *
* originaly based on todo written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
/*!
@class soinfolog
@abstract storage object / db-layer for InfoLog
@author Ralf Becker
@copyright GPL - GNU General Public License
@note all values passed to this class are run either through intval or addslashes to prevent query-insertion
and for pgSql 7.3 compatibility
*/
class soinfolog // DB-Layer
{
var $db,$db2;
var $grants;
var $data = array( );
var $user;
/*!
@function soinfolog
@abstract constructor
*/
function soinfolog( $info_id = 0)
{
$this->db = $GLOBALS['phpgw']->db;
$this->grants = $GLOBALS['phpgw']->acl->get_grants('infolog');
$this->user = $GLOBALS['phpgw_info']['user']['account_id'];
$this->links = CreateObject('infolog.solink');
$this->tz_offset = $GLOBALS['phpgw_info']['user']['preferences']['common']['tz_offset'];
$this->read( $info_id );
}
/*!
@function check_access
@abstract checks if user has the $required_rights to access $info_id (private access is handled too)
@syntax check_access( $info_id,$required_rights )
@param $info_id Id of InfoLog entry
@param $required_rights PHPGW_ACL_xyz anded together
@returns True if access is granted else False
*/
function check_access( $info_id,$required_rights )
{
if ($info_id != $this->data['info_id']) // already loaded?
{
// dont change our own internal data,
// dont use new as it changes $phpgw->db
$private_info = $this;
$info = $private_info->read($info_id);
}
else
{
$info = $this->data;
}
if (!$info || !$info_id)
{
return False;
}
$owner = $info['info_owner'];
$access_ok = $owner == $this->user || // user has all rights
// ACL only on public entrys || $owner granted _PRIVATE
(!!($this->grants[$owner] & $required_rights) ||
// implicite read-rights for responsible user !!!
$info['info_responsible'] == $this->user && $required_rights == PHPGW_ACL_READ) &&
($info['info_access'] == 'public' ||
!!($this->grants[$owner] & PHPGW_ACL_PRIVATE));
//echo "<p>check_access(info_id=$info_id (owner=$owner, user=$user),required_rights=$required_rights): access".($access_ok?"Ok":"Denied")."</p>\n";
return $access_ok;
}
/*!
@function aclFilter
@abstract generate sql to be AND'ed into a query to ensure ACL is respected (incl. _PRIVATE)
@param $filter: none|all - list all entrys user have rights to see<br>
private|own - list only his personal entrys (incl. those he is responsible for !!!)
@returns the necesary sql
*/
function aclFilter($filter = False)
{
preg_match('/(own|privat|all|none|user)([0-9]*)/',$filter_was=$filter,$vars);
$filter = $vars[1];
$f_user = intval($vars[2]);
if (isset($this->acl_filter[$filter.$user]))
{
return $this->acl_filter[$filter.$user]; // used cached filter if found
}
if (is_array($this->grants))
{
foreach($this->grants as $user => $grant)
{
// echo "<p>grants: user=$user, grant=$grant</p>";
if ($grant & (PHPGW_ACL_READ|PHPGW_ACL_EDIT))
{
$public_user_list[] = $user;
}
if ($grant & PHPGW_ACL_PRIVATE)
{
$private_user_list[] = $user;
}
}
if (count($private_user_list))
{
$has_private_access = 'info_owner IN ('.implode(',',$private_user_list).')';
}
}
$filtermethod = " (info_owner=$this->user"; // user has all rights
// implicit read-rights for responsible user
$filtermethod .= " OR (info_responsible=$this->user AND info_access='public')";
// private: own entries plus the one user is responsible for
if ($filter == 'private' || $filter == 'own')
{
$filtermethod .= " OR (info_responsible=$this->user OR info_status = 'offer')".
" AND (info_access='public'".($has_private_access?" OR $has_private_access":'').')';
}
else // none --> all entrys user has rights to see
{
if ($has_private_access)
{
$filtermethod .= " OR $has_private_access";
}
if (count($public_user_list))
{
$filtermethod .= " OR (info_access='public' AND info_owner IN(" . implode(',',$public_user_list) . '))';
}
}
$filtermethod .= ') ';
if ($filter == 'user' && $f_user > 0)
{
$filtermethod = " ((info_owner=$f_user AND info_responsible=0 OR info_responsible=$f_user) AND $filtermethod)";
}
//echo "<p>aclFilter(filter='$filter_was',user='$user') = '$filtermethod', privat_user_list=".print_r($privat_user_list,True).", public_user_list=".print_r($public_user_list,True)."</p>\n";
return $this->acl_filter[$filter.$user] = $filtermethod; // cache the filter
}
/*!
@function statusFilter
@abstract generate sql to filter based on the status of the log-entry
@syntax statusFilter($filter = '')
@param $filter done = done or billed, open = not ()done or billed), offer = offer
@returns the necesary sql
*/
function statusFilter($filter = '')
{
preg_match('/(done|open|offer)/',$filter,$vars);
$filter = $vars[1];
switch ($filter)
{
case 'done': return " AND info_status IN ('done','billed')";
case 'open': return " AND NOT (info_status IN ('done','billed'))";
case 'offer': return " AND info_status = 'offer'";
}
return '';
}
/*!
@function dateFilter
@abstract generate sql to filter based on the start- and enddate of the log-entry
@syntax dateFilter($filter = '')
@param $filter upcoming = startdate is in the future<br>
today startdate < tomorrow<br>
overdue enddate < tomorrow<br>
limitYYYY/MM/DD not older or open
@returns the necesary sql
*/
function dateFilter($filter = '')
{
preg_match('/(upcoming|today|overdue|date)([-\\/.0-9]*)/',$filter,$vars);
$filter = $vars[1];
if (isset($vars[2]) && !empty($vars[2]) && ($date = split('[-/.]',$vars[2])))
{
$today = mktime(-$this->tz_offset,0,0,intval($date[1]),intval($date[2]),intval($date[0]));
$tomorrow = mktime(-$this->tz_offset,0,0,intval($date[1]),intval($date[2])+1,intval($date[0]));
}
else
{
$now = getdate(time()-60*60*$this->tz_offset);
$tomorrow = mktime(-$this->tz_offset,0,0,$now['mon'],$now['mday']+1,$now['year']);
}
switch ($filter)
{
case 'upcoming':
return " AND info_startdate >= '$tomorrow'";
case 'today':
return " AND info_startdate < '$tomorrow'";
case 'overdue':
return " AND (info_enddate != 0 AND info_enddate < '$tomorrow')";
case 'date':
if (!$today || !$tomorrow)
{
return '';
}
return " AND ($today <= info_startdate AND info_startdate < $tomorrow)";
case 'limit':
return " AND (info_modified >= '$today' OR NOT (info_status IN ('done','billed')))";
}
return '';
}
/*!
@function init
@abstract initialise the internal $this->data to be empty
@discussion only non-empty values got initialised
*/
function init()
{
$this->data = array(
'info_owner' => $this->user,
'info_pri' => 'normal'
);
}
/*!
@function db2data
@abstract copy data after a query into $data
@syntax db2data(&$data)
@param $data array to copy the data
@description copy only non-numeric keys
*/
function db2data(&$data)
{
$data = array();
foreach ($this->db->Record as $key => $val)
{
if (!is_numeric($key))
{
$data[$key] = $val;
}
}
}
/*!
@function read
@abstract read InfoLog entry $info_id
@syntax read( $info_id )
@param $info_id id of log-entry
@description some cacheing is done to prevent multiple reads of the same entry
@returns the entry as array
*/
function read($info_id) // did _not_ ensure ACL
{
$info_id = intval($info_id);
if ($info_id <= 0 || $info_id != $this->data['info_id'] &&
(!$this->db->query("select * FROM phpgw_infolog WHERE info_id=$info_id",__LINE__,__FILE__) ||
!$this->db->next_record()))
{
$this->init( );
return False;
}
if ($info_id != $this->data['info_id']) // data yet read in
{
$this->db2data($this->data);
$this->db->query("SELECT info_extra_name,info_extra_value FROM phpgw_infolog_extra WHERE info_id=$info_id",__LINE__,__FILE__);
while ($this->db->next_record())
{
$this->data['#'.$this->db->f(0)] = $this->db->f(1);
}
}
return $this->data;
}
/*!
@function delete
@abstract delete InfoLog entry $info_id AND the links to it
@syntax delete( $info_id )
@param int $info_id id of log-entry
@param bool $delete_children delete the children, if not set there parent-id to $new_parent
@param int new_parent new parent-id to set for subs
*/
function delete($info_id,$delete_children=True,$new_parent=0) // did _not_ ensure ACL
{
//echo "<p>soinfolog::delete($info_id,'$delete_children',$new_parent)</p>\n";
if (($info_id = intval($info_id)) <= 0)
{
return;
}
$this->db->query("DELETE FROM phpgw_infolog WHERE info_id=$info_id",__LINE__,__FILE__);
$this->db->query("DELETE FROM phpgw_infolog_extra WHERE info_id=$info_id");
$this->links->unlink(0,'infolog',$info_id);
if ($this->data['info_id'] == $info_id)
{
$this->init( );
}
// delete children, if they are owned by the user
if ($delete_children)
{
$db2 = $this->db; // we need an extra result-set
$db2->query("SELECT info_id FROM phpgw_infolog WHERE info_id_parent=$info_id AND info_owner=$this->user",__LINE__,__FILE__);
while ($db2->next_record())
{
$this->delete($db2->f(0),$delete_children);
}
}
// set parent_id to $new_parent for all not deleted children
$new_parent = intval($new_parent);
$this->db->query("UPDATE phpgw_infolog SET info_id_parent=$new_parent WHERE info_id_parent=$info_id",__LINE__,__FILE__);
}
/*!
@function change_delete_owner
@abstract changes or deletes entries with a spezified owner (for hook_delete_account)
@syntax change_delete_owner( $owner,$new_owner=0 )
@param $owner old owner
@param $new_owner new owner or 0 if entries should be deleted
*/
function change_delete_owner($owner,$new_owner=0) // new_owner=0 means delete
{
$owner = intval($owner);
if (!($new_owner = intval($new_owner)))
{
$db2 = $this->db; // we need an extra result-set
$db2->query("SELECT info_id FROM phpgw_infolog WHERE info_owner=$owner",__LINE__,__FILE__);
while($db2->next_record())
{
$this->delete($this->db->f(0),False);
}
}
else
{
$this->db->query("UPDATE phpgw_infolog SET info_owner=$new_owner WHERE info_owner=$owner",__LINE__,__FILE__);
}
$this->db->query("UPDATE phpgw_infolog SET info_responsible=$new_owner WHERE info_responsible=$owner",__LINE__,__FILE__);
}
/*!
@function write
@abstract writes the given $values to InfoLog, a new entry gets created if info_id is not set or 0
@syntax write( $values )
@param $values array with the data of the log-entry
@return the info_id
*/
function write($values) // did _not_ ensure ACL
{
include(PHPGW_SERVER_ROOT.'/infolog/setup/tables_current.inc.php');
$db_cols = $phpgw_baseline['phpgw_infolog']['fd'];
unset($phpgw_baseline);
$info_id = intval($values['info_id']) > 0 ? intval($values['info_id']) : 0;
foreach($values as $key => $val)
{
if ($key != 'info_id')
{
if (!isset($db_cols[$key]))
{
continue; // not in infolog-table
}
$this->data[$key] = $val; // update internal data
switch($db_cols[$key]['type']) // protection against query-insertion
{
case 'int': case 'auto':
$val = intval($val);
break;
default:
$val = "'".$this->db->db_addslashes($val)."'";
break;
}
$cols .= (strlen($cols) ? ',' : '').$key;
$vals .= (strlen($vals) ? ',' : '').$val;
$query .= (strlen($query) ? ',' : '')."$key=$val";
}
}
if (($this->data['info_id'] = $info_id))
{
$query = "UPDATE phpgw_infolog SET $query WHERE info_id=$info_id";
$this->db->query($query,__LINE__,__FILE__);
}
else
{
$query = "INSERT INTO phpgw_infolog ($cols) VALUES ($vals)";
$this->db->query($query,__LINE__,__FILE__);
$this->data['info_id']=$this->db->get_last_insert_id('phpgw_infolog','info_id');
}
//echo "<p>soinfolog.write values= "; _debug_array($values);
// write customfields now
$existing = array();
if ($info_id) // existing entry
{
$this->db->query("SELECT info_extra_name FROM phpgw_infolog_extra WHERE info_id=$info_id",__LINE__,__FILE__);
while($this->db->next_record())
{
$existing[strtolower($this->db->f(0))] = True;
}
}
foreach($values as $key => $val)
{
if ($key[0] != '#')
{
continue; // no customfield
}
$this->data[$key] = $val; // update internal data
$val = $this->db->db_addslashes($val);
$name = $this->db->db_addslashes($key = substr($key,1));
if ($existing[strtolower($key)])
{
$query = "UPDATE phpgw_infolog_extra SET info_extra_value='$val' WHERE info_id=$info_id AND info_extra_name='$name'";
}
else
{
$query = "INSERT INTO phpgw_infolog_extra (info_id,info_extra_name,info_extra_value) VALUES (".$this->data['info_id'].",'$name','$val')";
}
$this->db->query($query,__LINE__,__FILE__);
}
// echo "<p>soinfolog.write this->data= "; _debug_array($this->data);
return $this->data['info_id'];
}
/*!
@function anzSubs
@abstract count the sub-entries of $info_id
@syntax anzSubs( $info_id )
@param $info_id id of log-entry
@returns the number of sub-entries
*/
function anzSubs( $info_id )
{
if (($info_id = intval($info_id)) <= 0)
{
return 0;
}
$this->db->query($sql="select count(*) FROM phpgw_infolog WHERE info_id_parent=$info_id AND ".$this->aclFilter(),__LINE__,__FILE__);
$this->db->next_record();
//echo "<p>anzSubs($info_id) = ".$this->db->f(0)." ($sql)</p>\n";
return $this->db->f(0);
}
/*!
@function search
@abstract searches InfoLog for a certain pattern in $query
@syntax search( $query )
@param $query[order] column-name to sort after
@param $query[sort] sort-order DESC or ASC
@param $query[filter] string with combination of acl-, date- and status-filters, eg. 'own-open-today' or ''
@param $query[cat_id] category to use or 0 or unset
@param $query[search] pattern to search, search is done in info_from, info_subject and info_des
@param $query[action] / $query[action_id] if only entries linked to a specified app/entry show be used
@param &$query[start], &$query[total] nextmatch-parameters will be used and set if query returns less entries
@param $query[col_filter] array with column-name - data pairs, data == '' means no filter (!)
@returns array with id's as key of the matching log-entries
*/
function search(&$query)
{
//echo "<p>soinfolog.search(".print_r($query,True).")</p>\n";
$action2app = array(
'addr' => 'addressbook',
'proj' => 'projects',
'event' => 'calendar'
);
$action = isset($action2app[$query['action']]) ? $action2app[$query['action']] : $query['action'];
if ($action != '')
{
$links = $this->links->get_links($action=='sp'?'infolog':$action,$query['action_id'],'infolog');
if (count($links))
{
$link_extra = ($action == 'sp' ? 'OR' : 'AND').' phpgw_infolog.info_id IN ('.implode(',',$links).')';
}
}
if (!empty($query['order']) && eregi('^[a-z_0-9, ]+$',$query['order']) && (empty($query['sort']) || eregi('^(DESC|ASC)$',$query['sort'])))
{
$order = array();
foreach(explode(',',$query['order']) as $val)
{
$val = trim($val);
$val = (substr($val,0,5) != 'info_' ? 'info_' : '').$val;
if ($val == 'info_des' && $this->db->Type == 'mssql')
{
$val = "CAST($val AS varchar)";
}
$order[] = $val;
}
$ordermethod = 'ORDER BY ' . implode(',',$order) . ' ' . $query['sort'];
}
else
{
$ordermethod = 'ORDER BY info_datemodified DESC'; // newest first
}
$filtermethod = $this->aclFilter($query['filter']);
$filtermethod .= $this->statusFilter($query['filter']);
$filtermethod .= $this->dateFilter($query['filter']);
if (is_array($query['col_filter']))
{
foreach($query['col_filter'] as $col => $data)
{
$data = $this->db->db_addslashes($data);
if (substr($col,0,5) != 'info_') $col = 'info_'.$col;
if (!empty($data) && eregi('^[a-z_0-9]+$',$col))
{
$filtermethod .= " AND $col = '$data'";
}
}
}
//echo "<p>filtermethod='$filtermethod'</p>";
if ((int)$query['cat_id'])
{
//$filtermethod .= ' AND info_cat='.intval($query['cat_id']).' ';
if (!is_object($GLOBALS['phpgw']->categories))
{
$GLOBALS['phpgw']->categories = CreateObject('phpgwapi.categories');
}
$cats = $GLOBALS['phpgw']->categories->return_all_children((int)$query['cat_id']);
$filtermethod .= ' AND info_cat'.(count($cats)>1? ' IN ('.implode(',',$cats).') ' : '='.(int)$query['cat_id']);
}
$join = '';
if ($query['query']) $query['search'] = $query['query']; // allow both names
if ($query['search']) // we search in _from, _subject, _des and _extra_value for $query
{
$pattern = "'%".$this->db->db_addslashes($query['search'])."%'";
$sql_query = "AND (info_from like $pattern OR info_subject LIKE $pattern OR info_des LIKE $pattern OR info_extra_value LIKE $pattern) ";
$join = 'LEFT JOIN phpgw_infolog_extra ON phpgw_infolog.info_id=phpgw_infolog_extra.info_id';
}
$pid = 'AND info_id_parent='.($action == 'sp' ? $query['action_id'] : 0);
if (!$GLOBALS['phpgw_info']['user']['preferences']['infolog']['listNoSubs'] &&
$action != 'sp')
{
$pid = '';
}
$ids = array( );
if ($action == '' || $action == 'sp' || count($links))
{
$sql_query = "FROM phpgw_infolog $join WHERE ($filtermethod $pid $sql_query) $link_extra";
// mssql cant use DISTICT of text columns (info_des) are involved
$distinct = $this->db->Type != 'mssql' ? 'DISTINCT' : '';
$this->db->query($sql="SELECT $distinct phpgw_infolog.info_id ".$sql_query,__LINE__,__FILE__);
$query['total'] = $this->db->num_rows();
if (!$query['start'] || $query['start'] > $query['total'])
{
$query['start'] = 0;
}
$this->db->limit_query($sql="SELECT $distinct phpgw_infolog.* $sql_query $ordermethod",$query['start'],__LINE__,__FILE__);
//echo "<p>sql='$sql'</p>\n";
while ($this->db->next_record())
{
$this->db2data($info);
$ids[$info['info_id']] = $info;
}
}
else
{
$query['start'] = $query['total'] = 0;
}
return $ids;
}
}

View File

@ -0,0 +1,824 @@
<?php
/**************************************************************************\
* eGroupWare API - Categories *
* This file written by Joseph Engo <jengo@phpgroupware.org> *
* and Bettina Gille [ceb@phpgroupware.org] *
* Category manager *
* Copyright (C) 2000, 2001 Joseph Engo, Bettina Gille *
* Copyright (C) 2002, 2003 Bettina Gille *
* ------------------------------------------------------------------------ *
* This library is part of the eGroupWare API *
* http://www.egroupware.org *
* ------------------------------------------------------------------------ *
* This library is free software; you can redistribute it and/or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, *
* or any later version. *
* This library is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library; if not, write to the Free Software Foundation, *
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
\**************************************************************************/
// $Id$
// $Source$
/*!
@class categories
@abstract class adds ability for applications to make use of categories
@discussion examples can be found in notes app
*/
class categories
{
var $account_id;
var $app_name;
var $cats;
var $db;
var $total_records;
var $grants;
/*!
@function categories
@abstract constructor for categories class
@param $accountid account id
@param $app_name app name defaults to current app
*/
function categories($accountid = '',$app_name = '')
{
$account_id = get_account_id($accountid);
if (! $app_name)
{
$app_name = $GLOBALS['phpgw_info']['flags']['currentapp'];
}
$this->account_id = $account_id;
$this->app_name = $GLOBALS['phpgw']->db->db_addslashes($app_name);
$this->db = $GLOBALS['phpgw']->db;
$this->db2 = $this->db;
$this->grants = $GLOBALS['phpgw']->acl->get_grants($app_name);
}
/*!
@function filter
@abstract ?
@param $type string
@result string either subs or mains
*/
function filter($type)
{
switch ($type)
{
case 'subs': $s = ' AND cat_parent != 0'; break;
case 'mains': $s = ' AND cat_parent = 0'; break;
case 'appandmains': $s = " AND cat_appname='" . $this->app_name . "' AND cat_parent =0"; break;
case 'appandsubs': $s = " AND cat_appname='" . $this->app_name . "' AND cat_parent !=0"; break;
case 'noglobal': $s = " AND cat_appname != '" . $this->app_name . "'"; break;
case 'noglobalapp': $s = " AND cat_appname = '" . $this->app_name . "' AND cat_owner != " . $this->account_id; break;
default: return False;
}
return $s;
}
/*!
@function total
@abstract returns the total number of categories for app, subs or mains
@param $for one of either 'app' 'subs' or 'mains'
@result integer count of categories
*/
function total($for = 'app')
{
switch($for)
{
case 'app': $w = " WHERE cat_appname='" . $this->app_name . "'"; break;
case 'appandmains': $w = " WHERE cat_appname='" . $this->app_name . "' AND cat_parent =0"; break;
case 'appandsubs': $w = " WHERE cat_appname='" . $this->app_name . "' AND cat_parent !=0"; break;
case 'subs': $w = ' WHERE cat_parent != 0'; break;
case 'mains': $w = ' WHERE cat_parent = 0'; break;
default: return False;
}
$this->db->query("SELECT COUNT(cat_id) FROM phpgw_categories $w",__LINE__,__FILE__);
$this->db->next_record();
return $this->db->f(0);
}
/*!
@funtion return_all_children
@abstract returns array with id's of all children from $cat_id and $cat_id itself!
@param $cat_id integer cat-id to search for
@returns array of cat-id's
*/
function return_all_children($cat_id)
{
$all_children = array($cat_id);
$children = $this->return_array('subs',0,False,'','','',True,$cat_id,-1,'id');
if (is_array($children) && count($children))
{
foreach($children as $child)
{
$all_children = array_merge($all_children,$this->return_all_children($child['id']));
}
}
//echo "<p>categories::return_all_children($cat_id)=(".implode(',',$all_children).")</p>\n";
return $all_children;
}
/*!
@function return_array
@abstract return an array populated with categories
@param $type string defaults to 'all'
@param $start ?
@param $limit ?
@param $query string defaults to ''
@param $sort string sort order, either defaults to 'ASC'
@param $order order by
@param $globals True or False, includes the global egroupware categories or not
@result $cats array
*/
function return_array($type,$start,$limit = True,$query = '',$sort = '',$order = '',$globals = False, $parent_id = '', $lastmod = -1, $column = '')
{
//casting and addslashes for security
$start = (int)$start;
$parent_id = (int)$parent_id;
$query = $this->db->db_addslashes($query);
$sort = $this->db->db_addslashes($sort);
$order = $this->db->db_addslashes($order);
if ($globals)
{
$global_cats = " OR cat_appname='phpgw'";
}
$filter = $this->filter($type);
if (!$sort)
{
$sort = 'ASC';
}
if (!empty($order) && preg_match('/^[a-zA-Z_(), ]+$/',$order) && (empty($sort) || preg_match('/^(ASC|DESC|asc|desc)$/',$sort)))
{
$ordermethod = " ORDER BY $order $sort";
}
else
{
$ordermethod = ' ORDER BY cat_main, cat_level, cat_name ASC';
}
if ($this->account_id == '-1')
{
$grant_cats = ' cat_owner=-1 ';
}
else
{
if (is_array($this->grants))
{
$grants = $this->grants;
while(list($user) = each($grants))
{
$public_user_list[] = $user;
}
reset($public_user_list);
$grant_cats = ' (cat_owner=' . $this->account_id . " OR cat_owner=-1 OR cat_access='public' AND cat_owner in(" . implode(',',$public_user_list) . ')) ';
}
else
{
$grant_cats = ' cat_owner=' . $this->account_id . ' OR cat_owner=-1 ';
}
}
if ($parent_id > 0)
{
$parent_filter = ' AND cat_parent=' . $parent_id;
}
if ($query)
{
$querymethod = " AND (cat_name LIKE '%$query%' OR cat_description LIKE '%$query%') ";
}
if($lastmod && $lastmod >= 0)
{
$querymethod .= ' AND last_mod > ' . (int)$lastmod;
}
if($column)
{
switch($column)
{
case 'id': $table_column = ' cat_id '; break;
case 'owner': $table_column = ' cat_owner '; break;
case 'access': $table_column = ' cat_access '; break;
case 'app_name': $table_column = ' cat_appname '; break;
case 'main': $table_column = ' cat_main '; break;
case 'parent': $table_column = ' cat_parent '; break;
case 'name': $table_column = ' cat_name '; break;
case 'description': $table_column = ' cat_description '; break;
case 'data': $table_column = ' cat_data '; break;
case 'last_mod': $table_column = ' last_mod '; break;
default: $table_column = ' cat_id '; break;
}
}
else
{
$table_column = ' * ';
}
$sql = "SELECT $table_column FROM phpgw_categories WHERE (cat_appname='" . $this->app_name . "' AND" . $grant_cats . $global_cats . ')'
. $parent_filter . $querymethod . $filter;
$this->db2->query($sql,__LINE__,__FILE__);
$this->total_records = $this->db2->num_rows();
if ($limit)
{
$this->db->limit_query($sql . $ordermethod,$start,__LINE__,__FILE__);
}
else
{
$this->db->query($sql . $ordermethod,__LINE__,__FILE__);
}
while ($this->db->next_record())
{
if ($column)
{
$cats[] = array
(
$column => $this->db->f(0)
);
}
else
{
$cats[] = array
(
'id' => $this->db->f('cat_id'),
'owner' => $this->db->f('cat_owner'),
'access' => $this->db->f('cat_access'),
'app_name' => $this->db->f('cat_appname'),
'main' => $this->db->f('cat_main'),
'level' => $this->db->f('cat_level'),
'parent' => $this->db->f('cat_parent'),
'name' => $this->db->f('cat_name'),
'description' => $this->db->f('cat_description'),
'data' => $this->db->f('cat_data'),
'last_mod' => $this->db->f('last_mod')
);
}
}
return $cats;
}
function return_sorted_array($start,$limit = True,$query = '',$sort = '',$order = '',$globals = False, $parent_id = '')
{
//casting and slashes for security
$start = (int)$start;
$query = $this->db->db_addslashes($query);
$sort = $this->db->db_addslashes($sort);
$order = $this->db->db_addslashes($order);
$parent_id = (int)$parent_id;
if ($globals)
{
$global_cats = " OR cat_appname='phpgw'";
}
if (!$sort)
{
$sort = 'ASC';
}
if (!empty($order) && preg_match('/^[a-zA-Z_, ]+$/',$order) && (empty($sort) || preg_match('/^(ASC|DESC|asc|desc)$/')))
{
$ordermethod = " ORDER BY $order $sort";
}
else
{
$ordermethod = ' ORDER BY cat_name ASC';
}
if ($this->account_id == '-1')
{
$grant_cats = " cat_owner='-1' ";
}
else
{
if (is_array($this->grants))
{
$grants = $this->grants;
while(list($user) = each($grants))
{
$public_user_list[] = $user;
}
reset($public_user_list);
$grant_cats = " (cat_owner='" . $this->account_id . "' OR cat_owner='-1' OR cat_access='public' AND cat_owner in(" . implode(',',$public_user_list) . ")) ";
}
else
{
$grant_cats = " cat_owner='" . $this->account_id . "' or cat_owner='-1' ";
}
}
$parent_select = ' AND cat_parent=' . $parent_id;
if ($query)
{
$querymethod = " AND (cat_name LIKE '%$query%' OR cat_description LIKE '%$query%') ";
}
$sql = "SELECT * FROM phpgw_categories WHERE (cat_appname='" . $this->app_name . "' AND" . $grant_cats . $global_cats . ")"
. $querymethod;
$this->db2->query($sql . $parent_select,__LINE__,__FILE__);
$total = $this->db2->num_rows();
if ($limit)
{
$this->db->limit_query($sql . $parent_select . $ordermethod,$start,__LINE__,__FILE__);
}
else
{
$this->db->query($sql . $parent_select . $ordermethod,__LINE__,__FILE__);
}
$i = 0;
while ($this->db->next_record())
{
$cats[$i]['id'] = (int)$this->db->f('cat_id');
$cats[$i]['owner'] = (int)$this->db->f('cat_owner');
$cats[$i]['access'] = $this->db->f('cat_access');
$cats[$i]['app_name'] = $this->db->f('cat_appname');
$cats[$i]['main'] = (int)$this->db->f('cat_main');
$cats[$i]['level'] = (int)$this->db->f('cat_level');
$cats[$i]['parent'] = (int)$this->db->f('cat_parent');
$cats[$i]['name'] = $this->db->f('cat_name');
$cats[$i]['description'] = $this->db->f('cat_description');
$cats[$i]['data'] = $this->db->f('cat_data');
$i++;
}
$num_cats = count($cats);
for ($i=0;$i < $num_cats;$i++)
{
$sub_select = ' AND cat_parent=' . $cats[$i]['id'] . ' AND cat_level=' . ($cats[$i]['level']+1);
/*$this->db2->query($sql . $sub_select,__LINE__,__FILE__);
$total_subs += $this->db2->num_rows();
if ($limit)
{
$this->db->limit_query($sql . $sub_select . $ordermethod,$start,__LINE__,__FILE__);
}
else
{*/
$this->db->query($sql . $sub_select . $ordermethod,__LINE__,__FILE__);
$total += $this->db->num_rows();
//}
$subcats = array();
$j = 0;
while ($this->db->next_record())
{
$subcats[$j]['id'] = (int)$this->db->f('cat_id');
$subcats[$j]['owner'] = (int)$this->db->f('cat_owner');
$subcats[$j]['access'] = $this->db->f('cat_access');
$subcats[$j]['app_name'] = $this->db->f('cat_appname');
$subcats[$j]['main'] = (int)$this->db->f('cat_main');
$subcats[$j]['level'] = (int)$this->db->f('cat_level');
$subcats[$j]['parent'] = (int)$this->db->f('cat_parent');
$subcats[$j]['name'] = $this->db->f('cat_name');
$subcats[$j]['description'] = $this->db->f('cat_description');
$subcats[$j]['data'] = $this->db->f('cat_data');
$j++;
}
$num_subcats = count($subcats);
if ($num_subcats != 0)
{
$newcats = array();
for ($k = 0; $k <= $i; $k++)
{
$newcats[$k] = $cats[$k];
}
for ($k = 0; $k < $num_subcats; $k++)
{
$newcats[$k+$i+1] = $subcats[$k];
}
for ($k = $i+1; $k < $num_cats; $k++)
{
$newcats[$k+$num_subcats] = $cats[$k];
}
$cats = $newcats;
$num_cats = count($cats);
}
}
$this->total_records = $total;
return $cats;
}
/*!
@function return_single
@abstract return single
@param $id integer id of category
@result $cats array populated with
*/
function return_single($id = '')
{
$this->db->query('SELECT * FROM phpgw_categories WHERE cat_id=' . (int)$id,__LINE__,__FILE__);
if ($this->db->next_record())
{
$cats[0]['id'] = $this->db->f('cat_id');
$cats[0]['owner'] = $this->db->f('cat_owner');
$cats[0]['access'] = $this->db->f('cat_access');
$cats[0]['app_name'] = $this->db->f('cat_appname');
$cats[0]['main'] = $this->db->f('cat_main');
$cats[0]['level'] = $this->db->f('cat_level');
$cats[0]['parent'] = $this->db->f('cat_parent');
$cats[0]['name'] = $this->db->f('cat_name');
$cats[0]['description'] = $this->db->f('cat_description');
$cats[0]['data'] = $this->db->f('cat_data');
}
return $cats;
}
/*!
@function formated_list
@abstract return into a select box, list or other formats
@param $format currently supports select (select box) or list
@param $type string - subs or mains
@param $selected - cat_id or array with cat_id values
@param $globals True or False, includes the global egroupware categories or not
@result $s array - populated with categories
*/
function formatted_list($format,$type='',$selected = '',$globals = False,$site_link = 'site')
{
return $this->formated_list($format,$type,$selected,$globals,$site_link);
}
function formated_list($format,$type='',$selected = '',$globals = False,$site_link = 'site')
{
if(is_array($format))
{
$temp_format = $format['format'];
$type = ($format['type']?$format['type']:'all');
$selected = (isset($format['selected'])?$format['selected']:'');
$self = (isset($format['self'])?$format['self']:'');
$globals = (isset($format['globals'])?$format['globals']:True);
$site_link = (isset($format['site_link'])?$format['site_link']:'site');
settype($format,'string');
$format = ($temp_format?$temp_format:'select');
unset($temp_format);
}
if (!is_array($selected))
{
$selected = explode(',',$selected);
}
if ($type != 'all')
{
$cats = $this->return_array($type,$start,False,$query,$sort,$order,$globals);
}
else
{
$cats = $this->return_sorted_array($start,False,$query,$sort,$order,$globals);
}
if($self)
{
for ($i=0;$i<count($cats);$i++)
{
if ($cats[$i]['id'] == $self)
{
unset($cats[$i]);
}
}
}
if ($format == 'select')
{
while (is_array($cats) && list(,$cat) = each($cats))
{
$s .= '<option value="' . $cat['id'] . '"';
if (in_array($cat['id'],$selected))
{
$s .= ' selected';
}
$s .= '>';
for ($j=0;$j<$cat['level'];$j++)
{
$s .= '&nbsp;';
}
$s .= $GLOBALS['phpgw']->strip_html($cat['name']);
if ($cat['app_name'] == 'phpgw')
{
$s .= '&nbsp;&lt;' . lang('Global') . '&gt;';
}
if ($cat['owner'] == '-1')
{
$s .= '&nbsp;&lt;' . lang('Global') . '&nbsp;' . lang($this->app_name) . '&gt;';
}
$s .= '</option>' . "\n";
}
return $s;
}
if ($format == 'list')
{
$space = '&nbsp;&nbsp;';
$s = '<table border="0" cellpadding="2" cellspacing="2">' . "\n";
if ($this->total_records > 0)
{
for ($i=0;$i<count($cats);$i++)
{
$image_set = '&nbsp;';
if (in_array($cats[$i]['id'],$selected))
{
$image_set = '<img src="' . PHPGW_IMAGES_DIR . '/roter_pfeil.gif">';
}
if (($cats[$i]['level'] == 0) && !in_array($cats[$i]['id'],$selected))
{
$image_set = '<img src="' . PHPGW_IMAGES_DIR . '/grauer_pfeil.gif">';
}
$space_set = str_repeat($space,$cats[$i]['level']);
$s .= '<tr>' . "\n";
$s .= '<td width="8">' . $image_set . '</td>' . "\n";
$s .= '<td>' . $space_set . '<a href="' . $GLOBALS['phpgw']->link($site_link,'cat_id=' . $cats[$i]['id']) . '">'
. $GLOBALS['phpgw']->strip_html($cats[$i]['name'])
. '</a></td>' . "\n"
. '</tr>' . "\n";
}
}
$s .= '</table>' . "\n";
return $s;
}
}
/*!
@function add
@abstract add categories
@param $cat_name category name
@param $cat_parent category parent
@param $cat_description category description defaults to ''
@param $cat_data category data defaults to ''
*/
function add($values)
{
$values['id'] = (int)$values['id'];
$values['parent'] = (int)$values['parent'];
if ($values['parent'] > 0)
{
$values['level'] = $this->id2name($values['parent'],'level')+1;
$values['main'] = $this->id2name($values['parent'],'main');
}
$values['descr'] = $this->db->db_addslashes($values['descr']);
$values['name'] = $this->db->db_addslashes($values['name']);
if ($values['id'] > 0)
{
$id_col = 'cat_id,';
$id_val = $values['id'] . ',';
}
$this->db->query('INSERT INTO phpgw_categories (' . $id_col . 'cat_parent,cat_owner,cat_access,cat_appname,cat_name,cat_description,cat_data,'
. 'cat_main,cat_level, last_mod) VALUES (' . $id_val . (int)$values['parent'] . ',' . $this->account_id . ",'" . $values['access']
. "','" . $this->app_name . "','" . $values['name'] . "','" . $values['descr'] . "','" . $values['data']
. "'," . (int)$values['main'] . ',' . (int)$values['level'] . ',' . time() . ')',__LINE__,__FILE__);
if ($values['id'] > 0)
{
$max = $values['id'];
}
else
{
$max = $this->db->get_last_insert_id('phpgw_categories','cat_id');
}
$max = (int)$max;
if ($values['parent'] == 0)
{
$this->db->query('UPDATE phpgw_categories SET cat_main=' . $max . ' WHERE cat_id=' . $max,__LINE__,__FILE__);
}
return $max;
}
/*!
@function delete
@abstract delete category
@param $cat_id int - category id
*/
/*function delete($cat_id,$subs = False)
{
$cat_id = (int)$cat_id;
if ($subs)
{
$subdelete = ' OR cat_parent=' . $cat_id . ' OR cat_main=' . $cat_id;
}
$this->db->query('DELETE FROM phpgw_categories WHERE cat_id=' . $cat_id . $subdelete . " AND cat_appname='"
. $this->app_name . "'",__LINE__,__FILE__);
} */
function delete($cat_id, $drop_subs = False, $modify_subs = False)
{
$cat_id = (int)$cat_id;
if ($drop_subs)
{
$subdelete = ' OR cat_parent=' . $cat_id . ' OR cat_main=' . $cat_id;
}
if ($modify_subs)
{
$cats = $this->return_sorted_array('',False,'','','',False, $cat_id);
$new_parent = $this->id2name($cat_id,'parent');
for ($i=0;$i<count($cats);$i++)
{
if ($cats[$i]['level'] == 1)
{
$this->db->query('UPDATE phpgw_categories set cat_level=0, cat_parent=0, cat_main=' . (int)$cats[$i]['id']
. ' WHERE cat_id=' . (int)$cats[$i]['id'] . " AND cat_appname='" . $this->app_name . "'",__LINE__,__FILE__);
$new_main = $cats[$i]['id'];
}
else
{
if ($new_main)
{
$update_main = ',cat_main=' . $new_main;
}
if ($cats[$i]['parent'] == $cat_id)
{
$update_parent = ',cat_parent=' . $new_parent;
}
$this->db->query('UPDATE phpgw_categories set cat_level=' . ($cats[$i]['level']-1) . $update_main . $update_parent
. ' WHERE cat_id=' . (int)$cats[$i]['id'] . " AND cat_appname='" . $this->app_name . "'",__LINE__,__FILE__);
}
}
}
$this->db->query('DELETE FROM phpgw_categories WHERE cat_id=' . $cat_id . $subdelete . " AND cat_appname='"
. $this->app_name . "'",__LINE__,__FILE__);
}
/*!
@function edit
@abstract edit a category
@param $cat_id int - category id
@param $cat_parent category parent
@param $cat_description category description defaults to ''
@param $cat_data category data defaults to ''
*/
function edit($values)
{
$values['id'] = (int)$values['id'];
$values['parent'] = (int)$values['parent'];
if (isset($values['old_parent']) && (int)$values['old_parent'] != $values['parent'])
{
$this->delete($values['id'],False,True);
return $this->add($values);
}
else
{
if ($values['parent'] > 0)
{
$values['main'] = (int)$this->id2name($values['parent'],'main');
$values['level'] = (int)$this->id2name($values['parent'],'level') + 1;
}
else
{
$values['main'] = $values['id'];
$values['level'] = 0;
}
}
$values['descr'] = $this->db->db_addslashes($values['descr']);
$values['name'] = $this->db->db_addslashes($values['name']);
$sql = "UPDATE phpgw_categories SET cat_name='" . $values['name'] . "', cat_description='" . $values['descr']
. "', cat_data='" . $values['data'] . "', cat_parent=" . $values['parent'] . ", cat_access='"
. $values['access'] . "', cat_main=" . $values['main'] . ', cat_level=' . $values['level'] . ',last_mod=' . time()
. " WHERE cat_appname='" . $this->app_name . "' AND cat_id=" . $values['id'];
$this->db->query($sql,__LINE__,__FILE__);
return $values['id'];
}
function name2id($cat_name)
{
$this->db->query("SELECT cat_id FROM phpgw_categories WHERE cat_name='" . $this->db->db_addslashes($cat_name) . "' "
."AND cat_appname='" . $this->app_name . "' AND (cat_owner=" . $this->account_id . ' OR cat_owner=-1)',__LINE__,__FILE__);
if(!$this->db->num_rows())
{
return 0;
}
$this->db->next_record();
return $this->db->f('cat_id');
}
function id2name($cat_id = '', $item = 'name')
{
$cat_id = (int)$cat_id;
if($cat_id == 0)
{
return '--';
}
switch($item)
{
case 'owner': $value = 'cat_owner'; break;
case 'main': $value = 'cat_main'; break;
case 'level': $value = 'cat_level'; break;
case 'parent': $value = 'cat_parent'; break;
case 'name': $value = 'cat_name'; break;
default: $value = 'cat_parent'; break;
}
$this->db->query("SELECT $value FROM phpgw_categories WHERE cat_id=" . $cat_id,__LINE__,__FILE__);
$this->db->next_record();
if ($this->db->f($value))
{
return $this->db->f($value);
}
else
{
if ($item == 'name')
{
return '--';
}
}
}
/*!
@function return_name
@abstract return category name given $cat_id
@param $cat_id
@result cat_name category name
*/
// NOTE: This is only a temp wrapper, use id2name() to keep things matching across the board. (jengo)
function return_name($cat_id)
{
return $this->id2name($cat_id);
}
/*!
@function exists
@abstract used for checking if a category name exists
@param $type subs or mains
@param $cat_name category name
@result boolean true or false
*/
function exists($type,$cat_name = '',$cat_id = '')
{
$cat_id = (int)$cat_id;
$filter = $this->filter($type);
if ($cat_name)
{
$cat_exists = " cat_name='" . $this->db->db_addslashes($cat_name) . "' ";
}
if ($cat_id)
{
$cat_exists = ' cat_parent=' . $cat_id;
}
if ($cat_name && $cat_id)
{
$cat_exists = " cat_name='" . $this->db->db_addslashes($cat_name) . "' AND cat_id != $cat_id ";
}
$this->db->query("SELECT COUNT(cat_id) FROM phpgw_categories WHERE $cat_exists $filter",__LINE__,__FILE__);
$this->db->next_record();
if ($this->db->f(0))
{
return True;
}
else
{
return False;
}
}
}
?>

View File

@ -181,6 +181,12 @@
if (!$this->Link_ID)
{
foreach(array('Host','Database','User','Password') as $name)
{
$$name = $this->$name;
}
$type = $this->Type;
switch($this->Type) // convert to ADO db-type-names
{
case 'pgsql':
@ -190,13 +196,12 @@
" user=$this->User".($this->Password ? " password='".addslashes($this->Password)."'" : '');
$User = $Password = $Database = ''; // to indicate $Host is a connection-string
break;
case 'mssql':
if ($this->Port) $Host .= ','.$this->Port;
break;
default:
$Host = $this->Host . ($this->Port ? ':'.$this->Port : '');
foreach(array('Database','User','Password') as $name)
{
$$name = $this->$name;
}
$type = $this->Type;
if ($this->Port) $Host .= ':'.$this->Port;
break;
}
if (!is_object($GLOBALS['phpgw']->ADOdb) || // we have no connection so far
@ -228,6 +233,15 @@
return 0; // in case error-reporting = 'no'
}
//echo "new ADOdb connection<pre>".print_r($GLOBALS['phpgw']->ADOdb,True)."</pre>\n";
if ($this->Type == 'mssql')
{
// this is the format ADOdb expects
$this->Link_ID->Execute('SET DATEFORMAT ymd');
// sets the limit to the maximum
ini_set('mssql.textlimit',2147483647);
ini_set('mssql.sizelimit',2147483647);
}
}
else
{
@ -682,7 +696,7 @@
function haltmsg($msg)
{
printf("<p><b>Database error:</b> %s<br>\n", $msg);
if ($this->Errno != "0" && $this->Error != "()")
if (($this->Errno || $this->Error) && $this->Error != "()")
{
printf("<b>$this->Type Error</b>: %s (%s)<br>\n",$this->Errno,$this->Error);
}
@ -943,6 +957,10 @@
break; // ADOdb has no BlobEncode for mysql and returns an unquoted string !!!
}
return "'" . $this->Link_ID->BlobEncode($value) . "'";
case 'date':
return $this->Link_ID->DBDate($value);
case 'timestamp':
return $this->Link_ID->DBTimeStamp($value);
}
return $this->Link_ID->quote($value);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,590 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.egroupware.org *
* -------------------------------------------- *
* This file written by Michael Dean<mdean@users.sourceforge.net> *
* and Miles Lott<milosch@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class schema_proc
{
var $m_oTranslator;
var $m_oDeltaProc;
var $m_odb;
var $m_aTables;
var $m_bDeltaOnly;
function schema_proc($dbms)
{
$this->sType = $dbms;
$this->m_oTranslator = CreateObject('phpgwapi.schema_proc_' . $dbms);
$this->m_oDeltaProc = CreateObject('phpgwapi.schema_proc_array');
$this->m_aTables = array();
$this->m_bDeltaOnly = False; // Default to false here in case it's just a CreateTable script
}
function GenerateScripts($aTables, $bOutputHTML=False)
{
if (!is_array($aTables))
{
return False;
}
$this->m_aTables = $aTables;
$sAllTableSQL = '';
foreach ($this->m_aTables as $sTableName => $aTableDef)
{
$sSequenceSQL = '';
$append_ix = False;
if($this->_GetTableSQL($sTableName, $aTableDef, $sTableSQL, $sSequenceSQL,$append_ix))
{
if($append_ix)
{
$sTableSQL = "CREATE TABLE $sTableName (\n$sTableSQL\n"
. $this->m_oTranslator->m_sStatementTerminator;
}
else
{
$sTableSQL = "CREATE TABLE $sTableName (\n$sTableSQL\n)"
. $this->m_oTranslator->m_sStatementTerminator;
}
if($sSequenceSQL != '')
{
$sAllTableSQL .= $sSequenceSQL . "\n";
}
$sAllTableSQL .= $sTableSQL . "\n\n";
}
else
{
if($bOutputHTML)
{
print('<br>Failed generating script for <b>' . $sTableName . '</b><br>');
echo '<pre style="text-align: left;">'.$sTableName.' = '; print_r($aTableDef); echo "</pre>\n";
}
return false;
}
}
if($bOutputHTML)
{
print('<pre>' . $sAllTableSQL . '</pre><br><br>');
}
return True;
}
function ExecuteScripts($aTables, $bOutputHTML=False)
{
if(!is_array($aTables) || !IsSet($this->m_odb))
{
return False;
}
reset($aTables);
$this->m_aTables = $aTables;
while(list($sTableName, $aTableDef) = each($aTables))
{
if($this->CreateTable($sTableName, $aTableDef))
{
if($bOutputHTML)
{
echo '<br>Create Table <b>' . $sTableName . '</b>';
}
}
else
{
if($bOutputHTML)
{
echo '<br>Create Table Failed For <b>' . $sTableName . '</b>';
}
return False;
}
}
return True;
}
function DropAllTables($aTables, $bOutputHTML=False)
{
if(!is_array($aTables) || !isset($this->m_odb))
{
return False;
}
$this->m_aTables = $aTables;
reset($this->m_aTables);
while(list($sTableName, $aTableDef) = each($this->m_aTables))
{
if($this->DropTable($sTableName))
{
if($bOutputHTML)
{
echo '<br>Drop Table <b>' . $sTableSQL . '</b>';
}
}
else
{
return False;
}
}
return True;
}
function DropTable($sTableName)
{
$retVal = $this->m_oDeltaProc->DropTable($this, $this->m_aTables, $sTableName);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->DropTable($this, $this->m_aTables, $sTableName);
}
function DropColumn($sTableName, $aTableDef, $sColumnName, $bCopyData = true)
{
$retVal = $this->m_oDeltaProc->DropColumn($this, $this->m_aTables, $sTableName, $aTableDef, $sColumnName, $bCopyData);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->DropColumn($this, $this->m_aTables, $sTableName, $aTableDef, $sColumnName, $bCopyData);
}
function RenameTable($sOldTableName, $sNewTableName)
{
$retVal = $this->m_oDeltaProc->RenameTable($this, $this->m_aTables, $sOldTableName, $sNewTableName);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->RenameTable($this, $this->m_aTables, $sOldTableName, $sNewTableName);
}
function RenameColumn($sTableName, $sOldColumnName, $sNewColumnName, $bCopyData=True)
{
$retVal = $this->m_oDeltaProc->RenameColumn($this, $this->m_aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->RenameColumn($this, $this->m_aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData);
}
function AlterColumn($sTableName, $sColumnName, $aColumnDef, $bCopyData=True)
{
$retVal = $this->m_oDeltaProc->AlterColumn($this, $this->m_aTables, $sTableName, $sColumnName, $aColumnDef, $bCopyData);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->AlterColumn($this, $this->m_aTables, $sTableName, $sColumnName, $aColumnDef, $bCopyData);
}
function AddColumn($sTableName, $sColumnName, $aColumnDef)
{
$retVal = $this->m_oDeltaProc->AddColumn($this, $this->m_aTables, $sTableName, $sColumnName, $aColumnDef);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->AddColumn($this, $this->m_aTables, $sTableName, $sColumnName, $aColumnDef);
}
function CreateTable($sTableName, $aTableDef)
{
$retVal = $this->m_oDeltaProc->CreateTable($this, $this->m_aTables, $sTableName, $aTableDef);
if($this->m_bDeltaOnly)
{
return $retVal;
}
return $retVal && $this->m_oTranslator->CreateTable($this, $this->m_aTables, $sTableName, $aTableDef);
}
function UpdateSequence($sTableName,$sColumnName)
{
if (method_exists($this->m_oTranslator,'UpdateSequence'))
{
return $this->m_oTranslator->UpdateSequence($this->m_odb,$sTableName,$sColumnName);
}
return True;
}
// This function manually re-created the table incl. primary key and all other indices
// It is meant to use if the primary key, existing indices or column-order changes or
// columns are not longer used or new columns need to be created (with there default value or NULL)
// Beside the default-value in the schema, one can give extra defaults via $aDefaults to eg. use an
// other colum or function to set the value of a new or changed column
function RefreshTable($sTableName, $aTableDef, $aDefaults=False)
{
if($GLOBALS['DEBUG']) { echo "<p>schema_proc::RefreshTable('$sTableName',"._debug_array($aTableDef,False).")<p>m_aTables[$sTableName]="._debug_array($this->m_aTables[$sTableName],False)."\n"; }
$old_fd = $this->m_aTables[$sTableName]['fd'];
$Ok = $this->m_oDeltaProc->RefreshTable($this, $this->m_aTables, $sTableName, $aTableDef);
if(!$Ok || $this->m_bDeltaOnly)
{
return $Ok; // nothing else to do
}
$tmp_name = 'tmp_'.$sTableName;
$this->m_odb->transaction_begin();
$select = array();
foreach($aTableDef['fd'] as $name => $data)
{
if ($aDefaults && isset($aDefaults[$name])) // use given default
{
$value = $aDefaults[$name];
}
elseif (isset($old_fd[$name])) // existing column, use its value => column-name in query
{
$value = $name;
}
else // new column => use default value or NULL
{
if (!isset($data['default']) && (!isset($data['nullable']) || $data['nullable']))
{
$value = 'NULL';
}
else
{
$value = $this->m_odb->quote(isset($data['default']) ? $data['default'] : '',$data['type']);
// fix for postgres error "no '<' operator for type 'unknown'"
if ($this->sType == 'pgsql')
{
$type_translated = $this->m_oTranslator->TranslateType($data['type']);
$value = "CAST($value AS $type_translated)";
}
}
}
$select[] = $value;
}
$select = implode(',',$select);
$Ok = $this->RenameTable($sTableName,$tmp_name) &&
$this->CreateTable($sTableName,$aTableDef) &&
$this->m_odb->query("INSERT INTO $sTableName SELECT DISTINCT $select FROM $tmp_name",__LINE__,__FILE__);
if (!$Ok)
{
$this->m_odb->transaction_abort();
return False;
}
// do we need to update the new sequences value ?
if (count($aTableDef['pk']) == 1 && $aTableDef['fd'][$aTableDef['pk'][0]]['type'] == 'auto')
{
$this->UpdateSequence($sTableName,$aTableDef['pk'][0]);
}
$this->DropTable($tmp_name);
$this->m_odb->transaction_commit();
return True;
}
function f($value)
{
if($this->m_bDeltaOnly)
{
// Don't care, since we are processing deltas only
return False;
}
return $this->m_odb->f($value);
}
function num_rows()
{
if($this->m_bDeltaOnly)
{
// If not False, we will cause while loops calling us to hang
return False;
}
return $this->m_odb->num_rows();
}
function next_record()
{
if($this->m_bDeltaOnly)
{
// If not False, we will cause while loops calling us to hang
return False;
}
return $this->m_odb->next_record();
}
function query($sQuery, $line='', $file='')
{
if($this->m_bDeltaOnly)
{
// Don't run this query, since we are processing deltas only
return True;
}
return $this->m_odb->query($sQuery, $line, $file);
}
function _GetTableSQL($sTableName, $aTableDef, &$sTableSQL, &$sSequenceSQL,&$append_ix)
{
if(!is_array($aTableDef))
{
return False;
}
$sTableSQL = '';
reset($aTableDef['fd']);
while(list($sFieldName, $aFieldAttr) = each($aTableDef['fd']))
{
$sFieldSQL = '';
if($this->_GetFieldSQL($aFieldAttr, $sFieldSQL))
{
if($sTableSQL != '')
{
$sTableSQL .= ",\n";
}
$sTableSQL .= "$sFieldName $sFieldSQL";
if($aFieldAttr['type'] == 'auto')
{
$this->m_oTranslator->GetSequenceSQL($sTableName, $sSequenceSQL);
if($sSequenceSQL != '')
{
$sTableSQL .= sprintf(" DEFAULT nextval('seq_%s')", $sTableName);
}
}
}
else
{
if($GLOBALS['DEBUG']) { echo 'GetFieldSQL failed for ' . $sFieldName; }
return False;
}
}
$sUCSQL = '';
$sPKSQL = '';
$sIXSQL = '';
if(count($aTableDef['pk']) > 0)
{
if(!$this->_GetPK($aTableDef['pk'], $sPKSQL))
{
if($bOutputHTML)
{
print('<br>Failed getting primary key<br>');
}
return False;
}
}
if(count($aTableDef['uc']) > 0)
{
if(!$this->_GetUC($aTableDef['uc'], $sUCSQL))
{
if($bOutputHTML)
{
print('<br>Failed getting unique constraint<br>');
}
return False;
}
}
if(count($aTableDef['ix']) > 0)
{
$append_ix = False;
if(!$this->_GetIX($aTableDef['ix'], $sIXSQL,$append_ix,$sTableName))
{
if($bOutputHTML)
{
print('<br>Failed getting index<br>');
}
return False;
}
// print('<br>HELLO!: ' . $sIXSQL);
}
if($sPKSQL != '')
{
$sTableSQL .= ",\n" . $sPKSQL;
}
if($sUCSQL != '')
{
$sTableSQL .= ",\n" . $sUCSQL;
}
if($sIXSQL != '')
{
if($append_ix)
{
$sTableSQL .= ");\n" . $sIXSQL;
//pg: CREATE INDEX test1_id_index ON test1 (id);
}
else
{
$sTableSQL .= ",\n" . $sIXSQL;
}
}
return True;
}
// Get field DDL
function _GetFieldSQL($aField, &$sFieldSQL)
{
if($GLOBALS['DEBUG']) { echo'<br>_GetFieldSQL(): Incoming ARRAY: '; var_dump($aField); }
if(!is_array($aField))
{
return false;
}
$sType = '';
$iPrecision = 0;
$iScale = 0;
$bNullable = true;
reset($aField);
while(list($sAttr, $vAttrVal) = each($aField))
{
switch ($sAttr)
{
case 'type':
$sType = $vAttrVal;
break;
case 'precision':
$iPrecision = (int)$vAttrVal;
break;
case 'scale':
$iScale = (int)$vAttrVal;
break;
case 'nullable':
$bNullable = $vAttrVal;
break;
default:
break;
}
}
// Translate the type for the DBMS
if($sFieldSQL = $this->m_oTranslator->TranslateType($sType, $iPrecision, $iScale))
{
if(strpos(strtolower($sFieldSQL),'null')===false)
{
if(!$bNullable)
{
$sFieldSQL .= ' NOT NULL';
}
elseif ($this->m_oTranslator->b_needExplicitNULL)
{
$sFieldSQL .= ' NULL';
}
}
if(isset($aField['default']))
{
if($GLOBALS['DEBUG']) { echo'<br>_GetFieldSQL(): Calling TranslateDefault for "' . $aField['default'] . '"'; }
// Get default DDL - useful for differences in date defaults (eg, now() vs. getdate())
$sFieldSQL .= ' DEFAULT ' . (is_numeric($aField['default']) ? $aField['default'] :
$this->m_oTranslator->TranslateDefault($aField['default']));
}
if($GLOBALS['DEBUG']) { echo'<br>_GetFieldSQL(): Outgoing SQL: ' . $sFieldSQL; }
return true;
}
if($GLOBALS['DEBUG']) { echo '<br>Failed to translate field: type[' . $sType . '] precision[' . $iPrecision . '] scale[' . $iScale . ']<br>'; }
return False;
}
function _GetPK($aFields, &$sPKSQL)
{
$sPKSQL = '';
if(count($aFields) < 1)
{
return True;
}
$sPKSQL = $this->m_oTranslator->GetPKSQL(implode(',',$aFields));
return True;
}
function _GetUC($aFields, &$sUCSQL)
{
$sUCSQL = '';
if(count($aFields) < 1)
{
return True;
}
foreach($aFields as $mFields)
{
$aUCSQL[] = $this->m_oTranslator->GetUCSQL(
is_array($mFields) ? implode(',',$mFields) : $mFields);
}
$sUCSQL = implode(",\n",$aUCSQL);
return True;
}
function _GetIX($aFields, &$sIXSQL, &$append, $sTableName)
{
$sUCSQL = '';
if(count($aFields) < 1)
{
return True;
}
$aIXSQL = array();
foreach($aFields as $mFields)
{
$options = False;
if (is_array($mFields))
{
if (isset($mFields['options'])) // array sets additional options
{
$options = @$mFields['options'][$this->sType]; // db-specific options, eg. index-type
unset($mFields['options']);
}
if ($options === false)
{
continue; // dont create index for that db, eg. cant index text
}
$mFields = implode(',',$mFields);
}
$aIXSQL[] = $this->m_oTranslator->GetIXSQL($mFields,$append,$options,$sTableName);
}
if($append)
{
$sIXSQL = implode("\n",$aIXSQL);
}
else
{
$sIXSQL = implode(",\n",$aIXSQL);
}
return True;
}
}
?>

View File

@ -0,0 +1,364 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.egroupware.org *
* -------------------------------------------- *
* This file written by Michael Dean<mdean@users.sourceforge.net> *
* and Miles Lott<milosch@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class schema_proc_mssql
{
var $m_sStatementTerminator;
/* Following added to convert sql to array */
var $sCol = array();
var $pk = array();
var $fk = array();
var $ix = array();
var $uc = array();
var $b_needExplicitNULL = true; // no definition means NOT NULL for mssql
function schema_proc_mssql()
{
$this->m_sStatementTerminator = ';';
}
/* Return a type suitable for DDL */
function TranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = '';
switch($sType)
{
case 'auto':
$sTranslated = 'int identity(1,1) NOT NULL';
break;
case 'blob':
$sTranslated = 'image'; /* wonder how well PHP will support this??? */
break;
case 'char':
if ($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = sprintf("char(%d)", $iPrecision);
}
if ($iPrecision > 255)
{
$sTranslated = 'text';
}
break;
case 'date':
$sTranslated = 'smalldatetime';
break;
case 'decimal':
$sTranslated = sprintf("decimal(%d,%d)", $iPrecision, $iScale);
break;
case 'float':
switch ($iPrecision)
{
case 4:
$sTranslated = 'float';
break;
case 8:
$sTranslated = 'real';
break;
}
break;
case 'int':
switch ($iPrecision)
{
case 2:
$sTranslated = 'smallint';
break;
case 4:
case 8:
$sTranslated = 'int';
break;
}
break;
case 'longtext':
case 'text':
$sTranslated = 'text';
break;
case 'timestamp':
$sTranslated = 'datetime';
break;
case 'bool':
$sTranslated = 'bit';
break;
case 'varchar':
if ($iPrecision > 0 && $iPrecision <= 256)
{
$sTranslated = sprintf("varchar(%d)", $iPrecision);
}
if ($iPrecision > 256)
{
$sTranslated = 'text';
}
break;
}
return $sTranslated;
}
function TranslateDefault($sDefault)
{
switch ($sDefault)
{
case 'current_date':
case 'current_timestamp':
return 'GetDate()';
}
return "'$sDefault'";
}
// Inverse of above, convert sql column types to array info
function rTranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = '';
if ($sType == 'int' || $sType == 'tinyint' || $sType == 'smallint')
{
if ($iPrecision > 8)
{
$iPrecision = 8;
}
elseif($iPrecision > 4)
{
$iPrecision = 4;
}
else
{
$iPrecision = 2;
}
}
switch($sType)
{
case 'tinyint':
case 'smallint':
$sTranslated = "'type' => 'int', 'precision' => 2";
break;
case 'int':
$sTranslated = "'type' => 'int', 'precision' => 4";
break;
case 'char':
if ($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'char', 'precision' => $iPrecision";
}
if ($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'decimal':
$sTranslated = "'type' => 'decimal', 'precision' => $iPrecision, 'scale' => $iScale";
break;
case 'float':
case 'double':
$sTranslated = "'type' => 'float', 'precision' => $iPrecision";
break;
case 'smalldatetime':
$sTranslated = "'type' => 'date'";
break;
case 'datetime':
$sTranslated = "'type' => 'timestamp'";
break;
case 'varchar':
if ($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'varchar', 'precision' => $iPrecision";
}
if ($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'image':
$sTranslated = "'type' => 'blob'";
break;
case 'text':
$sTranslated = "'type' => '$sType'";
break;
case 'bit':
$sTranslated = "'type' => 'bool'";
break;
}
return $sTranslated;
}
function GetPKSQL($sFields)
{
return "PRIMARY KEY NONCLUSTERED ($sFields)";
}
function GetUCSQL($sFields)
{
return "UNIQUE($sFields)";
}
function GetIXSQL($sFields,&$append,$options,$sTableName)
{
$append = True;
$ixFields = str_replace(',','_',$sFields);
$index = $sTableName . '_' . $ixFields . '_idx';
return "CREATE INDEX $index ON $sTableName ($sFields);\n";
}
function _GetColumns($oProc, $sTableName, &$sColumns, $sDropColumn = '')
{
$sColumns = '';
$this->pk = array();
$this->fk = array();
$this->ix = array();
$this->uc = array();
// Field, Type, Null, Key, Default, Extra
$oProc->m_odb->query("exec sp_columns '$sTableName'");
while ($oProc->m_odb->next_record())
{
$type = $default = $null = $nullcomma = $prec = $scale = $ret = $colinfo = $scales = '';
if ($sColumns != '')
{
$sColumns .= ',';
}
$sColumns .= $oProc->m_odb->f(0);
// The rest of this is used only for SQL->array
$colinfo = explode('(',$oProc->m_odb->f(1));
$prec = ereg_replace(')','',$colinfo[1]);
$scales = explode(',',$prec);
if ($scales[1])
{
$prec = $scales[0];
$scale = $scales[1];
}
$type = $this->rTranslateType($colinfo[0], $prec, $scale);
if ($oProc->m_odb->f(2) == 'YES')
{
$null = "'nullable' => True";
}
else
{
$null = "'nullable' => False";
}
if ($oProc->m_odb->f(4))
{
$default = "'default' => '".$oProc->m_odb->f(4)."'";
$nullcomma = ',';
}
else
{
$default = '';
$nullcomma = '';
}
if ($oProc->m_odb->f(5))
{
$type = "'type' => 'auto'";
}
$this->sCol[] = "\t\t\t\t'" . $oProc->m_odb->f(0)."' => array(" . $type . ',' . $null . $nullcomma . $default . '),' . "\n";
if ($oProc->m_odb->f(3) == 'PRI')
{
$this->pk[] = $oProc->m_odb->f(0);
}
if ($oProc->m_odb->f(3) == 'UNI')
{
$this->uc[] = $oProc->m_odb->f(0);
}
/* Hmmm, MUL could also mean unique, or not... */
if ($oProc->m_odb->f(3) == 'MUL')
{
$this->ix[] = $oProc->m_odb->f(0);
}
}
/* ugly as heck, but is here to chop the trailing comma on the last element (for php3) */
$this->sCol[count($this->sCol) - 1] = substr($this->sCol[count($this->sCol) - 1],0,-2) . "\n";
return false;
}
function DropTable($oProc, &$aTables, $sTableName)
{
return !!($oProc->m_odb->query("DROP TABLE " . $sTableName));
}
function DropColumn($oProc, &$aTables, $sTableName, $aNewTableDef, $sColumnName, $bCopyData = true)
{
return !!($oProc->m_odb->query("ALTER TABLE $sTableName DROP COLUMN $sColumnName"));
}
function RenameTable($oProc, &$aTables, $sOldTableName, $sNewTableName)
{
return !!($oProc->m_odb->query("EXEC sp_rename '$sOldTableName', '$sNewTableName'"));
}
function RenameColumn($oProc, &$aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData = true)
{
// This really needs testing - it can affect primary keys, and other table-related objects
// like sequences and such
global $DEBUG;
if ($DEBUG) { echo '<br>RenameColumn: calling _GetFieldSQL for ' . $sNewColumnName; }
if ($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sNewColumnName], $sNewColumnSQL))
{
return !!($oProc->m_odb->query("EXEC sp_rename '$sTableName.$sOldColumnName', '$sNewColumnName'"));
}
return false;
}
function AlterColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef, $bCopyData = true)
{
global $DEBUG;
if ($DEBUG) { echo '<br>AlterColumn: calling _GetFieldSQL for ' . $sNewColumnName; }
if ($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sColumnName], $sNewColumnSQL))
{
return !!($oProc->m_odb->query("ALTER TABLE $sTableName ALTER COLUMN $sColumnName " . $sNewColumnSQL));
}
return false;
}
function AddColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef)
{
$oProc->_GetFieldSQL($aColumnDef, $sFieldSQL);
$query = "ALTER TABLE $sTableName ADD $sColumnName $sFieldSQL";
return !!($oProc->m_odb->query($query));
}
function GetSequenceSQL($sTableName, &$sSequenceSQL)
{
$sSequenceSQL = '';
return true;
}
function CreateTable($oProc, &$aTables, $sTableName, $aTableDef)
{
if ($oProc->_GetTableSQL($sTableName, $aTableDef, $sTableSQL, $sSequenceSQL,$append_ix))
{
// create sequence first since it will be needed for default
if ($sSequenceSQL != '')
{
$oProc->m_odb->query($sSequenceSQL);
}
if($append_ix)
{
$query = "CREATE TABLE $sTableName ($sTableSQL";
}
else
{
$query = "CREATE TABLE $sTableName ($sTableSQL)";
}
return !!($oProc->m_odb->query($query));
}
return false;
}
}
?>

View File

@ -0,0 +1,426 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.egroupware.org *
* -------------------------------------------- *
* This file written by Michael Dean<mdean@users.sourceforge.net> *
* and Miles Lott<milosch@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class schema_proc_mysql
{
var $m_sStatementTerminator;
/* Following added to convert sql to array */
var $sCol = array();
var $pk = array();
var $fk = array();
var $ix = array();
var $uc = array();
function schema_proc_mysql()
{
$this->m_sStatementTerminator = ';';
}
/* Return a type suitable for DDL */
function TranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = '';
switch($sType)
{
case 'auto':
$sTranslated = 'int(11) auto_increment not null';
break;
case 'blob':
$sTranslated = 'blob';
break;
case 'bool':
$sTranslated = 'tinyint(1)';
break;
case 'char':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = sprintf("char(%d)", $iPrecision);
}
if($iPrecision > 255)
{
$sTranslated = 'text';
}
break;
case 'date':
$sTranslated = 'date';
break;
case 'decimal':
$sTranslated = sprintf("decimal(%d,%d)", $iPrecision, $iScale);
break;
case 'float':
switch($iPrecision)
{
case 4:
$sTranslated = 'float';
break;
case 8:
$sTranslated = 'double';
break;
}
break;
case 'int':
switch($iPrecision)
{
case 2:
$sTranslated = 'smallint';
break;
case 4:
$sTranslated = 'int';
break;
case 8:
$sTranslated = 'bigint';
break;
}
break;
case 'longtext':
$sTranslated = 'longtext';
break;
case 'text':
$sTranslated = 'text';
break;
case 'timestamp':
$sTranslated = 'datetime';
break;
case 'varchar':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = sprintf("varchar(%d)", $iPrecision);
}
if($iPrecision > 255)
{
$sTranslated = 'text';
}
break;
}
return $sTranslated;
}
function TranslateDefault($sDefault)
{
switch($sDefault)
{
case 'current_date':
case 'current_timestamp':
$sDefault = 'now';
}
return "'$sDefault'";
}
/* Inverse of above, convert sql column types to array info */
function rTranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = '';
if($sType == 'int' || $sType == 'tinyint' || $sType == 'smallint' || $sType == 'bigint')
{
if($iPrecision > 8)
{
$iPrecision = 8;
}
elseif($iPrecision > 4)
{
$iPrecision = 4;
}
else
{
$iPrecision = 2;
}
}
switch($sType)
{
case 'tinyint':
case 'smallint':
$sTranslated = "'type' => 'int', 'precision' => 2";
break;
case 'int':
$sTranslated = "'type' => 'int', 'precision' => 4";
break;
case 'bigint':
$sTranslated = "'type' => 'int', 'precision' => 8";
break;
case 'char':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'char', 'precision' => $iPrecision";
}
if($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'decimal':
$sTranslated = "'type' => 'decimal', 'precision' => $iPrecision, 'scale' => $iScale";
break;
case 'float':
case 'double':
$sTranslated = "'type' => 'float', 'precision' => $iPrecision";
break;
case 'datetime':
$sTranslated = "'type' => 'timestamp'";
break;
case 'enum':
/* Here comes a nasty assumption */
/* $sTranslated = "'type' => 'varchar', 'precision' => 255"; */
$sTranslated = "'type' => 'varchar', 'precision' => $iPrecision";
break;
case 'varchar':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'varchar', 'precision' => $iPrecision";
}
if($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'longtext':
case 'text':
case 'blob':
case 'date':
$sTranslated = "'type' => '$sType'";
break;
}
return $sTranslated;
}
function GetPKSQL($sFields)
{
return "PRIMARY KEY($sFields)";
}
function GetUCSQL($sFields)
{
return "UNIQUE($sFields)";
}
function GetIXSQL($sFields,&$append,$options=False)
{
$append = False;
$type = 'INDEX';
$length = '';
if(strtoupper($options) == 'FULLTEXT')
{
$type = 'FULLTEXT';
}
if(is_numeric($options))
{
$length = "($options)";
}
return "$type($sFields $length)";
}
function _GetColumns($oProc, $sTableName, &$sColumns, $sDropColumn = '')
{
$sColumns = '';
$this->pk = array();
$this->fk = array();
$this->ix = array();
$this->uc = array();
/* Field, Type, Null, Key, Default, Extra */
$oProc->m_odb->query("describe $sTableName");
while($oProc->m_odb->next_record())
{
$type = $default = $null = $nullcomma = $prec = $scale = $ret = $colinfo = $scales = '';
if($sColumns != '')
{
$sColumns .= ',';
}
$sColumns .= $oProc->m_odb->f(0);
/* The rest of this is used only for SQL->array */
$colinfo = explode('(',$oProc->m_odb->f(1));
$prec = ereg_replace('\).*','',$colinfo[1]);
$scales = explode(',',$prec);
if($colinfo[0] == 'enum')
{
/* set prec to length of longest enum-value */
for($prec=0; list($nul,$name) = @each($scales);)
{
if($prec < (strlen($name) - 2))
{
/* -2 as name is like "'name'" */
$prec = (strlen($name) - 2);
}
}
}
elseif($scales[1])
{
$prec = $scales[0];
$scale = $scales[1];
}
$type = $this->rTranslateType($colinfo[0], $prec, $scale);
if($oProc->m_odb->f(2) == 'YES')
{
$null = "'nullable' => True";
}
else
{
$null = "'nullable' => False";
}
if($oProc->m_odb->f(4) != '')
{
$default = "'default' => '".$oProc->m_odb->f(4)."'";
$nullcomma = ',';
}
else
{
$default = '';
$nullcomma = '';
}
if($oProc->m_odb->f(5))
{
$type = "'type' => 'auto'";
}
$this->sCol[] = "\t\t\t\t'" . $oProc->m_odb->f(0)."' => array(" . $type . ',' . $null . $nullcomma . $default . '),' . "\n";
/*
if($oProc->m_odb->f(3) == 'PRI')
{
$this->pk[] = $oProc->m_odb->f(0);
}
if($oProc->m_odb->f(3) == 'UNI')
{
$this->uc[] = $oProc->m_odb->f(0);
}
// index over multiple columns
if($oProc->m_odb->f(3) == 'MUL')
{
$this->ix[] = $oProc->m_odb->f(0);
}
*/
}
$this->_GetIndices($oProc,$sTableName,$this->pk,$this->ix,$this->uc,$this->fk);
/* ugly as heck, but is here to chop the trailing comma on the last element (for php3) */
$this->sCol[count($this->sCol) - 1] = substr($this->sCol[count($this->sCol) - 1],0,-2) . "\n";
return false;
}
function _GetIndices($oProc,$sTableName,&$aPk,&$aIx,&$aUc,&$aFk)
{
$aPk = $aIx = $aUc = $aFk = array();
$seq = $ix = $uc = 0;
$oProc->m_odb->query("show index from $sTableName");
while($oProc->m_odb->next_record())
{
if($seq >= $oProc->m_odb->f('Seq_in_index')) // new index started
{
$$type += 1;
}
if($oProc->m_odb->f('Key_name') == 'PRIMARY') // pk
{
$aPk[] = $oProc->m_odb->f('Column_name');
$type = 'pk';
}
elseif($oProc->m_odb->f('Non_unique')) // ix
{
$aIx[$ix][] = $oProc->m_odb->f('Column_name');
$type = 'ix';
if($oProc->m_odb->f('Comment') == 'FULLTEXT')
{
$aIx[$ix]['options'] = array('mysql' => 'FULLTEXT');
}
elseif((int)$oProc->m_odb->f('Sub_part'))
{
$aIx[$ix]['options'] = array('mysql' => (int)$oProc->m_odb->f('Sub_part'));
}
}
else // uc
{
$aUc[$uc][] = $oProc->m_odb->f('Column_name');
$type = 'uc';
}
$seq = $oProc->m_odb->f('Seq_in_index');
}
//echo "Indices from $sTableName<pre>pk=".print_r($aPk,True)."\nix=".print_r($aIx,True)."\nuc=".print_r($aUc,True)."</pre>\n";
}
function DropTable($oProc, &$aTables, $sTableName)
{
return !!($oProc->m_odb->query("DROP TABLE " . $sTableName));
}
function DropColumn($oProc, &$aTables, $sTableName, $aNewTableDef, $sColumnName, $bCopyData = true)
{
return !!($oProc->m_odb->query("ALTER TABLE $sTableName DROP COLUMN $sColumnName"));
}
function RenameTable($oProc, &$aTables, $sOldTableName, $sNewTableName)
{
return !!($oProc->m_odb->query("ALTER TABLE $sOldTableName RENAME $sNewTableName"));
}
function RenameColumn($oProc, &$aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData = true)
{
/*
TODO: This really needs testing - it can affect primary keys, and other table-related objects
like sequences and such
*/
if($GLOBALS['DEBUG']) { echo '<br>RenameColumn: calling _GetFieldSQL for ' . $sNewColumnName; }
if($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sNewColumnName], $sNewColumnSQL))
{
return !!($oProc->m_odb->query("ALTER TABLE $sTableName CHANGE $sOldColumnName $sNewColumnName " . $sNewColumnSQL));
}
return false;
}
function AlterColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef, $bCopyData = true)
{
if($GLOBALS['DEBUG']) { echo '<br>AlterColumn: calling _GetFieldSQL for ' . $sNewColumnName; }
if($oProc->_GetFieldSQL($aTables[$sTableName]["fd"][$sColumnName], $sNewColumnSQL))
{
return !!($oProc->m_odb->query("ALTER TABLE $sTableName MODIFY $sColumnName " . $sNewColumnSQL));
/* return !!($oProc->m_odb->query("ALTER TABLE $sTableName CHANGE $sColumnName $sColumnName " . $sNewColumnSQL)); */
}
return false;
}
function AddColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef)
{
$oProc->_GetFieldSQL($aColumnDef, $sFieldSQL);
$query = "ALTER TABLE $sTableName ADD COLUMN $sColumnName $sFieldSQL";
return !!($oProc->m_odb->query($query));
}
function GetSequenceSQL($sTableName, &$sSequenceSQL)
{
$sSequenceSQL = '';
return true;
}
function CreateTable($oProc, &$aTables, $sTableName, $aTableDef)
{
if($oProc->_GetTableSQL($sTableName, $aTableDef, $sTableSQL, $sSequenceSQL,$append_ix))
{
/* create sequence first since it will be needed for default */
if($sSequenceSQL != '')
{
$oProc->m_odb->query($sSequenceSQL);
}
$query = "CREATE TABLE $sTableName ($sTableSQL)";
return !!($oProc->m_odb->query($query));
}
return false;
}
}
?>

View File

@ -0,0 +1,748 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.egroupware.org *
* SQL for table properties taken from phpPgAdmin Version 2.2.1 *
* http://www.greatbridge.org/project/phppgadmin *
* Copyright (C) 1999-2000 Dan Wilson <phpPgAdmin@acucore.com> *
* Copyright (C) 1998-1999 Tobias Ratschiller <tobias@dnet.it> *
* -------------------------------------------- *
* This file written by Michael Dean<mdean@users.sourceforge.net> *
* and Miles Lott<milosch@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class schema_proc_pgsql
{
var $m_sStatementTerminator;
/* Following added to convert sql to array */
var $sCol = array();
var $pk = array();
var $fk = array();
var $ix = array();
var $uc = array();
function schema_proc_pgsql()
{
$this->m_sStatementTerminator = ';';
}
/* Return a type suitable for DDL */
function TranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = $sType;
switch($sType)
{
case 'auto':
$sTranslated = 'int4';
break;
case 'blob':
$sTranslated = 'bytea';
break;
case 'char':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = sprintf("char(%d)", $iPrecision);
}
if($iPrecision > 255)
{
$sTranslated = 'text';
}
break;
case 'decimal':
$sTranslated = sprintf("decimal(%d,%d)", $iPrecision, $iScale);
break;
case 'float':
if($iPrecision == 4 || $iPrecision == 8)
{
$sTranslated = sprintf("float%d", $iPrecision);
}
break;
case 'int':
if($iPrecision == 2 || $iPrecision == 4 || $iPrecision == 8)
{
$sTranslated = sprintf("int%d", $iPrecision);
}
break;
case 'longtext':
$sTranslated = 'text';
break;
case 'varchar':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = sprintf("varchar(%d)", $iPrecision);
}
if($iPrecision > 255)
{
$sTranslated = 'text';
}
break;
}
return $sTranslated;
}
function TranslateDefault($sDefault)
{
switch($sDefault)
{
case 'current_date':
case 'current_timestamp':
$sDefault = 'now';
}
return "'$sDefault'";
}
/* Inverse of above, convert sql column types to array info */
function rTranslateType($sType, $iPrecision = 0, $iScale = 0)
{
$sTranslated = '';
switch($sType)
{
case 'serial':
$sTranslated = "'type' => 'auto'";
break;
case 'int2':
$sTranslated = "'type' => 'int', 'precision' => 2";
break;
case 'int4':
$sTranslated = "'type' => 'int', 'precision' => 4";
break;
case 'int8':
$sTranslated = "'type' => 'int', 'precision' => 8";
break;
case 'bpchar':
case 'char':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'char', 'precision' => $iPrecision";
}
if($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'numeric':
/* Borrowed from phpPgAdmin */
$iPrecision = ($iScale >> 16) & 0xffff;
$iScale = ($iScale - 4) & 0xffff;
$sTranslated = "'type' => 'decimal', 'precision' => $iPrecision, 'scale' => $iScale";
break;
case 'float':
case 'float4':
case 'float8':
case 'double':
$sTranslated = "'type' => 'float', 'precision' => $iPrecision";
break;
case 'datetime':
case 'timestamp':
$sTranslated = "'type' => 'timestamp'";
break;
case 'varchar':
if($iPrecision > 0 && $iPrecision < 256)
{
$sTranslated = "'type' => 'varchar', 'precision' => $iPrecision";
}
if($iPrecision > 255)
{
$sTranslated = "'type' => 'text'";
}
break;
case 'text':
case 'blob':
case 'date':
case 'bool';
$sTranslated = "'type' => '$sType'";
break;
}
return $sTranslated;
}
function GetPKSQL($sFields)
{
return "PRIMARY KEY($sFields)";
}
function GetUCSQL($sFields)
{
return "UNIQUE($sFields)";
}
function GetIXSQL($sFields,&$append,$options,$sTableName)
{
$append = True;
$ixsql = '';
$ixFields = str_replace(',','_',$sFields);
$index = $sTableName . '_' . $ixFields . '_idx';
return "CREATE INDEX $index ON $sTableName ($sFields);\n";
}
function _GetColumns($oProc, $sTableName, &$sColumns, $sDropColumn='', $sAlteredColumn='', $sAlteredColumnType='')
{
$sdb = $oProc->m_odb;
$sdc = $oProc->m_odb;
$sColumns = '';
$this->pk = array();
$this->fk = array();
$this->ix = array();
$this->uc = array();
$query = "SELECT a.attname,a.attnum FROM pg_attribute a,pg_class b WHERE ";
$query .= "b.oid=a.attrelid AND a.attnum>0 and b.relname='$sTableName'";
if($sDropColumn != '')
{
$query .= " AND a.attname != '$sDropColumn'";
}
$query .= ' ORDER BY a.attnum';
// echo '_GetColumns: ' . $query;
$oProc->m_odb->query($query);
while($oProc->m_odb->next_record())
{
if($sColumns != '')
{
$sColumns .= ',';
}
$sFieldName = $oProc->m_odb->f(0);
/* Failsafe in case the query still includes the column to be dropped */
if($sFieldName != $sDropColumn)
{
$sColumns .= $sFieldName;
}
if($sAlteredColumn == $sFieldName && $sAlteredColumnType != '')
{
$sColumns .= '::' . $sAlteredColumnType;
}
}
//$qdefault = "SELECT substring(d.adsrc for 128) FROM pg_attrdef d, pg_class c "
// . "WHERE c.relname = $sTableName AND c.oid = d.adrelid AND d.adnum =" . $oProc->m_odb->f(1);
$sql_get_fields = "
SELECT
a.attnum,
a.attname AS field,
t.typname AS type,
a.attlen AS length,
a.atttypmod AS lengthvar,
a.attnotnull AS notnull
FROM
pg_class c,
pg_attribute a,
pg_type t
WHERE
c.relname = '$sTableName'
and a.attnum > 0
and a.attrelid = c.oid
and a.atttypid = t.oid
ORDER BY a.attnum";
/* attnum field type length lengthvar notnull(Yes/No) */
$sdb->query($sql_get_fields);
while($sdb->next_record())
{
$colnum = $sdb->f(0);
$colname = $sdb->f(1);
if($sdb->f(5) == 'Yes')
{
$null = "'nullable' => True";
}
else
{
$null = "'nullable' => False";
}
if($sdb->f(2) == 'numeric')
{
$prec = $sdb->f(3);
$scale = $sdb->f(4);
}
elseif($sdb->f(3) > 0)
{
$prec = $sdb->f(3);
$scale = 0;
}
elseif($sdb->f(4) > 0)
{
$prec = $sdb->f(4) - 4;
$scale = 0;
}
else
{
$prec = 0;
$scale = 0;
}
$type = $this->rTranslateType($sdb->f(2), $prec, $scale);
$sql_get_default = "
SELECT d.adsrc AS rowdefault
FROM pg_attrdef d, pg_class c
WHERE
c.relname = '$sTableName' AND
c.oid = d.adrelid AND
d.adnum = $colnum
";
$sdc->query($sql_get_default);
$sdc->next_record();
if($sdc->f(0))
{
if(strstr($sdc->f(0),'nextval'))
{
$default = '';
$nullcomma = '';
}
else
{
$default = "'default' => '".$sdc->f(0)."'";
$nullcomma = ',';
}
}
else
{
$default = '';
$nullcomma = '';
}
$default = str_replace("''","'",$default);
$this->sCol[] = "\t\t\t\t'" . $colname . "' => array(" . $type . ',' . $null . $nullcomma . $default . '),' . "\n";
}
$sql_pri_keys = "
SELECT
ic.relname AS index_name,
bc.relname AS tab_name,
ta.attname AS column_name,
i.indisunique AS unique_key,
i.indisprimary AS primary_key
FROM
pg_class bc,
pg_class ic,
pg_index i,
pg_attribute ta,
pg_attribute ia
WHERE
bc.oid = i.indrelid
AND ic.oid = i.indexrelid
AND ia.attrelid = i.indexrelid
AND ta.attrelid = bc.oid
AND bc.relname = '$sTableName'
AND ta.attrelid = i.indrelid
AND ta.attnum = i.indkey[ia.attnum-1]
ORDER BY
index_name, tab_name, column_name";
$sdc->query($sql_pri_keys);
while($sdc->next_record())
{
//echo '<br> checking: ' . $sdc->f(4);
if($sdc->f(4) == 't')
{
$this->pk[] = $sdc->f(2);
}
if($sdc->f(3) == 't')
{
$this->uc[] = $sdc->f(2);
}
}
$this->_GetIndices($oProc,$sTableName,$this->pk,$this->ix,$this->uc,$this->fk);
/* ugly as heck, but is here to chop the trailing comma on the last element (for php3) */
$this->sCol[count($this->sCol) - 1] = substr($this->sCol[count($this->sCol) - 1],0,-2) . "\n";
return False;
}
function _GetIndices($oProc,$sTableName,&$aPk,&$aIx,&$aUc,&$aFk)
{
/* Try not to die on errors with the query */
$tmp = $oProc->Halt_On_Error;
$oProc->Halt_On_Error = 'no';
$aIx = array();
/* This select excludes any indexes that are just base indexes for constraints. */
if(@$oProc->m_odb->db_version >= 7.3)
{
$sql = "SELECT pg_catalog.pg_get_indexdef(i.indexrelid) as pg_get_indexdef FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i WHERE c.relname = '$sTableName' AND pg_catalog.pg_table_is_visible(c.oid) AND c.oid = i.indrelid AND i.indexrelid = c2.oid AND NOT EXISTS ( SELECT 1 FROM pg_catalog.pg_depend d JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) WHERE d.classid = c2.tableoid AND d.objid = c2.oid AND d.deptype = 'i' AND c.contype IN ('u', 'p') ) ORDER BY c2.relname";
$num = 0;
}
else
{
$sql = "SELECT c2.relname, i.indisprimary, i.indisunique, pg_get_indexdef(i.indexrelid) FROM pg_class c, pg_class c2, pg_index i WHERE c.relname = '$sTableName' AND c.oid = i.indrelid AND i.indexrelid = c2.oid AND NOT i.indisprimary AND NOT i.indisunique ORDER BY c2.relname";
$num = 3;
}
@$oProc->m_odb->query($sql);
$oProc->m_odb->next_record();
$indexfields = ereg_replace("^CREATE.+\(",'',$oProc->m_odb->f($num));
$indexfields = ereg_replace("\)$",'',$indexfields);
$aIx = explode(',',$indexfields);
$i = 0;
foreach($aIx as $ix)
{
$aIx[$i] = trim($ix);
$i++;
}
/* Restore original value */
$oProc->Halt_On_Error = $tmp;
#echo "Indices from $sTableName<pre>pk=".print_r($aPk,True)."\nix=".print_r($aIx,True)."\nuc=".print_r($aUc,True)."</pre>\n";
}
function _CopyAlteredTable($oProc, &$aTables, $sSource, $sDest)
{
$oDB = $oProc->m_odb;
$oProc->m_odb->query("SELECT * FROM $sSource");
while($oProc->m_odb->next_record())
{
$sSQL = "INSERT INTO $sDest (";
$i=0;
@reset($aTables[$sDest]['fd']);
while(list($name,$arraydef) = each($aTables[$sDest]['fd']))
{
if($i > 0)
{
$sSQL .= ',';
}
$sSQL .= $name;
$i++;
}
$sSQL .= ') VALUES (';
@reset($aTables[$sDest]['fd']);
$i = 0;
while(list($name,$arraydef) = each($aTables[$sDest]['fd']))
{
if($i > 0)
{
$sSQL .= ',';
}
// !isset($arraydef['nullable']) means nullable !!!
if($oProc->m_odb->f($name) == NULL && (!isset($arraydef['nullable']) || $arraydef['nullable']))
{
$sSQL .= 'NULL';
}
else
{
$value = $oProc->m_odb->f($name) != NULL ? $oProc->m_odb->f($name) : @$arraydef['default'];
switch($arraydef['type'])
{
case 'blob':
case 'char':
case 'date':
case 'text':
case 'timestamp':
case 'varchar':
$sSQL .= "'" . $oProc->m_odb->db_addslashes($oProc->m_odb->f($name)) . "'";
break;
default:
$sSQL .= (int)$oProc->m_odb->f($name);
}
}
$i++;
}
$sSQL .= ')';
$oDB->query($sSQL);
}
return true;
}
function GetSequenceForTable($oProc,$table,&$sSequenceName)
{
if($GLOBALS['DEBUG']) { echo '<br>GetSequenceForTable: ' . $table; }
$oProc->m_odb->query("SELECT relname FROM pg_class WHERE NOT relname ~ 'pg_.*' AND relname LIKE 'seq_$table' AND relkind='S' ORDER BY relname",__LINE__,__FILE__);
$oProc->m_odb->next_record();
if($oProc->m_odb->f('relname'))
{
$sSequenceName = $oProc->m_odb->f('relname');
}
return True;
}
function GetSequenceFieldForTable($oProc,$table,&$sField)
{
if($GLOBALS['DEBUG']) { echo '<br>GetSequenceFieldForTable: You rang?'; }
$oProc->m_odb->query("SELECT a.attname FROM pg_attribute a, pg_class c, pg_attrdef d WHERE c.relname='$table' AND c.oid=d.adrelid AND d.adsrc LIKE '%seq_$table%' AND a.attrelid=c.oid AND d.adnum=a.attnum");
$oProc->m_odb->next_record();
if($oProc->m_odb->f('attname'))
{
$sField = $oProc->m_odb->f('attname');
}
return True;
}
function GetIndexesForTable($oProc,$table,&$sIndexNames)
{
$oProc->m_odb->query("SELECT a.attname FROM pg_attribute a, pg_class c, pg_attrdef d WHERE c.relname='$table' AND c.oid=d.adrelid AND d.adsrc LIKE '%$table%idx' AND a.attrelid=c.oid AND d.adnum=a.attnum");
while($oProc->m_odb->next_record())
{
$sIndexNames[] = $oProc->m_odb->f('attname');
}
return True;
}
function DropSequenceForTable($oProc,$table)
{
if($GLOBALS['DEBUG']) { echo '<br>DropSequenceForTable: ' . $table; }
$this->GetSequenceForTable($oProc,$table,$sSequenceName);
if($sSequenceName)
{
$oProc->m_odb->query("DROP SEQUENCE " . $sSequenceName,__LINE__,__FILE__);
}
return True;
}
function DropIndexesForTable($oProc,$table)
{
if($GLOBALS['DEBUG']) { echo '<br>DropSequenceForTable: ' . $table; }
$this->GetIndexesForTable($oProc,$table,$sIndexNames);
if(@is_array($sIndexNames))
{
foreach($sIndexNames as $null => $index)
{
$oProc->m_odb->query("DROP INDEX $index",__LINE__,__FILE__);
}
}
return True;
}
function DropTable($oProc, &$aTables, $sTableName)
{
$this->DropSequenceForTable($oProc,$sTableName);
return $oProc->m_odb->query("DROP TABLE " . $sTableName) &&
$this->DropSequenceForTable($oProc, $sTableName) &&
$this->DropIndexesForTable($oProc, $sTableName);
}
function DropColumn($oProc, &$aTables, $sTableName, $aNewTableDef, $sColumnName, $bCopyData = true)
{
if($GLOBALS['DEBUG'])
{
echo '<br>DropColumn: table=' . $sTableName . ', column=' . $sColumnName;
}
if($bCopyData)
{
$oProc->m_odb->query("SELECT * INTO $sTableName" . "_tmp FROM $sTableName");
}
$this->DropTable($oProc, $aTables, $sTableName);
$oProc->_GetTableSQL($sTableName, $aNewTableDef, $sTableSQL, $sSequenceSQL,$append_ix);
if($sSequenceSQL)
{
$oProc->m_odb->query($sSequenceSQL);
}
if($append_ix)
{
$query = "CREATE TABLE $sTableName ($sTableSQL";
}
else
{
$query = "CREATE TABLE $sTableName ($sTableSQL)";
}
if(!$bCopyData)
{
return !!($oProc->m_odb->query($query));
}
$oProc->m_odb->query($query);
$this->_GetColumns($oProc, $sTableName . '_tmp', $sColumns, $sColumnName);
$query = "INSERT INTO $sTableName($sColumns) SELECT $sColumns FROM $sTableName" . '_tmp';
$bRet = !!($oProc->m_odb->query($query));
return ($bRet && $this->DropTable($oProc, $aTables, $sTableName . '_tmp'));
}
function RenameTable($oProc, &$aTables, $sOldTableName, $sNewTableName)
{
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): Fetching old sequence for: ' . $sOldTableName; }
$this->GetSequenceForTable($oProc,$sOldTableName,$sSequenceName);
if($GLOBALS['DEBUG']) { echo ' - ' . $sSequenceName; }
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): Fetching sequence field for: ' . $sOldTableName; }
$this->GetSequenceFieldForTable($oProc,$sOldTableName,$sField);
if($GLOBALS['DEBUG']) { echo ' - ' . $sField; }
if($sSequenceName)
{
$oProc->m_odb->query("SELECT last_value FROM seq_$sOldTableName",__LINE__,__FILE__);
$oProc->m_odb->next_record();
$lastval = $oProc->m_odb->f(0);
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): dropping old sequence: ' . $sSequenceName . ' used on field: ' . $sField; }
$this->DropSequenceForTable($oProc,$sOldTableName);
if($lastval)
{
$lastval = ' start ' . $lastval;
}
$this->GetSequenceSQL($sNewTableName,$sSequenceSQL);
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): Making new sequence using: ' . $sSequenceSQL . $lastval; }
$oProc->m_odb->query($sSequenceSQL . $lastval,__LINE__,__FILE__);
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): Altering column default for: ' . $sField; }
$oProc->m_odb->query("ALTER TABLE $sOldTableName ALTER $sField SET DEFAULT nextval('seq_" . $sNewTableName . "')",__LINE__,__FILE__);
}
// renameing existing indexes and primary keys
$indexes = $oProc->m_odb->Link_ID->MetaIndexes($sOldTableName,True);
if($GLOBALS['DEBUG']) { echo '<br>RenameTable(): Fetching indexes: '; _debug_array($indexes); }
foreach($indexes as $name => $data)
{
$new_name = str_replace($sOldTableName,$sNewTableName,$name);
$sql = "ALTER TABLE $name RENAME TO $new_name";
if($GLOBALS['DEBUG']) { echo "<br>RenameTable(): Renaming the index '$name': $sql"; }
$oProc->m_odb->query($sql);
}
return !!($oProc->m_odb->query("ALTER TABLE $sOldTableName RENAME TO $sNewTableName"));
}
function RenameColumn($oProc, &$aTables, $sTableName, $sOldColumnName, $sNewColumnName, $bCopyData = true)
{
/*
This really needs testing - it can affect primary keys, and other table-related objects
like sequences and such
*/
if($bCopyData)
{
$oProc->m_odb->query("SELECT * INTO $sTableName" . "_tmp FROM $sTableName");
}
$this->DropTable($oProc, $aTables, $sTableName);
if(!$bCopyData)
{
return $this->CreateTable($oProc, $aTables, $sTableName, $oProc->m_aTables[$sTableName], false);
}
$this->CreateTable($oProc, $aTables, $sTableName, $aTables[$sTableName], True);
$this->_GetColumns($oProc, $sTableName . "_tmp", $sColumns);
$query = "INSERT INTO $sTableName SELECT $sColumns FROM $sTableName" . "_tmp";
$bRet = !!($oProc->m_odb->query($query));
return ($bRet && $this->DropTable($oProc, $aTables, $sTableName . "_tmp"));
}
function AlterColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef, $bCopyData = true)
{
if($bCopyData)
{
$oProc->m_odb->query("SELECT * INTO $sTableName" . "_tmp FROM $sTableName");
}
$this->DropTable($oProc, $aTables, $sTableName);
if(!$bCopyData)
{
return $this->CreateTable($oProc, $aTables, $sTableName, $aTables[$sTableName], True);
}
$this->CreateTable($oProc, $aTables, $sTableName, $aTables[$sTableName], True);
$this->_GetColumns($oProc, $sTableName . "_tmp", $sColumns, '', $sColumnName, $aColumnDef['type'] == 'auto' ? 'int4' : $aColumnDef['type']);
/*
TODO: analyze the type of change and determine if this is used or _CopyAlteredTable
this is a performance consideration only, _CopyAlteredTable should be safe
$query = "INSERT INTO $sTableName SELECT $sColumns FROM $sTableName" . "_tmp";
$bRet = !!($oProc->m_odb->query($query));
*/
$bRet = $this->_CopyAlteredTable($oProc, $aTables, $sTableName . '_tmp', $sTableName);
return ($bRet && $this->DropTable($oProc, $aTables, $sTableName . "_tmp"));
}
function AddColumn($oProc, &$aTables, $sTableName, $sColumnName, &$aColumnDef)
{
if(isset($aColumnDef['default'])) // pgsql cant add a colum with a default
{
$default = $aColumnDef['default'];
unset($aColumnDef['default']);
}
if(isset($aColumnDef['nullable']) && !$aColumnDef['nullable']) // pgsql cant add a column not nullable
{
$notnull = !$aColumnDef['nullable'];
unset($aColumnDef['nullable']);
}
$oProc->_GetFieldSQL($aColumnDef, $sFieldSQL);
$query = "ALTER TABLE $sTableName ADD COLUMN $sColumnName $sFieldSQL";
if(($Ok = !!($oProc->m_odb->query($query))) && isset($default))
{
$query = "ALTER TABLE $sTableName ALTER COLUMN $sColumnName SET DEFAULT '$default';\n";
$query .= "UPDATE $sTableName SET $sColumnName='$default';\n";
$Ok = !!($oProc->m_odb->query($query));
if($OK && $notnull)
{
// unfortunally this is pgSQL >= 7.3
//$query .= "ALTER TABLE $sTableName ALTER COLUMN $sColumnName SET NOT NULL;\n";
//$Ok = !!($oProc->m_odb->query($query));
// so we do it the slow way
AlterColumn($oProc, $aTables, $sTableName, $sColumnName, $aColumnDef);
}
}
return $Ok;
}
function UpdateSequence($oDb,$sTableName,$sColName)
{
$sql = "SELECT MAX($sColName) FROM $sTableName";
$oDb->query($sql,__LINE__,__FILE__);
if ($oDb->next_record() && $oDb->f(0))
{
$sql = "SELECT setval('seq_$sTableName',".(1 + $oDb->f(0)).")";
if($GLOBALS['DEBUG']) { echo "<br>Updating sequence 'seq_$sTableName' using: $sql"; }
return $oDb->query($sql,__LINE__,__FILE__);
}
return True;
}
function GetSequenceSQL($sTableName, &$sSequenceSQL)
{
$sSequenceSQL = sprintf("CREATE SEQUENCE seq_%s", $sTableName);
return true;
}
function CreateTable($oProc, $aTables, $sTableName, $aTableDef, $bCreateSequence = true)
{
if($oProc->_GetTableSQL($sTableName, $aTableDef, $sTableSQL, $sSequenceSQL,$append_ix))
{
/* create sequence first since it will be needed for default */
if($bCreateSequence && $sSequenceSQL != '')
{
if($GLOBALS['DEBUG']) { echo '<br>Making sequence using: ' . $sSequenceSQL; }
$oProc->m_odb->query($sSequenceSQL);
}
if($append_ix)
{
$query = "CREATE TABLE $sTableName ($sTableSQL";
}
else
{
$query = "CREATE TABLE $sTableName ($sTableSQL)";
}
return !!($oProc->m_odb->query($query));
}
return false;
}
}
?>

View File

@ -0,0 +1,964 @@
<?php
/**************************************************************************\
* eGroupWare - Setup *
* http://www.egroupware.org *
* -------------------------------------------- *
* This file written by Joseph Engo<jengo@phpgroupware.org> *
* and Dan Kuykendall<seek3r@phpgroupware.org> *
* and Mark Peters<skeeter@phpgroupware.org> *
* and Miles Lott<milosch@groupwhere.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class setup
{
var $db;
var $oProc;
var $detection = '';
var $process = '';
var $lang = '';
var $html = '';
var $appreg = '';
/* table name vars */
var $tbl_apps;
var $tbl_config;
var $tbl_hooks;
function setup($html=False, $translation=False)
{
$this->detection = CreateObject('phpgwapi.setup_detection');
$this->process = CreateObject('phpgwapi.setup_process');
$this->appreg = CreateObject('phpgwapi.app_registry');
/* The setup application needs these */
$this->html = $html ? CreateObject('phpgwapi.setup_html') : '';
$this->translation = $translation ? CreateObject('phpgwapi.setup_translation') : '';
// $this->tbl_apps = $this->get_apps_table_name();
// $this->tbl_config = $this->get_config_table_name();
$this->tbl_hooks = $this->get_hooks_table_name();
}
/*!
@function loaddb
@abstract include api db class for the ConfigDomain and connect to the db
*/
function loaddb()
{
if(!isset($this->ConfigDomain) || empty($this->ConfigDomain))
{
$this->ConfigDomain = get_var('ConfigDomain',array('COOKIE','POST'),$_POST['FormDomain']);
}
$GLOBALS['phpgw_info']['server']['db_type'] = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_type'];
if ($GLOBALS['phpgw_info']['server']['db_type'] == 'pgsql')
{
$GLOBALS['phpgw_info']['server']['db_persistent'] = False;
}
$this->db = CreateObject('phpgwapi.db');
$this->db->Host = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_host'];
$this->db->Port = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_port'];
$this->db->Type = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_type'];
$this->db->Database = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_name'];
$this->db->User = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_user'];
$this->db->Password = $GLOBALS['phpgw_domain'][$this->ConfigDomain]['db_pass'];
}
/**
* Set the domain used for cookies
*
* @return string domain
*/
function set_cookiedomain()
{
$this->cookie_domain = $_SERVER['HTTP_HOST'];
// remove port from HTTP_HOST
if (preg_match("/^(.*):(.*)$/",$this->cookie_domain,$arr))
{
$this->cookie_domain = $arr[1];
}
if (count(explode('.',$this->cookie_domain)) <= 1)
{
// setcookie dont likes domains without dots, leaving it empty, gets setcookie to fill the domain in
$this->cookie_domain = '';
}
}
/**
* Set a cookie
*
* @param string $cookiename name of cookie to be set
* @param string $cookievalue value to be used, if unset cookie is cleared (optional)
* @param int $cookietime when cookie should expire, 0 for session only (optional)
*/
function set_cookie($cookiename,$cookievalue='',$cookietime=0)
{
if(!isset($this->cookie_domain) || !$this->cookie_domain)
{
$this->set_cookiedomain();
}
setcookie($cookiename,$cookievalue,$cookietime,'/',$this->cookie_domain);
}
/*!
@function auth
@abstract authenticate the setup user
@param $auth_type ???
*/
function auth($auth_type='Config')
{
#phpinfo();
$FormLogout = get_var('FormLogout', array('GET','POST'));
if(!$FormLogout)
{
$ConfigLogin = get_var('ConfigLogin', array('POST'));
$HeaderLogin = get_var('HeaderLogin', array('POST'));
$FormDomain = get_var('FormDomain', array('POST'));
$FormUser = get_var('FormUser', array('POST'));
$FormPW = get_var('FormPW', array('POST'));
$this->ConfigDomain = get_var('ConfigDomain',array('POST','COOKIE'));
$ConfigUser = get_var('ConfigUser', array('POST','COOKIE'));
$ConfigPW = get_var('ConfigPW', array('POST','COOKIE'));
$HeaderUser = get_var('HeaderUser', array('POST','COOKIE'));
$HeaderPW = get_var('HeaderPW', array('POST','COOKIE'));
$ConfigLang = get_var('ConfigLang', array('POST','COOKIE'));
/* Setup defaults to aid in header upgrade to version 1.26.
* This was the first version to include the following values.
*/
if(!@isset($GLOBALS['phpgw_domain'][$FormDomain]['config_user']) && isset($GLOBALS['phpgw_domain'][$FormDomain]))
{
@$GLOBALS['phpgw_domain'][$FormDomain]['config_user'] = 'admin';
}
if(!@isset($GLOBALS['phpgw_info']['server']['header_admin_user']))
{
@$GLOBALS['phpgw_info']['server']['header_admin_user'] = 'admin';
}
}
$remoteip = $_SERVER['REMOTE_ADDR'];
if(!empty($remoteip) && !$this->checkip($remoteip)) { return False; }
/* If FormLogout is set, simply invalidate the cookies (LOGOUT) */
switch(strtolower($FormLogout))
{
case 'config':
/* config logout */
$expire = time() - 86400;
$this->set_cookie('ConfigUser','',$expire,'/');
$this->set_cookie('ConfigPW','',$expire,'/');
$this->set_cookie('ConfigDomain','',$expire,'/');
$this->set_cookie('ConfigLang','',$expire,'/');
$GLOBALS['phpgw_info']['setup']['LastDomain'] = $_COOKIE['ConfigDomain'];
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = lang('You have successfully logged out');
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = '';
return False;
case 'header':
/* header admin logout */
$expire = time() - 86400;
$this->set_cookie('HeaderUser','',$expire,'/');
$this->set_cookie('HeaderPW','',$expire,'/');
$this->set_cookie('ConfigLang','',$expire,'/');
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = lang('You have successfully logged out');
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = '';
return False;
}
/* We get here if FormLogout is not set (LOGIN or subsequent pages) */
/* Expire login if idle for 20 minutes. The cookies are updated on every page load. */
$expire = (int)(time() + (1200*9));
switch(strtolower($auth_type))
{
case 'header':
if(!empty($HeaderLogin))
{
/* header admin login */
/* New test is md5, cleartext version is for header < 1.26 */
if ($this->check_auth($FormUser,$FormPW,$GLOBALS['phpgw_info']['server']['header_admin_user'],
$GLOBALS['phpgw_info']['server']['header_admin_password']))
{
$this->set_cookie('HeaderUser',"$FormUser",$expire,'/');
$this->set_cookie('HeaderPW',"$FormPW",$expire,'/');
$this->set_cookie('ConfigLang',"$ConfigLang",$expire,'/');
return True;
}
else
{
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = lang('Invalid password');
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = '';
return False;
}
}
elseif(!empty($HeaderPW) && $auth_type == 'Header')
{
// Returning after login to header admin
/* New test is md5, cleartext version is for header < 1.26 */
if ($this->check_auth($HeaderUser,$HeaderPW,$GLOBALS['phpgw_info']['server']['header_admin_user'],
$GLOBALS['phpgw_info']['server']['header_admin_password']))
{
$this->set_cookie('HeaderUser',"$HeaderUser",$expire,'/');
$this->set_cookie('HeaderPW',"$HeaderPW",$expire,'/');
$this->set_cookie('ConfigLang',"$ConfigLang",$expire,'/');
return True;
}
else
{
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = lang('Invalid password');
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = '';
return False;
}
}
break;
case 'config':
if(!empty($ConfigLogin))
{
/* config login */
/* New test is md5, cleartext version is for header < 1.26 */
if (isset($GLOBALS['phpgw_domain'][$FormDomain]) &&
$this->check_auth($FormUser,$FormPW,@$GLOBALS['phpgw_domain'][$FormDomain]['config_user'],
@$GLOBALS['phpgw_domain'][$FormDomain]['config_passwd']))
{
$this->set_cookie('ConfigUser',"$FormUser",$expire,'/');
$this->set_cookie('ConfigPW',"$FormPW",$expire,'/');
$this->set_cookie('ConfigDomain',"$FormDomain",$expire,'/');
/* Set this now since the cookie will not be available until the next page load */
$this->ConfigDomain = "$FormDomain";
$this->set_cookie('ConfigLang',"$ConfigLang",$expire,'/');
return True;
}
else
{
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = lang('Invalid password');
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = '';
return False;
}
}
elseif(!empty($ConfigPW))
{
// Returning after login to config
/* New test is md5, cleartext version is for header < 1.26 */
if ($this->check_auth($ConfigUser,$ConfigPW,@$GLOBALS['phpgw_domain'][$this->ConfigDomain]['config_user'],
@$GLOBALS['phpgw_domain'][$this->ConfigDomain]['config_passwd']))
{
$this->set_cookie('ConfigUser',"$ConfigUser",$expire,'/');
$this->set_cookie('ConfigPW',"$ConfigPW",$expire,'/');
$this->set_cookie('ConfigDomain',$this->ConfigDomain,$expire,'/');
$this->set_cookie('ConfigLang',"$ConfigLang",$expire,'/');
return True;
}
else
{
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = lang('Invalid password');
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = '';
return False;
}
}
break;
}
return False;
}
// returns True if user and pw match, if conf_pw is a md5 ONLY compare with md5($pw) and NOT the plaintext !!!
function check_auth($user,$pw,$conf_user,$conf_pw)
{
if ($user != $conf_user)
{
return False; // wrong username
}
if (preg_match('/^[0-9a-f]{32}$/',$conf_pw)) // $conf_pw is a md5
{
$pw = md5($pw);
}
return $pw == $conf_pw;
}
function checkip($remoteip='')
{
//echo "<p>setup::checkip($remoteip) against setup_acl='".$GLOBALS['phpgw_info']['server']['setup_acl']."'</p>\n";
$allowed_ips = explode(',',@$GLOBALS['phpgw_info']['server']['setup_acl']);
if(empty($GLOBALS['phpgw_info']['server']['setup_acl']) || !is_array($allowed_ips))
{
return True; // no test
}
$remotes = explode('.',$remoteip);
foreach($allowed_ips as $value)
{
if (!preg_match('/^[0-9.]+$/',$value))
{
$value = gethostbyname($was=$value); // resolve domain-name, eg. a dyndns account
//echo "resolving '$was' to '$value'<br>\n";
}
$values = explode('.',$value);
for($i = 0; $i < count($values); ++$i)
{
if ((int) $values[$i] != (int) $remotes[$i])
{
break;
}
}
if ($i == count($values))
{
return True; // match
}
}
$GLOBALS['phpgw_info']['setup']['HeaderLoginMSG'] = '';
$GLOBALS['phpgw_info']['setup']['ConfigLoginMSG'] = lang('Invalid IP address');
return False;
}
/*!
@function get_major
@abstract Return X.X.X major version from X.X.X.X versionstring
@param $
*/
function get_major($versionstring)
{
if(!$versionstring)
{
return False;
}
$version = str_replace('pre','.',$versionstring);
$varray = explode('.',$version);
$major = implode('.',array($varray[0],$varray[1],$varray[2]));
return $major;
}
/*!
@function clear_session_cache
@abstract Clear system/user level cache so as to have it rebuilt with the next access
@param None
*/
function clear_session_cache()
{
$tables = Array();
$tablenames = $this->db->table_names();
foreach($tablenames as $key => $val)
{
$tables[] = $val['table_name'];
}
if(in_array('phpgw_app_sessions',$tables))
{
$this->db->lock(array('phpgw_app_sessions'));
@$this->db->query("DELETE FROM phpgw_app_sessions WHERE sessionid = '0' and loginid = '0' and app = 'phpgwapi' and location = 'config'",__LINE__,__FILE__);
@$this->db->query("DELETE FROM phpgw_app_sessions WHERE app = 'phpgwapi' and location = 'phpgw_info_cache'",__LINE__,__FILE__);
$this->db->unlock();
}
}
/*!
@function register_app
@abstract Add an application to the phpgw_applications table
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
@param $enable optional, set to True/False to override setup.inc.php setting
*/
function register_app($appname,$enable=99)
{
$setup_info = $GLOBALS['setup_info'];
if(!$appname)
{
return False;
}
if($enable==99)
{
$enable = $setup_info[$appname]['enable'];
}
$enable = (int)$enable;
/*
Use old applications table if the currentver is less than 0.9.10pre8,
but not if the currentver = '', which probably means new install.
*/
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.10pre8') && ($setup_info['phpgwapi']['currentver'] != ''))
{
$appstbl = 'applications';
}
else
{
$appstbl = 'phpgw_applications';
}
if($GLOBALS['DEBUG'])
{
echo '<br>register_app(): ' . $appname . ', version: ' . $setup_info[$appname]['version'] . ', table: ' . $appstbl . '<br>';
// _debug_array($setup_info[$appname]);
}
if($setup_info[$appname]['version'])
{
if($setup_info[$appname]['tables'])
{
$tables = implode(',',$setup_info[$appname]['tables']);
}
if ($setup_info[$appname]['tables_use_prefix'] == True)
{
echo $setup_info[$appname]['name'] . ' uses tables_use_prefix, storing '
. $setup_info[$appname]['tables_prefix']
. ' as prefix for ' . $setup_info[$appname]['name'] . " tables\n";
$sql = "INSERT INTO phpgw_config (config_app,config_name,config_value) "
."VALUES ('".$setup_info[$appname]['name']."','"
.$appname."_tables_prefix','".$setup_info[$appname]['tables_prefix']."');";
$this->db->query($sql,__LINE__,__FILE__);
}
$this->db->query("INSERT INTO $appstbl "
. "(app_name,app_enabled,app_order,app_tables,app_version) "
. "VALUES ("
. "'" . $setup_info[$appname]['name'] . "',"
. $enable . ","
. (int)$setup_info[$appname]['app_order'] . ","
. "'" . $tables . "',"
. "'" . $setup_info[$appname]['version'] . "');"
);
$this->clear_session_cache();
}
}
/*!
@function app_registered
@abstract Check if an application has info in the db
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
@param $enabled optional, set to False to not enable this app
*/
function app_registered($appname)
{
$setup_info = $GLOBALS['setup_info'];
if(!$appname)
{
return False;
}
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.10pre8') && ($setup_info['phpgwapi']['currentver'] != ''))
{
$appstbl = 'applications';
}
else
{
$appstbl = 'phpgw_applications';
}
if(@$GLOBALS['DEBUG'])
{
echo '<br>app_registered(): checking ' . $appname . ', table: ' . $appstbl;
// _debug_array($setup_info[$appname]);
}
$this->db->query("SELECT COUNT(app_name) FROM $appstbl WHERE app_name='".$appname."'");
$this->db->next_record();
if($this->db->f(0))
{
if(@$GLOBALS['DEBUG'])
{
echo '... app previously registered.';
}
return True;
}
if(@$GLOBALS['DEBUG'])
{
echo '... app not registered';
}
return False;
}
/*!
@function update_app
@abstract Update application info in the db
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
@param $enabled optional, set to False to not enable this app
*/
function update_app($appname)
{
$setup_info = $GLOBALS['setup_info'];
if(!$appname)
{
return False;
}
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.10pre8') && ($setup_info['phpgwapi']['currentver'] != ''))
{
$appstbl = 'applications';
}
else
{
$appstbl = 'phpgw_applications';
}
if($GLOBALS['DEBUG'])
{
echo '<br>update_app(): ' . $appname . ', version: ' . $setup_info[$appname]['currentver'] . ', table: ' . $appstbl . '<br>';
// _debug_array($setup_info[$appname]);
}
$this->db->query("SELECT COUNT(app_name) FROM $appstbl WHERE app_name='".$appname."'");
$this->db->next_record();
if(!$this->db->f(0))
{
return False;
}
if($setup_info[$appname]['version'])
{
//echo '<br>' . $setup_info[$appname]['version'];
if($setup_info[$appname]['tables'])
{
$tables = implode(',',$setup_info[$appname]['tables']);
}
$sql = "UPDATE $appstbl "
. "SET app_name='" . $setup_info[$appname]['name'] . "',"
. " app_enabled=" . (int)$setup_info[$appname]['enable'] . ","
. " app_order=" . (int)$setup_info[$appname]['app_order'] . ","
. " app_tables='" . $tables . "',"
. " app_version='" . $setup_info[$appname]['version'] . "'"
. " WHERE app_name='" . $appname . "'";
//echo $sql; exit;
$this->db->query($sql);
}
}
/*!
@function update_app_version
@abstract Update application version in applications table, post upgrade
@param $setup_info Array of application information (multiple apps or single)
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
@param $tableschanged ???
*/
function update_app_version($setup_info, $appname, $tableschanged = True)
{
if(!$appname)
{
return False;
}
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.10pre8') && ($setup_info['phpgwapi']['currentver'] != ''))
{
$appstbl = 'applications';
}
else
{
$appstbl = 'phpgw_applications';
}
if($tableschanged == True)
{
$GLOBALS['phpgw_info']['setup']['tableschanged'] = True;
}
if($setup_info[$appname]['currentver'])
{
$this->db->query("UPDATE $appstbl SET app_version='" . $setup_info[$appname]['currentver'] . "' WHERE app_name='".$appname."'");
}
return $setup_info;
}
/*!
@function deregister_app
@abstract de-Register an application
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
*/
function deregister_app($appname)
{
if(!$appname)
{
return False;
}
$setup_info = $GLOBALS['setup_info'];
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.10pre8') && ($setup_info['phpgwapi']['currentver'] != ''))
{
$appstbl = 'applications';
}
else
{
$appstbl = 'phpgw_applications';
}
//echo 'DELETING application: ' . $appname;
$this->db->query("DELETE FROM $appstbl WHERE app_name='". $appname ."'");
$this->clear_session_cache();
}
/*!
@function register_hooks
@abstract Register an application's hooks
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
*/
function register_hooks($appname)
{
$setup_info = $GLOBALS['setup_info'];
if(!$appname)
{
return False;
}
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.8pre5') && ($setup_info['phpgwapi']['currentver'] != ''))
{
/* No phpgw_hooks table yet. */
return False;
}
if (!is_object($this->hooks))
{
$this->hooks = CreateObject('phpgwapi.hooks',$this->db);
}
$this->hooks->register_hooks($appname,$setup_info[$appname]['hooks']);
}
/*!
@function update_hooks
@abstract Update an application's hooks
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
*/
function update_hooks($appname)
{
$this->register_hooks($appname);
}
/*!
@function deregister_hooks
@abstract de-Register an application's hooks
@param $appname Application 'name' with a matching $setup_info[$appname] array slice
*/
function deregister_hooks($appname)
{
if($this->alessthanb($setup_info['phpgwapi']['currentver'],'0.9.8pre5'))
{
/* No phpgw_hooks table yet. */
return False;
}
if(!$appname)
{
return False;
}
//echo "DELETING hooks for: " . $setup_info[$appname]['name'];
if (!is_object($this->hooks))
{
$this->hooks = CreateObject('phpgwapi.hooks',$this->db);
}
$this->hooks->register_hooks($appname);
}
/*!
@function hook
@abstract call the hooks for a single application
@param $location hook location - required
@param $appname application name - optional
*/
function hook($location, $appname='')
{
if (!is_object($this->hooks))
{
$this->hooks = CreateObject('phpgwapi.hooks',$this->db);
}
return $this->hooks->single($location,$appname,True,True);
}
/*
@function alessthanb
@abstract phpgw version checking, is param 1 < param 2 in phpgw versionspeak?
@param $a phpgw version number to check if less than $b
@param $b phpgw version number to check $a against
#return True if $a < $b
*/
function alessthanb($a,$b,$DEBUG=False)
{
$num = array('1st','2nd','3rd','4th');
if($DEBUG)
{
echo'<br>Input values: '
. 'A="'.$a.'", B="'.$b.'"';
}
$newa = str_replace('pre','.',$a);
$newb = str_replace('pre','.',$b);
$testa = explode('.',$newa);
if(@$testa[1] == '')
{
$testa[1] = 0;
}
$testb = explode('.',$newb);
if(@$testb[1] == '')
{
$testb[1] = 0;
}
if(@$testb[3] == '')
{
$testb[3] = 0;
}
$less = 0;
for($i=0;$i<count($testa);$i++)
{
if($DEBUG) { echo'<br>Checking if '. (int)$testa[$i] . ' is less than ' . (int)$testb[$i] . ' ...'; }
if((int)$testa[$i] < (int)$testb[$i])
{
if ($DEBUG) { echo ' yes.'; }
$less++;
if($i<3)
{
/* Ensure that this is definitely smaller */
if($DEBUG) { echo" This is the $num[$i] octet, so A is definitely less than B."; }
$less = 5;
break;
}
}
elseif((int)$testa[$i] > (int)$testb[$i])
{
if($DEBUG) { echo ' no.'; }
$less--;
if($i<2)
{
/* Ensure that this is definitely greater */
if($DEBUG) { echo" This is the $num[$i] octet, so A is definitely greater than B."; }
$less = -5;
break;
}
}
else
{
if($DEBUG) { echo ' no, they are equal or of different length.'; }
// makes sure eg. '1.0.0' is counted less the '1.0.0.xxx' !
$less = count($testa) < count($testb) ? 1 : 0;
}
}
if($DEBUG) { echo '<br>Check value is: "'.$less.'"'; }
if($less>0)
{
if($DEBUG) { echo '<br>A is less than B'; }
return True;
}
elseif($less<0)
{
if($DEBUG) { echo '<br>A is greater than B'; }
return False;
}
else
{
if($DEBUG) { echo '<br>A is equal to B'; }
return False;
}
}
/*!
@function amorethanb
@abstract phpgw version checking, is param 1 > param 2 in phpgw versionspeak?
@param $a phpgw version number to check if more than $b
@param $b phpgw version number to check $a against
#return True if $a < $b
*/
function amorethanb($a,$b,$DEBUG=False)
{
$num = array('1st','2nd','3rd','4th');
if($DEBUG)
{
echo'<br>Input values: '
. 'A="'.$a.'", B="'.$b.'"';
}
$newa = str_replace('pre','.',$a);
$newb = str_replace('pre','.',$b);
$testa = explode('.',$newa);
if($testa[3] == '')
{
$testa[3] = 0;
}
$testb = explode('.',$newb);
if($testb[3] == '')
{
$testb[3] = 0;
}
$less = 0;
for($i=0;$i<count($testa);$i++)
{
if($DEBUG) { echo'<br>Checking if '. (int)$testa[$i] . ' is more than ' . (int)$testb[$i] . ' ...'; }
if((int)$testa[$i] > (int)$testb[$i])
{
if($DEBUG) { echo ' yes.'; }
$less++;
if($i<3)
{
/* Ensure that this is definitely greater */
if($DEBUG) { echo" This is the $num[$i] octet, so A is definitely greater than B."; }
$less = 5;
break;
}
}
elseif((int)$testa[$i] < (int)$testb[$i])
{
if($DEBUG) { echo ' no.'; }
$less--;
if($i<2)
{
/* Ensure that this is definitely smaller */
if($DEBUG) { echo" This is the $num[$i] octet, so A is definitely less than B."; }
$less = -5;
break;
}
}
else
{
if($DEBUG) { echo ' no, they are equal.'; }
$less = 0;
}
}
if($DEBUG) { echo '<br>Check value is: "'.$less.'"'; }
if($less>0)
{
if($DEBUG) { echo '<br>A is greater than B'; }
return True;
}
elseif($less<0)
{
if($DEBUG) { echo '<br>A is less than B'; }
return False;
}
else
{
if($DEBUG) { echo '<br>A is equal to B'; }
return False;
}
}
function get_hooks_table_name()
{
if(@$this->alessthanb($GLOBALS['setup_info']['phpgwapi']['currentver'],'0.9.8pre5') &&
@$GLOBALS['setup_info']['phpgwapi']['currentver'] != '')
{
/* No phpgw_hooks table yet. */
return False;
}
return 'phpgw_hooks';
}
function setup_account_object()
{
if (!is_object($GLOBALS['phpgw']->accounts))
{
if (!is_object($this->db))
{
$this->loaddb();
}
/* Load up some configured values */
$this->db->query("SELECT config_name,config_value FROM phpgw_config "
. "WHERE config_name LIKE 'ldap%' OR config_name LIKE 'account_%' OR config_name LIKE '%encryption%'",__LINE__,__FILE__);
while($this->db->next_record())
{
$GLOBALS['phpgw_info']['server'][$this->db->f('config_name')] = $this->db->f('config_value');
}
if (!is_object($GLOBALS['phpgw']))
{
$GLOBALS['phpgw'] = CreateObject('phpgwapi.phpgw');
}
copyobj($this->db,$GLOBALS['phpgw']->db);
$GLOBALS['phpgw']->common = CreateObject('phpgwapi.common');
$GLOBALS['phpgw']->accounts = CreateObject('phpgwapi.accounts');
if(($GLOBALS['phpgw_info']['server']['account_repository'] == 'ldap') &&
!$GLOBALS['phpgw']->accounts->ds)
{
printf("<b>Error: Error connecting to LDAP server %s!</b><br>",$GLOBALS['phpgw_info']['server']['ldap_host']);
exit;
}
}
}
/*!
@function add_account
@abstract add an user account or a user group
@param username string alphanumerical username or groupname (account_lid)
@param first, last string first / last name
@param $passwd string cleartext pw
@param $group string/boolean Groupname for users primary group or False for a group, default 'Default'
@param $changepw boolean user has right to change pw, default False
@returns the numerical user-id
@note if the $username already exists, only the id is returned, no new user / group gets created
*/
function add_account($username,$first,$last,$passwd,$group='default',$changepw=False)
{
$this->setup_account_object();
$groupid = $group ? $GLOBALS['phpgw']->accounts->name2id($group) : False;
if(!($accountid = $GLOBALS['phpgw']->accounts->name2id($username)))
{
$accountid = $accountid ? $accountid : $GLOBALS['phpgw']->accounts->create(array(
'account_type' => $group ? 'u' : 'g',
'account_lid' => $username,
'account_passwd' => $passwd,
'account_firstname' => $first,
'account_lastname' => $last,
'account_status' => 'A',
'account_primary_group' => $groupid,
'account_expires' => -1
));
}
$accountid = (int)$accountid;
if($groupid)
{
$this->add_acl('phpgw_group',(int)$groupid,$accountid);
}
$this->add_acl('preferences','changepassword',$accountid,(int)$changepw);
return $accountid;
}
/*!
@function add_acl
@abstract Add ACL rights
@param $app string/array with app-names
@param $locations string eg. run
@param $account int/string accountid or account_lid
@param $rights int rights to set, default 1
*/
function add_acl($apps,$location,$account,$rights=1)
{
if (!is_int($account))
{
$this->setup_account_object();
$account = $GLOBALS['phpgw']->accounts->name2id($account);
}
$rights = (int)$rights;
if(!is_object($this->db))
{
$this->loaddb();
}
if(!is_array($apps))
{
$apps = array($apps);
}
foreach($apps as $app)
{
$this->db->query("DELETE FROM phpgw_acl WHERE acl_appname='$app' AND acl_location='$location' AND acl_account=$account");
if ($rights)
{
$this->db->query("INSERT INTO phpgw_acl(acl_appname,acl_location,acl_account,acl_rights) VALUES('$app','$location',$account,$rights)");
}
}
}
}
?>

View File

@ -426,7 +426,7 @@
// explode with "\t" and removing "\n" with str_replace, needed to work with mbstring.overload=7
list($message_id,$app_name,,$content) = explode("\t",$line);
$content=str_replace("\n",'',$content);
$content=str_replace(array("\n","\r"),'',$content);
$message_id = substr(strtolower(chop($message_id)),0,MAX_MESSAGE_ID_LENGTH);
$app_name = chop($app_name);
$raw[$app_name][$message_id] = $content;

File diff suppressed because it is too large Load Diff

183
setup/setup_demo.php Normal file
View File

@ -0,0 +1,183 @@
<?php
/**************************************************************************\
* eGroupWare *
* http://www.egroupware.org *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
// Little file to setup a demo install
$GLOBALS['phpgw_info']['flags'] = array(
'noheader' => True,
'nonavbar' => True,
'currentapp' => 'home',
'noapi' => True
);
include('./inc/functions.inc.php');
// Authorize the user to use setup app and load the database
// Does not return unless user is authorized
if(!$GLOBALS['phpgw_setup']->auth('Config') || get_var('cancel',Array('POST')))
{
Header('Location: index.php');
exit;
}
if(!get_var('submit',Array('POST')))
{
$tpl_root = $GLOBALS['phpgw_setup']->html->setup_tpl_dir('setup');
$setup_tpl = CreateObject('setup.Template',$tpl_root);
$setup_tpl->set_file(array(
'T_head' => 'head.tpl',
'T_footer' => 'footer.tpl',
'T_alert_msg' => 'msg_alert_msg.tpl',
'T_login_main' => 'login_main.tpl',
'T_login_stage_header' => 'login_stage_header.tpl',
'T_setup_demo' => 'setup_demo.tpl'
));
$setup_tpl->set_block('T_login_stage_header','B_multi_domain','V_multi_domain');
$setup_tpl->set_block('T_login_stage_header','B_single_domain','V_single_domain');
$GLOBALS['phpgw_setup']->html->show_header(lang('Demo Server Setup'));
$setup_tpl->set_var('action_url','setup_demo.php');
$setup_tpl->set_var('description',lang('<b>This will create 1 admin account and 3 demo accounts</b><br>The username/passwords are: demo/guest, demo2/guest and demo3/guest.'));
$setup_tpl->set_var('lang_deleteall',lang('Delete all existing SQL accounts, groups, ACLs and preferences (normally not necessary)?'));
$setup_tpl->set_var('detailadmin',lang('Details for Admin account'));
$setup_tpl->set_var('adminusername',lang('Admin username'));
$setup_tpl->set_var('adminfirstname',lang('Admin first name'));
$setup_tpl->set_var('adminlastname',lang('Admin last name'));
$setup_tpl->set_var('adminpassword',lang('Admin password'));
$setup_tpl->set_var('adminpassword2',lang('Re-enter password'));
$setup_tpl->set_var('create_demo_accounts',lang('Create demo accounts'));
$setup_tpl->set_var('lang_submit',lang('Save'));
$setup_tpl->set_var('lang_cancel',lang('Cancel'));
$setup_tpl->pparse('out','T_setup_demo');
$GLOBALS['phpgw_setup']->html->show_footer();
}
else
{
/* Posted admin data */
$passwd = get_var('passwd',Array('POST'));
$passwd2 = get_var('passwd2',Array('POST'));
$username = get_var('username',Array('POST'));
$fname = get_var('fname',Array('POST'));
$lname = get_var('lname',Array('POST'));
if($passwd != $passwd2)
{
echo lang('Passwords did not match, please re-enter') . '.';
exit;
}
if(!$username)
{
echo lang('You must enter a username for the admin') . '.';
exit;
}
$GLOBALS['phpgw_setup']->loaddb();
/* Begin transaction for acl, etc */
$GLOBALS['phpgw_setup']->db->transaction_begin();
if($_POST['delete_all'])
{
/* Now, clear out existing tables */
$GLOBALS['phpgw_setup']->db->query('DELETE FROM phpgw_accounts');
$GLOBALS['phpgw_setup']->db->query('DELETE FROM phpgw_preferences');
$GLOBALS['phpgw_setup']->db->query('DELETE FROM phpgw_acl');
}
/* Create the demo groups */
$defaultgroupid = (int)$GLOBALS['phpgw_setup']->add_account('Default','Default','Group',False,False);
$admingroupid = (int)$GLOBALS['phpgw_setup']->add_account('Admins','Admin','Group',False,False);
if (!$defaultgroupid || !$admingroupid)
{
echo '<p><b>'.lang('Error in group-creation !!!')."</b></p>\n";
echo '<p>'.lang('click <a href="index.php">here</a> to return to setup.')."</p>\n";
$GLOBALS['phpgw_setup']->db->transaction_abort();
exit;
}
/* Group perms for the default group */
$GLOBALS['phpgw_setup']->add_acl(array('addressbook','calendar','infolog','email','preferences'),'run',$defaultgroupid);
// give admin access to all apps, to save us some support requests
$all_apps = array();
$GLOBALS['phpgw_setup']->db->query('SELECT app_name FROM phpgw_applications WHERE app_enabled<3');
while ($GLOBALS['phpgw_setup']->db->next_record())
{
$all_apps[] = $GLOBALS['phpgw_setup']->db->f('app_name');
}
$GLOBALS['phpgw_setup']->add_acl($all_apps,'run',$admingroupid);
function insert_default_prefs($accountid)
{
$defaultprefs = array(
'common' => array(
'maxmatchs' => 15,
'template_set' => 'idots',
'theme' => 'idots',
'navbar_format' => 'icons',
'tz_offset' => 0,
'dateformat' => 'Y/m/d',
'timeformat' => '24',
'lang' => get_var('ConfigLang',Array('POST','COOKIE'),'en'),
'default_app' => 'calendar',
'currency' => '$',
'show_help' => True,
),
'calendar' => array(
'workdaystarts' => 9,
'workdayends' => 17,
'weekdaystarts' => 'Monday',
'defaultcalendar' => 'day',
'planner_start_with_group' => $GLOBALS['defaultgroupid'],
),
);
foreach ($defaultprefs as $app => $prefs)
{
$prefs = $GLOBALS['phpgw_setup']->db->db_addslashes(serialize($prefs));
$GLOBALS['phpgw_setup']->db->query("INSERT INTO phpgw_preferences(preference_owner,preference_app,preference_value) VALUES($accountid,'$app','$prefs')",__FILE__,__LINE__);
}
}
insert_default_prefs(-2); // set some default prefs
/* Creation of the demo accounts is optional - the checkbox is on by default. */
if(get_var('create_demo',Array('POST')))
{
// Create 3 demo accounts
$GLOBALS['phpgw_setup']->add_account('demo','Demo','Account','guest');
$GLOBALS['phpgw_setup']->add_account('demo2','Demo2','Account','guest');
$GLOBALS['phpgw_setup']->add_account('demo3','Demo3','Account','guest');
}
/* Create records for administrator account, with Admins as primary and Default as additional group */
$accountid = $GLOBALS['phpgw_setup']->add_account($username,$fname,$lname,$passwd,'Admins',True);
if (!$accountid)
{
echo '<p><b>'.lang('Error in admin-creation !!!')."</b></p>\n";
echo '<p>'.lang('click <a href="index.php">here</a> to return to setup.')."</p>\n";
$GLOBALS['phpgw_setup']->db->transaction_abort();
exit;
}
$GLOBALS['phpgw_setup']->add_acl('phpgw_group',$admingroupid,$accountid);
$GLOBALS['phpgw_setup']->add_acl('phpgw_group',$defaultgroupid,$accountid);
/* Clear the access log, since these are all new users anyway */
$GLOBALS['phpgw_setup']->db->query('DELETE FROM phpgw_access_log');
$GLOBALS['phpgw_setup']->db->transaction_commit();
Header('Location: index.php');
exit;
}
?>