....................................../////.===Shadow-Here===./////................................................ > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < > < ------------------------------------------------------------------------------------------------------------------- /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// RIFF¤ WEBPVP8 ˜ ðÑ *ôô>‘HŸK¥¤"§£±¨àð enü¹%½_F‘åè¿2ºQú³íªú`N¿­3ÿƒügµJžaÿ¯ÿ°~¼ÎùnúîÞÖô•òíôÁÉß®Sm¥Ü/ ‡ó˜f£Ùà<˜„xëJ¢Ù€SO3x<ªÔ©4¿+ç¶A`q@Ì“Úñè™ÍÿJÌ´ª-˜ÆtÊÛL]Ïq*‘Ý”ì#ŸÌÏãY]@ê`¿ /ªfkØB4·®£ó z—Üw¥Pxù–ÞLШKÇN¾AkÙTf½è'‰g gÆv›Øuh~ a˜Z— ïj*á¥t d£“uÒ ¨`K˜¹ßþ]b>˜]_ÏÔ6W—è2r4x•íÖ…"ƒÖNîä!¦å Ú}ýxGøÌ —@ ;ÆÚŠ=ɾ1ý8lªË¥ô ^yf®Œ¢u&2©nÙÇ›ñÂñŒ³ aPo['½»øFùà­+4ê“$!lövlüÞ=;N®3ð‚õ›DÉKòÞ>ÄÍ ¥ˆuߤ#ˆ$6ù™¥îЇy’ÍB¼ çxÛ;X"WL£R÷͝*ó-¶Zu}º.s¸sšXqù–DþÿvªhüïwyŸ ¯é³lÀ:KCûÄ£Ëá\…­ ~—ýóî ¼ûûÜTÓüÇy…ŽÆvc»¾×U ñ¸žþоP÷¦ó:Ò¨¨5;Ð#&#ÖúñläÿÁœ GxÉ­/ñ‡áQðìYÉtÒw޼GÔ´zàÒò ð*ëzƒ•4~H]Ø‹f ñÓÈñ`NåWçs'ÆÏW^ø¹!XžµmQ5ÃËoLœÎ: ÞËÍ¥J ù…î èo£ßPÎñ¶ž8.Œ]ʵ~5›ÙË-ù*8ÙÖß±~ ©¹rÓê‚j¶d¸{^Q'˜±Crß ÚH—#¥¥QlÀ×ëã‡DÜ«èî þ&Çæžî;ŽÏºò6ÒLÃXy&ZŒ'j‚¢Ù€IßÚù+–MGi‰*jE€‘JcÜ ÓÌ EÏÚj]o˜ Þr <¾U ûŪæÍ/šÝH¥˜b”¼ ÁñßX GP›ï2›4WŠÏà×£…íÓk†¦H·ÅíMh–*nó÷à]ÁjCº€b7<ب‹¨5車bp2:Á[UªM„QŒçiNMa#<5›áËó¸HýÊ"…×Éw¹¦ì2º–x<›»a±¸3Weü®FÝ⑱ö–î–³|LPÈ~çð~Çå‡|º kD¢µÏàÆAI %1À% ¹Ò – ”ϝS¦‰4&¶£°à Öý”û_Ò Áw°A«Å€?mÇÛgHÉ/8)á¾ÛìáöŽP í¨PŸNÙµº¦‡§Ùš"ÿ«>+ªÕ`Ê÷‡‚ß Õû˜þãÇ-PÍ.¾XV‘€ dÜ"þ4¹ ±Oú‘©t¥¦FªÄÃÄ•b‚znýu½—#cDs˜ÃiÑOˆñ×QO=*IAÊ,¶ŽZƒ;‡wøXè%EÐk:F±Ú” .Ѽ+Áu&Ç`."pÈÉw o&¿dE6‘’EqTuK@Ì¥ã™À(Êk(h‰,H}RÀIXÛš3µ1©_OqÚÒJAñ$ÊÙÜ;D3çŒ[þùœh¬Ã³™ö6ç†NY".Ú‰ï[ªŸŒ '²Ð öø_¨ÂÉ9ué¶³ÒŠõTàîMØ#û¯gN‡bÙ놚X„ö …ÉeüÌ^J ‹€.œ$Æ)βÄeæW#óüßĺŸ€ ÀzwV 9oä»f4V*uB «Ë†¹ì¯žR霓æHXa=&“I4K;¯ç‹h×·"UŠ~<•╪Vêª&ÍSÃÆÅ?ÔqÎ*mTM ˜›µwêd#[C¡©§‘D<©àb†–ÁœøvH/,í:¯( ²£|4-„Æövv„Yͼ™^Á$ˆ„¢Û[6yB.åH*V¨æ?$=˜Ñ€•ñ·­(VlŸ‘ nÀt8W÷´Bûba?q9ú¶Xƒl«ÿ\ù¶’þòUÐj/õ¢Ìµ³g$ƒÎR!¸»|Oߍë’BhîÚÑ¢ñåŒJ„®„£2Ð3•ô02Nt…!£Í]Ïc½Qÿ?ˆ<&ÃA¾Ú,JˆijÌ#5yz„‰Î|ÊŽ5QÏ:‹ÐaóVÔxW—CpeÏzÐïíçôÿÅ_[hãsÐ_/ŽTÝ?BîˆííV$<¿i>²F¬_Eß¿ †bÊŒº­ÿ®Z H“C}”¬,Mp ý/Bá£w>˜YV°aƒúh+cŠ- r/[%|üUMHäQ°X»|û/@|°¥Ð !BÔ Ç¢Ä©š+Õì D«7ìN¶ŽðÔ " ƶ’ÖçtA‰Û×}{tþz­¾GÍ›k¹OEJR$ Â׃ «ëÁ"oÉôž$oUK(Ä)Ãz³Ê-‹êN[Ò3Œñbï8P 4ƒ×q¢bo|?<ÛX¬òÄͰL–±›(™ûG?ýË©ÚÄ–ÂDØÐ_Ç¡ô ¾–ÄÏø ×e8Ë©$ÄF¹Å‹ì[©óìl:F¾f´‹‹Xì²ï®\¬ôùƒ ÿat¥óèÒùHß0äe‚;ü×h:ÆWðHž=Ã8骣"kœ'Y?³}Tûè€>?0l›e1Lòñ„aæKÆw…hÖŠùW…ÈÆÄ0ši·›[pcwËþñiêíY/~-Á5˜!¿†A›™Mÿþ(±“t@â“ö2­´TG5yé]çå僳 .·ÍïçÝ7UÚ±Ð/Nè»,_Ï ùdj7\ï Wì4›„»c¸àešg#ÒÊ⥭áØo5‘?ÌdÝô¯ ¹kzsƒ=´#ëÉK›Ø´±-¥eW?‡çßtòTã…$Ý+qÿ±ƒ÷_3Ô¥í÷:æ–ž<·Ö‡‰Å¢ š‡%Ô—utÌÈìðžgÖÀz²À—ï÷Óîäõ{K'´È÷³yaÏÁjƒô}ž§®æÊydÕÈë5¯èˆõvÕ©ã*çD„ “z„Ó‡^^xÂ3M§A´JG‚öï 3W'ˆ.OvXè¡ÊÕª?5º7†˜(˜Ç¶#çê’¶!ÌdZK§æ 0fãaN]òY³RV ™î$®K2R¨`W!1Ôó\;Ý ýB%qæK•&ÓÈe9È0êI±žeŸß -ú@žQr¦ ö4»M¼Áè¹µmw 9 EÆE_°2ó„ŸXKWÁ×Hóì^´²GѝF©óäR†¦‰ç"V»eØ<3ùd3ÿÚ¤Žú“Gi" —‘_ÙËÎ~Üö¯¥½Î»üŸEÚŽåmÞþí ;ÞólËΦMzA"Âf(´òá;Éï(/7½ûñÌ­cïÕçлþÝz¾-ÍvÑ“pH­–ðÓj$¸Äû¤‚‘ãUBË-n“2åPkS5&‹Â|+g^œ®Ì͆d!OïäîU«c;{Û!ÅŽ«ëZ9Ókóˆ]¯ƒ›né `ÇÒ+tÆš (ØKá¾—=3œ®•vuMñg²\ï Ec€ 05±d™‡×iÇ×›UúvÌ¢£Èþ¡ÕØô¶ßÎA"ß±#Ö²ˆÊŸ¦*Ä~ij|àø.-¼'»Ú¥£h ofº¦‡VsR=N½„Î v˜Z*SÌ{=jÑB‹tê…;’HžH¯8–îDù8ñ¢|Q•bÛçš–‹m³“ê¨ åÏ^m¬Žãþ©ïêO‡½6] µÆ„Ooòü ²x}N¦Ë3ïé¿»€›HA˜m%çÞ/¿í7Fø“‹léUk)É°Œµ8Q8›:ÀŠeT*šõ~ôڝG6 ¢}`ùH­–”¡k ‰P1>š†®9z11!X wKfmÁ¦xÑ,N1Q”–æB¶M…ÒÃv6SMˆhU¬ÊPŽï‘öj=·CŒ¯u¹ƒVIЃsx4’ömÛýcå¡¶7ßŠß 57^\wÒÐÆ k§h,Œý î«q^R½3]J¸ÇðN ‚çU¬ôº^Áì} ³f©Õœ§ˆã:FÄÈ‚é(€™?àýÓüè1Gô£¼éj‚OÅñ  #>×—ßtà 0G¥Åa뀐kßhc™À_ÉñÞ#±)GD" YîäË-ÿÙ̪ ¹™a¯´¢E\ÝÒö‚;™„ë]_ p8‰o¡ñ+^÷ 3‘'dT4œŽ ðVë½° :¬víÑ«£tßÚS-3¶“þ2 †üüʨòrš¹M{É_¤`Û¨0ìjœøJ‡:÷ÃáZ˜†@GP&œÑDGÏs¡þ¦þDGú‘1Yá9Ôþ¼ ûø…§÷8&–ÜÑnÄ_m®^üÆ`;ÉVÁJ£?â€-ßê}suÍ2sõA NÌúA磸‘îÿÚ»ƒìö·á¿±tÑÐ"Tÿü˜[@/äj¬€uüªìù¥Ý˜á8Ý´sõj 8@rˆð äþZÇD®ÿUÏ2ùôõrBzÆÏÞž>Ì™xœ“ wiÎ×7_… ¸ \#€MɁV¶¥üÕÿPÔ9Z‡ø§É8#H:ƒ5ÀÝå9ÍIŒ5åKÙŠ÷qÄ>1AÈøžj"µÂд/ªnÀ qªã}"iŸBå˜ÓÛŽ¦…&ݧ;G@—³b¯“•"´4í¨ôM¨åñC‹ïùÉó¯ÓsSH2Ý@ßáM‡ˆKÀªÛUeø/4\gnm¥‹ŸŒ qÄ b9ÞwÒNÏ_4Ég³ú=܆‚´ •â¥õeíþkjz>éÚyU«Íӝ݃6"8/ø{=Ô¢»G¥ äUw°W«,ô—¿ãㆅү¢³xŠUû™yŒ (øSópÐ 9\åTâ»—*oG$/×ÍT†Y¿1¤Þ¢_‡ ¼ „±ÍçèSaÓ 3ÛMÁBkxs‰’R/¡¤ˆÙçª(*õ„üXÌ´ƒ E§´¬EF"Ù”R/ÐNyÆÂ^°?™6¡œïJ·±$§?º>ÖüœcNÌù¯G ‹ñ2ЁBB„^·úìaz¨k:#¨Æ¨8LÎõލ£^§S&cŒÐU€ü(‡F±Š¼&P>8ÙÁ ‰ p5?0ÊÆƒZl¸aô š¼¡}gÿ¶zÆC²¹¬ÎÖG*HB¡O<º2#ñŒAƒ–¡B˜´É$¥›É:FÀÔx¾u?XÜÏÓvN©RS{2ʈãk9rmP¼Qq̳ è¼ÐFׄ^¡Öì fE“F4A…!ì/…¦Lƒ… … $%´¾yã@CI¬ á—3PþBÏNÿ<ý°4Ü ËÃ#ØÍ~âW«rEñw‹eùMMHß²`¬Öó½íf³:‹k˜¯÷}Z!ã¿<¥,\#öµÀ¯aÒNÆIé,Ћ–lŽ#Àæ9ÀÒS·I’½-Ïp Äz¤Š Â* ­íÄ9­< h>׍3ZkËU¹§˜ŒŠ±f­’¤º³Q ÏB?‹#µíÃ¥®@(Gs«†vI¥Mµ‹Á©e~2ú³ÁP4ìÕi‚²Ê^ö@-DþÓàlÜOÍ]n"µã:žpsŽ¢:! Aõ.ç~ÓBûH÷JCÌ]õVƒd «ú´QÙEA–¯¯Œ!.ˆˆëQ±ù œ·Ì!Õâ )ùL„ÅÀlÚè5@B…o´Æ¸XÓ&Û…O«˜”_#‡ƒ„ûÈt!¤ÁÏ›ÎÝŠ?c9 â\>lÓÁVÄÑ™£eØY]:fÝ–—ù+p{™ðè û³”g±OƒÚSù£áÁÊ„ä,ï7š²G ÕÌBk)~ÑiCµ|h#u¤¶îK¨² #²vݯGãeÖ϶ú…¾múÀ¶þÔñ‚Š9'^($¤§ò “š½{éúp÷J›ušS¹áªCÂubÃH9™D™/ZöØÁ‡¦ÝÙŸ·kð*_”.C‹{áXó€‡c¡c€§/šò/&éš÷,àéJþ‰X›fµ“C¨œ®r¬"kL‰Â_q…Z–.ÉL~O µ›zn‚¹À¦Öª7\àHµšÖ %»ÇníV[¥*Õ;ƒ#½¾HK-ÖIÊdÏEÚ#=o÷Óò³´Š: Ç?{¾+9›–‘OEáU·S€˜j"ÄaÜ ŒÛWt› á–c#a»pÔZÞdŽtWê=9éöÊ¢µ~ ë ;Öe‡Œ®:bî3±ýê¢wà¼îpêñ¹¾4 zc¾ðÖÿzdêŒÑÒŝÀ‰s6¤í³ÎÙB¿OZ”+F¤á‡3@Ñëäg©·Ž ˆèª<ù@É{&S„œÕúÀA)‰h:YÀ5^ÂÓŒ°õäU\ ùËÍû#²?Xe¬tu‰^zÒÔãë¼ÛWtEtû …‚g¶Úüâî*moGè¨7%u!]PhÏd™Ý%Îx: VÒ¦ôÊD3ÀŽKÛËãvÆî…N¯ä>Eró–ð`5 Œ%u5XkñÌ*NU%¶áœÊ:Qÿú»“úzyÏ6å-၇¾ ´ ÒÊ]y žO‘w2Äøæ…H’²f±ÎÇ.ª|¥'gîV•Ü .̘¯€šòü¤U~Ù†*¢!?ò wý,}´°ÔÞnïoKq5µb!áÓ3"vAßH¡³¡·G(ÐÎ0Îò¼MG!/ài®@—¬04*`…«é8ªøøló“ˆÊ”èù¤…ßÊoÿé'ËuÌÖ5×È¡§ˆˆfŽë9}hìâ_!!¯  B&Ëö¶‰ÀAÙNVŸ Wh›¸®XÑJì¨ú“¿÷3uj²˜¨ÍÎìë±aúŠÝå¯ð*Ó¨ôJ“yºØ)m°WýOè68†ŸÏ2—‰Ïüꪫٚ¥‹l1 ø ÏÄFjêµvÌbü¦èÝx:X±¢H=MÐß—,ˆÉÇ´(9ú¾^ÅÚ4¿m‡$âX‘å%(AlZo@½¨UOÌÕ”1ø¸jÎÀÃÃ_ µ‘Ü.œº¦Ut: Æï’!=¯uwû#,“pþÇúŒø(é@?³ü¥‘Mo §—s@Œ#)§ŒùkL}NOÆêA›¸~r½¼ÙA—HJ«eˆÖ´*¡ÓpÌŸö.m<-"³ûÈ$¬_6­åf£ïÚâj1y§ÕJ½@dÞÁr&Í\Z%D£Íñ·AZ Û³øüd/ªAi†/Й~  ‡âĮҮÏh§°b—›Û«mJžòG'[ÈYýŒ¦9psl ýÁ ®±f¦x,‰½tN ‚Xª9 ÙÖH.«Lo0×?͹m¡å†Ѽ+›2ƒF ±Ê8 7Hցϓ²Æ–m9…òŸï]Â1äN†VLâCˆU .ÿ‰Ts +ÅÎx(%¦u]6AF Š ØF鈄‘ |¢¶c±soŒ/t[a¾–û:s·`i햍ê›ËchÈ…8ßÀUÜewŒðNOƒõD%q#éû\9¤x¹&UE×G¥ Í—™$ð E6-‡¼!ýpãÔM˜ Âsìe¯ñµK¢Ç¡ùôléœ4Ö£”À Š®Ðc ^¨À}ÙËŸ§›ºê{ÊuÉC ×Sr€¤’fÉ*j!úÓ’Gsùìoîßîn%ò· àc Wp÷$¨˜)û»H ×8ŽÒ€Zj¤3ÀÙºY'Ql¦py{-6íÔCeiØp‘‡XÊîÆUߢ܂ž£Xé¼Y8þ©ëgñß}é.ÎógÒ„ÃØËø¯»™§Xýy M%@NŠ À(~áÐvu7&•,Ù˜ó€uP‡^^®=_E„jt’ 403WebShell
403Webshell
Server IP : 66.29.146.187  /  Your IP : 216.73.216.167
Web Server : LiteSpeed
System : Linux premium302.web-hosting.com 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
User : ailwtbdh ( 734)
PHP Version : 8.1.34
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : ON  |  Sudo : OFF  |  Pkexec : OFF
Directory :  /home/ailwtbdh/www/wp-content/plugins/wpforo/classes/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /home/ailwtbdh/www/wp-content/plugins/wpforo/classes/Permissions.php
<?php

