1) so-layers now run every parameter through either addslashes of intval, to prevent query-insertion and for pgSql 7.3 compatibility

2) corrected the escapeing of " and '
3) added some inline-docs
This commit is contained in:
Ralf Becker 2003-06-14 13:51:53 +00:00
parent 415faa58ed
commit 1095c64709
3 changed files with 249 additions and 122 deletions

View File

@ -19,11 +19,18 @@
/*!
@class bolink
@author ralfbecker
@copyright GPL - GNU General Public License
@abstract generalized linking between entries of phpGroupware apps - BO layer
@discussion This class is the BO-layer of the links
@discussion Links have two ends each pointing to an entry, each entry is a double:
@discussion app app-name or directory-name of an phpgw application, eg. 'infolog'
@discussion id this is the id, eg. an integer or a tupple like '0:INBOX:1234'
@discussion This class is the BO-layer of the links<br>
Links have two ends each pointing to an entry, each entry is a double:<br>
app app-name or directory-name of an phpgw application, eg. 'infolog'<br>
id this is the id, eg. an integer or a tupple like '0:INBOX:1234'<br>
The BO-layer implementes 2 extra features on top of the so-layer:<br>
1) It handles links to not already existing entries. This is used by the eTemplate link-widget, which allows to
setup links even for new / not already existing entries, before they get saved.
In that case you have to set the first id to 0 for the link-function and pass the array returned in that id
(not the return-value) after saveing your new entry again to the link function.<br>
2) Attaching files: they are saved in the vfs and not the link-table (!).
*/
class bolink extends solink
{
@ -54,13 +61,7 @@
'menuaction' => 'calendar.uicalendar.view'
),
'view_id' => 'cal_id'
), /*
'email' => array(
'view' => array(
'menuaction' => 'email.uimessage.message'
),
'view_id' => 'msgball[acctnum:folder:msgnum]' // id is a tupple/array, fields separated by ':'
), */
'infolog' => array(
'query' => 'infolog.boinfolog.link_query',
'title' => 'infolog.boinfolog.link_title',
@ -70,13 +71,27 @@
),
'view_id' => 'action_id',
),
/*
'email' => array(
'view' => array(
'menuaction' => 'email.uimessage.message'
),
'view_id' => 'msgball[acctnum:folder:msgnum]' // id is a tupple/array, fields separated by ':'
),
*/
);
var $vfs;
var $vfs_basedir='/infolog';
var $vfs_basedir='/infolog'; // might changes to links if class gets imported in the api
var $vfs_appname='file'; // pseudo-appname for own file-attachments in vfs, this is NOT the vfs-app
var $valid_pathes = array();
var $send_file_ips = array();
/*!
@function bolink
@syntax bolink( )
@author ralfbecker
@abstract constructor
*/
function bolink( )
{
$this->solink( ); // call constructor of derived class
@ -115,26 +130,26 @@
/*!
@function link
@syntax link( $app1,$id1,$app2,$id2='',$remark='',$user=0 )
@syntax link( $app1,&$id1,$app2,$id2='',$remark='',$user=0 )
@author ralfbecker
@abstract creats a link between $app1,$id1 and $app2,$id2 - $id1 does NOT need to exist yet
@param $app1 app of $id1
@param $id1 id of item to linkto or 0 if item not yet created or array with links
of not created item or $file-array if $app1 == $this->vfs_appname (see below)
of not created item or $file-array if $app1 == $this->vfs_appname (see below).
If $id==0 it will be set on return to an array with the links for the new item.
@param $app2 app of 2.linkend or array with links ($id2 not used)
@param $id2 id of 2. item of $file-array if $app2 == $this->vfs_appname (see below)
@param $file array with informations about the file in format of the etemplate file-type
@param $file['name'] name of the file (no directory)
@param $file['type'] mine-type of the file
@param $file['tmp_name'] name of the uploaded file (incl. directory)
@param $file['path'] path of the file on the client computer
@param $file['ip'] of the client
@discussion path and ip are only needed if u want a symlink (if possible)
@param $id2 id of 2. item of $file-array if $app2 == $this->vfs_appname (see below)<br>
$file array with informations about the file in format of the etemplate file-type<br>
$file['name'] name of the file (no directory)<br>
$file['type'] mine-type of the file<br>
$file['tmp_name'] name of the uploaded file (incl. directory)<br>
$file['path'] path of the file on the client computer<br>
$file['ip'] of the client (path and ip in $file are only needed if u want a symlink (if possible))
@param $remark Remark to be saved with the link (defaults to '')
@param $owner Owner of the link (defaults to user)
@discussion Does NOT check if link already exists
@result False (for db or param-error) or link_id on success
@result if $id1==0 or already an array: $id1 is array with links
@discussion Does NOT check if link already exists.<br>
File-attachments return a negative link-id !!!
@result False (for db or param-error) or on success link_id (Please not the return-value of $id1)
*/
function link( $app1,&$id1,$app2,$id2='',$remark='',$owner=0,$lastmod=0 )
{
@ -256,7 +271,7 @@
@param $app_link_id > 0 link_id of link or app-name of link
@param $id,$app2,$id2 other param of the link if not link_id given
@result array with link-data or False
@disscussion If $id is an array (links not yet created) only link_ids are allowed.
@discussion If $id is an array (links not yet created) only link_ids are allowed.
*/
function get_link($app_link_id,$id='',$app2='',$id2='')
{
@ -291,7 +306,7 @@
@param $link_id link-id to remove if > 0
@param $app,$id,$owner,$app2,$id2 if $link_id <= 0: removes all links matching the non-empty params
@discussion Note: if $link_id != '' and $id is an array: unlink removes links from that array only
@discussion unlink has to be called with &$id so see the result !!!
unlink has to be called with &$id so see the result !!!
@result the number of links deleted
*/
function unlink($link_id,$app='',$id='',$owner='',$app2='',$id2='')
@ -325,7 +340,7 @@
@function app_list
@syntax app_list( )
@author ralfbecker
@abstrac get list/array of link-aware apps the user has rights to use
@abstract get list/array of link-aware apps the user has rights to use
@result array( $app => lang($app), ... )
*/
function app_list( )
@ -503,17 +518,17 @@
}
/*!
@function vfs_path
@syntax vfs_path ( $app,$id,$file='' )
@function attach_file
@syntax attach_file ( $app,$id,$file,$comment='' )
@abstract Put a file to the corrosponding place in the VFS and set the attributes
@param $app/$id entry which should the file should be linked with
@param $file array with informations about the file in format of the etemplate file-type
@param $file['name'] name of the file (no directory)
@param $file['type'] mine-type of the file
@param $file['tmp_name'] name of the uploaded file (incl. directory)
@param $file['path'] path of the file on the client computer
@param $file['ip'] of the client
@discussion path and ip are only needed if u want a symlink (if possible)
$file['name'] name of the file (no directory)
$file['type'] mine-type of the file
$file['tmp_name'] name of the uploaded file (incl. directory)
$file['path'] path of the file on the client computer
$file['ip'] of the client (path and ip are only needed if u want a symlink (if possible))
@param $comment
*/
function attach_file($app,$id,$file,$comment='')
{

View File

@ -13,6 +13,14 @@
/* $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-inserting
and for pgSql 7.3 compatibility
*/
class soinfolog // DB-Layer
{
var $db,$db2;
@ -20,9 +28,11 @@
var $data = array( );
var $filters = array( );
var $user;
var $maybe_slashes = array (
'info_des'=>1,'info_subject'=>1,'info_from'=>1,'info_addr'=>1
);
/*!
@function soinfolog
@abstract constructor
*/
function soinfolog( $info_id = 0)
{
$this->db = $GLOBALS['phpgw']->db;
@ -34,7 +44,14 @@
$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?
@ -65,10 +82,13 @@
return $access_ok;
}
// sql to be AND into a query to ensure ACL is respected (incl. _PRIVATE)
// filter: none|all - list all entrys user have rights to see
// private|own - list only his personal entrys
// (incl. those he is responsible for !!!)
/*!
@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 = 'none')
{
ereg('.*(own|privat|all|none).*',$filter,$vars);
@ -94,8 +114,7 @@
}
if (count($private_user_list))
{
$has_private_access = 'info_owner IN ('.
implode(',',$private_user_list).')';
$has_private_access = 'info_owner IN ('.implode(',',$private_user_list).')';
}
}
$filtermethod = " (info_owner=$this->user"; // user has all rights
@ -122,6 +141,13 @@
return $this->acl_filter[$filter] = $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 = '')
{
ereg('.*(done|open|offer).*',$filter,$vars);
@ -136,6 +162,15 @@
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
@returns the necesary sql
*/
function dateFilter($filter = '')
{
ereg('.*(upcoming|today|overdue).*',$filter,$vars);
@ -146,45 +181,56 @@
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 'upcoming':
return " AND info_startdate >= '$tomorrow'";
case 'today':
return " AND info_startdate < '$tomorrow'";
case 'overdue':
return " AND (info_enddate != 0 AND info_enddate < '$tomorrow')";
}
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' );
$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 doesnt do much anymore
*/
function db2data(&$data)
{
$data = $this->db->Record;
reset($this->maybe_slashes);
while (list($key) = each($this->maybe_slashes))
{
$data[$key] = stripslashes($data[$key]);
}
/*
$links = $this->links->get_links('infolog',$this->data['info_id']);
while (list($nul,$link) = each($links))
{
if ($link['app'] == 'addressbook')
$data['info_addr_id'] = $link['id'];
if ($link['app'] == 'projects')
$data['info_proj_id'] = $link['id'];
if ($link['app'] == 'calendar')
$data['info_event_id'] = $link['id'];
}
*/
}
/*!
@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'") || !$this->db->next_record()))
(!$this->db->query("select * FROM phpgw_infolog where info_id=$info_id",__LINE__,__FILE__) ||
!$this->db->next_record()))
{
$this->init( );
return False;
@ -196,11 +242,21 @@
return $this->data;
}
/*!
@function delete
@abstract delete InfoLog entry $info_id AND the links to it
@syntax delete( $info_id )
@param $info_id id of log-entry
*/
function delete($info_id) // did _not_ ensure ACL
{
$this->db->query("delete FROM phpgw_infolog where info_id='$info_id' or info_id_parent='"
. "$info_id' AND ((info_access='public' and info_owner != '$this->user')"
. " or (info_owner='$this->user'))" ,__LINE__,__FILE__);
if (($info_id = intval($info_id)) <= 0)
{
return;
}
$this->db->query("delete FROM phpgw_infolog where info_id=$info_id or info_id_parent=$info_id" .
"AND ((info_access='public' and info_owner != '$this->user') OR (info_owner=$this->user))",
__LINE__,__FILE__);
$this->links->unlink(0,'infolog',$info_id);
@ -210,22 +266,37 @@
}
}
/*!
@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
{
if (!$new_owner)
$owner = intval($owner);
if (!($new_owner = intval($new_owner)))
{
$sql = "delete FROM phpgw_infolog where info_owner='$owner'";
$sql2 = "update phpgw_infolog set info_responsible='0' where info_responsible='$owner'";
$sql = "delete FROM phpgw_infolog where info_owner=$owner";
$sql2 = "update phpgw_infolog set info_responsible=0 where info_responsible=$owner";
}
else
{
$sql = "update phpgw_infolog set info_owner='$new_owner' where info_owner='$owner'";
$sql2 = "update phpgw_infolog set info_responsible='$new_owner' where info_responsible='$owner'";
$sql = "update phpgw_infolog set info_owner=$new_owner where info_owner=$owner";
$sql2 = "update phpgw_infolog set info_responsible=$new_owner where info_responsible=$owner";
}
$this->db->query($sql,__LINE__,__FILE__);
$this->db->query($sql2,__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
@returns nothing direct, but the info_id gets
*/
function write($values) // did _not_ ensure ACL
{
include(PHPGW_SERVER_ROOT.'/infolog/setup/tables_current.inc.php');
@ -242,18 +313,23 @@
}
$this->data[$key] = $val; // update internal data
if ($this->maybe_slashes[$key])
switch($val['type']) // protection against query-insertion
{
$val = addslashes($val);
case 'int': case 'auto':
$val = intval($val);
break;
default:
$val = "'".$this->db->db_addslashes($val)."'";
break;
}
$cols .= ($cols ? ',' : '').$key;
$vals .= ($vals ? ',' : '')."'$val'";
$query .= ($query ? ',' : '')."$key='$val'";
$vals .= ($vals ? ',' : '').$val;
$query .= ($query ? ',' : '')."$key=$val";
}
}
if (($this->data['info_id'] = $values['info_id']) > 0)
if (($this->data['info_id'] = intval($values['info_id'])) > 0)
{
$query = "UPDATE phpgw_infolog SET $query where info_id='".$values['info_id']."'";
$query = "UPDATE phpgw_infolog SET $query where info_id='".$this->data['info_id']."'";
$this->db->query($query,__LINE__,__FILE__);
}
else
@ -264,31 +340,44 @@
}
// echo "<p>soinfolog.write values= "; _debug_array($values);
// echo "<p>soinfolog.write this->data= "; _debug_array($this->data);
/*
if ($this->data['info_addr_id'])
$this->links->link('infolog',$this->data['info_id'],'addressbook',$this->data['info_addr_id']);
if ($this->data['info_proj_id'])
$this->links->link('infolog',$this->data['info_id'],'projects',$this->data['info_proj_id']);
if ($this->data['info_event_id'])
$this->links->link('infolog',$this->data['info_id'],'calendar',$this->data['info_event_id']); */
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 <= 0)
if (($info_id = intval($info_id)) <= 0)
{
return 0;
}
$this->db->query('select count(*) FROM phpgw_infolog where '.
"info_id_parent=$info_id",__LINE__,__FILE__);
$this->db->query("select count(*) FROM phpgw_infolog where info_id_parent=$info_id",__LINE__,__FILE__);
$this->db->next_record();
return $this->db->f(0);
}
function search($order,$sort,$filter,$cat_id,$query,$action,$action_id,
$ordermethod,&$start,&$total)
/*!
@function search
@abstract searches InfoLog for a certain pattern in $query
@syntax search( $order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,&$start,&$total )
@param $order comma-separated list of columns to order the result (no 'ORDER BY'), eg. 'info_subject DESC'
@param $sort comma-separated list of columns to to sort by (incl. 'SORT BY') or ''
@param $filter string with combination of acl-, date- and status-filters, eg. 'own-open-today' or ''
@param $cat_id category to use or 0
@param $query pattern to search, search is done in info_from, info_subject and info_des
@param $action / $action_id if only entries linked to a specified app/entry show be used
@param &$start, &$total nextmatch-parameters will be used and set if query returns less entries
@returns array with id's as key of the matching log-entries
*/
function search($order,$sort,$filter,$cat_id,$query,$action,$action_id,$ordermethod,&$start,&$total)
{
//echo "<p>soinfolog.search(action='$action/$action_id')</p>\n";
$action2app = array(
@ -311,7 +400,7 @@
}
if ($order)
{
$ordermethod = 'ORDER BY ' . $order . ' ' . $sort;
$ordermethod = 'ORDER BY ' . $this->db->db_addslashes($order) . ' ' . $this->db->db_addslashes($sort);
}
else
{
@ -322,12 +411,13 @@
$filtermethod .= $this->dateFilter($filter);
// echo "<p>filtermethod='$filtermethod'</p>";
if ($cat_id)
if (intval($cat_id))
{
$filtermethod .= " AND info_cat='$cat_id' ";
$filtermethod .= ' AND info_cat='.intval($cat_id).' ';
}
if ($query) // we search in _from, _subject and _des for $query
{
$query = $this->db->db_addslashes($query);
$sql_query = "AND (info_from like '%$query%' OR info_subject ".
"LIKE '%$query%' OR info_des LIKE '%$query%') ";
}

View File

@ -16,11 +16,14 @@
/*!
@class solink
@author ralfbecker
@copyright GPL - GNU General Public License
@abstract generalized linking between entries of phpGroupware apps - DB layer
@discussion This class is to access the links in the DB
@discussion Links have to ends each pointing two an entry, each entry is a double:
@discussion app app-name or directory-name of an phpgw application, eg. 'infolog'
@discussion id this is the id, eg. an integer or a tupple like '0:INBOX:1234'
@discussion This class is to access the links in the DB<br>
Links have to ends each pointing two an entry, each entry is a double:<br>
app app-name or directory-name of an phpgw application, eg. 'infolog'<br>
id this is the id, eg. an integer or a tupple like '0:INBOX:1234'
@note All vars passed to this class are run either through addslashes or intval
to prevent query insertion and to get pgSql 7.3 compatibility.
*/
class solink // DB-Layer
{
@ -70,7 +73,7 @@
{
return False; // dont link to self or other nosense
}
if ($this->get_link($app1,$id1,$app2,$id2))
if ($link = $this->get_link($app1,$id1,$app2,$id2))
{
return $link['link_id']; // link alread exist
}
@ -78,13 +81,17 @@
{
$owner = $this->user;
}
$remark = $this->db->db_addslashes($remark);
$vars2addslashes = array('app1','id1','app2','id2','remark');
foreach ($vars2addslashes as $var)
{
$$var = $this->db->db_addslashes($$var);
}
if (!$lastmod)
{
$lastmod = time();
}
$sql = "INSERT INTO $this->db_name (link_app1,link_id1,link_app2,link_id2,link_remark,link_lastmod,link_owner) ".
" VALUES ('$app1','$id1','$app2','$id2','$remark',$lastmod,$owner)";
" VALUES ('$app1','$id1','$app2','$id2','$remark',".intval($lastmod).','.intval($owner).')';
if ($this->debug)
{
@ -108,6 +115,11 @@
{
$links = array();
$vars2addslashes = array('app','id','only_app','order');
foreach ($vars2addslashes as $var)
{
$$var = $this->db->db_addslashes($$var);
}
$sql = "SELECT * FROM $this->db_name".
" WHERE (link_app1 = '$app' AND link_id1 = '$id')".
" OR (link_app2 = '$app' AND link_id2 = '$id')".
@ -131,14 +143,14 @@
{
$link = array(
'app' => $row['link_app2'],
'id' => stripslashes($row['link_id2'])
'id' => $row['link_id2']
);
}
else
{
$link = array(
'app' => $row['link_app1'],
'id' => stripslashes($row['link_id1'])
'id' => $row['link_id1']
);
}
if ($only_app && $not_only == ($link['app'] == $only_app) ||
@ -146,7 +158,7 @@
{
continue;
}
$link['remark'] = stripslashes($row['link_remark']);
$link['remark'] = $row['link_remark'];
$link['owner'] = $row['link_owner'];
$link['lastmod'] = $row['link_lastmod'];
$link['link_id'] = $row['link_id'];
@ -174,7 +186,7 @@
$sql = "SELECT * FROM $this->db_name WHERE ";
if (intval($app_link_id) > 0)
{
$sql .= "link_id=$app_link_id";
$sql .= 'link_id='.intval($app_link_id);
}
else
{
@ -182,6 +194,11 @@
{
return False;
}
$vars2addslashes = array('app_link_id','id','app2','id2');
foreach ($vars2addslashes as $var)
{
$$var = $this->db->db_addslashes($$var);
}
$sql .= "(link_app1='$app_link_id' AND link_id1='$id' AND link_app2='$app2' AND link_id2='$id2') OR".
"(link_app2='$app_link_id' AND link_id2='$id' AND link_app1='$app2' AND link_id1='$id2')";
}
@ -210,9 +227,9 @@
function unlink($link_id,$app='',$id='',$owner='',$app2='',$id2='')
{
$sql = "DELETE FROM $this->db_name WHERE ";
if ($link_id > 0)
if (intval($link_id) > 0)
{
$sql .= "link_id=$link_id";
$sql .= 'link_id='.intval($link_id);
}
elseif ($app == '' AND $owner == '')
{
@ -220,6 +237,11 @@
}
else
{
$vars2addslashes = array('app','id','app2','id2');
foreach ($vars2addslashes as $var)
{
$$var = $this->db->db_addslashes($$var);
}
if ($app != '' && $app2 == '')
{
$sql .= "((link_app1='$app'";
@ -238,7 +260,7 @@
}
if ($owner != '')
{
$sql .= ($app != '' ? ' AND ' : '') . "link_owner='$owner'";
$sql .= ($app != '' ? ' AND ' : '') . 'link_owner='.intval($owner);
}
}
if ($this->debug)
@ -261,11 +283,11 @@
*/
function chown($owner,$new_owner)
{
if ($owner <= 0 || $new_owner <= 0)
if (intval($owner) <= 0 || intval($new_owner) <= 0)
{
return 0;
}
$this->db->query("UPDATE $this->db_name SET owner=$new_owner WHERE owner=$owner",__LINE__,__FILE__);
$this->db->query("UPDATE $this->db_name SET owner=".intval($new_owner).' WHERE owner='.intval($owner),__LINE__,__FILE__);
return $this->db->affected_rows();
}