PageRenderTime 61ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/class.xuser.inc

https://github.com/jcplat/console-seolan
PHP | 894 lines | 749 code | 62 blank | 83 comment | 202 complexity | f98181b0bfa2b3006a46cdcdf1d89dba MD5 | raw file
Possible License(s): LGPL-2.0, LGPL-2.1, GPL-3.0, Apache-2.0, BSD-3-Clause
  1. <?php
  2. /// classe representant un utilisateur authentifie
  3. class XUser {
  4. const DB_SESSION_CACHE_PREFIX='cache::';
  5. public $table='USERS';
  6. public $_cur=NULL;
  7. public $_curoid=NULL;
  8. public $_debug=false;
  9. public $admin=false;
  10. static $_cacheml=array();
  11. static $_C81=array();
  12. static $_C82=array();
  13. static $_C8OID = array();
  14. static $_C8OIDS = array();
  15. static $_cache_sGroup=array();
  16. static $_cache_listObjectAccess=array();
  17. // creation d'un utilisateur ou d'un object utilisateur a partir d'un alias, d'un uid, d'un ar avec UID
  18. function __construct($ar=NULL) {
  19. if(is_string($ar)) {
  20. if(Kernel::isAKoid($ar)) $this->_curoid=$ar;
  21. else {
  22. $uid=selectQueryGetOne('SELECT KOID FROM USERS WHERE alias="'.$ar.'" LIMIT 1');
  23. if(!empty($uid)) $this->_curoid=$uid['KOID'];
  24. }
  25. }
  26. if(empty($this->_curoid)) {
  27. $p = new XParam($ar, array('UID'=>TZR_USERID_NOBODY));
  28. $this->_curoid=$p->get('UID');
  29. }
  30. if($this->_curoid!=TZR_USERID_NOBODY) $this->load();
  31. else{
  32. $this->_cur['ldata']='';
  33. $this->_cur['luser']='';
  34. }
  35. }
  36. static function clearCache() {
  37. XUser::$_cacheml = array();
  38. XUser::$_C81 = array();
  39. XUser::$_C82 = array();
  40. XUser::$_cache_sGroup = array();
  41. XUser::$_cache_listObjectAccess=array();
  42. XUser::clearDbSessionDataAndRightCache();
  43. }
  44. static public function authentified() {
  45. $uid=getSessionVar('UID');
  46. if(!empty($uid) && ($uid!='USERS:0')) return true;
  47. return false;
  48. }
  49. static function get_current_user_uid() {
  50. $uid= getSessionVar('UID');
  51. if(empty($uid)) $uid=TZR_USERID_NOBODY;
  52. return $uid;
  53. }
  54. static function isNobody() {
  55. $uid= getSessionVar('UID');
  56. if(empty($uid)) return true;
  57. if($uid==TZR_USERID_NOBODY) return true;
  58. return false;
  59. }
  60. public static function &get_user() {
  61. return $GLOBALS['XUSER'];
  62. }
  63. function uid() {
  64. return $this->_curoid;
  65. }
  66. function isRoot() { return(!empty($this->_cur['grp']) && in_array(TZR_GROUPID_ROOT,$this->_cur['grp'])); }
  67. /// rend le nom en clair de l'utilisateur authentifie
  68. function fullname() {
  69. return $this->_cur['fullnam'];
  70. }
  71. /// rend le home du backoffice de l'utilisateur
  72. function bohome() {
  73. if(!empty($this->_cur['bohome']) && Kernel::objectExists($this->_cur['bohome']))
  74. return $this->_cur['bohome'];
  75. else
  76. return 'home';
  77. }
  78. /// rend le top du menu backoffice de l'utilisateur
  79. function botop() {
  80. if(!empty($this->_cur['bohome']) && Kernel::objectExists($this->_cur['bohome']))
  81. return $this->_cur['bohome'];
  82. else
  83. return 'top';
  84. }
  85. /// rend l'email en clair de l'utilisateur authentifie
  86. function email() {
  87. return $this->_cur['email'];
  88. }
  89. /// rend la date de derniere connexion en clair de l'utilisateur authentifie
  90. function lastconnection() {
  91. return $this->_cur['lastcon'];
  92. }
  93. function language($ar=NULL) {
  94. return array(@$this->_cur['ldata'],@$this->_cur['luser']);
  95. }
  96. function load() {
  97. $this->_cur = selectQuery('SELECT * FROM '.$this->table .' WHERE KOID="'.$this->_curoid.'"')->fetch(PDO::FETCH_ASSOC);
  98. $this->_cur['grp'] = explode('||', $this->_cur['GRP']);
  99. if(empty($this->_cur['luser']))
  100. $this->_cur['luser'] = TZR_DEFAULT_LANG;
  101. if(XShell::admini_mode() && !XUser::isNobody()) {
  102. if(!in_array(TZR_GROUPID_AUTH,$this->_cur['grp']))
  103. $this->_cur['grp'][]=TZR_GROUPID_AUTH;
  104. }
  105. elseif(!in_array(TZR_GROUPID_NOBODY,$this->_cur['grp']))
  106. $this->_cur['grp'][]=TZR_GROUPID_NOBODY;
  107. }
  108. function getUserList($myselfIncluded = true) {
  109. $LANG_USER = XShell::getLangUser();
  110. $liste = array();
  111. $cond='';
  112. if ( !$myselfIncluded ) {
  113. $cond.=' KOID != "'.$this->_curoid.'" ';
  114. }
  115. $requete = 'select * from USERS '.$cond.' order by fullnam';
  116. $rs=selectQuery($requete);
  117. $liste=array();
  118. $ors=array();
  119. while($rs && ($ors=$rs->fetch())) {
  120. $fullnam=$ors['fullnam'];
  121. $alias=$ors['alias'];
  122. $liste[$ors['KOID']]="$fullnam [$alias]";
  123. }
  124. return $liste;
  125. }
  126. function groups($refresh=false) {
  127. if(!$refresh && !empty($this->_cur['groups'])) return $this->_cur['groups'];
  128. $limits=array();
  129. $limits['USERS']=array('GRP');
  130. $limits['GRP']=array('GRPS');
  131. $g1=Kernel::followLinks(array($this->_curoid),$limits);
  132. // Si l'utilisateur est authentifié, il fait parti du groupe "Utilisateurs authentifié" automatiquement
  133. if(!XUser::isNobody() && !in_array(TZR_GROUPID_AUTH, $g1)) $g1[]=TZR_GROUPID_AUTH;
  134. // Si l'utilisateur fait parti du groupe "Utilisateurs authentifiés", il ne fera pas parti du groupe "Tout le monde"
  135. if(!in_array(TZR_GROUPID_AUTH, $g1) && !in_array(TZR_GROUPID_NOBODY, $g1)) $g1[]=TZR_GROUPID_NOBODY;
  136. $this->_cur['groups']=$g1;
  137. return $g1;
  138. }
  139. static function sGroups($uoid) {
  140. if(!is_array($uoid)) $uoid=array($uoid);
  141. $idx=implode('-',$uoid);
  142. if(empty(XUser::$_cache_sGroup[$idx])){
  143. $limits=array();
  144. $limits['USERS']=array('GRP');
  145. $limits['GRP']=array('GRPS');
  146. $g1=Kernel::followLinks($uoid,$limits);
  147. if(!XUser::isNobody() && !in_array(TZR_GROUPID_AUTH, $g1)) $g1[]=TZR_GROUPID_AUTH;
  148. if(!in_array(TZR_GROUPID_AUTH, $g1) && !in_array(TZR_GROUPID_NOBODY, $g1)) $g1[]=TZR_GROUPID_NOBODY;
  149. XUser::$_cache_sGroup[$idx]=array_unique($g1);
  150. }
  151. return XUser::$_cache_sGroup[$idx];
  152. }
  153. // Rend vrai si l'utiliser uid est dans les groupes $grps (attention si $parents==true, en ajoute dans grps les groupes parents et surtout GRP:0 ou GRP:2 selon si authentifié ou pas)
  154. function inGroups($grps,$parents=true) {
  155. if(!is_array($grps)) $grps=array($grps);
  156. $mygroups = $this->groups();
  157. if($parents) $otgroups = XUser::sGroups($grps);
  158. else $otgroups = $grps;
  159. $r1=array_intersect($mygroups, $otgroups);
  160. if(empty($r1)) {
  161. return false;
  162. }
  163. return true;
  164. }
  165. /// Compare 2 niveaux de sécurité pour une classe donnée
  166. static public function compareSecLevels($class,$lvl1,$lvl2,$op){
  167. if(is_numeric($class)){
  168. $mod=XModule::objectFactory($class);
  169. $class=get_class($mod);
  170. }
  171. $secs=call_user_func(array($class,'secList'),NULL);
  172. $res1=array_search($lvl1,$secs);
  173. $res2=array_search($lvl2,$secs);
  174. return eval('return '.$res1.$op.$res2.';');
  175. }
  176. /// Vérifie si l'utilisateur courant peut attribuer un droit spécifique à un objet
  177. static public function isAuthorizedToSetAccess($class,$moid,$lang,$oid,$lvl){
  178. if($lvl=='default') return true;
  179. $actlvl=XUser::secure8maxlevel($moid,$oid,null,$lang);
  180. return XUser::compareSecLevels($moid,$lvl,$actlvl,'<=');
  181. }
  182. /// Positionnement du niveau d'accés dans la base de donnéees
  183. public function setUserAccess($class,$moid,$lang,$oid,$level,$uoid=NULL,$cache=false,$force=true,$comment='') {
  184. if(empty($uoid)) $uoid=$this->_curoid;
  185. if(!$force && !$cache && !XShell::isRoot()){
  186. if(!XUser::isAuthorizedToSetAccess($class,$moid,$lang,$oid,$level)) return false;
  187. }
  188. $table=($cache?'ACL4_CACHE':'ACL4');
  189. $aoid=substr(md5(uniqid('')),0,40);
  190. if(!empty($moid)) {
  191. $q='DELETE FROM '.$table.' where AMOID="'.$moid.'" and ALANG="'.$lang.'" and AKOID="'.$oid.'" and AGRP="'.$uoid.'"';
  192. $q2='INSERT INTO '.$table.'(AOID,UPD,AGRP,AFUNCTION,ALANG,AMOID,AKOID,OK,ACOMMENT) '.
  193. 'values ("'.$aoid.'",NULL,"'.$uoid.'","'.$level.'","'.$lang.'","'.$moid.'","'.$oid.'",1,"'.$comment.'")';
  194. $q3='DELETE FROM ACL4_CACHE where AMOID="'.$moid.'" and ALANG="'.$lang.'"';
  195. if(!$cache) XLogs::update('security', $uoid, 'Delete security rules for moid='.$moid.' oid='.$oid.' user='.$uoid.' lang='.$lang);
  196. } else {
  197. $q='DELETE FROM '.$table.' where ACLASS="'.$class.'" and ALANG="'.$lang.'" and AKOID="'.$oid.'" and AGRP="'.$uoid.'"';
  198. $q2='INSERT INTO '.$table.'(AOID,UPD,AGRP,AFUNCTION,ACLASS,ALANG,AKOID,OK,ACOMMENT) '.
  199. 'values ("'.$aoid.'",NULL,"'.$uoid.'","'.$level.'","'.$class.'","'.$lang.'","'.$oid.'",1,"")';
  200. $q3='DELETE FROM ACL4_CACHE where ACLASS="'.$class.'" and ALANG="'.$lang.'"';
  201. if(!$cache) XLogs::update('security', $uoid, 'Delete security rules for class='.$class.' oid='.$oid.' user='.$uoid.' lang='.$lang);
  202. }
  203. if($lang=='all'){
  204. $q=str_replace('and ALANG="all"','',$q);
  205. $q3=str_replace('and ALANG="all"','',$q3);
  206. }
  207. // On efface d'eventuels drois deja presents
  208. updateQuery($q);
  209. // On efface le cache du module
  210. if(!$cache) updateQuery($q3);
  211. if($level!='default') {
  212. if($lang=='all'){
  213. foreach($GLOBALS['TZR_LANGUAGES'] as $lg=>$locale){
  214. updateQuery(str_replace('"all"','"'.$lg.'"',$q2));
  215. $this->_cacheml[$class.$moid.$lg.$uoid.$oid]=$level;
  216. }
  217. }else{
  218. updateQuery($q2);
  219. $this->_cacheml[$class.$moid.$lang.$uoid.$oid]=$level;
  220. }
  221. if(!$cache) XLogs::update('security', $uoid, "New security rules for '$uoid',1,'$level','$class','$lang','$moid','$oid',1");
  222. }else{
  223. unset($this->_cacheml[$class.$moid.$lang.$uoid.$oid]);
  224. }
  225. return true;
  226. }
  227. /// Copie des acces sur un oid vers un autre oid
  228. public function copyUserAccess($oidsrc, $oiddst, $moid) {
  229. $rs=selectQuery('select * FROM ACL4 where AMOID="'.$moid.'" and AKOID="'.$oidsrc.'"');
  230. while($ors=$rs->fetch()) {
  231. // on verifie que l'acl n'existe pas
  232. $n=countSelectQuery('select count(*) from ACL4 where AGRP="'.$ors['AGRP'].'" and AFUNCTION="'.$ors['AFUNCTION'].'" and ACLASS="'.$ors['ACLASS'].'" '.
  233. 'and ALANG="'.$ors['ALANG'].'" and AMOID="'.$ors['AMOID'].'" and AKOID="'.$oiddst.'" and OK="'.$ors['OK'].'"');
  234. if(!$n){
  235. $aoid=substr(md5(uniqid("")),0,40);
  236. updateQuery('INSERT INTO ACL4(AOID,AGRP,AFUNCTION,ACLASS,ALANG,AMOID,AKOID,OK) values ("'.
  237. $aoid.'","'.$ors['AGRP'].'","'.$ors['AFUNCTION'].'","'.$ors['ACLASS'].'","'.$ors['ALANG'].
  238. '","'.$ors['AMOID'].'","'.$oiddst.'","'.$ors['OK'].'")');
  239. }
  240. }
  241. $rs->closeCursor();
  242. XLogs::update('security',$oiddst,'Copy security rules from '.$oidsrc.' to '.$oiddst.' on '.$moid);
  243. }
  244. /// Copie tous les droits d'un utilisateur/groupe vers un autre
  245. function copyAllUserAccess($suid,$duid){
  246. $rs=selectQuery('select * FROM ACL4 where AGRP="'.$suid.'"');
  247. while($ors=$rs->fetch()) {
  248. $aoid=md5(uniqid(''));
  249. updateQuery('INSERT INTO ACL4(AOID,AGRP,AFUNCTION,ACLASS,ALANG,AMOID,AKOID,OK) values ("'.$aoid.'","'.$duid.'","'.$ors['AFUNCTION'].'",'.
  250. '"'.$ors['ACLASS'].'","'.$ors['ALANG'].'","'.$ors['AMOID'].'","'.$ors['AKOID'].'","'.$ors['OK'].'")');
  251. }
  252. $rs->closeCursor();
  253. XLogs::update('security',$duid,'Copy all security rules from '.$suid);
  254. }
  255. /// Effaccement des droits correspondant a un module, une langue, un oid, des utilisateurs donnes
  256. public function clearUserAccess($class, $moid, $lang, $oid, $uoid=NULL) {
  257. if(!empty($uoid)) $AGRP=' and AGRP="'.$uoid.'"';
  258. else $AGRP='';
  259. updateQuery('DELETE FROM ACL4 where ACLASS="'.$class.'" and AMOID="'.$moid.'" and ALANG="'.$lang.'" and AKOID="'.$oid.'"'.$AGRP);
  260. XLogs::update('security',$oid,'Clear security rules for '.$class.','.$moid.','.$lang.','.$oid.' on '.$AGRP);
  261. }
  262. /// Rend la liste des droits pour un moid/oid
  263. public function getObjectAccess($mod, $lang, $oid=NULL, $grp=NULL) {
  264. if(!$mod) return array();
  265. if(is_numeric($mod)) $mod=XModule::objectFactory($mod);
  266. if(!$mod) return array(array(),array());
  267. $seclistfull = $seclist = $mod->secList();
  268. $level=self::secure8maxlevel($mod,$oid,$grp,$lang);
  269. $cnt=count($seclist);
  270. $i=$cnt-1;
  271. while($i>=0) {
  272. if(!($level==$seclist[$i])) {
  273. unset($seclist[$i]);
  274. $i--;
  275. } else break;
  276. }
  277. if(count($seclist)<=0) $seclist=array("none");
  278. return array($seclist,$seclistfull);
  279. }
  280. /// Alias de getObjectAccess
  281. public function getUserAccess($class, $moid, $lang=NULL, $oid=NULL, $grp=NULL) {
  282. return $this->getObjectAccess($moid, $lang, $oid, $grp);
  283. }
  284. /// recherche des acces pour tous les utilsiateurs sur module donne. si $oid, alors sur objet
  285. static function getModuleAccess(XModule &$mod,$all=true) {
  286. global $TZR_LANGUAGES;
  287. list($users, $groups) = XUser::getUsersAndGroups(true,$all);
  288. $x1=self::get_user();
  289. foreach($users['lines_oid'] as $i=>$uoid) {
  290. $users['lines_nsec'][$i]=count($users['lines_sec'][$i][TZR_DEFAULT_LANG][0]);
  291. $users['lines_sec'][$i]=array();
  292. foreach($TZR_LANGUAGES as $lang=>$v){
  293. $users['lines_sec'][$i][$lang]=$x1->getUserAccess(get_class($mod), $mod->_moid, $lang, NULL, $uoid);
  294. }
  295. }
  296. foreach($groups['lines_oid'] as $i=>$uoid) {
  297. $groups['lines_nsec'][$i]=count($groups['lines_sec'][$i][TZR_DEFAULT_LANG][0]);
  298. $groups['lines_sec'][$i]=array();
  299. foreach($TZR_LANGUAGES as $lang=>$v){
  300. $groups['lines_sec'][$i][$lang]=$x1->getUserAccess(get_class($mod), $mod->_moid, $lang, NULL, $uoid);
  301. }
  302. }
  303. return array($users, $groups);
  304. }
  305. public function getObjectsAccess($mod, $lang, &$oids) {
  306. $l=$this->getObjectAccess($mod, $lang);
  307. $l=array_flip($l[0]);
  308. if(empty($mod->object_sec)) {
  309. $levs = array();
  310. foreach($oids as $i => $oid) {
  311. $levs[$i]=$l;
  312. }
  313. } else {
  314. $hasrules=XUser::getObjectsWithSec($mod,XUser::get_current_user_uid());
  315. $hasrules=array_flip($hasrules);
  316. $levs = array();
  317. foreach($oids as $i => $oid) {
  318. if(array_key_exists($oid,$hasrules)){
  319. $l2 = $this->getObjectAccess($mod, $lang, $oid);
  320. $l2=array_flip($l2[0]);
  321. $levs[$i]=$l2;
  322. }else{
  323. $levs[$i]=$l;
  324. }
  325. }
  326. }
  327. return $levs;
  328. }
  329. /// Pour un user/group donné, retourne les oids pour lesquels des droits spécifique ont été posé
  330. static function &getObjectsWithSec($mod,$uid){
  331. $uids=XUser::sGroups($uid);
  332. $hasrules=selectQueryGetColumn('(select AKOID from ACL4 where AGRP in ("'.implode('","',$uids).'") and AMOID="'.$mod->_moid.'" and AKOID!="" AND AKOID NOT LIKE "_field%") UNION DISTINCT '.
  333. '(select AKOID from ACL4_CACHE where AGRP in ("'.implode('","',$uids).'") and AMOID="'.$mod->_moid.'" and AKOID!="" and ACOMMENT="'.XSession::CS8_EMPTY_CHECK.'")');
  334. return $hasrules;
  335. }
  336. public function listObjectAccess(XModule &$mod, $lang, $oid, $details=false) {
  337. $lang_cond="";
  338. if(!empty($lang)) $lang_cond = "and ALANG='$lang'";
  339. $rs=selectQuery("select * from ACL4 where AMOID='".$mod->_moid."' ".$lang_cond." and AKOID='$oid' order by AGRP,ALANG");
  340. $r=array();
  341. $k = new Kernel();
  342. $ors=array();
  343. while( $ors=$rs->fetch()) {
  344. if($details) {
  345. $d1=&XUser::$_cache_listObjectAccess[$ors['AGRP']];
  346. if(!$d1) $d1=XDataSource::objectDisplayHelper($ors['AGRP']);
  347. if(is_array($d1)) {
  348. if($d1['ofullnam']->raw) $names[]='B-'.$d1['ofullnam']->raw;
  349. else $names[]='A-'.$d1['oGRP']->raw;
  350. $r['acl_uid'][]=$ors['AGRP'];
  351. $r['acl_own'][]=$d1;
  352. $r['acl_level'][]=$ors['AFUNCTION'];
  353. $r['acl_lang'][]=$ors['ALANG'];
  354. $r['acl_longlevel'][]=XLabels::getSysLabel('security',$ors['AFUNCTION']);
  355. } else {
  356. updateQuery('delete from ACL4 where AGRP = "'.$ors['AGRP'].'"');
  357. }
  358. } else $r['acl_uid'][]=$ors['AGRP'];
  359. }
  360. if($details) array_multisort($names,$r['acl_uid'],$r['acl_own'],$r['acl_level'],$r['acl_lang'],$r['acl_longlevel']);
  361. $r["oid"]=$oid;
  362. if(XShell::admini_mode() && ($lang==TZR_DEFAULT_LANG)) {
  363. if(!$oid){
  364. $r['title']=XLabels::getSysLabel('general','module','text').' '.$mod->modulename;
  365. }elseif((substr($oid,0,7)!='_field-') && Kernel::objectExists($oid)){
  366. $otab=XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS='.$oid);
  367. $ro = $otab->display(array("_publishedonly"=>true,"tplentry"=>TZR_RETURN_DATA,"oid"=>$oid, '_archive'=>''));
  368. $r["title"]=$ro['link'];
  369. }else{
  370. $r['title']=$mod->xset->desc[substr($oid,7)]->label;
  371. }
  372. }
  373. $r["lang"]=$lang;
  374. $r["moid"]=$mod->_moid;
  375. $r["classname"]=get_class($mod);
  376. return $r;
  377. }
  378. public function editObjectAccess(XModule &$mod, $lang, $oid) {
  379. $rs=selectQuery("select * from ACL4 where AMOID='".$mod->_moid."' and ALANG='$lang' and AKOID='$oid'");
  380. $r=array();
  381. $k = new Kernel();
  382. $ls = $this->getObjectAccess($mod,$lang,$oid);
  383. $ors=array();
  384. while( $ors=$rs->fetch()) {
  385. $d1=$k->data_display(array("tplentry"=>TZR_RETURN_DATA, "oid"=>$ors['AGRP'],
  386. '_options'=>array('error'=>'return')));
  387. if(is_array($d1)) {
  388. $r['acl_uid'][]=$ors['AGRP'];
  389. $r['acl_own'][]=$d1;
  390. $r['acl_level'][]=$ors['AFUNCTION'];
  391. $r['acl_longlevel'][]=XLabels::getSysLabel('security',$ors['AFUNCTION']);
  392. } else {
  393. updateQuery('delete from ACL4 where AGRP = "'.$ors['AGRP'].'"');
  394. }
  395. }
  396. $rs->closeCursor();
  397. return $r;
  398. }
  399. /// envoi d'un mail a  l'utilisateur, ou a $mail si $mail est renseigné
  400. /// $mail peut etre : une adresse, un tableau d'adresses, un tableau de la forme (mail=>mail,name=>nom), un tableau de tableau mail/nom
  401. public function sendMail2User($subject,$message,$email=NULL,$from=NULL,$archive=true,$filename=NULL,$filetitle=NULL,$stringattachment=NULL,$mime=NULL,$params=array()) {
  402. if(!XUser::isNobody() && empty($email)) {
  403. $rs=selectQuery('select * from USERS where KOID="'.$this->_curoid.'"');
  404. if($rs && $ors=$rs->fetch()) {
  405. $email = $ors['email'];
  406. }
  407. }
  408. if(empty($email)) return;
  409. if(empty($from)) $from=TZR_SENDER_ADDRESS;
  410. $xmail=new XMail();
  411. $xmail->setTZRSubject($subject);
  412. $xmail->logActive=$archive;
  413. @$xmail->_modid=$params['moid'];
  414. @$xmail->_mtype=$params['mtype'];
  415. if(is_array($from)){
  416. $xmail->From=$from[0];
  417. $xmail->FromName=$from[1];
  418. }else{
  419. $xmail->From=$from;
  420. $xmail->FromName="";
  421. }
  422. if(preg_match("/(^<html>)/",$message)) {
  423. $xmail->IsHTML(true);
  424. if(!empty($params['sign'])) $xmail->setTZRBody($message);
  425. else $xmail->Body=$message;
  426. } else {
  427. $xmail->IsHTML(false);
  428. if(!array_key_exists('sign',$params) || !empty($params['sign'])) $xmail->setTZRBody(wordwrap($message, 65));
  429. else $xmail->Body=wordwrap($message, 65);
  430. }
  431. if(!empty($filename)){
  432. if(!is_array($filename)) $filename=array($filename);
  433. if(!is_array($filetitle)) $filetitle=array($filetitle);
  434. foreach($filename as $i=>$fn){
  435. $xmail->AddAttachment($filename[$i], $filetitle[$i]);
  436. }
  437. }
  438. if(!empty($stringattachment)) $xmail->AddStringAttachment($stringattachment, $filetitle, "base64", $mime);
  439. if(!is_array($email)) $email=array($email);
  440. elseif(array_key_exists('mail',$email)) $email=array($email);
  441. foreach($email as $i=>$mail){
  442. $xmail->ClearAllRecipients();
  443. if(is_array($mail)) $xmail->AddAddress($mail['mail'],$mail['name']);
  444. else $xmail->AddAddress($mail);
  445. $xmail->Send();
  446. if($archive) XLogs::update("mail sent", '',"To: $mail\nSubject: $subject\n".$xmail->Body);
  447. }
  448. }
  449. // creation d'un nouvel utilisateur
  450. // fonction non autorisée depuis internet
  451. //
  452. function newUser($ar=NULL) {
  453. $p = new XParam($ar,array());
  454. $tplentry=$p->get("tplentry");
  455. $login = $p->get("login");
  456. $passwd = $p->get("passwd");
  457. $thenlog = $p->get("_thenlog");
  458. $login=preg_replace('/([^[A-Za-z0-9]]+)/','',$login);
  459. $status=false;
  460. if(empty($login) && ($login!="root")) {
  461. $message=XLabels::getSysLabel("xmoduser.aliasnotaccepted");
  462. } else {
  463. $cnt=countSelectQuery("select COUNT(*) from USERS where alias='$login'");
  464. if($cnt>0) {
  465. $status=false;
  466. $message=XLabels::getSysLabel("xmoduser.existing_user");
  467. } else {
  468. $xuser=XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS='.'USERS');
  469. $ar["alias"]=$login;
  470. $ar["passwd"]=$passwd;
  471. $ar["GRP"]=$p->get("GRP","local");
  472. $xuser->procInput($ar);
  473. if($thenlog) {
  474. $xsession=new XSession();
  475. $xsession->procAuth(array("login"=>$login, "password"=>$passwd));
  476. $status=true;
  477. }
  478. }
  479. }
  480. $r=array("status"=>$status, "message"=>$message);
  481. if($tplentry==TZR_RETURN_DATA) {
  482. return $r;
  483. }
  484. return XShell::toScreen1($tplentry, $r);
  485. }
  486. function &getUserName($user) {
  487. static $names=array();
  488. if(!empty($names[$user])) return $names[$user];
  489. $rs=selectQuery("SELECT * FROM USERS WHERE KOID='$user'");
  490. if($ors=$rs->fetch()) {
  491. $names[$user]=array(1=>$ors['fullnam'],2=>$user);
  492. } else {
  493. $names[$user]=array(1=>'',2=>'');
  494. }
  495. $rs->closeCursor();
  496. return $names[$user];
  497. }
  498. /// recherche de la liste des utilisateurs et groupes
  499. static function &getUsersAndGroups($valid=false,$all=true,$directory=NULL) {
  500. if(empty($directory)) {
  501. $xuser = XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS=USERS');
  502. $cond=array();
  503. if(!$all || $all==='groups') $cond['GRP']=array('!=','');
  504. if($valid){
  505. if($xuser->fieldExists('DATEF') && $xuser->fieldExists('DATET')) {
  506. $cond['DATET']=array('>=',date('Y-m-d'));
  507. $cond['DATEF']=array('<=',date('Y-m-d'));
  508. }
  509. if($xuser->fieldExists('PUBLISH')) {
  510. $cond['PUBLISH']=array('=',1);
  511. }
  512. }
  513. $select=(!empty($cond)?$xuser->select_query(array('cond'=>$cond)):'');;
  514. $acl_user=$xuser->browse(array('tplentry'=>TZR_RETURN_DATA,'order'=>'fullnam','select'=>$select,'pagesize'=>'9999','selectedfields'=>array('fullnam','GRP','alias')));
  515. } else {
  516. $xuser = XModule::objectFactory($directory);
  517. if(empty($xuser)) return array();
  518. $select='';
  519. if($valid && $xuser->xset->fieldExists('DATEF') && $xuser->xset->fieldExists('DATET')) {
  520. $select = 'DATET >= "'.date('Y-m-d').'"';
  521. $select .= 'AND DATEF <= "'.date('Y-m-d').'"';
  522. }
  523. $acl_user=$xuser->browse(array('_local'=>1, 'select'=>$select, 'pagesize'=>9999, 'order'=>'fullnam', 'selectedfields'=>array('fullnam','GRP','alias')));
  524. }
  525. // On récupère tous les groupes et sous-groupes des utilisateurs actifs
  526. $grps = self::sGroups($acl_user['lines_oid']);
  527. // Si le paramètre "all" est activé, on ajoute les groupes "Tout le monde" et "Utilisateurs authentifiés" à la liste
  528. if($all && $all!=='users') $grps = array_merge($grps, array('GRP:*','GRP:2'));
  529. $grps=array_unique($grps);
  530. $xgrp=XDataSource::objectFactoryHelper8('BCLASS=XDSTable&SPECS=GRP');
  531. $select=$xgrp->select_query(array('cond'=>array('KOID'=>array('=',$grps))));
  532. $acl_grp=$xgrp->browse(array('tplentry'=>TZR_RETURN_DATA, 'order'=>'GRP','pagesize'=>'1000','select'=>$select));
  533. $ar=array(&$acl_user,&$acl_grp);
  534. return $ar;
  535. }
  536. /// Vérifie le niveau de droit d'une fonction sur un module pour un ensemble d'oid
  537. /// $function : nom de la fonction à tester
  538. /// $mod : module à tester
  539. /// $oid : oid ou tableau d'oid à tester
  540. /// $user : uid du user à tester
  541. /// $lang : langue à tester
  542. /// @return : [ fonction accessible (bool), nb de regle parcourue (int), niveau max de droit (string) ]
  543. static function secure8($function, $mod, $oid=null, $user=null, $lang=null, $checkparent=true) {
  544. // Recherche de la liste des groupes/users a tester
  545. if(!$user) $user=XUser::get_current_user_uid();
  546. elseif(is_object($user)) $user=$user->_curoid;
  547. $g1 = XUser::sGroups($user);
  548. // Si on est dans le groupe des administrateurs on a tous les droits
  549. if(in_array(TZR_GROUPID_ROOT, $g1)) return array(true,1,'admin');
  550. $g1=array_unique($g1);
  551. // Récupération du module et nettoyage des oids
  552. if(is_numeric($mod)) $mod=XModule::objectFactory($mod);
  553. if(!$lang) $lang=TZR_DEFAULT_LANG;
  554. if(!$mod->objectSecurityEnabled() || !$oid){
  555. $oids=array('');
  556. }elseif(!is_array($oid)){
  557. $oids=array($oid);
  558. }else{
  559. $oids=array_unique($oid,SORT_REGULAR);
  560. }
  561. $ooids=$oids;
  562. // Liste des droits necessaires pour l'execution de la fonction
  563. $needed = $mod->secGroups($function);
  564. if(!is_array($needed)) return false;
  565. list($minlvl)=$needed;
  566. if($minlvl=='none') return array(true,1,'none');
  567. // Condition SQL
  568. $cond='"'.implode('","',$g1).'"';
  569. // Vérifie le cache statique
  570. $idx=$cond.$minlvl.$mod->_moid.implode('',$oids).$lang;
  571. if(isset(XUser::$_C81[$idx])){
  572. return XUser::$_C81[$idx];
  573. }
  574. // Nombre de requete effectuée pour trouver un droit. Si à la fin du while celui ci vaut 0, c'est qu'aucune regle n'a été trouvé en base et qu'il faut donc faire jouer l'heritage
  575. $found=false;
  576. $rqs=0;
  577. $maxlvl=null;
  578. $maxlvluid='';
  579. $cache=true;
  580. $nboids=count($oids);
  581. $firstoid=$oids[0];
  582. // Si on ne demande le droit que d'un oid sur un user, on vérifié le cache SQL
  583. // Ce cas étant le plus courant, c'est le seul cache SQL disponible pour l'instant
  584. $cacheenabled=($mod->rightCacheEnabled() && $nboids==1 && self::oidIsUser($user));
  585. while(($oid=array_shift($oids))!==null){
  586. // Vérifie si l'objet est locké ou pas
  587. if(!empty($GLOBALS['XLOCK']) && !empty($oid) && !in_array('ro',$needed)) {
  588. $locked=$GLOBALS['XLOCK']->locked($oid, $lang);
  589. if(!empty($locked) && $user!=$locked['OWN']){
  590. return array(false,1,'none');
  591. }
  592. }
  593. // Cache SQL
  594. if($cacheenabled){
  595. XAudit::plusplus('secure8-cachesql');
  596. $cache=selectQueryGetOne('select OK,AMAX from ACL4_CACHE where AFUNCTION="'.$function.'" AND AGRP="'.$user.'" and ALANG="'.$lang.'" and AMOID="'.$mod->_moid.'" AND AKOID="'.$oid.'"');
  597. if($cache){
  598. XAudit::plusplus('secure8-cachesql-ok');
  599. $rqs++;
  600. $found=(bool)$cache['OK'];
  601. list($maxlvl,$maxlvluid)=explode(';',$cache['AMAX']);
  602. break;
  603. }
  604. }
  605. // On recupere toutes les regles en base ou dans le cache statique
  606. $idx2=$cond.$mod->_moid.$oid.$lang;
  607. if(!isset(XUser::$_C82[$idx2])){
  608. XAudit::plusplus('secure8-query');
  609. XUser::$_C82[$idx2]=selectQueryGetAll('SELECT * FROM ACL4 WHERE AGRP IN ('.$cond.') AND AKOID="'.$oid.'" AND AMOID="'.$mod->_moid.'" AND ALANG="'.$lang.'" /* secure8 */');
  610. }
  611. $rs=&XUser::$_C82[$idx2];
  612. foreach($rs as &$acl){
  613. $rqs++;
  614. $lvl=array_search($acl['AFUNCTION'], $needed);
  615. // Si on trouve une regle sur le user, elle a la priorité, on recupere le resultat et on stoppe la boucle
  616. if(self::oidIsUser($acl['AGRP'])){
  617. $maxlvl=$lvl;
  618. $found=($lvl!==false);
  619. break;
  620. }
  621. if($lvl!==false) {
  622. $found=true;
  623. }
  624. // Si le niveau detecté est supérieur ou qu'il est egal sur la personne demandée (cette derniere condition est necessaire pour etre sur qu'il s'agit d'un heritage ou pas)
  625. if($lvl>$maxlvl || $maxlvl===null || ($lvl==$maxlvl && $acl['AGRP']==$user)){
  626. $maxlvl=$lvl;
  627. $maxlvluid=$acl['AGRP'];
  628. }
  629. }
  630. // Si une regle positive a été trouvée, pas la peine de passer à l'oid suivant
  631. if($found) break;
  632. }
  633. // Si aucune règle n'a été trouvé en base et si on est pas déjà au niveau du module (oid vide), on va tester d'enventuels parents
  634. if($checkparent && !$rqs && !empty($firstoid) && $mod->objectSecurityEnabled()){
  635. $parents=$mod->getParentsOids($ooids);
  636. if(!empty($parents)){
  637. $res=self::secure8($function,$mod,$parents,$user,$lang);
  638. $found=$res[0];
  639. $rqs+=$res[1];
  640. $maxlvl=$res[2];
  641. $maxlvluid=$res[3];
  642. }
  643. }
  644. // Recupere le niveau max de droit
  645. if(is_numeric($maxlvl)) $maxlvl=$needed[$maxlvl];
  646. elseif($maxlvl===NULL) $maxlvl='none';
  647. // Si la personne avec les droits les plus élevé est celle demandée à l'origine, on retourne une chaine vide pour siginifier que ce n'est pas de l'heritage
  648. if($maxlvluid==$user) $maxlvluid='';
  649. // Si on ne demande le droit que d'un oid sur un user, on met le résultat en cache SQL
  650. // Va de paire avec le select ACL4_CACHE quelques lignes au dessus
  651. if($cacheenabled && !$cache){
  652. XUser::setCache($user, $function, $lang, $mod->_moid, $firstoid, $found, 'secure8', $maxlvl, $maxlvluid);
  653. }
  654. XUser::$_C81[$idx]=array($found,$rqs,$maxlvl,$maxlvluid);
  655. return XUser::$_C81[$idx];
  656. }
  657. static function setCache($user=null, $function, $lang=null, $moid, $oid, $ok, $comment, $maxlevel, $maxleveluid) {
  658. if (empty($user))
  659. $user = XUser::get_current_user_uid();
  660. if (empty($lang))
  661. $lang = TZR_DEFAULT_LANG;
  662. $aoid=substr(md5(uniqid('')),0,40);
  663. updateQuery('insert into ACL4_CACHE(AOID,ACOMMENT,AGRP,AFUNCTION,ALANG,AMOID,AKOID,OK,AMAX) '.
  664. 'values("'.$aoid.'","'.$comment.'","'.$user.'","'.$function.'","'.$lang.'",'.$moid.',"'.$oid.'",'.(int)$ok.',"'.$maxlevel.';'.$maxleveluid.'")');
  665. }
  666. /// retourne les oids pour lesquels des droits sont positionnées et ceux du module(clef vide)
  667. static function secure8oids($mod, $user=null, $lang=TZR_DEFAULT_LANG) {
  668. if (!$lang)
  669. $lang = TZR_DEFAULT_LANG;
  670. // Recherche de la liste des groupes/users a tester
  671. if (!$user) $user=XUser::get_current_user_uid();
  672. elseif (is_object($user)) $user=$user->_curoid;
  673. $g1 = XUser::sGroups($user);
  674. if (is_object($mod))
  675. $mod = $mod->_moid;
  676. $idx = "$user-$mod-$lang";
  677. //
  678. if (!isset(XUser::$_C8OIDS[$idx])) {
  679. $cond='"'.implode('","',$g1).'"';
  680. $acls = selectQuery('SELECT AKOID, AFUNCTION, AGRP FROM ACL4 WHERE AGRP IN ('.$cond.') AND AMOID="'.$mod.'" AND ALANG="'.$lang.'" order by AGRP desc /* secure8oids */')->fetchAll(PDO::FETCH_GROUP); // users before group
  681. XUser::$_C8OIDS[$idx] = $acls;
  682. }
  683. return XUser::$_C8OIDS[$idx];
  684. }
  685. /// Vérifie les droits sur un module/oid/user
  686. static function secure8oid($function, $mod, $oid=null, $user=null, $lang=TZR_DEFAULT_LANG, $checkparent=false) {
  687. if (!$lang)
  688. $lang = TZR_DEFAULT_LANG;
  689. if (XShell::isRoot())
  690. return true;
  691. if (is_numeric($mod))
  692. $mod = XModule::objectFactory($mod);
  693. $needed = $mod->secGroups($function);
  694. if (!is_array($needed))
  695. return false;
  696. list($minlvl) = $needed;
  697. if ($minlvl=='none')
  698. return true;
  699. // Vérifie si l'objet est locké ou pas
  700. if(!empty($GLOBALS['XLOCK']) && !empty($oid) && !in_array('ro', $needed)) {
  701. $locked=$GLOBALS['XLOCK']->locked($oid, $lang);
  702. if(!empty($locked) && $user!=$locked['OWN']){
  703. return false;
  704. }
  705. }
  706. $idx = "$function-".$mod->_moid."-$oid-$user-$lang-$checkparent";
  707. if (isset(XUser::$_C8OID[$idx]))
  708. return XUser::$_C8OID[$idx];
  709. $acls = XUser::secure8oids($mod, $user, $lang);
  710. // les règles utilisateur viennent avant celle des groupes
  711. foreach ($acls[$oid] as $acl) {
  712. $level = $acl['AFUNCTION'];
  713. if (in_array($level, $needed))
  714. return XUser::$_C8OID[$idx] = true;
  715. // si une règle est positionné sur l'utilisateur, elle a priorité
  716. if ($acl['AGRP'] == $user)
  717. break;
  718. }
  719. if (!isset($acls[$oid]) && $checkparent) {
  720. $parents = $mod->getParentsOids(array($oid));
  721. foreach ($parents as $parentOid) {
  722. if (XUser::secure8oid($function, $mod, $parentOid, $user, $lang, $checkparent)) {
  723. return XUser::$_C8OID[$idx] = true;
  724. }
  725. }
  726. }
  727. // default le module
  728. foreach ($acls[''] as $acl) {
  729. $level = $acl['AFUNCTION'];
  730. if (in_array($level, $needed))
  731. return XUser::$_C8OID[$idx] = true;
  732. if ($acl['AGRP'] == $user)
  733. break;
  734. }
  735. return XUser::$_C8OID[$idx] = false;
  736. }
  737. /// Vérifie si une methode sur une classe est accessible. Cela n'est possible que si la methode est acessible par tout le monde
  738. static function secure8class($class, $function){
  739. if(XShell::isRoot()) return true;
  740. $secs=call_user_func(array($class,"secGroups"),$function);
  741. return in_array('none',$secs);
  742. }
  743. /// Retourne le niveau max d'accès pour un module/oid
  744. static function secure8maxlevel($mod, $oid='', $user=NULL, $lang=TZR_DEFAULT_LANG) {
  745. $sec=self::secure8(':list', $mod, $oid, $user, $lang);
  746. return $sec[2];
  747. }
  748. /// Vérifie si un oid représente un user
  749. static function oidIsUser($oid){
  750. return (strpos($oid,'USERS:')===0);
  751. }
  752. /// Teste si le user USERS:self existe
  753. static function selfExists() {
  754. static $done=false;
  755. static $exists=false;
  756. if(!$done) {
  757. $exists=countSelectQuery('SELECT COUNT(KOID) FROM USERS WHERE KOID="'.TZR_SELF_USER.'"');
  758. $done=true;
  759. }
  760. return $exists;
  761. }
  762. /// Récupere une variable de session en base de données
  763. static function getDbSessionData($varname){
  764. static $cache=array();
  765. $sessid=session_id();
  766. if(!$sessid) return null;
  767. if(!array_key_exists($varname,$cache)){
  768. $row=selectQueryGetOne('select value from _VARS where sessid="'.$sessid.'" and name="'.$varname.'"');
  769. if($row) $cache[$varname]=unserialize($row['value']);
  770. else return null;
  771. }
  772. return $cache[$varname];
  773. }
  774. /// Récupere une variable de cache en base de données
  775. static function getDbCacheData($varname){
  776. return self::getDBSessionData(self::DB_SESSION_CACHE_PREFIX.$varname);
  777. }
  778. /// Ajoute/modifie une variable de session en base de données
  779. static function setDbSessionData($varname,$value){
  780. $sessid=session_id();
  781. if(!$sessid) return null;
  782. updateQuery('replace into _VARS (sessid,user,name,value) values ("'.$sessid.'","'.XUser::get_current_user_uid().'","'.$varname.'",'.$GLOBALS['TZR_DB']->quote(serialize($value)).')');
  783. }
  784. /// Ajoute/modifie une variable de cache en base de données
  785. static function setDbCacheData($varname,$value){
  786. return self::setDbSessionData(self::DB_SESSION_CACHE_PREFIX.$varname,$value);
  787. }
  788. /// Efface une variable de session en base de données
  789. static function deleteDbSessionDataUPD($varname){
  790. $sessid=session_id();
  791. if(!$sessid) return null;
  792. updateQuery('delete from _VARS where sessid="'.$sessid.'" and name="'.$varname.'"');
  793. }
  794. /// Efface une variable de cache en base de données
  795. static function deleteDbCacheDataUPD($varname){
  796. return self::deleteDbSessionDataUPD(self::DB_SESSION_CACHE_PREFIX.$varname);
  797. }
  798. /// Met à jour l'upd d'une variable de session en base de données
  799. static function updateDbSessionDataUPD($varname){
  800. $sessid=session_id();
  801. if(!$sessid) return null;
  802. updateQuery('update ignore _VARS set UPD=NOW() where sessid="'.$sessid.'" and name="'.$varname.'"');
  803. }
  804. /// Met à jour l'upd d'une variable de cache en base de données
  805. static function updateDbCacheDataUPD($varname){
  806. return self::updateDbSessionDataUPD(self::DB_SESSION_CACHE_PREFIX.$varname);
  807. }
  808. /// Efface toutes les données d'une session en base de données
  809. static function clearDbSessionDataAndRightCache(){
  810. $sessid=session_id();
  811. if(!$sessid) return null;
  812. updateQuery('delete from _VARS where sessid="'.$sessid.'"');
  813. updateQuery('delete from ACL4_CACHE where AGRP="'.XUser::get_current_user_uid().'"');
  814. }
  815. /// Efface toutes les données de session/cache périmées en base de données
  816. static function clearOldDbSessionDataAndRightCache(){
  817. // Efface le cache
  818. updateQuery('delete from _VARS where sessid is not null and name like "'.self::DB_SESSION_CACHE_PREFIX.'%" and UPD<="'.date('Y-m-d H:i:s',strtotime('-10 minutes')).'"');
  819. // Efface les sessions
  820. $rs=selectQuery('select sessid from _VARS where name="last_activity" and UPD<="'.date('Y-m-d H:i:s',strtotime('-'.TZR_SESSION_DURATION.' seconds')).'"');
  821. while($rs && $ors=$rs->fetch()){
  822. updateQuery('delete from _VARS where sessid="'.$ors['sessid'].'"');
  823. }
  824. // Efface le cache des droits des users qui n'ont plus de session actives
  825. $rs=selectQuery('select distinct(AGRP) as AGRP from ACL4_CACHE');
  826. while($rs && $ors=$rs->fetch()){
  827. $nb=countSelectQuery('select count(*) from _VARS where name="last_activity" and user="'.$ors['AGRP'].'"');
  828. if(!$nb) updateQuery('delete from ACL4_CACHE where AGRP="'.$ors['AGRP'].'"');
  829. }
  830. }
  831. }
  832. ?>