namespace wpforo\classes;

use stdClass;
use WP_User;

// Exit if accessed directly
if( ! defined( 'ABSPATH' ) ) exit;

class Permissions {
	public $default;
	public $accesses;
	public $cans;

	function __construct() {
		$this->init_defaults();
		$this->init_cans();
		$this->init();
		add_action( 'wpforo_after_init_classes', function() {
			if( WPF()->is_installed() ) $this->init_current_user_accesses();
		} );
		add_action( 'wpforo_after_change_board', function() {
			if( WPF()->is_installed() && ! is_null( WPF()->forum ) ) $this->init_current_user_accesses();
		} );
	}

	private function init_defaults() {
		$this->default         = new stdClass;
		$this->default->access = [
			'accessid' => 0,
			'access'   => '',
			'title'    => '',
			'cans'     => '',
		];
		$this->default->cans   = [
			'vf'   => __( 'Can view forum', 'wpforo' ),
			'enf'  => __( 'Can enter forum', 'wpforo' ),
			'ct'   => __( 'Can create topic', 'wpforo' ),
			'vt'   => __( 'Can view topic', 'wpforo' ),
			'ent'  => __( 'Can enter topic', 'wpforo' ),
			'et'   => __( 'Can edit topic', 'wpforo' ),
			'dt'   => __( 'Can delete topic', 'wpforo' ),
			'cr'   => __( 'Can post reply', 'wpforo' ),
			'ocr'  => __( 'Can reply to own topic', 'wpforo' ),
			'vr'   => __( 'Can view replies', 'wpforo' ),
			'er'   => __( 'Can edit replies', 'wpforo' ),
			'dr'   => __( 'Can delete replies', 'wpforo' ),
			'eot'  => __( 'Can edit own topic', 'wpforo' ),
			'eor'  => __( 'Can edit own reply', 'wpforo' ),
			'dot'  => __( 'Can delete own topic', 'wpforo' ),
			'dor'  => __( 'Can delete own reply', 'wpforo' ),
			'tag'  => __( 'Can add tags', 'wpforo' ),
			'sb'   => __( 'Can subscribe', 'wpforo' ),
			'l'    => __( 'Can like', 'wpforo' ),
			'r'    => __( 'Can report', 'wpforo' ),
			's'    => __( 'Can set topic sticky', 'wpforo' ),
			'p'    => __( 'Can set topic private', 'wpforo' ),
			'op'   => __( 'Can set own topic private', 'wpforo' ),
			'vp'   => __( 'Can view private topic', 'wpforo' ),
			'au'   => __( 'Can approve/unapprove content', 'wpforo' ),
			'sv'   => __( 'Can set topic solved', 'wpforo' ),
			'osv'  => __( 'Can set own topic solved', 'wpforo' ),
			'v'    => __( 'Can vote', 'wpforo' ),
			'vop'  => __( 'Can leave voice posts', 'wpforo' ),
			'vlp'  => __( 'Can listen voice posts', 'wpforo' ),
			'a'    => __( 'Can attach file', 'wpforo' ),
			'va'   => __( 'Can view attached files', 'wpforo' ),
			'at'   => __( 'Can set topic answered', 'wpforo' ),
			'oat'  => __( 'Can set own topic answered', 'wpforo' ),
			'aot'  => __( 'Can answer own question', 'wpforo' ),
			'cot'  => __( 'Can close topic', 'wpforo' ),
			'mt'   => __( 'Can move topic', 'wpforo' ),
			// Poll-related permissions moved to wpForo Polls plugin
		];
	}

	private function init_cans() {
		$this->cans = apply_filters( 'wpforo_init_cans', $this->default->cans );
	}

	private function init() {
		if( WPF()->is_installed() ) {
			if( $accesses = $this->get_accesses() ) {
				foreach( $accesses as $access ) {
					$this->accesses[ intval( $access['accessid'] ) ] = $this->accesses[ $access['access'] ] = $access;
				}
			}
		}
	}

	private function init_current_user_accesses() {
		WPF()->current_user_accesses = $this->get_forum_accesses_by_usergroup();
	}

	public function fix_access( $access ) {
		$access         = wpforo_array_args_cast_and_merge( (array) $access, $this->default->access );
		$cans           = array_map( '__return_zero', $this->cans );
		$access['cans'] = maybe_unserialize( $access['cans'] );
		if( is_array( $access['cans'] ) ) {
			$access['cans'] = wpforo_array_args_cast_and_merge( $access['cans'], $cans );
		} else {
			$access['cans'] = $cans;
		}

		return $access;
	}

	/**
	 *
	 * @param string|int $access
	 *
	 * @return array access row by access key
	 */
	function get_access( $access ) {
		if( wpforo_is_id( $access ) ) {
			$access = intval( $access );
		} else {
			$access = sanitize_text_field( $access );
		}
		if( ! empty( $this->accesses[ $access ] ) ) return $this->accesses[ $access ];

		$sql = "SELECT * FROM " . WPF()->tables->accesses;
		if( is_int( $access ) ) {
			$sql .= " WHERE `accessid` = %d";
		} else {
			$sql .= " WHERE `access` = %s";
		}

		$access_row = $this->fix_access( WPF()->db->get_row( WPF()->db->prepare( $sql, $access ), ARRAY_A ) );
		/**
		 * Filter after getting an access row to allow add-ons to adjust permissions dynamically.
		 * Example: Polls add-on sets default poll permissions per access level.
		 *
		 * @since 2.4.0
		 * @param array $access_row
		 */
		$access_row = apply_filters( 'wpforo_after_get_access', $access_row );
		return $access_row;
	}


	/**
	 * get all accesses from accesses table
	 *
	 * @return array|null
	 */
	function get_accesses() {
		$sql = "SELECT * FROM " . WPF()->tables->accesses . " ORDER BY `accessid`";

		$rows = array_map( [ $this, 'fix_access' ], WPF()->db->get_results( $sql, ARRAY_A ) );
		// Allow add-ons to adjust each access after retrieval (e.g., apply default poll permissions)
		$rows = array_map( function( $row ) { return apply_filters( 'wpforo_after_get_access', $row ); }, $rows );
		return $rows;
	}

	/**
	 * @param array $access
	 *
	 * @return int|bool inserted id or false
	 */
	function add( $access ) {
		if( ! ( $access['title'] = sanitize_text_field( $access['title'] ) ) ) {
			WPF()->notice->add( 'Access title is empty', 'error' );

			return false;
		}

		if( ! $access['access'] ) $access['access'] = uniqid();

		/**
		 * Allow add-ons to adjust access data before adding.
		 * Example: Polls add-on injects default poll permissions.
		 *
		 * @since 2.4.0
		 * @param array $access
		 */
		$access = apply_filters( 'wpforo_before_add_access', $access );

		$i    = 2;
		$slug = $access['access'];
		while( WPF()->db->get_var( WPF()->db->prepare( "SELECT `access` FROM " . WPF()->tables->accesses . " WHERE `access` = %s", sanitize_text_field( $slug ) ) ) ) {
			$slug = $access['access'] . '-' . $i;
			$i ++;
		}

		if( WPF()->db->insert(
			WPF()->tables->accesses, [
			'title'  => $access['title'],
			'access' => sanitize_text_field(
				$slug
			),
			'cans'   => serialize(
				$access['cans']
			),
		],  [ '%s', '%s', '%s', ]
		) ) {
			$access['accessid'] = WPF()->db->insert_id;
			WPF()->notice->add( 'Access successfully added', 'success' );

			return $access['accessid'];
		}

		WPF()->notice->add( 'Access add error', 'error' );

		return false;
	}

	/**
	 * @param array $access
	 *
	 * @return bool|int edited id or false
	 */
	function edit( $access ) {
		/**
		 * Allow add-ons to adjust access data before editing.
		 * Example: Polls add-on injects/ensures poll permissions are present.
		 *
		 * @since 2.4.0
		 * @param array $access
		 */
		$access = apply_filters( 'wpforo_before_edit_access', $access );
		if( false !== WPF()->db->update( WPF()->tables->accesses, [
				'title' => sanitize_text_field( $access['title'] ),
				'cans'  => serialize( $access['cans'] ),
			], [
			                                 'accessid' => $access['accessid'],
		                                 ], [ '%s', '%s' ], [ '%d' ] ) ) {
			WPF()->notice->add( 'Access successfully edited', 'success' );

			return $access['accessid'];
		}

		WPF()->notice->add( 'Access edit error', 'error' );

		return false;
	}

	/**
	 * @param int $accessid
	 *
	 * @return bool|int deleted id or false
	 */
	function delete( $accessid ) {
		$accessid = intval( $accessid );
		if( ! $accessid ) {
			WPF()->notice->add( 'Access delete error', 'error' );

			return false;
		}

		if( false !== WPF()->db->delete( WPF()->tables->accesses, [ 'accessid' => $accessid ], [ '%d' ] ) ) {
			WPF()->notice->add( 'Access successfully deleted', 'success' );

			return $accessid;
		}

		WPF()->notice->add( 'Access delete error', 'error' );

		return false;
	}

	function forum_can( $do, $forumid = null, $groupids = null ) {
		/**
		 * filter for other add-ons to manage can_attach bool value.
		 * e.g. PM add-on attachment function.
		 */
		$filter_forum_can = apply_filters( 'wpforo_permissions_forum_can', null, $do, $forumid, $groupids );
		if( ! is_null( $filter_forum_can ) ) return (int) (bool) $filter_forum_can;

		if( ( is_null( $groupids ) && ! WPF()->current_user_groupids ) || ! $do ) return 0;

		//User Forum accesses from Current Object of Current user
		if( is_null( $groupids ) && WPF()->current_user_accesses ) {
			$forum_id = (int) ( is_null( $forumid ) ? wpfval( WPF()->current_object, 'forum', 'forumid' ) : ( wpfkey( $forumid, 'forumid' ) ? $forumid['forumid'] : $forumid ) );
			if( $forum_id && ( $forum_accesses = wpfval( WPF()->current_user_accesses, $forum_id ) ) ) {
				foreach( $forum_accesses as $cans ) {
					if( (int) wpfval( $cans, $do ) ) return 1;
				}
			}

			return 0;
		}

		//Use Custom User Forum Accesses
		$forum = is_null( $forumid ) ? WPF()->current_object['forum'] : ( ! wpfkey( $forumid, 'forumid' ) ? WPF()->forum->get_forum( $forumid ) : $forumid );
		if( $forum ) {
			$permissions = maybe_unserialize( $forum['permissions'] );
			if( is_null( $groupids ) ) $groupids = WPF()->current_user_groupids;
			$groupids = array_map( 'intval', (array) $groupids );
			foreach( $groupids as $groupid ) {
				if( $_access = wpfval( $permissions, $groupid ) ) {
					$access = $this->get_access( $_access );
					if( (int) wpfval( $access, 'cans', $do ) ) return 1;
				}
			}
		}

		return 0;
	}

	function user_can_manage_user( $user_id, $managing_user_id ) {
		if( ! $user_id || ! $managing_user_id ) return false;
		if( $user_id == $managing_user_id ) return true;

		$user       = new WP_User( $user_id );
		$user_level = $this->user_wp_level( $user );
		if( ! empty( $user->roles ) && is_array( $user->roles ) ) $user_role = array_shift( $user->roles );

		$managing_user       = new WP_User( $managing_user_id );
		$managing_user_level = $this->user_wp_level( $managing_user );
		if( ! empty( $managing_user->roles ) && is_array( $managing_user->roles ) ) $managing_user_role = array_shift( $managing_user->roles );

		if( (int) $user_level > (int) $managing_user_level ) {
			return true;
		} elseif( $user_id == 1 && $user_role === 'administrator' ) {
			return true;
		} elseif( (int) $user_level === (int) $managing_user_level ) {
			$member                   = WPF()->member->get_member( $user_id );
			$managing_member          = WPF()->member->get_member( $managing_user_id );
			$user_wpforo_can          = WPF()->usergroup->can( 'em', $member['groupids'] );
			$managing_user_wpforo_can = WPF()->usergroup->can( 'em', $managing_member['groupids'] );
			if( $user_wpforo_can && ! $managing_user_wpforo_can ) {
				return true;
			} else {
				return false;
			}
		} elseif( $user_id != 1 && $managing_user_id == 1 && $managing_user_role === 'administrator' ) {
			return false;
		} else {
			return false;
		}
	}

	function user_wp_level( $user_object ) {
		$level  = 0;
		$levels = [];
		if( is_int( $user_object ) ) {
			$user_object = new WP_User( $user_object );
		}
		if( isset( $user_object->allcaps ) && is_array( $user_object->allcaps ) && ! empty( $user_object->allcaps ) ) {
			foreach( $user_object->allcaps as $level_key => $level_value ) {
				if( strpos( (string) $level_key, 'level_' ) !== false && $level_value == 1 ) {
					$levels[] = intval( str_replace( 'level_', '', $level_key ) );
				}
			}
			if( ! empty( $levels ) ) {
				$level = max( $levels );
			}
		}

		return $level;
	}

	function can_edit_user( $userid ) {
		if( ! $userid ) return false;
		if( ! $this->user_can_edit_account( $userid ) ) {
			WPF()->notice->clear();
			WPF()->notice->add( 'Permission denied', 'error' );
			wp_safe_redirect( wpforo_get_request_uri() );
			exit();
		}

		return true;
	}

	public function can_link() {
		if( ! WPF()->usergroup->can( 'em' ) ) {
			$posts = WPF()->member->member_approved_posts( WPF()->current_userid );
			$posts = intval( $posts );
			if( ( $min_posts = wpforo_setting( 'antispam', 'min_number_posts_to_link' ) ) && $posts <= $min_posts ) return false;
		}

		return true;
	}

	public function can_attach( $forumid = null ) {
		if( ! $forumid ) $forumid = null;

		/**
		 * filter for other add-ons to manage can_attach bool value.
		 * e.g. PM add-on attachment function.
		 */
		$filter_wpforo_can_attach = apply_filters( 'wpforo_can_attach', null, $forumid );
		if( ! is_null( $filter_wpforo_can_attach ) ) return (bool) $filter_wpforo_can_attach;

		if( ! $this->forum_can( 'a', $forumid ) ) return false;
		if( ! WPF()->usergroup->can( 'em' ) ) {
			$posts = WPF()->member->member_approved_posts( WPF()->current_userid );
			$posts = intval( $posts );
			if( ( $min_posts = wpforo_setting( 'antispam', 'min_number_posts_to_attach' ) ) && $posts <= $min_posts ) return false;
		}

		return true;
	}

	public function can_attach_file_type( $ext = '' ) {
		if( ! WPF()->usergroup->can( 'em' ) && WPF()->member->current_user_is_new() && in_array( $ext, wpforo_setting( 'antispam', 'limited_file_ext' ) ) ) return false;

		return true;
	}

	/**
	 * Check if user can post now based on flood protection settings
	 *
	 * @param string $flood_reason Reference to store the reason if blocked
	 * @return bool|string True if can post, false if blocked, 'unapprove' if should be unapproved
	 */
	public function can_post_now( &$flood_reason = '' ) {
		if( wpforo_is_admin() || ( defined( 'IS_GO2WPFORO' ) && IS_GO2WPFORO ) ) {
			return true;
		}

		// Users with "Dashboard - Moderate Topics & Posts" permission bypass flood protection
		if( WPF()->usergroup->can( 'aum' ) ) {
			return true;
		}

		$userid  = WPF()->current_userid;
		$email   = $userid ? '' : WPF()->current_user_email;
		$groupid = WPF()->current_user_groupid;
		if( WPF()->member->current_user_is_new() ) {
			$groupid = 0;
		}

		// Check for temporary ban first
		if( $this->is_flood_banned() ) {
			$flood_reason = 'temp_ban';
			return false;
		}

		// Legacy flood interval check (per user group)
		if( $flood_interval = WPF()->usergroup->get_flood_interval( $groupid ) ) {
			$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
			$args = [
				'userid'    => $userid,
				'email'     => $email,
				'orderby'   => '`created` DESC, `postid` DESC',
				'row_count' => 1,
				'where'     => "`created` >= '$hour_ago'",
			];
			$items_count = 0;
			$lastpost    = WPF()->post->get_posts( $args, $items_count, false );
			if( $lasttime = wpfval( $lastpost, 0, 'created' ) ) {
				$lasttime = strtotime( $lasttime . ' GMT' );
				$nowtime  = time();
				$diff     = $nowtime - $lasttime;
				if( $diff < $flood_interval ) {
					$flood_reason = 'interval';
					return false;
				}
			}
		}

		// Advanced flood protection checks
		if( ! wpforo_setting( 'antispam', 'flood_protection_enabled' ) ) {
			return true;
		}

		// Check posts per minute
		$posts_per_minute = (int) wpforo_setting( 'antispam', 'flood_posts_per_minute' );
		if( $posts_per_minute > 0 ) {
			$minute_ago = gmdate( 'Y-m-d H:i:s', time() - 60 );
			$count = $this->get_user_post_count_since( $userid, $email, $minute_ago );
			if( $count >= $posts_per_minute ) {
				$flood_reason = 'per_minute';
				return $this->handle_flood_action();
			}
		}

		// Check posts per hour
		$posts_per_hour = (int) wpforo_setting( 'antispam', 'flood_posts_per_hour' );
		if( $posts_per_hour > 0 ) {
			$hour_ago = gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS );
			$count = $this->get_user_post_count_since( $userid, $email, $hour_ago );
			if( $count >= $posts_per_hour ) {
				$flood_reason = 'per_hour';
				return $this->handle_flood_action();
			}
		}

		// IP-based flood protection (tracked via transients since posts table has no IP column)
		if( wpforo_setting( 'antispam', 'flood_ip_protection_enabled' ) ) {
			$posts_per_ip_hour = (int) wpforo_setting( 'antispam', 'flood_posts_per_ip_hour' );
			if( $posts_per_ip_hour > 0 ) {
				$ip = $this->get_user_ip();
				if( $ip ) {
					$count = $this->get_ip_post_count_in_window( $ip, HOUR_IN_SECONDS );
					if( $count >= $posts_per_ip_hour ) {
						$flood_reason = 'ip_per_hour';
						return $this->handle_flood_action();
					}
				}
			}
		}

		// All checks passed - record IP post attempt for IP-based tracking
		if( wpforo_setting( 'antispam', 'flood_ip_protection_enabled' ) ) {
			$ip = $this->get_user_ip();
			if( $ip ) {
				$this->record_ip_post_attempt( $ip );
			}
		}

		return true;
	}

	/**
	 * Get the current user's IP address
	 *
	 * @return string|null IP address or null if not available
	 */
	private function get_user_ip() {
		// Check for forwarded IP first (behind proxy/load balancer)
		$headers = [ 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR' ];
		foreach( $headers as $header ) {
			if( ! empty( $_SERVER[ $header ] ) ) {
				$ip = $_SERVER[ $header ];
				// HTTP_X_FORWARDED_FOR can contain multiple IPs, get the first one
				if( strpos( $ip, ',' ) !== false ) {
					$ip = trim( explode( ',', $ip )[0] );
				}
				if( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
					return $ip;
				}
			}
		}
		return null;
	}

	/**
	 * Get post count for a user since a specific time
	 *
	 * @param int    $userid User ID
	 * @param string $email  Email for guests
	 * @param string $since  MySQL datetime string
	 * @return int Post count
	 */
	private function get_user_post_count_since( $userid, $email, $since ) {
		$posts_table = WPF()->tables->posts;

		if( $userid ) {
			$count = WPF()->db->get_var( WPF()->db->prepare(
				"SELECT COUNT(*) FROM `{$posts_table}` WHERE `userid` = %d AND `created` >= %s",
				$userid,
				$since
			) );
		} elseif( $email ) {
			$count = WPF()->db->get_var( WPF()->db->prepare(
				"SELECT COUNT(*) FROM `{$posts_table}` WHERE `email` = %s AND `created` >= %s",
				$email,
				$since
			) );
		} else {
			return 0;
		}

		return (int) $count;
	}

	/**
	 * Get post count for an IP address within a time window (using transients)
	 *
	 * @param string $ip             IP address
	 * @param int    $window_seconds Time window in seconds
	 * @return int Post count
	 */
	private function get_ip_post_count_in_window( $ip, $window_seconds ) {
		$key = 'wpforo_ip_posts_' . md5( $ip );
		$timestamps = get_transient( $key );
		if( ! is_array( $timestamps ) ) {
			return 0;
		}

		// Filter to only include timestamps within the window
		$cutoff = time() - $window_seconds;
		$valid_timestamps = array_filter( $timestamps, function( $ts ) use ( $cutoff ) {
			return $ts >= $cutoff;
		});

		return count( $valid_timestamps );
	}

	/**
	 * Record an IP post attempt for flood tracking
	 *
	 * @param string $ip IP address
	 */
	private function record_ip_post_attempt( $ip ) {
		$key = 'wpforo_ip_posts_' . md5( $ip );
		$timestamps = get_transient( $key );
		if( ! is_array( $timestamps ) ) {
			$timestamps = [];
		}

		// Add current timestamp
		$timestamps[] = time();

		// Clean old entries (keep last hour only)
		$cutoff = time() - HOUR_IN_SECONDS;
		$timestamps = array_filter( $timestamps, function( $ts ) use ( $cutoff ) {
			return $ts >= $cutoff;
		});

		// Re-index array and store with 1-hour expiration
		$timestamps = array_values( $timestamps );
		set_transient( $key, $timestamps, HOUR_IN_SECONDS );
	}

	/**
	 * Handle flood action based on settings
	 *
	 * @return bool|string False to block, 'unapprove' to allow but unapprove
	 */
	private function handle_flood_action() {
		$action = wpforo_setting( 'antispam', 'flood_action' );

		if( $action === 'temp_ban' ) {
			$this->set_flood_ban();
			return false;
		}

		if( $action === 'unapprove' ) {
			return 'unapprove';
		}

		// Default: block
		return false;
	}

	/**
	 * Set a temporary flood ban for the current user/IP
	 */
	private function set_flood_ban() {
		$duration = (int) wpforo_setting( 'antispam', 'flood_temp_ban_duration' );
		$ban_until = time() + ( $duration * 60 );

		$userid = WPF()->current_userid;
		$ip = $this->get_user_ip();

		// Store ban in transient (keyed by user ID or IP)
		if( $userid ) {
			set_transient( 'wpforo_flood_ban_user_' . $userid, $ban_until, $duration * 60 );
		}
		if( $ip ) {
			set_transient( 'wpforo_flood_ban_ip_' . md5( $ip ), $ban_until, $duration * 60 );
		}
	}

	/**
	 * Check if the current user/IP is temporarily banned for flooding
	 *
	 * @return bool True if banned
	 */
	public function is_flood_banned() {
		$userid = WPF()->current_userid;
		$ip = $this->get_user_ip();

		// Check user ban
		if( $userid ) {
			$ban_until = get_transient( 'wpforo_flood_ban_user_' . $userid );
			if( $ban_until && time() < $ban_until ) {
				return true;
			}
		}

		// Check IP ban
		if( $ip ) {
			$ban_until = get_transient( 'wpforo_flood_ban_ip_' . md5( $ip ) );
			if( $ban_until && time() < $ban_until ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Get remaining flood ban time in seconds
	 *
	 * @return int Seconds remaining, 0 if not banned
	 */
	public function get_flood_ban_remaining() {
		$userid = WPF()->current_userid;
		$ip = $this->get_user_ip();
		$max_remaining = 0;

		if( $userid ) {
			$ban_until = get_transient( 'wpforo_flood_ban_user_' . $userid );
			if( $ban_until && time() < $ban_until ) {
				$max_remaining = max( $max_remaining, $ban_until - time() );
			}
		}

		if( $ip ) {
			$ban_until = get_transient( 'wpforo_flood_ban_ip_' . md5( $ip ) );
			if( $ban_until && time() < $ban_until ) {
				$max_remaining = max( $max_remaining, $ban_until - time() );
			}
		}

		return $max_remaining;
	}

	public function get_forum_accesses_by_usergroup( $groupids = [] ) {
		$forum_accesses = [];
		if( ! $groupids ) $groupids = WPF()->current_user_groupids;
		if( ( $groupids = array_map( 'intval', (array) $groupids ) ) && ( $forums = WPF()->forum->get_forums() ) ) {
			foreach( $forums as $forum ) {
				if( $permissions = maybe_unserialize( $forum['permissions'] ) ) {
					foreach( $groupids as $groupid ) {
						$access = wpfval( $permissions, $groupid );
						if( $_access = $this->get_access( $access ) ) {
							if( $cans = wpfval( $_access, 'cans' ) ) {
								if( ! wpfkey( $forum_accesses, $forum['forumid'], $access ) ) $forum_accesses[ $forum['forumid'] ][ $access ] = $cans;
							}
						}
					}
				}
			}
		}

		return apply_filters( 'wpforo_permissions_forum_accesses_by_usergroup', $forum_accesses, $groupids );
	}

	public function show_accesses_selectbox( $selected = [], $exclude = [] ) {
		$accesses = $this->get_accesses();
		foreach( $accesses as $accesse ) {
			if( in_array( $accesse['access'], (array) $exclude ) ) continue;
			printf(
				'<option value="%1$s" %2$s>%3$s</option>',
				esc_attr( $accesse['access'] ),
				in_array( $accesse['access'], (array) $selected ) ? 'selected' : '',
				esc_html( $accesse['title'] )
			);
		}
	}

	/**
	 * @param array|int $owner
	 * @param array|int $user
	 *
	 * @return bool
	 */
	public function user_can_edit_account( $owner = [], $user = [] ) {
		if( ! $user ) $user = WPF()->current_user;
		if( ! $owner ) $owner = WPF()->current_object['user'];
		if( wpforo_is_id( $owner ) ) $owner = WPF()->member->get_member( $owner );
		if( wpforo_is_id( $user ) ) $user = WPF()->member->get_member( $user );
		if( ! $user || ! $owner ) return false;
		$is_users_same = wpforo_is_users_same( $user, $owner );

		return wpforo_user_is( $user['userid'], 'admin' ) || ( WPF()->usergroup->can( 'em', $user['groupids'] ) && $this->user_can_manage_user(
					$user['userid'],
					$owner['userid']
				) ) || ( $is_users_same && wpforo_user_is( $user['userid'], 'moderator' ) ) || ( $is_users_same && $user['posts'] >= wpforo_setting( 'antispam', 'min_number_posts_to_edit_account' ) );
	}

	public function can_report( $forumid, $groupids = null ): bool {
		if( ( is_null( $groupids ) && ! WPF()->current_user_groupids ) ) return false;
		if( is_null( $groupids ) ) $groupids = WPF()->current_user_groupids;

		$res = WPF()->current_userid && ! in_array( WPF()->current_user_status, [ 'banned', 'trashed' ] ) && ! WPF()->member->current_user_is_new() && $this->forum_can( 'r', $forumid, $groupids );

		return apply_filters( 'wpforo_can_report', $res, $forumid, $groupids );
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit